From: Richard Kettlewell Date: Sat, 10 Nov 2007 15:49:07 +0000 (+0000) Subject: use an external browser to view disorder help X-Git-Tag: debian-1_5_99dev8~50 X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~mdw/git/disorder/commitdiff_plain/f486ea184ba1d605110eab4862406c11554ed13e use an external browser to view disorder help --- diff --git a/.bzrignore b/.bzrignore index a9aab7e..f9d8ac1 100644 --- a/.bzrignore +++ b/.bzrignore @@ -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 diff --git a/configure.ac b/configure.ac index a9331b2..a020864 100644 --- a/configure.ac +++ b/configure.ac @@ -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])], diff --git a/disobedience/Makefile.am b/disobedience/Makefile.am index eb257d6..62535e1 100644 --- a/disobedience/Makefile.am +++ b/disobedience/Makefile.am @@ -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) diff --git a/disobedience/disobedience.c b/disobedience/disobedience.c index 291d955..2d7ab3e 100644 --- a/disobedience/disobedience.c +++ b/disobedience/disobedience.c @@ -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); diff --git a/disobedience/disobedience.h b/disobedience/disobedience.h index dbc6882..edb973d 100644 --- a/disobedience/disobedience.h +++ b/disobedience/disobedience.h @@ -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); diff --git a/disobedience/help.c b/disobedience/help.c index 7fbde80..db46db0 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", 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)
+    ;
 }
 
 /*
diff --git a/disobedience/appearance.c b/disobedience/settings.c
similarity index 97%
rename from disobedience/appearance.c
rename to disobedience/settings.c
index 868f8c9..75f7396 100644
--- a/disobedience/appearance.c
+++ b/disobedience/settings.c
@@ -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;
diff --git a/lib/Makefile.am b/lib/Makefile.am
index dc6518d..524496e 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -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
diff --git a/lib/defs.c b/lib/defs.c
index d0f5c66..c9668c0 100644
--- a/lib/defs.c
+++ b/lib/defs.c
@@ -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
diff --git a/lib/defs.h b/lib/defs.h
index c14bb9b..c340e8e 100644
--- a/lib/defs.h
+++ b/lib/defs.h
@@ -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
index 7ce16d9..0000000
--- a/lib/html.c
+++ /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 
-#include "types.h"
-
-#include 
-#include 
-#include 
-
-#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
index fd81d1d..0000000
--- a/lib/html.h
+++ /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:
-*/