~ubuntu-branches/ubuntu/edgy/newt/edgy

« back to all changes in this revision

Viewing changes to form.c

  • Committer: Bazaar Package Importer
  • Author(s): Junichi Uekawa
  • Date: 2002-03-31 09:38:18 UTC
  • Revision ID: james.westby@ubuntu.com-20020331093818-t3cla7103r07qnyw
Tags: upstream-0.50.17
ImportĀ upstreamĀ versionĀ 0.50.17

Show diffs side-by-side

added added

removed removed

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