]> git.ipfire.org Git - thirdparty/newt.git/blobdiff - form.c
install python modules to purelib and platlib
[thirdparty/newt.git] / form.c
diff --git a/form.c b/form.c
index 31402135657f8b3f275a0a262c3fb13bdf13582f..24c601d41f3772f8c02e4ef04facf0f1431baac7 100644 (file)
--- a/form.c
+++ b/form.c
@@ -1,16 +1,18 @@
 #include "config.h"
 
+#include <sys/types.h>
+
 #include <slang.h>
 #include <stdarg.h>
 #include <stdlib.h>
+#ifdef HAVE_SYS_SELECT_H
 #include <sys/select.h>
+#endif
 #include <sys/time.h>
-#include <string.h>
 
 #ifdef USE_GPM
 #include <ctype.h>
 #include <sys/time.h>      /* timeval */
-#include <sys/types.h>     /* socket() */
 #include <sys/socket.h>    /* socket() */
 #include <sys/un.h>        /* struct sockaddr_un */
 #include <sys/fcntl.h>     /* O_RDONLY */
 
 #include "newt.h"
 #include "newt_pr.h"
-#include "eawidth.h"
-
-struct label {
-       char *text;
-       int length;
-};
 
 #ifdef USE_GPM
 /*....................................... The connection data structure */
@@ -87,6 +83,7 @@ static int gpm_fd=-1;
 static int gpm_flag=0;
 static int gpm_tried=0;
 Gpm_Stst *gpm_stack=NULL;
+static char *gpm_sock_name=NULL;
 static struct sigaction gpm_saved_suspend_hook;
 static struct sigaction gpm_saved_winch_hook;
 
@@ -159,7 +156,6 @@ static int Gpm_Open(Gpm_Connect *conn, int flag)
   int i;
   struct sockaddr_un addr;
   Gpm_Stst *new;
-  char* sock_name = 0;
 
   /*....................................... First of all, check xterm */
 
@@ -232,10 +228,10 @@ static int Gpm_Open(Gpm_Connect *conn, int flag)
 
       bzero((char *)&addr,sizeof(addr));
       addr.sun_family=AF_UNIX;
-      if (!(sock_name = tempnam (0, "gpm"))) {
+      if (!(gpm_sock_name = tempnam (0, "gpm"))) {
         goto err;
       } /*if*/
-      strncpy (addr.sun_path, sock_name, sizeof (addr.sun_path));
+      strncpy (addr.sun_path, gpm_sock_name, sizeof (addr.sun_path));
       if (bind (gpm_fd, (struct sockaddr*)&addr,
                 sizeof (addr.sun_family) + strlen (addr.sun_path))==-1) {
         goto err;
@@ -306,12 +302,13 @@ static int Gpm_Open(Gpm_Connect *conn, int flag)
     }
   while(gpm_stack);
   if (gpm_fd>=0) close(gpm_fd);
-  if (sock_name) {
-    unlink(sock_name);
-    free(sock_name);
-    sock_name = 0;
+  if (gpm_sock_name) {
+    unlink(gpm_sock_name);
+    free(gpm_sock_name);
+    gpm_sock_name = NULL;
   } /*if*/
   gpm_flag=0;
+  gpm_fd=-1;
   return -1;
 }
 
@@ -337,6 +334,11 @@ static int Gpm_Close(void)
 
   if (gpm_fd>=0) close(gpm_fd);
   gpm_fd=-1;
+  if (gpm_sock_name) {
+    unlink(gpm_sock_name);
+    free(gpm_sock_name);
+    gpm_sock_name = NULL;
+  }
 #ifdef SIGTSTP
   sigaction(SIGTSTP, &gpm_saved_suspend_hook, 0);
 #endif
@@ -376,8 +378,7 @@ static int Gpm_GetEvent(Gpm_Event *event)
 *****************************************************************************/
 
 struct element {
-    int top, left;             /* Actual, not virtual. These are translated */
-    newtComponent co;          /* into actual through vertOffset */
+    newtComponent co;
 };
 
 struct fdInfo {
@@ -399,7 +400,6 @@ struct form {
     int * hotKeys;
     int numHotKeys;
     int background;
-    int beenSet;
     int numFds;
     struct fdInfo * fds;
     int maxFd;
@@ -409,7 +409,7 @@ struct form {
     newtCallback helpCb;
 };
 
-static void gotoComponent(struct form * form, int newComp);
+static void gotoComponent(newtComponent co, int newComp);
 static struct eventResult formEvent(newtComponent co, struct event ev);
 static struct eventResult sendEvent(newtComponent comp, struct event ev);
 static void formPlace(newtComponent co, int left, int top);
@@ -426,13 +426,16 @@ struct componentOps formOps = {
     newtDefaultMappedHandler,
 } ;
 
+int needResize = 0;
+
 static inline int componentFits(newtComponent co, int compNum) {
     struct form * form = co->data;
     struct element * el = form->elements + compNum;
 
-    if ((co->top + form->vertOffset) > el->top) return 0;
-    if ((co->top + form->vertOffset + co->height) <
-           (el->top + el->co->height)) return 0;
+    if (co->top > el->co->top)
+       return 0;
+    if (co->top + co->height < el->co->top + el->co->height)
+       return 0;
 
     return 1;
 }
@@ -449,10 +452,11 @@ newtComponent newtForm(newtComponent vertBar, void * help, int flags) {
     co->top = -1;
     co->left = -1;
     co->isMapped = 0;
-       co->isLabel = 0;
 
     co->takesFocus = 0;                        /* we may have 0 components */
     co->ops = &formOps;
+    co->callback = NULL;
+    co->destroyCallback = NULL;
 
     form->help = help;
     form->flags = flags;
@@ -465,7 +469,6 @@ newtComponent newtForm(newtComponent vertBar, void * help, int flags) {
     form->numFds = 0;
     form->maxFd = 0;
     form->fds = NULL;
-    form->beenSet = 0;
     form->elements = malloc(sizeof(*(form->elements)) * form->numCompsAlloced);
 
     form->background = COLORSET_WINDOW;
@@ -491,9 +494,44 @@ newtComponent newtForm(newtComponent vertBar, void * help, int flags) {
 newtComponent newtFormGetCurrent(newtComponent co) {
     struct form * form = co->data;
 
+    if (form->currComp == -1) return 0;
     return form->elements[form->currComp].co;
 }
 
+static void formScroll(newtComponent co, int delta) {
+    struct form * form = co->data;
+    struct element * el;
+    int i, newVertOffset = form->vertOffset + delta;
+
+    if (newVertOffset < 0)
+       newVertOffset = 0;
+    if (newVertOffset > form->numRows - co->height)
+       newVertOffset = form->numRows - co->height;
+
+    delta = newVertOffset - form->vertOffset;
+    form->vertOffset = newVertOffset;
+
+    for (i = 0, el = form->elements; i < form->numComps; i++, el++) {
+       if (el->co == form->vertBar)
+           continue;
+       el->co->ops->place(el->co, el->co->left, el->co->top - delta);
+    }
+}
+
+int newtFormGetScrollPosition(newtComponent co) {
+    struct form * form = co->data;
+
+    return form->vertOffset;
+}
+
+void newtFormSetScrollPosition(newtComponent co, int position) {
+    struct form * form = co->data;
+
+    if (form->numRows == 0)
+       newtFormSetSize(co);
+    formScroll(co, position - form->vertOffset);
+}
+
 void newtFormSetCurrent(newtComponent co, newtComponent subco) {
     struct form * form = co->data;
     int i, new;
@@ -506,13 +544,11 @@ void newtFormSetCurrent(newtComponent co, newtComponent subco) {
     new = i;
 
     if (co->isMapped && !componentFits(co, new)) {
-       gotoComponent(form, -1);
-       form->vertOffset = form->elements[new].top - co->top - 1;
-       if (form->vertOffset > (form->numRows - co->height))
-           form->vertOffset = form->numRows - co->height;
+       gotoComponent(co, -1);
+       formScroll(co, form->elements[new].co->top - co->top - 1);
     }
 
-    gotoComponent(form, new);
+    gotoComponent(co, new);
 }
 
 void newtFormSetTimer(newtComponent co, int millisecs) {
@@ -536,8 +572,6 @@ void newtFormSetWidth(newtComponent co, int width) {
 
 void newtFormAddComponent(newtComponent co, newtComponent newco) {
     struct form * form = co->data;
-       int i, j, k, l, xmap, ymap, x, y;
-       char *map, *s = NULL;
 
     co->takesFocus = 1;
 
@@ -547,85 +581,12 @@ void newtFormAddComponent(newtComponent co, newtComponent newco) {
                            sizeof(*(form->elements)) * form->numCompsAlloced);
     }
 
-    /* we grab real values for these a bit later */
-    form->elements[form->numComps].left = -2;
-    form->elements[form->numComps].top = -2;
     form->elements[form->numComps].co = newco;
 
     if (newco->takesFocus && form->currComp == -1)
        form->currComp = form->numComps;
 
     form->numComps++;
-
-       /* check multibyte char broken */
-       /* create text map */
-       xmap = 0;
-       ymap = 0;
-       for ( i = 0; i < form->numComps; i++ ) {
-               if ((form->elements[i].co->top + form->elements[i].co->height) > ymap )
-                       ymap = form->elements[i].co->top + form->elements[i].co->height;
-               if ((form->elements[i].co->left + form->elements[i].co->width) > xmap )
-                       xmap = form->elements[i].co->left + form->elements[i].co->width;
-       }
-       map = (char *)calloc ((xmap+1) * (ymap+1), sizeof (char));
-
-#define MAP(x,y) *(map + ((x)*ymap + (y)))
-
-       /* create non-label components map */
-       for ( i = 0; i < form->numComps; i++ ) {
-               if ( form->elements[i].co->isLabel == 0 && form->elements[i].co->left >= 0 && form->elements[i].co->top >= 0 ) {
-                       for ( x = 0; x < form->elements[i].co->width; x++ ) {
-                               for ( y = 0; y < form->elements[i].co->height; y++ )
-                                       MAP (form->elements[i].co->left+x, form->elements[i].co->top+y) = 1;
-                       }
-               }
-       }
-
-       /* check label overlap */
-       for ( i = 0; i < form->numComps; i++ ) {
-               if ( form->elements[i].co->isLabel != 0 ) {
-                       y = form->elements[i].co->top;
-                       l = form->elements[i].co->left;
-                       if ( y >= 0 && l >= 0 ) {
-                               for ( j = 0; j < form->elements[i].co->width; j++ ) {
-                                       if ( MAP (j+l, y) != 0 ) {
-                                               if ( MAP (j+l, y) != 1 ) {
-                                                       /* if label is here, move label */
-                                                       while ( MAP (form->elements[i].co->left, y) != 0 )
-                                                               form->elements[i].co->left++;
-                                               } else {
-                                                       /* if label is overlapping, cut label */
-                                                       if ((j+l) == form->elements[i].co->left ) {
-                                                               free (((struct label *)form->elements[i].co->data)->text);
-                                                               ((struct label *)form->elements[i].co->data)->text = malloc (1);
-                                                               ((struct label *)form->elements[i].co->data)->text[0] = 0;
-                                                               ((struct label *)form->elements[i].co->data)->length = 0;
-                                                               form->elements[i].co->width = 0;
-                                                       } else {
-                                                               x = 0;
-                                                               while (x < j) {
-                                                                       s = &((struct label *)form->elements[i].co->data)->text[x];
-                                                                       k = east_asia_mblen (NULL, s, strlen (s), 0);
-                                                                       if ( k <= 0 ) break;
-                                                                       else {
-                                                                               if ((x+k) < j ) x += k;
-                                                                               else break;
-                                                                       }
-                                                               }
-                                                               s = ((struct label *)form->elements[i].co->data)->text;
-                                                               ((struct label *)form->elements[i].co->data)->text = realloc(s, x+1);
-                                                               ((struct label *)form->elements[i].co->data)->text[x] = 0;
-                                                               ((struct label *)form->elements[i].co->data)->length = strlen (s);
-                                                               form->elements[i].co->width = get_east_asia_str_width (NULL, s, 0);
-                                                       }
-                                               }
-                                       } else
-                                               MAP (j+l, y) = 2;
-                               }
-                       }
-               }
-       }
-       free (map);
 }
 
 void newtFormAddComponents(newtComponent co, ...) {
@@ -646,18 +607,14 @@ static void formPlace(newtComponent co, int left, int top) {
     struct element * el;
     int i;
 
-    newtFormSetSize(co);
-
     vertDelta = top - co->top;
     horizDelta = left - co->left;
     co->top = top;
     co->left = left;
 
     for (i = 0, el = form->elements; i < form->numComps; i++, el++) {
-       el->co->top += vertDelta;
-       el->top += vertDelta;
-       el->co->left += horizDelta;
-       el->left += horizDelta;
+       el->co->ops->place(el->co, el->co->left + horizDelta,
+               el->co->top + vertDelta);
     }
 }
 
@@ -670,20 +627,15 @@ void newtDrawForm(newtComponent co) {
 
     SLsmg_set_color(form->background);
     newtClearBox(co->left, co->top, co->width, co->height);
+
     for (i = 0, el = form->elements; i < form->numComps; i++, el++) {
-       /* the scrollbar *always* fits somewhere */
-       if (el->co == form->vertBar) {
+       /* only draw it if it'll fit on the screen vertically
+          (the scrollbar *always* fits somewhere) */
+       if (el->co == form->vertBar || componentFits(co, i)) {
            el->co->ops->mapped(el->co, 1);
            el->co->ops->draw(el->co);
        } else {
-           /* only draw it if it'll fit on the screen vertically */
-           if (componentFits(co, i)) {
-               el->co->top = el->top - form->vertOffset;
-               el->co->ops->mapped(el->co, 1);
-               el->co->ops->draw(el->co);
-           } else {
-               el->co->ops->mapped(el->co, 0);
-           }
+           el->co->ops->mapped(el->co, 0);
        }
     }
 
@@ -704,7 +656,7 @@ static struct eventResult formEvent(newtComponent co, struct event ev) {
     er.result = ER_IGNORED;
     if (!form->numComps) return er;
 
-    subco = form->elements[form->currComp].co;
+    if (form->currComp == -1) return er;
 
     switch (ev.when) {
       case EV_EARLY:
@@ -744,7 +696,7 @@ static struct eventResult formEvent(newtComponent co, struct event ev) {
                      (el->co->left + el->co->width > ev.u.mouse.x)) {
                      found = 1;
                      if (el->co->takesFocus) {
-                         gotoComponent(form, i);
+                         gotoComponent(co, i);
                          subco = form->elements[form->currComp].co;
                      }
                  }
@@ -816,8 +768,9 @@ static struct eventResult formEvent(newtComponent co, struct event ev) {
            else if (new >= form->numComps)
                new = (form->numComps - 1);
 
-           while (!form->elements[new].co->takesFocus)
-               new = new - dir;
+           while (!form->elements[new].co->takesFocus &&
+                   new - dir >= 0 && new - dir < form->numComps)
+               new -= dir;
        } else {
            do {
                new += dir;
@@ -827,6 +780,9 @@ static struct eventResult formEvent(newtComponent co, struct event ev) {
                        new = form->numComps - 1;
                    else if (new >= form->numComps)
                        new = 0;
+                   if (new == form->currComp)
+                       /* back where we started */
+                       return er;
                } else if (new < 0 || new >= form->numComps)
                    return er;
            } while (!form->elements[new].co->takesFocus);
@@ -834,32 +790,51 @@ static struct eventResult formEvent(newtComponent co, struct event ev) {
 
        /* make sure this component is visible */
        if (!componentFits(co, new)) {
-           gotoComponent(form, -1);
+           int vertDelta;
+
+           gotoComponent(co, -1);
 
            if (dir < 0) {
                /* make the new component the first one */
-               form->vertOffset = form->elements[new].top - co->top;
+               vertDelta = form->elements[new].co->top - co->top;
            } else {
                /* make the new component the last one */
-               form->vertOffset = (form->elements[new].top +
+               vertDelta = (form->elements[new].co->top +
                                        form->elements[new].co->height) -
                                    (co->top + co->height);
            }
 
-           if (form->vertOffset < 0) form->vertOffset = 0;
-           if (form->vertOffset > (form->numRows - co->height))
-               form->vertOffset = form->numRows - co->height;
-
+           formScroll(co, vertDelta);
            newtDrawForm(co);
        }
 
-       gotoComponent(form, new);
+       gotoComponent(co, new);
        er.result = ER_SWALLOWED;
     }
 
     return er;
 }
 
+/* Destroy a component.  Components which have been added to a form
+ * are destroyed when the form is destroyed; this is just for the
+ * (rare) case of components which for whatever reason weren't added
+ * to a form.
+ */
+void newtComponentDestroy(newtComponent co) {
+    /* If the user registered a destroy callback for this component,
+     * now is a good time to call it.
+     */
+    if (co->destroyCallback)
+        co->destroyCallback(co, co->destroyCallbackData);
+
+    if (co->ops->destroy) {
+        co->ops->destroy(co);
+    } else {
+        if (co->data) free(co->data);
+       free(co);
+    }
+}
+
 /* this also destroys all of the components on the form */
 void newtFormDestroy(newtComponent co) {
     newtComponent subco;
@@ -869,12 +844,7 @@ void newtFormDestroy(newtComponent co) {
     /* first, destroy all of the components */
     for (i = 0; i < form->numComps; i++) {
        subco = form->elements[i].co;
-       if (subco->ops->destroy) {
-           subco->ops->destroy(subco);
-       } else {
-           if (subco->data) free(subco->data);
-           free(subco);
-       }
+       newtComponentDestroy(subco);
     }
 
     if (form->hotKeys) free(form->hotKeys);
@@ -882,7 +852,6 @@ void newtFormDestroy(newtComponent co) {
     free(form->elements);
     free(form);
     free(co);
-    newtResizeScreen(1);
 }
 
 newtComponent newtRunForm(newtComponent co) {
@@ -896,7 +865,8 @@ newtComponent newtRunForm(newtComponent co) {
        } else {
            return NULL;
        }
-    }
+    } else if (es.reason == NEWT_EXIT_ERROR)
+       return NULL;
 
     return es.u.co;
 }
@@ -911,26 +881,29 @@ void newtFormAddHotKey(newtComponent co, int key) {
 
 void newtFormSetSize(newtComponent co) {
     struct form * form = co->data;
-    int delta, i;
+    int delta, i, first;
     struct element * el;
 
-    if (form->beenSet) return;
-
-    form->beenSet = 1;
-
-    if (!form->numComps) return;
+    form->numRows = 0;
 
     co->width = 0;
     if (!form->fixedHeight) co->height = 0;
 
-    co->top = form->elements[0].co->top;
-    co->left = form->elements[0].co->left;
+    co->top = -1;
+    co->left = -1;
+    first = 1;
+
     for (i = 0, el = form->elements; i < form->numComps; i++, el++) {
        if (el->co->ops == &formOps)
            newtFormSetSize(el->co);
+       else if (el->co == form->vertBar)
+           continue;
 
-       el->left = el->co->left;
-       el->top = el->co->top;
+       if (first) {
+           co->top = el->co->top;
+           co->left = el->co->left;
+           first = 0;
+       }
 
        if (co->left > el->co->left) {
            delta = co->left - el->co->left;
@@ -941,6 +914,7 @@ void newtFormSetSize(newtComponent co) {
        if (co->top > el->co->top) {
            delta = co->top - el->co->top;
            co->top -= delta;
+           form->numRows += delta;
            if (!form->fixedHeight)
                co->height += delta;
        }
@@ -957,6 +931,8 @@ void newtFormSetSize(newtComponent co) {
            form->numRows = el->co->top + el->co->height - co->top;
        }
     }
+
+    co->top += form->vertOffset;
 }
 
 void newtFormRun(newtComponent co, struct newtExitStruct * es) {
@@ -965,7 +941,7 @@ void newtFormRun(newtComponent co, struct newtExitStruct * es) {
     struct eventResult er;
     int key, i, max;
     int done = 0;
-    fd_set readSet, writeSet;
+    fd_set readSet, writeSet, exceptSet;
     struct timeval nextTimeout, now, timeout;
 #ifdef USE_GPM
     int x, y;
@@ -981,20 +957,21 @@ void newtFormRun(newtComponent co, struct newtExitStruct * es) {
     Gpm_Open(&conn, 0);
 #endif
 
-    newtFormSetSize(co);
     /* draw all of the components */
     newtDrawForm(co);
 
     if (form->currComp == -1) {
-       gotoComponent(form, 0);
+       if (form->numComps)
+           gotoComponent(co, 0);
     } else
-       gotoComponent(form, form->currComp);
+       gotoComponent(co, form->currComp);
 
     while (!done) {
        newtRefresh();
 
        FD_ZERO(&readSet);
        FD_ZERO(&writeSet);
+       FD_ZERO(&exceptSet);
        FD_SET(0, &readSet);
 #ifdef USE_GPM
        if (gpm_fd > 0) {
@@ -1010,21 +987,26 @@ void newtFormRun(newtComponent co, struct newtExitStruct * es) {
                FD_SET(form->fds[i].fd, &readSet);
            if (form->fds[i].flags & NEWT_FD_WRITE)
                FD_SET(form->fds[i].fd, &writeSet);
+           if (form->fds[i].flags & NEWT_FD_EXCEPT)
+               FD_SET(form->fds[i].fd, &exceptSet);
        }
 
        if (form->timer) {
            /* Calculate when we next need to return with a timeout. Do
               this inside the loop in case a callback resets the timer. */
-           if (!form->lastTimeout.tv_sec && !form->lastTimeout.tv_usec)
-               gettimeofday(&form->lastTimeout, NULL);
+           gettimeofday(&now, 0);
+
+           if ((!form->lastTimeout.tv_sec && !form->lastTimeout.tv_usec) ||
+                   now.tv_sec < form->lastTimeout.tv_sec ||
+                   (now.tv_sec == form->lastTimeout.tv_sec &&
+                    now.tv_usec < form->lastTimeout.tv_usec))
+               form->lastTimeout = now;
 
            nextTimeout.tv_sec = form->lastTimeout.tv_sec + 
                    (form->timer / 1000);
            nextTimeout.tv_usec = form->lastTimeout.tv_usec + 
                                    (form->timer % 1000) * 1000;
 
-           gettimeofday(&now, 0);
-
            if (now.tv_sec > nextTimeout.tv_sec) {
                timeout.tv_sec = timeout.tv_usec = 0;
            } else if (now.tv_sec == nextTimeout.tv_sec) {
@@ -1046,7 +1028,24 @@ void newtFormRun(newtComponent co, struct newtExitStruct * es) {
            timeout.tv_sec = timeout.tv_usec = 0;
        }
 
-       i = select(max + 1, &readSet, &writeSet, NULL, 
+       if (needResize) {
+               needResize = 0;
+               newtResizeScreen(1);
+
+               /* The application may want to handle the resize */
+               for (i = 0; i < form->numHotKeys; i++) {
+                   if (form->hotKeys[i] == NEWT_KEY_RESIZE) {
+                       es->reason = NEWT_EXIT_HOTKEY;
+                       es->u.key = NEWT_KEY_RESIZE;
+                       done = 1;
+                       break;
+                   }
+               }
+               if (done)
+                   break;
+       }
+
+       i = select(max + 1, &readSet, &writeSet, &exceptSet, 
                        form->timer ? &timeout : NULL);
        if (i < 0) continue;    /* ?? What should we do here? */
 
@@ -1085,11 +1084,6 @@ void newtFormRun(newtComponent co, struct newtExitStruct * es) {
 
                key = newtGetKey();
 
-               if (key == NEWT_KEY_RESIZE) {
-                   /* newtResizeScreen(1); */
-                   continue;
-               }
-
                for (i = 0; i < form->numHotKeys; i++) {
                    if (form->hotKeys[i] == key) {
                        es->reason = NEWT_EXIT_HOTKEY;
@@ -1099,8 +1093,23 @@ void newtFormRun(newtComponent co, struct newtExitStruct * es) {
                    }
                }
 
-               if (key == NEWT_KEY_F1 && form->helpTag && form->helpCb)
+               if (key == NEWT_KEY_F1 && form->helpTag && form->helpCb) {
+                   if (form->currComp != -1) {
+                       ev.event = EV_UNFOCUS;
+                       sendEvent(form->elements[form->currComp].co, ev);
+                   }
                    form->helpCb(co, form->helpTag);
+                   if (form->currComp != -1) {
+                       ev.event = EV_FOCUS;
+                       sendEvent(form->elements[form->currComp].co, ev);
+                   }
+               }
+
+               if (key == NEWT_KEY_ERROR) {
+                   es->u.watch = -1;
+                   es->reason = NEWT_EXIT_ERROR;
+                   done = 1;
+               }
 
                if (!done) {
                    ev.event = EV_KEYPRESS;
@@ -1115,6 +1124,19 @@ void newtFormRun(newtComponent co, struct newtExitStruct * es) {
                    }
                }
            } else {
+               for (i = 0; i < form->numFds; i++) {
+                   if (((form->fds[i].flags & NEWT_FD_READ)
+                       && FD_ISSET(form->fds[i].fd, &readSet))
+                       || ((form->fds[i].flags & NEWT_FD_WRITE)
+                       && FD_ISSET(form->fds[i].fd, &writeSet))
+                       || ((form->fds[i].flags & NEWT_FD_EXCEPT)
+                       && FD_ISSET(form->fds[i].fd, &exceptSet))) break;
+               }
+               if(i < form->numFds)
+                   es->u.watch = form->fds[i].fd;
+               else
+                   es->u.watch = -1;
+
                es->reason = NEWT_EXIT_FDREADY;
                done = 1;
            }
@@ -1145,7 +1167,8 @@ static struct eventResult sendEvent(newtComponent co, struct event ev) {
     return er;
 }
 
-static void gotoComponent(struct form * form, int newComp) {
+static void gotoComponent(newtComponent co, int newComp) {
+    struct form * form = co->data;
     struct event ev;
 
     if (form->currComp != -1) {
@@ -1160,6 +1183,9 @@ static void gotoComponent(struct form * form, int newComp) {
        ev.when = EV_NORMAL;
        sendEvent(form->elements[form->currComp].co, ev);
     }
+
+    if (co->callback)
+       co->callback(co, co->callbackData);
 }
 
 void newtComponentAddCallback(newtComponent co, newtCallback f, void * data) {
@@ -1167,6 +1193,13 @@ void newtComponentAddCallback(newtComponent co, newtCallback f, void * data) {
     co->callbackData = data;
 }
 
+/* Add a callback which is called when the component is destroyed. */
+void newtComponentAddDestroyCallback(newtComponent co,
+                               newtCallback f, void * data) {
+    co->destroyCallback = f;
+    co->destroyCallbackData = data;
+}
+
 void newtComponentTakesFocus(newtComponent co, int val) {
     co->takesFocus = val;
 }
@@ -1179,10 +1212,17 @@ void newtFormSetBackground(newtComponent co, int color) {
 
 void newtFormWatchFd(newtComponent co, int fd, int fdFlags) {
     struct form * form = co->data;
+    int i;
+
+    for (i = 0; i < form->numFds; i++)
+      if (form->fds[i].fd == fd)
+       break;
+
+    if(i >= form->numFds)
+      form->fds = realloc(form->fds, (++form->numFds) * sizeof(*form->fds));
 
-    form->fds = realloc(form->fds, (form->numFds + 1) * sizeof(*form->fds));
-    form->fds[form->numFds].fd = fd;
-    form->fds[form->numFds++].flags = fdFlags;
+    form->fds[i].fd = fd;
+    form->fds[i].flags = fdFlags;
     if (form->maxFd < fd) form->maxFd = fd;
 }