Nicholas Marriott | 35876ea | 2009-06-01 22:58:49 +0000 | [diff] [blame] | 1 | /* $OpenBSD$ */ |
| 2 | |
| 3 | /* |
nicm | 995af0e | 2016-01-19 15:59:12 +0000 | [diff] [blame] | 4 | * Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com> |
Nicholas Marriott | 35876ea | 2009-06-01 22:58:49 +0000 | [diff] [blame] | 5 | * |
| 6 | * Permission to use, copy, modify, and distribute this software for any |
| 7 | * purpose with or without fee is hereby granted, provided that the above |
| 8 | * copyright notice and this permission notice appear in all copies. |
| 9 | * |
| 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
| 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
| 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
| 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
| 14 | * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER |
| 15 | * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING |
| 16 | * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
| 17 | */ |
| 18 | |
| 19 | #include <sys/types.h> |
| 20 | |
Nicholas Marriott | d42fb43 | 2009-06-04 18:48:24 +0000 | [diff] [blame] | 21 | #include <stdlib.h> |
Nicholas Marriott | 35876ea | 2009-06-01 22:58:49 +0000 | [diff] [blame] | 22 | #include <string.h> |
Nicholas Marriott | ac9daf9 | 2010-04-06 21:35:44 +0000 | [diff] [blame] | 23 | #include <unistd.h> |
nicm | 8149bc3 | 2017-06-04 09:02:36 +0000 | [diff] [blame] | 24 | #include <vis.h> |
Nicholas Marriott | 35876ea | 2009-06-01 22:58:49 +0000 | [diff] [blame] | 25 | |
| 26 | #include "tmux.h" |
| 27 | |
nicm | 82776c4 | 2018-07-31 11:49:26 +0000 | [diff] [blame] | 28 | /* Selected area in screen. */ |
| 29 | struct screen_sel { |
| 30 | int hidden; |
| 31 | int rectangle; |
| 32 | int modekeys; |
| 33 | |
| 34 | u_int sx; |
| 35 | u_int sy; |
| 36 | |
| 37 | u_int ex; |
| 38 | u_int ey; |
| 39 | |
| 40 | struct grid_cell cell; |
| 41 | }; |
| 42 | |
| 43 | /* Entry on title stack. */ |
nicm | 88517ce | 2017-10-05 13:29:18 +0000 | [diff] [blame] | 44 | struct screen_title_entry { |
| 45 | char *text; |
| 46 | |
| 47 | TAILQ_ENTRY(screen_title_entry) entry; |
| 48 | }; |
| 49 | TAILQ_HEAD(screen_titles, screen_title_entry); |
| 50 | |
nicm | c426e48 | 2016-10-10 21:29:23 +0000 | [diff] [blame] | 51 | static void screen_resize_y(struct screen *, u_int); |
Nicholas Marriott | 35876ea | 2009-06-01 22:58:49 +0000 | [diff] [blame] | 52 | |
nicm | e454018 | 2016-10-11 13:21:59 +0000 | [diff] [blame] | 53 | static void screen_reflow(struct screen *, u_int); |
nicm | 88517ce | 2017-10-05 13:29:18 +0000 | [diff] [blame] | 54 | |
| 55 | /* Free titles stack. */ |
| 56 | static void |
| 57 | screen_free_titles(struct screen *s) |
| 58 | { |
| 59 | struct screen_title_entry *title_entry; |
| 60 | |
| 61 | if (s->titles == NULL) |
| 62 | return; |
| 63 | |
| 64 | while ((title_entry = TAILQ_FIRST(s->titles)) != NULL) { |
| 65 | TAILQ_REMOVE(s->titles, title_entry, entry); |
| 66 | free(title_entry->text); |
| 67 | free(title_entry); |
| 68 | } |
| 69 | |
| 70 | free(s->titles); |
| 71 | s->titles = NULL; |
| 72 | } |
nicm | e454018 | 2016-10-11 13:21:59 +0000 | [diff] [blame] | 73 | |
Nicholas Marriott | 35876ea | 2009-06-01 22:58:49 +0000 | [diff] [blame] | 74 | /* Create a new screen. */ |
| 75 | void |
| 76 | screen_init(struct screen *s, u_int sx, u_int sy, u_int hlimit) |
| 77 | { |
| 78 | s->grid = grid_create(sx, sy, hlimit); |
nicm | d9b3133 | 2015-08-28 17:11:12 +0000 | [diff] [blame] | 79 | s->title = xstrdup(""); |
nicm | 88517ce | 2017-10-05 13:29:18 +0000 | [diff] [blame] | 80 | s->titles = NULL; |
Nicholas Marriott | 35876ea | 2009-06-01 22:58:49 +0000 | [diff] [blame] | 81 | |
Nicholas Marriott | 3ea5e06 | 2011-05-20 19:17:39 +0000 | [diff] [blame] | 82 | s->cstyle = 0; |
Nicholas Marriott | 944b5e6 | 2011-05-20 19:03:58 +0000 | [diff] [blame] | 83 | s->ccolour = xstrdup(""); |
Nicholas Marriott | d42fb43 | 2009-06-04 18:48:24 +0000 | [diff] [blame] | 84 | s->tabs = NULL; |
nicm | 82776c4 | 2018-07-31 11:49:26 +0000 | [diff] [blame] | 85 | s->sel = NULL; |
Nicholas Marriott | d42fb43 | 2009-06-04 18:48:24 +0000 | [diff] [blame] | 86 | |
Nicholas Marriott | 35876ea | 2009-06-01 22:58:49 +0000 | [diff] [blame] | 87 | screen_reinit(s); |
| 88 | } |
| 89 | |
| 90 | /* Reinitialise screen. */ |
| 91 | void |
| 92 | screen_reinit(struct screen *s) |
| 93 | { |
| 94 | s->cx = 0; |
| 95 | s->cy = 0; |
| 96 | |
| 97 | s->rupper = 0; |
| 98 | s->rlower = screen_size_y(s) - 1; |
| 99 | |
Nicholas Marriott | ac9daf9 | 2010-04-06 21:35:44 +0000 | [diff] [blame] | 100 | s->mode = MODE_CURSOR | MODE_WRAP; |
Nicholas Marriott | 15a64b8 | 2009-12-03 22:50:09 +0000 | [diff] [blame] | 101 | |
Nicholas Marriott | d42fb43 | 2009-06-04 18:48:24 +0000 | [diff] [blame] | 102 | screen_reset_tabs(s); |
Nicholas Marriott | 35876ea | 2009-06-01 22:58:49 +0000 | [diff] [blame] | 103 | |
nicm | 4179b42 | 2016-10-13 20:27:27 +0000 | [diff] [blame] | 104 | grid_clear_lines(s->grid, s->grid->hsize, s->grid->sy, 8); |
Nicholas Marriott | 35876ea | 2009-06-01 22:58:49 +0000 | [diff] [blame] | 105 | |
| 106 | screen_clear_selection(s); |
nicm | 88517ce | 2017-10-05 13:29:18 +0000 | [diff] [blame] | 107 | screen_free_titles(s); |
Nicholas Marriott | 35876ea | 2009-06-01 22:58:49 +0000 | [diff] [blame] | 108 | } |
| 109 | |
| 110 | /* Destroy a screen. */ |
| 111 | void |
| 112 | screen_free(struct screen *s) |
| 113 | { |
nicm | 82776c4 | 2018-07-31 11:49:26 +0000 | [diff] [blame] | 114 | free(s->sel); |
Nicholas Marriott | df912e3 | 2012-07-10 11:53:01 +0000 | [diff] [blame] | 115 | free(s->tabs); |
| 116 | free(s->title); |
| 117 | free(s->ccolour); |
nicm | 88517ce | 2017-10-05 13:29:18 +0000 | [diff] [blame] | 118 | |
Nicholas Marriott | 35876ea | 2009-06-01 22:58:49 +0000 | [diff] [blame] | 119 | grid_destroy(s->grid); |
nicm | 88517ce | 2017-10-05 13:29:18 +0000 | [diff] [blame] | 120 | |
| 121 | screen_free_titles(s); |
Nicholas Marriott | d42fb43 | 2009-06-04 18:48:24 +0000 | [diff] [blame] | 122 | } |
| 123 | |
| 124 | /* Reset tabs to default, eight spaces apart. */ |
| 125 | void |
| 126 | screen_reset_tabs(struct screen *s) |
| 127 | { |
| 128 | u_int i; |
| 129 | |
Nicholas Marriott | df912e3 | 2012-07-10 11:53:01 +0000 | [diff] [blame] | 130 | free(s->tabs); |
Nicholas Marriott | d42fb43 | 2009-06-04 18:48:24 +0000 | [diff] [blame] | 131 | |
| 132 | if ((s->tabs = bit_alloc(screen_size_x(s))) == NULL) |
| 133 | fatal("bit_alloc failed"); |
| 134 | for (i = 8; i < screen_size_x(s); i += 8) |
| 135 | bit_set(s->tabs, i); |
Nicholas Marriott | 35876ea | 2009-06-01 22:58:49 +0000 | [diff] [blame] | 136 | } |
| 137 | |
Nicholas Marriott | 3ea5e06 | 2011-05-20 19:17:39 +0000 | [diff] [blame] | 138 | /* Set screen cursor style. */ |
| 139 | void |
| 140 | screen_set_cursor_style(struct screen *s, u_int style) |
| 141 | { |
Nicholas Marriott | 87d092d | 2012-03-17 21:37:36 +0000 | [diff] [blame] | 142 | if (style <= 6) |
Nicholas Marriott | 3ea5e06 | 2011-05-20 19:17:39 +0000 | [diff] [blame] | 143 | s->cstyle = style; |
| 144 | } |
| 145 | |
Nicholas Marriott | 944b5e6 | 2011-05-20 19:03:58 +0000 | [diff] [blame] | 146 | /* Set screen cursor colour. */ |
| 147 | void |
nicm | 2a1f27e | 2015-12-28 14:02:52 +0000 | [diff] [blame] | 148 | screen_set_cursor_colour(struct screen *s, const char *colour) |
Nicholas Marriott | 944b5e6 | 2011-05-20 19:03:58 +0000 | [diff] [blame] | 149 | { |
Nicholas Marriott | df912e3 | 2012-07-10 11:53:01 +0000 | [diff] [blame] | 150 | free(s->ccolour); |
nicm | 2a1f27e | 2015-12-28 14:02:52 +0000 | [diff] [blame] | 151 | s->ccolour = xstrdup(colour); |
Nicholas Marriott | 944b5e6 | 2011-05-20 19:03:58 +0000 | [diff] [blame] | 152 | } |
| 153 | |
Nicholas Marriott | 35876ea | 2009-06-01 22:58:49 +0000 | [diff] [blame] | 154 | /* Set screen title. */ |
| 155 | void |
| 156 | screen_set_title(struct screen *s, const char *title) |
| 157 | { |
Nicholas Marriott | df912e3 | 2012-07-10 11:53:01 +0000 | [diff] [blame] | 158 | free(s->title); |
nicm | 8149bc3 | 2017-06-04 09:02:36 +0000 | [diff] [blame] | 159 | utf8_stravis(&s->title, title, VIS_OCTAL|VIS_CSTYLE|VIS_TAB|VIS_NL); |
Nicholas Marriott | 35876ea | 2009-06-01 22:58:49 +0000 | [diff] [blame] | 160 | } |
| 161 | |
nicm | f3dc38d | 2019-11-15 11:16:53 +0000 | [diff] [blame] | 162 | /* Set screen path. */ |
| 163 | void |
| 164 | screen_set_path(struct screen *s, const char *path) |
| 165 | { |
| 166 | free(s->path); |
| 167 | utf8_stravis(&s->path, path, VIS_OCTAL|VIS_CSTYLE|VIS_TAB|VIS_NL); |
| 168 | } |
| 169 | |
nicm | 88517ce | 2017-10-05 13:29:18 +0000 | [diff] [blame] | 170 | /* Push the current title onto the stack. */ |
| 171 | void |
| 172 | screen_push_title(struct screen *s) |
| 173 | { |
| 174 | struct screen_title_entry *title_entry; |
| 175 | |
| 176 | if (s->titles == NULL) { |
| 177 | s->titles = xmalloc(sizeof *s->titles); |
| 178 | TAILQ_INIT(s->titles); |
| 179 | } |
| 180 | title_entry = xmalloc(sizeof *title_entry); |
| 181 | title_entry->text = xstrdup(s->title); |
| 182 | TAILQ_INSERT_HEAD(s->titles, title_entry, entry); |
| 183 | } |
| 184 | |
| 185 | /* |
| 186 | * Pop a title from the stack and set it as the screen title. If the stack is |
| 187 | * empty, do nothing. |
| 188 | */ |
| 189 | void |
| 190 | screen_pop_title(struct screen *s) |
| 191 | { |
| 192 | struct screen_title_entry *title_entry; |
| 193 | |
| 194 | if (s->titles == NULL) |
| 195 | return; |
| 196 | |
| 197 | title_entry = TAILQ_FIRST(s->titles); |
| 198 | if (title_entry != NULL) { |
| 199 | screen_set_title(s, title_entry->text); |
| 200 | |
| 201 | TAILQ_REMOVE(s->titles, title_entry, entry); |
| 202 | free(title_entry->text); |
| 203 | free(title_entry); |
| 204 | } |
| 205 | } |
| 206 | |
Nicholas Marriott | 35876ea | 2009-06-01 22:58:49 +0000 | [diff] [blame] | 207 | /* Resize screen. */ |
| 208 | void |
Nicholas Marriott | 8903c1f | 2013-02-05 11:08:59 +0000 | [diff] [blame] | 209 | screen_resize(struct screen *s, u_int sx, u_int sy, int reflow) |
Nicholas Marriott | 35876ea | 2009-06-01 22:58:49 +0000 | [diff] [blame] | 210 | { |
| 211 | if (sx < 1) |
| 212 | sx = 1; |
| 213 | if (sy < 1) |
| 214 | sy = 1; |
| 215 | |
Nicholas Marriott | d42fb43 | 2009-06-04 18:48:24 +0000 | [diff] [blame] | 216 | if (sx != screen_size_x(s)) { |
nicm | 9ee1a8f | 2019-03-20 19:19:11 +0000 | [diff] [blame] | 217 | s->grid->sx = sx; |
Nicholas Marriott | d42fb43 | 2009-06-04 18:48:24 +0000 | [diff] [blame] | 218 | screen_reset_tabs(s); |
nicm | 3887d95 | 2017-11-02 18:26:38 +0000 | [diff] [blame] | 219 | } else |
| 220 | reflow = 0; |
Nicholas Marriott | d42fb43 | 2009-06-04 18:48:24 +0000 | [diff] [blame] | 221 | |
Nicholas Marriott | 35876ea | 2009-06-01 22:58:49 +0000 | [diff] [blame] | 222 | if (sy != screen_size_y(s)) |
| 223 | screen_resize_y(s, sy); |
Nicholas Marriott | 8903c1f | 2013-02-05 11:08:59 +0000 | [diff] [blame] | 224 | |
| 225 | if (reflow) |
| 226 | screen_reflow(s, sx); |
Nicholas Marriott | 35876ea | 2009-06-01 22:58:49 +0000 | [diff] [blame] | 227 | } |
| 228 | |
nicm | c426e48 | 2016-10-10 21:29:23 +0000 | [diff] [blame] | 229 | static void |
Nicholas Marriott | 35876ea | 2009-06-01 22:58:49 +0000 | [diff] [blame] | 230 | screen_resize_y(struct screen *s, u_int sy) |
| 231 | { |
| 232 | struct grid *gd = s->grid; |
Nicholas Marriott | f4b8f00 | 2009-06-24 19:12:44 +0000 | [diff] [blame] | 233 | u_int needed, available, oldy, i; |
Nicholas Marriott | 35876ea | 2009-06-01 22:58:49 +0000 | [diff] [blame] | 234 | |
| 235 | if (sy == 0) |
| 236 | fatalx("zero size"); |
Nicholas Marriott | f4b8f00 | 2009-06-24 19:12:44 +0000 | [diff] [blame] | 237 | oldy = screen_size_y(s); |
| 238 | |
Nicholas Marriott | 15a64b8 | 2009-12-03 22:50:09 +0000 | [diff] [blame] | 239 | /* |
Nicholas Marriott | f4b8f00 | 2009-06-24 19:12:44 +0000 | [diff] [blame] | 240 | * When resizing: |
| 241 | * |
| 242 | * If the height is decreasing, delete lines from the bottom until |
| 243 | * hitting the cursor, then push lines from the top into the history. |
Nicholas Marriott | 15a64b8 | 2009-12-03 22:50:09 +0000 | [diff] [blame] | 244 | * |
nicm | 2627ab3 | 2016-09-02 20:57:20 +0000 | [diff] [blame] | 245 | * When increasing, pull as many lines as possible from scrolled |
| 246 | * history (not explicitly cleared from view) to the top, then fill the |
| 247 | * remaining with blanks at the bottom. |
Nicholas Marriott | f4b8f00 | 2009-06-24 19:12:44 +0000 | [diff] [blame] | 248 | */ |
Nicholas Marriott | 35876ea | 2009-06-01 22:58:49 +0000 | [diff] [blame] | 249 | |
| 250 | /* Size decreasing. */ |
Nicholas Marriott | f4b8f00 | 2009-06-24 19:12:44 +0000 | [diff] [blame] | 251 | if (sy < oldy) { |
| 252 | needed = oldy - sy; |
Nicholas Marriott | 35876ea | 2009-06-01 22:58:49 +0000 | [diff] [blame] | 253 | |
Nicholas Marriott | f4b8f00 | 2009-06-24 19:12:44 +0000 | [diff] [blame] | 254 | /* Delete as many lines as possible from the bottom. */ |
| 255 | available = oldy - 1 - s->cy; |
| 256 | if (available > 0) { |
| 257 | if (available > needed) |
| 258 | available = needed; |
nicm | 4179b42 | 2016-10-13 20:27:27 +0000 | [diff] [blame] | 259 | grid_view_delete_lines(gd, oldy - available, available, |
| 260 | 8); |
Nicholas Marriott | 35876ea | 2009-06-01 22:58:49 +0000 | [diff] [blame] | 261 | } |
Nicholas Marriott | f4b8f00 | 2009-06-24 19:12:44 +0000 | [diff] [blame] | 262 | needed -= available; |
Nicholas Marriott | 35876ea | 2009-06-01 22:58:49 +0000 | [diff] [blame] | 263 | |
Nicholas Marriott | f4b8f00 | 2009-06-24 19:12:44 +0000 | [diff] [blame] | 264 | /* |
Nicholas Marriott | 3592859 | 2009-07-13 10:43:52 +0000 | [diff] [blame] | 265 | * Now just increase the history size, if possible, to take |
| 266 | * over the lines which are left. If history is off, delete |
| 267 | * lines from the top. |
Nicholas Marriott | f4b8f00 | 2009-06-24 19:12:44 +0000 | [diff] [blame] | 268 | */ |
Nicholas Marriott | 3592859 | 2009-07-13 10:43:52 +0000 | [diff] [blame] | 269 | available = s->cy; |
nicm | 2627ab3 | 2016-09-02 20:57:20 +0000 | [diff] [blame] | 270 | if (gd->flags & GRID_HISTORY) { |
| 271 | gd->hscrolled += needed; |
Nicholas Marriott | 3592859 | 2009-07-13 10:43:52 +0000 | [diff] [blame] | 272 | gd->hsize += needed; |
nicm | 2627ab3 | 2016-09-02 20:57:20 +0000 | [diff] [blame] | 273 | } else if (needed > 0 && available > 0) { |
Nicholas Marriott | 3592859 | 2009-07-13 10:43:52 +0000 | [diff] [blame] | 274 | if (available > needed) |
| 275 | available = needed; |
nicm | 4179b42 | 2016-10-13 20:27:27 +0000 | [diff] [blame] | 276 | grid_view_delete_lines(gd, 0, available, 8); |
Nicholas Marriott | 3592859 | 2009-07-13 10:43:52 +0000 | [diff] [blame] | 277 | } |
Nicholas Marriott | f4b8f00 | 2009-06-24 19:12:44 +0000 | [diff] [blame] | 278 | s->cy -= needed; |
Nicholas Marriott | 15a64b8 | 2009-12-03 22:50:09 +0000 | [diff] [blame] | 279 | } |
Nicholas Marriott | 35876ea | 2009-06-01 22:58:49 +0000 | [diff] [blame] | 280 | |
nicm | 2fae6a5 | 2018-07-04 09:44:07 +0000 | [diff] [blame] | 281 | /* Resize line array. */ |
| 282 | grid_adjust_lines(gd, gd->hsize + sy); |
Nicholas Marriott | 35876ea | 2009-06-01 22:58:49 +0000 | [diff] [blame] | 283 | |
| 284 | /* Size increasing. */ |
Nicholas Marriott | f4b8f00 | 2009-06-24 19:12:44 +0000 | [diff] [blame] | 285 | if (sy > oldy) { |
| 286 | needed = sy - oldy; |
| 287 | |
Nicholas Marriott | 3592859 | 2009-07-13 10:43:52 +0000 | [diff] [blame] | 288 | /* |
nicm | c426e48 | 2016-10-10 21:29:23 +0000 | [diff] [blame] | 289 | * Try to pull as much as possible out of scrolled history, if |
| 290 | * is is enabled. |
Nicholas Marriott | 3592859 | 2009-07-13 10:43:52 +0000 | [diff] [blame] | 291 | */ |
nicm | 2627ab3 | 2016-09-02 20:57:20 +0000 | [diff] [blame] | 292 | available = gd->hscrolled; |
Nicholas Marriott | 3592859 | 2009-07-13 10:43:52 +0000 | [diff] [blame] | 293 | if (gd->flags & GRID_HISTORY && available > 0) { |
Nicholas Marriott | f4b8f00 | 2009-06-24 19:12:44 +0000 | [diff] [blame] | 294 | if (available > needed) |
| 295 | available = needed; |
nicm | 2627ab3 | 2016-09-02 20:57:20 +0000 | [diff] [blame] | 296 | gd->hscrolled -= available; |
Nicholas Marriott | f4b8f00 | 2009-06-24 19:12:44 +0000 | [diff] [blame] | 297 | gd->hsize -= available; |
| 298 | s->cy += available; |
Nicholas Marriott | 3592859 | 2009-07-13 10:43:52 +0000 | [diff] [blame] | 299 | } else |
| 300 | available = 0; |
Nicholas Marriott | f4b8f00 | 2009-06-24 19:12:44 +0000 | [diff] [blame] | 301 | needed -= available; |
| 302 | |
| 303 | /* Then fill the rest in with blanks. */ |
Nicholas Marriott | 5e01b6d | 2009-08-08 13:29:27 +0000 | [diff] [blame] | 304 | for (i = gd->hsize + sy - needed; i < gd->hsize + sy; i++) |
nicm | 2fae6a5 | 2018-07-04 09:44:07 +0000 | [diff] [blame] | 305 | memset(grid_get_line(gd, i), 0, sizeof(struct grid_line)); |
Nicholas Marriott | 35876ea | 2009-06-01 22:58:49 +0000 | [diff] [blame] | 306 | } |
| 307 | |
Nicholas Marriott | f4b8f00 | 2009-06-24 19:12:44 +0000 | [diff] [blame] | 308 | /* Set the new size, and reset the scroll region. */ |
Nicholas Marriott | 35876ea | 2009-06-01 22:58:49 +0000 | [diff] [blame] | 309 | gd->sy = sy; |
Nicholas Marriott | 35876ea | 2009-06-01 22:58:49 +0000 | [diff] [blame] | 310 | s->rupper = 0; |
| 311 | s->rlower = screen_size_y(s) - 1; |
| 312 | } |
| 313 | |
| 314 | /* Set selection. */ |
| 315 | void |
Nicholas Marriott | 3ef3802 | 2010-02-06 17:35:01 +0000 | [diff] [blame] | 316 | screen_set_selection(struct screen *s, u_int sx, u_int sy, |
nicm | 82776c4 | 2018-07-31 11:49:26 +0000 | [diff] [blame] | 317 | u_int ex, u_int ey, u_int rectangle, int modekeys, struct grid_cell *gc) |
Nicholas Marriott | 35876ea | 2009-06-01 22:58:49 +0000 | [diff] [blame] | 318 | { |
nicm | 82776c4 | 2018-07-31 11:49:26 +0000 | [diff] [blame] | 319 | if (s->sel == NULL) |
| 320 | s->sel = xcalloc(1, sizeof *s->sel); |
Nicholas Marriott | 35876ea | 2009-06-01 22:58:49 +0000 | [diff] [blame] | 321 | |
nicm | 82776c4 | 2018-07-31 11:49:26 +0000 | [diff] [blame] | 322 | memcpy(&s->sel->cell, gc, sizeof s->sel->cell); |
| 323 | s->sel->hidden = 0; |
| 324 | s->sel->rectangle = rectangle; |
| 325 | s->sel->modekeys = modekeys; |
nicm | 7e6c2cb | 2016-11-24 13:38:44 +0000 | [diff] [blame] | 326 | |
nicm | 82776c4 | 2018-07-31 11:49:26 +0000 | [diff] [blame] | 327 | s->sel->sx = sx; |
| 328 | s->sel->sy = sy; |
| 329 | s->sel->ex = ex; |
| 330 | s->sel->ey = ey; |
Nicholas Marriott | 35876ea | 2009-06-01 22:58:49 +0000 | [diff] [blame] | 331 | } |
| 332 | |
| 333 | /* Clear selection. */ |
| 334 | void |
| 335 | screen_clear_selection(struct screen *s) |
| 336 | { |
nicm | 82776c4 | 2018-07-31 11:49:26 +0000 | [diff] [blame] | 337 | free(s->sel); |
| 338 | s->sel = NULL; |
nicm | 7e6c2cb | 2016-11-24 13:38:44 +0000 | [diff] [blame] | 339 | } |
| 340 | |
| 341 | /* Hide selection. */ |
| 342 | void |
| 343 | screen_hide_selection(struct screen *s) |
| 344 | { |
nicm | 82776c4 | 2018-07-31 11:49:26 +0000 | [diff] [blame] | 345 | if (s->sel != NULL) |
| 346 | s->sel->hidden = 1; |
Nicholas Marriott | 35876ea | 2009-06-01 22:58:49 +0000 | [diff] [blame] | 347 | } |
| 348 | |
| 349 | /* Check if cell in selection. */ |
| 350 | int |
| 351 | screen_check_selection(struct screen *s, u_int px, u_int py) |
| 352 | { |
nicm | 82776c4 | 2018-07-31 11:49:26 +0000 | [diff] [blame] | 353 | struct screen_sel *sel = s->sel; |
nicm | 29d20a5 | 2014-08-11 22:18:16 +0000 | [diff] [blame] | 354 | u_int xx; |
Nicholas Marriott | 35876ea | 2009-06-01 22:58:49 +0000 | [diff] [blame] | 355 | |
nicm | 82776c4 | 2018-07-31 11:49:26 +0000 | [diff] [blame] | 356 | if (sel == NULL || sel->hidden) |
Nicholas Marriott | 35876ea | 2009-06-01 22:58:49 +0000 | [diff] [blame] | 357 | return (0); |
| 358 | |
nicm | 82776c4 | 2018-07-31 11:49:26 +0000 | [diff] [blame] | 359 | if (sel->rectangle) { |
Nicholas Marriott | 3ef3802 | 2010-02-06 17:35:01 +0000 | [diff] [blame] | 360 | if (sel->sy < sel->ey) { |
| 361 | /* start line < end line -- downward selection. */ |
| 362 | if (py < sel->sy || py > sel->ey) |
| 363 | return (0); |
| 364 | } else if (sel->sy > sel->ey) { |
| 365 | /* start line > end line -- upward selection. */ |
| 366 | if (py > sel->sy || py < sel->ey) |
| 367 | return (0); |
| 368 | } else { |
| 369 | /* starting line == ending line. */ |
| 370 | if (py != sel->sy) |
| 371 | return (0); |
| 372 | } |
| 373 | |
| 374 | /* |
| 375 | * Need to include the selection start row, but not the cursor |
| 376 | * row, which means the selection changes depending on which |
| 377 | * one is on the left. |
| 378 | */ |
| 379 | if (sel->ex < sel->sx) { |
| 380 | /* Cursor (ex) is on the left. */ |
Nicholas Marriott | 20ed20e | 2010-12-11 17:56:01 +0000 | [diff] [blame] | 381 | if (px < sel->ex) |
Nicholas Marriott | 3ef3802 | 2010-02-06 17:35:01 +0000 | [diff] [blame] | 382 | return (0); |
| 383 | |
| 384 | if (px > sel->sx) |
| 385 | return (0); |
| 386 | } else { |
| 387 | /* Selection start (sx) is on the left. */ |
| 388 | if (px < sel->sx) |
| 389 | return (0); |
| 390 | |
Nicholas Marriott | 20ed20e | 2010-12-11 17:56:01 +0000 | [diff] [blame] | 391 | if (px > sel->ex) |
Nicholas Marriott | 3ef3802 | 2010-02-06 17:35:01 +0000 | [diff] [blame] | 392 | return (0); |
| 393 | } |
| 394 | } else { |
| 395 | /* |
| 396 | * Like emacs, keep the top-left-most character, and drop the |
| 397 | * bottom-right-most, regardless of copy direction. |
| 398 | */ |
| 399 | if (sel->sy < sel->ey) { |
| 400 | /* starting line < ending line -- downward selection. */ |
| 401 | if (py < sel->sy || py > sel->ey) |
| 402 | return (0); |
| 403 | |
nicm | 29d20a5 | 2014-08-11 22:18:16 +0000 | [diff] [blame] | 404 | if (py == sel->sy && px < sel->sx) |
nicm | 4e956d5 | 2014-09-01 21:50:18 +0000 | [diff] [blame] | 405 | return (0); |
nicm | 29d20a5 | 2014-08-11 22:18:16 +0000 | [diff] [blame] | 406 | |
nicm | 34c0807 | 2019-01-15 09:56:31 +0000 | [diff] [blame] | 407 | if (sel->modekeys == MODEKEY_EMACS) |
| 408 | xx = (sel->ex == 0 ? 0 : sel->ex - 1); |
| 409 | else |
| 410 | xx = sel->ex; |
| 411 | if (py == sel->ey && px > xx) |
Nicholas Marriott | 3ef3802 | 2010-02-06 17:35:01 +0000 | [diff] [blame] | 412 | return (0); |
| 413 | } else if (sel->sy > sel->ey) { |
| 414 | /* starting line > ending line -- upward selection. */ |
| 415 | if (py > sel->sy || py < sel->ey) |
| 416 | return (0); |
| 417 | |
nicm | 29d20a5 | 2014-08-11 22:18:16 +0000 | [diff] [blame] | 418 | if (py == sel->ey && px < sel->ex) |
| 419 | return (0); |
| 420 | |
| 421 | if (sel->modekeys == MODEKEY_EMACS) |
| 422 | xx = sel->sx - 1; |
| 423 | else |
| 424 | xx = sel->sx; |
nicm | 13a0b6b | 2017-02-08 16:45:18 +0000 | [diff] [blame] | 425 | if (py == sel->sy && (sel->sx == 0 || px > xx)) |
Nicholas Marriott | 3ef3802 | 2010-02-06 17:35:01 +0000 | [diff] [blame] | 426 | return (0); |
| 427 | } else { |
| 428 | /* starting line == ending line. */ |
| 429 | if (py != sel->sy) |
| 430 | return (0); |
| 431 | |
| 432 | if (sel->ex < sel->sx) { |
| 433 | /* cursor (ex) is on the left */ |
nicm | 29d20a5 | 2014-08-11 22:18:16 +0000 | [diff] [blame] | 434 | if (sel->modekeys == MODEKEY_EMACS) |
| 435 | xx = sel->sx - 1; |
| 436 | else |
| 437 | xx = sel->sx; |
| 438 | if (px > xx || px < sel->ex) |
Nicholas Marriott | 3ef3802 | 2010-02-06 17:35:01 +0000 | [diff] [blame] | 439 | return (0); |
| 440 | } else { |
| 441 | /* selection start (sx) is on the left */ |
nicm | 34c0807 | 2019-01-15 09:56:31 +0000 | [diff] [blame] | 442 | if (sel->modekeys == MODEKEY_EMACS) |
| 443 | xx = (sel->ex == 0 ? 0 : sel->ex - 1); |
| 444 | else |
| 445 | xx = sel->ex; |
| 446 | if (px < sel->sx || px > xx) |
Nicholas Marriott | 3ef3802 | 2010-02-06 17:35:01 +0000 | [diff] [blame] | 447 | return (0); |
| 448 | } |
| 449 | } |
Nicholas Marriott | 35876ea | 2009-06-01 22:58:49 +0000 | [diff] [blame] | 450 | } |
| 451 | |
Nicholas Marriott | 35876ea | 2009-06-01 22:58:49 +0000 | [diff] [blame] | 452 | return (1); |
| 453 | } |
Nicholas Marriott | 8903c1f | 2013-02-05 11:08:59 +0000 | [diff] [blame] | 454 | |
nicm | 4160df4 | 2016-10-12 13:24:07 +0000 | [diff] [blame] | 455 | /* Get selected grid cell. */ |
| 456 | void |
| 457 | screen_select_cell(struct screen *s, struct grid_cell *dst, |
| 458 | const struct grid_cell *src) |
| 459 | { |
nicm | 82776c4 | 2018-07-31 11:49:26 +0000 | [diff] [blame] | 460 | if (s->sel == NULL || s->sel->hidden) |
nicm | 4160df4 | 2016-10-12 13:24:07 +0000 | [diff] [blame] | 461 | return; |
| 462 | |
nicm | 82776c4 | 2018-07-31 11:49:26 +0000 | [diff] [blame] | 463 | memcpy(dst, &s->sel->cell, sizeof *dst); |
nicm | 4160df4 | 2016-10-12 13:24:07 +0000 | [diff] [blame] | 464 | |
| 465 | utf8_copy(&dst->data, &src->data); |
| 466 | dst->attr = dst->attr & ~GRID_ATTR_CHARSET; |
| 467 | dst->attr |= src->attr & GRID_ATTR_CHARSET; |
| 468 | dst->flags = src->flags; |
| 469 | } |
| 470 | |
Nicholas Marriott | 8903c1f | 2013-02-05 11:08:59 +0000 | [diff] [blame] | 471 | /* Reflow wrapped lines. */ |
nicm | e454018 | 2016-10-11 13:21:59 +0000 | [diff] [blame] | 472 | static void |
Nicholas Marriott | 9b7e18f | 2013-03-21 16:12:10 +0000 | [diff] [blame] | 473 | screen_reflow(struct screen *s, u_int new_x) |
Nicholas Marriott | 8903c1f | 2013-02-05 11:08:59 +0000 | [diff] [blame] | 474 | { |
nicm | ffa4d48 | 2019-04-02 08:45:32 +0000 | [diff] [blame] | 475 | u_int cx = s->cx, cy = s->grid->hsize + s->cy, wx, wy; |
nicm | 9ee1a8f | 2019-03-20 19:19:11 +0000 | [diff] [blame] | 476 | struct timeval start, tv; |
| 477 | |
| 478 | gettimeofday(&start, NULL); |
| 479 | |
nicm | ffa4d48 | 2019-04-02 08:45:32 +0000 | [diff] [blame] | 480 | grid_wrap_position(s->grid, cx, cy, &wx, &wy); |
| 481 | log_debug("%s: cursor %u,%u is %u,%u", __func__, cx, cy, wx, wy); |
nicm | 9ee1a8f | 2019-03-20 19:19:11 +0000 | [diff] [blame] | 482 | |
| 483 | grid_reflow(s->grid, new_x); |
| 484 | |
nicm | ffa4d48 | 2019-04-02 08:45:32 +0000 | [diff] [blame] | 485 | grid_unwrap_position(s->grid, &cx, &cy, wx, wy); |
nicm | 9ee1a8f | 2019-03-20 19:19:11 +0000 | [diff] [blame] | 486 | log_debug("%s: new cursor is %u,%u", __func__, cx, cy); |
| 487 | |
| 488 | if (cy >= s->grid->hsize) { |
| 489 | s->cx = cx; |
| 490 | s->cy = cy - s->grid->hsize; |
| 491 | } else { |
| 492 | s->cx = 0; |
| 493 | s->cy = 0; |
| 494 | } |
| 495 | |
| 496 | gettimeofday(&tv, NULL); |
| 497 | timersub(&tv, &start, &tv); |
| 498 | |
| 499 | log_debug("%s: reflow took %llu.%06u seconds", __func__, |
| 500 | (unsigned long long)tv.tv_sec, (u_int)tv.tv_usec); |
Nicholas Marriott | 8903c1f | 2013-02-05 11:08:59 +0000 | [diff] [blame] | 501 | } |