X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~mdw/git/disorder/blobdiff_plain/f3d18e005fcd2ade17d24918979e9997d6f4d683..e9e8a16d359c900f114853eb0e407a8064e4350c:/disobedience/help.c diff --git a/disobedience/help.c b/disobedience/help.c index 7fbde80..55309f0 100644 --- a/disobedience/help.c +++ b/disobedience/help.c @@ -22,213 +22,26 @@ */ #include "disobedience.h" -#include "html.h" -#include "manual.h" +#include +#include -VECTOR_TYPE(markstack, GtkTextMark *, xrealloc); - -/** @brief Known tag type */ -struct tag { - /** @brief HTML tag name */ - const char *name; - - /** @brief Called to set up the tag */ - void (*init)(GtkTextTag *tag); - -}; - -/** @brief Initialize the bold tag - * - * This doesn't seem to work on OS X though the italic and monospace tags are - * fine, and bold is OK on Linux, even connecting to the Apple X swerver. - */ -static void init_bold(GtkTextTag *tag) { - g_object_set(G_OBJECT(tag), "weight", PANGO_WEIGHT_BOLD, (char *)0); -} - -/** @brief Initialize the italic tag */ -static void init_italic(GtkTextTag *tag) { - g_object_set(G_OBJECT(tag), "style", PANGO_STYLE_ITALIC, (char *)0); -} - -/** @brief Initialize the pre tag */ -static void init_pre(GtkTextTag *tag) { - g_object_set(G_OBJECT(tag), "family", "monospace", (char *)0); -} - -/** @brief Table of known tags - * - * Keep in alphabetical order - */ -static const struct tag tags[] = { - { "b", init_bold }, - { "i", init_italic }, - { "pre", init_pre } -}; - -/** @brief Number of known tags */ -#define NTAGS (sizeof tags / sizeof *tags) - -/** @brief State structure for insert_html() */ -struct state { - /** @brief The buffer to insert into */ - GtkTextBuffer *buffer; - - /** @brief The buffer's tag table */ - GtkTextTagTable *tagtable; - - /** @brief True if we are inside */ - int body; - - /** @brief True if inside
 */
-  int pre;
-
-  /** @brief True if a space is required before any non-space */
-  int space;
-
-  /** @brief Stack of marks corresponding to tags */
-  struct markstack marks[1];
-
-};
-
-/** @brief Called for an open tag */
-static void html_open(const char *tag,
-		      hash attribute((unused)) *attrs,
-		      void *u) {
-  struct state *const s = u;
-  GtkTextIter iter[1];
-
-  if(!strcmp(tag, "body"))
-    ++s->body;
-  else if(!strcmp(tag, "pre"))
-    ++s->pre;
-  if(!s->body)
-    return;
-  /* push a mark for the start of the region */
-  gtk_text_buffer_get_iter_at_mark(s->buffer, iter,
-				   gtk_text_buffer_get_insert(s->buffer));
-  markstack_append(s->marks,
-		   gtk_text_buffer_create_mark(s->buffer,
-					       0/* mark_name */,
-					       iter,
-					       TRUE/*left_gravity*/));
-}
-
-/** @brief Called for a close tag */
-static void html_close(const char *tag,
-		       void *u) {
-  struct state *const s = u;
-  GtkTextIter start[1], end[1];
-  GtkTextTag *texttag;
-
-  if(!strcmp(tag, "body"))
-    --s->body;
-  else if(!strcmp(tag, "pre")) {
-    --s->pre;
-    s->space = 0;
-  }
-  if(!s->body)
-    return;
-  /* see if this is a known tag */
-  texttag = gtk_text_tag_table_lookup(s->tagtable, tag);
-  if(!texttag)
-    return;
-  /* pop the mark at the start of the region */
-  assert(s->marks->nvec > 0);
-  gtk_text_buffer_get_iter_at_mark(s->buffer, start,
-				   s->marks->vec[--s->marks->nvec]);
-  gtk_text_buffer_get_iter_at_mark(s->buffer, end,
-				   gtk_text_buffer_get_insert(s->buffer));
-  /* apply the tag */
-  gtk_text_buffer_apply_tag(s->buffer, texttag, start, end);
-  /* don't need the start mark any more */
-  gtk_text_buffer_delete_mark(s->buffer, s->marks->vec[s->marks->nvec]);
-}
-
-/** @brief Called for text */
-static void html_text(const char *text,
-		      void *u) {
-  struct state *const s = u;
-
-  /* ignore header */
-  if(!s->body)
-    return;
-  if(!s->pre) {
-    char *formatted = xmalloc(strlen(text) + 1), *t = formatted;
-    /* normalize spacing */
-    while(*text) {
-      if(isspace((unsigned char)*text)) {
-	s->space = 1;
-	++text;
-      } else {
-	if(s->space) {
-	  *t++ = ' ';
-	  s->space = 0;
-	}
-	*t++ = *text++;
-      }
-    }
-    *t = 0;
-    text = formatted;
-  }
-  gtk_text_buffer_insert_at_cursor(s->buffer, text, strlen(text));
-}
-
-/** @brief Callbacks for insert_html() */
-static const struct html_parser_callbacks insert_html_callbacks = {
-  html_open,
-  html_close,
-  html_text
-};
-
-/** @brief Insert @p html into @p buffer at cursor */
-static void insert_html(GtkTextBuffer *buffer,
-			const char *html) {
-  struct state s[1];
-  size_t n;
-
-  memset(s, 0, sizeof *s);
-  s->buffer = buffer;
-  markstack_init(s->marks);
-  /* initialize tags */
-  s->tagtable = gtk_text_buffer_get_tag_table(s->buffer);
-  for(n = 0; n < NTAGS; ++n) {
-    GtkTextTag *const tag = gtk_text_tag_new(tags[n].name);
-    tags[n].init(tag);
-    gtk_text_tag_table_add(s->tagtable, tag);
-  }
-  /* convert the input */
-  html_parse(&insert_html_callbacks, html, s);
-}
-
-/** @brief Create a GtkTextBuffer with @p html rendered into it */
-static GtkTextBuffer *html_buffer(const char *html) {
-  GtkTextBuffer *buffer = gtk_text_buffer_new(NULL);
-
-  insert_html(buffer, html);
-  return buffer;
-}
-
-/** @brief The manual page window */
-static GtkWidget *help_window;
-
-/** @brief Pop up the manual page in a window */
+/** @brief Display the manual page */
 void popup_help(void) {
-  GtkWidget *view;
-  
-  if(help_window) {
-    gtk_window_present(GTK_WINDOW(help_window));
-    return;
+  char *path;
+  pid_t pid;
+  int w;
+
+  byte_xasprintf(&path, "%s/disobedience.html", pkgdatadir);
+  if(!(pid = xfork())) {
+    exitfn = _exit;
+    if(!xfork()) {
+      execlp(browser, browser, path, (char *)0);
+      fatal(errno, "error executing %s", browser);
+    }
+    _exit(0);
   }
-  help_window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
-  g_signal_connect(help_window, "destroy",
-		   G_CALLBACK(gtk_widget_destroyed), &help_window);
-  gtk_window_set_title(GTK_WINDOW(help_window), "Disobedience Manual Page");
-  view = gtk_text_view_new_with_buffer(html_buffer(manual));
-  gtk_text_view_set_editable(GTK_TEXT_VIEW(view), FALSE);
-  gtk_container_add(GTK_CONTAINER(help_window), scroll_widget(view));
-  gtk_window_set_default_size(GTK_WINDOW(help_window), 512, 512);
-  gtk_widget_show_all(help_window);
+  while(waitpid(pid, &w, 0) < 0 && errno == EINTR)
+    ;
 }
 
 /*