~ubuntu-branches/ubuntu/gutsy/vnc4/gutsy

« back to all changes in this revision

Viewing changes to unix/xc/programs/Xserver/hw/xfree86/XF86Setup/tclcurses.c

  • Committer: Bazaar Package Importer
  • Author(s): Ola Lundqvist
  • Date: 2006-05-15 20:35:17 UTC
  • mfrom: (1.1.2 upstream)
  • Revision ID: james.westby@ubuntu.com-20060515203517-l4lre1ku942mn26k
Tags: 4.1.1+X4.3.0-10
* Correction of critical security issue. Thanks to Martin Kogler
  <e9925248@student.tuwien.ac.at> that informed me about the issue,
  and provided the patch.
  This flaw was originally found by Steve Wiseman of intelliadmin.com.
* Applied patch from Javier Kohen <jkohen@users.sourceforge.net> that
  inform the user that only 8 first characters of the password will
  actually be used when typing more than 8 characters, closes:
  #355619.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* $XFree86: xc/programs/Xserver/hw/xfree86/XF86Setup/tclcurses.c,v 1.2 1999/04/05 08:28:23 dawes Exp $ */
 
2
/*
 
3
 * Copyright 1997 by Joseph V. Moss <joe@XFree86.Org>
 
4
 *
 
5
 * Permission to use, copy, modify, distribute, and sell this software and its
 
6
 * documentation for any purpose is hereby granted without fee, provided that
 
7
 * the above copyright notice appear in all copies and that both that
 
8
 * copyright notice and this permission notice appear in supporting
 
9
 * documentation, and that the name of Joseph Moss not be used in
 
10
 * advertising or publicity pertaining to distribution of the software without
 
11
 * specific, written prior permission.  Joseph Moss makes no representations
 
12
 * about the suitability of this software for any purpose.  It is provided
 
13
 * "as is" without express or implied warranty.
 
14
 *
 
15
 * JOSEPH MOSS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
 
16
 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
 
17
 * EVENT SHALL JOSEPH MOSS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
 
18
 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
 
19
 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
 
20
 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 
21
 * PERFORMANCE OF THIS SOFTWARE.
 
22
 */
 
23
 
 
24
 
 
25
/*
 
26
  This file contains Tcl bindings to the curses library
 
27
 */
 
28
 
 
29
#include <tcl.h>
 
30
#ifdef CURSES
 
31
#ifdef NCURSES
 
32
#include <ncurses.h>
 
33
#else
 
34
#include <curses.h>
 
35
#endif
 
36
#include <string.h>
 
37
#include "tclcurses.h"
 
38
#endif /* CURSES */
 
39
 
 
40
static int curs_debug = 0;
 
41
 
 
42
/*
 
43
   Adds the curses command to the Tcl interpreter
 
44
*/
 
45
 
 
46
int
 
47
Curses_Init(interp)
 
48
    Tcl_Interp  *interp;
 
49
{
 
50
        Tcl_CreateCommand(interp, "curses", TCL_Curses, NULL,
 
51
                (void (*)()) NULL);
 
52
 
 
53
        return TCL_OK;
 
54
}
 
55
 
 
56
#ifndef CURSES
 
57
 
 
58
/* Stub version */
 
59
int
 
60
TCL_Curses(clientData, interp, argc, argv)
 
61
    ClientData  clientData;
 
62
    Tcl_Interp  *interp;
 
63
    int         argc;
 
64
    char        *argv[];
 
65
{
 
66
        Tcl_AppendResult(interp,
 
67
                "Curses not compiled in to this version of XF86SETUP", NULL);
 
68
        return TCL_ERROR;
 
69
}
 
70
 
 
71
#else
 
72
 
 
73
/*
 
74
*/
 
75
 
 
76
int
 
77
TCL_Curses(clientData, interp, argc, argv)
 
78
    ClientData  clientData;
 
79
    Tcl_Interp  *interp;
 
80
    int         argc;
 
81
    char        *argv[];
 
82
{
 
83
        struct windata *winPtr;
 
84
        WINDOW *tmpwin;
 
85
 
 
86
        if (argc < 2) {
 
87
                Tcl_SetResult(interp, "Usage: curses ", TCL_STATIC);
 
88
                return TCL_ERROR;
 
89
        }
 
90
 
 
91
        if (!strcmp(argv[1], "init")) {
 
92
                if (stdscr) {
 
93
                        Tcl_AppendResult(interp, "Already initialized", NULL);
 
94
                        return TCL_ERROR;
 
95
                }
 
96
                if (initscr() == NULL) {
 
97
                        Tcl_AppendResult(interp, "Unable to initialize curses", NULL);
 
98
                        return TCL_ERROR;
 
99
                }
 
100
                cbreak();
 
101
                noecho();
 
102
                nonl();
 
103
                intrflush(stdscr, FALSE);
 
104
                keypad(stdscr, TRUE);
 
105
                if (has_colors()) {
 
106
                        start_color();
 
107
                }
 
108
                init_pair(PAIR_SCREEN);
 
109
                init_pair(PAIR_ULBORD);
 
110
                init_pair(PAIR_LRBORD);
 
111
                init_pair(PAIR_TEXT);
 
112
                init_pair(PAIR_TITLE);
 
113
                init_pair(PAIR_SELECT);
 
114
                winPtr = initwinPtr(stdscr);
 
115
                bkgd(ATTR_SCREEN);
 
116
                attrset(ATTR_SCREEN);
 
117
                Tcl_CreateCommand(interp,"stdscr",TCL_WinProc,winPtr,NULL);
 
118
        } else if (argc == 3 && !strcmp(argv[1], "debug")) {
 
119
                curs_debug = atoi(argv[2]);
 
120
        } else if (!strcmp(argv[1], "end")) {
 
121
                if (endwin() != OK) {
 
122
                        Tcl_AppendResult(interp, "curses end failed", NULL);
 
123
                        return TCL_ERROR;
 
124
                }
 
125
        } else if (!strcmp(argv[1], "menubar")) {
 
126
                /* TBD */
 
127
                Tcl_AppendResult(interp, "Not yet implemented", NULL);
 
128
                return TCL_OK;
 
129
        } else if (!strcmp(argv[1], "newwin")) {
 
130
                if (argc != 7) {
 
131
                        Tcl_AppendResult(interp,
 
132
                                "Usage: curses newwin <winname> <nlines>"
 
133
                                " <ncols> <begin_y> <begin_x>",
 
134
                                NULL);
 
135
                        return TCL_ERROR;
 
136
                }
 
137
                if ((tmpwin = newwin(atoi(argv[3]),atoi(argv[4]),
 
138
                                        atoi(argv[5]),atoi(argv[6]))) == NULL) {
 
139
                        Tcl_AppendResult(interp, "Unable to create window", NULL);
 
140
                        ckfree(tmpwin);
 
141
                        return TCL_ERROR;
 
142
                }
 
143
                keypad(tmpwin, TRUE);
 
144
                winPtr = initwinPtr(tmpwin);
 
145
                wbkgd(winPtr->win,ATTR_TEXT);
 
146
                Tcl_CreateCommand(interp,argv[2],TCL_WinProc,winPtr,NULL);
 
147
        } else if (!strcmp(argv[1], "delwin")) {
 
148
                if (argc != 3) {
 
149
                        Tcl_AppendResult(interp,
 
150
                                "Usage: curses delwin <winname>", NULL);
 
151
                        return TCL_ERROR;
 
152
                }
 
153
                if (Tcl_DeleteCommand(interp, argv[2]) == TCL_ERROR)
 
154
                        return TCL_ERROR;
 
155
        } else {
 
156
                Tcl_AppendResult(interp, "Invalid option: ",
 
157
                        argv[2], NULL);
 
158
                return TCL_ERROR;
 
159
        }
 
160
        return TCL_OK;
 
161
}
 
162
 
 
163
void TCL_WinDelete(clientData)
 
164
    ClientData  clientData;
 
165
{
 
166
        struct windata *winPtr;
 
167
        int i;
 
168
 
 
169
        winPtr = (struct windata *) clientData;
 
170
        delwin(winPtr->win);
 
171
        ckfree(winPtr->title);
 
172
        ckfree(winPtr->menu.chkd);
 
173
        ckfree(winPtr->menu.win);
 
174
        ckfree(winPtr->menu.data);
 
175
        ckfree(winPtr->text.buffer);
 
176
        ckfree(winPtr->text.data);
 
177
        for (i = 0; i < MAXBUTTONS; i++)
 
178
                ckfree(winPtr->button[i]);
 
179
        ckfree(winPtr);
 
180
}
 
181
 
 
182
/*
 
183
*/
 
184
 
 
185
int
 
186
TCL_WinProc(clientData, interp, argc, argv)
 
187
    ClientData  clientData;
 
188
    Tcl_Interp  *interp;
 
189
    int         argc;
 
190
    char        *argv[];
 
191
{
 
192
        struct windata *winPtr = (struct windata *) clientData;
 
193
        char tmpbuf[64];
 
194
 
 
195
        if (argc == 4 && !strcmp(argv[1], "move")) {
 
196
                wmove(winPtr->win,atoi(argv[2]),atoi(argv[3]));
 
197
        } else if (argc == 3 && !strcmp(argv[1], "addstr")) {
 
198
                waddstr(winPtr->win,argv[2]);
 
199
        } else if (argc == 3 && !strcmp(argv[1], "text")) {
 
200
                return settext(winPtr, interp, argv[2]);
 
201
        } else if (argc == 2 && !strcmp(argv[1], "activate")) {
 
202
                return processinput(winPtr, interp);
 
203
        } else if (argc == 2 && !strcmp(argv[1], "clear")) {
 
204
                wclear(winPtr->win);
 
205
        } else if (argc == 2 && !strcmp(argv[1], "update")) {
 
206
                wrefresh(winPtr->win);
 
207
        } else if (argc == 2 && !strcmp(argv[1], "info")) {
 
208
                sprintf(tmpbuf, "%d %d %d %d", winPtr->width, winPtr->height,
 
209
                        winPtr->border, winPtr->shadow);
 
210
                Tcl_AppendResult(interp, tmpbuf, NULL);
 
211
                Tcl_AppendElement(interp, winPtr->title);
 
212
        } else if (argc > 2 && !strcmp(argv[1], "menu")) {
 
213
                winPtr->menu.type=TYPE_MENU;
 
214
                return setmenu(winPtr, interp, argc, argv);
 
215
        } else if (argc > 2 && !strcmp(argv[1], "checklist")) {
 
216
                winPtr->menu.type=TYPE_CHECK;
 
217
                return setmenu(winPtr, interp, argc, argv);
 
218
        } else if (argc > 2 && !strcmp(argv[1], "radiolist")) {
 
219
                winPtr->menu.type=TYPE_RADIO;
 
220
                return setmenu(winPtr, interp, argc, argv);
 
221
        } else if (argc > 2 && !strcmp(argv[1], "buttons")) {
 
222
                return setbuttons(winPtr, interp, argc, argv);
 
223
        } else if (argc > 2 && !strcmp(argv[1], "configure")) {
 
224
                return winconfig(winPtr, interp, argc, argv);
 
225
        } else {
 
226
                Tcl_AppendResult(interp, "Invalid option: ",
 
227
                        argv[1], NULL);
 
228
                return TCL_ERROR;
 
229
        }
 
230
        return TCL_OK;
 
231
}
 
232
 
 
233
static int
 
234
settext(winPtr, interp, text)
 
235
        struct windata  *winPtr;
 
236
        Tcl_Interp      *interp;
 
237
        char            *text;
 
238
{
 
239
        int i, numcols;
 
240
        char savechar, *ptr, *nlptr, *spcptr, *endchar;
 
241
 
 
242
        DEBUG4("settext(%p, %p, %s)\n", winPtr, interp, text);
 
243
 
 
244
        numcols = winPtr->width - (winPtr->border==BORDER_NONE? 0: 2);
 
245
        if (winPtr->text.data) {
 
246
                ckfree(winPtr->text.data);
 
247
                ckfree(winPtr->text.buffer);
 
248
        }
 
249
        winPtr->text.items = winPtr->text.topline = 0;
 
250
        if (strlen(text)) {
 
251
                winPtr->text.buffer = strdup(text);
 
252
                ptr = nlptr = winPtr->text.buffer;
 
253
                endchar = winPtr->text.buffer + strlen(text);
 
254
                while (nlptr < endchar) {
 
255
                        if ((nlptr = strchr(ptr, '\n')) == NULL)
 
256
                                nlptr = endchar;
 
257
                        if (nlptr - ptr > numcols) {
 
258
                                *nlptr = '\0';
 
259
                                while (strlen(ptr) > numcols) {
 
260
                                        savechar = ptr[numcols];
 
261
                                        ptr[numcols] = '\0';
 
262
                                        spcptr = strrchr(ptr, ' ');
 
263
                                        ptr[numcols] = savechar;
 
264
                                        if (spcptr == NULL) {
 
265
                                                ptr[numcols-1] = '\n';
 
266
                                                ptr += numcols - 1;
 
267
                                        } else {
 
268
                                                *spcptr = '\n';
 
269
                                                ptr = spcptr + 1;
 
270
                                        }
 
271
                                }
 
272
                                if (nlptr != endchar)
 
273
                                        *nlptr = '\n';
 
274
                        }
 
275
                        ptr = nlptr + 1;
 
276
                }
 
277
        } else {
 
278
                winPtr->text.data = (char **) 0;
 
279
                winPtr->text.buffer = endchar = NULL;
 
280
        }
 
281
 
 
282
        for (ptr= nlptr= winPtr->text.buffer; ptr<endchar && nlptr; ptr= nlptr+1) {
 
283
                nlptr = strchr(ptr, '\n');
 
284
                winPtr->text.items++;
 
285
        }
 
286
        winPtr->text.data = (char **) ckalloc(winPtr->text.items * sizeof(char *));
 
287
 
 
288
        for (i=0, ptr= nlptr= winPtr->text.buffer; ptr<endchar && nlptr; ptr= nlptr+1) {
 
289
                if ((nlptr = strchr(ptr, '\n')) != NULL)
 
290
                        *nlptr = '\0';
 
291
                winPtr->text.data[i++] = ptr;
 
292
        }
 
293
        DEBUG3("(text='%s' items=%d)\n", winPtr->text.buffer, winPtr->text.items);
 
294
        
 
295
        updatetext(winPtr, interp);
 
296
        DEBUG1("settext() returning okay\n");
 
297
        return TCL_OK;
 
298
}
 
299
 
 
300
static int
 
301
updatetext(winPtr, interp)
 
302
        struct windata  *winPtr;
 
303
        Tcl_Interp      *interp;
 
304
{
 
305
        int i, j, row, col, numrows, numcols;
 
306
 
 
307
        DEBUG3("updatetext(%p, %p)\n", winPtr, interp);
 
308
        wattrset(winPtr->win, ATTR_TEXT);
 
309
        if (winPtr->border == BORDER_NONE) {
 
310
                row = col = 0;
 
311
                numcols = winPtr->width;
 
312
        } else {
 
313
                row = col = 1;
 
314
                numcols = winPtr->width-2;
 
315
        }
 
316
        numrows = textlines(winPtr);
 
317
 
 
318
        for (i = row; i < row+numrows; i++) {
 
319
                wmove(winPtr->win, i, col);
 
320
                for (j = col; j < col+numcols; j++)
 
321
                        waddch(winPtr->win, ATTR_TEXT | ' ');
 
322
        }
 
323
        if (!winPtr->text.items)
 
324
                return TCL_OK;
 
325
 
 
326
        for (i= 0, j= winPtr->text.topline; i<numrows && j<winPtr->text.items; i++, j++) {
 
327
                wmove(winPtr->win, i+row, col);
 
328
                waddstr(winPtr->win, winPtr->text.data[j]);
 
329
        }
 
330
        DEBUG1("updatetext() returning okay\n");
 
331
        return TCL_OK;
 
332
}
 
333
 
 
334
static int
 
335
textlines(winPtr)
 
336
        struct windata  *winPtr;
 
337
{
 
338
        int rows;
 
339
 
 
340
        if (winPtr->border == BORDER_NONE) {
 
341
                rows = winPtr->height;
 
342
                if (winPtr->button[0]) rows--;
 
343
        } else {
 
344
                rows = winPtr->height-2;
 
345
                if (winPtr->button[0]) rows-=2;
 
346
        }
 
347
        if (winPtr->menu.items) rows -= winPtr->menu.items+2;
 
348
 
 
349
        return rows;
 
350
}
 
351
 
 
352
static int
 
353
processinput(winPtr, interp)
 
354
        struct windata  *winPtr;
 
355
        Tcl_Interp      *interp;
 
356
{
 
357
        int key=0, i, lastbutton;
 
358
 
 
359
#define mybeep()        beep(); wrefresh(winPtr->win)
 
360
 
 
361
        for (lastbutton=0; lastbutton<MAXBUTTONS; lastbutton++) {
 
362
                if (!winPtr->button[lastbutton])
 
363
                        break;
 
364
        }
 
365
        while (1) {
 
366
            switch (key = wgetch(winPtr->win)) {
 
367
                case KEY_RIGHT:
 
368
                        if (!winPtr->button[0] || winPtr->butsel == lastbutton-1) {
 
369
                                mybeep();
 
370
                        } else {
 
371
                                winPtr->butsel++;
 
372
                                updatebuttons(winPtr);
 
373
                        }
 
374
                when KEY_LEFT:
 
375
                        if (!winPtr->button[0] || winPtr->butsel == 0) {
 
376
                                mybeep();
 
377
                        } else {
 
378
                                winPtr->butsel--;
 
379
                                updatebuttons(winPtr);
 
380
                        }
 
381
                when KEY_UP:
 
382
                case KEY_SR:
 
383
                        if (updatepos(winPtr, interp, KEY_UP, SCROLL_LINE) == TCL_ERROR)
 
384
                                return TCL_ERROR;
 
385
                when KEY_DOWN:
 
386
                case KEY_SF:
 
387
                        if (updatepos(winPtr, interp, KEY_DOWN, SCROLL_LINE) == TCL_ERROR)
 
388
                                return TCL_ERROR;
 
389
                when KEY_HOME:
 
390
                case KEY_BEG:
 
391
                        if (updatepos(winPtr, interp, KEY_UP, SCROLL_ALL) == TCL_ERROR)
 
392
                                return TCL_ERROR;
 
393
                when KEY_LL:
 
394
                case KEY_END:
 
395
                        if (updatepos(winPtr, interp, KEY_DOWN, SCROLL_ALL) == TCL_ERROR)
 
396
                                return TCL_ERROR;
 
397
                when KEY_PPAGE:
 
398
                        if (updatepos(winPtr, interp, KEY_UP, SCROLL_PAGE) == TCL_ERROR)
 
399
                                return TCL_ERROR;
 
400
                when KEY_NPAGE:
 
401
                        if (updatepos(winPtr, interp, KEY_DOWN, SCROLL_PAGE) == TCL_ERROR)
 
402
                                return TCL_ERROR;
 
403
                when KEY_ENTER:
 
404
                case '\r':
 
405
                case '\n':
 
406
                        Tcl_AppendElement(interp, winPtr->button[0]?
 
407
                                        winPtr->button[winPtr->butsel]: "");
 
408
                        if (winPtr->menu.items) {
 
409
                                if (winPtr->menu.type == TYPE_RADIO) {
 
410
                                        Tcl_AppendElement(interp,
 
411
                                                winPtr->menu.data[winPtr->menu.rsel]);
 
412
                                } else if (winPtr->menu.type == TYPE_CHECK) {
 
413
                                        for (i = 0; i < winPtr->menu.items; i++) {
 
414
                                                if (winPtr->menu.chkd[i])
 
415
                                                        Tcl_AppendElement(interp,
 
416
                                                                winPtr->menu.data[i]);
 
417
                                        }
 
418
                                } else
 
419
                                        Tcl_AppendElement(interp,
 
420
                                                winPtr->menu.data[winPtr->menu.current]);
 
421
                        }
 
422
                        return TCL_OK;
 
423
                when KEY_SELECT:
 
424
                case ' ':
 
425
                        if (winPtr->menu.items == 0
 
426
                                        || winPtr->menu.type == TYPE_NONE
 
427
                                        || winPtr->menu.type == TYPE_MENU) {
 
428
                                mybeep();
 
429
                        } else {
 
430
                                if (winPtr->menu.type == TYPE_RADIO)
 
431
                                        winPtr->menu.rsel = winPtr->menu.current;
 
432
                                else
 
433
                                        winPtr->menu.chkd[winPtr->menu.current] =
 
434
                                                (winPtr->menu.chkd[winPtr->menu.current]+1)%2;
 
435
                                if (updatemenu(winPtr) == TCL_ERROR)
 
436
                                        return TCL_ERROR;
 
437
                                wrefresh(winPtr->menu.win);
 
438
                        }
 
439
                when KEY_REFRESH:
 
440
                case 0x0c:  /* ^L */
 
441
                        wrefresh(curscr);
 
442
                when KEY_ESC:
 
443
                        Tcl_AppendResult(interp, "Escape", NULL);
 
444
                        return TCL_OK;
 
445
                        /* break */
 
446
                default:
 
447
                        mybeep();
 
448
            }
 
449
        }
 
450
}
 
451
 
 
452
static int
 
453
updatepos(winPtr, interp, dir, amt)
 
454
        struct windata  *winPtr;
 
455
        Tcl_Interp      *interp;
 
456
        int             dir, amt;
 
457
{
 
458
        int scroll;
 
459
 
 
460
        if ((winPtr->menu.type == TYPE_NONE && winPtr->text.data == NULL)
 
461
         || (winPtr->menu.type != TYPE_NONE && winPtr->menu.lines == 0)   ) {
 
462
                mybeep();
 
463
                return TCL_OK;
 
464
        }
 
465
        switch (amt) {
 
466
                case SCROLL_LINE:
 
467
                                        scroll = 1;
 
468
                when SCROLL_PAGE:
 
469
                                        if (winPtr->menu.type == TYPE_NONE) {
 
470
                                                scroll = textlines(winPtr);
 
471
                                        } else {
 
472
                                                scroll = winPtr->menu.lines;
 
473
                                        }
 
474
                when SCROLL_ALL:
 
475
                                        scroll = 0;
 
476
                                        break;
 
477
                default:
 
478
                                        Tcl_AppendResult(interp,
 
479
                                            "internal error: updatepos() called with invalid scroll amount (%d)",
 
480
                                            amt, NULL);
 
481
                                        return TCL_ERROR;
 
482
        }
 
483
        if (winPtr->menu.type == TYPE_NONE) {
 
484
            int rows = textlines(winPtr);
 
485
            switch (dir) {
 
486
                case KEY_UP:
 
487
                        if (winPtr->text.topline == 0) {
 
488
                                mybeep();
 
489
                                return TCL_OK;
 
490
                        }
 
491
                        winPtr->text.topline -= scroll;
 
492
                        if (!scroll || winPtr->text.topline < 0)
 
493
                                winPtr->text.topline = 0;
 
494
                        if (updatetext(winPtr, interp) == TCL_ERROR)
 
495
                                return TCL_ERROR;
 
496
                        wrefresh(winPtr->win);
 
497
                when KEY_DOWN:
 
498
                        if (winPtr->text.topline >= winPtr->text.items-rows) {
 
499
                                mybeep();
 
500
                                return TCL_OK;
 
501
                        }
 
502
                        winPtr->text.topline += scroll;
 
503
                        if (!scroll || winPtr->text.topline > winPtr->text.items-rows) {
 
504
                                winPtr->text.topline = winPtr->text.items-rows;
 
505
                                if (winPtr->text.topline < 0)
 
506
                                        winPtr->text.topline = 0;
 
507
                        }
 
508
                        if (updatetext(winPtr, interp) == TCL_ERROR)
 
509
                                return TCL_ERROR;
 
510
                        wrefresh(winPtr->win);
 
511
                        break;
 
512
                default:
 
513
                        Tcl_AppendResult(interp,
 
514
                                "internal error: updatepos() called with invalid dir (%d)",
 
515
                                dir, NULL);
 
516
                        return TCL_ERROR;
 
517
            }
 
518
        } else {
 
519
            switch (dir) {
 
520
                case KEY_UP:
 
521
                        if (winPtr->menu.current == 0) {
 
522
                                mybeep();
 
523
                                return TCL_OK;
 
524
                        }
 
525
                        winPtr->menu.current -= scroll;
 
526
                        if (!scroll || winPtr->menu.current < 0)
 
527
                                winPtr->menu.current = 0;
 
528
                        if (scroll != 1) {
 
529
                                winPtr->menu.topline -= scroll;
 
530
                                if (!scroll || winPtr->menu.topline < 0)
 
531
                                        winPtr->menu.topline = 0;
 
532
                        }
 
533
                        if (updatemenu(winPtr, interp) == TCL_ERROR)
 
534
                                return TCL_ERROR;
 
535
                        wrefresh(winPtr->menu.win);
 
536
                when KEY_DOWN:
 
537
                        if (winPtr->menu.current == winPtr->menu.items-1) {
 
538
                                mybeep();
 
539
                                return TCL_OK;
 
540
                        }
 
541
                        winPtr->menu.current += scroll;
 
542
                        if (!scroll || winPtr->menu.current > winPtr->menu.items-1)
 
543
                                winPtr->menu.current = winPtr->menu.items-1;
 
544
                        if (scroll != 1) {
 
545
                                winPtr->menu.topline += scroll;
 
546
                                if (!scroll || winPtr->menu.topline > winPtr->menu.items-winPtr->menu.lines)
 
547
                                        winPtr->menu.topline = winPtr->menu.items-winPtr->menu.lines;
 
548
                        }
 
549
                        if (updatemenu(winPtr, interp) == TCL_ERROR)
 
550
                                return TCL_ERROR;
 
551
                        wrefresh(winPtr->menu.win);
 
552
                        break;
 
553
                default:
 
554
                        Tcl_AppendResult(interp,
 
555
                                "internal error: updatepos() called with invalid dir (%d)",
 
556
                                dir, NULL);
 
557
                        return TCL_ERROR;
 
558
            }
 
559
        }
 
560
        return TCL_OK;
 
561
}
 
562
 
 
563
static struct windata *
 
564
initwinPtr(win)
 
565
        WINDOW  *win;
 
566
{
 
567
        struct windata *winPtr;
 
568
        int i;
 
569
 
 
570
        if ((winPtr= (struct windata *) ckalloc(sizeof(struct windata))) == NULL)
 
571
                return NULL;
 
572
        winPtr->win = win;
 
573
        getmaxyx(win, winPtr->height, winPtr->width);
 
574
        winPtr->title = (char *) 0;
 
575
        winPtr->border = BORDER_NONE;
 
576
        winPtr->shadow = 0;
 
577
 
 
578
        winPtr->menu.type = TYPE_NONE;
 
579
        winPtr->menu.lines = 0;
 
580
        winPtr->menu.items = 0;
 
581
        winPtr->menu.topline = 0;
 
582
        winPtr->menu.current = 0;
 
583
        winPtr->menu.rsel = 0;
 
584
        winPtr->menu.chkd = (int *) 0;
 
585
        winPtr->menu.win = (WINDOW *) 0;
 
586
        winPtr->menu.data = (char **) 0;
 
587
        winPtr->text.items = 0;
 
588
        winPtr->text.topline = 0;
 
589
        winPtr->text.buffer = (char *) 0;
 
590
        winPtr->text.data = (char **) 0;
 
591
        winPtr->butsel = 0;
 
592
        for (i = 0; i < MAXBUTTONS; i++)
 
593
                winPtr->button[i] = (char *) 0;
 
594
        return winPtr;
 
595
}
 
596
 
 
597
static int
 
598
winconfig(winPtr, interp, argc, argv)
 
599
        struct windata  *winPtr;
 
600
        Tcl_Interp      *interp;
 
601
        int             argc;
 
602
        char            *argv[];
 
603
{
 
604
        int i;
 
605
 
 
606
        DEBUG5("winconfig(%p, %p, %d, %p)\n", winPtr, interp, argc, argv);
 
607
        for (i = 2; i < argc-1; i += 2) {
 
608
                if (!strcmp(argv[i],"-shadow")) {
 
609
                        /* TBD */
 
610
                        Tcl_AppendResult(interp, "Not yet implemented", NULL);
 
611
                        return TCL_OK;
 
612
                } else if (!strcmp(argv[i],"-title")) {
 
613
                        if (winPtr->border == BORDER_NONE) {
 
614
                                Tcl_AppendResult(interp,
 
615
                                        "Only bordered windows can have titles",
 
616
                                        NULL);
 
617
                                return TCL_ERROR;
 
618
                        }
 
619
                        if (strlen(argv[i+1]) > winPtr->width-2) {
 
620
                                Tcl_AppendResult(interp,
 
621
                                        "Title too long", NULL);
 
622
                                return TCL_ERROR;
 
623
                        }
 
624
                        if (winPtr->title) {
 
625
                                ckfree(winPtr->title);
 
626
                                drawbox(winPtr, 0, 0, winPtr->height,
 
627
                                        winPtr->width, winPtr->border-1,
 
628
                                        ATTR_ULBORD, ATTR_LRBORD);
 
629
                        }
 
630
                        wmove(winPtr->win, 0, (winPtr->width-strlen(argv[i+1]))/2);
 
631
                        wattrset(winPtr->win, ATTR_TITLE);
 
632
                        waddstr(winPtr->win, argv[i+1]);
 
633
                } else if (!strcmp(argv[i],"-border")) {
 
634
                        if (!strcmp(argv[i+1], "none")) {
 
635
                                winPtr->border=BORDER_NONE;
 
636
                        } else if (!strcmp(argv[i+1], "blank")) {
 
637
                                winPtr->border=BORDER_BLANK;
 
638
                                drawbox(winPtr, 0, 0, winPtr->height,
 
639
                                        winPtr->width, 0, ATTR_ULBORD, ATTR_LRBORD);
 
640
                        } else if (!strcmp(argv[i+1], "line")) {
 
641
                                winPtr->border=BORDER_LINE;
 
642
                                drawbox(winPtr, 0, 0, winPtr->height,
 
643
                                        winPtr->width, 1, ATTR_ULBORD, ATTR_LRBORD);
 
644
                        } else {
 
645
                                Tcl_AppendResult(interp, "Invalid border type: ",
 
646
                                        argv[i+1], NULL);
 
647
                                return TCL_ERROR;
 
648
                        }
 
649
                } else {
 
650
                        Tcl_AppendResult(interp, "Invalid option: ",
 
651
                                argv[i], NULL);
 
652
                        return TCL_ERROR;
 
653
                }
 
654
        }
 
655
        DEBUG1("winconfig() returning okay\n");
 
656
        return TCL_OK;
 
657
}
 
658
 
 
659
static int
 
660
setmenu(winPtr, interp, argc, argv)
 
661
        struct windata  *winPtr;
 
662
        Tcl_Interp      *interp;
 
663
        int             argc;
 
664
        char            *argv[];
 
665
{
 
666
        int i, subx, suby, subwid, subht, winy, winx;
 
667
        static char *defaultbuttons[] = {"menu", "buttons", "Okay", "Cancel"};
 
668
 
 
669
        DEBUG5("setmenu(%p, %p, %d, %p)\n", winPtr, interp, argc, argv);
 
670
        if (winPtr->menu.data)
 
671
                ckfree(winPtr->menu.data);
 
672
        if (winPtr->menu.win)
 
673
                delwin(winPtr->menu.win);
 
674
        if (!(winPtr->menu.items = argc-3)) {
 
675
                winPtr->menu.lines = 0;
 
676
                winPtr->menu.topline = 0;
 
677
                winPtr->menu.current = 0;
 
678
                return TCL_OK;
 
679
        }
 
680
        subht = winPtr->menu.lines = atoi(argv[2]);
 
681
        i = winPtr->height - 3 - (winPtr->border? 3: 0);
 
682
        if (subht > i) {
 
683
                Tcl_AppendResult(interp, "Not enough room for menu window",
 
684
                        NULL);
 
685
                return TCL_ERROR;
 
686
        }
 
687
        winPtr->menu.data = (char **) ckalloc(sizeof(char *) * (argc-2));
 
688
        for (i = 0; i<argc-3; i++) {
 
689
                winPtr->menu.data[i] = strdup(argv[i+3]);
 
690
        }
 
691
        if (winPtr->menu.type == TYPE_CHECK) {
 
692
                winPtr->menu.chkd = (int *) ckalloc(sizeof(int) * (argc-3));
 
693
                for (i = 0; i<argc-3; i++) {
 
694
                        winPtr->menu.chkd[i] = 0;
 
695
                }
 
696
        }
 
697
        winPtr->menu.data[i] = NULL;
 
698
        if (!winPtr->button[0]) {
 
699
                if (setbuttons(winPtr, interp, 4, defaultbuttons) == TCL_ERROR)
 
700
                        return TCL_ERROR;
 
701
        }
 
702
        getbegyx(winPtr->win, winy, winx);
 
703
        subx = (winPtr->border? 3: 2);
 
704
        suby = winPtr->height - 2 - (winPtr->border? 2: 0) - subht;
 
705
        subwid = winPtr->width - (winPtr->border? 6: 4);
 
706
        if ((winPtr->menu.win = subwin(winPtr->win, subht, subwid,
 
707
                                        suby+winy, subx+winx)) == NULL) {
 
708
                Tcl_AppendResult(interp, "Unable to create menu subwindow",
 
709
                        NULL);
 
710
                return TCL_ERROR;
 
711
        }
 
712
        drawbox(winPtr, suby-1, subx-1, subht+2, subwid+2, 1,
 
713
                 ATTR_LRBORD, ATTR_ULBORD);
 
714
 
 
715
        if (updatemenu(winPtr, interp) == TCL_ERROR)
 
716
                return TCL_ERROR;
 
717
        if (updatetext(winPtr, interp) == TCL_ERROR)
 
718
                return TCL_ERROR;
 
719
        DEBUG1("setmenu() returning okay\n");
 
720
        return TCL_OK;
 
721
}
 
722
 
 
723
static int
 
724
updatemenu(winPtr, interp)
 
725
        struct windata  *winPtr;
 
726
        Tcl_Interp      *interp;
 
727
{
 
728
        int i, j, tmp, bottom, wid, ht;
 
729
        DEBUG3("updatemenu(%p, %p)\n", winPtr, interp);
 
730
        bottom = winPtr->menu.topline + winPtr->menu.lines - 1;
 
731
        DEBUG2("bottom = %d\n", bottom);
 
732
        if (winPtr->menu.current < winPtr->menu.topline) {
 
733
                winPtr->menu.topline = winPtr->menu.current;
 
734
        }
 
735
        if (winPtr->menu.current > bottom) {
 
736
                winPtr->menu.topline = winPtr->menu.current - winPtr->menu.lines + 1;
 
737
        }
 
738
        DEBUG5("menu.current=%d, menu.topline=%d, menu.lines=%d, bottom=%d\n",
 
739
                winPtr->menu.current, winPtr->menu.topline, (int) winPtr->menu.lines, bottom);
 
740
        getmaxyx(winPtr->menu.win, ht, wid);
 
741
        for (i = 0; i < winPtr->menu.lines; i++) {
 
742
                tmp = i+winPtr->menu.topline;
 
743
                if (tmp == winPtr->menu.current)
 
744
                        wattrset(winPtr->menu.win, ATTR_SELECT);
 
745
                else
 
746
                        wattrset(winPtr->menu.win, ATTR_TEXT);
 
747
                wmove(winPtr->menu.win, i, 0);
 
748
                for (j = 0; j < wid; j++)
 
749
                        waddch(winPtr->menu.win, ' ');
 
750
                if (tmp < winPtr->menu.items && winPtr->menu.data[tmp]) {
 
751
                        wmove(winPtr->menu.win, i, 0);
 
752
                        if (winPtr->menu.type == TYPE_RADIO) {
 
753
                                if (winPtr->menu.rsel == tmp)
 
754
                                        waddstr(winPtr->menu.win, "(X) ");
 
755
                                else
 
756
                                        waddstr(winPtr->menu.win, "( ) ");
 
757
                        }
 
758
                        if (winPtr->menu.type == TYPE_CHECK) {
 
759
                                if (winPtr->menu.chkd[tmp])
 
760
                                        waddstr(winPtr->menu.win, "[X] ");
 
761
                                else
 
762
                                        waddstr(winPtr->menu.win, "[ ] ");
 
763
                        }
 
764
                        waddstr(winPtr->menu.win, winPtr->menu.data[tmp]);
 
765
                }
 
766
        }
 
767
        return TCL_OK;
 
768
}
 
769
 
 
770
static int
 
771
setbuttons(winPtr, interp, argc, argv)
 
772
        struct windata  *winPtr;
 
773
        Tcl_Interp      *interp;
 
774
        int             argc;
 
775
        char            *argv[];
 
776
{
 
777
        int i, needlines=1, needcols=0;
 
778
 
 
779
        DEBUG5("setbuttons(%p, %p, %d, %p)\n", winPtr, interp, argc, argv);
 
780
        if (winPtr->text.items) needlines++;
 
781
        if (winPtr->border) {
 
782
                needlines+= winPtr->text.items? 3:2;
 
783
                needcols+=2;
 
784
        }
 
785
        for (i = 2; i < argc; i++) {
 
786
                needcols += strlen(argv[i]) + 3;
 
787
        }
 
788
        if (winPtr->height < needlines || winPtr->width < needcols) {
 
789
                Tcl_AppendResult(interp, "Window too small", NULL);
 
790
                return TCL_ERROR;
 
791
        }
 
792
        if (winPtr->border && winPtr->text.items) {
 
793
                wattrset(winPtr->win, ATTR_ULBORD);
 
794
                wmove(winPtr->win, winPtr->height-3, 0);
 
795
                waddch(winPtr->win, ACS_LTEE);
 
796
                for (i = 0; i < winPtr->width-2; i++)
 
797
                        waddch(winPtr->win, ACS_HLINE);
 
798
                wattrset(winPtr->win, ATTR_LRBORD);
 
799
                waddch(winPtr->win, ACS_RTEE);
 
800
        }
 
801
        for (i = 0; i < MAXBUTTONS; i++) {
 
802
                if (winPtr->button[i])
 
803
                        ckfree(winPtr->button);
 
804
        }
 
805
        for (i = 0; argv[i+2]; i++)
 
806
                winPtr->button[i] = strdup(argv[i+2]);
 
807
        updatebuttons(winPtr);
 
808
        DEBUG1("setbuttons() returning okay\n");
 
809
        return TCL_OK;
 
810
}
 
811
 
 
812
static void
 
813
updatebuttons(winPtr)
 
814
        struct windata  *winPtr;
 
815
{
 
816
        int i, j, numbuttons, needcols=0, x, y;
 
817
 
 
818
        DEBUG1("updatebuttons(winPtr)\n");
 
819
 
 
820
        getyx(winPtr->win, y, x);
 
821
        for (i = numbuttons = 0; i < MAXBUTTONS; i++) {
 
822
                if (winPtr->button[i])
 
823
                        numbuttons++;
 
824
                else
 
825
                        break;
 
826
        }
 
827
        if (winPtr->border)
 
828
                needcols+=2;
 
829
        for (i = 0; i < numbuttons; i++) {
 
830
                needcols += strlen(winPtr->button[i]) + 3;
 
831
        }
 
832
        wmove(winPtr->win, winPtr->height-2, 1);
 
833
        for (i = 0; i < winPtr->width-2; i++) {
 
834
                waddch(winPtr->win, ' ');
 
835
        }
 
836
        wmove(winPtr->win, winPtr->height-2, 1);
 
837
        wattrset(winPtr->win, ATTR_TEXT);
 
838
        for (i = 0; i < numbuttons; i++) {
 
839
                for (j = 0; j < (winPtr->width-needcols)/(numbuttons+1); j++)
 
840
                        waddch(winPtr->win, ' ');
 
841
                if (winPtr->butsel == i) {
 
842
                        wattrset(winPtr->win, ATTR_SELECT);
 
843
                        getyx(winPtr->win, y, x);
 
844
                }
 
845
                waddch(winPtr->win, '<');
 
846
                waddstr(winPtr->win, winPtr->button[i]);
 
847
                waddch(winPtr->win, '>');
 
848
                wattrset(winPtr->win, ATTR_TEXT);
 
849
        }
 
850
        wmove(winPtr->win, y, x+1);
 
851
}
 
852
 
 
853
static void
 
854
drawbox(winPtr, begrow, begcol, rows, cols, lchar, ulattr, lrattr)
 
855
        struct windata  *winPtr;
 
856
        int             begrow, begcol, rows, cols, lchar;
 
857
        chtype          ulattr, lrattr;
 
858
{
 
859
        int i;
 
860
 
 
861
#define bchar(ch)       (lchar? (ch): ' ')
 
862
 
 
863
        DEBUG9("drawbox(%p, %d, %d, %d, %d, %d, %lx, %lx)\n",
 
864
                winPtr, begrow, begcol, rows, cols, lchar, ulattr, lrattr);
 
865
        wattrset(winPtr->win, ulattr);
 
866
        wmove(winPtr->win, begrow, begcol);
 
867
        waddch(winPtr->win, bchar(ACS_ULCORNER));
 
868
        for (i=0; i<cols-2; i++)
 
869
                waddch(winPtr->win, bchar(ACS_HLINE));
 
870
        wattrset(winPtr->win, lrattr);
 
871
        waddch(winPtr->win, bchar(ACS_URCORNER));
 
872
        for (i=begrow+1; i<begrow+rows-1; i++) {
 
873
                wattrset(winPtr->win, ulattr);
 
874
                mvwaddch(winPtr->win,i,begcol,bchar(ACS_VLINE));
 
875
                wattrset(winPtr->win, lrattr);
 
876
                mvwaddch(winPtr->win,i,begcol+cols-1,bchar(ACS_VLINE));
 
877
        }
 
878
        wmove(winPtr->win, begrow+rows-1, begcol);
 
879
        wattrset(winPtr->win, ulattr);
 
880
        waddch(winPtr->win, bchar(ACS_LLCORNER));
 
881
        wattrset(winPtr->win, lrattr);
 
882
        for (i=0; i<cols-2; i++)
 
883
                waddch(winPtr->win, bchar(ACS_HLINE));
 
884
        waddch(winPtr->win, bchar(ACS_LRCORNER));
 
885
}
 
886
 
 
887
#endif  /* CURSES */