~ubuntu-branches/ubuntu/vivid/newt/vivid

« back to all changes in this revision

Viewing changes to form.c

  • Committer: Package Import Robot
  • Author(s): Matthias Klose
  • Date: 2012-11-08 14:50:00 UTC
  • mfrom: (2.1.20 sid)
  • Revision ID: package-import@ubuntu.com-20121108145000-0yfrol7obct0jufq
Tags: 0.52.14-11ubuntu1
* Merge with Debian; remaining changes:
  - Port python module to python3.
  - Fix installation for multiple python3 versions.
  - Move libnewt to /lib and whiptail to /bin so they can be used by
    friendly-recovery on systems that have a separate /usr.
  - debian/libnewt0.52.install, debian/libnewt0.52.postinst,
    debian/palette => debian/palette.original:
    - move palette from /usr to /etc such that they can be edited by an
      admin.
* Configure --with-colorsfile=/etc/newt/palette.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#include "config.h"
 
2
 
 
3
#include <sys/types.h>
 
4
 
 
5
#include <slang.h>
 
6
#include <stdarg.h>
 
7
#include <stdlib.h>
 
8
#ifdef HAVE_SYS_SELECT_H
 
9
#include <sys/select.h>
 
10
#endif
 
11
#include <sys/time.h>
 
12
 
 
13
#ifdef USE_GPM
 
14
#include <ctype.h>
 
15
#include <sys/time.h>      /* timeval */
 
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>
 
25
#endif
 
26
 
 
27
#include "newt.h"
 
28
#include "newt_pr.h"
 
29
 
 
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;
 
86
static struct sigaction gpm_saved_suspend_hook;
 
87
static struct sigaction gpm_saved_winch_hook;
 
88
 
 
89
#define GPM_XTERM_ON
 
90
#define GPM_XTERM_OFF
 
91
#define GPM_NODE_DEV "/dev/gpmctl"
 
92
#define GPM_NODE_CTL GPM_NODE_DEV
 
93
 
 
94
static inline int putdata(int where,  Gpm_Connect *what)
 
95
{
 
96
  if (write(where,what,sizeof(Gpm_Connect))!=sizeof(Gpm_Connect))
 
97
    {
 
98
      return -1;
 
99
    }
 
100
  return 0;
 
101
}
 
102
 
 
103
static void gpm_winch_hook (int signum)
 
104
{
 
105
  if (SIG_IGN != gpm_saved_winch_hook.sa_handler &&
 
106
      SIG_DFL != gpm_saved_winch_hook.sa_handler) {
 
107
    gpm_saved_winch_hook.sa_handler(signum);
 
108
  } /*if*/
 
109
}
 
110
 
 
111
static void gpm_suspend_hook (int signum)
 
112
{
 
113
  Gpm_Connect gpm_connect;
 
114
  sigset_t old_sigset;
 
115
  sigset_t new_sigset;
 
116
  struct sigaction sa;
 
117
  int success;
 
118
 
 
119
  sigemptyset (&new_sigset);
 
120
  sigaddset (&new_sigset, SIGTSTP);
 
121
  sigprocmask (SIG_BLOCK, &new_sigset, &old_sigset);
 
122
 
 
123
  /* Open a completely transparent gpm connection */
 
124
  gpm_connect.eventMask = 0;
 
125
  gpm_connect.defaultMask = ~0;
 
126
  gpm_connect.minMod = ~0;
 
127
  gpm_connect.maxMod = 0;
 
128
  /* cannot do this under xterm, tough */
 
129
  success = (Gpm_Open (&gpm_connect, 0) >= 0);
 
130
 
 
131
  /* take the default action, whatever it is (probably a stop :) */
 
132
  sigprocmask (SIG_SETMASK, &old_sigset, 0);
 
133
  sigaction (SIGTSTP, &gpm_saved_suspend_hook, 0);
 
134
  kill (getpid (), SIGTSTP);
 
135
 
 
136
  /* in bardo here */
 
137
 
 
138
  /* Reincarnation. Prepare for another death early. */
 
139
  sigemptyset(&sa.sa_mask);
 
140
  sa.sa_handler = gpm_suspend_hook;
 
141
  sa.sa_flags = SA_NOMASK;
 
142
  sigaction (SIGTSTP, &sa, 0);
 
143
 
 
144
  /* Pop the gpm stack by closing the useless connection */
 
145
  /* but do it only when we know we opened one.. */
 
146
  if (success) {
 
147
    Gpm_Close ();
 
148
  } /*if*/
 
149
}
 
150
 
 
151
static int Gpm_Open(Gpm_Connect *conn, int flag)
 
152
{
 
153
  char tty[32];
 
154
  char *term;
 
155
  int i;
 
156
  struct sockaddr_un addr;
 
157
  Gpm_Stst *new;
 
158
  char* sock_name = 0;
 
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;
 
231
      if (!(sock_name = tempnam (0, "gpm"))) {
 
232
        goto err;
 
233
      } /*if*/
 
234
      strncpy (addr.sun_path, sock_name, sizeof (addr.sun_path));
 
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);
 
305
  if (sock_name) {
 
306
    unlink(sock_name);
 
307
    free(sock_name);
 
308
    sock_name = 0;
 
309
  } /*if*/
 
310
  gpm_flag=0;
 
311
  gpm_fd=-1;
 
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;
 
337
#ifdef SIGTSTP
 
338
  sigaction(SIGTSTP, &gpm_saved_suspend_hook, 0);
 
339
#endif
 
340
#ifdef SIGWINCH
 
341
  sigaction(SIGWINCH, &gpm_saved_winch_hook, 0);
 
342
#endif
 
343
  return 0;
 
344
}
 
345
 
 
346
/*-------------------------------------------------------------------*/
 
347
static int Gpm_GetEvent(Gpm_Event *event)
 
348
{
 
349
  int count;
 
350
 
 
351
  if (!gpm_flag) return 0;
 
352
 
 
353
  if ((count=read(gpm_fd,event,sizeof(Gpm_Event)))!=sizeof(Gpm_Event))
 
354
    {
 
355
      if (count==0)
 
356
        {
 
357
          Gpm_Close();
 
358
          return 0;
 
359
        }
 
360
      return -1;
 
361
    }
 
362
  return 1;
 
363
}
 
364
#endif
 
365
 
 
366
/****************************************************************************
 
367
    These forms handle vertical scrolling of components with a height of 1
 
368
 
 
369
    Horizontal scrolling won't work, and scrolling large widgets will fail
 
370
    miserably. It shouldn't be too hard to fix either of those if anyone
 
371
    cares to. I only use scrolling for listboxes and text boxes though so
 
372
    I didn't bother.
 
373
*****************************************************************************/
 
374
 
 
375
struct element {
 
376
    newtComponent co;
 
377
};
 
378
 
 
379
struct fdInfo {
 
380
    int fd;
 
381
    int flags;
 
382
};
 
383
 
 
384
struct form {
 
385
    int numCompsAlloced;
 
386
    struct element * elements;
 
387
    int numComps;
 
388
    int currComp;
 
389
    int fixedHeight;
 
390
    int flags;
 
391
    int vertOffset;
 
392
    newtComponent vertBar, exitComp;
 
393
    const char * help;
 
394
    int numRows;
 
395
    int * hotKeys;
 
396
    int numHotKeys;
 
397
    int background;
 
398
    int numFds;
 
399
    struct fdInfo * fds;
 
400
    int maxFd;
 
401
    int timer;    /* in milliseconds */
 
402
    struct timeval lastTimeout;
 
403
    void * helpTag;
 
404
    newtCallback helpCb;
 
405
};
 
406
 
 
407
static void gotoComponent(struct form * form, int newComp);
 
408
static struct eventResult formEvent(newtComponent co, struct event ev);
 
409
static struct eventResult sendEvent(newtComponent comp, struct event ev);
 
410
static void formPlace(newtComponent co, int left, int top);
 
411
 
 
412
/* Global, ick */
 
413
static newtCallback helpCallback;
 
414
 
 
415
/* this isn't static as grid.c tests against it to find forms */
 
416
struct componentOps formOps = {
 
417
    newtDrawForm,
 
418
    formEvent,
 
419
    newtFormDestroy,
 
420
    formPlace,
 
421
    newtDefaultMappedHandler,
 
422
} ;
 
423
 
 
424
int needResize = 0;
 
425
 
 
426
static inline int componentFits(newtComponent co, int compNum) {
 
427
    struct form * form = co->data;
 
428
    struct element * el = form->elements + compNum;
 
429
 
 
430
    if (co->top > el->co->top)
 
431
        return 0;
 
432
    if (co->top + co->height < el->co->top + el->co->height)
 
433
        return 0;
 
434
 
 
435
    return 1;
 
436
}
 
437
 
 
438
newtComponent newtForm(newtComponent vertBar, void * help, int flags) {
 
439
    newtComponent co;
 
440
    struct form * form;
 
441
 
 
442
    co = malloc(sizeof(*co));
 
443
    form = malloc(sizeof(*form));
 
444
    co->data = form;
 
445
    co->width = 0;
 
446
    co->height = 0;
 
447
    co->top = -1;
 
448
    co->left = -1;
 
449
    co->isMapped = 0;
 
450
 
 
451
    co->takesFocus = 0;                 /* we may have 0 components */
 
452
    co->ops = &formOps;
 
453
    co->destroyCallback = NULL;
 
454
 
 
455
    form->help = help;
 
456
    form->flags = flags;
 
457
    form->numCompsAlloced = 5;
 
458
    form->numComps = 0;
 
459
    form->currComp = -1;
 
460
    form->vertOffset = 0;
 
461
    form->fixedHeight = 0;
 
462
    form->numRows = 0;
 
463
    form->numFds = 0;
 
464
    form->maxFd = 0;
 
465
    form->fds = NULL;
 
466
    form->elements = malloc(sizeof(*(form->elements)) * form->numCompsAlloced);
 
467
 
 
468
    form->background = COLORSET_WINDOW;
 
469
    form->hotKeys = malloc(sizeof(int));
 
470
    form->numHotKeys = 0;
 
471
    form->timer = 0;
 
472
    form->lastTimeout.tv_sec = form->lastTimeout.tv_usec = 0;
 
473
    if (!(form->flags & NEWT_FLAG_NOF12)) {
 
474
        newtFormAddHotKey(co, NEWT_KEY_F12);
 
475
    }
 
476
    newtFormAddHotKey (co, NEWT_KEY_ESCAPE);
 
477
 
 
478
    if (vertBar)
 
479
        form->vertBar = vertBar;
 
480
    else
 
481
        form->vertBar = NULL;
 
482
 
 
483
    form->helpTag = help;
 
484
    form->helpCb = helpCallback;
 
485
 
 
486
    return co;
 
487
}
 
488
 
 
489
newtComponent newtFormGetCurrent(newtComponent co) {
 
490
    struct form * form = co->data;
 
491
 
 
492
    if (form->currComp == -1) return 0;
 
493
    return form->elements[form->currComp].co;
 
494
}
 
495
 
 
496
static void formScroll(newtComponent co, int delta) {
 
497
    struct form * form = co->data;
 
498
    struct element * el;
 
499
    int i, newVertOffset = form->vertOffset + delta;
 
500
 
 
501
    if (newVertOffset < 0)
 
502
        newVertOffset = 0;
 
503
    if (newVertOffset > form->numRows - co->height)
 
504
        newVertOffset = form->numRows - co->height;
 
505
 
 
506
    delta = newVertOffset - form->vertOffset;
 
507
    form->vertOffset = newVertOffset;
 
508
 
 
509
    for (i = 0, el = form->elements; i < form->numComps; i++, el++) {
 
510
        if (el->co == form->vertBar)
 
511
            continue;
 
512
        el->co->ops->place(el->co, el->co->left, el->co->top - delta);
 
513
    }
 
514
}
 
515
 
 
516
void newtFormSetCurrent(newtComponent co, newtComponent subco) {
 
517
    struct form * form = co->data;
 
518
    int i, new;
 
519
 
 
520
    for (i = 0; i < form->numComps; i++) {
 
521
         if (form->elements[i].co == subco) break;
 
522
    }
 
523
 
 
524
    if (form->elements[i].co != subco) return;
 
525
    new = i;
 
526
 
 
527
    if (co->isMapped && !componentFits(co, new)) {
 
528
        gotoComponent(form, -1);
 
529
        formScroll(co, form->elements[new].co->top - co->top - 1);
 
530
    }
 
531
 
 
532
    gotoComponent(form, new);
 
533
}
 
534
 
 
535
void newtFormSetTimer(newtComponent co, int millisecs) {
 
536
    struct form * form = co->data;
 
537
 
 
538
    form->timer = millisecs;
 
539
    form->lastTimeout.tv_usec = 0;
 
540
    form->lastTimeout.tv_sec = 0;
 
541
}
 
542
 
 
543
void newtFormSetHeight(newtComponent co, int height) {
 
544
    struct form * form = co->data;
 
545
 
 
546
    form->fixedHeight = 1;
 
547
    co->height = height;
 
548
}
 
549
 
 
550
void newtFormSetWidth(newtComponent co, int width) {
 
551
    co->width = width;
 
552
}
 
553
 
 
554
void newtFormAddComponent(newtComponent co, newtComponent newco) {
 
555
    struct form * form = co->data;
 
556
 
 
557
    co->takesFocus = 1;
 
558
 
 
559
    if (form->numCompsAlloced == form->numComps) {
 
560
        form->numCompsAlloced += 5;
 
561
        form->elements = realloc(form->elements,
 
562
                            sizeof(*(form->elements)) * form->numCompsAlloced);
 
563
    }
 
564
 
 
565
    form->elements[form->numComps].co = newco;
 
566
 
 
567
    if (newco->takesFocus && form->currComp == -1)
 
568
        form->currComp = form->numComps;
 
569
 
 
570
    form->numComps++;
 
571
}
 
572
 
 
573
void newtFormAddComponents(newtComponent co, ...) {
 
574
    va_list ap;
 
575
    newtComponent subco;
 
576
 
 
577
    va_start(ap, co);
 
578
 
 
579
    while ((subco = va_arg(ap, newtComponent)))
 
580
        newtFormAddComponent(co, subco);
 
581
 
 
582
    va_end(ap);
 
583
}
 
584
 
 
585
static void formPlace(newtComponent co, int left, int top) {
 
586
    struct form * form = co->data;
 
587
    int vertDelta, horizDelta;
 
588
    struct element * el;
 
589
    int i;
 
590
 
 
591
    vertDelta = top - co->top;
 
592
    horizDelta = left - co->left;
 
593
    co->top = top;
 
594
    co->left = left;
 
595
 
 
596
    for (i = 0, el = form->elements; i < form->numComps; i++, el++) {
 
597
        el->co->ops->place(el->co, el->co->left + horizDelta,
 
598
                el->co->top + vertDelta);
 
599
    }
 
600
}
 
601
 
 
602
void newtDrawForm(newtComponent co) {
 
603
    struct form * form = co->data;
 
604
    struct element * el;
 
605
    int i;
 
606
 
 
607
    newtFormSetSize(co);
 
608
 
 
609
    SLsmg_set_color(form->background);
 
610
    newtClearBox(co->left, co->top, co->width, co->height);
 
611
 
 
612
    for (i = 0, el = form->elements; i < form->numComps; i++, el++) {
 
613
        /* only draw it if it'll fit on the screen vertically
 
614
           (the scrollbar *always* fits somewhere) */
 
615
        if (el->co == form->vertBar || componentFits(co, i)) {
 
616
            el->co->ops->mapped(el->co, 1);
 
617
            el->co->ops->draw(el->co);
 
618
        } else {
 
619
            el->co->ops->mapped(el->co, 0);
 
620
        }
 
621
    }
 
622
 
 
623
    if (form->vertBar)
 
624
        newtScrollbarSet(form->vertBar, form->vertOffset,
 
625
                         form->numRows - co->height);
 
626
}
 
627
 
 
628
static struct eventResult formEvent(newtComponent co, struct event ev) {
 
629
    struct form * form = co->data;
 
630
    newtComponent subco = form->elements[form->currComp].co;
 
631
    int new, wrap = 0;
 
632
    struct eventResult er;
 
633
    int dir = 0, page = 0;
 
634
    int i, num, found;
 
635
    struct element * el;
 
636
 
 
637
    er.result = ER_IGNORED;
 
638
    if (!form->numComps) return er;
 
639
 
 
640
    if (form->currComp == -1) return er;
 
641
 
 
642
    switch (ev.when) {
 
643
      case EV_EARLY:
 
644
          if (ev.event == EV_KEYPRESS) {
 
645
            if (ev.u.key == NEWT_KEY_TAB) {
 
646
                er.result = ER_SWALLOWED;
 
647
                dir = 1;
 
648
                wrap = 1;
 
649
            } else if (ev.u.key == NEWT_KEY_UNTAB) {
 
650
                er.result = ER_SWALLOWED;
 
651
                dir = -1;
 
652
                wrap = 1;
 
653
            }
 
654
        }
 
655
 
 
656
        if (form->numComps) {
 
657
            i = form->currComp;
 
658
            num = 0;
 
659
            while (er.result == ER_IGNORED && num != form->numComps ) {
 
660
                er = form->elements[i].co->ops->event(form->elements[i].co, ev);
 
661
 
 
662
                num++;
 
663
                i++;
 
664
                if (i == form->numComps) i = 0;
 
665
            }
 
666
        }
 
667
 
 
668
        break;
 
669
 
 
670
      case EV_NORMAL:
 
671
          if (ev.event == EV_MOUSE) {
 
672
              found = 0;
 
673
              for (i = 0, el = form->elements; i < form->numComps; i++, el++) {
 
674
                  if ((el->co->top <= ev.u.mouse.y) &&
 
675
                      (el->co->top + el->co->height > ev.u.mouse.y) &&
 
676
                      (el->co->left <= ev.u.mouse.x) &&
 
677
                      (el->co->left + el->co->width > ev.u.mouse.x)) {
 
678
                      found = 1;
 
679
                      if (el->co->takesFocus) {
 
680
                          gotoComponent(form, i);
 
681
                          subco = form->elements[form->currComp].co;
 
682
                      }
 
683
                  }
 
684
                  /* If we did not find a co to send this event to, we
 
685
                     should just swallow the event here. */
 
686
              }
 
687
              if (!found) {
 
688
                  er.result = ER_SWALLOWED;
 
689
 
 
690
                  return er;
 
691
              }
 
692
          }
 
693
        er = subco->ops->event(subco, ev);
 
694
        switch (er.result) {
 
695
          case ER_NEXTCOMP:
 
696
            er.result = ER_SWALLOWED;
 
697
            dir = 1;
 
698
            break;
 
699
 
 
700
          case ER_EXITFORM:
 
701
            form->exitComp = subco;
 
702
            break;
 
703
 
 
704
          default:
 
705
            break;
 
706
        }
 
707
        break;
 
708
 
 
709
      case EV_LATE:
 
710
        er = subco->ops->event(subco, ev);
 
711
 
 
712
        if (er.result == ER_IGNORED) {
 
713
            switch (ev.u.key) {
 
714
              case NEWT_KEY_UP:
 
715
              case NEWT_KEY_LEFT:
 
716
              case NEWT_KEY_BKSPC:
 
717
                er.result = ER_SWALLOWED;
 
718
                dir = -1;
 
719
                break;
 
720
 
 
721
              case NEWT_KEY_DOWN:
 
722
              case NEWT_KEY_RIGHT:
 
723
                er.result = ER_SWALLOWED;
 
724
                dir = 1;
 
725
                break;
 
726
 
 
727
             case NEWT_KEY_PGUP:
 
728
                er.result = ER_SWALLOWED;
 
729
                dir = -1;
 
730
                page = 1;
 
731
                break;
 
732
 
 
733
             case NEWT_KEY_PGDN:
 
734
                er.result = ER_SWALLOWED;
 
735
                dir = 1;
 
736
                page = 1;
 
737
                break;
 
738
            }
 
739
        }
 
740
    }
 
741
 
 
742
    if (dir) {
 
743
        new = form->currComp;
 
744
 
 
745
        if (page) {
 
746
            new += dir * co->height;
 
747
            if (new < 0)
 
748
                new = 0;
 
749
            else if (new >= form->numComps)
 
750
                new = (form->numComps - 1);
 
751
 
 
752
            while (!form->elements[new].co->takesFocus &&
 
753
                    new - dir >= 0 && new - dir < form->numComps)
 
754
                new -= dir;
 
755
        } else {
 
756
            do {
 
757
                new += dir;
 
758
 
 
759
                if (wrap) {
 
760
                    if (new < 0)
 
761
                        new = form->numComps - 1;
 
762
                    else if (new >= form->numComps)
 
763
                        new = 0;
 
764
                    if (new == form->currComp)
 
765
                        /* back where we started */
 
766
                        return er;
 
767
                } else if (new < 0 || new >= form->numComps)
 
768
                    return er;
 
769
            } while (!form->elements[new].co->takesFocus);
 
770
        }
 
771
 
 
772
        /* make sure this component is visible */
 
773
        if (!componentFits(co, new)) {
 
774
            int vertDelta;
 
775
 
 
776
            gotoComponent(form, -1);
 
777
 
 
778
            if (dir < 0) {
 
779
                /* make the new component the first one */
 
780
                vertDelta = form->elements[new].co->top - co->top;
 
781
            } else {
 
782
                /* make the new component the last one */
 
783
                vertDelta = (form->elements[new].co->top +
 
784
                                        form->elements[new].co->height) -
 
785
                                    (co->top + co->height);
 
786
            }
 
787
 
 
788
            formScroll(co, vertDelta);
 
789
            newtDrawForm(co);
 
790
        }
 
791
 
 
792
        gotoComponent(form, new);
 
793
        er.result = ER_SWALLOWED;
 
794
    }
 
795
 
 
796
    return er;
 
797
}
 
798
 
 
799
/* Destroy a component.  Components which have been added to a form
 
800
 * are destroyed when the form is destroyed; this is just for the
 
801
 * (rare) case of components which for whatever reason weren't added
 
802
 * to a form.
 
803
 */
 
804
void newtComponentDestroy(newtComponent co) {
 
805
    /* If the user registered a destroy callback for this component,
 
806
     * now is a good time to call it.
 
807
     */
 
808
    if (co->destroyCallback)
 
809
        co->destroyCallback(co, co->destroyCallbackData);
 
810
 
 
811
    if (co->ops->destroy) {
 
812
        co->ops->destroy(co);
 
813
    } else {
 
814
        if (co->data) free(co->data);
 
815
        free(co);
 
816
    }
 
817
}
 
818
 
 
819
/* this also destroys all of the components on the form */
 
820
void newtFormDestroy(newtComponent co) {
 
821
    newtComponent subco;
 
822
    struct form * form = co->data;
 
823
    int i;
 
824
 
 
825
    /* first, destroy all of the components */
 
826
    for (i = 0; i < form->numComps; i++) {
 
827
        subco = form->elements[i].co;
 
828
        newtComponentDestroy(subco);
 
829
    }
 
830
 
 
831
    if (form->hotKeys) free(form->hotKeys);
 
832
 
 
833
    free(form->elements);
 
834
    free(form);
 
835
    free(co);
 
836
}
 
837
 
 
838
newtComponent newtRunForm(newtComponent co) {
 
839
    struct newtExitStruct es;
 
840
 
 
841
    newtFormRun(co, &es);
 
842
    if (es.reason == NEWT_EXIT_HOTKEY) {
 
843
        if (es.u.key == NEWT_KEY_F12) {
 
844
            es.reason = NEWT_EXIT_COMPONENT;
 
845
            es.u.co = co;
 
846
        } else {
 
847
            return NULL;
 
848
        }
 
849
    } else if (es.reason == NEWT_EXIT_ERROR)
 
850
        return NULL;
 
851
 
 
852
    return es.u.co;
 
853
}
 
854
 
 
855
void newtFormAddHotKey(newtComponent co, int key) {
 
856
    struct form * form = co->data;
 
857
 
 
858
    form->numHotKeys++;
 
859
    form->hotKeys = realloc(form->hotKeys, sizeof(int) * form->numHotKeys);
 
860
    form->hotKeys[form->numHotKeys - 1] = key;
 
861
}
 
862
 
 
863
void newtFormSetSize(newtComponent co) {
 
864
    struct form * form = co->data;
 
865
    int delta, i, first;
 
866
    struct element * el;
 
867
 
 
868
    form->numRows = 0;
 
869
 
 
870
    co->width = 0;
 
871
    if (!form->fixedHeight) co->height = 0;
 
872
 
 
873
    co->top = -1;
 
874
    co->left = -1;
 
875
    first = 1;
 
876
 
 
877
    for (i = 0, el = form->elements; i < form->numComps; i++, el++) {
 
878
        if (el->co->ops == &formOps)
 
879
            newtFormSetSize(el->co);
 
880
        else if (el->co == form->vertBar)
 
881
            continue;
 
882
 
 
883
        if (first) {
 
884
            co->top = el->co->top;
 
885
            co->left = el->co->left;
 
886
            first = 0;
 
887
        }
 
888
 
 
889
        if (co->left > el->co->left) {
 
890
            delta = co->left - el->co->left;
 
891
            co->left -= delta;
 
892
            co->width += delta;
 
893
        }
 
894
 
 
895
        if (co->top > el->co->top) {
 
896
            delta = co->top - el->co->top;
 
897
            co->top -= delta;
 
898
            form->numRows += delta;
 
899
            if (!form->fixedHeight)
 
900
                co->height += delta;
 
901
        }
 
902
 
 
903
        if ((co->left + co->width) < (el->co->left + el->co->width))
 
904
            co->width = (el->co->left + el->co->width) - co->left;
 
905
 
 
906
        if (!form->fixedHeight) {
 
907
            if ((co->top + co->height) < (el->co->top + el->co->height))
 
908
                co->height = (el->co->top + el->co->height) - co->top;
 
909
        }
 
910
 
 
911
        if ((el->co->top + el->co->height - co->top) > form->numRows) {
 
912
            form->numRows = el->co->top + el->co->height - co->top;
 
913
        }
 
914
    }
 
915
 
 
916
    co->top += form->vertOffset;
 
917
}
 
918
 
 
919
void newtFormRun(newtComponent co, struct newtExitStruct * es) {
 
920
    struct form * form = co->data;
 
921
    struct event ev;
 
922
    struct eventResult er;
 
923
    int key, i, max;
 
924
    int done = 0;
 
925
    fd_set readSet, writeSet, exceptSet;
 
926
    struct timeval nextTimeout, now, timeout;
 
927
#ifdef USE_GPM
 
928
    int x, y;
 
929
    Gpm_Connect conn;
 
930
    Gpm_Event event;
 
931
 
 
932
    /* Set up GPM interface */
 
933
    conn.eventMask   = ~GPM_MOVE;
 
934
    conn.defaultMask = GPM_MOVE;
 
935
    conn.minMod      = 0;
 
936
    conn.maxMod      = 0;
 
937
 
 
938
    Gpm_Open(&conn, 0);
 
939
#endif
 
940
 
 
941
    /* draw all of the components */
 
942
    newtDrawForm(co);
 
943
 
 
944
    if (form->currComp == -1) {
 
945
        if (form->numComps)
 
946
            gotoComponent(form, 0);
 
947
    } else
 
948
        gotoComponent(form, form->currComp);
 
949
 
 
950
    while (!done) {
 
951
        newtRefresh();
 
952
 
 
953
        FD_ZERO(&readSet);
 
954
        FD_ZERO(&writeSet);
 
955
        FD_ZERO(&exceptSet);
 
956
        FD_SET(0, &readSet);
 
957
#ifdef USE_GPM
 
958
        if (gpm_fd > 0) {
 
959
            FD_SET(gpm_fd, &readSet);
 
960
        }
 
961
        max = form->maxFd > gpm_fd ? form->maxFd : gpm_fd;
 
962
#else
 
963
        max = form->maxFd;
 
964
#endif
 
965
 
 
966
        for (i = 0; i < form->numFds; i++) {
 
967
            if (form->fds[i].flags & NEWT_FD_READ)
 
968
                FD_SET(form->fds[i].fd, &readSet);
 
969
            if (form->fds[i].flags & NEWT_FD_WRITE)
 
970
                FD_SET(form->fds[i].fd, &writeSet);
 
971
            if (form->fds[i].flags & NEWT_FD_EXCEPT)
 
972
                FD_SET(form->fds[i].fd, &exceptSet);
 
973
        }
 
974
 
 
975
        if (form->timer) {
 
976
            /* Calculate when we next need to return with a timeout. Do
 
977
               this inside the loop in case a callback resets the timer. */
 
978
            gettimeofday(&now, 0);
 
979
 
 
980
            if ((!form->lastTimeout.tv_sec && !form->lastTimeout.tv_usec) ||
 
981
                    now.tv_sec < form->lastTimeout.tv_sec ||
 
982
                    (now.tv_sec == form->lastTimeout.tv_sec &&
 
983
                     now.tv_usec < form->lastTimeout.tv_usec))
 
984
                form->lastTimeout = now;
 
985
 
 
986
            nextTimeout.tv_sec = form->lastTimeout.tv_sec + 
 
987
                    (form->timer / 1000);
 
988
            nextTimeout.tv_usec = form->lastTimeout.tv_usec + 
 
989
                                    (form->timer % 1000) * 1000;
 
990
 
 
991
            if (now.tv_sec > nextTimeout.tv_sec) {
 
992
                timeout.tv_sec = timeout.tv_usec = 0;
 
993
            } else if (now.tv_sec == nextTimeout.tv_sec) {
 
994
                timeout.tv_sec = 0;
 
995
                if (now.tv_usec > nextTimeout.tv_usec)
 
996
                    timeout.tv_usec = 0;
 
997
                else
 
998
                    timeout.tv_usec = nextTimeout.tv_usec - now.tv_usec;
 
999
            } else if (now.tv_sec < nextTimeout.tv_sec) {
 
1000
                timeout.tv_sec = nextTimeout.tv_sec - now.tv_sec;
 
1001
                if (now.tv_usec > nextTimeout.tv_usec)
 
1002
                    timeout.tv_sec--,
 
1003
                    timeout.tv_usec = nextTimeout.tv_usec + 1000000 -
 
1004
                                        now.tv_usec;
 
1005
                else 
 
1006
                    timeout.tv_usec = nextTimeout.tv_usec - now.tv_usec;
 
1007
            }
 
1008
        } else {
 
1009
            timeout.tv_sec = timeout.tv_usec = 0;
 
1010
        }
 
1011
 
 
1012
        if (needResize) {
 
1013
                needResize = 0;
 
1014
                newtResizeScreen(1);
 
1015
        }
 
1016
 
 
1017
        i = select(max + 1, &readSet, &writeSet, &exceptSet, 
 
1018
                        form->timer ? &timeout : NULL);
 
1019
        if (i < 0) continue;    /* ?? What should we do here? */
 
1020
 
 
1021
        if (i == 0) {
 
1022
            done = 1;
 
1023
            es->reason = NEWT_EXIT_TIMER;
 
1024
            gettimeofday(&form->lastTimeout, NULL);
 
1025
        } else
 
1026
#ifdef USE_GPM
 
1027
        if (gpm_fd > 0 && FD_ISSET(gpm_fd, &readSet)) {
 
1028
            Gpm_GetEvent(&event);
 
1029
 
 
1030
            if (event.type & GPM_DOWN) {
 
1031
                /* Transform coordinates to current window */
 
1032
                newtGetWindowPos(&x, &y);
 
1033
 
 
1034
                ev.event = EV_MOUSE;
 
1035
                ev.u.mouse.type = MOUSE_BUTTON_DOWN;
 
1036
                ev.u.mouse.x = event.x - x - 1;
 
1037
                ev.u.mouse.y = event.y - y - 1;
 
1038
 
 
1039
                /* Send the form the event */
 
1040
                er = sendEvent(co, ev);
 
1041
 
 
1042
                if (er.result == ER_EXITFORM) {
 
1043
                    done = 1;
 
1044
                    es->reason = NEWT_EXIT_COMPONENT;
 
1045
                    es->u.co = form->exitComp;
 
1046
                }
 
1047
 
 
1048
            }
 
1049
        } else
 
1050
#endif
 
1051
        {
 
1052
            if (FD_ISSET(0, &readSet)) {
 
1053
 
 
1054
                key = newtGetKey();
 
1055
 
 
1056
                for (i = 0; i < form->numHotKeys; i++) {
 
1057
                    if (form->hotKeys[i] == key) {
 
1058
                        es->reason = NEWT_EXIT_HOTKEY;
 
1059
                        es->u.key = key;
 
1060
                        done = 1;
 
1061
                        break;
 
1062
                    }
 
1063
                }
 
1064
 
 
1065
                if (key == NEWT_KEY_F1 && form->helpTag && form->helpCb) {
 
1066
                    if (form->currComp != -1) {
 
1067
                        ev.event = EV_UNFOCUS;
 
1068
                        sendEvent(form->elements[form->currComp].co, ev);
 
1069
                    }
 
1070
                    form->helpCb(co, form->helpTag);
 
1071
                    if (form->currComp != -1) {
 
1072
                        ev.event = EV_FOCUS;
 
1073
                        sendEvent(form->elements[form->currComp].co, ev);
 
1074
                    }
 
1075
                }
 
1076
 
 
1077
                if (key == NEWT_KEY_ERROR) {
 
1078
                    es->u.watch = -1;
 
1079
                    es->reason = NEWT_EXIT_ERROR;
 
1080
                    done = 1;
 
1081
                }
 
1082
 
 
1083
                if (!done) {
 
1084
                    ev.event = EV_KEYPRESS;
 
1085
                    ev.u.key = key;
 
1086
 
 
1087
                    er = sendEvent(co, ev);
 
1088
 
 
1089
                    if (er.result == ER_EXITFORM) {
 
1090
                        done = 1;
 
1091
                        es->reason = NEWT_EXIT_COMPONENT;
 
1092
                        es->u.co = form->exitComp;
 
1093
                    }
 
1094
                }
 
1095
            } else {
 
1096
                for (i = 0; i < form->numFds; i++) {
 
1097
                    if (((form->fds[i].flags & NEWT_FD_READ)
 
1098
                        && FD_ISSET(form->fds[i].fd, &readSet))
 
1099
                        || ((form->fds[i].flags & NEWT_FD_WRITE)
 
1100
                        && FD_ISSET(form->fds[i].fd, &writeSet))
 
1101
                        || ((form->fds[i].flags & NEWT_FD_EXCEPT)
 
1102
                        && FD_ISSET(form->fds[i].fd, &exceptSet))) break;
 
1103
                }
 
1104
                if(i < form->numFds)
 
1105
                    es->u.watch = form->fds[i].fd;
 
1106
                else
 
1107
                    es->u.watch = -1;
 
1108
 
 
1109
                es->reason = NEWT_EXIT_FDREADY;
 
1110
                done = 1;
 
1111
            }
 
1112
        }
 
1113
    }
 
1114
    newtRefresh();
 
1115
#ifdef USE_GPM
 
1116
    Gpm_Close();
 
1117
#endif
 
1118
}
 
1119
 
 
1120
static struct eventResult sendEvent(newtComponent co, struct event ev) {
 
1121
    struct eventResult er;
 
1122
 
 
1123
    ev.when = EV_EARLY;
 
1124
    er = co->ops->event(co, ev);
 
1125
 
 
1126
    if (er.result == ER_IGNORED) {
 
1127
        ev.when = EV_NORMAL;
 
1128
        er = co->ops->event(co, ev);
 
1129
    }
 
1130
 
 
1131
    if (er.result == ER_IGNORED) {
 
1132
        ev.when = EV_LATE;
 
1133
        er = co->ops->event(co, ev);
 
1134
    }
 
1135
 
 
1136
    return er;
 
1137
}
 
1138
 
 
1139
static void gotoComponent(struct form * form, int newComp) {
 
1140
    struct event ev;
 
1141
 
 
1142
    if (form->currComp != -1) {
 
1143
        ev.event = EV_UNFOCUS;
 
1144
        sendEvent(form->elements[form->currComp].co, ev);
 
1145
    }
 
1146
 
 
1147
    form->currComp = newComp;
 
1148
 
 
1149
    if (form->currComp != -1) {
 
1150
        ev.event = EV_FOCUS;
 
1151
        ev.when = EV_NORMAL;
 
1152
        sendEvent(form->elements[form->currComp].co, ev);
 
1153
    }
 
1154
}
 
1155
 
 
1156
void newtComponentAddCallback(newtComponent co, newtCallback f, void * data) {
 
1157
    co->callback = f;
 
1158
    co->callbackData = data;
 
1159
}
 
1160
 
 
1161
/* Add a callback which is called when the component is destroyed. */
 
1162
void newtComponentAddDestroyCallback(newtComponent co,
 
1163
                                newtCallback f, void * data) {
 
1164
    co->destroyCallback = f;
 
1165
    co->destroyCallbackData = data;
 
1166
}
 
1167
 
 
1168
void newtComponentTakesFocus(newtComponent co, int val) {
 
1169
    co->takesFocus = val;
 
1170
}
 
1171
 
 
1172
void newtFormSetBackground(newtComponent co, int color) {
 
1173
    struct form * form = co->data;
 
1174
 
 
1175
    form->background = color;
 
1176
}
 
1177
 
 
1178
void newtFormWatchFd(newtComponent co, int fd, int fdFlags) {
 
1179
    struct form * form = co->data;
 
1180
    int i;
 
1181
 
 
1182
    for (i = 0; i < form->numFds; i++)
 
1183
      if (form->fds[i].fd == fd)
 
1184
        break;
 
1185
 
 
1186
    if(i >= form->numFds)
 
1187
      form->fds = realloc(form->fds, (++form->numFds) * sizeof(*form->fds));
 
1188
 
 
1189
    form->fds[i].fd = fd;
 
1190
    form->fds[i].flags = fdFlags;
 
1191
    if (form->maxFd < fd) form->maxFd = fd;
 
1192
}
 
1193
 
 
1194
void newtSetHelpCallback(newtCallback cb) {
 
1195
    helpCallback = cb;
 
1196
}