diff --git a/cmd-split-window.c b/cmd-split-window.c index ed3f47fc..c95700dc 100644 --- a/cmd-split-window.c +++ b/cmd-split-window.c @@ -39,11 +39,12 @@ const struct cmd_entry cmd_new_pane_entry = { .name = "new-pane", .alias = "newp", - .args = { "bc:de:fF:hIkl:m:p:PR:s:S:t:vZ", 0, -1, NULL }, + .args = { "bc:de:fF:hIkl:Lm:p:PR:s:S:t:vx:X:y:Y:Z", 0, -1, NULL }, .usage = "[-bdefhIklPvZ] [-c start-directory] [-e environment] " "[-F format] [-l size] [-m message] [-p percentage] " "[-s style] [-S active-border-style] " - "[-R inactive-border-style] " CMD_TARGET_PANE_USAGE " " + "[-R inactive-border-style] [-x width] [-y height] " + "[-X x-position] [-Y y-position] " CMD_TARGET_PANE_USAGE " " "[shell-command [argument ...]]", .target = { 't', CMD_FIND_PANE, 0 }, @@ -70,15 +71,48 @@ const struct cmd_entry cmd_split_window_entry = { }; static struct layout_cell * -cmd_split_window_get_tiled_layout_cell(struct cmdq_item *item, - struct args *args, struct window *w, struct window_pane *wp, int flags) +cmd_split_window_get_floating_cell(struct cmdq_item *item, struct args *args, + struct window *w, struct window_pane *wp) +{ + struct layout_cell *lc = NULL; + char *cause = NULL; + u_int x, y, sx, sy; + + if (window_pane_floating_geometry(w, wp, &x, &y, &sx, &sy, item, args, + &cause) != 0) { + cmdq_error(item, "invalid floating pane geometry %s", cause); + free(cause); + return (NULL); + } + + /* + * Floating panes sit in layout cells which are not in the layout_root + * tree so we call it with parent == NULL. + */ + lc = layout_create_cell(NULL); + lc->xoff = x; + lc->yoff = y; + lc->sx = sx; + lc->sy = sy; + + return (lc); +} + +static struct layout_cell * +cmd_split_window_get_tiled_cell(struct cmdq_item *item, struct args *args, + struct window *w, struct window_pane *wp, int flags) { enum layout_type type; struct layout_cell *lc = NULL; char *cause = NULL; int size; - if (window_pane_tile_geometry(w, wp, &size, &flags, &type, item, args, + if (wp->flags & PANE_FLOATING) { + cmdq_error(item, "can't split a floating pane"); + return (NULL); + } + + if (window_pane_tiled_geometry(w, wp, &size, &flags, &type, item, args, &cause) != 0) { cmdq_error(item, "invalid tiled geometry %s", cause); free(cause); @@ -89,6 +123,7 @@ cmd_split_window_get_tiled_layout_cell(struct cmdq_item *item, lc = layout_split_pane(wp, type, size, flags); if (lc == NULL) cmdq_error(item, "no space for new pane"); + return (lc); } @@ -106,15 +141,19 @@ cmd_split_window_exec(struct cmd *self, struct cmdq_item *item) struct window_pane *wp = target->wp, *new_wp; struct layout_cell *lc = NULL; struct cmd_find_state fs; - int flags, input; + int input, is_floating, flags = 0; const char *template, *style; char *cause = NULL, *cp; struct args_value *av; u_int count = args_count(args); + if (cmd_get_entry(self) == &cmd_new_pane_entry) + is_floating = 0; /* !args_has(args, 'L'); */ + else + is_floating = 0; input = (args_has(args, 'I') && count == 0); - flags = 0; + flags = is_floating ? SPAWN_FLOATING : 0; if (args_has(args, 'b')) flags |= SPAWN_BEFORE; if (args_has(args, 'f')) @@ -122,7 +161,10 @@ cmd_split_window_exec(struct cmd *self, struct cmdq_item *item) if (input || (count == 1 && *args_string(args, 0) == '\0')) flags |= SPAWN_EMPTY; - lc = cmd_split_window_get_tiled_layout_cell(item, args, w, wp, flags); + if (is_floating) + lc = cmd_split_window_get_floating_cell(item, args, w, wp); + else + lc = cmd_split_window_get_tiled_cell(item, args, w, wp, flags); if (lc == NULL) return (CMD_RETURN_ERROR); @@ -169,8 +211,8 @@ cmd_split_window_exec(struct cmd *self, struct cmdq_item *item) } options_set_string(new_wp->options, "window-active-style", 0, "%s", style); - new_wp->flags |= (PANE_REDRAW|PANE_STYLECHANGED - |PANE_THEMECHANGED); + new_wp->flags |= (PANE_REDRAW|PANE_STYLECHANGED| + PANE_THEMECHANGED); } style = args_get(args, 'S'); if (style != NULL) { @@ -201,7 +243,8 @@ cmd_split_window_exec(struct cmd *self, struct cmdq_item *item) switch (window_pane_start_input(new_wp, item, &cause)) { case -1: server_client_remove_pane(new_wp); - layout_close_pane(new_wp); + if (!is_floating) + layout_close_pane(new_wp); window_remove_pane(wp->window, new_wp); cmdq_error(item, "%s", cause); free(cause); @@ -216,8 +259,11 @@ cmd_split_window_exec(struct cmd *self, struct cmdq_item *item) } if (!args_has(args, 'd')) cmd_find_from_winlink_pane(current, wl, new_wp, 0); - window_pop_zoom(wp->window); - server_redraw_window(wp->window); + + if (!is_floating) { + window_pop_zoom(wp->window); + server_redraw_window(wp->window); + } server_status_session(s); if (args_has(args, 'P')) { diff --git a/spawn.c b/spawn.c index 1d284144..dddb3ce1 100644 --- a/spawn.c +++ b/spawn.c @@ -282,6 +282,13 @@ spawn_pane(struct spawn_context *sc, char **cause) layout_assign_pane(sc->lc, new_wp, 0); } + /* + * If window currently zoomed, window_set_active_pane calls + * window_unzoom which it copies back the saved_layout_cell. + */ + if (w->flags & WINDOW_ZOOMED) + new_wp->saved_layout_cell = new_wp->layout_cell; + /* * Now we have a pane with nothing running in it ready for the new * process. Work out the command and arguments and store the working @@ -374,7 +381,7 @@ spawn_pane(struct spawn_context *sc, char **cause) goto complete; } - /* Store current working directory and change to new one. */ + /* Store current working directory and change to new one. */ if (getcwd(path, sizeof path) != NULL) { if (chdir(new_wp->cwd) == 0) actual_cwd = new_wp->cwd; diff --git a/tmux.h b/tmux.h index 5ac1d4f7..097ba090 100644 --- a/tmux.h +++ b/tmux.h @@ -1346,6 +1346,9 @@ struct window { u_int new_xpixel; u_int new_ypixel; + u_int last_new_pane_x; + u_int last_new_pane_y; + struct utf8_data *fill_character; int flags; #define WINDOW_BELL 0x1 @@ -3421,9 +3424,12 @@ enum client_theme window_pane_get_theme(struct window_pane *); void window_pane_send_theme_update(struct window_pane *); struct style_range *window_pane_border_status_get_range(struct window_pane *, u_int, u_int); -int window_pane_tile_geometry(struct window *, +int window_pane_tiled_geometry(struct window *, struct window_pane *, int *, int *, enum layout_type *, struct cmdq_item *, struct args *, char **); +int window_pane_floating_geometry(struct window *, + struct window_pane *, u_int *, u_int *, u_int *, u_int *, + struct cmdq_item *, struct args *, char **); /* layout.c */ u_int layout_count_cells(struct layout_cell *); diff --git a/window.c b/window.c index ac48246f..e6e6eba7 100644 --- a/window.c +++ b/window.c @@ -541,6 +541,7 @@ window_set_active_pane(struct window *w, struct window_pane *wp, int notify) } tty_update_window_offset(w); + server_redraw_window(w); if (notify) notify_window("window-pane-changed", w); @@ -585,6 +586,8 @@ window_redraw_active_switch(struct window *w, struct window_pane *wp) wp->flags |= PANE_REDRAW; } } + if (wp == w->active) + break; /* If the pane is floating, move to the front. */ if (wp->flags & PANE_FLOATING) { @@ -593,9 +596,9 @@ window_redraw_active_switch(struct window *w, struct window_pane *wp) wp->flags |= PANE_REDRAW; } - if (wp == w->active) - break; wp = w->active; + if (wp == NULL) + break; } } @@ -613,7 +616,7 @@ window_get_active_at(struct window *w, u_int x, u_int y) continue; window_pane_full_size_offset(wp, &xoff, &yoff, &sx, &sy); if (~wp->flags & PANE_FLOATING) { - /* Tiled - to and including bottom or right border. */ + /* Tiled - to and including bottom or right border. */ if ((int)x < xoff || x > xoff + sx) continue; if (pane_status == PANE_STATUS_TOP) { @@ -689,7 +692,6 @@ window_zoom(struct window_pane *wp) if (w->flags & WINDOW_ZOOMED) return (-1); - if (window_count_panes(w, 1) == 1) return (-1); @@ -726,7 +728,7 @@ window_unzoom(struct window *w, int notify) TAILQ_FOREACH(wp, &w->panes, entry) { wp->layout_cell = wp->saved_layout_cell; wp->saved_layout_cell = NULL; - wp->flags ^= PANE_ZOOMED; + wp->flags &= ~PANE_ZOOMED; } layout_fix_panes(w, NULL); @@ -779,7 +781,7 @@ window_add_pane(struct window *w, struct window_pane *other, u_int hlimit, TAILQ_INSERT_BEFORE(other, wp, entry); } else { log_debug("%s: @%u after %%%u", __func__, w->id, wp->id); - if (flags & SPAWN_FULLSIZE) + if (flags & (SPAWN_FULLSIZE|SPAWN_FLOATING)) TAILQ_INSERT_TAIL(&w->panes, wp, entry); else TAILQ_INSERT_AFTER(&w->panes, other, wp, entry); @@ -787,8 +789,8 @@ window_add_pane(struct window *w, struct window_pane *other, u_int hlimit, if (~flags & SPAWN_FLOATING) TAILQ_INSERT_TAIL(&w->z_index, wp, zentry); else { - TAILQ_INSERT_HEAD(&w->z_index, wp, zentry); wp->flags |= PANE_FLOATING; + TAILQ_INSERT_HEAD(&w->z_index, wp, zentry); } return (wp); } @@ -946,7 +948,7 @@ window_pane_printable_flags(struct window_pane *wp) { struct window *w = wp->window; static char flags[32]; - u_int pos = 0; + int pos = 0; if (wp == w->active) flags[pos++] = '*'; @@ -2057,8 +2059,9 @@ window_pane_border_status_get_range(struct window_pane *wp, u_int x, u_int y) return (style_ranges_get_range(srs, x - wp->xoff - 2)); } +/* Work out geometry for tiled panes. */ int -window_pane_tile_geometry(struct window *w, struct window_pane *wp, +window_pane_tiled_geometry(struct window *w, struct window_pane *wp, int *out_size, int *out_flags, enum layout_type *out_type, struct cmdq_item *item, struct args *args, char **cause) { @@ -2106,3 +2109,62 @@ window_pane_tile_geometry(struct window *w, struct window_pane *wp, *out_type = type; return (0); } + +/* Work out geometry for floating panes. */ +int +window_pane_floating_geometry(struct window *w, __unused struct window_pane *wp, + u_int *out_x, u_int *out_y, u_int *out_sx, u_int *out_sy, + struct cmdq_item *item, struct args *args, char **cause) +{ + u_int x, y, sx = w->sx / 2, sy = w->sy / 2; + + if (args_has(args, 'x')) { + sx = args_percentage_and_expand(args, 'x', 0, USHRT_MAX, w->sx, + item, cause); + if (*cause != NULL) + return (-1); + } + if (args_has(args, 'y')) { + sy = args_percentage_and_expand(args, 'y', 0, USHRT_MAX, w->sy, + item, cause); + if (*cause != NULL) + return (-1); + } + + if (args_has(args, 'X')) { + x = args_percentage_and_expand(args, 'X', 0, USHRT_MAX, w->sx, + item, cause); + if (*cause != NULL) + return (-1); + } else { + if (w->last_new_pane_x == 0) + x = 4; + else { + x = w->last_new_pane_x + 4; + if (w->last_new_pane_x > w->sx) + x = 4; + } + w->last_new_pane_x = x; + } + if (args_has(args, 'Y')) { + y = args_percentage_and_expand(args, 'Y', 0, USHRT_MAX, w->sy, + item, cause); + if (*cause != NULL) + return (-1); + } else { + if (w->last_new_pane_y == 0) + y = 2; + else { + y = w->last_new_pane_y + 2; + if (w->last_new_pane_y > w->sy) + y = 2; + } + w->last_new_pane_y = y; + } + + *out_x = x; + *out_y = y; + *out_sx = sx; + *out_sy = sy; + return (0); +}