summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSadrul Habib Chowdhury <sadrul@users.sourceforge.net>2010-02-21 01:14:06 -0500
committerSadrul Habib Chowdhury <sadrul@users.sourceforge.net>2010-02-21 01:14:06 -0500
commite29d6de0f8f4c40806e9b3300ed3609aaefc104b (patch)
tree749e8fd1e0ff57d00cfd81a5f0bf06d2c137f61e
parentbd6946ebc341b0059b3f5cda51787329fa51b536 (diff)
downloadscreen-e29d6de0f8f4c40806e9b3300ed3609aaefc104b.tar.gz
Start working on a generic list framework.
The list of displays uses this framework. Eventually, the list of windows, bindkeys etc. will also use this framework. In the list of displays, you can press 'd' to detach the selected display (and 'D' to power-detach). Eventually, the plan is to add typeahead search in the list too.
-rw-r--r--src/Makefile.in8
-rw-r--r--src/help.c4
-rw-r--r--src/list_display.c363
-rw-r--r--src/list_generic.c266
-rw-r--r--src/list_generic.h63
5 files changed, 492 insertions, 212 deletions
diff --git a/src/Makefile.in b/src/Makefile.in
index 8120726..0706290 100644
--- a/src/Makefile.in
+++ b/src/Makefile.in
@@ -62,11 +62,12 @@ CFILES= screen.c ansi.c fileio.c mark.c misc.c resize.c socket.c \
termcap.c input.c attacher.c pty.c process.c display.c comm.c \
kmapdef.c acls.c braille.c braille_tsi.c logfile.c layer.c \
sched.c teln.c nethack.c encoding.c canvas.c layout.c viewport.c \
- list_display.c
+ list_display.c list_generic.c
OFILES= screen.o ansi.o fileio.o mark.o misc.o resize.o socket.o \
search.o tty.o term.o window.o utmp.o loadav.o putenv.o help.o \
termcap.o input.o attacher.o pty.o process.o display.o comm.o \
kmapdef.o acls.o braille.o braille_tsi.o logfile.o layer.o \
+ list_generic.o list_display.o \
sched.o teln.o nethack.o encoding.o canvas.o layout.o viewport.o
all: screen
@@ -303,7 +304,7 @@ loadav.o: layout.h viewport.h canvas.h loadav.c config.h screen.h os.h osdef.h a
comm.h layer.h term.h image.h display.h window.h extern.h
putenv.o: layout.h viewport.h canvas.h putenv.c config.h
help.o: layout.h viewport.h canvas.h help.c config.h screen.h os.h osdef.h ansi.h acls.h \
- comm.h layer.h term.h image.h display.h window.h extern.h list_display.c
+ comm.h layer.h term.h image.h display.h window.h extern.h list_display.c list_generic.h
termcap.o: layout.h viewport.h canvas.h termcap.c config.h screen.h os.h osdef.h ansi.h acls.h \
comm.h layer.h term.h image.h display.h window.h extern.h
input.o: layout.h viewport.h canvas.h input.c config.h screen.h os.h osdef.h ansi.h acls.h \
@@ -346,3 +347,6 @@ layout.o: layout.h viewport.h canvas.h layout.c config.h screen.h os.h osdef.h a
viewport.o: layout.h viewport.h canvas.h viewport.c config.h screen.h os.h osdef.h ansi.h acls.h \
comm.h layer.h term.h image.h display.h window.h extern.h \
braille.h
+list_generic.o: list_generic.h list_generic.c layer.h
+list_display.o: list_generic.h list_display.c layer.h
+
diff --git a/src/help.c b/src/help.c
index e98f50c..1e37354 100644
--- a/src/help.c
+++ b/src/help.c
@@ -33,6 +33,8 @@
#include "screen.h"
#include "extern.h"
+#include "list_generic.h"
+
char version[60]; /* initialised by main() */
extern struct layer *flayer;
@@ -681,8 +683,6 @@ int y, xs, xe, isblank;
}
-#include "list_display.c"
-
/*
**
** here is the windowlist
diff --git a/src/list_display.c b/src/list_display.c
index 3693f01..28ec7bb 100644
--- a/src/list_display.c
+++ b/src/list_display.c
@@ -1,4 +1,7 @@
-/* Copyright (c) 2008, 2009
+/* Copyright (c) 2010
+ * Juergen Weigert (jnweiger@immd4.informatik.uni-erlangen.de)
+ * Sadrul Habib Chowdhury (sadrul@users.sourceforge.net)
+ * Copyright (c) 2008, 2009
* Juergen Weigert (jnweiger@immd4.informatik.uni-erlangen.de)
* Michael Schroeder (mlschroe@immd4.informatik.uni-erlangen.de)
* Micah Cowan (micah@cowan.name)
@@ -28,150 +31,16 @@
/* Deals with the list of displays */
-#ifdef MULTI
-
-struct displaysdata
-{
- struct display *selected; /* The selected display */
- struct display *current; /* The current display (that's showing this list) */
-};
-
-static void DisplaysProcess __P((char **, int *));
-static void DisplaysRedisplayLine __P((int, int, int, int));
-static void displayspage __P((struct displaysdata *));
-
-static struct LayFuncs DisplaysLf =
-{
- DisplaysProcess,
- HelpAbort,
- DisplaysRedisplayLine,
- DefClearLine,
- DefRewrite,
- DefResize,
- DefRestore
-};
+#include "config.h"
-void
-display_displays()
-{
- struct displaysdata *ddata;
- if (flayer->l_width < 10 || flayer->l_height < 5)
- {
- LMsg(0, "Window size too small for displays page");
- return;
- }
- if (InitOverlayPage(sizeof(struct displaysdata), &DisplaysLf, 0))
- return;
- flayer->l_mode = 1;
- flayer->l_x = 0;
- flayer->l_y = flayer->l_height - 1;
- ddata = flayer->l_data;
- ddata->current = display;
- ddata->selected = display;
- displayspage(ddata);
-}
+#include "screen.h"
+#include "list_generic.h"
-static void
-display_list_change(struct displaysdata *ddata, int dir)
-{
- struct display *d;
- for (d = displays; d; d = d->d_next)
- {
- if (dir == -1 && d->d_next == ddata->selected)
- {
- ddata->selected = d;
- break;
- }
- else if (dir == 1 && d == ddata->selected && d->d_next)
- {
- ddata->selected = d->d_next;
- break;
- }
- }
-
- if (d)
- {
- /* Selection changed */
- displayspage(ddata);
- }
-}
-
-static void
-DisplaysProcess(ppbuf, plen)
-char **ppbuf;
-int *plen;
-{
- int done = 0;
-
- ASSERT(flayer);
- while (!done && *plen > 0)
- {
- unsigned char ch = (unsigned char)**ppbuf;
- ++*ppbuf;
- --*plen;
- if (flayer->l_mouseevent.start)
- {
- int r = LayProcessMouse(flayer, ch);
- if (r == -1)
- LayProcessMouseSwitch(flayer, 0);
- else
- {
- if (r)
- ch = 0222;
- else
- continue;
- }
- }
- switch (ch)
- {
- case ' ':
- displayspage(flayer->l_data);
- break;
- case '\r':
- case '\n':
- HelpAbort();
- done = 1;
- break;
-
- case 0220: /* up */
- case 16: /* ^P like emacs */
- case 'k':
- display_list_change(flayer->l_data, -1);
- break;
-
- case 0216: /* down */
- case 14: /* ^N like emacs */
- case 'j':
- display_list_change(flayer->l_data, 1);
- break;
-
- case 0222: /* mouse event */
- if (flayer->l_mouseevent.start)
- {
- /* All the data is available to process the mouse event. */
- int button = flayer->l_mouseevent.buffer[0];
- if (button == 'a')
- {
- /* Scroll down */
- display_list_change(flayer->l_data, 1);
- }
- else if (button == '`')
- {
- /* Scroll up */
- display_list_change(flayer->l_data, -1);
- }
- LayProcessMouseSwitch(flayer, 0);
- }
- else
- LayProcessMouseSwitch(flayer, 1);
- break;
-
- default:
- break;
- }
- }
-}
+#ifdef MULTI
+extern struct layer *flayer;
+extern struct display *display, *displays;
+extern struct mchar mchar_blank, mchar_so;
/*
* layout of the displays page is as follows:
@@ -180,7 +49,7 @@ xterm 80x42 jnweiger@/dev/ttyp4 0(m11) &rWx
facit 80x24 nb mlschroe@/dev/ttyhf 11(tcsh) rwx
xterm 80x42 jnhollma@/dev/ttyp5 0(m11) &R.x
- | | | | | | | | ¦___ window permissions
+ | | | | | | | | ¦___ window permissions
| | | | | | | | (R. is locked r-only,
| | | | | | | | W has wlock)
| | | | | | | |___ Window is shared
@@ -191,97 +60,175 @@ xterm 80x42 jnhollma@/dev/ttyp5 0(m11) &R.x
| | |___ Display is in nonblocking mode. Shows 'NB' if obuf is full.
| |___ Displays geometry as width x height.
|___ the terminal type known by screen for this display.
-
+
*/
-static void
-displayspage(ddata)
-struct displaysdata *ddata;
+static int
+gl_Display_header(struct ListData *ldata)
{
- int y, l;
+ leftline("term-type size user interface window Perms", 0, 0);
+ leftline("---------- ------- ---------- ----------------- ---------- -----", 1, 0);
+ return 2;
+}
+
+static int
+gl_Display_footer(struct ListData *ldata)
+{
+ centerline("[Press Space to refresh; Return to end.]", flayer->l_height - 1);
+}
+
+static int
+gl_Display_row(struct ListData *ldata, struct ListRow *lrow)
+{
+ struct display *d = lrow->data;
char tbuf[80];
- struct display *d;
- struct win *w;
static char *blockstates[5] = {"nb", "NB", "Z<", "Z>", "BL"};
+ struct win *w = d->d_fore;
struct mchar m_current = mchar_blank;
m_current.attr = A_BD;
- if (!ddata)
- return;
+ sprintf(tbuf, " %-10.10s%4dx%-4d%10.10s@%-16.16s%s",
+ d->d_termname, d->d_width, d->d_height, d->d_user->u_name,
+ d->d_usertty,
+ (d->d_blocked || d->d_nonblock >= 0) && d->d_blocked <= 4 ? blockstates[d->d_blocked] : " ");
- LClearAll(flayer, 0);
+ if (w)
+ {
+ int l = 10 - strlen(w->w_title);
+ if (l < 0)
+ l = 0;
+ sprintf(tbuf + strlen(tbuf), "%3d(%.10s)%*s%c%c%c%c",
+ w->w_number, w->w_title, l, "",
+ /* w->w_dlist->next */ 0 ? '&' : ' ',
+ /*
+ * The rwx triple:
+ * -,r,R no read, read, read only due to foreign wlock
+ * -,.,w,W no write, write suppressed by foreign wlock,
+ * write, own wlock
+ * -,x no execute, execute
+ */
+#ifdef MULTIUSER
+ (AclCheckPermWin(d->d_user, ACL_READ, w) ? '-' :
+ ((w->w_wlock == WLOCK_OFF || d->d_user == w->w_wlockuser) ?
+ 'r' : 'R')),
+ (AclCheckPermWin(d->d_user, ACL_READ, w) ? '-' :
+ ((w->w_wlock == WLOCK_OFF) ? 'w' :
+ ((d->d_user == w->w_wlockuser) ? 'W' : 'v'))),
+ (AclCheckPermWin(d->d_user, ACL_READ, w) ? '-' : 'x')
+#else
+ 'r', 'w', 'x'
+#endif
+ );
+ }
+ leftline(tbuf, lrow->y, lrow == ldata->selected ? &mchar_so : d == display ? &m_current : 0);
- leftline("term-type size user interface window Perms", 0, 0);
- leftline("---------- ------- ---------- ----------------- ---------- -----", 1, 0);
- y = 2;
+ return 1;
+}
+static void
+gl_Display_rebuild(struct ListData *ldata)
+{
+ /* recreate the rows */
+ struct display *d;
+ struct ListRow *row = NULL;
for (d = displays; d; d = d->d_next)
{
- struct mchar *mc;
- w = d->d_fore;
+ row = glist_add_row(ldata, d, row);
+ if (d == display)
+ ldata->selected = row;
+ }
- if (y >= flayer->l_height - 3)
- break;
- sprintf(tbuf, " %-10.10s%4dx%-4d%10.10s@%-16.16s%s",
- d->d_termname, d->d_width, d->d_height, d->d_user->u_name,
- d->d_usertty,
- (d->d_blocked || d->d_nonblock >= 0) && d->d_blocked <= 4 ? blockstates[d->d_blocked] : " ");
+ glist_display_all(ldata);
+}
- if (w)
- {
- l = 10 - strlen(w->w_title);
- if (l < 0)
- l = 0;
- sprintf(tbuf + strlen(tbuf), "%3d(%.10s)%*s%c%c%c%c",
- w->w_number, w->w_title, l, "",
- /* w->w_dlist->next */ 0 ? '&' : ' ',
- /*
- * The rwx triple:
- * -,r,R no read, read, read only due to foreign wlock
- * -,.,w,W no write, write suppressed by foreign wlock,
- * write, own wlock
- * -,x no execute, execute
- */
-#ifdef MULTIUSER
- (AclCheckPermWin(d->d_user, ACL_READ, w) ? '-' :
- ((w->w_wlock == WLOCK_OFF || d->d_user == w->w_wlockuser) ?
- 'r' : 'R')),
- (AclCheckPermWin(d->d_user, ACL_READ, w) ? '-' :
- ((w->w_wlock == WLOCK_OFF) ? 'w' :
- ((d->d_user == w->w_wlockuser) ? 'W' : 'v'))),
- (AclCheckPermWin(d->d_user, ACL_READ, w) ? '-' : 'x')
+static int
+gl_Display_input(struct ListData *ldata, char **inp, int *len)
+{
+ struct display *cd = display;
+ unsigned char ch = (unsigned char) **inp;
+
+ ++*inp;
+ --*len;
+
+ switch (ch)
+ {
+ case ' ': /* Space to refresh */
+ glist_remove_rows(ldata);
+ gl_Display_rebuild(ldata);
+ break;
+
+ case '\r':
+ case '\n':
+ glist_abort();
+ *len = 0;
+ break;
+
+ case 'd': /* Detach */
+ case 'D': /* Power detach */
+ display = ldata->selected->data;
+ if (display == cd) /* We do not allow detaching the current display */
+ break;
+ Detach(
+#ifdef POW_DETACH
+ ch == 'D' ? D_REMOTE_POWER : D_REMOTE
#else
- 'r', 'w', 'x'
+ D_REMOTE
#endif
);
- }
- leftline(tbuf, y, d == ddata->selected ? &mchar_so : d == ddata->current ? &m_current : 0);
- if (d == ddata->selected)
- flayer->l_y = y;
- y++;
+ display = cd;
+ glist_remove_rows(ldata);
+ gl_Display_rebuild(ldata);
+ break;
+
+ break;
+
+ default:
+ /* We didn't actually process the input. */
+ --*inp;
+ ++*len;
+ return 0;
}
- sprintf(tbuf,"[Press Space %s Return to end.]",
- 1 ? "to refresh;" : "or");
- centerline(tbuf, flayer->l_height - 2);
- LaySetCursor();
+ return 1;
}
-static void
-DisplaysRedisplayLine(y, xs, xe, isblank)
-int y, xs, xe, isblank;
+static int
+gl_Display_freerow(struct ListData *ldata, struct ListRow *row)
{
- ASSERT(flayer);
- if (y < 0)
+ /* There was no allocation when row->data was set. So nothing to do here. */
+}
+
+static struct GenericList gl_Display =
+{
+ gl_Display_header,
+ gl_Display_footer,
+ gl_Display_row,
+ gl_Display_input,
+ gl_Display_freerow
+};
+
+void
+display_displays()
+{
+ struct display *d;
+ struct ListRow *row = NULL;
+ struct ListData *ldata;
+ if (flayer->l_width < 10 || flayer->l_height < 5)
{
- displayspage(flayer->l_data);
+ LMsg(0, "Window size too small for displays page");
return;
}
- if (y != 0 && y != flayer->l_height - 1)
- return;
- if (isblank)
+
+ ldata = glist_display(&gl_Display);
+ if (!ldata)
return;
- LClearArea(flayer, xs, y, xe, y, 0, 0);
- /* To be filled in... */
+
+ for (d = displays; d; d = d->d_next)
+ {
+ row = glist_add_row(ldata, d, row);
+ if (d == display)
+ ldata->selected = row;
+ }
+ glist_display_all(ldata);
}
#endif /* MULTI */
diff --git a/src/list_generic.c b/src/list_generic.c
new file mode 100644
index 0000000..112b588
--- /dev/null
+++ b/src/list_generic.c
@@ -0,0 +1,266 @@
+/* Copyright (c) 2010
+ * Juergen Weigert (jnweiger@immd4.informatik.uni-erlangen.de)
+ * Sadrul Habib Chowdhury (sadrul@users.sourceforge.net)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program (see the file COPYING); if not, see
+ * http://www.gnu.org/licenses/, or contact Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
+ *
+ ****************************************************************
+ */
+
+#include "config.h"
+#include "screen.h"
+#include "list_generic.h"
+#include "layer.h"
+
+/* Deals with a generic list display */
+
+extern struct layer *flayer;
+
+static void ListProcess __P((char **, int *));
+static void ListAbort __P((void));
+static void ListRedisplayLine __P((int, int, int, int));
+static void ListClearLine __P((int, int, int, int));
+static int ListRewrite __P((int, int, int, struct mchar *, int));
+static int ListResize __P((int, int));
+static void ListRestore __P((void));
+
+static struct LayFuncs ListLf =
+{
+ ListProcess,
+ ListAbort,
+ ListRedisplayLine,
+ ListClearLine,
+ ListRewrite,
+ ListResize,
+ ListRestore
+};
+
+/** Returns non-zero on success. */
+struct ListData *
+glist_display(struct GenericList *list)
+{
+ struct ListData *ldata;
+
+ if (InitOverlayPage(sizeof(struct ListData), &ListLf, 0))
+ return NULL;
+ ldata = flayer->l_data;
+
+ ldata->list_fn = list;
+
+ flayer->l_mode = 1;
+ flayer->l_x = 0;
+ flayer->l_y = flayer->l_height - 1;
+
+ return ldata;
+}
+
+static void ListProcess(char **ppbuf, int *plen)
+{
+ struct ListData *ldata = flayer->l_data;
+
+ while (*plen > 0)
+ {
+ struct ListRow *old;
+ unsigned char ch;
+
+ if (ldata->list_fn->gl_pinput &&
+ ldata->list_fn->gl_pinput(ldata, ppbuf, plen))
+ continue;
+
+ if (!ldata->selected)
+ *plen = 0;
+
+ ch = **ppbuf;
+ ++*ppbuf;
+ --*plen;
+
+ old = ldata->selected;
+ switch (ch)
+ {
+ case ' ':
+ break;
+
+ case '\r':
+ case '\n':
+ break;
+
+ case 0220: /* up */
+ case 16: /* ^P */
+ case 'k':
+ if (!ldata->selected->prev) /* There's no where to go */
+ break;
+ ldata->selected = old->prev;
+ break;
+
+ case 0216: /* down */
+ case 14: /* ^N like emacs */
+ case 'j':
+ if (!ldata->selected->next) /* Nothing to do */
+ break;
+ old = ldata->selected;
+ ldata->selected = old->next;
+ break;
+
+ case 007:
+ ListAbort();
+ *plen = 0;
+ return;
+ }
+
+ if (old == ldata->selected) /* The selection didn't change */
+ continue;
+
+ if (ldata->selected->y == -1)
+ {
+ /* We need to list all the rows, since we are scrolling down */
+ glist_display_all(ldata);
+ }
+ else
+ {
+ /* just redisplay the two lines. */
+ ldata->list_fn->gl_printrow(ldata, old);
+ ldata->list_fn->gl_printrow(ldata, ldata->selected);
+ }
+ }
+}
+
+static void ListAbort(void)
+{
+ struct ListData *ldata = flayer->l_data;
+ glist_remove_rows(ldata);
+ LAY_CALL_UP(LRefreshAll(flayer, 0));
+ ExitOverlayPage();
+}
+
+static void ListRedisplayLine(int y, int xs, int xe, int isblank)
+{
+ ASSERT(flayer);
+ if (y < 0)
+ {
+ glist_display_all(flayer->l_data);
+ return;
+ }
+ if (y != 0 && y != flayer->l_height - 1)
+ return;
+
+ if (isblank)
+ return;
+ LClearArea(flayer, xs, y, xe, y, 0, 0);
+}
+
+static void ListClearLine(int y, int xs, int xe, int bce)
+{
+ DefClearLine(y, xs, xe, bce);
+}
+
+static int ListRewrite(int y, int xs, int xe, struct mchar *rend, int doit)
+{
+ return EXPENSIVE;
+}
+
+static int ListResize (int wi, int he)
+{
+ if (wi < 10 || he < 5)
+ return -1;
+
+ flayer->l_width = wi;
+ flayer->l_height = he;
+ flayer->l_y = he - 1;
+
+ return 0;
+}
+
+static void ListRestore (void)
+{
+ DefRestore();
+}
+
+struct ListRow *
+glist_add_row(struct ListData *ldata, void *data, struct ListRow *after)
+{
+ struct ListRow *r = calloc(1, sizeof(struct ListRow));
+ r->data = data;
+
+ if (after)
+ {
+ r->next = after->next;
+ r->prev = after;
+ after->next = r;
+ if (r->next)
+ r->next->prev = r;
+ }
+ else
+ {
+ r->next = ldata->root;
+ if (ldata->root)
+ ldata->root->prev = r;
+ ldata->root = r;
+ }
+
+ return r;
+}
+
+void
+glist_remove_rows(struct ListData *ldata)
+{
+ struct ListRow *row;
+ for (row = ldata->root; row; row = row->next)
+ {
+ ldata->list_fn->gl_freerow(ldata, row);
+ free(row);
+ }
+ ldata->root = ldata->selected = ldata->top = NULL;
+}
+
+void
+glist_display_all(struct ListData *list)
+{
+ int y;
+ struct ListRow *row;
+
+ LClearAll(flayer, 0);
+
+ y = list->list_fn->gl_printheader(list);
+
+ if (!list->top)
+ list->top = list->root;
+
+ for (row = list->root; row != list->top; row = row->next)
+ row->y = -1;
+
+ for (row = list->top; row; row = row->next)
+ {
+ row->y = y++;
+ if (!list->list_fn->gl_printrow(list, row))
+ {
+ row->y = -1;
+ y--;
+ }
+ if (y + 1 == flayer->l_height)
+ break;
+ }
+ for (; row; row = row->next)
+ row->y = -1;
+
+ list->list_fn->gl_printfooter(list);
+ LaySetCursor();
+}
+
+void glist_abort(void)
+{
+ ListAbort();
+}
+
diff --git a/src/list_generic.h b/src/list_generic.h
new file mode 100644
index 0000000..0c0e5b0
--- /dev/null
+++ b/src/list_generic.h
@@ -0,0 +1,63 @@
+/* Copyright (c) 2010
+ * Juergen Weigert (jnweiger@immd4.informatik.uni-erlangen.de)
+ * Sadrul Habib Chowdhury (sadrul@users.sourceforge.net)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program (see the file COPYING); if not, see
+ * http://www.gnu.org/licenses/, or contact Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
+ *
+ ****************************************************************
+ */
+
+struct ListData;
+
+struct ListRow
+{
+ void *data; /* Some data relevant to this row */
+ struct ListRow *next, *prev; /* doubly linked list */
+ struct ListRow *parent, *child; /* can also be tree */
+ int y; /* -1 if not on display */
+};
+
+struct GenericList
+{
+ int (*gl_printheader) __P((struct ListData *));
+ int (*gl_printfooter) __P((struct ListData *));
+ int (*gl_printrow) __P((struct ListData *, struct ListRow *));
+ int (*gl_pinput) __P((struct ListData *, char **inp, int *len));
+ int (*gl_freerow) __P((struct ListData *, struct ListRow *));
+};
+
+struct ListData
+{
+ struct ListRow *root; /* The first item in the list */
+ struct ListRow *selected; /* The selected row */
+ struct ListRow *top; /* The topmost visible row */
+
+ struct GenericList *list_fn; /* The functions that deal with the list */
+};
+
+
+struct ListRow * glist_add_row __P((struct ListData *ldata, void *data, struct ListRow *after));
+
+void glist_remove_rows __P((struct ListData *ldata));
+
+void glist_display_all __P((struct ListData *list));
+
+struct ListData * glist_display __P((struct GenericList *list));
+
+void glist_abort __P((void));
+
+void display_displays __P((void));
+