Improve display for large files. Keep newly added material in view if 1.2.3
authormdw <mdw>
Wed, 24 Mar 1999 22:23:57 +0000 (22:23 +0000)
committermdw <mdw>
Wed, 24 Mar 1999 22:23:57 +0000 (22:23 +0000)
scrolled to bottom of window.

xcatch.c

index 9a69aa1..43d3b02 100644 (file)
--- a/xcatch.c
+++ b/xcatch.c
@@ -1,6 +1,6 @@
 /* -*-c-*-
  *
- * $Id: xcatch.c,v 1.3 1998/12/20 17:19:16 mdw Exp $
+ * $Id: xcatch.c,v 1.4 1999/03/24 22:23:57 mdw Exp $
  *
  * Catch input and trap it in an X window
  *
 /*----- Revision history --------------------------------------------------* 
  *
  * $Log: xcatch.c,v $
+ * 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.
@@ -97,82 +101,122 @@ 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);
+    }
+
+    /* --- End of file --- *
+     *
+     * If the box is closed, then exit quiety; otherwise wait for it to
+     * go away.
+     */
 
-  /* --- Append the new text --- */
+    if (r == 0) {
+      close(fd);
+      if (textbox)
+       flags |= f_closed;
+      else
+       gtk_main_quit();
+      break;
+    }
+
+    /* --- 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(GTK_TEXT(textbox), font, 0, 0, buf, count);
+    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 --- */
@@ -321,6 +365,11 @@ int main(int argc, char *argv[])
     }
   }
 
+  {
+    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 (status);