#include "config.h" #include #include #include #include #ifdef HAVE_SYS_SELECT_H #include #endif #include #ifdef USE_GPM #include #include /* timeval */ #include /* socket() */ #include /* struct sockaddr_un */ #include /* O_RDONLY */ #include /* stat() */ #include /* winsize */ #include #include /* KDGETMODE */ #include #include #endif #include "newt.h" #include "newt_pr.h" #ifdef USE_GPM /*....................................... The connection data structure */ typedef struct Gpm_Connect { unsigned short eventMask, defaultMask; unsigned short minMod, maxMod; int pid; int vc; } Gpm_Connect; /*....................................... Stack struct */ typedef struct Gpm_Stst { Gpm_Connect info; struct Gpm_Stst *next; } Gpm_Stst; enum Gpm_Etype { GPM_MOVE=1, GPM_DRAG=2, /* exactly one of the bare ones is active at a time */ GPM_DOWN=4, GPM_UP= 8, #define GPM_BARE_EVENTS(type) ((type)&(0x0f|GPM_ENTER|GPM_LEAVE)) GPM_SINGLE=16, /* at most one in three is set */ GPM_DOUBLE=32, GPM_TRIPLE=64, /* WARNING: I depend on the values */ GPM_MFLAG=128, /* motion during click? */ GPM_HARD=256, /* if set in the defaultMask, force an already used event to pass over to another handler */ GPM_ENTER=512, /* enter event, user in Roi's */ GPM_LEAVE=1024 /* leave event, used in Roi's */ }; /*....................................... The reported event */ enum Gpm_Margin {GPM_TOP=1, GPM_BOT=2, GPM_LFT=4, GPM_RGT=8}; typedef struct Gpm_Event { unsigned char buttons, modifiers; /* try to be a multiple of 4 */ unsigned short vc; short dx, dy, x, y; enum Gpm_Etype type; int clicks; enum Gpm_Margin margin; } Gpm_Event; static int Gpm_Open(Gpm_Connect *conn, int flag); static int Gpm_Close(void); 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; #define GPM_XTERM_ON #define GPM_XTERM_OFF #define GPM_NODE_DEV "/dev/gpmctl" #define GPM_NODE_CTL GPM_NODE_DEV static inline int putdata(int where, Gpm_Connect *what) { if (write(where,what,sizeof(Gpm_Connect))!=sizeof(Gpm_Connect)) { return -1; } return 0; } static void gpm_winch_hook (int signum) { if (SIG_IGN != gpm_saved_winch_hook.sa_handler && SIG_DFL != gpm_saved_winch_hook.sa_handler) { gpm_saved_winch_hook.sa_handler(signum); } /*if*/ } static void gpm_suspend_hook (int signum) { Gpm_Connect gpm_connect; sigset_t old_sigset; sigset_t new_sigset; struct sigaction sa; int success; sigemptyset (&new_sigset); sigaddset (&new_sigset, SIGTSTP); sigprocmask (SIG_BLOCK, &new_sigset, &old_sigset); /* Open a completely transparent gpm connection */ gpm_connect.eventMask = 0; gpm_connect.defaultMask = ~0; gpm_connect.minMod = ~0; gpm_connect.maxMod = 0; /* cannot do this under xterm, tough */ success = (Gpm_Open (&gpm_connect, 0) >= 0); /* take the default action, whatever it is (probably a stop :) */ sigprocmask (SIG_SETMASK, &old_sigset, 0); sigaction (SIGTSTP, &gpm_saved_suspend_hook, 0); kill (getpid (), SIGTSTP); /* in bardo here */ /* Reincarnation. Prepare for another death early. */ sigemptyset(&sa.sa_mask); sa.sa_handler = gpm_suspend_hook; sa.sa_flags = SA_NOMASK; sigaction (SIGTSTP, &sa, 0); /* Pop the gpm stack by closing the useless connection */ /* but do it only when we know we opened one.. */ if (success) { Gpm_Close (); } /*if*/ } static int Gpm_Open(Gpm_Connect *conn, int flag) { char tty[32]; char *term; int i; struct sockaddr_un addr; Gpm_Stst *new; /*....................................... First of all, check xterm */ if ((term=(char *)getenv("TERM")) && !strncmp(term,"xterm",5)) { if (gpm_tried) return gpm_fd; /* no stack */ gpm_fd=-2; GPM_XTERM_ON; gpm_flag=1; return gpm_fd; } /*....................................... No xterm, go on */ /* * So I chose to use the current tty, instead of /dev/console, which * has permission problems. (I am fool, and my console is * readable/writeable by everybody. * * However, making this piece of code work has been a real hassle. */ if (!gpm_flag && gpm_tried) return -1; gpm_tried=1; /* do or die */ new=malloc(sizeof(Gpm_Stst)); if (!new) return -1; new->next=gpm_stack; gpm_stack=new; conn->pid=getpid(); /* fill obvious values */ if (new->next) conn->vc=new->next->info.vc; /* inherit */ else { conn->vc=0; /* default handler */ if (flag>0) { /* forced vc number */ conn->vc=flag; sprintf(tty,"/dev/tty%i",flag); } else if (flag==0) /* use your current vc */ { char *t = ttyname(0); /* stdin */ if (!t) t = ttyname(1); /* stdout */ if (!t) goto err; strcpy(tty,t); if (strncmp(tty,"/dev/tty",8) || !isdigit(tty[8])) goto err; conn->vc=atoi(tty+8); } else /* a default handler -- use console */ sprintf(tty,"/dev/tty0"); } new->info=*conn; /*....................................... Connect to the control socket */ if (!(gpm_flag++)) { if ( (gpm_fd=socket(AF_UNIX,SOCK_STREAM,0))<0 ) { goto err; } bzero((char *)&addr,sizeof(addr)); addr.sun_family=AF_UNIX; if (!(gpm_sock_name = tempnam (0, "gpm"))) { goto err; } /*if*/ 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; } /*if*/ bzero((char *)&addr,sizeof(addr)); addr.sun_family=AF_UNIX; strcpy(addr.sun_path, GPM_NODE_CTL); i=sizeof(addr.sun_family)+strlen(GPM_NODE_CTL); if ( connect(gpm_fd,(struct sockaddr *)(&addr),i)<0 ) { struct stat stbuf; /* * Well, try to open a chr device called /dev/gpmctl. This should * be forward-compatible with a kernel server */ close(gpm_fd); /* the socket */ if ((gpm_fd=open(GPM_NODE_DEV,O_RDWR))==-1) { goto err; } /*if*/ if (fstat(gpm_fd,&stbuf)==-1 || (stbuf.st_mode&S_IFMT)!=S_IFCHR) goto err; } } /*....................................... Put your data */ if (putdata(gpm_fd,conn)!=-1) { /* itz Wed Dec 16 23:22:16 PST 1998 use sigaction, the old code caused a signal loop under XEmacs */ struct sigaction sa; sigemptyset(&sa.sa_mask); #if (defined(SIGWINCH)) /* And the winch hook .. */ sa.sa_handler = gpm_winch_hook; sa.sa_flags = 0; sigaction(SIGWINCH, &sa, &gpm_saved_winch_hook); #endif #if (defined(SIGTSTP)) if (gpm_flag == 1) { /* Install suspend hook */ sa.sa_handler = SIG_IGN; sigaction(SIGTSTP, &sa, &gpm_saved_suspend_hook); /* if signal was originally ignored, job control is not supported */ if (gpm_saved_suspend_hook.sa_handler != SIG_IGN) { sa.sa_flags = SA_NOMASK; sa.sa_handler = gpm_suspend_hook; sigaction(SIGTSTP, &sa, 0); } /*if*/ } /*if*/ #endif } /*if*/ return gpm_fd; /*....................................... Error: free all memory */ err: do { new=gpm_stack->next; free(gpm_stack); gpm_stack=new; } while(gpm_stack); if (gpm_fd>=0) close(gpm_fd); 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; } /*-------------------------------------------------------------------*/ static int Gpm_Close(void) { Gpm_Stst *next; gpm_tried=0; /* reset the error flag for next time */ if (gpm_fd==-2) /* xterm */ GPM_XTERM_OFF; else /* linux */ { if (!gpm_flag) return 0; next=gpm_stack->next; free(gpm_stack); gpm_stack=next; if (next) putdata(gpm_fd,&(next->info)); if (--gpm_flag) return -1; } 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 #ifdef SIGWINCH sigaction(SIGWINCH, &gpm_saved_winch_hook, 0); #endif return 0; } /*-------------------------------------------------------------------*/ static int Gpm_GetEvent(Gpm_Event *event) { int count; if (!gpm_flag) return 0; if ((count=read(gpm_fd,event,sizeof(Gpm_Event)))!=sizeof(Gpm_Event)) { if (count==0) { Gpm_Close(); return 0; } return -1; } return 1; } #endif /**************************************************************************** These forms handle vertical scrolling of components with a height of 1 Horizontal scrolling won't work, and scrolling large widgets will fail miserably. It shouldn't be too hard to fix either of those if anyone cares to. I only use scrolling for listboxes and text boxes though so I didn't bother. *****************************************************************************/ struct element { newtComponent co; }; struct fdInfo { int fd; int flags; }; struct form { int numCompsAlloced; struct element * elements; int numComps; int currComp; int fixedHeight; int flags; int vertOffset; newtComponent vertBar, exitComp; const char * help; int numRows; int * hotKeys; int numHotKeys; int background; int numFds; struct fdInfo * fds; int maxFd; int timer; /* in milliseconds */ struct timeval lastTimeout; void * helpTag; newtCallback helpCb; }; 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); /* Global, ick */ static newtCallback helpCallback; /* this isn't static as grid.c tests against it to find forms */ struct componentOps formOps = { newtDrawForm, formEvent, newtFormDestroy, formPlace, 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 > el->co->top) return 0; if (co->top + co->height < el->co->top + el->co->height) return 0; return 1; } newtComponent newtForm(newtComponent vertBar, void * help, int flags) { newtComponent co; struct form * form; co = malloc(sizeof(*co)); form = malloc(sizeof(*form)); co->data = form; co->width = 0; co->height = 0; co->top = -1; co->left = -1; co->isMapped = 0; co->takesFocus = 0; /* we may have 0 components */ co->ops = &formOps; co->callback = NULL; co->destroyCallback = NULL; form->help = help; form->flags = flags; form->numCompsAlloced = 5; form->numComps = 0; form->currComp = -1; form->vertOffset = 0; form->fixedHeight = 0; form->numRows = 0; form->numFds = 0; form->maxFd = 0; form->fds = NULL; form->elements = malloc(sizeof(*(form->elements)) * form->numCompsAlloced); form->background = COLORSET_WINDOW; form->hotKeys = malloc(sizeof(int)); form->numHotKeys = 0; form->timer = 0; form->lastTimeout.tv_sec = form->lastTimeout.tv_usec = 0; if (!(form->flags & NEWT_FLAG_NOF12)) { newtFormAddHotKey(co, NEWT_KEY_F12); } if (vertBar) form->vertBar = vertBar; else form->vertBar = NULL; form->helpTag = help; form->helpCb = helpCallback; return co; } 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; for (i = 0; i < form->numComps; i++) { if (form->elements[i].co == subco) break; } if (form->elements[i].co != subco) return; new = i; if (co->isMapped && !componentFits(co, new)) { gotoComponent(co, -1); formScroll(co, form->elements[new].co->top - co->top - 1); } gotoComponent(co, new); } void newtFormSetTimer(newtComponent co, int millisecs) { struct form * form = co->data; form->timer = millisecs; form->lastTimeout.tv_usec = 0; form->lastTimeout.tv_sec = 0; } void newtFormSetHeight(newtComponent co, int height) { struct form * form = co->data; form->fixedHeight = 1; co->height = height; } void newtFormSetWidth(newtComponent co, int width) { co->width = width; } void newtFormAddComponent(newtComponent co, newtComponent newco) { struct form * form = co->data; co->takesFocus = 1; if (form->numCompsAlloced == form->numComps) { form->numCompsAlloced += 5; form->elements = realloc(form->elements, sizeof(*(form->elements)) * form->numCompsAlloced); } form->elements[form->numComps].co = newco; if (newco->takesFocus && form->currComp == -1) form->currComp = form->numComps; form->numComps++; } void newtFormAddComponents(newtComponent co, ...) { va_list ap; newtComponent subco; va_start(ap, co); while ((subco = va_arg(ap, newtComponent))) newtFormAddComponent(co, subco); va_end(ap); } static void formPlace(newtComponent co, int left, int top) { struct form * form = co->data; int vertDelta, horizDelta; struct element * el; int i; 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->ops->place(el->co, el->co->left + horizDelta, el->co->top + vertDelta); } } void newtDrawForm(newtComponent co) { struct form * form = co->data; struct element * el; int i; newtFormSetSize(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++) { /* 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 { el->co->ops->mapped(el->co, 0); } } if (form->vertBar) newtScrollbarSet(form->vertBar, form->vertOffset, form->numRows - co->height); } static struct eventResult formEvent(newtComponent co, struct event ev) { struct form * form = co->data; newtComponent subco = form->elements[form->currComp].co; int new, wrap = 0; struct eventResult er; int dir = 0, page = 0; int i, num, found; struct element * el; er.result = ER_IGNORED; if (!form->numComps) return er; if (form->currComp == -1) return er; switch (ev.when) { case EV_EARLY: if (ev.event == EV_KEYPRESS) { if (ev.u.key == NEWT_KEY_TAB) { er.result = ER_SWALLOWED; dir = 1; wrap = 1; } else if (ev.u.key == NEWT_KEY_UNTAB) { er.result = ER_SWALLOWED; dir = -1; wrap = 1; } } if (form->numComps) { i = form->currComp; num = 0; while (er.result == ER_IGNORED && num != form->numComps ) { er = form->elements[i].co->ops->event(form->elements[i].co, ev); num++; i++; if (i == form->numComps) i = 0; } } break; case EV_NORMAL: if (ev.event == EV_MOUSE) { found = 0; for (i = 0, el = form->elements; i < form->numComps; i++, el++) { if ((el->co->top <= ev.u.mouse.y) && (el->co->top + el->co->height > ev.u.mouse.y) && (el->co->left <= ev.u.mouse.x) && (el->co->left + el->co->width > ev.u.mouse.x)) { found = 1; if (el->co->takesFocus) { gotoComponent(co, i); subco = form->elements[form->currComp].co; } } /* If we did not find a co to send this event to, we should just swallow the event here. */ } if (!found) { er.result = ER_SWALLOWED; return er; } } er = subco->ops->event(subco, ev); switch (er.result) { case ER_NEXTCOMP: er.result = ER_SWALLOWED; dir = 1; break; case ER_EXITFORM: form->exitComp = subco; break; default: break; } break; case EV_LATE: er = subco->ops->event(subco, ev); if (er.result == ER_IGNORED) { switch (ev.u.key) { case NEWT_KEY_UP: case NEWT_KEY_LEFT: case NEWT_KEY_BKSPC: er.result = ER_SWALLOWED; dir = -1; break; case NEWT_KEY_DOWN: case NEWT_KEY_RIGHT: er.result = ER_SWALLOWED; dir = 1; break; case NEWT_KEY_PGUP: er.result = ER_SWALLOWED; dir = -1; page = 1; break; case NEWT_KEY_PGDN: er.result = ER_SWALLOWED; dir = 1; page = 1; break; } } } if (dir) { new = form->currComp; if (page) { new += dir * co->height; if (new < 0) new = 0; else if (new >= form->numComps) new = (form->numComps - 1); while (!form->elements[new].co->takesFocus && new - dir >= 0 && new - dir < form->numComps) new -= dir; } else { do { new += dir; if (wrap) { if (new < 0) 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); } /* make sure this component is visible */ if (!componentFits(co, new)) { int vertDelta; gotoComponent(co, -1); if (dir < 0) { /* make the new component the first one */ vertDelta = form->elements[new].co->top - co->top; } else { /* make the new component the last one */ vertDelta = (form->elements[new].co->top + form->elements[new].co->height) - (co->top + co->height); } formScroll(co, vertDelta); newtDrawForm(co); } 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; struct form * form = co->data; int i; /* first, destroy all of the components */ for (i = 0; i < form->numComps; i++) { subco = form->elements[i].co; newtComponentDestroy(subco); } if (form->hotKeys) free(form->hotKeys); free(form->elements); free(form); free(co); } newtComponent newtRunForm(newtComponent co) { struct newtExitStruct es; newtFormRun(co, &es); if (es.reason == NEWT_EXIT_HOTKEY) { if (es.u.key == NEWT_KEY_F12) { es.reason = NEWT_EXIT_COMPONENT; es.u.co = co; } else { return NULL; } } else if (es.reason == NEWT_EXIT_ERROR) return NULL; return es.u.co; } void newtFormAddHotKey(newtComponent co, int key) { struct form * form = co->data; form->numHotKeys++; form->hotKeys = realloc(form->hotKeys, sizeof(int) * form->numHotKeys); form->hotKeys[form->numHotKeys - 1] = key; } void newtFormSetSize(newtComponent co) { struct form * form = co->data; int delta, i, first; struct element * el; form->numRows = 0; co->width = 0; if (!form->fixedHeight) co->height = 0; 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; 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; co->left -= delta; co->width += delta; } if (co->top > el->co->top) { delta = co->top - el->co->top; co->top -= delta; form->numRows += delta; if (!form->fixedHeight) co->height += delta; } if ((co->left + co->width) < (el->co->left + el->co->width)) co->width = (el->co->left + el->co->width) - co->left; if (!form->fixedHeight) { if ((co->top + co->height) < (el->co->top + el->co->height)) co->height = (el->co->top + el->co->height) - co->top; } if ((el->co->top + el->co->height - co->top) > form->numRows) { form->numRows = el->co->top + el->co->height - co->top; } } co->top += form->vertOffset; } void newtFormRun(newtComponent co, struct newtExitStruct * es) { struct form * form = co->data; struct event ev; struct eventResult er; int key, i, max; int done = 0; fd_set readSet, writeSet, exceptSet; struct timeval nextTimeout, now, timeout; #ifdef USE_GPM int x, y; Gpm_Connect conn; Gpm_Event event; /* Set up GPM interface */ conn.eventMask = ~GPM_MOVE; conn.defaultMask = GPM_MOVE; conn.minMod = 0; conn.maxMod = 0; Gpm_Open(&conn, 0); #endif /* draw all of the components */ newtDrawForm(co); if (form->currComp == -1) { if (form->numComps) gotoComponent(co, 0); } else 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) { FD_SET(gpm_fd, &readSet); } max = form->maxFd > gpm_fd ? form->maxFd : gpm_fd; #else max = form->maxFd; #endif for (i = 0; i < form->numFds; i++) { if (form->fds[i].flags & NEWT_FD_READ) 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. */ 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; if (now.tv_sec > nextTimeout.tv_sec) { timeout.tv_sec = timeout.tv_usec = 0; } else if (now.tv_sec == nextTimeout.tv_sec) { timeout.tv_sec = 0; if (now.tv_usec > nextTimeout.tv_usec) timeout.tv_usec = 0; else timeout.tv_usec = nextTimeout.tv_usec - now.tv_usec; } else if (now.tv_sec < nextTimeout.tv_sec) { timeout.tv_sec = nextTimeout.tv_sec - now.tv_sec; if (now.tv_usec > nextTimeout.tv_usec) timeout.tv_sec--, timeout.tv_usec = nextTimeout.tv_usec + 1000000 - now.tv_usec; else timeout.tv_usec = nextTimeout.tv_usec - now.tv_usec; } } else { timeout.tv_sec = timeout.tv_usec = 0; } 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? */ if (i == 0) { done = 1; es->reason = NEWT_EXIT_TIMER; gettimeofday(&form->lastTimeout, NULL); } else #ifdef USE_GPM if (gpm_fd > 0 && FD_ISSET(gpm_fd, &readSet)) { Gpm_GetEvent(&event); if (event.type & GPM_DOWN) { /* Transform coordinates to current window */ newtGetWindowPos(&x, &y); ev.event = EV_MOUSE; ev.u.mouse.type = MOUSE_BUTTON_DOWN; ev.u.mouse.x = event.x - x - 1; ev.u.mouse.y = event.y - y - 1; /* Send the form the event */ er = sendEvent(co, ev); if (er.result == ER_EXITFORM) { done = 1; es->reason = NEWT_EXIT_COMPONENT; es->u.co = form->exitComp; } } } else #endif { if (FD_ISSET(0, &readSet)) { key = newtGetKey(); for (i = 0; i < form->numHotKeys; i++) { if (form->hotKeys[i] == key) { es->reason = NEWT_EXIT_HOTKEY; es->u.key = key; done = 1; break; } } 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; ev.u.key = key; er = sendEvent(co, ev); if (er.result == ER_EXITFORM) { done = 1; es->reason = NEWT_EXIT_COMPONENT; es->u.co = form->exitComp; } } } 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; } } } newtRefresh(); #ifdef USE_GPM Gpm_Close(); #endif } static struct eventResult sendEvent(newtComponent co, struct event ev) { struct eventResult er; ev.when = EV_EARLY; er = co->ops->event(co, ev); if (er.result == ER_IGNORED) { ev.when = EV_NORMAL; er = co->ops->event(co, ev); } if (er.result == ER_IGNORED) { ev.when = EV_LATE; er = co->ops->event(co, ev); } return er; } static void gotoComponent(newtComponent co, int newComp) { struct form * form = co->data; struct event ev; if (form->currComp != -1) { ev.event = EV_UNFOCUS; sendEvent(form->elements[form->currComp].co, ev); } form->currComp = newComp; if (form->currComp != -1) { ev.event = EV_FOCUS; 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) { co->callback = f; 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; } void newtFormSetBackground(newtComponent co, int color) { struct form * form = co->data; form->background = 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[i].fd = fd; form->fds[i].flags = fdFlags; if (form->maxFd < fd) form->maxFd = fd; } void newtSetHelpCallback(newtCallback cb) { helpCallback = cb; }