tmux  3.2a
About: tmux is a terminal multiplexer that lets you switch easily between several programs in one terminal.
  Fossies Dox: tmux-3.2a.tar.gz  ("unofficial" and yet experimental doxygen-generated source code documentation)  

popup.c
Go to the documentation of this file.
1 /* $OpenBSD$ */
2 
3 /*
4  * Copyright (c) 2020 Nicholas Marriott <nicholas.marriott@gmail.com>
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 #include <sys/wait.h>
21 
22 #include <signal.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <unistd.h>
26 
27 #include "tmux.h"
28 
29 struct popup_data {
30  struct client *c;
31  struct cmdq_item *item;
32  int flags;
33 
34  struct screen s;
35  struct job *job;
36  struct input_ctx *ictx;
37  int status;
39  void *arg;
40 
41  u_int px;
42  u_int py;
43  u_int sx;
44  u_int sy;
45 
46  enum { OFF, MOVE, SIZE } dragging;
47  u_int dx;
48  u_int dy;
49 
50  u_int lx;
51  u_int ly;
52  u_int lb;
53 };
54 
55 struct popup_editor {
56  char *path;
58  void *arg;
59 };
60 
61 static void
62 popup_redraw_cb(const struct tty_ctx *ttyctx)
63 {
64  struct popup_data *pd = ttyctx->arg;
65 
67 }
68 
69 static int
70 popup_set_client_cb(struct tty_ctx *ttyctx, struct client *c)
71 {
72  struct popup_data *pd = ttyctx->arg;
73 
74  if (c != pd->c)
75  return (0);
76  if (pd->c->flags & CLIENT_REDRAWOVERLAY)
77  return (0);
78 
79  ttyctx->bigger = 0;
80  ttyctx->wox = 0;
81  ttyctx->woy = 0;
82  ttyctx->wsx = c->tty.sx;
83  ttyctx->wsy = c->tty.sy;
84 
85  ttyctx->xoff = ttyctx->rxoff = pd->px + 1;
86  ttyctx->yoff = ttyctx->ryoff = pd->py + 1;
87 
88  return (1);
89 }
90 
91 static void
92 popup_init_ctx_cb(struct screen_write_ctx *ctx, struct tty_ctx *ttyctx)
93 {
94  struct popup_data *pd = ctx->arg;
95 
96  ttyctx->redraw_cb = popup_redraw_cb;
98  ttyctx->arg = pd;
99 }
100 
101 static struct screen *
102 popup_mode_cb(struct client *c, u_int *cx, u_int *cy)
103 {
104  struct popup_data *pd = c->overlay_data;
105 
106  *cx = pd->px + 1 + pd->s.cx;
107  *cy = pd->py + 1 + pd->s.cy;
108  return (&pd->s);
109 }
110 
111 static int
112 popup_check_cb(struct client *c, u_int px, u_int py)
113 {
114  struct popup_data *pd = c->overlay_data;
115 
116  if (px < pd->px || px > pd->px + pd->sx - 1)
117  return (1);
118  if (py < pd->py || py > pd->py + pd->sy - 1)
119  return (1);
120  return (0);
121 }
122 
123 static void
125 {
126  struct popup_data *pd = c->overlay_data;
127  struct tty *tty = &c->tty;
128  struct screen s;
129  struct screen_write_ctx ctx;
130  u_int i, px = pd->px, py = pd->py;
131 
132  screen_init(&s, pd->sx, pd->sy, 0);
133  screen_write_start(&ctx, &s);
134  screen_write_clearscreen(&ctx, 8);
135  screen_write_box(&ctx, pd->sx, pd->sy);
136  screen_write_cursormove(&ctx, 1, 1, 0);
137  screen_write_fast_copy(&ctx, &pd->s, 0, 0, pd->sx - 2, pd->sy - 2);
138  screen_write_stop(&ctx);
139 
140  c->overlay_check = NULL;
141  for (i = 0; i < pd->sy; i++){
142  tty_draw_line(tty, &s, 0, i, pd->sx, px, py + i,
143  &grid_default_cell, NULL);
144  }
146 }
147 
148 static void
150 {
151  struct popup_data *pd = c->overlay_data;
152  struct cmdq_item *item = pd->item;
153 
154  if (pd->cb != NULL)
155  pd->cb(pd->status, pd->arg);
156 
157  if (item != NULL) {
158  if (cmdq_get_client(item) != NULL &&
159  cmdq_get_client(item)->session == NULL)
160  cmdq_get_client(item)->retval = pd->status;
161  cmdq_continue(item);
162  }
163  server_client_unref(pd->c);
164 
165  if (pd->job != NULL)
166  job_free(pd->job);
167  input_free(pd->ictx);
168 
169  screen_free(&pd->s);
170  free(pd);
171 }
172 
173 static void
174 popup_handle_drag(struct client *c, struct popup_data *pd,
175  struct mouse_event *m)
176 {
177  u_int px, py;
178 
179  if (!MOUSE_DRAG(m->b))
180  pd->dragging = OFF;
181  else if (pd->dragging == MOVE) {
182  if (m->x < pd->dx)
183  px = 0;
184  else if (m->x - pd->dx + pd->sx > c->tty.sx)
185  px = c->tty.sx - pd->sx;
186  else
187  px = m->x - pd->dx;
188  if (m->y < pd->dy)
189  py = 0;
190  else if (m->y - pd->dy + pd->sy > c->tty.sy)
191  py = c->tty.sy - pd->sy;
192  else
193  py = m->y - pd->dy;
194  pd->px = px;
195  pd->py = py;
196  pd->dx = m->x - pd->px;
197  pd->dy = m->y - pd->py;
199  } else if (pd->dragging == SIZE) {
200  if (m->x < pd->px + 3)
201  return;
202  if (m->y < pd->py + 3)
203  return;
204  pd->sx = m->x - pd->px;
205  pd->sy = m->y - pd->py;
206 
207  screen_resize(&pd->s, pd->sx - 2, pd->sy - 2, 0);
208  if (pd->job != NULL)
209  job_resize(pd->job, pd->sx - 2, pd->sy - 2);
211  }
212 }
213 
214 static int
215 popup_key_cb(struct client *c, struct key_event *event)
216 {
217  struct popup_data *pd = c->overlay_data;
218  struct mouse_event *m = &event->m;
219  const char *buf;
220  size_t len;
221 
222  if (KEYC_IS_MOUSE(event->key)) {
223  if (pd->dragging != OFF) {
224  popup_handle_drag(c, pd, m);
225  goto out;
226  }
227  if (m->x < pd->px ||
228  m->x > pd->px + pd->sx - 1 ||
229  m->y < pd->py ||
230  m->y > pd->py + pd->sy - 1) {
231  if (MOUSE_BUTTONS (m->b) == 1)
232  return (1);
233  return (0);
234  }
235  if ((m->b & MOUSE_MASK_META) ||
236  m->x == pd->px ||
237  m->x == pd->px + pd->sx - 1 ||
238  m->y == pd->py ||
239  m->y == pd->py + pd->sy - 1) {
240  if (!MOUSE_DRAG(m->b))
241  goto out;
242  if (MOUSE_BUTTONS(m->lb) == 0)
243  pd->dragging = MOVE;
244  else if (MOUSE_BUTTONS(m->lb) == 2)
245  pd->dragging = SIZE;
246  pd->dx = m->lx - pd->px;
247  pd->dy = m->ly - pd->py;
248  goto out;
249  }
250  }
251 
252  if ((((pd->flags & (POPUP_CLOSEEXIT|POPUP_CLOSEEXITZERO)) == 0) ||
253  pd->job == NULL) &&
254  (event->key == '\033' || event->key == '\003'))
255  return (1);
256  if (pd->job != NULL) {
257  if (KEYC_IS_MOUSE(event->key)) {
258  /* Must be inside, checked already. */
259  if (!input_key_get_mouse(&pd->s, m, m->x - pd->px - 1,
260  m->y - pd->py - 1, &buf, &len))
261  return (0);
262  bufferevent_write(job_get_event(pd->job), buf, len);
263  return (0);
264  }
265  input_key(&pd->s, job_get_event(pd->job), event->key);
266  }
267  return (0);
268 
269 out:
270  pd->lx = m->x;
271  pd->ly = m->y;
272  pd->lb = m->b;
273  return (0);
274 }
275 
276 static void
278 {
279  struct popup_data *pd = job_get_data(job);
280  struct evbuffer *evb = job_get_event(job)->input;
281  struct client *c = pd->c;
282  struct screen *s = &pd->s;
283  void *data = EVBUFFER_DATA(evb);
284  size_t size = EVBUFFER_LENGTH(evb);
285 
286  if (size == 0)
287  return;
288 
289  c->overlay_check = NULL;
290  c->tty.flags &= ~~TTY_FREEZE;
291 
292  input_parse_screen(pd->ictx, s, popup_init_ctx_cb, pd, data, size);
293 
294  c->tty.flags |= TTY_FREEZE;
296 
297  evbuffer_drain(evb, size);
298 }
299 
300 static void
302 {
303  struct popup_data *pd = job_get_data(job);
304  int status;
305 
306  status = job_get_status(pd->job);
307  if (WIFEXITED(status))
308  pd->status = WEXITSTATUS(status);
309  else if (WIFSIGNALED(status))
310  pd->status = WTERMSIG(status);
311  else
312  pd->status = 0;
313  pd->job = NULL;
314 
315  if ((pd->flags & POPUP_CLOSEEXIT) ||
316  ((pd->flags & POPUP_CLOSEEXITZERO) && pd->status == 0))
318 }
319 
320 int
321 popup_display(int flags, struct cmdq_item *item, u_int px, u_int py, u_int sx,
322  u_int sy, const char *shellcmd, int argc, char **argv, const char *cwd,
323  struct client *c, struct session *s, popup_close_cb cb, void *arg)
324 {
325  struct popup_data *pd;
326 
327  if (sx < 3 || sy < 3)
328  return (-1);
329  if (c->tty.sx < sx || c->tty.sy < sy)
330  return (-1);
331 
332  pd = xcalloc(1, sizeof *pd);
333  pd->item = item;
334  pd->flags = flags;
335 
336  pd->c = c;
337  pd->c->references++;
338 
339  pd->cb = cb;
340  pd->arg = arg;
341  pd->status = 128 + SIGHUP;
342 
343  screen_init(&pd->s, sx - 2, sy - 2, 0);
344 
345  pd->px = px;
346  pd->py = py;
347  pd->sx = sx;
348  pd->sy = sy;
349 
350  pd->job = job_run(shellcmd, argc, argv, s, cwd,
352  JOB_NOWAIT|JOB_PTY|JOB_KEEPWRITE, pd->sx - 2, pd->sy - 2);
353  pd->ictx = input_init(NULL, job_get_event(pd->job));
354 
357  return (0);
358 }
359 
360 static void
362 {
363  unlink(pe->path);
364  free(pe->path);
365  free(pe);
366 }
367 
368 static void
370 {
371  struct popup_editor *pe = arg;
372  FILE *f;
373  char *buf = NULL;
374  off_t len = 0;
375 
376  if (status != 0) {
377  pe->cb(NULL, 0, pe->arg);
378  popup_editor_free(pe);
379  return;
380  }
381 
382  f = fopen(pe->path, "r");
383  if (f != NULL) {
384  fseeko(f, 0, SEEK_END);
385  len = ftello(f);
386  fseeko(f, 0, SEEK_SET);
387 
388  if (len == 0 ||
389  (uintmax_t)len > (uintmax_t)SIZE_MAX ||
390  (buf = malloc(len)) == NULL ||
391  fread(buf, len, 1, f) != 1) {
392  free(buf);
393  buf = NULL;
394  len = 0;
395  }
396  fclose(f);
397  }
398  pe->cb(buf, len, pe->arg); /* callback now owns buffer */
399  popup_editor_free(pe);
400 }
401 
402 int
403 popup_editor(struct client *c, const char *buf, size_t len,
404  popup_finish_edit_cb cb, void *arg)
405 {
406  struct popup_editor *pe;
407  int fd;
408  FILE *f;
409  char *cmd;
410  char path[] = _PATH_TMP "tmux.XXXXXXXX";
411  const char *editor;
412  u_int px, py, sx, sy;
413 
414  editor = options_get_string(global_options, "editor");
415  if (*editor == '\0')
416  return (-1);
417 
418  fd = mkstemp(path);
419  if (fd == -1)
420  return (-1);
421  f = fdopen(fd, "w");
422  if (fwrite(buf, len, 1, f) != 1) {
423  fclose(f);
424  return (-1);
425  }
426  fclose(f);
427 
428  pe = xcalloc(1, sizeof *pe);
429  pe->path = xstrdup(path);
430  pe->cb = cb;
431  pe->arg = arg;
432 
433  sx = c->tty.sx * 9 / 10;
434  sy = c->tty.sy * 9 / 10;
435  px = (c->tty.sx / 2) - (sx / 2);
436  py = (c->tty.sy / 2) - (sy / 2);
437 
438  xasprintf(&cmd, "%s %s", editor, path);
439  if (popup_display(POPUP_CLOSEEXIT, NULL, px, py, sx, sy, cmd, 0, NULL,
440  _PATH_TMP, c, NULL, popup_editor_close_cb, pe) != 0) {
441  popup_editor_free(pe);
442  free(cmd);
443  return (-1);
444  }
445  free(cmd);
446  return (0);
447 }
struct client * cmdq_get_client(struct cmdq_item *item)
Definition: cmd-queue.c:150
void cmdq_continue(struct cmdq_item *item)
Definition: cmd-queue.c:434
#define _PATH_TMP
Definition: compat.h:102
#define __unused
Definition: compat.h:60
const struct grid_cell grid_default_cell
Definition: grid.c:39
int input_key(struct screen *s, struct bufferevent *bev, key_code key)
Definition: input-keys.c:417
int input_key_get_mouse(struct screen *s, struct mouse_event *m, u_int x, u_int y, const char **rbuf, size_t *rlen)
Definition: input-keys.c:557
void input_parse_screen(struct input_ctx *ictx, struct screen *s, screen_write_init_ctx_cb cb, void *arg, u_char *buf, size_t len)
Definition: input.c:983
struct input_ctx * input_init(struct window_pane *wp, struct bufferevent *bev)
Definition: input.c:800
void input_free(struct input_ctx *ictx)
Definition: input.c:823
void * job_get_data(struct job *job)
Definition: job.c:332
void job_resize(struct job *job, u_int sx, u_int sy)
Definition: job.c:226
void job_free(struct job *job)
Definition: job.c:204
int job_get_status(struct job *job)
Definition: job.c:325
struct bufferevent * job_get_event(struct job *job)
Definition: job.c:339
const char * options_get_string(struct options *oo, const char *name)
Definition: options.c:686
static void popup_editor_close_cb(int status, void *arg)
Definition: popup.c:369
static struct screen * popup_mode_cb(struct client *c, u_int *cx, u_int *cy)
Definition: popup.c:102
static void popup_draw_cb(struct client *c, struct screen_redraw_ctx *ctx0)
Definition: popup.c:124
static int popup_key_cb(struct client *c, struct key_event *event)
Definition: popup.c:215
static int popup_set_client_cb(struct tty_ctx *ttyctx, struct client *c)
Definition: popup.c:70
static void popup_editor_free(struct popup_editor *pe)
Definition: popup.c:361
static void popup_job_complete_cb(struct job *job)
Definition: popup.c:301
static void popup_init_ctx_cb(struct screen_write_ctx *ctx, struct tty_ctx *ttyctx)
Definition: popup.c:92
int popup_display(int flags, struct cmdq_item *item, u_int px, u_int py, u_int sx, u_int sy, const char *shellcmd, int argc, char **argv, const char *cwd, struct client *c, struct session *s, popup_close_cb cb, void *arg)
Definition: popup.c:321
static void popup_job_update_cb(struct job *job)
Definition: popup.c:277
static void popup_free_cb(struct client *c)
Definition: popup.c:149
static int popup_check_cb(struct client *c, u_int px, u_int py)
Definition: popup.c:112
static void popup_handle_drag(struct client *c, struct popup_data *pd, struct mouse_event *m)
Definition: popup.c:174
int popup_editor(struct client *c, const char *buf, size_t len, popup_finish_edit_cb cb, void *arg)
Definition: popup.c:403
static void popup_redraw_cb(const struct tty_ctx *ttyctx)
Definition: popup.c:62
void screen_write_fast_copy(struct screen_write_ctx *ctx, struct screen *src, u_int px, u_int py, u_int nx, u_int ny)
Definition: screen-write.c:548
void screen_write_start(struct screen_write_ctx *ctx, struct screen *s)
Definition: screen-write.c:284
void screen_write_box(struct screen_write_ctx *ctx, u_int nx, u_int ny)
Definition: screen-write.c:672
void screen_write_cursormove(struct screen_write_ctx *ctx, int px, int py, int origin)
void screen_write_stop(struct screen_write_ctx *ctx)
Definition: screen-write.c:296
void screen_write_clearscreen(struct screen_write_ctx *ctx, u_int bg)
void screen_resize(struct screen *s, u_int sx, u_int sy, int reflow)
Definition: screen.c:276
void screen_init(struct screen *s, u_int sx, u_int sy, u_int hlimit)
Definition: screen.c:74
void screen_free(struct screen *s)
Definition: screen.c:122
void server_client_set_overlay(struct client *c, u_int delay, overlay_check_cb checkcb, overlay_mode_cb modecb, overlay_draw_cb drawcb, overlay_key_cb keycb, overlay_free_cb freecb, void *data)
Definition: server-client.c:90
void server_client_clear_overlay(struct client *c)
void server_client_unref(struct client *c)
void server_redraw_client(struct client *c)
Definition: server-fn.c:34
Definition: tmux.h:1608
int retval
Definition: tmux.h:1622
struct tty tty
Definition: tmux.h:1640
void * overlay_data
Definition: tmux.h:1757
int references
Definition: tmux.h:1746
overlay_check_cb overlay_check
Definition: tmux.h:1752
uint64_t flags
Definition: tmux.h:1703
Definition: cmd.c:212
Definition: job.c:42
key_code key
Definition: tmux.h:1267
u_int y
Definition: tmux.h:1247
u_int lx
Definition: tmux.h:1250
u_int b
Definition: tmux.h:1248
u_int x
Definition: tmux.h:1246
u_int ly
Definition: tmux.h:1251
u_int lb
Definition: tmux.h:1252
u_int py
Definition: popup.c:42
enum popup_data::@10 dragging
struct job * job
Definition: popup.c:35
u_int lb
Definition: popup.c:52
u_int lx
Definition: popup.c:50
popup_close_cb cb
Definition: popup.c:38
struct client * c
Definition: popup.c:30
u_int dy
Definition: popup.c:48
u_int px
Definition: popup.c:41
u_int dx
Definition: popup.c:47
void * arg
Definition: popup.c:39
struct screen s
Definition: popup.c:34
@ MOVE
Definition: popup.c:46
@ SIZE
Definition: popup.c:46
@ OFF
Definition: popup.c:46
u_int sx
Definition: popup.c:43
struct input_ctx * ictx
Definition: popup.c:36
int flags
Definition: popup.c:32
u_int ly
Definition: popup.c:51
struct cmdq_item * item
Definition: popup.c:31
int status
Definition: popup.c:37
u_int sy
Definition: popup.c:44
popup_finish_edit_cb cb
Definition: popup.c:57
char * path
Definition: popup.c:56
void * arg
Definition: popup.c:58
void * arg
Definition: tmux.h:857
struct screen * s
Definition: tmux.h:851
Definition: tmux.h:816
u_int cy
Definition: tmux.h:824
u_int cx
Definition: tmux.h:823
Definition: tmux.h:1179
Definition: tmux.h:1375
u_int rxoff
Definition: tmux.h:1402
u_int yoff
Definition: tmux.h:1401
u_int wsy
Definition: tmux.h:1419
tty_ctx_set_client_cb set_client_cb
Definition: tmux.h:1379
u_int wox
Definition: tmux.h:1416
u_int xoff
Definition: tmux.h:1400
u_int woy
Definition: tmux.h:1417
tty_ctx_redraw_cb redraw_cb
Definition: tmux.h:1378
u_int ryoff
Definition: tmux.h:1403
u_int wsx
Definition: tmux.h:1418
void * arg
Definition: tmux.h:1380
int bigger
Definition: tmux.h:1415
Definition: tmux.h:1304
u_int sx
Definition: tmux.h:1308
u_int sy
Definition: tmux.h:1309
int flags
Definition: tmux.h:1355
struct options * global_options
Definition: tmux.c:36
struct job * job_run(const char *, int, char **, struct session *, const char *, job_update_cb, job_complete_cb, job_free_cb, void *, int, int, int)
#define KEYC_IS_MOUSE(key)
Definition: tmux.h:144
#define JOB_KEEPWRITE
Definition: tmux.h:2100
void(* popup_finish_edit_cb)(char *, size_t, void *)
Definition: tmux.h:3081
void tty_draw_line(struct tty *, struct screen *, u_int, u_int, u_int, u_int, u_int, const struct grid_cell *, int *)
Definition: tty.c:1281
#define CLIENT_REDRAWOVERLAY
Definition: tmux.h:1679
#define POPUP_CLOSEEXITZERO
Definition: tmux.h:3079
#define MOUSE_DRAG(b)
Definition: tmux.h:1233
#define JOB_PTY
Definition: tmux.h:2101
#define TTY_FREEZE
Definition: tmux.h:1345
#define MOUSE_MASK_META
Definition: tmux.h:1221
#define JOB_NOWAIT
Definition: tmux.h:2099
#define POPUP_CLOSEEXIT
Definition: tmux.h:3078
#define MOUSE_BUTTONS(b)
Definition: tmux.h:1231
void(* popup_close_cb)(int, void *)
Definition: tmux.h:3080
enum window_copy_cmd_action(* f)(struct window_copy_cmd_state *)
Definition: window-copy.c:2248
int xasprintf(char **ret, const char *fmt,...)
Definition: xmalloc.c:109
void * xcalloc(size_t nmemb, size_t size)
Definition: xmalloc.c:41
char * xstrdup(const char *str)
Definition: xmalloc.c:89