X-Git-Url: https://git.distorted.org.uk/~mdw/xtoys/blobdiff_plain/63351ac66772542ebe1f4b38936f7ed9fd43e9b9..f227ff283ca1c6c6e39eec6790278ab714a918b2:/xcatch.c diff --git a/xcatch.c b/xcatch.c index cf9608b..9a6c636 100644 --- a/xcatch.c +++ b/xcatch.c @@ -1,6 +1,6 @@ /* -*-c-*- * - * $Id: xcatch.c,v 1.1 1998/12/15 23:46:50 mdw Exp $ + * $Id: xcatch.c,v 1.6 1999/05/19 20:41:15 mdw Exp $ * * Catch input and trap it in an X window * @@ -29,6 +29,23 @@ /*----- Revision history --------------------------------------------------* * * $Log: xcatch.c,v $ + * Revision 1.6 1999/05/19 20:41:15 mdw + * Track gratuitous change in mdwopt interface. + * + * Revision 1.5 1999/05/05 18:55:18 mdw + * Block SIGCHLD around the `fork' call to prevent a race. + * + * Revision 1.4 1999/03/24 22:23:57 mdw + * Improve display for large files. Keep newly added material in view if + * scrolled to bottom of window. + * + * Revision 1.3 1998/12/20 17:19:16 mdw + * Return exit status of child process, rather than always returning + * success. + * + * Revision 1.2 1998/12/16 00:10:58 mdw + * Fix tabbing in help text. + * * Revision 1.1 1998/12/15 23:46:50 mdw * New program: captures input and puts it in a window. * @@ -67,8 +84,11 @@ enum { f_bogus = 2 }; -GtkWidget *textbox = 0; -GdkFont *font; +static GtkWidget *textbox = 0; +static GdkFont *font; + +static pid_t kid = -1; +static int status; /*----- Main code ---------------------------------------------------------*/ @@ -87,90 +107,142 @@ static void killwin(GtkWidget *w, gpointer p) static void ready(gpointer data, gint fd, GdkInputCondition c) { char buf[1024]; - int count; + int doscroll = 1; + GtkText *t; + GtkAdjustment *va; - /* --- Read the next buffer of data --- */ + /* --- If not ready to read then go away --- */ if (!(c & GDK_INPUT_READ)) return; - count = read(fd, buf, sizeof(buf)); - /* --- Decide what to do --- */ + /* --- Decide whether to scroll the window --- */ - if (count < 0) { - msg(":~OK", "error reading data: %s", strerror(errno)); - exit(EXIT_FAILURE); + if (textbox) { + t = GTK_TEXT(textbox); + va = t->vadj; + if (va->value + va->page_size < va->upper) + doscroll = 0; + gtk_text_freeze(t); } - if (count == 0) { - close(fd); - if (textbox) - flags |= f_closed; - else - gtk_main_quit(); - return; - } + /* --- Read data into the buffer --- * + * + * This is a bit of a mess. + */ - /* --- If there's no output window, create one --- */ - - if (!textbox) { - GtkWidget *win; - GtkWidget *t; - GtkWidget *w; - - win = gtk_dialog_new(); - gtk_signal_connect(GTK_OBJECT(win), "destroy", - GTK_SIGNAL_FUNC(killwin), 0); - - t = gtk_table_new(2, 2, 0); - gtk_container_border_width(GTK_CONTAINER(t), 8); - gtk_box_pack_start(GTK_BOX(GTK_DIALOG(win)->vbox), t, 1, 1, 0); - gtk_widget_show(t); - - textbox = gtk_text_new(0, 0); - gtk_table_attach(GTK_TABLE(t), textbox, 0, 1, 0, 1, - GTK_EXPAND | GTK_SHRINK | GTK_FILL, - GTK_EXPAND | GTK_SHRINK | GTK_FILL, - 0, 0); - gtk_text_set_editable(GTK_TEXT(textbox), 0); - gtk_widget_set_usize(textbox, 500, 100); - gtk_widget_show(textbox); - - w = gtk_vscrollbar_new(GTK_TEXT(textbox)->vadj); - gtk_table_attach(GTK_TABLE(t), w, 1, 2, 0, 1, - 0, GTK_EXPAND | GTK_SHRINK | GTK_FILL, 0, 0); - gtk_widget_show(w); - - w = gtk_hscrollbar_new(GTK_TEXT(textbox)->hadj); - gtk_table_attach(GTK_TABLE(t), w, 0, 1, 1, 2, - GTK_EXPAND | GTK_SHRINK | GTK_FILL, 0, 0, 0); - gtk_widget_show(w); - - gtk_box_set_homogeneous(GTK_BOX(GTK_DIALOG(win)->action_area), 0); - w = gtk_button_new_with_label("Dismiss"); - gtk_signal_connect_object(GTK_OBJECT(w), "clicked", - GTK_SIGNAL_FUNC(gtk_object_destroy), - GTK_OBJECT(win)); - gtk_box_pack_end(GTK_BOX(GTK_DIALOG(win)->action_area), w, 0, 0, 0); - GTK_WIDGET_SET_FLAGS(w, GTK_CAN_DEFAULT); - gtk_widget_grab_default(w); - cancel(GTK_WINDOW(win), w); - gtk_widget_show(w); - - gtk_widget_show(win); - } + for (;;) { + int r = read(fd, buf, sizeof(buf)); + + /* --- The read failed --- * + * + * Maybe there's no more data to read. In this case, we get + * @EWOULDBLOCK@, indicating it's time to stop and do something else. + * Otherwise something serious has happened. + */ + + if (r < 0) { + if (errno == EWOULDBLOCK) + break; + msg(":~OK", "error reading data: %s", strerror(errno)); + exit(EXIT_FAILURE); + } - /* --- Append the new text --- */ + /* --- End of file --- * + * + * If the box is closed, then exit quiety; otherwise wait for it to + * go away. + */ + + if (r == 0) { + close(fd); + if (textbox) + flags |= f_closed; + else + gtk_main_quit(); + break; + } - gtk_text_insert(GTK_TEXT(textbox), font, 0, 0, buf, count); + /* --- If there's no output window, create one --- */ + + if (!textbox) { + GtkWidget *win; + GtkWidget *tbl; + GtkWidget *w; + + win = gtk_dialog_new(); + gtk_signal_connect(GTK_OBJECT(win), "destroy", + GTK_SIGNAL_FUNC(killwin), 0); + + tbl = gtk_table_new(2, 2, 0); + gtk_container_border_width(GTK_CONTAINER(tbl), 8); + gtk_box_pack_start(GTK_BOX(GTK_DIALOG(win)->vbox), tbl, 1, 1, 0); + gtk_widget_show(tbl); + + textbox = gtk_text_new(0, 0); + t = GTK_TEXT(textbox); + va = t->vadj; + gtk_table_attach(GTK_TABLE(tbl), textbox, 0, 1, 0, 1, + GTK_EXPAND | GTK_SHRINK | GTK_FILL, + GTK_EXPAND | GTK_SHRINK | GTK_FILL, + 0, 0); + gtk_text_set_editable(t, 0); + gtk_widget_set_usize(textbox, 500, 300); + gtk_text_freeze(t); + gtk_widget_show(textbox); + + w = gtk_vscrollbar_new(va); + gtk_table_attach(GTK_TABLE(tbl), w, 1, 2, 0, 1, + 0, GTK_EXPAND | GTK_SHRINK | GTK_FILL, 0, 0); + gtk_widget_show(w); + + w = gtk_hscrollbar_new(t->hadj); + gtk_table_attach(GTK_TABLE(tbl), w, 0, 1, 1, 2, + GTK_EXPAND | GTK_SHRINK | GTK_FILL, 0, 0, 0); + gtk_widget_show(w); + + gtk_box_set_homogeneous(GTK_BOX(GTK_DIALOG(win)->action_area), 0); + w = gtk_button_new_with_label("Dismiss"); + gtk_signal_connect_object(GTK_OBJECT(w), "clicked", + GTK_SIGNAL_FUNC(gtk_object_destroy), + GTK_OBJECT(win)); + gtk_box_pack_end(GTK_BOX(GTK_DIALOG(win)->action_area), w, 0, 0, 0); + GTK_WIDGET_SET_FLAGS(w, GTK_CAN_DEFAULT); + gtk_widget_grab_default(w); + cancel(GTK_WINDOW(win), w); + gtk_widget_show(w); + + gtk_widget_show(win); + } + + gtk_text_insert(t, font, 0, 0, buf, r); + } + + if (textbox) { + gtk_text_thaw(t); + if (doscroll) + gtk_adjustment_set_value(va, va->upper - va->page_size); + } } /* --- Signal handler --- */ static void reap(int sig) { - while (waitpid(-1, 0, WNOHANG) > 0) - ; + pid_t k; + int s; + + for (;;) { + k = waitpid(-1, &s, WNOHANG); + if (k <= 0) + break; + if (k == kid) { + if (WIFEXITED(s)) + status = WEXITSTATUS(s); + else + status = 127; + } + } } /* --- Main program --- */ @@ -198,8 +270,8 @@ int main(int argc, char *argv[]) { "help", 0, 0, 'h' }, { "usage", 0, 0, 'u' }, { "version", 0, 0, 'v' }, - { "file", gFlag_argReq, 0, 'f' }, - { "font", gFlag_argReq, 0, 'F' }, + { "file", OPTF_ARGREQ, 0, 'f' }, + { "font", OPTF_ARGREQ, 0, 'F' }, { 0, 0, 0, 0 } }; int i = mdwopt(argc, argv, "huvf:F:", opt, 0, 0, 0); @@ -222,8 +294,8 @@ int main(int argc, char *argv[]) "-h, --help Display this help text\n" "-u, --usage Display a quick usage summary\n" "-v, --version Display the version number\n" -"-f, --file=FILE Read input from the named file\n" -"-F, --font=FONT Display output in the named font\n", +"-f, --file=FILE\t Read input from the named file\n" +"-F, --font=FONT\t Display output in the named font\n", stdout); exit(0); break; @@ -260,8 +332,8 @@ int main(int argc, char *argv[]) fd = STDIN_FILENO; else { int pfd[2]; - pid_t kid; struct sigaction sa; + sigset_t newmask, oldmask; /* --- Set up a signal handler --- */ @@ -274,6 +346,11 @@ int main(int argc, char *argv[]) if (pipe(pfd)) die(1, "couldn't open pipe: %s", strerror(errno)); + + sigemptyset(&newmask); + sigaddset(&newmask, SIGCHLD); + sigprocmask(SIG_BLOCK, &newmask, &oldmask); + kid = fork(); if (kid < 0) die(1, "couldn't fork: %s", strerror(errno)); @@ -295,14 +372,21 @@ int main(int argc, char *argv[]) write(STDERR_FILENO, d.buf, d.len); _exit(127); } + + sigprocmask(SIG_SETMASK, &oldmask, 0); fd = pfd[0]; close(pfd[1]); } } + { + int f = fcntl(fd, F_GETFL); + fcntl(fd, F_SETFL, f | O_NONBLOCK); + } + gdk_input_add(fd, GDK_INPUT_READ, ready, 0); gtk_main(); - return (0); + return (status); } /*----- That's all, folks -------------------------------------------------*/