chiark / gitweb /
use an external browser to view disorder help
authorRichard Kettlewell <rjk@greenend.org.uk>
Sat, 10 Nov 2007 15:49:07 +0000 (15:49 +0000)
committerRichard Kettlewell <rjk@greenend.org.uk>
Sat, 10 Nov 2007 15:49:07 +0000 (15:49 +0000)
12 files changed:
.bzrignore
configure.ac
disobedience/Makefile.am
disobedience/disobedience.c
disobedience/disobedience.h
disobedience/help.c
disobedience/settings.c [moved from disobedience/appearance.c with 97% similarity]
lib/Makefile.am
lib/defs.c
lib/defs.h
lib/html.c [deleted file]
lib/html.h [deleted file]

index a9aab7e..f9d8ac1 100644 (file)
@@ -109,8 +109,6 @@ doc/disorder-normalize.8.html
 doc/disorder-decode.8.html
 doc/disorder-decode.8
 doc/plumbing.png
-disobedience/manual.h
-disobedience/manual.html
 disobedience/images.h
 debian/disorder-server
 doc/disorder-stats.8
@@ -118,3 +116,4 @@ doc/disorder-stats.8.html
 server/disorder-stats
 *.deb
 *.dsc
+disobedience/disobedience.html
index a9331b2..a020864 100644 (file)
@@ -79,6 +79,7 @@ case "$host" in
   if test $want_coreaudio = yes; then
     COREAUDIO="-framework CoreAudio"
   fi
+  BROWSER=open
   ;;
 * )
   AC_MSG_RESULT([unknown, winging it])
@@ -87,6 +88,25 @@ case "$host" in
 esac
 AC_SUBST([COREAUDIO])
 
+AC_ARG_WITH([browser],
+            [AS_HELP_STRING([--with-browser=BROWSER],
+                           [use BROWSER to display HTML])],
+            [browser=$withval])
+
+AC_CACHE_CHECK([default HTML viewer],[rjk_cv_browser],[
+  rjk_cv_browser=UNKNOWN
+  for candidate in x-www-browser firefox mozilla konqueror netscape; do
+    if type $candidate >/dev/null 2>&1; then
+      rjk_cv_browser="$candidate"
+      break
+    fi
+  done
+])
+if test -z "$browser"; then
+  browser="$rjk_cv_browser"
+fi
+AC_DEFINE_UNQUOTED([BROWSER],["$browser"],[HTML viewer])
+
 AC_ARG_WITH([server],
            [AS_HELP_STRING([--without-server],
                            [do not build server])],
index eb257d6..62535e1 100644 (file)
@@ -19,6 +19,7 @@
 #
 
 bin_PROGRAMS=disobedience
+doc_DATA=disobedience.html
 
 AM_CPPFLAGS=-I${top_srcdir}/lib -I../lib
 AM_CFLAGS=$(GLIB_CFLAGS) $(GTK_CFLAGS)
@@ -27,7 +28,7 @@ PNGS:=$(wildcard ${top_srcdir}/images/*.png)
 disobedience_SOURCES=disobedience.h disobedience.c client.c queue.c    \
                  choose.c misc.c control.c properties.c menu.c \
                  log.c progress.c login.c rtp.c help.c \
-                 ../lib/memgc.c appearance.c
+                 ../lib/memgc.c settings.c
 disobedience_LDADD=../lib/libdisorder.a $(LIBPCRE) $(LIBGC) $(LIBGCRYPT)
 disobedience_LDFLAGS=$(GTK_LIBS)
 
@@ -36,18 +37,12 @@ install-exec-hook:
 
 check: check-help
 
-help.o: manual.h
-
-manual.html: ../doc/disobedience.1 $(top_srcdir)/scripts/htmlman
+disobedience.html: ../doc/disobedience.1 $(top_srcdir)/scripts/htmlman
        rm -f $@.new
        $(top_srcdir)/scripts/htmlman $< >$@.new
        chmod 444 $@.new
        mv -f $@.new $@
 
-manual.h: manual.html ${top_srcdir}/scripts/text2c
-       ${top_srcdir}/scripts/text2c manual manual.html > $@.tmp
-       mv $@.tmp $@
-
 misc.o: images.h
 
 images.h: $(PNGS)
index 291d955..2d7ab3e 100644 (file)
@@ -452,7 +452,7 @@ int main(int argc, char **argv) {
     }
   }
   signal(SIGPIPE, SIG_IGN);
-  load_appearance();
+  load_settings();
   /* create the event loop */
   D(("create main loop"));
   mainloop = g_main_loop_new(0, 0);
index dbc6882..edb973d 100644 (file)
@@ -245,14 +245,16 @@ int rtp_running(void);
 void start_rtp(void);
 void stop_rtp(void);
 
-/* Appearance */
+/* Settings */
 
 extern GdkColor tool_bg, tool_fg, layout_bg, even_bg, odd_bg;
 extern GdkColor active_bg, selected_bg, selected_fg, search_bg;
 extern GdkColor title_bg, title_fg, item_fg, drag_target, tool_active;
 
-void save_appearance(void);
-void load_appearance(void);
+extern const char *browser;
+
+void save_settings(void);
+void load_settings(void);
 void set_tool_colors(GtkWidget *w);
 void set_slider_colors(GtkWidget *w);
 
index 7fbde80..db46db0 100644 (file)
  */
 
 #include "disobedience.h"
-#include "html.h"
-#include "manual.h"
+#include <sys/wait.h>
+#include <unistd.h>
 
-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 <body> */
-  int body;
-
-  /** @brief True if inside <pre> */
-  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", docdir);
+  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)
+    ;
 }
 
 /*
similarity index 97%
rename from disobedience/appearance.c
rename to disobedience/settings.c
index 868f8c9..75f7396 100644 (file)
@@ -17,8 +17,8 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
  * USA
  */
-/** @file disobedience/appearance.c
- * @brief Visual appearance of Disobedience
+/** @file disobedience/settings.c
+ * @brief Disobedience settings
  *
  * Originally I attempted to use a built-in rc file to configure
  * Disobedience's colors.  This is quite convenient but fails in the
@@ -79,6 +79,9 @@ GdkColor search_bg = { 0, 0xFFFF, 0xFFFF, 0x0000 };
 /** @brief Drag target color */
 GdkColor drag_target = { 0, 0x6666, 0x6666, 0x6666 };
 
+/** @brief HTML displayer */
+const char *browser = BROWSER;
+
 struct colordesc {
   GdkColor *color;
   const char *name;
@@ -109,7 +112,7 @@ static const struct colordesc colors[] = {
 
 #define NCOLORS (sizeof colors / sizeof *colors)
 
-void save_appearance(void) {
+void save_settings(void) {
   char *dir, *path, *tmp;
   FILE *fp = 0;
   size_t n;
@@ -151,7 +154,7 @@ static inline unsigned clamp(unsigned n) {
   return n > 0xFFFF ? 0xFFFF : n;
 }
 
-void load_appearance(void) {
+void load_settings(void) {
   char *path, *line;
   FILE *fp;
   size_t n;
index dc6518d..524496e 100644 (file)
@@ -1,6 +1,6 @@
 #
 # This file is part of DisOrder.
-# Copyright (C) 2004, 2005, 2006, s007 Richard Kettlewell
+# Copyright (C) 2004, 2005, 2006, 2007 Richard Kettlewell
 #
 # 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
@@ -38,7 +38,6 @@ libdisorder_a_SOURCES=charset.c charset.h             \
        hash.c hash.h                                   \
        heap.h                                          \
        hex.c hex.h                                     \
-       html.c html.h                                   \
        ifreq.c ifreq.h                                 \
        inputline.c inputline.h                         \
        kvp.c kvp.h                                     \
@@ -82,6 +81,7 @@ definitions.h: Makefile
        echo "#define SBINDIR \"${sbindir}/\"" >> $@.new
        echo "#define BINDIR \"${bindir}/\"" >> $@.new
        echo "#define FINKBINDIR \"${finkbindir}/\"" >> $@.new
+       echo "#define DOCDIR \"${docdir}/\"" >> $@.new
        @if cmp $@.new $@; then \
                echo rm -f $@.new; rm -f $@.new; else \
                echo mv $@.new $@; mv $@.new $@; fi
index d0f5c66..c9668c0 100644 (file)
@@ -56,6 +56,9 @@ const char sbindir[] = SBINDIR;
  */
 const char finkbindir[] = FINKBINDIR;
 
+/** @brief Package documentation directory */
+const char docdir[] = DOCDIR;
+
 /*
 Local Variables:
 c-basic-offset:2
index c14bb9b..c340e8e 100644 (file)
@@ -29,6 +29,7 @@ extern const char pkgdatadir[];
 extern const char bindir[];
 extern const char sbindir[];
 extern const char finkbindir[];
+extern const char docdir[];
 
 #endif /* DEFS_H */
 
diff --git a/lib/html.c b/lib/html.c
deleted file mode 100644 (file)
index 7ce16d9..0000000
+++ /dev/null
@@ -1,205 +0,0 @@
-/*
- * This file is part of DisOrder
- * Copyright (C) 2007 Richard Kettlewell
- *
- * 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 2 of the License, 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; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
- * USA
- */
-/** @file lib/html.c
- * @brief Noddy HTML parser
- */
-
-#include <config.h>
-#include "types.h"
-
-#include <string.h>
-#include <ctype.h>
-#include <stddef.h>
-
-#include "hash.h"
-#include "html.h"
-#include "mem.h"
-#include "log.h"
-#include "vector.h"
-#include "charset.h"
-#include "table.h"
-
-/** @brief Entity table type */
-struct entity {
-  const char *name;
-  uint32_t value;
-};
-
-/** @brief Known entities
- *
- * We only support the entities that turn up in the HTML files we
- * actually care about.
- *
- * Keep in alphabetical order.
- */
-static const struct entity entities[] = {
-  { "amp", '&' },
-  { "gt", '>' },
-  { "lt", '<' }
-};
-
-/** @brief Skip whitespace */
-static const char *skipwhite(const char *input) {
-  while(*input && isspace((unsigned char)*input))
-    ++input;
-  return input;
-}
-
-/** @brief Parse an entity */
-static const char *parse_entity(const char *input,
-                               uint32_t *entityp) {
-  input = skipwhite(input);
-  if(*input == '#') {
-    input = skipwhite(input + 1);
-    if(*input == 'x')
-      *entityp = strtoul(skipwhite(input + 1), (char **)&input, 16);
-    else
-      *entityp = strtoul(input, (char **)&input, 10);
-  } else {
-    struct dynstr name[1];
-    int n;
-
-    dynstr_init(name);
-    while(isalnum((unsigned char)*input))
-      dynstr_append(name, tolower((unsigned char)*input++));
-    dynstr_terminate(name);
-    if((n = TABLE_FIND(entities, struct entity, name, name->vec)) < 0) {
-      error(0, "unknown entity '%s'", name->vec);
-      *entityp = '?';
-    } else
-      *entityp = entities[n].value;
-  }
-  input = skipwhite(input);
-  if(*input == ';')
-    ++input;
-  return input;
-}
-
-/** @brief Parse one character or entity and append it to a @ref dynstr */
-static const char *parse_one(const char *input, struct dynstr *d) {
-  if(*input == '&') {
-    uint32_t c;
-    input = parse_entity(input + 1, &c);
-    if(one_ucs42utf8(c, d))
-      dynstr_append(d, '?');   /* U+FFFD might be a better choice */
-  } else
-    dynstr_append(d, *input++);
-  return input;
-}
-
-/** @brief Too-stupid-to-live HTML parser
- * @param callbacks Parser callbacks
- * @param input HTML document
- * @param u User data pointer
- * @return 0 on success, -1 on error
- */
-int html_parse(const struct html_parser_callbacks *callbacks,
-              const char *input,
-              void *u) {
-  struct dynstr text[1];
-
-  dynstr_init(text);
-  while(*input) {
-    if(*input == '<') {
-      struct dynstr tag[1];
-      hash *attrs;
-
-      /* flush collected text */
-      if(text->nvec) {
-       dynstr_terminate(text);
-       callbacks->text(text->vec, u);
-       text->nvec = 0;
-      }
-      dynstr_init(tag);
-      input = skipwhite(input + 1);
-      /* see if it's an open or close tag */
-      if(*input == '/') {
-       input = skipwhite(input + 1);
-       attrs = 0;
-      } else
-       attrs = hash_new(sizeof(char *));
-      /* gather tag */
-      while(isalnum((unsigned char)*input))
-       dynstr_append(tag, tolower((unsigned char)*input++));
-      dynstr_terminate(tag);
-      input = skipwhite(input);
-      if(attrs) {
-       /* gather attributes */
-       while(*input && *input != '>') {
-         struct dynstr name[1], value[1];
-
-         dynstr_init(name);
-         dynstr_init(value);
-         /* attribute name */
-         while(isalnum((unsigned char)*input))
-           dynstr_append(name, tolower((unsigned char)*input++));
-         dynstr_terminate(name);       
-         input = skipwhite(input);
-         if(*input == '=') {
-           /* attribute value */
-           input = skipwhite(input + 1);
-           if(*input == '"' || *input == '\'') {
-             /* quoted value */
-             const int q = *input++;
-             while(*input && *input != q)
-               input = parse_one(input, value);
-             if(*input == q)
-               ++input;
-           } else {
-             /* unquoted value */
-             while(*input && *input != '>' && !isspace((unsigned char)*input))
-               input = parse_one(input, value);
-           }
-           dynstr_terminate(value);
-         }
-         /* stash the value */
-         hash_add(attrs, name->vec, value->vec, HASH_INSERT_OR_REPLACE);
-         input = skipwhite(input);
-       }
-      }
-      if(*input != '>') {
-       error(0, "unterminated tag %s", tag->vec);
-       return -1;
-      }
-      ++input;
-      if(attrs)
-       callbacks->open(tag->vec, attrs, u);
-      else
-       callbacks->close(tag->vec, u);
-    } else
-      input = parse_one(input, text);
-  }
-  /* flush any trailing text */
-  if(text->nvec) {
-    dynstr_terminate(text);
-    callbacks->text(text->vec, u);
-    text->nvec = 0;
-  }
-  return 0;
-}
-
-/*
-Local Variables:
-c-basic-offset:2
-comment-column:40
-fill-column:79
-indent-tabs-mode:nil
-End:
-*/
diff --git a/lib/html.h b/lib/html.h
deleted file mode 100644 (file)
index fd81d1d..0000000
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * This file is part of DisOrder
- * Copyright (C) 2007 Richard Kettlewell
- *
- * 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 2 of the License, 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; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
- * USA
- */
-/** @file lib/html.c
- * @brief Noddy HTML parser
- */
-
-#ifndef HTML_H
-#define HTML_H
-
-/** @brief HTML parser callbacks */
-struct html_parser_callbacks {
-  /** @brief Called for an open tag
-   * @param tag Name of tag, normalized to lower case
-   * @param attrs Hash containing attributes
-   * @param u User data pointer
-   */
-  void (*open)(const char *tag,
-              hash *attrs,
-              void *u);
-
-  /** @brief Called for a close tag
-   * @param tag Name of tag, normalized to lower case
-   * @param u User data pointer
-   */
-  void (*close)(const char *tag,
-               void *u);
-
-  /** @brief Called for text
-   * @param text Pointer to text
-   * @param u User data pointer
-   */
-  void (*text)(const char *text,
-              void *u);
-};
-
-int html_parse(const struct html_parser_callbacks *callbacks,
-              const char *input,
-              void *u);
-
-#endif /* HTML_H */
-
-/*
-Local Variables:
-c-basic-offset:2
-comment-column:40
-fill-column:79
-indent-tabs-mode:nil
-End:
-*/