diff options
Diffstat (limited to 'popup.c')
-rw-r--r-- | popup.c | 157 |
1 files changed, 119 insertions, 38 deletions
@@ -30,9 +30,15 @@ struct popup_data { struct client *c; struct cmdq_item *item; int flags; + char *title; + + struct grid_cell border_cell; + enum box_lines border_lines; struct screen s; + struct grid_cell defaults; struct colour_palette palette; + struct job *job; struct input_ctx *ictx; int status; @@ -116,7 +122,7 @@ popup_set_client_cb(struct tty_ctx *ttyctx, struct client *c) ttyctx->wsx = c->tty.sx; ttyctx->wsy = c->tty.sy; - if (pd->flags & POPUP_NOBORDER) { + if (pd->border_lines == BOX_LINES_NONE) { ttyctx->xoff = ttyctx->rxoff = pd->px; ttyctx->yoff = ttyctx->ryoff = pd->py; } else { @@ -132,6 +138,7 @@ popup_init_ctx_cb(struct screen_write_ctx *ctx, struct tty_ctx *ttyctx) { struct popup_data *pd = ctx->arg; + memcpy(&ttyctx->defaults, &pd->defaults, sizeof ttyctx->defaults); ttyctx->palette = &pd->palette; ttyctx->redraw_cb = popup_redraw_cb; ttyctx->set_client_cb = popup_set_client_cb; @@ -146,7 +153,7 @@ popup_mode_cb(__unused struct client *c, void *data, u_int *cx, u_int *cy) if (pd->md != NULL) return (menu_mode_cb(c, pd->md, cx, cy)); - if (pd->flags & POPUP_NOBORDER) { + if (pd->border_lines == BOX_LINES_NONE) { *cx = pd->px + pd->s.cx; *cy = pd->py + pd->s.cy; } else { @@ -156,18 +163,49 @@ popup_mode_cb(__unused struct client *c, void *data, u_int *cx, u_int *cy) return (&pd->s); } -static int -popup_check_cb(struct client *c, void *data, u_int px, u_int py) +/* Return parts of the input range which are not obstructed by the popup. */ +static void +popup_check_cb(struct client* c, void *data, u_int px, u_int py, u_int nx, + struct overlay_ranges *r) { struct popup_data *pd = data; + struct overlay_ranges or[2]; + u_int i, j, k = 0; - if (pd->md != NULL && menu_check_cb(c, pd->md, px, py) == 0) - return (0); - if (px < pd->px || px > pd->px + pd->sx - 1) - return (1); - if (py < pd->py || py > pd->py + pd->sy - 1) - return (1); - return (0); + if (pd->md != NULL) { + /* Check each returned range for the menu against the popup. */ + menu_check_cb(c, pd->md, px, py, nx, r); + for (i = 0; i < 2; i++) { + server_client_overlay_range(pd->px, pd->py, pd->sx, + pd->sy, r->px[i], py, r->nx[i], &or[i]); + } + + /* + * or has up to OVERLAY_MAX_RANGES non-overlapping ranges, + * ordered from left to right. Collect them in the output. + */ + for (i = 0; i < 2; i++) { + /* Each or[i] only has 2 ranges. */ + for (j = 0; j < 2; j++) { + if (or[i].nx[j] > 0) { + r->px[k] = or[i].px[j]; + r->nx[k] = or[i].nx[j]; + k++; + } + } + } + + /* Zero remaining ranges if any. */ + for (i = k; i < OVERLAY_MAX_RANGES; i++) { + r->px[i] = 0; + r->nx[i] = 0; + } + + return; + } + + server_client_overlay_range(pd->px, pd->py, pd->sx, pd->sy, px, py, nx, + r); } static void @@ -179,26 +217,29 @@ popup_draw_cb(struct client *c, void *data, struct screen_redraw_ctx *rctx) struct screen_write_ctx ctx; u_int i, px = pd->px, py = pd->py; struct colour_palette *palette = &pd->palette; - struct grid_cell gc; + struct grid_cell defaults; screen_init(&s, pd->sx, pd->sy, 0); screen_write_start(&ctx, &s); screen_write_clearscreen(&ctx, 8); - if (pd->flags & POPUP_NOBORDER) { + if (pd->border_lines == BOX_LINES_NONE) { screen_write_cursormove(&ctx, 0, 0, 0); screen_write_fast_copy(&ctx, &pd->s, 0, 0, pd->sx, pd->sy); } else if (pd->sx > 2 && pd->sy > 2) { - screen_write_box(&ctx, pd->sx, pd->sy); + screen_write_box(&ctx, pd->sx, pd->sy, pd->border_lines, + &pd->border_cell, pd->title); screen_write_cursormove(&ctx, 1, 1, 0); screen_write_fast_copy(&ctx, &pd->s, 0, 0, pd->sx - 2, pd->sy - 2); } screen_write_stop(&ctx); - memcpy(&gc, &grid_default_cell, sizeof gc); - gc.fg = pd->palette.fg; - gc.bg = pd->palette.bg; + memcpy(&defaults, &pd->defaults, sizeof defaults); + if (defaults.fg == 8) + defaults.fg = palette->fg; + if (defaults.bg == 8) + defaults.bg = palette->bg; if (pd->md != NULL) { c->overlay_check = menu_check_cb; @@ -207,8 +248,10 @@ popup_draw_cb(struct client *c, void *data, struct screen_redraw_ctx *rctx) c->overlay_check = NULL; c->overlay_data = NULL; } - for (i = 0; i < pd->sy; i++) - tty_draw_line(tty, &s, 0, i, pd->sx, px, py + i, &gc, palette); + for (i = 0; i < pd->sy; i++) { + tty_draw_line(tty, &s, 0, i, pd->sx, px, py + i, &defaults, + palette); + } if (pd->md != NULL) { c->overlay_check = NULL; c->overlay_data = NULL; @@ -245,6 +288,7 @@ popup_free_cb(struct client *c, void *data) screen_free(&pd->s); colour_palette_free(&pd->palette); + free(pd->title); free(pd); } @@ -278,7 +322,7 @@ popup_resize_cb(__unused struct client *c, void *data) pd->px = pd->ppx; /* Avoid zero size screens. */ - if (pd->flags & POPUP_NOBORDER) { + if (pd->border_lines == BOX_LINES_NONE) { screen_resize(&pd->s, pd->sx, pd->sy, 0); if (pd->job != NULL) job_resize(pd->job, pd->sx, pd->sy ); @@ -404,7 +448,7 @@ popup_handle_drag(struct client *c, struct popup_data *pd, pd->ppy = py; server_redraw_client(c); } else if (pd->dragging == SIZE) { - if (pd->flags & POPUP_NOBORDER) { + if (pd->border_lines == BOX_LINES_NONE) { if (m->x < pd->px + 1) return; if (m->y < pd->py + 1) @@ -420,7 +464,7 @@ popup_handle_drag(struct client *c, struct popup_data *pd, pd->psx = pd->sx; pd->psy = pd->sy; - if (pd->flags & POPUP_NOBORDER) { + if (pd->border_lines == BOX_LINES_NONE) { screen_resize(&pd->s, pd->sx, pd->sy, 0); if (pd->job != NULL) job_resize(pd->job, pd->sx, pd->sy); @@ -464,11 +508,11 @@ popup_key_cb(struct client *c, void *data, struct key_event *event) m->x > pd->px + pd->sx - 1 || m->y < pd->py || m->y > pd->py + pd->sy - 1) { - if (MOUSE_BUTTONS(m->b) == 2) + if (MOUSE_BUTTONS(m->b) == MOUSE_BUTTON_3) goto menu; return (0); } - if (~pd->flags & POPUP_NOBORDER) { + if (pd->border_lines != BOX_LINES_NONE) { if (m->x == pd->px) border = LEFT; else if (m->x == pd->px + pd->sx - 1) @@ -479,16 +523,16 @@ popup_key_cb(struct client *c, void *data, struct key_event *event) border = BOTTOM; } if ((m->b & MOUSE_MASK_MODIFIERS) == 0 && - MOUSE_BUTTONS(m->b) == 2 && + MOUSE_BUTTONS(m->b) == MOUSE_BUTTON_3 && (border == LEFT || border == TOP)) goto menu; if (((m->b & MOUSE_MASK_MODIFIERS) == MOUSE_MASK_META) || border != NONE) { if (!MOUSE_DRAG(m->b)) goto out; - if (MOUSE_BUTTONS(m->lb) == 0) + if (MOUSE_BUTTONS(m->lb) == MOUSE_BUTTON_1) pd->dragging = MOVE; - else if (MOUSE_BUTTONS(m->lb) == 2) + else if (MOUSE_BUTTONS(m->lb) == MOUSE_BUTTON_3) pd->dragging = SIZE; pd->dx = m->lx - pd->px; pd->dy = m->ly - pd->py; @@ -502,7 +546,7 @@ popup_key_cb(struct client *c, void *data, struct key_event *event) if (pd->job != NULL) { if (KEYC_IS_MOUSE(event->key)) { /* Must be inside, checked already. */ - if (pd->flags & POPUP_NOBORDER) { + if (pd->border_lines == BOX_LINES_NONE) { px = m->x - pd->px; py = m->y - pd->py; } else { @@ -521,10 +565,10 @@ popup_key_cb(struct client *c, void *data, struct key_event *event) menu: pd->menu = menu_create(""); if (pd->flags & POPUP_INTERNAL) { - menu_add_items(pd->menu, popup_internal_menu_items, NULL, NULL, + menu_add_items(pd->menu, popup_internal_menu_items, NULL, c, NULL); } else - menu_add_items(pd->menu, popup_menu_items, NULL, NULL, NULL); + menu_add_items(pd->menu, popup_menu_items, NULL, c, NULL); if (m->x >= (pd->menu->width + 4) / 2) x = m->x - (pd->menu->width + 4) / 2; else @@ -588,14 +632,25 @@ popup_job_complete_cb(struct job *job) } 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) +popup_display(int flags, enum box_lines lines, struct cmdq_item *item, u_int px, + u_int py, u_int sx, u_int sy, struct environ *env, const char *shellcmd, + int argc, char **argv, const char *cwd, const char *title, struct client *c, + struct session *s, const char* style, const char* border_style, + popup_close_cb cb, void *arg) { struct popup_data *pd; u_int jx, jy; + struct options *o; + struct style sytmp; + + if (s != NULL) + o = s->curw->window->options; + else + o = c->session->curw->window->options; - if (flags & POPUP_NOBORDER) { + if (lines == BOX_LINES_DEFAULT) + lines = options_get_number(o, "popup-border-lines"); + if (lines == BOX_LINES_NONE) { if (sx < 1 || sy < 1) return (-1); jx = sx; @@ -612,6 +667,8 @@ popup_display(int flags, struct cmdq_item *item, u_int px, u_int py, u_int sx, pd = xcalloc(1, sizeof *pd); pd->item = item; pd->flags = flags; + if (title != NULL) + pd->title = xstrdup(title); pd->c = c; pd->c->references++; @@ -620,10 +677,33 @@ popup_display(int flags, struct cmdq_item *item, u_int px, u_int py, u_int sx, pd->arg = arg; pd->status = 128 + SIGHUP; - screen_init(&pd->s, sx - 2, sy - 2, 0); + pd->border_lines = lines; + memcpy(&pd->border_cell, &grid_default_cell, sizeof pd->border_cell); + style_apply(&pd->border_cell, o, "popup-border-style", NULL); + if (border_style != NULL) { + style_set(&sytmp, &grid_default_cell); + if (style_parse(&sytmp, &pd->border_cell, border_style) == 0) { + pd->border_cell.fg = sytmp.gc.fg; + pd->border_cell.bg = sytmp.gc.bg; + } + } + pd->border_cell.attr = 0; + + screen_init(&pd->s, jx, jy, 0); colour_palette_init(&pd->palette); colour_palette_from_option(&pd->palette, global_w_options); + memcpy(&pd->defaults, &grid_default_cell, sizeof pd->defaults); + style_apply(&pd->defaults, o, "popup-style", NULL); + if (style != NULL) { + style_set(&sytmp, &grid_default_cell); + if (style_parse(&sytmp, &pd->defaults, style) == 0) { + pd->defaults.fg = sytmp.gc.fg; + pd->defaults.bg = sytmp.gc.bg; + } + } + pd->defaults.attr = 0; + pd->px = px; pd->py = py; pd->sx = sx; @@ -634,7 +714,7 @@ popup_display(int flags, struct cmdq_item *item, u_int px, u_int py, u_int sx, pd->psx = sx; pd->psy = sy; - pd->job = job_run(shellcmd, argc, argv, s, cwd, + pd->job = job_run(shellcmd, argc, argv, env, s, cwd, popup_job_update_cb, popup_job_complete_cb, NULL, pd, JOB_NOWAIT|JOB_PTY|JOB_KEEPWRITE, jx, jy); pd->ictx = input_init(NULL, job_get_event(pd->job), &pd->palette); @@ -723,8 +803,9 @@ popup_editor(struct client *c, const char *buf, size_t len, py = (c->tty.sy / 2) - (sy / 2); xasprintf(&cmd, "%s %s", editor, path); - if (popup_display(POPUP_INTERNAL|POPUP_CLOSEEXIT, NULL, px, py, sx, sy, - cmd, 0, NULL, _PATH_TMP, c, NULL, popup_editor_close_cb, pe) != 0) { + if (popup_display(POPUP_INTERNAL|POPUP_CLOSEEXIT, BOX_LINES_DEFAULT, + NULL, px, py, sx, sy, NULL, cmd, 0, NULL, _PATH_TMP, NULL, c, NULL, + NULL, NULL, popup_editor_close_cb, pe) != 0) { popup_editor_free(pe); free(cmd); return (-1); |