+namespace
+{
+
+struct HtmlBrowser {
+ operator bool() const { return (binary && *binary) || (command && *command); }
+ gchar *command_result() const;
+
+ const gchar *binary; /**< the binary to look for in the path */
+ const gchar *command; /**< has 3 capabilities:
+ * nullptr exec binary with html file path as command line
+ * string exec string and use results for command line
+ * !string use text following ! as command line, replacing optional %s with html file path */
+};
+
+constexpr std::array<HtmlBrowser, 10> html_browsers{{
+ /* Our specific script */
+ {GQ_APPNAME_LC "_html_browser", nullptr},
+ /* Redhat has a nifty htmlview script to start the user's preferred browser */
+ {"htmlview", nullptr},
+ /* Debian has even better approach with alternatives */
+ {"sensible-browser", nullptr},
+ /* GNOME 2 */
+ {"gconftool-2", "gconftool-2 -g /desktop/gnome/url-handlers/http/command"},
+ /* KDE */
+ {"kfmclient", "!kfmclient exec \"%s\""},
+ /* use fallbacks */
+ {"firefox", nullptr},
+ {"mozilla", nullptr},
+ {"konqueror", nullptr},
+ {"netscape", nullptr},
+ {"opera", "!opera --remote 'openURL(%s,new-page)'"},
+}};
+
+gchar *HtmlBrowser::command_result() const
+{
+ gchar *result = nullptr;
+ FILE *f;
+ gchar buf[2048];
+ gint l;
+
+ if (!binary || binary[0] == '\0') return nullptr;
+ if (!file_in_path(binary)) return nullptr;
+
+ if (!command || command[0] == '\0') return g_strdup(binary);
+ if (command[0] == '!') return g_strdup(command + 1);
+
+ f = popen(command, "r");
+ if (!f) return nullptr;
+
+ while ((l = fread(buf, sizeof(gchar), sizeof(buf), f)) > 0)
+ {
+ if (!result)
+ {
+ gint n = 0;
+
+ while (n < l && buf[n] != '\n' && buf[n] != '\r') n++;
+ if (n > 0) result = g_strndup(buf, n);
+ }
+ }
+
+ pclose(f);
+
+ return result;
+}
+
+} // namespace
+