chiark / gitweb /
sgt-puzzles (20161228.7cae89f-1) unstable; urgency=medium
[sgt-puzzles.git] / debian / patches / 202_online-help.diff
1 Author: Ben Hutchings <ben@decadent.org.uk>
2 Description: Add HTML-based online help
3
4 This works along the same lines as the Windows implementation,
5 though we have to try a bit harder to find a help browser.
6
7 --- a/gtk.c
8 +++ b/gtk.c
9 @@ -2,6 +2,10 @@
10   * gtk.c: GTK front end for my puzzle collection.
11   */
12  
13 +#ifndef _POSIX_C_SOURCE
14 +#define _POSIX_C_SOURCE 1 /* for PATH_MAX */
15 +#endif
16 +
17  #include <stdio.h>
18  #include <assert.h>
19  #include <stdlib.h>
20 @@ -10,6 +14,9 @@
21  #include <string.h>
22  #include <errno.h>
23  #include <math.h>
24 +#include <limits.h>
25 +#include <unistd.h>
26 +#include <locale.h>
27  
28  #include <sys/time.h>
29  #include <sys/resource.h>
30 @@ -2273,6 +2280,89 @@ static void menu_config_event(GtkMenuIte
31      midend_redraw(fe->me);
32  }
33  
34 +#ifndef HELP_BROWSER_PATH
35 +#define HELP_BROWSER_PATH "xdg-open:sensible-browser"
36 +#endif
37 +
38 +static void show_help(frontend *fe, const char *topic)
39 +{
40 +    const char *list = HELP_BROWSER_PATH;
41 +    char path[PATH_MAX + 1];
42 +    struct {
43 +       const char *s;
44 +       int len;
45 +    } lang[3];
46 +    int i;
47 +
48 +    /*
49 +     * Search for help file, trying:
50 +     * 1. Version for this locale, ignoring encoding (HTML browsers
51 +     *    must handle multiple encodings)
52 +     * 2. Version for this locale, ignoring encoding and country
53 +     * 3. English version
54 +     */
55 +    lang[0].s = setlocale(LC_MESSAGES, NULL);
56 +    lang[0].len = strcspn(lang[0].s, ".@");
57 +    lang[1].s = lang[0].s;
58 +    lang[1].len = strcspn(lang[1].s, "_");
59 +    if (lang[1].len > lang[0].len)
60 +       lang[1].len = lang[0].len;
61 +    lang[2].s = "en";
62 +    lang[2].len = 2;
63 +    for (i = 0; i < lenof(lang); i++) {
64 +       sprintf(path, "%s/sgt-puzzles/help/%.*s/%s.html",
65 +               SHAREDIR, lang[i].len, lang[i].s, topic);
66 +       if (access(path, R_OK) == 0)
67 +           break;
68 +    }
69 +    if (i == lenof(lang)) {
70 +       error_box(fe->window, "Help file is not installed");
71 +       return;
72 +    }
73 +
74 +    for (;;) {
75 +       size_t len;
76 +       char buf[PATH_MAX + 1];
77 +       const char *command;
78 +       const char *argv[3];
79 +
80 +       len = strcspn(list, ":");
81 +       if (len <= PATH_MAX) {
82 +           memcpy(buf, list, len);
83 +           buf[len] = 0;
84 +           if (buf[0] == '$')
85 +               command = getenv(buf + 1);
86 +           else
87 +               command = buf;
88 +           if (command) {
89 +               argv[0] = command;
90 +               argv[1] = path;
91 +               argv[2] = NULL;
92 +               if (g_spawn_async(NULL, (char **)argv, NULL,
93 +                                 G_SPAWN_SEARCH_PATH,
94 +                                 NULL, NULL, NULL, NULL))
95 +                   return;
96 +           }
97 +       }
98 +
99 +       if (!list[len])
100 +           break;
101 +       list += len + 1;
102 +    }
103 +
104 +    error_box(fe->window, "Failed to start a help browser");
105 +}
106 +
107 +static void menu_help_contents_event(GtkMenuItem *menuitem, gpointer data)
108 +{
109 +    show_help((frontend *)data, "index");
110 +}
111 +
112 +static void menu_help_specific_event(GtkMenuItem *menuitem, gpointer data)
113 +{
114 +    show_help((frontend *)data, thegame.htmlhelp_topic);
115 +}
116 +
117  static void menu_about_event(GtkMenuItem *menuitem, gpointer data)
118  {
119      frontend *fe = (frontend *)data;
120 @@ -2593,6 +2683,25 @@ static frontend *new_window(char *arg, i
121      menu = gtk_menu_new();
122      gtk_menu_item_set_submenu(GTK_MENU_ITEM(menuitem), menu);
123  
124 +    menuitem = gtk_menu_item_new_with_label("Contents");
125 +    gtk_container_add(GTK_CONTAINER(menu), menuitem);
126 +    g_signal_connect(G_OBJECT(menuitem), "activate",
127 +                    G_CALLBACK(menu_help_contents_event), fe);
128 +    gtk_widget_show(menuitem);
129 +
130 +    if (thegame.htmlhelp_topic) {
131 +       char *item;
132 +       assert(thegame.name);
133 +       item = snewn(9+strlen(thegame.name), char); /*ick*/
134 +       sprintf(item, "Help on %s", thegame.name);
135 +       menuitem = gtk_menu_item_new_with_label(item);
136 +       sfree(item);
137 +       gtk_container_add(GTK_CONTAINER(menu), menuitem);
138 +       g_signal_connect(G_OBJECT(menuitem), "activate",
139 +                        G_CALLBACK(menu_help_specific_event), fe);
140 +       gtk_widget_show(menuitem);
141 +    }
142 +
143      menuitem = gtk_menu_item_new_with_label("About");
144      gtk_container_add(GTK_CONTAINER(menu), menuitem);
145      g_signal_connect(G_OBJECT(menuitem), "activate",
146 --- a/Recipe
147 +++ b/Recipe
148 @@ -95,6 +95,7 @@ Puzzles.dmg: Puzzles
149  
150  !begin am
151  bin_PROGRAMS = $(GAMES)
152 +GTK_CFLAGS += -DSHAREDIR="\"$(datarootdir)\""
153  !end
154  !begin am_begin
155  GAMES =