]>
Commit | Line | Data |
---|---|---|
45f6c4fd | 1 | #include "config.h" |
2 | ||
4bb1be99 | 3 | #include <sys/types.h> |
4 | ||
139f06bc | 5 | #include <slang.h> |
6fb96a3f | 6 | #include <stdarg.h> |
7 | #include <stdlib.h> | |
4bb1be99 | 8 | #ifdef HAVE_SYS_SELECT_H |
d02ffb49 | 9 | #include <sys/select.h> |
4bb1be99 | 10 | #endif |
e67a6cab | 11 | #include <sys/time.h> |
6fb96a3f | 12 | |
33b9b6eb | 13 | #ifdef USE_GPM |
14 | #include <ctype.h> | |
15 | #include <sys/time.h> /* timeval */ | |
33b9b6eb | 16 | #include <sys/socket.h> /* socket() */ |
17 | #include <sys/un.h> /* struct sockaddr_un */ | |
18 | #include <sys/fcntl.h> /* O_RDONLY */ | |
19 | #include <sys/stat.h> /* stat() */ | |
20 | #include <termios.h> /* winsize */ | |
21 | #include <unistd.h> | |
22 | #include <sys/kd.h> /* KDGETMODE */ | |
23 | #include <signal.h> | |
24 | #include <stdio.h> | |
45f6c4fd | 25 | #endif |
26 | ||
6fb96a3f | 27 | #include "newt.h" |
28 | #include "newt_pr.h" | |
29 | ||
33b9b6eb | 30 | #ifdef USE_GPM |
31 | /*....................................... The connection data structure */ | |
32 | ||
33 | typedef struct Gpm_Connect { | |
34 | unsigned short eventMask, defaultMask; | |
35 | unsigned short minMod, maxMod; | |
36 | int pid; | |
37 | int vc; | |
38 | } Gpm_Connect; | |
39 | ||
40 | /*....................................... Stack struct */ | |
41 | typedef struct Gpm_Stst { | |
42 | Gpm_Connect info; | |
43 | struct Gpm_Stst *next; | |
44 | } Gpm_Stst; | |
45 | ||
46 | enum Gpm_Etype { | |
47 | GPM_MOVE=1, | |
48 | GPM_DRAG=2, /* exactly one of the bare ones is active at a time */ | |
49 | GPM_DOWN=4, | |
50 | GPM_UP= 8, | |
51 | ||
52 | #define GPM_BARE_EVENTS(type) ((type)&(0x0f|GPM_ENTER|GPM_LEAVE)) | |
53 | ||
54 | GPM_SINGLE=16, /* at most one in three is set */ | |
55 | GPM_DOUBLE=32, | |
56 | GPM_TRIPLE=64, /* WARNING: I depend on the values */ | |
57 | ||
58 | GPM_MFLAG=128, /* motion during click? */ | |
59 | GPM_HARD=256, /* if set in the defaultMask, force an already | |
60 | used event to pass over to another handler */ | |
61 | ||
62 | GPM_ENTER=512, /* enter event, user in Roi's */ | |
63 | GPM_LEAVE=1024 /* leave event, used in Roi's */ | |
64 | }; | |
65 | ||
66 | /*....................................... The reported event */ | |
67 | ||
68 | enum Gpm_Margin {GPM_TOP=1, GPM_BOT=2, GPM_LFT=4, GPM_RGT=8}; | |
69 | ||
70 | typedef struct Gpm_Event { | |
71 | unsigned char buttons, modifiers; /* try to be a multiple of 4 */ | |
72 | unsigned short vc; | |
73 | short dx, dy, x, y; | |
74 | enum Gpm_Etype type; | |
75 | int clicks; | |
76 | enum Gpm_Margin margin; | |
77 | } Gpm_Event; | |
78 | ||
79 | static int Gpm_Open(Gpm_Connect *conn, int flag); | |
80 | static int Gpm_Close(void); | |
81 | ||
82 | static int gpm_fd=-1; | |
83 | static int gpm_flag=0; | |
84 | static int gpm_tried=0; | |
85 | Gpm_Stst *gpm_stack=NULL; | |
36ccb508 | 86 | static char *gpm_sock_name=NULL; |
33b9b6eb | 87 | static struct sigaction gpm_saved_suspend_hook; |
88 | static struct sigaction gpm_saved_winch_hook; | |
89 | ||
90 | #define GPM_XTERM_ON | |
91 | #define GPM_XTERM_OFF | |
92 | #define GPM_NODE_DEV "/dev/gpmctl" | |
93 | #define GPM_NODE_CTL GPM_NODE_DEV | |
94 | ||
95 | static inline int putdata(int where, Gpm_Connect *what) | |
96 | { | |
97 | if (write(where,what,sizeof(Gpm_Connect))!=sizeof(Gpm_Connect)) | |
98 | { | |
99 | return -1; | |
100 | } | |
101 | return 0; | |
102 | } | |
103 | ||
104 | static void gpm_winch_hook (int signum) | |
105 | { | |
106 | if (SIG_IGN != gpm_saved_winch_hook.sa_handler && | |
107 | SIG_DFL != gpm_saved_winch_hook.sa_handler) { | |
108 | gpm_saved_winch_hook.sa_handler(signum); | |
109 | } /*if*/ | |
110 | } | |
111 | ||
112 | static void gpm_suspend_hook (int signum) | |
113 | { | |
114 | Gpm_Connect gpm_connect; | |
115 | sigset_t old_sigset; | |
116 | sigset_t new_sigset; | |
117 | struct sigaction sa; | |
118 | int success; | |
119 | ||
120 | sigemptyset (&new_sigset); | |
121 | sigaddset (&new_sigset, SIGTSTP); | |
122 | sigprocmask (SIG_BLOCK, &new_sigset, &old_sigset); | |
123 | ||
124 | /* Open a completely transparent gpm connection */ | |
125 | gpm_connect.eventMask = 0; | |
126 | gpm_connect.defaultMask = ~0; | |
127 | gpm_connect.minMod = ~0; | |
128 | gpm_connect.maxMod = 0; | |
129 | /* cannot do this under xterm, tough */ | |
130 | success = (Gpm_Open (&gpm_connect, 0) >= 0); | |
131 | ||
132 | /* take the default action, whatever it is (probably a stop :) */ | |
133 | sigprocmask (SIG_SETMASK, &old_sigset, 0); | |
134 | sigaction (SIGTSTP, &gpm_saved_suspend_hook, 0); | |
135 | kill (getpid (), SIGTSTP); | |
136 | ||
137 | /* in bardo here */ | |
138 | ||
139 | /* Reincarnation. Prepare for another death early. */ | |
140 | sigemptyset(&sa.sa_mask); | |
141 | sa.sa_handler = gpm_suspend_hook; | |
142 | sa.sa_flags = SA_NOMASK; | |
143 | sigaction (SIGTSTP, &sa, 0); | |
144 | ||
145 | /* Pop the gpm stack by closing the useless connection */ | |
146 | /* but do it only when we know we opened one.. */ | |
147 | if (success) { | |
148 | Gpm_Close (); | |
149 | } /*if*/ | |
150 | } | |
151 | ||
152 | static int Gpm_Open(Gpm_Connect *conn, int flag) | |
153 | { | |
154 | char tty[32]; | |
155 | char *term; | |
156 | int i; | |
157 | struct sockaddr_un addr; | |
158 | Gpm_Stst *new; | |
33b9b6eb | 159 | |
160 | /*....................................... First of all, check xterm */ | |
161 | ||
162 | if ((term=(char *)getenv("TERM")) && !strncmp(term,"xterm",5)) | |
163 | { | |
164 | if (gpm_tried) return gpm_fd; /* no stack */ | |
165 | gpm_fd=-2; | |
166 | GPM_XTERM_ON; | |
167 | gpm_flag=1; | |
168 | return gpm_fd; | |
169 | } | |
170 | /*....................................... No xterm, go on */ | |
171 | ||
172 | ||
173 | /* | |
174 | * So I chose to use the current tty, instead of /dev/console, which | |
175 | * has permission problems. (I am fool, and my console is | |
176 | * readable/writeable by everybody. | |
177 | * | |
178 | * However, making this piece of code work has been a real hassle. | |
179 | */ | |
180 | ||
181 | if (!gpm_flag && gpm_tried) return -1; | |
182 | gpm_tried=1; /* do or die */ | |
183 | ||
184 | new=malloc(sizeof(Gpm_Stst)); | |
185 | if (!new) return -1; | |
186 | ||
187 | new->next=gpm_stack; | |
188 | gpm_stack=new; | |
189 | ||
190 | conn->pid=getpid(); /* fill obvious values */ | |
191 | ||
192 | if (new->next) | |
193 | conn->vc=new->next->info.vc; /* inherit */ | |
194 | else | |
195 | { | |
196 | conn->vc=0; /* default handler */ | |
197 | if (flag>0) | |
198 | { /* forced vc number */ | |
199 | conn->vc=flag; | |
200 | sprintf(tty,"/dev/tty%i",flag); | |
201 | } | |
202 | else if (flag==0) /* use your current vc */ | |
203 | { | |
204 | char *t = ttyname(0); /* stdin */ | |
205 | if (!t) t = ttyname(1); /* stdout */ | |
206 | if (!t) goto err; | |
207 | strcpy(tty,t); | |
208 | if (strncmp(tty,"/dev/tty",8) || !isdigit(tty[8])) | |
209 | goto err; | |
210 | conn->vc=atoi(tty+8); | |
211 | } | |
212 | else /* a default handler -- use console */ | |
213 | sprintf(tty,"/dev/tty0"); | |
214 | ||
215 | } | |
216 | ||
217 | new->info=*conn; | |
218 | ||
219 | /*....................................... Connect to the control socket */ | |
220 | ||
221 | if (!(gpm_flag++)) | |
222 | { | |
223 | ||
224 | if ( (gpm_fd=socket(AF_UNIX,SOCK_STREAM,0))<0 ) | |
225 | { | |
226 | goto err; | |
227 | } | |
228 | ||
229 | bzero((char *)&addr,sizeof(addr)); | |
230 | addr.sun_family=AF_UNIX; | |
36ccb508 | 231 | if (!(gpm_sock_name = tempnam (0, "gpm"))) { |
33b9b6eb | 232 | goto err; |
233 | } /*if*/ | |
36ccb508 | 234 | strncpy (addr.sun_path, gpm_sock_name, sizeof (addr.sun_path)); |
33b9b6eb | 235 | if (bind (gpm_fd, (struct sockaddr*)&addr, |
236 | sizeof (addr.sun_family) + strlen (addr.sun_path))==-1) { | |
237 | goto err; | |
238 | } /*if*/ | |
239 | ||
240 | bzero((char *)&addr,sizeof(addr)); | |
241 | addr.sun_family=AF_UNIX; | |
242 | strcpy(addr.sun_path, GPM_NODE_CTL); | |
243 | i=sizeof(addr.sun_family)+strlen(GPM_NODE_CTL); | |
244 | ||
245 | if ( connect(gpm_fd,(struct sockaddr *)(&addr),i)<0 ) | |
246 | { | |
247 | struct stat stbuf; | |
248 | ||
249 | /* | |
250 | * Well, try to open a chr device called /dev/gpmctl. This should | |
251 | * be forward-compatible with a kernel server | |
252 | */ | |
253 | close(gpm_fd); /* the socket */ | |
254 | if ((gpm_fd=open(GPM_NODE_DEV,O_RDWR))==-1) { | |
255 | goto err; | |
256 | } /*if*/ | |
257 | if (fstat(gpm_fd,&stbuf)==-1 || (stbuf.st_mode&S_IFMT)!=S_IFCHR) | |
258 | goto err; | |
259 | } | |
260 | } | |
261 | /*....................................... Put your data */ | |
262 | ||
263 | if (putdata(gpm_fd,conn)!=-1) | |
264 | { | |
265 | /* itz Wed Dec 16 23:22:16 PST 1998 use sigaction, the old | |
266 | code caused a signal loop under XEmacs */ | |
267 | struct sigaction sa; | |
268 | sigemptyset(&sa.sa_mask); | |
269 | ||
270 | #if (defined(SIGWINCH)) | |
271 | /* And the winch hook .. */ | |
272 | sa.sa_handler = gpm_winch_hook; | |
273 | sa.sa_flags = 0; | |
274 | sigaction(SIGWINCH, &sa, &gpm_saved_winch_hook); | |
275 | #endif | |
276 | ||
277 | #if (defined(SIGTSTP)) | |
278 | if (gpm_flag == 1) { | |
279 | /* Install suspend hook */ | |
280 | sa.sa_handler = SIG_IGN; | |
281 | sigaction(SIGTSTP, &sa, &gpm_saved_suspend_hook); | |
282 | ||
283 | /* if signal was originally ignored, job control is not supported */ | |
284 | if (gpm_saved_suspend_hook.sa_handler != SIG_IGN) { | |
285 | sa.sa_flags = SA_NOMASK; | |
286 | sa.sa_handler = gpm_suspend_hook; | |
287 | sigaction(SIGTSTP, &sa, 0); | |
288 | } /*if*/ | |
289 | } /*if*/ | |
290 | #endif | |
291 | ||
292 | } /*if*/ | |
293 | return gpm_fd; | |
294 | ||
295 | /*....................................... Error: free all memory */ | |
296 | err: | |
297 | do | |
298 | { | |
299 | new=gpm_stack->next; | |
300 | free(gpm_stack); | |
301 | gpm_stack=new; | |
302 | } | |
303 | while(gpm_stack); | |
304 | if (gpm_fd>=0) close(gpm_fd); | |
36ccb508 ML |
305 | if (gpm_sock_name) { |
306 | unlink(gpm_sock_name); | |
307 | free(gpm_sock_name); | |
308 | gpm_sock_name = NULL; | |
33b9b6eb | 309 | } /*if*/ |
310 | gpm_flag=0; | |
9a3aad92 | 311 | gpm_fd=-1; |
33b9b6eb | 312 | return -1; |
313 | } | |
314 | ||
315 | /*-------------------------------------------------------------------*/ | |
316 | static int Gpm_Close(void) | |
317 | { | |
318 | Gpm_Stst *next; | |
319 | ||
320 | gpm_tried=0; /* reset the error flag for next time */ | |
321 | if (gpm_fd==-2) /* xterm */ | |
322 | GPM_XTERM_OFF; | |
323 | else /* linux */ | |
324 | { | |
325 | if (!gpm_flag) return 0; | |
326 | next=gpm_stack->next; | |
327 | free(gpm_stack); | |
328 | gpm_stack=next; | |
329 | if (next) | |
330 | putdata(gpm_fd,&(next->info)); | |
331 | ||
332 | if (--gpm_flag) return -1; | |
333 | } | |
334 | ||
335 | if (gpm_fd>=0) close(gpm_fd); | |
336 | gpm_fd=-1; | |
36ccb508 ML |
337 | if (gpm_sock_name) { |
338 | unlink(gpm_sock_name); | |
339 | free(gpm_sock_name); | |
340 | gpm_sock_name = NULL; | |
341 | } | |
33b9b6eb | 342 | #ifdef SIGTSTP |
343 | sigaction(SIGTSTP, &gpm_saved_suspend_hook, 0); | |
344 | #endif | |
345 | #ifdef SIGWINCH | |
346 | sigaction(SIGWINCH, &gpm_saved_winch_hook, 0); | |
347 | #endif | |
348 | return 0; | |
349 | } | |
350 | ||
351 | /*-------------------------------------------------------------------*/ | |
352 | static int Gpm_GetEvent(Gpm_Event *event) | |
353 | { | |
354 | int count; | |
355 | ||
356 | if (!gpm_flag) return 0; | |
357 | ||
358 | if ((count=read(gpm_fd,event,sizeof(Gpm_Event)))!=sizeof(Gpm_Event)) | |
359 | { | |
360 | if (count==0) | |
361 | { | |
362 | Gpm_Close(); | |
363 | return 0; | |
364 | } | |
365 | return -1; | |
366 | } | |
367 | return 1; | |
368 | } | |
369 | #endif | |
370 | ||
f5daa14e | 371 | /**************************************************************************** |
45f6c4fd | 372 | These forms handle vertical scrolling of components with a height of 1 |
373 | ||
f5daa14e | 374 | Horizontal scrolling won't work, and scrolling large widgets will fail |
375 | miserably. It shouldn't be too hard to fix either of those if anyone | |
376 | cares to. I only use scrolling for listboxes and text boxes though so | |
377 | I didn't bother. | |
378 | *****************************************************************************/ | |
379 | ||
380 | struct element { | |
5c72fb03 | 381 | newtComponent co; |
f5daa14e | 382 | }; |
383 | ||
d02ffb49 | 384 | struct fdInfo { |
385 | int fd; | |
386 | int flags; | |
387 | }; | |
388 | ||
c4827b34 | 389 | struct form { |
6fb96a3f | 390 | int numCompsAlloced; |
f5daa14e | 391 | struct element * elements; |
6fb96a3f | 392 | int numComps; |
393 | int currComp; | |
8c4e1047 | 394 | int fixedHeight; |
02b180e8 | 395 | int flags; |
f5daa14e | 396 | int vertOffset; |
02b180e8 | 397 | newtComponent vertBar, exitComp; |
d4109c37 | 398 | const char * help; |
f1f3611f | 399 | int numRows; |
da151ca8 | 400 | int * hotKeys; |
401 | int numHotKeys; | |
8f4e87fc | 402 | int background; |
d02ffb49 | 403 | int numFds; |
404 | struct fdInfo * fds; | |
405 | int maxFd; | |
e67a6cab | 406 | int timer; /* in milliseconds */ |
407 | struct timeval lastTimeout; | |
72b71fa6 | 408 | void * helpTag; |
409 | newtCallback helpCb; | |
6fb96a3f | 410 | }; |
411 | ||
ad2dca95 | 412 | static void gotoComponent(newtComponent co, int newComp); |
c4827b34 | 413 | static struct eventResult formEvent(newtComponent co, struct event ev); |
434c766b | 414 | static struct eventResult sendEvent(newtComponent comp, struct event ev); |
8f52cd47 | 415 | static void formPlace(newtComponent co, int left, int top); |
c4827b34 | 416 | |
72b71fa6 | 417 | /* Global, ick */ |
418 | static newtCallback helpCallback; | |
419 | ||
8f52cd47 | 420 | /* this isn't static as grid.c tests against it to find forms */ |
421 | struct componentOps formOps = { | |
8b68158d | 422 | newtDrawForm, |
c4827b34 | 423 | formEvent, |
424 | newtFormDestroy, | |
8f52cd47 | 425 | formPlace, |
426 | newtDefaultMappedHandler, | |
c4827b34 | 427 | } ; |
428 | ||
0593cb33 ML |
429 | int needResize = 0; |
430 | ||
f5daa14e | 431 | static inline int componentFits(newtComponent co, int compNum) { |
432 | struct form * form = co->data; | |
433 | struct element * el = form->elements + compNum; | |
434 | ||
5c72fb03 ML |
435 | if (co->top > el->co->top) |
436 | return 0; | |
437 | if (co->top + co->height < el->co->top + el->co->height) | |
438 | return 0; | |
f5daa14e | 439 | |
440 | return 1; | |
441 | } | |
442 | ||
72b71fa6 | 443 | newtComponent newtForm(newtComponent vertBar, void * help, int flags) { |
c4827b34 | 444 | newtComponent co; |
445 | struct form * form; | |
446 | ||
447 | co = malloc(sizeof(*co)); | |
d92e05d0 RG |
448 | if (co == NULL) |
449 | return NULL; | |
450 | ||
c4827b34 | 451 | form = malloc(sizeof(*form)); |
d92e05d0 RG |
452 | if (form == NULL) { |
453 | free(co); | |
454 | return NULL; | |
455 | } | |
456 | ||
c4827b34 | 457 | co->data = form; |
458 | co->width = 0; | |
459 | co->height = 0; | |
460 | co->top = -1; | |
461 | co->left = -1; | |
3da9c9a2 | 462 | co->isMapped = 0; |
c4827b34 | 463 | |
6f481af2 | 464 | co->takesFocus = 0; /* we may have 0 components */ |
c4827b34 | 465 | co->ops = &formOps; |
ad2dca95 | 466 | co->callback = NULL; |
c101e99e | 467 | co->destroyCallback = NULL; |
6fb96a3f | 468 | |
d92e05d0 RG |
469 | form->elements = NULL; |
470 | form->hotKeys = NULL; | |
471 | ||
02b180e8 | 472 | form->help = help; |
473 | form->flags = flags; | |
6fb96a3f | 474 | form->numCompsAlloced = 5; |
475 | form->numComps = 0; | |
476 | form->currComp = -1; | |
f5daa14e | 477 | form->vertOffset = 0; |
8c4e1047 | 478 | form->fixedHeight = 0; |
f1f3611f | 479 | form->numRows = 0; |
d02ffb49 | 480 | form->numFds = 0; |
481 | form->maxFd = 0; | |
482 | form->fds = NULL; | |
f5daa14e | 483 | form->elements = malloc(sizeof(*(form->elements)) * form->numCompsAlloced); |
d92e05d0 | 484 | if (form->elements == NULL) goto error; |
6fb96a3f | 485 | |
8f4e87fc | 486 | form->background = COLORSET_WINDOW; |
da151ca8 | 487 | form->hotKeys = malloc(sizeof(int)); |
d92e05d0 RG |
488 | if (form->hotKeys == NULL) goto error; |
489 | ||
da151ca8 | 490 | form->numHotKeys = 0; |
73390860 | 491 | form->timer = 0; |
492 | form->lastTimeout.tv_sec = form->lastTimeout.tv_usec = 0; | |
4a93351d | 493 | if (!(form->flags & NEWT_FLAG_NOF12)) { |
6f481af2 | 494 | newtFormAddHotKey(co, NEWT_KEY_F12); |
da151ca8 | 495 | } |
496 | ||
02b180e8 | 497 | if (vertBar) |
6f481af2 | 498 | form->vertBar = vertBar; |
f1f3611f | 499 | else |
6f481af2 | 500 | form->vertBar = NULL; |
f1f3611f | 501 | |
72b71fa6 | 502 | form->helpTag = help; |
503 | form->helpCb = helpCallback; | |
504 | ||
c4827b34 | 505 | return co; |
d92e05d0 RG |
506 | |
507 | error: | |
508 | free(form->hotKeys); | |
509 | free(form->elements); | |
510 | free(form); | |
511 | free(co); | |
512 | ||
513 | return NULL; | |
6fb96a3f | 514 | } |
515 | ||
2a2998a0 | 516 | newtComponent newtFormGetCurrent(newtComponent co) { |
517 | struct form * form = co->data; | |
518 | ||
d78245ab | 519 | if (form->currComp == -1) return 0; |
2a2998a0 | 520 | return form->elements[form->currComp].co; |
521 | } | |
522 | ||
5c72fb03 ML |
523 | static void formScroll(newtComponent co, int delta) { |
524 | struct form * form = co->data; | |
525 | struct element * el; | |
526 | int i, newVertOffset = form->vertOffset + delta; | |
527 | ||
528 | if (newVertOffset < 0) | |
529 | newVertOffset = 0; | |
530 | if (newVertOffset > form->numRows - co->height) | |
531 | newVertOffset = form->numRows - co->height; | |
532 | ||
533 | delta = newVertOffset - form->vertOffset; | |
534 | form->vertOffset = newVertOffset; | |
535 | ||
536 | for (i = 0, el = form->elements; i < form->numComps; i++, el++) { | |
537 | if (el->co == form->vertBar) | |
538 | continue; | |
539 | el->co->ops->place(el->co, el->co->left, el->co->top - delta); | |
540 | } | |
541 | } | |
542 | ||
7f72e4ef DW |
543 | int newtFormGetScrollPosition(newtComponent co) { |
544 | struct form * form = co->data; | |
545 | ||
546 | return form->vertOffset; | |
547 | } | |
548 | ||
549 | void newtFormSetScrollPosition(newtComponent co, int position) { | |
550 | struct form * form = co->data; | |
551 | ||
552 | if (form->numRows == 0) | |
553 | newtFormSetSize(co); | |
554 | formScroll(co, position - form->vertOffset); | |
555 | } | |
556 | ||
7ea3dccd | 557 | void newtFormSetCurrent(newtComponent co, newtComponent subco) { |
558 | struct form * form = co->data; | |
559 | int i, new; | |
560 | ||
561 | for (i = 0; i < form->numComps; i++) { | |
6f481af2 | 562 | if (form->elements[i].co == subco) break; |
7ea3dccd | 563 | } |
564 | ||
565 | if (form->elements[i].co != subco) return; | |
566 | new = i; | |
567 | ||
3da9c9a2 | 568 | if (co->isMapped && !componentFits(co, new)) { |
ad2dca95 | 569 | gotoComponent(co, -1); |
5c72fb03 | 570 | formScroll(co, form->elements[new].co->top - co->top - 1); |
7ea3dccd | 571 | } |
572 | ||
ad2dca95 | 573 | gotoComponent(co, new); |
7ea3dccd | 574 | } |
575 | ||
e67a6cab | 576 | void newtFormSetTimer(newtComponent co, int millisecs) { |
577 | struct form * form = co->data; | |
578 | ||
579 | form->timer = millisecs; | |
73390860 | 580 | form->lastTimeout.tv_usec = 0; |
581 | form->lastTimeout.tv_sec = 0; | |
e67a6cab | 582 | } |
583 | ||
8c4e1047 | 584 | void newtFormSetHeight(newtComponent co, int height) { |
f5daa14e | 585 | struct form * form = co->data; |
586 | ||
8c4e1047 | 587 | form->fixedHeight = 1; |
f5daa14e | 588 | co->height = height; |
589 | } | |
590 | ||
ea947804 | 591 | void newtFormSetWidth(newtComponent co, int width) { |
592 | co->width = width; | |
593 | } | |
594 | ||
c4827b34 | 595 | void newtFormAddComponent(newtComponent co, newtComponent newco) { |
596 | struct form * form = co->data; | |
6fb96a3f | 597 | |
8f52cd47 | 598 | co->takesFocus = 1; |
599 | ||
6fb96a3f | 600 | if (form->numCompsAlloced == form->numComps) { |
6f481af2 | 601 | form->numCompsAlloced += 5; |
602 | form->elements = realloc(form->elements, | |
603 | sizeof(*(form->elements)) * form->numCompsAlloced); | |
6fb96a3f | 604 | } |
605 | ||
f5daa14e | 606 | form->elements[form->numComps].co = newco; |
f1f3611f | 607 | |
608 | if (newco->takesFocus && form->currComp == -1) | |
6f481af2 | 609 | form->currComp = form->numComps; |
f1f3611f | 610 | |
f5daa14e | 611 | form->numComps++; |
6fb96a3f | 612 | } |
613 | ||
c4827b34 | 614 | void newtFormAddComponents(newtComponent co, ...) { |
6fb96a3f | 615 | va_list ap; |
c4827b34 | 616 | newtComponent subco; |
6fb96a3f | 617 | |
c4827b34 | 618 | va_start(ap, co); |
6fb96a3f | 619 | |
c4827b34 | 620 | while ((subco = va_arg(ap, newtComponent))) |
6f481af2 | 621 | newtFormAddComponent(co, subco); |
45f6c4fd | 622 | |
6fb96a3f | 623 | va_end(ap); |
624 | } | |
625 | ||
8f52cd47 | 626 | static void formPlace(newtComponent co, int left, int top) { |
627 | struct form * form = co->data; | |
628 | int vertDelta, horizDelta; | |
629 | struct element * el; | |
630 | int i; | |
631 | ||
8f52cd47 | 632 | vertDelta = top - co->top; |
633 | horizDelta = left - co->left; | |
634 | co->top = top; | |
635 | co->left = left; | |
636 | ||
637 | for (i = 0, el = form->elements; i < form->numComps; i++, el++) { | |
5c72fb03 ML |
638 | el->co->ops->place(el->co, el->co->left + horizDelta, |
639 | el->co->top + vertDelta); | |
8f52cd47 | 640 | } |
641 | } | |
642 | ||
8b68158d | 643 | void newtDrawForm(newtComponent co) { |
c4827b34 | 644 | struct form * form = co->data; |
f5daa14e | 645 | struct element * el; |
6fb96a3f | 646 | int i; |
6fb96a3f | 647 | |
3da9c9a2 | 648 | newtFormSetSize(co); |
649 | ||
8f4e87fc | 650 | SLsmg_set_color(form->background); |
a1331450 | 651 | newtClearBox(co->left, co->top, co->width, co->height); |
7ff5fd71 | 652 | |
f5daa14e | 653 | for (i = 0, el = form->elements; i < form->numComps; i++, el++) { |
5c72fb03 ML |
654 | /* only draw it if it'll fit on the screen vertically |
655 | (the scrollbar *always* fits somewhere) */ | |
656 | if (el->co == form->vertBar || componentFits(co, i)) { | |
6f481af2 | 657 | el->co->ops->mapped(el->co, 1); |
658 | el->co->ops->draw(el->co); | |
659 | } else { | |
5c72fb03 | 660 | el->co->ops->mapped(el->co, 0); |
6f481af2 | 661 | } |
6fb96a3f | 662 | } |
f1f3611f | 663 | |
664 | if (form->vertBar) | |
6f481af2 | 665 | newtScrollbarSet(form->vertBar, form->vertOffset, |
666 | form->numRows - co->height); | |
c4827b34 | 667 | } |
6fb96a3f | 668 | |
c4827b34 | 669 | static struct eventResult formEvent(newtComponent co, struct event ev) { |
670 | struct form * form = co->data; | |
f5daa14e | 671 | newtComponent subco = form->elements[form->currComp].co; |
d1a682d1 | 672 | int new, wrap = 0; |
c4827b34 | 673 | struct eventResult er; |
d1a682d1 | 674 | int dir = 0, page = 0; |
45f6c4fd | 675 | int i, num, found; |
676 | struct element * el; | |
6fb96a3f | 677 | |
c4827b34 | 678 | er.result = ER_IGNORED; |
8f52cd47 | 679 | if (!form->numComps) return er; |
680 | ||
d78245ab | 681 | if (form->currComp == -1) return er; |
6fb96a3f | 682 | |
434c766b | 683 | switch (ev.when) { |
684 | case EV_EARLY: | |
6f481af2 | 685 | if (ev.event == EV_KEYPRESS) { |
686 | if (ev.u.key == NEWT_KEY_TAB) { | |
687 | er.result = ER_SWALLOWED; | |
688 | dir = 1; | |
689 | wrap = 1; | |
690 | } else if (ev.u.key == NEWT_KEY_UNTAB) { | |
691 | er.result = ER_SWALLOWED; | |
692 | dir = -1; | |
693 | wrap = 1; | |
694 | } | |
695 | } | |
696 | ||
697 | if (form->numComps) { | |
698 | i = form->currComp; | |
699 | num = 0; | |
700 | while (er.result == ER_IGNORED && num != form->numComps ) { | |
701 | er = form->elements[i].co->ops->event(form->elements[i].co, ev); | |
702 | ||
703 | num++; | |
704 | i++; | |
705 | if (i == form->numComps) i = 0; | |
706 | } | |
707 | } | |
708 | ||
709 | break; | |
45f6c4fd | 710 | |
434c766b | 711 | case EV_NORMAL: |
6f481af2 | 712 | if (ev.event == EV_MOUSE) { |
713 | found = 0; | |
714 | for (i = 0, el = form->elements; i < form->numComps; i++, el++) { | |
715 | if ((el->co->top <= ev.u.mouse.y) && | |
716 | (el->co->top + el->co->height > ev.u.mouse.y) && | |
717 | (el->co->left <= ev.u.mouse.x) && | |
718 | (el->co->left + el->co->width > ev.u.mouse.x)) { | |
719 | found = 1; | |
720 | if (el->co->takesFocus) { | |
ad2dca95 | 721 | gotoComponent(co, i); |
6f481af2 | 722 | subco = form->elements[form->currComp].co; |
723 | } | |
724 | } | |
725 | /* If we did not find a co to send this event to, we | |
726 | should just swallow the event here. */ | |
727 | } | |
728 | if (!found) { | |
729 | er.result = ER_SWALLOWED; | |
730 | ||
731 | return er; | |
732 | } | |
733 | } | |
734 | er = subco->ops->event(subco, ev); | |
735 | switch (er.result) { | |
736 | case ER_NEXTCOMP: | |
737 | er.result = ER_SWALLOWED; | |
738 | dir = 1; | |
739 | break; | |
740 | ||
741 | case ER_EXITFORM: | |
742 | form->exitComp = subco; | |
743 | break; | |
744 | ||
745 | default: | |
746 | break; | |
747 | } | |
748 | break; | |
434c766b | 749 | |
750 | case EV_LATE: | |
6f481af2 | 751 | er = subco->ops->event(subco, ev); |
752 | ||
753 | if (er.result == ER_IGNORED) { | |
754 | switch (ev.u.key) { | |
755 | case NEWT_KEY_UP: | |
756 | case NEWT_KEY_LEFT: | |
757 | case NEWT_KEY_BKSPC: | |
758 | er.result = ER_SWALLOWED; | |
759 | dir = -1; | |
760 | break; | |
761 | ||
762 | case NEWT_KEY_DOWN: | |
763 | case NEWT_KEY_RIGHT: | |
764 | er.result = ER_SWALLOWED; | |
765 | dir = 1; | |
766 | break; | |
767 | ||
768 | case NEWT_KEY_PGUP: | |
769 | er.result = ER_SWALLOWED; | |
770 | dir = -1; | |
771 | page = 1; | |
772 | break; | |
773 | ||
774 | case NEWT_KEY_PGDN: | |
775 | er.result = ER_SWALLOWED; | |
776 | dir = 1; | |
777 | page = 1; | |
778 | break; | |
779 | } | |
780 | } | |
c4827b34 | 781 | } |
6fb96a3f | 782 | |
f5daa14e | 783 | if (dir) { |
6f481af2 | 784 | new = form->currComp; |
785 | ||
786 | if (page) { | |
787 | new += dir * co->height; | |
788 | if (new < 0) | |
789 | new = 0; | |
790 | else if (new >= form->numComps) | |
791 | new = (form->numComps - 1); | |
792 | ||
cf69773e ML |
793 | while (!form->elements[new].co->takesFocus && |
794 | new - dir >= 0 && new - dir < form->numComps) | |
795 | new -= dir; | |
6f481af2 | 796 | } else { |
797 | do { | |
798 | new += dir; | |
799 | ||
800 | if (wrap) { | |
801 | if (new < 0) | |
802 | new = form->numComps - 1; | |
803 | else if (new >= form->numComps) | |
804 | new = 0; | |
cf69773e ML |
805 | if (new == form->currComp) |
806 | /* back where we started */ | |
807 | return er; | |
6f481af2 | 808 | } else if (new < 0 || new >= form->numComps) |
809 | return er; | |
810 | } while (!form->elements[new].co->takesFocus); | |
811 | } | |
812 | ||
813 | /* make sure this component is visible */ | |
814 | if (!componentFits(co, new)) { | |
5c72fb03 ML |
815 | int vertDelta; |
816 | ||
ad2dca95 | 817 | gotoComponent(co, -1); |
6f481af2 | 818 | |
819 | if (dir < 0) { | |
820 | /* make the new component the first one */ | |
5c72fb03 | 821 | vertDelta = form->elements[new].co->top - co->top; |
6f481af2 | 822 | } else { |
823 | /* make the new component the last one */ | |
5c72fb03 | 824 | vertDelta = (form->elements[new].co->top + |
6f481af2 | 825 | form->elements[new].co->height) - |
826 | (co->top + co->height); | |
827 | } | |
828 | ||
5c72fb03 | 829 | formScroll(co, vertDelta); |
6f481af2 | 830 | newtDrawForm(co); |
831 | } | |
832 | ||
ad2dca95 | 833 | gotoComponent(co, new); |
6f481af2 | 834 | er.result = ER_SWALLOWED; |
c4827b34 | 835 | } |
6fb96a3f | 836 | |
c4827b34 | 837 | return er; |
6fb96a3f | 838 | } |
839 | ||
c101e99e RJ |
840 | /* Destroy a component. Components which have been added to a form |
841 | * are destroyed when the form is destroyed; this is just for the | |
842 | * (rare) case of components which for whatever reason weren't added | |
843 | * to a form. | |
844 | */ | |
845 | void newtComponentDestroy(newtComponent co) { | |
846 | /* If the user registered a destroy callback for this component, | |
847 | * now is a good time to call it. | |
848 | */ | |
849 | if (co->destroyCallback) | |
850 | co->destroyCallback(co, co->destroyCallbackData); | |
851 | ||
852 | if (co->ops->destroy) { | |
853 | co->ops->destroy(co); | |
854 | } else { | |
855 | if (co->data) free(co->data); | |
856 | free(co); | |
857 | } | |
858 | } | |
859 | ||
6fb96a3f | 860 | /* this also destroys all of the components on the form */ |
c4827b34 | 861 | void newtFormDestroy(newtComponent co) { |
c4827b34 | 862 | newtComponent subco; |
863 | struct form * form = co->data; | |
f1f3611f | 864 | int i; |
6fb96a3f | 865 | |
866 | /* first, destroy all of the components */ | |
867 | for (i = 0; i < form->numComps; i++) { | |
6f481af2 | 868 | subco = form->elements[i].co; |
c101e99e | 869 | newtComponentDestroy(subco); |
6fb96a3f | 870 | } |
871 | ||
4e61f5db | 872 | if (form->hotKeys) free(form->hotKeys); |
873 | ||
f5daa14e | 874 | free(form->elements); |
6fb96a3f | 875 | free(form); |
c4827b34 | 876 | free(co); |
877 | } | |
878 | ||
879 | newtComponent newtRunForm(newtComponent co) { | |
da151ca8 | 880 | struct newtExitStruct es; |
881 | ||
882 | newtFormRun(co, &es); | |
883 | if (es.reason == NEWT_EXIT_HOTKEY) { | |
6f481af2 | 884 | if (es.u.key == NEWT_KEY_F12) { |
885 | es.reason = NEWT_EXIT_COMPONENT; | |
886 | es.u.co = co; | |
887 | } else { | |
888 | return NULL; | |
889 | } | |
b8b8a86f ML |
890 | } else if (es.reason == NEWT_EXIT_ERROR) |
891 | return NULL; | |
da151ca8 | 892 | |
893 | return es.u.co; | |
894 | } | |
895 | ||
896 | void newtFormAddHotKey(newtComponent co, int key) { | |
897 | struct form * form = co->data; | |
898 | ||
899 | form->numHotKeys++; | |
900 | form->hotKeys = realloc(form->hotKeys, sizeof(int) * form->numHotKeys); | |
901 | form->hotKeys[form->numHotKeys - 1] = key; | |
902 | } | |
903 | ||
3da9c9a2 | 904 | void newtFormSetSize(newtComponent co) { |
f7540d34 | 905 | struct form * form = co->data; |
21150df5 | 906 | int delta, i, first; |
f7540d34 | 907 | struct element * el; |
908 | ||
21150df5 | 909 | form->numRows = 0; |
8f52cd47 | 910 | |
f7540d34 | 911 | co->width = 0; |
3da9c9a2 | 912 | if (!form->fixedHeight) co->height = 0; |
913 | ||
35d6a6ab ML |
914 | co->top = -1; |
915 | co->left = -1; | |
21150df5 | 916 | first = 1; |
35d6a6ab | 917 | |
f7540d34 | 918 | for (i = 0, el = form->elements; i < form->numComps; i++, el++) { |
6f481af2 | 919 | if (el->co->ops == &formOps) |
920 | newtFormSetSize(el->co); | |
35d6a6ab ML |
921 | else if (el->co == form->vertBar) |
922 | continue; | |
923 | ||
21150df5 | 924 | if (first) { |
35d6a6ab ML |
925 | co->top = el->co->top; |
926 | co->left = el->co->left; | |
21150df5 | 927 | first = 0; |
35d6a6ab | 928 | } |
6f481af2 | 929 | |
6f481af2 | 930 | if (co->left > el->co->left) { |
931 | delta = co->left - el->co->left; | |
932 | co->left -= delta; | |
933 | co->width += delta; | |
934 | } | |
935 | ||
936 | if (co->top > el->co->top) { | |
937 | delta = co->top - el->co->top; | |
938 | co->top -= delta; | |
35d6a6ab | 939 | form->numRows += delta; |
6f481af2 | 940 | if (!form->fixedHeight) |
941 | co->height += delta; | |
942 | } | |
943 | ||
944 | if ((co->left + co->width) < (el->co->left + el->co->width)) | |
945 | co->width = (el->co->left + el->co->width) - co->left; | |
946 | ||
947 | if (!form->fixedHeight) { | |
948 | if ((co->top + co->height) < (el->co->top + el->co->height)) | |
949 | co->height = (el->co->top + el->co->height) - co->top; | |
950 | } | |
951 | ||
952 | if ((el->co->top + el->co->height - co->top) > form->numRows) { | |
953 | form->numRows = el->co->top + el->co->height - co->top; | |
954 | } | |
f7540d34 | 955 | } |
5c72fb03 ML |
956 | |
957 | co->top += form->vertOffset; | |
f7540d34 | 958 | } |
959 | ||
da151ca8 | 960 | void newtFormRun(newtComponent co, struct newtExitStruct * es) { |
c4827b34 | 961 | struct form * form = co->data; |
962 | struct event ev; | |
963 | struct eventResult er; | |
45f6c4fd | 964 | int key, i, max; |
da151ca8 | 965 | int done = 0; |
d7e202d6 | 966 | fd_set readSet, writeSet, exceptSet; |
e67a6cab | 967 | struct timeval nextTimeout, now, timeout; |
33b9b6eb | 968 | #ifdef USE_GPM |
45f6c4fd | 969 | int x, y; |
970 | Gpm_Connect conn; | |
971 | Gpm_Event event; | |
972 | ||
973 | /* Set up GPM interface */ | |
974 | conn.eventMask = ~GPM_MOVE; | |
975 | conn.defaultMask = GPM_MOVE; | |
976 | conn.minMod = 0; | |
977 | conn.maxMod = 0; | |
978 | ||
979 | Gpm_Open(&conn, 0); | |
980 | #endif | |
c4827b34 | 981 | |
f7540d34 | 982 | /* draw all of the components */ |
8b68158d | 983 | newtDrawForm(co); |
c4827b34 | 984 | |
f1f3611f | 985 | if (form->currComp == -1) { |
d3cfe899 | 986 | if (form->numComps) |
ad2dca95 | 987 | gotoComponent(co, 0); |
f1f3611f | 988 | } else |
ad2dca95 | 989 | gotoComponent(co, form->currComp); |
45f6c4fd | 990 | |
da151ca8 | 991 | while (!done) { |
6f481af2 | 992 | newtRefresh(); |
c4827b34 | 993 | |
6f481af2 | 994 | FD_ZERO(&readSet); |
995 | FD_ZERO(&writeSet); | |
996 | FD_ZERO(&exceptSet); | |
997 | FD_SET(0, &readSet); | |
33b9b6eb | 998 | #ifdef USE_GPM |
6f481af2 | 999 | if (gpm_fd > 0) { |
1000 | FD_SET(gpm_fd, &readSet); | |
1001 | } | |
1002 | max = form->maxFd > gpm_fd ? form->maxFd : gpm_fd; | |
45f6c4fd | 1003 | #else |
6f481af2 | 1004 | max = form->maxFd; |
45f6c4fd | 1005 | #endif |
1006 | ||
6f481af2 | 1007 | for (i = 0; i < form->numFds; i++) { |
1008 | if (form->fds[i].flags & NEWT_FD_READ) | |
1009 | FD_SET(form->fds[i].fd, &readSet); | |
1010 | if (form->fds[i].flags & NEWT_FD_WRITE) | |
1011 | FD_SET(form->fds[i].fd, &writeSet); | |
1012 | if (form->fds[i].flags & NEWT_FD_EXCEPT) | |
1013 | FD_SET(form->fds[i].fd, &exceptSet); | |
1014 | } | |
1015 | ||
1016 | if (form->timer) { | |
1017 | /* Calculate when we next need to return with a timeout. Do | |
1018 | this inside the loop in case a callback resets the timer. */ | |
57660927 | 1019 | gettimeofday(&now, 0); |
1020 | ||
1021 | if ((!form->lastTimeout.tv_sec && !form->lastTimeout.tv_usec) || | |
1022 | now.tv_sec < form->lastTimeout.tv_sec || | |
1023 | (now.tv_sec == form->lastTimeout.tv_sec && | |
1024 | now.tv_usec < form->lastTimeout.tv_usec)) | |
1025 | form->lastTimeout = now; | |
6f481af2 | 1026 | |
1027 | nextTimeout.tv_sec = form->lastTimeout.tv_sec + | |
1028 | (form->timer / 1000); | |
1029 | nextTimeout.tv_usec = form->lastTimeout.tv_usec + | |
1030 | (form->timer % 1000) * 1000; | |
1031 | ||
6f481af2 | 1032 | if (now.tv_sec > nextTimeout.tv_sec) { |
1033 | timeout.tv_sec = timeout.tv_usec = 0; | |
1034 | } else if (now.tv_sec == nextTimeout.tv_sec) { | |
1035 | timeout.tv_sec = 0; | |
1036 | if (now.tv_usec > nextTimeout.tv_usec) | |
1037 | timeout.tv_usec = 0; | |
1038 | else | |
1039 | timeout.tv_usec = nextTimeout.tv_usec - now.tv_usec; | |
1040 | } else if (now.tv_sec < nextTimeout.tv_sec) { | |
1041 | timeout.tv_sec = nextTimeout.tv_sec - now.tv_sec; | |
1042 | if (now.tv_usec > nextTimeout.tv_usec) | |
1043 | timeout.tv_sec--, | |
1044 | timeout.tv_usec = nextTimeout.tv_usec + 1000000 - | |
1045 | now.tv_usec; | |
1046 | else | |
1047 | timeout.tv_usec = nextTimeout.tv_usec - now.tv_usec; | |
1048 | } | |
1049 | } else { | |
1050 | timeout.tv_sec = timeout.tv_usec = 0; | |
1051 | } | |
1052 | ||
0593cb33 ML |
1053 | if (needResize) { |
1054 | needResize = 0; | |
1055 | newtResizeScreen(1); | |
d861e991 ML |
1056 | |
1057 | /* The application may want to handle the resize */ | |
1058 | for (i = 0; i < form->numHotKeys; i++) { | |
1059 | if (form->hotKeys[i] == NEWT_KEY_RESIZE) { | |
1060 | es->reason = NEWT_EXIT_HOTKEY; | |
1061 | es->u.key = NEWT_KEY_RESIZE; | |
1062 | done = 1; | |
1063 | break; | |
1064 | } | |
1065 | } | |
1066 | if (done) | |
1067 | break; | |
0593cb33 ML |
1068 | } |
1069 | ||
6f481af2 | 1070 | i = select(max + 1, &readSet, &writeSet, &exceptSet, |
1071 | form->timer ? &timeout : NULL); | |
1072 | if (i < 0) continue; /* ?? What should we do here? */ | |
1073 | ||
1074 | if (i == 0) { | |
1075 | done = 1; | |
1076 | es->reason = NEWT_EXIT_TIMER; | |
1077 | gettimeofday(&form->lastTimeout, NULL); | |
1078 | } else | |
33b9b6eb | 1079 | #ifdef USE_GPM |
6f481af2 | 1080 | if (gpm_fd > 0 && FD_ISSET(gpm_fd, &readSet)) { |
1081 | Gpm_GetEvent(&event); | |
d02ffb49 | 1082 | |
6f481af2 | 1083 | if (event.type & GPM_DOWN) { |
1084 | /* Transform coordinates to current window */ | |
1085 | newtGetWindowPos(&x, &y); | |
c4827b34 | 1086 | |
6f481af2 | 1087 | ev.event = EV_MOUSE; |
1088 | ev.u.mouse.type = MOUSE_BUTTON_DOWN; | |
1089 | ev.u.mouse.x = event.x - x - 1; | |
1090 | ev.u.mouse.y = event.y - y - 1; | |
d02ffb49 | 1091 | |
6f481af2 | 1092 | /* Send the form the event */ |
1093 | er = sendEvent(co, ev); | |
45f6c4fd | 1094 | |
6f481af2 | 1095 | if (er.result == ER_EXITFORM) { |
1096 | done = 1; | |
1097 | es->reason = NEWT_EXIT_COMPONENT; | |
1098 | es->u.co = form->exitComp; | |
1099 | } | |
45f6c4fd | 1100 | |
6f481af2 | 1101 | } |
1102 | } else | |
45f6c4fd | 1103 | #endif |
6f481af2 | 1104 | { |
1105 | if (FD_ISSET(0, &readSet)) { | |
1106 | ||
1107 | key = newtGetKey(); | |
1108 | ||
6f481af2 | 1109 | for (i = 0; i < form->numHotKeys; i++) { |
1110 | if (form->hotKeys[i] == key) { | |
1111 | es->reason = NEWT_EXIT_HOTKEY; | |
1112 | es->u.key = key; | |
1113 | done = 1; | |
1114 | break; | |
1115 | } | |
1116 | } | |
1117 | ||
9fc6a6b0 | 1118 | if (key == NEWT_KEY_F1 && form->helpTag && form->helpCb) { |
1119 | if (form->currComp != -1) { | |
1120 | ev.event = EV_UNFOCUS; | |
1121 | sendEvent(form->elements[form->currComp].co, ev); | |
1122 | } | |
6f481af2 | 1123 | form->helpCb(co, form->helpTag); |
9fc6a6b0 | 1124 | if (form->currComp != -1) { |
1125 | ev.event = EV_FOCUS; | |
1126 | sendEvent(form->elements[form->currComp].co, ev); | |
1127 | } | |
1128 | } | |
6f481af2 | 1129 | |
b8b8a86f ML |
1130 | if (key == NEWT_KEY_ERROR) { |
1131 | es->u.watch = -1; | |
1132 | es->reason = NEWT_EXIT_ERROR; | |
1133 | done = 1; | |
1134 | } | |
1135 | ||
6f481af2 | 1136 | if (!done) { |
1137 | ev.event = EV_KEYPRESS; | |
1138 | ev.u.key = key; | |
1139 | ||
1140 | er = sendEvent(co, ev); | |
1141 | ||
1142 | if (er.result == ER_EXITFORM) { | |
1143 | done = 1; | |
1144 | es->reason = NEWT_EXIT_COMPONENT; | |
1145 | es->u.co = form->exitComp; | |
1146 | } | |
1147 | } | |
1148 | } else { | |
1149 | for (i = 0; i < form->numFds; i++) { | |
1150 | if (((form->fds[i].flags & NEWT_FD_READ) | |
1151 | && FD_ISSET(form->fds[i].fd, &readSet)) | |
1152 | || ((form->fds[i].flags & NEWT_FD_WRITE) | |
1153 | && FD_ISSET(form->fds[i].fd, &writeSet)) | |
1154 | || ((form->fds[i].flags & NEWT_FD_EXCEPT) | |
1155 | && FD_ISSET(form->fds[i].fd, &exceptSet))) break; | |
1156 | } | |
1157 | if(i < form->numFds) | |
1158 | es->u.watch = form->fds[i].fd; | |
1159 | else | |
1160 | es->u.watch = -1; | |
1161 | ||
1162 | es->reason = NEWT_EXIT_FDREADY; | |
1163 | done = 1; | |
1164 | } | |
1165 | } | |
45f6c4fd | 1166 | } |
c4827b34 | 1167 | newtRefresh(); |
33b9b6eb | 1168 | #ifdef USE_GPM |
45f6c4fd | 1169 | Gpm_Close(); |
1170 | #endif | |
6fb96a3f | 1171 | } |
1172 | ||
434c766b | 1173 | static struct eventResult sendEvent(newtComponent co, struct event ev) { |
1174 | struct eventResult er; | |
1175 | ||
1176 | ev.when = EV_EARLY; | |
1177 | er = co->ops->event(co, ev); | |
1178 | ||
1179 | if (er.result == ER_IGNORED) { | |
6f481af2 | 1180 | ev.when = EV_NORMAL; |
1181 | er = co->ops->event(co, ev); | |
434c766b | 1182 | } |
1183 | ||
1184 | if (er.result == ER_IGNORED) { | |
6f481af2 | 1185 | ev.when = EV_LATE; |
1186 | er = co->ops->event(co, ev); | |
434c766b | 1187 | } |
1188 | ||
1189 | return er; | |
1190 | } | |
1191 | ||
ad2dca95 DW |
1192 | static void gotoComponent(newtComponent co, int newComp) { |
1193 | struct form * form = co->data; | |
6fb96a3f | 1194 | struct event ev; |
1195 | ||
1196 | if (form->currComp != -1) { | |
6f481af2 | 1197 | ev.event = EV_UNFOCUS; |
1198 | sendEvent(form->elements[form->currComp].co, ev); | |
6fb96a3f | 1199 | } |
1200 | ||
1201 | form->currComp = newComp; | |
45f6c4fd | 1202 | |
f5daa14e | 1203 | if (form->currComp != -1) { |
6f481af2 | 1204 | ev.event = EV_FOCUS; |
1205 | ev.when = EV_NORMAL; | |
1206 | sendEvent(form->elements[form->currComp].co, ev); | |
f5daa14e | 1207 | } |
ad2dca95 DW |
1208 | |
1209 | if (co->callback) | |
1210 | co->callback(co, co->callbackData); | |
6fb96a3f | 1211 | } |
da151ca8 | 1212 | |
1213 | void newtComponentAddCallback(newtComponent co, newtCallback f, void * data) { | |
1214 | co->callback = f; | |
1215 | co->callbackData = data; | |
1216 | } | |
1217 | ||
c101e99e RJ |
1218 | /* Add a callback which is called when the component is destroyed. */ |
1219 | void newtComponentAddDestroyCallback(newtComponent co, | |
1220 | newtCallback f, void * data) { | |
1221 | co->destroyCallback = f; | |
1222 | co->destroyCallbackData = data; | |
1223 | } | |
1224 | ||
41d86a3c | 1225 | void newtComponentTakesFocus(newtComponent co, int val) { |
1226 | co->takesFocus = val; | |
1227 | } | |
1228 | ||
8f4e87fc | 1229 | void newtFormSetBackground(newtComponent co, int color) { |
1230 | struct form * form = co->data; | |
1231 | ||
1232 | form->background = color; | |
1233 | } | |
d02ffb49 | 1234 | |
1235 | void newtFormWatchFd(newtComponent co, int fd, int fdFlags) { | |
1236 | struct form * form = co->data; | |
005d8237 | 1237 | int i; |
1238 | ||
1239 | for (i = 0; i < form->numFds; i++) | |
1240 | if (form->fds[i].fd == fd) | |
6f481af2 | 1241 | break; |
005d8237 | 1242 | |
1243 | if(i >= form->numFds) | |
1244 | form->fds = realloc(form->fds, (++form->numFds) * sizeof(*form->fds)); | |
d02ffb49 | 1245 | |
005d8237 | 1246 | form->fds[i].fd = fd; |
1247 | form->fds[i].flags = fdFlags; | |
d02ffb49 | 1248 | if (form->maxFd < fd) form->maxFd = fd; |
1249 | } | |
72b71fa6 | 1250 | |
1251 | void newtSetHelpCallback(newtCallback cb) { | |
1252 | helpCallback = cb; | |
1253 | } |