X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~mdw/git/disorder/blobdiff_plain/f3d18e005fcd2ade17d24918979e9997d6f4d683..7a201620482ca3f6061436e1f740e1b5ff495425:/disobedience/help.c diff --git a/disobedience/help.c b/disobedience/help.c index 7fbde80..a182940 100644 --- a/disobedience/help.c +++ b/disobedience/help.c @@ -1,6 +1,7 @@ + /* * This file is part of DisOrder - * Copyright (C) 2007 Richard Kettlewell + * Copyright (C) 2007, 2008 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 @@ -22,213 +23,26 @@ */ #include "disobedience.h" -#include "html.h" -#include "manual.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
*/ - 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]; - -}; +#include+#include -/** @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) + ; } /*