Annotation of src/usr.bin/tmux/window-choose.c, Revision 1.22
1.22 ! nicm 1: /* $OpenBSD: window-choose.c,v 1.21 2012/07/10 11:53:01 nicm Exp $ */
1.1 nicm 2:
3: /*
4: * Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
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:
1.19 nicm 21: #include <ctype.h>
1.21 nicm 22: #include <stdlib.h>
1.1 nicm 23: #include <string.h>
24:
25: #include "tmux.h"
26:
27: struct screen *window_choose_init(struct window_pane *);
28: void window_choose_free(struct window_pane *);
29: void window_choose_resize(struct window_pane *, u_int, u_int);
1.16 nicm 30: void window_choose_key(struct window_pane *, struct session *, int);
1.1 nicm 31: void window_choose_mouse(
1.16 nicm 32: struct window_pane *, struct session *, struct mouse_event *);
1.1 nicm 33:
1.19 nicm 34: void window_choose_fire_callback(
35: struct window_pane *, struct window_choose_data *);
1.1 nicm 36: void window_choose_redraw_screen(struct window_pane *);
37: void window_choose_write_line(
1.13 nicm 38: struct window_pane *, struct screen_write_ctx *, u_int);
1.1 nicm 39:
40: void window_choose_scroll_up(struct window_pane *);
41: void window_choose_scroll_down(struct window_pane *);
42:
1.22 ! nicm 43: enum window_choose_input_type {
! 44: WINDOW_CHOOSE_NORMAL = -1,
! 45: WINDOW_CHOOSE_GOTO_ITEM,
! 46: };
! 47:
1.1 nicm 48: const struct window_mode window_choose_mode = {
49: window_choose_init,
50: window_choose_free,
51: window_choose_resize,
52: window_choose_key,
53: window_choose_mouse,
54: NULL,
55: };
56:
57: struct window_choose_mode_data {
58: struct screen screen;
59:
60: struct mode_key_data mdata;
61:
62: ARRAY_DECL(, struct window_choose_mode_item) list;
1.22 ! nicm 63: int width;
1.1 nicm 64: u_int top;
65: u_int selected;
1.22 ! nicm 66: enum window_choose_input_type input_type;
! 67: const char *input_prompt;
! 68: char *input_str;
1.1 nicm 69:
1.19 nicm 70: void (*callbackfn)(struct window_choose_data *);
71: void (*freefn)(struct window_choose_data *);
1.1 nicm 72: };
73:
1.22 ! nicm 74: int window_choose_index_key(int);
! 75: void window_choose_prompt_input(enum window_choose_input_type,
! 76: const char *, struct window_pane *, int);
1.11 nicm 77:
1.1 nicm 78: void
1.19 nicm 79: window_choose_add(struct window_pane *wp, struct window_choose_data *wcd)
1.1 nicm 80: {
81: struct window_choose_mode_data *data = wp->modedata;
82: struct window_choose_mode_item *item;
1.22 ! nicm 83: int width;
! 84: char tmp[10];
1.1 nicm 85:
86: ARRAY_EXPAND(&data->list, 1);
87: item = &ARRAY_LAST(&data->list);
88:
1.19 nicm 89: item->name = format_expand(wcd->ft, wcd->ft_template);
90: item->wcd = wcd;
1.22 ! nicm 91: item->pos = ARRAY_LENGTH(&data->list) - 1;
! 92:
! 93: width = snprintf (tmp, sizeof tmp, "%u", item->pos);
! 94: if (width > data->width)
! 95: data->width = width;
1.1 nicm 96: }
97:
98: void
1.3 nicm 99: window_choose_ready(struct window_pane *wp, u_int cur,
1.19 nicm 100: void (*callbackfn)(struct window_choose_data *),
101: void (*freefn)(struct window_choose_data *))
1.1 nicm 102: {
103: struct window_choose_mode_data *data = wp->modedata;
104: struct screen *s = &data->screen;
105:
106: data->selected = cur;
107: if (data->selected > screen_size_y(s) - 1)
108: data->top = ARRAY_LENGTH(&data->list) - screen_size_y(s);
109:
1.3 nicm 110: data->callbackfn = callbackfn;
111: data->freefn = freefn;
1.1 nicm 112:
113: window_choose_redraw_screen(wp);
114: }
115:
116: struct screen *
117: window_choose_init(struct window_pane *wp)
118: {
119: struct window_choose_mode_data *data;
120: struct screen *s;
1.5 nicm 121: int keys;
1.1 nicm 122:
123: wp->modedata = data = xmalloc(sizeof *data);
1.3 nicm 124:
125: data->callbackfn = NULL;
126: data->freefn = NULL;
1.22 ! nicm 127: data->input_type = WINDOW_CHOOSE_NORMAL;
! 128: data->input_str = xstrdup("");
! 129: data->input_prompt = NULL;
1.3 nicm 130:
1.1 nicm 131: ARRAY_INIT(&data->list);
132: data->top = 0;
133:
134: s = &data->screen;
135: screen_init(s, screen_size_x(&wp->base), screen_size_y(&wp->base), 0);
136: s->mode &= ~MODE_CURSOR;
1.7 nicm 137: if (options_get_number(&wp->window->options, "mode-mouse"))
1.17 nicm 138: s->mode |= MODE_MOUSE_STANDARD;
1.1 nicm 139:
1.5 nicm 140: keys = options_get_number(&wp->window->options, "mode-keys");
141: if (keys == MODEKEY_EMACS)
1.6 nicm 142: mode_key_init(&data->mdata, &mode_key_tree_emacs_choice);
1.5 nicm 143: else
1.6 nicm 144: mode_key_init(&data->mdata, &mode_key_tree_vi_choice);
1.1 nicm 145:
146: return (s);
147: }
148:
1.19 nicm 149: struct window_choose_data *
150: window_choose_data_create(struct cmd_ctx *ctx)
151: {
152: struct window_choose_data *wcd;
153:
154: wcd = xmalloc(sizeof *wcd);
155: wcd->ft = format_create();
156: wcd->ft_template = NULL;
1.20 nicm 157: wcd->command = NULL;
1.19 nicm 158: wcd->client = ctx->curclient;
159: wcd->session = ctx->curclient->session;
160: wcd->idx = -1;
161:
162: return (wcd);
163: }
164:
1.1 nicm 165: void
166: window_choose_free(struct window_pane *wp)
167: {
168: struct window_choose_mode_data *data = wp->modedata;
1.19 nicm 169: struct window_choose_mode_item *item;
1.1 nicm 170: u_int i;
171:
1.19 nicm 172: for (i = 0; i < ARRAY_LENGTH(&data->list); i++) {
173: item = &ARRAY_ITEM(&data->list, i);
174: if (data->freefn != NULL && item->wcd != NULL)
175: data->freefn(item->wcd);
1.21 nicm 176: free(item->name);
1.19 nicm 177: }
1.1 nicm 178: ARRAY_FREE(&data->list);
1.22 ! nicm 179: free(data->input_str);
1.1 nicm 180:
181: screen_free(&data->screen);
1.21 nicm 182: free(data);
1.1 nicm 183: }
184:
185: void
186: window_choose_resize(struct window_pane *wp, u_int sx, u_int sy)
187: {
188: struct window_choose_mode_data *data = wp->modedata;
189: struct screen *s = &data->screen;
190:
191: data->top = 0;
192: if (data->selected > sy - 1)
193: data->top = data->selected - (sy - 1);
194:
195: screen_resize(s, sx, sy);
196: window_choose_redraw_screen(wp);
197: }
198:
1.18 nicm 199: void
1.19 nicm 200: window_choose_fire_callback(
201: struct window_pane *wp, struct window_choose_data *wcd)
1.18 nicm 202: {
203: struct window_choose_mode_data *data = wp->modedata;
204: const struct window_mode *oldmode;
205:
206: oldmode = wp->mode;
207: wp->mode = NULL;
208:
1.19 nicm 209: data->callbackfn(wcd);
1.18 nicm 210:
211: wp->mode = oldmode;
212: }
213:
1.22 ! nicm 214: void
! 215: window_choose_prompt_input(enum window_choose_input_type input_type,
! 216: const char *prompt, struct window_pane *wp, int key)
! 217: {
! 218: struct window_choose_mode_data *data = wp->modedata;
! 219: size_t input_len;
! 220:
! 221: data->input_type = input_type;
! 222: data->input_prompt = prompt;
! 223: input_len = strlen(data->input_str) + 2;
! 224:
! 225: data->input_str = xrealloc(data->input_str, 1, input_len);
! 226: data->input_str[input_len - 2] = key;
! 227: data->input_str[input_len - 1] = '\0';
! 228:
! 229: window_choose_redraw_screen(wp);
! 230: }
! 231:
1.12 nicm 232: /* ARGSUSED */
1.1 nicm 233: void
1.16 nicm 234: window_choose_key(struct window_pane *wp, unused struct session *sess, int key)
1.1 nicm 235: {
236: struct window_choose_mode_data *data = wp->modedata;
237: struct screen *s = &data->screen;
238: struct screen_write_ctx ctx;
239: struct window_choose_mode_item *item;
1.22 ! nicm 240: size_t input_len;
! 241: u_int items, n;
1.11 nicm 242: int idx;
1.1 nicm 243:
244: items = ARRAY_LENGTH(&data->list);
245:
246: switch (mode_key_lookup(&data->mdata, key)) {
1.5 nicm 247: case MODEKEYCHOICE_CANCEL:
1.19 nicm 248: window_choose_fire_callback(wp, NULL);
1.1 nicm 249: window_pane_reset_mode(wp);
250: break;
1.5 nicm 251: case MODEKEYCHOICE_CHOOSE:
1.22 ! nicm 252: switch (data->input_type) {
! 253: case WINDOW_CHOOSE_NORMAL:
! 254: item = &ARRAY_ITEM(&data->list, data->selected);
! 255: window_choose_fire_callback(wp, item->wcd);
! 256: window_pane_reset_mode(wp);
! 257: break;
! 258: case WINDOW_CHOOSE_GOTO_ITEM:
! 259: n = strtonum(data->input_str, 0, INT_MAX, NULL);
! 260: if (n > items - 1)
! 261: break;
! 262: item = &ARRAY_ITEM(&data->list, n);
! 263: window_choose_fire_callback(wp, item->wcd);
! 264: window_pane_reset_mode(wp);
! 265: break;
! 266: }
1.1 nicm 267: break;
1.5 nicm 268: case MODEKEYCHOICE_UP:
1.1 nicm 269: if (items == 0)
270: break;
271: if (data->selected == 0) {
272: data->selected = items - 1;
273: if (data->selected > screen_size_y(s) - 1)
274: data->top = items - screen_size_y(s);
275: window_choose_redraw_screen(wp);
276: break;
277: }
278: data->selected--;
279: if (data->selected < data->top)
280: window_choose_scroll_up(wp);
281: else {
282: screen_write_start(&ctx, wp, NULL);
283: window_choose_write_line(
284: wp, &ctx, data->selected - data->top);
285: window_choose_write_line(
286: wp, &ctx, data->selected + 1 - data->top);
287: screen_write_stop(&ctx);
288: }
289: break;
1.5 nicm 290: case MODEKEYCHOICE_DOWN:
1.1 nicm 291: if (items == 0)
292: break;
293: if (data->selected == items - 1) {
294: data->selected = 0;
295: data->top = 0;
296: window_choose_redraw_screen(wp);
297: break;
298: }
299: data->selected++;
1.5 nicm 300:
1.15 nicm 301: if (data->selected < data->top + screen_size_y(s)) {
1.1 nicm 302: screen_write_start(&ctx, wp, NULL);
303: window_choose_write_line(
304: wp, &ctx, data->selected - data->top);
305: window_choose_write_line(
306: wp, &ctx, data->selected - 1 - data->top);
307: screen_write_stop(&ctx);
1.15 nicm 308: } else
309: window_choose_scroll_down(wp);
310: break;
311: case MODEKEYCHOICE_SCROLLUP:
312: if (items == 0 || data->top == 0)
313: break;
314: if (data->selected == data->top + screen_size_y(s) - 1) {
315: data->selected--;
316: window_choose_scroll_up(wp);
317: screen_write_start(&ctx, wp, NULL);
318: window_choose_write_line(
319: wp, &ctx, screen_size_y(s) - 1);
320: screen_write_stop(&ctx);
321: } else
322: window_choose_scroll_up(wp);
323: break;
324: case MODEKEYCHOICE_SCROLLDOWN:
325: if (items == 0 ||
326: data->top + screen_size_y(&data->screen) >= items)
327: break;
328: if (data->selected == data->top) {
329: data->selected++;
330: window_choose_scroll_down(wp);
331: screen_write_start(&ctx, wp, NULL);
332: window_choose_write_line(wp, &ctx, 0);
333: screen_write_stop(&ctx);
334: } else
335: window_choose_scroll_down(wp);
1.1 nicm 336: break;
1.5 nicm 337: case MODEKEYCHOICE_PAGEUP:
1.1 nicm 338: if (data->selected < screen_size_y(s)) {
339: data->selected = 0;
340: data->top = 0;
341: } else {
342: data->selected -= screen_size_y(s);
343: if (data->top < screen_size_y(s))
344: data->top = 0;
345: else
346: data->top -= screen_size_y(s);
347: }
1.13 nicm 348: window_choose_redraw_screen(wp);
1.1 nicm 349: break;
1.5 nicm 350: case MODEKEYCHOICE_PAGEDOWN:
1.1 nicm 351: data->selected += screen_size_y(s);
352: if (data->selected > items - 1)
353: data->selected = items - 1;
354: data->top += screen_size_y(s);
355: if (screen_size_y(s) < items) {
356: if (data->top + screen_size_y(s) > items)
357: data->top = items - screen_size_y(s);
358: } else
359: data->top = 0;
360: if (data->selected < data->top)
361: data->top = data->selected;
362: window_choose_redraw_screen(wp);
363: break;
1.22 ! nicm 364: case MODEKEYCHOICE_BACKSPACE:
! 365: input_len = strlen(data->input_str);
! 366: if (input_len > 0)
! 367: data->input_str[input_len - 1] = '\0';
! 368: window_choose_redraw_screen(wp);
! 369: break;
! 370: case MODEKEYCHOICE_STARTNUMBERPREFIX:
! 371: if (key < '0' && key > '9')
1.11 nicm 372: break;
1.13 nicm 373:
1.22 ! nicm 374: /*
! 375: * If there's less than ten items (0-9) then pressing a number
! 376: * will automatically select that item; otherwise, prompt for
! 377: * the item to go to.
! 378: */
! 379: if (ARRAY_LENGTH(&data->list) - 1 <= 9) {
! 380: idx = window_choose_index_key(key);
! 381: if (idx < 0 || (u_int) idx >= ARRAY_LENGTH(&data->list))
! 382: break;
! 383: data->selected = idx;
! 384:
! 385: item = &ARRAY_ITEM(&data->list, data->selected);
! 386: window_choose_fire_callback(wp, item->wcd);
! 387: window_pane_reset_mode(wp);
! 388: } else {
! 389: window_choose_prompt_input(
! 390: WINDOW_CHOOSE_GOTO_ITEM, "Goto item", wp, key);
! 391: }
! 392: break;
! 393: default:
1.1 nicm 394: break;
395: }
396: }
397:
1.12 nicm 398: /* ARGSUSED */
1.1 nicm 399: void
1.10 nicm 400: window_choose_mouse(
1.16 nicm 401: struct window_pane *wp, unused struct session *sess, struct mouse_event *m)
1.1 nicm 402: {
403: struct window_choose_mode_data *data = wp->modedata;
404: struct screen *s = &data->screen;
405: struct window_choose_mode_item *item;
406: u_int idx;
407:
1.10 nicm 408: if ((m->b & 3) == 3)
1.1 nicm 409: return;
1.10 nicm 410: if (m->x >= screen_size_x(s))
1.1 nicm 411: return;
1.10 nicm 412: if (m->y >= screen_size_y(s))
1.1 nicm 413: return;
414:
1.10 nicm 415: idx = data->top + m->y;
1.1 nicm 416: if (idx >= ARRAY_LENGTH(&data->list))
417: return;
418: data->selected = idx;
419:
420: item = &ARRAY_ITEM(&data->list, data->selected);
1.19 nicm 421: window_choose_fire_callback(wp, item->wcd);
1.1 nicm 422: window_pane_reset_mode(wp);
423: }
424:
425: void
426: window_choose_write_line(
427: struct window_pane *wp, struct screen_write_ctx *ctx, u_int py)
428: {
429: struct window_choose_mode_data *data = wp->modedata;
430: struct window_choose_mode_item *item;
1.9 nicm 431: struct options *oo = &wp->window->options;
1.1 nicm 432: struct screen *s = &data->screen;
433: struct grid_cell gc;
1.22 ! nicm 434: size_t last, xoff = 0;
! 435: char hdr[32];
! 436: int utf8flag;
1.1 nicm 437:
1.3 nicm 438: if (data->callbackfn == NULL)
1.1 nicm 439: fatalx("called before callback assigned");
440:
1.22 ! nicm 441: last = screen_size_y(s) - 1;
1.2 nicm 442: utf8flag = options_get_number(&wp->window->options, "utf8");
1.1 nicm 443: memcpy(&gc, &grid_default_cell, sizeof gc);
1.22 ! nicm 444: if (data->selected == data->top + py)
! 445: window_mode_attrs(&gc, oo);
1.1 nicm 446:
447: screen_write_cursormove(ctx, 0, py);
448: if (data->top + py < ARRAY_LENGTH(&data->list)) {
449: item = &ARRAY_ITEM(&data->list, data->top + py);
1.22 ! nicm 450: screen_write_nputs(ctx, screen_size_x(s) - 1,
! 451: &gc, utf8flag, "(%*d) %s", data->width,
! 452: item->pos, item->name);
1.11 nicm 453:
1.1 nicm 454: }
455: while (s->cx < screen_size_x(s))
456: screen_write_putc(ctx, &gc, ' ');
1.11 nicm 457:
1.22 ! nicm 458: if (data->input_type != WINDOW_CHOOSE_NORMAL) {
! 459: window_mode_attrs(&gc, oo);
1.11 nicm 460:
1.22 ! nicm 461: xoff = xsnprintf(hdr, sizeof hdr,
! 462: "%s: %s", data->input_prompt, data->input_str);
! 463: screen_write_cursormove(ctx, 0, last);
! 464: screen_write_puts(ctx, &gc, "%s", hdr);
! 465: screen_write_cursormove(ctx, xoff, py);
! 466: memcpy(&gc, &grid_default_cell, sizeof gc);
1.11 nicm 467: }
1.22 ! nicm 468:
1.11 nicm 469: }
470:
471: int
1.22 ! nicm 472: window_choose_index_key(int key)
1.11 nicm 473: {
1.22 ! nicm 474: static const char keys[] = "0123456789";
1.11 nicm 475: const char *ptr;
476: u_int idx = 0;
477:
478: for (ptr = keys; *ptr != '\0'; ptr++) {
479: if (key == *ptr)
480: return (idx);
481: idx++;
482: }
483: return (-1);
1.1 nicm 484: }
485:
486: void
487: window_choose_redraw_screen(struct window_pane *wp)
488: {
489: struct window_choose_mode_data *data = wp->modedata;
490: struct screen *s = &data->screen;
491: struct screen_write_ctx ctx;
492: u_int i;
493:
494: screen_write_start(&ctx, wp, NULL);
495: for (i = 0; i < screen_size_y(s); i++)
496: window_choose_write_line(wp, &ctx, i);
497: screen_write_stop(&ctx);
498: }
499:
500: void
501: window_choose_scroll_up(struct window_pane *wp)
502: {
503: struct window_choose_mode_data *data = wp->modedata;
504: struct screen_write_ctx ctx;
505:
506: if (data->top == 0)
507: return;
508: data->top--;
509:
510: screen_write_start(&ctx, wp, NULL);
511: screen_write_cursormove(&ctx, 0, 0);
512: screen_write_insertline(&ctx, 1);
513: window_choose_write_line(wp, &ctx, 0);
514: if (screen_size_y(&data->screen) > 1)
515: window_choose_write_line(wp, &ctx, 1);
516: screen_write_stop(&ctx);
517: }
518:
519: void
520: window_choose_scroll_down(struct window_pane *wp)
521: {
522: struct window_choose_mode_data *data = wp->modedata;
523: struct screen *s = &data->screen;
524: struct screen_write_ctx ctx;
525:
526: if (data->top >= ARRAY_LENGTH(&data->list))
527: return;
528: data->top++;
529:
530: screen_write_start(&ctx, wp, NULL);
531: screen_write_cursormove(&ctx, 0, 0);
532: screen_write_deleteline(&ctx, 1);
533: window_choose_write_line(wp, &ctx, screen_size_y(s) - 1);
534: if (screen_size_y(&data->screen) > 1)
535: window_choose_write_line(wp, &ctx, screen_size_y(s) - 2);
536: screen_write_stop(&ctx);
1.19 nicm 537: }
538:
539: void
540: window_choose_ctx(struct window_choose_data *cdata)
541: {
542: struct cmd_ctx ctx;
543: struct cmd_list *cmdlist;
1.20 nicm 544: char *cause;
1.19 nicm 545:
1.20 nicm 546: /* The command template will have already been replaced. But if it's
547: * NULL, bail here.
548: */
549: if (cdata->command == NULL)
550: return;
1.19 nicm 551:
1.20 nicm 552: if (cmd_string_parse(cdata->command, &cmdlist, &cause) != 0) {
1.19 nicm 553: if (cause != NULL) {
554: *cause = toupper((u_char) *cause);
555: status_message_set(cdata->client, "%s", cause);
1.21 nicm 556: free(cause);
1.19 nicm 557: }
558: return;
559: }
560:
561: ctx.msgdata = NULL;
562: ctx.curclient = cdata->client;
563:
564: ctx.error = key_bindings_error;
565: ctx.print = key_bindings_print;
566: ctx.info = key_bindings_info;
567:
568: ctx.cmdclient = NULL;
569:
570: cmd_list_exec(cmdlist, &ctx);
571: cmd_list_free(cmdlist);
1.20 nicm 572: }
573:
574: struct window_choose_data *
575: window_choose_add_session(struct window_pane *wp, struct cmd_ctx *ctx,
1.22 ! nicm 576: struct session *s, const char *template, char *action, u_int idx)
1.20 nicm 577: {
578: struct window_choose_data *wcd;
579:
580: wcd = window_choose_data_create(ctx);
581: wcd->idx = s->idx;
582: wcd->command = cmd_template_replace(action, s->name, 1);
583: wcd->ft_template = xstrdup(template);
584: format_add(wcd->ft, "line", "%u", idx);
585: format_session(wcd->ft, s);
586:
587: wcd->client->references++;
588: wcd->session->references++;
589:
590: window_choose_add(wp, wcd);
591:
592: return (wcd);
593: }
594:
595: struct window_choose_data *
596: window_choose_add_window(struct window_pane *wp, struct cmd_ctx *ctx,
1.22 ! nicm 597: struct session *s, struct winlink *wl, const char *template,
! 598: char *action, u_int idx)
1.20 nicm 599: {
600: struct window_choose_data *wcd;
601: char *action_data;
602:
603: wcd = window_choose_data_create(ctx);
604:
605: xasprintf(&action_data, "%s:%d", s->name, wl->idx);
606: wcd->command = cmd_template_replace(action, action_data, 1);
1.21 nicm 607: free(action_data);
1.20 nicm 608:
609: wcd->idx = wl->idx;
610: wcd->ft_template = xstrdup(template);
611: format_add(wcd->ft, "line", "%u", idx);
612: format_session(wcd->ft, s);
613: format_winlink(wcd->ft, s, wl);
614: format_window_pane(wcd->ft, wl->window->active);
615:
616: wcd->client->references++;
617: wcd->session->references++;
618:
619: window_choose_add(wp, wcd);
620:
621: return (wcd);
1.1 nicm 622: }