forked from mbert/elvis
-
Notifications
You must be signed in to change notification settings - Fork 0
/
guicurs.c
440 lines (386 loc) · 10.3 KB
/
guicurs.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
/* guicurs.c */
/* Copyright 1995 by Steve Kirkendall */
#define WINDOW elviswin
#include "elvis.h"
#ifdef FEATURE_RCSID
char id_guicurs[] = "$Id: guicurs.c,v 2.25 2003/10/17 17:41:23 steve Exp $";
#endif
#undef WINDOW
#ifdef GUI_CURSES
#include <curses.h>
/* Graphic characters */
#ifndef ACS_ULCORNER
# define ACS_ULCORNER '.'
# define ACS_LLCORNER '`'
# define ACS_URCORNER '.'
# define ACS_LRCORNER '\''
# define ACS_RTEE '|'
# define ACS_LTEE '|'
# define ACS_BTEE '^'
# define ACS_TTEE '-'
# define ACS_HLINE '-'
# define ACS_VLINE '|'
# define ACS_PLUS '+'
# define ACS(w, on_off)
#else
# define ACS(w, on_off) wattrset(w, (on_off) ? A_ALTCHARSET : A_NORMAL);
#endif
typedef struct cwin_s
{
struct cwin_s *next; /* pointer to some other window */
WINDOW *frame; /* the window plus the frame */
WINDOW *window; /* the text portion of the window */
char *title; /* name of the window */
int rows, columns; /* size of the window, in cells */
int ypos, xpos; /* position on the screen */
} CWIN;
#if USE_PROTOTYPES
static ELVBOOL clr2eol(GUIWIN *gw);
static ELVBOOL creategw(char *name, char *firstcmd);
static ELVBOOL focusgw (GUIWIN *gw);
static int init(int argc, char **argv);
static int test(void);
static void bell(GUIWIN *gw);
static void destroygw(GUIWIN *gw, ELVBOOL force);
static void draw(GUIWIN *gw, _char_ font, CHAR *text, int len);
static void flush(void);
static void loop(void);
static void moveto(GUIWIN *gw, int column, int row);
static void retitle(GUIWIN *gw, char *name);
static void term(void);
#endif
CWIN *winlist, *current;
/* Test whether this GUI is available in this environment.
* Returns 0 if the GUI is unavailable, or 1 if available.
* This should not have any visible side-effects. If the
* GUI can't be tested without side-effects, then this
* function should return 2 to indicate "maybe available".
*/
static int test()
{
return getenv("TERMCAP") ? 1 : 0;
}
/* Start the GUI.
*
* argc and argv are the command line arguments. The GUI
* may scan the arguments for GUI-specific options; if it
* finds any, then they should be deleted from the argv list.
* The resulting value of argc should be returned normally.
* If the GUI couldn't initialize itself, it should emit an
* error message and return -1.
*
* Other than "name" and "test", no other fields of the GUI
* structure are accessed before this function has been called.
*/
static int init(argc, argv)
int argc; /* number of command-line arguments */
char **argv; /* values of command-line arguments */
{
initscr();
raw();
noecho();
nonl();
return argc;
}
/* In a loop, receive events from the GUI and call elvis
* functions which will act on the event. When this function
* returns, elvis will call the GUI's term() function and then exit.
* (This function should return only when the number of windows becomes 0.)
*/
static void loop()
{
int key;
CHAR text[10];
int len;
CWIN *cwin;
/* peform the -c command or -t tag */
if (mainfirstcmd(windefault))
return;
/* loop until we don't have any windows left */
while (winlist)
{
/* refresh all windows, expecially the current one */
for (cwin = winlist; cwin; cwin = cwin->next)
{
eventdraw((GUIWIN *)cwin);
wrefresh(cwin->frame);
}
touchwin(current->frame);
wrefresh(current->frame);
wrefresh(current->window);
/* read the next event */
key = wgetch(current->frame);
/* process the event */
text[0] = key;
len = 1;
eventfocus((GUIWIN *)current);
(void)eventkeys((GUIWIN *)current, text, len);
}
}
/* End the GUI. For "termcap" this means switching the
* the terminal back into "cooked" mode. For "x11", the
* window should be deleted and any other X resources freed.
*
* This function is called after all windows have been deleted
* by delwin(), when elvis is about to terminate.
*/
static void term()
{
move(LINES-1, 0);
clrtoeol();
refresh();
nl();
noraw();
echo();
endwin();
}
/* This function makes a particular window current -- placing on top of all
* other windows, and sending any keystrokes to it.
*/
static ELVBOOL focusgw(gw)
GUIWIN *gw; /* window to receive keystrokes */
{
int i;
CWIN *cw = (CWIN *)gw;
/* if some other window was already current, it isn't now */
if (current)
{
/* draw the frame around the window */
ACS(current->frame, ElvTrue);
box(current->frame, ACS_VLINE, ACS_HLINE);
ACS(current->frame, ElvFalse);
wstandout(current->frame);
mvwprintw(current->frame, 0, 0, "%.*s", current->columns + 2, current->title); /* nishi */
wstandend(current->frame);
wrefresh(current->frame);
}
/* make the new window current */
current = cw;
/* draw a *highlighted* frame around the window */
wstandout(cw->frame);
for (i = 0; i < current->rows + 2; i++)
{
mvwaddch(cw->frame, i, 0, ' ');
mvwaddch(cw->frame, i, cw->columns + 1, ' ');
}
for (i = 1; i < cw->columns + 1; i++)
{
mvwaddch(cw->frame, 0, i, ' ');
mvwaddch(cw->frame, cw->rows + 1, i, ' ');
}
mvwprintw(cw->frame, 0, 0, "%.*s", cw->columns + 2, cw->title);
wstandend(cw->frame);
return ElvTrue;
}
/* Create a new window for the buffer named name. If successful,
* return TRUE and then simulate a "create" event later. Return
* FALSE if the GUIWIN can't be created, e.g., because the GUI doesn't
* support multiple windows. The msg() function should be called to
* describe the reason for the failure.
*/
static ELVBOOL creategw(name, firstcmd)
char *name; /* name of window to create */
char *firstcmd; /* first command to execute in window */
{
CWIN *newp;
/* allocate storate space for the window */
newp = (CWIN *)safealloc(1, sizeof(CWIN));
newp->next = winlist;
/* initialize it. */
winlist = newp;
newp->rows = 18;
newp->columns = 70;
newp->ypos = rand() & 3;
newp->xpos = rand() & 7;
newp->frame = newwin(newp->rows + 2, newp->columns + 2, newp->ypos, newp->xpos);
newp->window = subwin(newp->frame, newp->rows, newp->columns, newp->ypos + 1, newp->xpos + 1);
newp->title = safedup(name);
leaveok(newp->frame, ElvTrue);
/* make it the current window */
focusgw((GUIWIN *)newp);
/* simulate a "window create" event */
eventcreate((GUIWIN *)newp, NULL, name, newp->rows, newp->columns);
/* execute the firstcmd, if any */
if (firstcmd)
{
winoptions(winofgw((GUIWIN *)newp));
exstring(windefault, toCHAR(firstcmd), "+cmd");
}
return ElvTrue;
}
/* Simulate a "destroy" event for the window. */
static void destroygw(gw, force)
GUIWIN *gw; /* window to destroy */
ELVBOOL force; /* if ElvTrue, try harder to destroy the window */
{
CWIN *cw, *prev;
/* find the doomed window */
for (cw = winlist, prev = NULL; cw != (CWIN *)gw; prev = cw, cw = cw->next)
{
assert(cw->next != NULL);
}
eventdestroy((GUIWIN *)cw);
/* delete the window from the list of existing windows */
if (prev)
{
prev->next = cw->next;
}
else
{
winlist = cw->next;
}
/* if it was current, it isn't now! */
if (current == cw && winlist != NULL)
{
focusgw((GUIWIN *)winlist);
}
/* free the window's resources */
safefree(cw->title);
werase(cw->window); /* nishi */
werase(cw->frame); /* nishi */
wrefresh(cw->window); /* nishi */
wrefresh(cw->frame); /* nishi */
delwin(cw->window);
delwin(cw->frame);
safefree(cw);
}
/* Change the title of the window. This function is called when a
* buffer's name changes, or different window becomes associated with
* a window. The name argument is the new buffer name.
*/
static void retitle(gw, name)
GUIWIN *gw; /* window to be retitled */
char *name; /* new title (nul-terminated) */
{
CWIN *cw = (CWIN *)gw;
safefree(cw->title);
cw->title = safedup(name);
focusgw((GUIWIN *)cw);
}
/* Flush all changes out to the screen */
static void flush()
{
CWIN *cw;
for (cw = winlist; cw; cw = cw->next)
{
wrefresh(cw->frame);
}
}
/* Move the cursor to a given character cell. The upper left
* character cell is designated column 0, row 0.
*/
static void moveto(gw, column, row)
GUIWIN *gw; /* window whose cursor should move */
int column; /* column to move to */
int row; /* row to move to */
{
CWIN *cw = (CWIN *)gw;
wmove(cw->window, row, column);
}
/* Displays text on the screen, starting at the cursor's
* current position, in the given font. The text string is
* guaranteed to contain only printable characters.
*
* The font is indicated by a single letter. The letter will
* be lowercase normally, or uppercase to indicate that the
* text should be visibly marked for the <v> and <V> commands.
* The letters are:
* n/N normal characters
* b/B bold characters
* i/I italic characters
* u/U underlined characters
* g/G graphic characters
* s standout (used for messages on bottom row)
* p popup menu
*
* This function should move the text cursor to the end of
* the output text.
*/
static void draw(gw, font, text, len)
GUIWIN *gw; /* window where text should be displayed */
_char_ font; /* font to use */
CHAR *text; /* text to be drawn */
int len; /* length of text */
{
CWIN *cw = (CWIN *)gw;
if (font == 'p' || elvupper(font))
{
wstandout(cw->window);
wprintw(cw->window, "%.*s", len, text);
wstandend(cw->window);
}
else
{
#ifdef A_NORMAL
switch (font)
{
case 'b':
case 'e': wattrset(cw->window, A_BOLD); break;
case 'u': wattrset(cw->window, A_UNDERLINE); break;
case 'i': wattrset(cw->window, A_DIM); break;
default: wattrset(cw->window, A_NORMAL);
}
#endif
wprintw(cw->window, "%.*s", len, text);
}
}
static ELVBOOL clr2eol(gw)
GUIWIN *gw; /* window whose row is to be cleared */
{
CWIN *cw = (CWIN *)gw;
wclrtoeol(cw->window);
return ElvTrue;
}
static void bell(gw)
GUIWIN *gw; /* window that generated a bell request */
{
ttywrite("\007", 1);
}
GUI guicurses =
{
"curses", /* name */
"Curses-based text interface",
ElvFalse, /* exonly */
ElvFalse, /* newblank */
ElvFalse, /* minimizeclr */
ElvTrue, /* scrolllast */
ElvFalse, /* shiftrows */
0, /* movecost */
0, /* nopts */
NULL, /* optdescs */
test,
init,
NULL, /* usage */
loop,
NULL, /* wpoll */
term,
creategw,
destroygw,
focusgw,
retitle,
NULL, /* reset */
flush,
moveto,
draw,
NULL, /* shift */
NULL, /* scroll */
clr2eol,
NULL, /* newline */
bell,
NULL, /* msg */
NULL, /* scrollbar */
NULL, /* status */
NULL, /* keylabel */
NULL, /* clipopen */
NULL, /* clipwrite */
NULL, /* clipread */
NULL, /* clipclose */
NULL, /* color */
NULL, /* guicmd */
NULL, /* tabcmd */
NULL, /* save */
NULL, /* wildcard */
NULL, /* prgopen */
NULL /* prgclose */
};
#endif