diff --git a/tools/backend/contents.c b/tools/backend/contents.c new file mode 100644 index 0000000..d76102d --- /dev/null +++ b/tools/backend/contents.c @@ -0,0 +1,224 @@ +/* $Id$ */ +/* Copyright (c) 2015 Pierre Pronchery */ +/* This file is part of DeforaOS Desktop Surfer */ +/* 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, version 3 of the License. + * + * 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, see . */ + + + + +/* public */ +/* prototypes */ +int helper_open_contents(Helper * helper, char const * package, + char const * command); + + +/* private */ +/* prototypes */ +static void _new_contents(Helper * helper); + +/* callbacks */ +static void _helper_on_contents_row_activated(GtkWidget * widget, + GtkTreePath * path, GtkTreeViewColumn * column, gpointer data); + +/* filters */ +static gboolean _helper_filter_contents(GtkTreeModel * model, + GtkTreeIter * iter, gpointer data); + + +/* public */ +/* functions */ +/* helper_open_contents */ +int helper_open_contents(Helper * helper, char const * package, + char const * command) +{ + char buf[256]; + + if(package == NULL) + return -1; + if(command == NULL) + command = "index"; + /* read a package documentation */ + snprintf(buf, sizeof(buf), "%s%s%s%s%s", "file://" CONTENTSDIR "/", + package, "/", command, ".html"); + return helper_open(helper, buf); +} + + +/* functions */ +/* new_contents */ +static gboolean _new_contents_idle(gpointer data); +static void _new_contents_package(Helper * helper, char const * contentsdir, + GtkTreeStore * store, char const * package); + +static void _new_contents(Helper * helper) +{ + GtkWidget * widget; + GtkTreeModel * model; + GtkCellRenderer * renderer; + GtkTreeViewColumn * column; + + widget = gtk_scrolled_window_new(NULL, NULL); + gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(widget), + GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); + model = gtk_tree_model_filter_new(GTK_TREE_MODEL(helper->store), NULL); + gtk_tree_model_filter_set_visible_func(GTK_TREE_MODEL_FILTER(model), + _helper_filter_contents, NULL, NULL); + model = gtk_tree_model_sort_new_with_model(model); + helper->contents = gtk_tree_view_new_with_model(model); + gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(helper->contents), + FALSE); + gtk_tree_view_set_search_column(GTK_TREE_VIEW(helper->contents), + HSC_CONTENTS_PACKAGE); + renderer = gtk_cell_renderer_pixbuf_new(); + column = gtk_tree_view_column_new_with_attributes(NULL, renderer, + "pixbuf", HSC_ICON, NULL); + gtk_tree_view_append_column(GTK_TREE_VIEW(helper->contents), column); + renderer = gtk_cell_renderer_text_new(); + column = gtk_tree_view_column_new_with_attributes(_("Package"), + renderer, "text", HSC_CONTENTS_PACKAGE, NULL); + gtk_tree_view_column_set_sort_column_id(column, HSC_CONTENTS_PACKAGE); + gtk_tree_view_append_column(GTK_TREE_VIEW(helper->contents), column); + gtk_tree_view_column_clicked(column); + g_signal_connect(helper->contents, "row-activated", G_CALLBACK( + _helper_on_contents_row_activated), helper); + gtk_container_add(GTK_CONTAINER(widget), helper->contents); + gtk_notebook_append_page(GTK_NOTEBOOK(helper->notebook), widget, + gtk_label_new(_("Contents"))); +} + +static gboolean _new_contents_idle(gpointer data) +{ + Helper * helper = data; + DIR * dir; + struct dirent * de; + + helper->source = g_idle_add(_new_manual_idle, helper); + helper->p = NULL; + if((dir = opendir(CONTENTSDIR)) == NULL) + return FALSE; + while((de = readdir(dir)) != NULL) + if(de->d_name[0] != '.') + _new_contents_package(helper, CONTENTSDIR, + helper->store, de->d_name); + closedir(dir); + return FALSE; +} + +static void _new_contents_package(Helper * helper, char const * contentsdir, + GtkTreeStore * store, char const * package) +{ + const char ext[] = ".html"; + gchar * p; + DIR * dir; + struct dirent * de; + size_t len; + GtkTreeIter parent; + GtkTreeIter iter; + gint size = 16; + GdkPixbuf * pixbuf; + + if((p = g_strdup_printf("%s/%s", contentsdir, package)) == NULL) + return; + dir = opendir(p); + g_free(p); + if(dir == NULL) + return; + gtk_icon_size_lookup(GTK_ICON_SIZE_MENU, &size, &size); + pixbuf = gtk_icon_theme_load_icon(helper->icontheme, "folder", size, 0, + NULL); +#if GTK_CHECK_VERSION(2, 10, 0) + gtk_tree_store_insert_with_values(store, &parent, NULL, -1, +#else + gtk_tree_store_insert(store, &parent, NULL, -1); + gtk_tree_store_set(store, &parent, +#endif + HSC_TYPE, HST_CONTENTS, HSC_ICON, pixbuf, + HSC_CONTENTS_PACKAGE, package, -1); + if(pixbuf != NULL) + { + g_object_unref(pixbuf); + pixbuf = NULL; + } + while((de = readdir(dir)) != NULL) + { + if(de->d_name[0] == '.' + || (len = strlen(de->d_name)) < sizeof(ext) + || strcmp(&de->d_name[len - sizeof(ext) + 1], + ext) != 0) + continue; + de->d_name[len - sizeof(ext) + 1] = '\0'; + if(pixbuf == NULL) + pixbuf = gtk_icon_theme_load_icon(helper->icontheme, + "help-contents", size, 0, NULL); +#if GTK_CHECK_VERSION(2, 10, 0) + gtk_tree_store_insert_with_values(store, &iter, &parent, -1, +#else + gtk_tree_store_insert(store, &iter, &parent, -1); + gtk_tree_store_set(store, &iter, +#endif + HSC_TYPE, HST_CONTENTS, HSC_ICON, pixbuf, + HSC_CONTENTS_PACKAGE, de->d_name, -1); + } + closedir(dir); + if(pixbuf != NULL) + g_object_unref(pixbuf); +} + + +/* callbacks */ +/* helper_on_contents_row_activated */ +static void _helper_on_contents_row_activated(GtkWidget * widget, + GtkTreePath * path, GtkTreeViewColumn * column, gpointer data) +{ + Helper * helper = data; + GtkTreeModel * model; + GtkTreeIter iter; + GtkTreeIter parent; + gchar * package; + gchar * command; + + model = gtk_tree_view_get_model(GTK_TREE_VIEW(widget)); + gtk_tree_model_get_iter(model, &iter, path); + gtk_tree_model_sort_convert_iter_to_child_iter(GTK_TREE_MODEL_SORT( + model), &parent, &iter); + model = gtk_tree_model_sort_get_model(GTK_TREE_MODEL_SORT(model)); + gtk_tree_model_filter_convert_iter_to_child_iter(GTK_TREE_MODEL_FILTER( + model), &iter, &parent); + model = GTK_TREE_MODEL(helper->store); + if(gtk_tree_model_iter_parent(model, &parent, &iter) == FALSE) + { + if(gtk_tree_view_row_expanded(GTK_TREE_VIEW(widget), path)) + gtk_tree_view_collapse_row(GTK_TREE_VIEW(widget), path); + else + gtk_tree_view_expand_row(GTK_TREE_VIEW(widget), path, + FALSE); + return; + } + gtk_tree_model_get(model, &parent, HSC_CONTENTS_PACKAGE, &package, -1); + gtk_tree_model_get(model, &iter, HSC_CONTENTS_PACKAGE, &command, -1); + helper_open_contents(helper, package, command); + g_free(package); + g_free(command); +} + + +/* filters */ +/* helper_filter_contents */ +static gboolean _helper_filter_contents(GtkTreeModel * model, + GtkTreeIter * iter, gpointer data) +{ + unsigned int type; + + gtk_tree_model_get(model, iter, HSC_TYPE, &type, -1); + return (type == HST_CONTENTS) ? TRUE : FALSE; +} diff --git a/tools/backend/gtkdoc.c b/tools/backend/gtkdoc.c new file mode 100644 index 0000000..989c3fd --- /dev/null +++ b/tools/backend/gtkdoc.c @@ -0,0 +1,273 @@ +/* $Id$ */ +/* Copyright (c) 2015 Pierre Pronchery */ +/* This file is part of DeforaOS Desktop Surfer */ +/* 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, version 3 of the License. + * + * 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, see . */ + + + +/* public */ +int helper_open_gtkdoc(Helper * helper, char const * gtkdocdir, + char const * package); + + +/* private */ +/* constants */ +static char const * _gtkdoc_prefix[] = +{ + /* FIXME look into more directories */ + DATADIR "/gtk-doc/html", DATADIR "/devhelp/books", + "/usr/local/share/gtk-doc/html", + "/usr/local/share/devhelp/books", + "/usr/share/gtk-doc/html", "/usr/share/devhelp/books", NULL +}; + + +/* prototypes */ +static void _new_gtkdoc(Helper * helper); + +/* callbacks */ +static void _helper_on_gtkdoc_row_activated(GtkWidget * widget, + GtkTreePath * path, GtkTreeViewColumn * column, gpointer data); + +/* filters */ +static gboolean _helper_filter_gtkdoc(GtkTreeModel * model, GtkTreeIter * iter, + gpointer data); + + +/* public */ +/* functions */ +/* helper_open_gtkdoc */ +int helper_open_gtkdoc(Helper * helper, char const * gtkdocdir, + char const * package) +{ + int ret; + char const * prefix[] = + { + DATADIR "/gtk-doc/html", DATADIR "/devhelp/books", + "/usr/local/share/gtk-doc/html", + "/usr/local/share/devhelp/books", + "/usr/share/gtk-doc/html", "/usr/share/devhelp/books", NULL + }; + char const ** p; + String * s; + +#ifdef DEBUG + fprintf(stderr, "DEBUG: %s(\"%s\", \"%s\")\n", __func__, gtkdocdir, + package); +#endif + for(p = prefix; gtkdocdir == NULL && *p != NULL; p++) + { + if((s = string_new_append(*p, "/", package, "/index.html", + NULL)) == NULL) + return -1; + ret = access(s, R_OK); + string_delete(s); + if(ret == 0) + break; + } + if(gtkdocdir != NULL) + p = >kdocdir; + if(*p == NULL) + return -1; + /* read the API documentation */ + if((s = string_new_append("file://", *p, "/", package, "/index.html", + NULL)) == NULL) + return -1; + ret = helper_open(helper, s); + string_delete(s); + return ret; +} + + +/* private */ +/* functions */ +/* new_gtkdoc */ +static gboolean _new_gtkdoc_idle(gpointer data); +static void _new_gtkdoc_package(Helper * helper, char const * gtkdocdir, + GtkTreeStore * store, char const * package); + +static void _new_gtkdoc(Helper * helper) +{ + GtkWidget * widget; + GtkTreeModel * model; + GtkCellRenderer * renderer; + GtkTreeViewColumn * column; + + widget = gtk_scrolled_window_new(NULL, NULL); + gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(widget), + GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); + model = gtk_tree_model_filter_new(GTK_TREE_MODEL(helper->store), NULL); + gtk_tree_model_filter_set_visible_func(GTK_TREE_MODEL_FILTER(model), + _helper_filter_gtkdoc, NULL, NULL); + model = gtk_tree_model_sort_new_with_model(model); + helper->gtkdoc = gtk_tree_view_new_with_model(model); + gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(helper->gtkdoc), FALSE); + gtk_tree_view_set_search_column(GTK_TREE_VIEW(helper->gtkdoc), + HSC_GTKDOC_PACKAGE); + renderer = gtk_cell_renderer_pixbuf_new(); + column = gtk_tree_view_column_new_with_attributes(NULL, renderer, + "pixbuf", HSC_ICON, NULL); + gtk_tree_view_append_column(GTK_TREE_VIEW(helper->gtkdoc), column); + renderer = gtk_cell_renderer_text_new(); + column = gtk_tree_view_column_new_with_attributes(_("Package"), + renderer, "text", HSC_GTKDOC_PACKAGE, NULL); + gtk_tree_view_column_set_sort_column_id(column, HSC_GTKDOC_PACKAGE); + gtk_tree_view_append_column(GTK_TREE_VIEW(helper->gtkdoc), column); + gtk_tree_view_column_clicked(column); + g_signal_connect(helper->gtkdoc, "row-activated", G_CALLBACK( + _helper_on_gtkdoc_row_activated), helper); + gtk_container_add(GTK_CONTAINER(widget), helper->gtkdoc); + gtk_notebook_append_page(GTK_NOTEBOOK(helper->notebook), widget, + gtk_label_new(_("API reference"))); + helper->source = g_idle_add(_new_gtkdoc_idle, helper); +} + +static gboolean _new_gtkdoc_idle(gpointer data) +{ + Helper * helper = data; + char const * p; + DIR * dir; + struct dirent * de; + + if(helper->p == NULL) + helper->p = _gtkdoc_prefix; + for(p = *(helper->p); p != NULL; (helper->p)++, p = *(helper->p)) + { + /* XXX avoid duplicates */ + if((helper->p != &_gtkdoc_prefix[0] + && strcmp(p, _gtkdoc_prefix[0]) == 0) + || (helper->p != &_gtkdoc_prefix[1] + && strcmp(p, _gtkdoc_prefix[1]) == 0)) + continue; + if((dir = opendir(p)) == NULL) + continue; + while((de = readdir(dir)) != NULL) + if(de->d_name[0] != '.') + _new_gtkdoc_package(helper, p, helper->store, + de->d_name); + closedir(dir); + (helper->p)++; + return TRUE; + } + helper->source = g_idle_add(_new_contents_idle, helper); + helper->p = NULL; + return FALSE; +} + +static void _new_gtkdoc_package(Helper * helper, char const * gtkdocdir, + GtkTreeStore * store, char const * package) +{ + gchar * p; + FILE * fp; + GtkTreeIter parent; + GtkTreeIter iter; + gint size = 16; + GdkPixbuf * pixbuf; + + if((p = g_strdup_printf("%s/%s/%s.devhelp2", gtkdocdir, package, + package)) == NULL) + return; + if((fp = fopen(p, "r")) == NULL) + { + _error(p, 1); + g_free(p); + if((p = g_strdup_printf("%s/%s/%s.devhelp", gtkdocdir, package, + package)) == NULL) + return; + } + if(fp == NULL && (fp = fopen(p, "r")) == NULL) + _error(p, 1); + g_free(p); + if(fp == NULL) + return; + gtk_icon_size_lookup(GTK_ICON_SIZE_MENU, &size, &size); + pixbuf = gtk_icon_theme_load_icon(helper->icontheme, "folder", size, 0, + NULL); +#if GTK_CHECK_VERSION(2, 10, 0) + gtk_tree_store_insert_with_values(store, &parent, NULL, -1, +#else + gtk_tree_store_insert(store, &parent, NULL, -1); + gtk_tree_store_set(store, &parent, +#endif + HSC_TYPE, HST_GTKDOC, HSC_ICON, pixbuf, + HSC_GTKDOC_PACKAGE, package, -1); + if(pixbuf != NULL) + { + g_object_unref(pixbuf); + pixbuf = NULL; + } + if(pixbuf == NULL) + pixbuf = gtk_icon_theme_load_icon(helper->icontheme, + "help-contents", size, 0, NULL); + /* FIXME parse the contents of the devhelp(2) file */ +#if GTK_CHECK_VERSION(2, 10, 0) + gtk_tree_store_insert_with_values(store, &iter, &parent, -1, +#else + gtk_tree_store_insert(store, &iter, &parent, -1); + gtk_tree_store_set(store, &iter, +#endif + HSC_TYPE, HST_GTKDOC, HSC_ICON, pixbuf, + HSC_GTKDOC_PACKAGE, package, + HSC_GTKDOC_DIRECTORY, gtkdocdir, -1); + if(pixbuf != NULL) + g_object_unref(pixbuf); + fclose(fp); +} + + +/* callbacks */ +/* helper_on_gtkdoc_row_activated */ +static void _helper_on_gtkdoc_row_activated(GtkWidget * widget, + GtkTreePath * path, GtkTreeViewColumn * column, gpointer data) +{ + Helper * helper = data; + GtkTreeModel * model; + GtkTreeIter iter; + GtkTreeIter parent; + gchar * package; + gchar * gtkdocdir; + + model = gtk_tree_view_get_model(GTK_TREE_VIEW(widget)); + gtk_tree_model_get_iter(model, &iter, path); + gtk_tree_model_sort_convert_iter_to_child_iter(GTK_TREE_MODEL_SORT( + model), &parent, &iter); + model = gtk_tree_model_sort_get_model(GTK_TREE_MODEL_SORT(model)); + gtk_tree_model_filter_convert_iter_to_child_iter(GTK_TREE_MODEL_FILTER( + model), &iter, &parent); + model = GTK_TREE_MODEL(helper->store); + if(gtk_tree_model_iter_parent(model, &parent, &iter) == FALSE) + { + if(gtk_tree_view_row_expanded(GTK_TREE_VIEW(widget), path)) + gtk_tree_view_collapse_row(GTK_TREE_VIEW(widget), path); + else + gtk_tree_view_expand_row(GTK_TREE_VIEW(widget), path, + FALSE); + return; + } + gtk_tree_model_get(model, &iter, HSC_GTKDOC_PACKAGE, &package, + HSC_GTKDOC_DIRECTORY, >kdocdir, -1); + helper_open_gtkdoc(helper, gtkdocdir, package); + g_free(package); + g_free(gtkdocdir); +} + + +/* helper_filter_gtkdoc */ +static gboolean _helper_filter_gtkdoc(GtkTreeModel * model, GtkTreeIter * iter, + gpointer data) +{ + unsigned int type; + + gtk_tree_model_get(model, iter, HSC_TYPE, &type, -1); + return (type == HST_GTKDOC) ? TRUE : FALSE; +} diff --git a/tools/backend/manual.c b/tools/backend/manual.c new file mode 100644 index 0000000..7e3fe65 --- /dev/null +++ b/tools/backend/manual.c @@ -0,0 +1,306 @@ +/* $Id$ */ +/* Copyright (c) 2015 Pierre Pronchery */ +/* This file is part of DeforaOS Desktop Surfer */ +/* 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, version 3 of the License. + * + * 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, see . */ + + + +/* public */ +/* prototypes */ +int helper_open_manual(Helper * helper, char const * section, char const * page, + char const * manhtmldir); + + +/* private */ +/* constants */ +static char const * _manual_prefix[] = { MANDIR, "/usr/share/man", NULL }; + + +/* prototypes */ +static void _new_manual(Helper * helper); + +/* callbacks */ +static void _helper_on_manual_row_activated(GtkWidget * widget, + GtkTreePath * path, GtkTreeViewColumn * column, gpointer data); + +/* filters */ +static gboolean _helper_filter_manual(GtkTreeModel * model, GtkTreeIter * iter, + gpointer data); + + +/* public */ +/* functions */ +/* helper_open_manual */ +int helper_open_manual(Helper * helper, char const * section, char const * page, + char const * manhtmldir) +{ + char const * prefix[] = + { + DATADIR "/man", PREFIX "/man", "/usr/local/share/man", + "/usr/local/man", "/usr/share/man", "/usr/man", NULL + }; + char const ** p; + char buf[256]; + +#ifdef DEBUG + fprintf(stderr, "DEBUG: %s(%d, \"%s\")\n", __func__, section, page); +#endif + if(section == NULL) + return -1; + if(manhtmldir != NULL) + p = &manhtmldir; + else + for(p = prefix; *p != NULL; p++) + { + snprintf(buf, sizeof(buf), "%s%s%s%s%s%s", *p, + "/html", section, "/", page, ".html"); + if(access(buf, R_OK) == 0) + break; + } + if(*p == NULL) + return -1; + /* read a manual page */ + snprintf(buf, sizeof(buf), "%s%s%s%s%s%s%s", "file://", *p, "/html", + section, "/", page, ".html"); + return helper_open(helper, buf); +} + + +/* private */ +/* functions */ +/* new_manual */ +static gboolean _new_manual_idle(gpointer data); +static void _new_manual_section(Helper * helper, char const * manhtmldir, + char const * name, GtkTreeStore * store, char const * section); +static void _new_manual_section_lookup(GtkTreeStore * store, GtkTreeIter * iter, + GdkPixbuf * pixbuf, char const * manhtmldir, + char const * section, char const * name); + +static void _new_manual(Helper * helper) +{ + GtkWidget * widget; + GtkTreeModel * model; + GtkCellRenderer * renderer; + GtkTreeViewColumn * column; + + /* FIXME fully implement, de-duplicate code if possible */ + widget = gtk_scrolled_window_new(NULL, NULL); + gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(widget), + GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); + model = gtk_tree_model_filter_new(GTK_TREE_MODEL(helper->store), NULL); + gtk_tree_model_filter_set_visible_func(GTK_TREE_MODEL_FILTER(model), + _helper_filter_manual, NULL, NULL); + model = gtk_tree_model_sort_new_with_model(model); + helper->manual = gtk_tree_view_new_with_model(model); + gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(helper->manual), FALSE); + gtk_tree_view_set_search_column(GTK_TREE_VIEW(helper->manual), + HSC_MANUAL_FILENAME); + renderer = gtk_cell_renderer_pixbuf_new(); + column = gtk_tree_view_column_new_with_attributes(NULL, renderer, + "pixbuf", HSC_ICON, NULL); + gtk_tree_view_append_column(GTK_TREE_VIEW(helper->manual), column); + renderer = gtk_cell_renderer_text_new(); + column = gtk_tree_view_column_new_with_attributes(_("Section"), + renderer, "text", HSC_MANUAL_FILENAME, NULL); + gtk_tree_view_column_set_sort_column_id(column, HSC_MANUAL_FILENAME); + gtk_tree_view_append_column(GTK_TREE_VIEW(helper->manual), column); + gtk_tree_view_column_clicked(column); + g_signal_connect(helper->manual, "row-activated", G_CALLBACK( + _helper_on_manual_row_activated), helper); + gtk_container_add(GTK_CONTAINER(widget), helper->manual); + gtk_notebook_append_page(GTK_NOTEBOOK(helper->notebook), widget, + gtk_label_new(_("Manual"))); +} + +static gboolean _new_manual_idle(gpointer data) +{ + Helper * helper = data; + char const * p; + DIR * dir; + struct dirent * de; + + if(helper->p == NULL) + helper->p = _manual_prefix; + for(p = *(helper->p); p != NULL; (helper->p)++, p = *(helper->p)) + { + /* XXX avoid duplicates */ + if((helper->p != &_manual_prefix[0] + && strcmp(p, _manual_prefix[0]) == 0) + || (helper->p != &_manual_prefix[1] + && strcmp(p, _manual_prefix[1]) == 0)) + continue; + if((dir = opendir(p)) == NULL) + continue; + while((de = readdir(dir)) != NULL) + if(strncasecmp(de->d_name, "html", 4) == 0 + && de->d_name[4] != '\0') + _new_manual_section(helper, p, de->d_name, + helper->store, &de->d_name[4]); + closedir(dir); + (helper->p)++; + return TRUE; + } + helper->source = 0; + helper->p = NULL; + return FALSE; +} + +static void _new_manual_section(Helper * helper, char const * manhtmldir, + char const * name, GtkTreeStore * store, char const * section) +{ + const char ext[] = ".html"; + gchar * p; + DIR * dir; + struct dirent * de; + size_t len; + GtkTreeIter parent; + GtkTreeIter iter; + gint size = 16; + GdkPixbuf * pixbuf; + + if((p = g_strdup_printf("%s/%s", manhtmldir, name)) == NULL) + return; + dir = opendir(p); + g_free(p); + if(dir == NULL) + return; + gtk_icon_size_lookup(GTK_ICON_SIZE_MENU, &size, &size); + pixbuf = gtk_icon_theme_load_icon(helper->icontheme, "folder", size, 0, + NULL); + _new_manual_section_lookup(store, &parent, pixbuf, manhtmldir, section, + name); + if(pixbuf != NULL) + { + g_object_unref(pixbuf); + pixbuf = NULL; + } + while((de = readdir(dir)) != NULL) + { + if(de->d_name[0] == '.' + || (len = strlen(de->d_name)) < sizeof(ext) + || strcmp(&de->d_name[len - sizeof(ext) + 1], + ext) != 0) + continue; + de->d_name[len - sizeof(ext) + 1] = '\0'; + if(pixbuf == NULL) + pixbuf = gtk_icon_theme_load_icon(helper->icontheme, + "help-contents", size, 0, NULL); +#if GTK_CHECK_VERSION(2, 10, 0) + gtk_tree_store_insert_with_values(store, &iter, &parent, -1, +#else + gtk_tree_store_insert(store, &iter, &parent, -1); + gtk_tree_store_set(store, &iter, +#endif + HSC_TYPE, HST_MANUAL, HSC_ICON, pixbuf, + HSC_MANUAL_DIRECTORY, manhtmldir, + HSC_MANUAL_SECTION, section, + HSC_MANUAL_FILENAME, de->d_name, -1); + } + closedir(dir); + if(pixbuf != NULL) + g_object_unref(pixbuf); +} + +static void _new_manual_section_lookup(GtkTreeStore * store, GtkTreeIter * iter, + GdkPixbuf * pixbuf, char const * manhtmldir, + char const * section, char const * name) +{ + GtkTreeModel * model = GTK_TREE_MODEL(store); + gboolean valid; + unsigned int type; + gchar * n; + int res; + + for(valid = gtk_tree_model_get_iter_first(model, iter); valid == TRUE; + valid = gtk_tree_model_iter_next(model, iter)) + { + gtk_tree_model_get(model, iter, HSC_TYPE, &type, -1); + if(type != HST_MANUAL) + continue; + gtk_tree_model_get(model, iter, HSC_MANUAL_FILENAME, &n, -1); + res = (n != NULL) && (strcmp(name, n) == 0); + g_free(n); + if(res != 0) + break; + } + if(valid == FALSE) + { +#if GTK_CHECK_VERSION(2, 10, 0) + gtk_tree_store_insert_with_values(store, iter, NULL, -1, +#else + gtk_tree_store_insert(store, iter, NULL, -1); + gtk_tree_store_set(store, iter, +#endif + HSC_TYPE, HST_MANUAL, HSC_ICON, pixbuf, + HSC_MANUAL_DIRECTORY, manhtmldir, + HSC_MANUAL_SECTION, section, + HSC_MANUAL_FILENAME, name, -1); + } + else + gtk_tree_store_set(store, iter, HSC_ICON, pixbuf, + HSC_MANUAL_DIRECTORY, manhtmldir, + HSC_MANUAL_SECTION, section, + HSC_MANUAL_FILENAME, name, -1); +} + + +/* callbacks */ +/* helper_on_manual_row_activated */ +static void _helper_on_manual_row_activated(GtkWidget * widget, + GtkTreePath * path, GtkTreeViewColumn * column, gpointer data) +{ + Helper * helper = data; + GtkTreeModel * model; + GtkTreeIter iter; + GtkTreeIter parent; + gchar * manhtmldir; + gchar * section; + gchar * command; + + model = gtk_tree_view_get_model(GTK_TREE_VIEW(widget)); + gtk_tree_model_get_iter(model, &iter, path); + gtk_tree_model_sort_convert_iter_to_child_iter(GTK_TREE_MODEL_SORT( + model), &parent, &iter); + model = gtk_tree_model_sort_get_model(GTK_TREE_MODEL_SORT(model)); + gtk_tree_model_filter_convert_iter_to_child_iter(GTK_TREE_MODEL_FILTER( + model), &iter, &parent); + model = GTK_TREE_MODEL(helper->store); + if(gtk_tree_model_iter_parent(model, &parent, &iter) == FALSE) + { + if(gtk_tree_view_row_expanded(GTK_TREE_VIEW(widget), path)) + gtk_tree_view_collapse_row(GTK_TREE_VIEW(widget), path); + else + gtk_tree_view_expand_row(GTK_TREE_VIEW(widget), path, + FALSE); + return; + } + gtk_tree_model_get(model, &iter, HSC_MANUAL_DIRECTORY, &manhtmldir, + HSC_MANUAL_SECTION, §ion, + HSC_MANUAL_FILENAME, &command, -1); + helper_open_manual(helper, section, command, manhtmldir); + g_free(manhtmldir); + g_free(section); + g_free(command); +} + + +/* filters */ +/* helper_filter_manual */ +static gboolean _helper_filter_manual(GtkTreeModel * model, GtkTreeIter * iter, + gpointer data) +{ + unsigned int type; + + gtk_tree_model_get(model, iter, HSC_TYPE, &type, -1); + return (type == HST_MANUAL) ? TRUE : FALSE; +} diff --git a/tools/backend/search.c b/tools/backend/search.c new file mode 100644 index 0000000..a6726af --- /dev/null +++ b/tools/backend/search.c @@ -0,0 +1,201 @@ +/* $Id$ */ +/* Copyright (c) 2015 Pierre Pronchery */ +/* This file is part of DeforaOS Desktop Surfer */ +/* 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, version 3 of the License. + * + * 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, see . */ + + + +/* private */ +/* prototypes */ +static void _new_search(Helper * helper); + + +/* callbacks */ +static void _helper_on_search(gpointer data); +static void _helper_on_search_row_activated(GtkWidget * widget, + GtkTreePath * path, GtkTreeViewColumn * column, gpointer data); + + +/* functions */ +/* new_search */ +static gboolean _new_search_filter(GtkTreeModel * model, GtkTreeIter * iter, + gpointer data); +static gboolean _new_search_filter_do(GtkTreeModel * model, GtkTreeIter * iter, + char const * search); +/* callbacks */ +#if GTK_CHECK_VERSION(2, 16, 0) +static void _new_search_on_clear(gpointer data); +#endif + +static void _new_search(Helper * helper) +{ + GtkWidget * vbox; + GtkWidget * hbox; + GtkWidget * widget; + GtkTreeModel * model; + GtkCellRenderer * renderer; + GtkTreeViewColumn * column; + +#if GTK_CHECK_VERSION(3, 0, 0) + vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 4); +#else + vbox = gtk_vbox_new(FALSE, 4); +#endif +#if GTK_CHECK_VERSION(3, 0, 0) + hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 4); +#else + hbox = gtk_hbox_new(FALSE, 4); +#endif + helper->entry = gtk_entry_new(); +#if GTK_CHECK_VERSION(2, 16, 0) + gtk_entry_set_icon_from_stock(GTK_ENTRY(helper->entry), + GTK_ENTRY_ICON_SECONDARY, GTK_STOCK_CLEAR); + g_signal_connect_swapped(helper->entry, "icon-press", G_CALLBACK( + _new_search_on_clear), helper); +#endif + g_signal_connect_swapped(helper->entry, "activate", G_CALLBACK( + _helper_on_search), helper); + gtk_box_pack_start(GTK_BOX(hbox), helper->entry, TRUE, TRUE, 0); + widget = gtk_button_new_with_mnemonic(_("_Search")); + g_signal_connect_swapped(widget, "clicked", G_CALLBACK( + _helper_on_search), helper); + gtk_box_pack_start(GTK_BOX(hbox), widget, FALSE, TRUE, 0); + gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, TRUE, 0); + widget = gtk_scrolled_window_new(NULL, NULL); + gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(widget), + GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); + model = gtk_tree_model_filter_new(GTK_TREE_MODEL(helper->store), NULL); + gtk_tree_model_filter_set_visible_func(GTK_TREE_MODEL_FILTER(model), + _new_search_filter, helper, NULL); + model = gtk_tree_model_sort_new_with_model(model); + helper->search = gtk_tree_view_new_with_model(model); + gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(helper->search), FALSE); + g_signal_connect(helper->search, "row-activated", G_CALLBACK( + _helper_on_search_row_activated), helper); + renderer = gtk_cell_renderer_pixbuf_new(); + column = gtk_tree_view_column_new_with_attributes(NULL, renderer, + "pixbuf", HSC_ICON, NULL); + gtk_tree_view_append_column(GTK_TREE_VIEW(helper->search), column); + renderer = gtk_cell_renderer_text_new(); + column = gtk_tree_view_column_new_with_attributes(NULL, renderer, + "text", HSC_DISPLAY, NULL); + gtk_tree_view_append_column(GTK_TREE_VIEW(helper->search), column); + gtk_container_add(GTK_CONTAINER(widget), helper->search); + gtk_box_pack_start(GTK_BOX(vbox), widget, TRUE, TRUE, 0); + gtk_notebook_append_page(GTK_NOTEBOOK(helper->notebook), vbox, + gtk_label_new(_("Search"))); +} + +static gboolean _new_search_filter(GtkTreeModel * model, GtkTreeIter * iter, + gpointer data) +{ + Helper * helper = data; + char const * search; + GtkTreeIter child; + gboolean valid; + + if((search = gtk_entry_get_text(GTK_ENTRY(helper->entry))) == NULL + || strlen(search) == 0) + return FALSE; + if(_new_search_filter_do(model, iter, search) == TRUE) + return TRUE; + for(valid = gtk_tree_model_iter_children(model, &child, iter); + valid == TRUE; + valid = gtk_tree_model_iter_next(model, &child)) + if(_new_search_filter_do(model, &child, search) == TRUE) + return TRUE; + return FALSE; +} + +static gboolean _new_search_filter_do(GtkTreeModel * model, GtkTreeIter * iter, + char const * search) +{ + gboolean ret; + char * display; + + gtk_tree_model_get(model, iter, HSC_DISPLAY, &display, -1); + if(display == NULL) + return FALSE; + ret = (strlen(display) > 0 && strcasestr(display, search) != NULL) + ? TRUE : FALSE; + g_free(display); + return ret; +} + +#if GTK_CHECK_VERSION(2, 16, 0) +static void _new_search_on_clear(gpointer data) +{ + Helper * helper = data; + + gtk_entry_set_text(GTK_ENTRY(helper->entry), ""); +} +#endif + + +/* callbacks */ +/* helper_on_search */ +static void _helper_on_search(gpointer data) +{ + Helper * helper = data; + GtkTreeModel * model; + + model = gtk_tree_view_get_model(GTK_TREE_VIEW(helper->search)); + model = gtk_tree_model_sort_get_model(GTK_TREE_MODEL_SORT(model)); + gtk_tree_model_filter_refilter(GTK_TREE_MODEL_FILTER(model)); +} + + +/* helper_on_search_row_activated */ +static void _helper_on_search_row_activated(GtkWidget * widget, + GtkTreePath * path, GtkTreeViewColumn * column, gpointer data) +{ + Helper * helper = data; + GtkTreeModel * model; + GtkTreeIter iter; + GtkTreeIter parent; + unsigned int type; + + model = gtk_tree_view_get_model(GTK_TREE_VIEW(widget)); + gtk_tree_model_get_iter(model, &iter, path); + gtk_tree_model_sort_convert_iter_to_child_iter(GTK_TREE_MODEL_SORT( + model), &parent, &iter); + model = gtk_tree_model_sort_get_model(GTK_TREE_MODEL_SORT(model)); + gtk_tree_model_filter_convert_iter_to_child_iter(GTK_TREE_MODEL_FILTER( + model), &iter, &parent); + model = GTK_TREE_MODEL(helper->store); + if(gtk_tree_model_iter_parent(model, &parent, &iter) == FALSE) + { + if(gtk_tree_view_row_expanded(GTK_TREE_VIEW(widget), path)) + gtk_tree_view_collapse_row(GTK_TREE_VIEW(widget), path); + else + gtk_tree_view_expand_row(GTK_TREE_VIEW(widget), path, + FALSE); + return; + } + gtk_tree_model_get(model, &iter, HSC_TYPE, &type, -1); + switch(type) + { + case HST_CONTENTS: + _helper_on_contents_row_activated(widget, path, column, + helper); + break; + case HST_GTKDOC: + _helper_on_gtkdoc_row_activated(widget, path, column, + helper); + break; + case HST_MANUAL: + _helper_on_manual_row_activated(widget, path, column, + helper); + break; + } +} diff --git a/tools/helper-main.c b/tools/helper-main.c new file mode 100644 index 0000000..73560fb --- /dev/null +++ b/tools/helper-main.c @@ -0,0 +1,117 @@ +/* $Id$ */ +/* Copyright (c) 2015 Pierre Pronchery */ +/* This file is part of DeforaOS Desktop Surfer */ +/* 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, version 3 of the License. + * + * 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, see . */ + + + +#include +#include +#include +#include +#include +#include "helper.h" +#include "../config.h" +#define _(string) gettext(string) +#define N_(string) string + +/* constants */ +#ifndef PROGNAME +# define PROGNAME "helper" +#endif +#ifndef PREFIX +# define PREFIX "/usr/local" +#endif +#ifndef DATADIR +# define DATADIR PREFIX "/share" +#endif +#ifndef LOCALEDIR +# define LOCALEDIR DATADIR "/locale" +#endif + + +/* helper */ +/* private */ +/* prototypes */ +static int _usage(void); + + +/* functions */ +/* usage */ +static int _usage(void) +{ + fprintf(stderr, _("Usage: %s [-c][-p package] command\n" +" %s -d package\n" +" %s -s section page\n" +" -d Open an API reference\n" +" -s Section of the manual page to read from\n"), + PROGNAME, PROGNAME, PROGNAME); + return 1; +} + + +/* public */ +/* functions */ +/* main */ +int main(int argc, char * argv[]) +{ + int o; + int devel = 0; + char const * package = NULL; + char const * section = NULL; + Helper * helper; + + if(setlocale(LC_ALL, "") == NULL) + helper_error(NULL, "setlocale", 1); + bindtextdomain(PACKAGE, LOCALEDIR); + textdomain(PACKAGE); +#if defined(WITH_GTKHTML) || defined(WITH_GTKTEXTVIEW) || defined(WITH_WEBKIT) + if(g_thread_supported() == FALSE) + g_thread_init(NULL); +#endif + gtk_init(&argc, &argv); + while((o = getopt(argc, argv, "cdp:s:")) != -1) + switch(o) + { + case 'c': + section = NULL; + devel = 0; + break; + case 'd': + section = NULL; + devel = 1; + break; + case 'p': + package = optarg; + break; + case 's': + section = optarg; + break; + default: + return _usage(); + } + if(optind != argc && (optind + 1) != argc) + return _usage(); + if((helper = helper_new()) == NULL) + return 2; + if(section != NULL) + helper_open_manual(helper, section, argv[optind], NULL); + else if(argv[optind] != NULL && devel != 0) + helper_open_gtkdoc(helper, NULL, argv[optind]); + else if(argv[optind] != NULL) + helper_open_contents(helper, (package != NULL) ? package + : argv[optind], argv[optind]); + gtk_main(); + helper_delete(helper); + return 0; +} diff --git a/tools/helper.c b/tools/helper.c index f4e5b14..d194bfe 100644 --- a/tools/helper.c +++ b/tools/helper.c @@ -30,6 +30,7 @@ static char const _license[] = #include #include "ghtml.h" #include +#include "helper.h" #include "../config.h" #define _(string) gettext(string) #define N_(string) string @@ -50,15 +51,12 @@ static char const _license[] = #ifndef MANDIR # define MANDIR DATADIR "/man" #endif -#ifndef LOCALEDIR -# define LOCALEDIR DATADIR "/locale" -#endif /* helper */ /* private */ /* types */ -typedef struct _Surfer +struct _Surfer { guint source; char const ** p; @@ -89,7 +87,7 @@ typedef struct _Surfer /* about */ GtkWidget * ab_window; -} Helper; +}; typedef enum _HelperStoreType { @@ -115,20 +113,7 @@ typedef enum _HelperStoreColumn /* prototypes */ -static Helper * _helper_new(void); -void _helper_delete(Helper * helper); - -static int _helper_open(Helper * helper, char const * url); -static int _helper_open_contents(Helper * helper, char const * package, - char const * command); -static int _helper_open_dialog(Helper * helper); -static int _helper_open_gtkdoc(Helper * helper, char const * gtkdocdir, - char const * package); -static int _helper_open_man(Helper * helper, char const * section, - char const * page, char const * manhtmldir); - static int _error(char const * message, int ret); -static int _usage(void); /* callbacks */ static void _helper_on_back(gpointer data); @@ -150,15 +135,6 @@ static void _helper_on_fullscreen(gpointer data); static void _helper_on_help_about(gpointer data); static void _helper_on_help_contents(gpointer data); #endif -static void _helper_on_contents_row_activated(GtkWidget * widget, - GtkTreePath * path, GtkTreeViewColumn * column, gpointer data); -static void _helper_on_gtkdoc_row_activated(GtkWidget * widget, - GtkTreePath * path, GtkTreeViewColumn * column, gpointer data); -static void _helper_on_manual_row_activated(GtkWidget * widget, - GtkTreePath * path, GtkTreeViewColumn * column, gpointer data); -static void _helper_on_search(gpointer data); -static void _helper_on_search_row_activated(GtkWidget * widget, - GtkTreePath * path, GtkTreeViewColumn * column, gpointer data); #ifdef EMBEDDED static void _helper_on_open(gpointer data); #endif @@ -166,13 +142,10 @@ static void _helper_on_open(gpointer data); static void _helper_on_view_fullscreen(gpointer data); #endif -/* filters */ -static gboolean _helper_filter_contents(GtkTreeModel * model, - GtkTreeIter * iter, gpointer data); -static gboolean _helper_filter_gtkdoc(GtkTreeModel * model, GtkTreeIter * iter, - gpointer data); -static gboolean _helper_filter_manual(GtkTreeModel * model, GtkTreeIter * iter, - gpointer data); +#include "backend/manual.c" +#include "backend/contents.c" +#include "backend/gtkdoc.c" +#include "backend/search.c" /* constants */ @@ -270,47 +243,11 @@ static const DesktopMenubar _helper_menubar[] = }; #endif -static char const * _gtkdoc_prefix[] = -{ - /* FIXME look into more directories */ - DATADIR "/gtk-doc/html", DATADIR "/devhelp/books", - "/usr/local/share/gtk-doc/html", - "/usr/local/share/devhelp/books", - "/usr/share/gtk-doc/html", "/usr/share/devhelp/books", NULL -}; - -static char const * _manual_prefix[] = { MANDIR, "/usr/share/man", NULL }; - /* functions */ /* Helper */ /* helper_new */ -static void _new_contents(Helper * helper); -static gboolean _new_contents_idle(gpointer data); -static void _new_contents_package(Helper * helper, char const * contentsdir, - GtkTreeStore * store, char const * package); -static void _new_gtkdoc(Helper * helper); -static gboolean _new_gtkdoc_idle(gpointer data); -static void _new_gtkdoc_package(Helper * helper, char const * gtkdocdir, - GtkTreeStore * store, char const * package); -static void _new_manual(Helper * helper); -static gboolean _new_manual_idle(gpointer data); -static void _new_manual_section(Helper * helper, char const * manhtmldir, - char const * name, GtkTreeStore * store, char const * section); -static void _new_manual_section_lookup(GtkTreeStore * store, GtkTreeIter * iter, - GdkPixbuf * pixbuf, char const * manhtmldir, - char const * section, char const * name); -static void _new_search(Helper * helper); -static gboolean _new_search_filter(GtkTreeModel * model, GtkTreeIter * iter, - gpointer data); -static gboolean _new_search_filter_do(GtkTreeModel * model, GtkTreeIter * iter, - char const * search); -/* callbacks */ -#if GTK_CHECK_VERSION(2, 16, 0) -static void _new_search_on_clear(gpointer data); -#endif - -static Helper * _helper_new(void) +Helper * helper_new(void) { Helper * helper; GtkAccelGroup * group; @@ -405,522 +342,9 @@ static Helper * _helper_new(void) return helper; } -static void _new_contents(Helper * helper) -{ - GtkWidget * widget; - GtkTreeModel * model; - GtkCellRenderer * renderer; - GtkTreeViewColumn * column; - - widget = gtk_scrolled_window_new(NULL, NULL); - gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(widget), - GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); - model = gtk_tree_model_filter_new(GTK_TREE_MODEL(helper->store), NULL); - gtk_tree_model_filter_set_visible_func(GTK_TREE_MODEL_FILTER(model), - _helper_filter_contents, NULL, NULL); - model = gtk_tree_model_sort_new_with_model(model); - helper->contents = gtk_tree_view_new_with_model(model); - gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(helper->contents), - FALSE); - gtk_tree_view_set_search_column(GTK_TREE_VIEW(helper->contents), - HSC_CONTENTS_PACKAGE); - renderer = gtk_cell_renderer_pixbuf_new(); - column = gtk_tree_view_column_new_with_attributes(NULL, renderer, - "pixbuf", HSC_ICON, NULL); - gtk_tree_view_append_column(GTK_TREE_VIEW(helper->contents), column); - renderer = gtk_cell_renderer_text_new(); - column = gtk_tree_view_column_new_with_attributes(_("Package"), - renderer, "text", HSC_CONTENTS_PACKAGE, NULL); - gtk_tree_view_column_set_sort_column_id(column, HSC_CONTENTS_PACKAGE); - gtk_tree_view_append_column(GTK_TREE_VIEW(helper->contents), column); - gtk_tree_view_column_clicked(column); - g_signal_connect(helper->contents, "row-activated", G_CALLBACK( - _helper_on_contents_row_activated), helper); - gtk_container_add(GTK_CONTAINER(widget), helper->contents); - gtk_notebook_append_page(GTK_NOTEBOOK(helper->notebook), widget, - gtk_label_new(_("Contents"))); -} - -static gboolean _new_contents_idle(gpointer data) -{ - Helper * helper = data; - DIR * dir; - struct dirent * de; - - helper->source = g_idle_add(_new_manual_idle, helper); - helper->p = NULL; - if((dir = opendir(CONTENTSDIR)) == NULL) - return FALSE; - while((de = readdir(dir)) != NULL) - if(de->d_name[0] != '.') - _new_contents_package(helper, CONTENTSDIR, - helper->store, de->d_name); - closedir(dir); - return FALSE; -} - -static void _new_contents_package(Helper * helper, char const * contentsdir, - GtkTreeStore * store, char const * package) -{ - const char ext[] = ".html"; - gchar * p; - DIR * dir; - struct dirent * de; - size_t len; - GtkTreeIter parent; - GtkTreeIter iter; - gint size = 16; - GdkPixbuf * pixbuf; - - if((p = g_strdup_printf("%s/%s", contentsdir, package)) == NULL) - return; - dir = opendir(p); - g_free(p); - if(dir == NULL) - return; - gtk_icon_size_lookup(GTK_ICON_SIZE_MENU, &size, &size); - pixbuf = gtk_icon_theme_load_icon(helper->icontheme, "folder", size, 0, - NULL); -#if GTK_CHECK_VERSION(2, 10, 0) - gtk_tree_store_insert_with_values(store, &parent, NULL, -1, -#else - gtk_tree_store_insert(store, &parent, NULL, -1); - gtk_tree_store_set(store, &parent, -#endif - HSC_TYPE, HST_CONTENTS, HSC_ICON, pixbuf, - HSC_CONTENTS_PACKAGE, package, -1); - if(pixbuf != NULL) - { - g_object_unref(pixbuf); - pixbuf = NULL; - } - while((de = readdir(dir)) != NULL) - { - if(de->d_name[0] == '.' - || (len = strlen(de->d_name)) < sizeof(ext) - || strcmp(&de->d_name[len - sizeof(ext) + 1], - ext) != 0) - continue; - de->d_name[len - sizeof(ext) + 1] = '\0'; - if(pixbuf == NULL) - pixbuf = gtk_icon_theme_load_icon(helper->icontheme, - "help-contents", size, 0, NULL); -#if GTK_CHECK_VERSION(2, 10, 0) - gtk_tree_store_insert_with_values(store, &iter, &parent, -1, -#else - gtk_tree_store_insert(store, &iter, &parent, -1); - gtk_tree_store_set(store, &iter, -#endif - HSC_TYPE, HST_CONTENTS, HSC_ICON, pixbuf, - HSC_CONTENTS_PACKAGE, de->d_name, -1); - } - closedir(dir); - if(pixbuf != NULL) - g_object_unref(pixbuf); -} - -static void _new_gtkdoc(Helper * helper) -{ - GtkWidget * widget; - GtkTreeModel * model; - GtkCellRenderer * renderer; - GtkTreeViewColumn * column; - - widget = gtk_scrolled_window_new(NULL, NULL); - gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(widget), - GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); - model = gtk_tree_model_filter_new(GTK_TREE_MODEL(helper->store), NULL); - gtk_tree_model_filter_set_visible_func(GTK_TREE_MODEL_FILTER(model), - _helper_filter_gtkdoc, NULL, NULL); - model = gtk_tree_model_sort_new_with_model(model); - helper->gtkdoc = gtk_tree_view_new_with_model(model); - gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(helper->gtkdoc), FALSE); - gtk_tree_view_set_search_column(GTK_TREE_VIEW(helper->gtkdoc), - HSC_GTKDOC_PACKAGE); - renderer = gtk_cell_renderer_pixbuf_new(); - column = gtk_tree_view_column_new_with_attributes(NULL, renderer, - "pixbuf", HSC_ICON, NULL); - gtk_tree_view_append_column(GTK_TREE_VIEW(helper->gtkdoc), column); - renderer = gtk_cell_renderer_text_new(); - column = gtk_tree_view_column_new_with_attributes(_("Package"), - renderer, "text", HSC_GTKDOC_PACKAGE, NULL); - gtk_tree_view_column_set_sort_column_id(column, HSC_GTKDOC_PACKAGE); - gtk_tree_view_append_column(GTK_TREE_VIEW(helper->gtkdoc), column); - gtk_tree_view_column_clicked(column); - g_signal_connect(helper->gtkdoc, "row-activated", G_CALLBACK( - _helper_on_gtkdoc_row_activated), helper); - gtk_container_add(GTK_CONTAINER(widget), helper->gtkdoc); - gtk_notebook_append_page(GTK_NOTEBOOK(helper->notebook), widget, - gtk_label_new(_("API reference"))); - helper->source = g_idle_add(_new_gtkdoc_idle, helper); -} - -static gboolean _new_gtkdoc_idle(gpointer data) -{ - Helper * helper = data; - char const * p; - DIR * dir; - struct dirent * de; - - if(helper->p == NULL) - helper->p = _gtkdoc_prefix; - for(p = *(helper->p); p != NULL; (helper->p)++, p = *(helper->p)) - { - /* XXX avoid duplicates */ - if((helper->p != &_gtkdoc_prefix[0] - && strcmp(p, _gtkdoc_prefix[0]) == 0) - || (helper->p != &_gtkdoc_prefix[1] - && strcmp(p, _gtkdoc_prefix[1]) == 0)) - continue; - if((dir = opendir(p)) == NULL) - continue; - while((de = readdir(dir)) != NULL) - if(de->d_name[0] != '.') - _new_gtkdoc_package(helper, p, helper->store, - de->d_name); - closedir(dir); - (helper->p)++; - return TRUE; - } - helper->source = g_idle_add(_new_contents_idle, helper); - helper->p = NULL; - return FALSE; -} - -static void _new_gtkdoc_package(Helper * helper, char const * gtkdocdir, - GtkTreeStore * store, char const * package) -{ - gchar * p; - FILE * fp; - GtkTreeIter parent; - GtkTreeIter iter; - gint size = 16; - GdkPixbuf * pixbuf; - - if((p = g_strdup_printf("%s/%s/%s.devhelp2", gtkdocdir, package, - package)) == NULL) - return; - if((fp = fopen(p, "r")) == NULL) - { - _error(p, 1); - g_free(p); - if((p = g_strdup_printf("%s/%s/%s.devhelp", gtkdocdir, package, - package)) == NULL) - return; - } - if(fp == NULL && (fp = fopen(p, "r")) == NULL) - _error(p, 1); - g_free(p); - if(fp == NULL) - return; - gtk_icon_size_lookup(GTK_ICON_SIZE_MENU, &size, &size); - pixbuf = gtk_icon_theme_load_icon(helper->icontheme, "folder", size, 0, - NULL); -#if GTK_CHECK_VERSION(2, 10, 0) - gtk_tree_store_insert_with_values(store, &parent, NULL, -1, -#else - gtk_tree_store_insert(store, &parent, NULL, -1); - gtk_tree_store_set(store, &parent, -#endif - HSC_TYPE, HST_GTKDOC, HSC_ICON, pixbuf, - HSC_GTKDOC_PACKAGE, package, -1); - if(pixbuf != NULL) - { - g_object_unref(pixbuf); - pixbuf = NULL; - } - if(pixbuf == NULL) - pixbuf = gtk_icon_theme_load_icon(helper->icontheme, - "help-contents", size, 0, NULL); - /* FIXME parse the contents of the devhelp(2) file */ -#if GTK_CHECK_VERSION(2, 10, 0) - gtk_tree_store_insert_with_values(store, &iter, &parent, -1, -#else - gtk_tree_store_insert(store, &iter, &parent, -1); - gtk_tree_store_set(store, &iter, -#endif - HSC_TYPE, HST_GTKDOC, HSC_ICON, pixbuf, - HSC_GTKDOC_PACKAGE, package, - HSC_GTKDOC_DIRECTORY, gtkdocdir, -1); - if(pixbuf != NULL) - g_object_unref(pixbuf); - fclose(fp); -} - -static void _new_manual(Helper * helper) -{ - GtkWidget * widget; - GtkTreeModel * model; - GtkCellRenderer * renderer; - GtkTreeViewColumn * column; - - /* FIXME fully implement, de-duplicate code if possible */ - widget = gtk_scrolled_window_new(NULL, NULL); - gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(widget), - GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); - model = gtk_tree_model_filter_new(GTK_TREE_MODEL(helper->store), NULL); - gtk_tree_model_filter_set_visible_func(GTK_TREE_MODEL_FILTER(model), - _helper_filter_manual, NULL, NULL); - model = gtk_tree_model_sort_new_with_model(model); - helper->manual = gtk_tree_view_new_with_model(model); - gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(helper->manual), FALSE); - gtk_tree_view_set_search_column(GTK_TREE_VIEW(helper->manual), - HSC_MANUAL_FILENAME); - renderer = gtk_cell_renderer_pixbuf_new(); - column = gtk_tree_view_column_new_with_attributes(NULL, renderer, - "pixbuf", HSC_ICON, NULL); - gtk_tree_view_append_column(GTK_TREE_VIEW(helper->manual), column); - renderer = gtk_cell_renderer_text_new(); - column = gtk_tree_view_column_new_with_attributes(_("Section"), - renderer, "text", HSC_MANUAL_FILENAME, NULL); - gtk_tree_view_column_set_sort_column_id(column, HSC_MANUAL_FILENAME); - gtk_tree_view_append_column(GTK_TREE_VIEW(helper->manual), column); - gtk_tree_view_column_clicked(column); - g_signal_connect(helper->manual, "row-activated", G_CALLBACK( - _helper_on_manual_row_activated), helper); - gtk_container_add(GTK_CONTAINER(widget), helper->manual); - gtk_notebook_append_page(GTK_NOTEBOOK(helper->notebook), widget, - gtk_label_new(_("Manual"))); -} - -static gboolean _new_manual_idle(gpointer data) -{ - Helper * helper = data; - char const * p; - DIR * dir; - struct dirent * de; - - if(helper->p == NULL) - helper->p = _manual_prefix; - for(p = *(helper->p); p != NULL; (helper->p)++, p = *(helper->p)) - { - /* XXX avoid duplicates */ - if((helper->p != &_manual_prefix[0] - && strcmp(p, _manual_prefix[0]) == 0) - || (helper->p != &_manual_prefix[1] - && strcmp(p, _manual_prefix[1]) == 0)) - continue; - if((dir = opendir(p)) == NULL) - continue; - while((de = readdir(dir)) != NULL) - if(strncasecmp(de->d_name, "html", 4) == 0 - && de->d_name[4] != '\0') - _new_manual_section(helper, p, de->d_name, - helper->store, &de->d_name[4]); - closedir(dir); - (helper->p)++; - return TRUE; - } - helper->source = 0; - helper->p = NULL; - return FALSE; -} - -static void _new_manual_section(Helper * helper, char const * manhtmldir, - char const * name, GtkTreeStore * store, char const * section) -{ - const char ext[] = ".html"; - gchar * p; - DIR * dir; - struct dirent * de; - size_t len; - GtkTreeIter parent; - GtkTreeIter iter; - gint size = 16; - GdkPixbuf * pixbuf; - - if((p = g_strdup_printf("%s/%s", manhtmldir, name)) == NULL) - return; - dir = opendir(p); - g_free(p); - if(dir == NULL) - return; - gtk_icon_size_lookup(GTK_ICON_SIZE_MENU, &size, &size); - pixbuf = gtk_icon_theme_load_icon(helper->icontheme, "folder", size, 0, - NULL); - _new_manual_section_lookup(store, &parent, pixbuf, manhtmldir, section, - name); - if(pixbuf != NULL) - { - g_object_unref(pixbuf); - pixbuf = NULL; - } - while((de = readdir(dir)) != NULL) - { - if(de->d_name[0] == '.' - || (len = strlen(de->d_name)) < sizeof(ext) - || strcmp(&de->d_name[len - sizeof(ext) + 1], - ext) != 0) - continue; - de->d_name[len - sizeof(ext) + 1] = '\0'; - if(pixbuf == NULL) - pixbuf = gtk_icon_theme_load_icon(helper->icontheme, - "help-contents", size, 0, NULL); -#if GTK_CHECK_VERSION(2, 10, 0) - gtk_tree_store_insert_with_values(store, &iter, &parent, -1, -#else - gtk_tree_store_insert(store, &iter, &parent, -1); - gtk_tree_store_set(store, &iter, -#endif - HSC_TYPE, HST_MANUAL, HSC_ICON, pixbuf, - HSC_MANUAL_DIRECTORY, manhtmldir, - HSC_MANUAL_SECTION, section, - HSC_MANUAL_FILENAME, de->d_name, -1); - } - closedir(dir); - if(pixbuf != NULL) - g_object_unref(pixbuf); -} - -static void _new_manual_section_lookup(GtkTreeStore * store, GtkTreeIter * iter, - GdkPixbuf * pixbuf, char const * manhtmldir, - char const * section, char const * name) -{ - GtkTreeModel * model = GTK_TREE_MODEL(store); - gboolean valid; - unsigned int type; - gchar * n; - int res; - - for(valid = gtk_tree_model_get_iter_first(model, iter); valid == TRUE; - valid = gtk_tree_model_iter_next(model, iter)) - { - gtk_tree_model_get(model, iter, HSC_TYPE, &type, -1); - if(type != HST_MANUAL) - continue; - gtk_tree_model_get(model, iter, HSC_MANUAL_FILENAME, &n, -1); - res = (n != NULL) && (strcmp(name, n) == 0); - g_free(n); - if(res != 0) - break; - } - if(valid == FALSE) - { -#if GTK_CHECK_VERSION(2, 10, 0) - gtk_tree_store_insert_with_values(store, iter, NULL, -1, -#else - gtk_tree_store_insert(store, iter, NULL, -1); - gtk_tree_store_set(store, iter, -#endif - HSC_TYPE, HST_MANUAL, HSC_ICON, pixbuf, - HSC_MANUAL_DIRECTORY, manhtmldir, - HSC_MANUAL_SECTION, section, - HSC_MANUAL_FILENAME, name, -1); - } - else - gtk_tree_store_set(store, iter, HSC_ICON, pixbuf, - HSC_MANUAL_DIRECTORY, manhtmldir, - HSC_MANUAL_SECTION, section, - HSC_MANUAL_FILENAME, name, -1); -} - -static void _new_search(Helper * helper) -{ - GtkWidget * vbox; - GtkWidget * hbox; - GtkWidget * widget; - GtkTreeModel * model; - GtkCellRenderer * renderer; - GtkTreeViewColumn * column; - -#if GTK_CHECK_VERSION(3, 0, 0) - vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 4); -#else - vbox = gtk_vbox_new(FALSE, 4); -#endif -#if GTK_CHECK_VERSION(3, 0, 0) - hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 4); -#else - hbox = gtk_hbox_new(FALSE, 4); -#endif - helper->entry = gtk_entry_new(); -#if GTK_CHECK_VERSION(2, 16, 0) - gtk_entry_set_icon_from_stock(GTK_ENTRY(helper->entry), - GTK_ENTRY_ICON_SECONDARY, GTK_STOCK_CLEAR); - g_signal_connect_swapped(helper->entry, "icon-press", G_CALLBACK( - _new_search_on_clear), helper); -#endif - g_signal_connect_swapped(helper->entry, "activate", G_CALLBACK( - _helper_on_search), helper); - gtk_box_pack_start(GTK_BOX(hbox), helper->entry, TRUE, TRUE, 0); - widget = gtk_button_new_with_mnemonic(_("_Search")); - g_signal_connect_swapped(widget, "clicked", G_CALLBACK( - _helper_on_search), helper); - gtk_box_pack_start(GTK_BOX(hbox), widget, FALSE, TRUE, 0); - gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, TRUE, 0); - widget = gtk_scrolled_window_new(NULL, NULL); - gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(widget), - GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); - model = gtk_tree_model_filter_new(GTK_TREE_MODEL(helper->store), NULL); - gtk_tree_model_filter_set_visible_func(GTK_TREE_MODEL_FILTER(model), - _new_search_filter, helper, NULL); - model = gtk_tree_model_sort_new_with_model(model); - helper->search = gtk_tree_view_new_with_model(model); - gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(helper->search), FALSE); - g_signal_connect(helper->search, "row-activated", G_CALLBACK( - _helper_on_search_row_activated), helper); - renderer = gtk_cell_renderer_pixbuf_new(); - column = gtk_tree_view_column_new_with_attributes(NULL, renderer, - "pixbuf", HSC_ICON, NULL); - gtk_tree_view_append_column(GTK_TREE_VIEW(helper->search), column); - renderer = gtk_cell_renderer_text_new(); - column = gtk_tree_view_column_new_with_attributes(NULL, renderer, - "text", HSC_DISPLAY, NULL); - gtk_tree_view_append_column(GTK_TREE_VIEW(helper->search), column); - gtk_container_add(GTK_CONTAINER(widget), helper->search); - gtk_box_pack_start(GTK_BOX(vbox), widget, TRUE, TRUE, 0); - gtk_notebook_append_page(GTK_NOTEBOOK(helper->notebook), vbox, - gtk_label_new(_("Search"))); -} - -static gboolean _new_search_filter(GtkTreeModel * model, GtkTreeIter * iter, - gpointer data) -{ - Helper * helper = data; - char const * search; - GtkTreeIter child; - gboolean valid; - - if((search = gtk_entry_get_text(GTK_ENTRY(helper->entry))) == NULL - || strlen(search) == 0) - return FALSE; - if(_new_search_filter_do(model, iter, search) == TRUE) - return TRUE; - for(valid = gtk_tree_model_iter_children(model, &child, iter); - valid == TRUE; - valid = gtk_tree_model_iter_next(model, &child)) - if(_new_search_filter_do(model, &child, search) == TRUE) - return TRUE; - return FALSE; -} - -static gboolean _new_search_filter_do(GtkTreeModel * model, GtkTreeIter * iter, - char const * search) -{ - gboolean ret; - char * display; - - gtk_tree_model_get(model, iter, HSC_DISPLAY, &display, -1); - if(display == NULL) - return FALSE; - ret = (strlen(display) > 0 && strcasestr(display, search) != NULL) - ? TRUE : FALSE; - g_free(display); - return ret; -} - -#if GTK_CHECK_VERSION(2, 16, 0) -static void _new_search_on_clear(gpointer data) -{ - Helper * helper = data; - - gtk_entry_set_text(GTK_ENTRY(helper->entry), ""); -} -#endif - /* helper_delete */ -void _helper_delete(Helper * helper) +void helper_delete(Helper * helper) { if(helper->source != 0) g_source_remove(helper->source); @@ -934,40 +358,30 @@ void _helper_delete(Helper * helper) /* useful */ +/* helper_error */ +int helper_error(Helper * helper, char const * message, int ret) +{ + return surfer_error(helper, message, ret); +} + + /* helper_open */ -static int _helper_open(Helper * helper, char const * url) +int helper_open(Helper * helper, char const * url) { #ifdef DEBUG fprintf(stderr, "DEBUG: %s(\"%s\")\n", __func__, url); #endif if(url == NULL) - return _helper_open_dialog(helper); + return helper_open_dialog(helper); ghtml_load_url(helper->view, url); return 0; } -/* helper_open_contents */ -static int _helper_open_contents(Helper * helper, char const * package, - char const * command) -{ - char buf[256]; - - if(package == NULL) - return -1; - if(command == NULL) - command = "index"; - /* read a package documentation */ - snprintf(buf, sizeof(buf), "%s%s%s%s%s", "file://" CONTENTSDIR "/", - package, "/", command, ".html"); - return _helper_open(helper, buf); -} - - /* helper_open_dialog */ static void _open_dialog_on_entry1_changed(GtkWidget * widget, gpointer data); -static int _helper_open_dialog(Helper * helper) +int helper_open_dialog(Helper * helper) { int ret; GtkSizeGroup * lgroup; @@ -1050,7 +464,7 @@ static int _helper_open_dialog(Helper * helper) if(package == NULL || strlen(package) == 0) ret = -1; else - ret = _helper_open_contents(helper, package, command); + ret = helper_open_contents(helper, package, command); gtk_widget_destroy(dialog); return ret; } @@ -1081,85 +495,6 @@ static void _open_dialog_on_entry1_changed(GtkWidget * widget, gpointer data) } -/* helper_open_gtkdoc */ -static int _helper_open_gtkdoc(Helper * helper, char const * gtkdocdir, - char const * package) -{ - int ret; - char const * prefix[] = - { - DATADIR "/gtk-doc/html", DATADIR "/devhelp/books", - "/usr/local/share/gtk-doc/html", - "/usr/local/share/devhelp/books", - "/usr/share/gtk-doc/html", "/usr/share/devhelp/books", NULL - }; - char const ** p; - String * s; - -#ifdef DEBUG - fprintf(stderr, "DEBUG: %s(\"%s\", \"%s\")\n", __func__, gtkdocdir, - package); -#endif - for(p = prefix; gtkdocdir == NULL && *p != NULL; p++) - { - if((s = string_new_append(*p, "/", package, "/index.html", - NULL)) == NULL) - return -1; - ret = access(s, R_OK); - string_delete(s); - if(ret == 0) - break; - } - if(gtkdocdir != NULL) - p = >kdocdir; - if(*p == NULL) - return -1; - /* read the API documentation */ - if((s = string_new_append("file://", *p, "/", package, "/index.html", - NULL)) == NULL) - return -1; - ret = _helper_open(helper, s); - string_delete(s); - return ret; -} - - -/* helper_open_man */ -static int _helper_open_man(Helper * helper, char const * section, - char const * page, char const * manhtmldir) -{ - char const * prefix[] = - { - DATADIR "/man", PREFIX "/man", "/usr/local/share/man", - "/usr/local/man", "/usr/share/man", "/usr/man", NULL - }; - char const ** p; - char buf[256]; - -#ifdef DEBUG - fprintf(stderr, "DEBUG: %s(%d, \"%s\")\n", __func__, section, page); -#endif - if(section == NULL) - return -1; - if(manhtmldir != NULL) - p = &manhtmldir; - else - for(p = prefix; *p != NULL; p++) - { - snprintf(buf, sizeof(buf), "%s%s%s%s%s%s", *p, - "/html", section, "/", page, ".html"); - if(access(buf, R_OK) == 0) - break; - } - if(*p == NULL) - return -1; - /* read a manual page */ - snprintf(buf, sizeof(buf), "%s%s%s%s%s%s%s", "file://", *p, "/html", - section, "/", page, ".html"); - return _helper_open(helper, buf); -} - - /* callbacks */ /* helper_on_back */ static void _helper_on_back(gpointer data) @@ -1233,7 +568,7 @@ static void _helper_on_file_open(gpointer data) { Helper * helper = data; - _helper_open_dialog(helper); + helper_open_dialog(helper); } #endif @@ -1321,187 +656,18 @@ static void _helper_on_help_contents(gpointer data) { Helper * helper = data; - _helper_open_man(helper, "1", PROGNAME, MANDIR); + helper_open_manual(helper, "1", PROGNAME, MANDIR); } #endif -/* helper_on_contents_row_activated */ -static void _helper_on_contents_row_activated(GtkWidget * widget, - GtkTreePath * path, GtkTreeViewColumn * column, gpointer data) -{ - Helper * helper = data; - GtkTreeModel * model; - GtkTreeIter iter; - GtkTreeIter parent; - gchar * package; - gchar * command; - - model = gtk_tree_view_get_model(GTK_TREE_VIEW(widget)); - gtk_tree_model_get_iter(model, &iter, path); - gtk_tree_model_sort_convert_iter_to_child_iter(GTK_TREE_MODEL_SORT( - model), &parent, &iter); - model = gtk_tree_model_sort_get_model(GTK_TREE_MODEL_SORT(model)); - gtk_tree_model_filter_convert_iter_to_child_iter(GTK_TREE_MODEL_FILTER( - model), &iter, &parent); - model = GTK_TREE_MODEL(helper->store); - if(gtk_tree_model_iter_parent(model, &parent, &iter) == FALSE) - { - if(gtk_tree_view_row_expanded(GTK_TREE_VIEW(widget), path)) - gtk_tree_view_collapse_row(GTK_TREE_VIEW(widget), path); - else - gtk_tree_view_expand_row(GTK_TREE_VIEW(widget), path, - FALSE); - return; - } - gtk_tree_model_get(model, &parent, HSC_CONTENTS_PACKAGE, &package, -1); - gtk_tree_model_get(model, &iter, HSC_CONTENTS_PACKAGE, &command, -1); - _helper_open_contents(helper, package, command); - g_free(package); - g_free(command); -} - - -/* helper_on_gtkdoc_row_activated */ -static void _helper_on_gtkdoc_row_activated(GtkWidget * widget, - GtkTreePath * path, GtkTreeViewColumn * column, gpointer data) -{ - Helper * helper = data; - GtkTreeModel * model; - GtkTreeIter iter; - GtkTreeIter parent; - gchar * package; - gchar * gtkdocdir; - - model = gtk_tree_view_get_model(GTK_TREE_VIEW(widget)); - gtk_tree_model_get_iter(model, &iter, path); - gtk_tree_model_sort_convert_iter_to_child_iter(GTK_TREE_MODEL_SORT( - model), &parent, &iter); - model = gtk_tree_model_sort_get_model(GTK_TREE_MODEL_SORT(model)); - gtk_tree_model_filter_convert_iter_to_child_iter(GTK_TREE_MODEL_FILTER( - model), &iter, &parent); - model = GTK_TREE_MODEL(helper->store); - if(gtk_tree_model_iter_parent(model, &parent, &iter) == FALSE) - { - if(gtk_tree_view_row_expanded(GTK_TREE_VIEW(widget), path)) - gtk_tree_view_collapse_row(GTK_TREE_VIEW(widget), path); - else - gtk_tree_view_expand_row(GTK_TREE_VIEW(widget), path, - FALSE); - return; - } - gtk_tree_model_get(model, &iter, HSC_GTKDOC_PACKAGE, &package, - HSC_GTKDOC_DIRECTORY, >kdocdir, -1); - _helper_open_gtkdoc(helper, gtkdocdir, package); - g_free(package); - g_free(gtkdocdir); -} - - -/* helper_on_manual_row_activated */ -static void _helper_on_manual_row_activated(GtkWidget * widget, - GtkTreePath * path, GtkTreeViewColumn * column, gpointer data) -{ - Helper * helper = data; - GtkTreeModel * model; - GtkTreeIter iter; - GtkTreeIter parent; - gchar * manhtmldir; - gchar * section; - gchar * command; - - model = gtk_tree_view_get_model(GTK_TREE_VIEW(widget)); - gtk_tree_model_get_iter(model, &iter, path); - gtk_tree_model_sort_convert_iter_to_child_iter(GTK_TREE_MODEL_SORT( - model), &parent, &iter); - model = gtk_tree_model_sort_get_model(GTK_TREE_MODEL_SORT(model)); - gtk_tree_model_filter_convert_iter_to_child_iter(GTK_TREE_MODEL_FILTER( - model), &iter, &parent); - model = GTK_TREE_MODEL(helper->store); - if(gtk_tree_model_iter_parent(model, &parent, &iter) == FALSE) - { - if(gtk_tree_view_row_expanded(GTK_TREE_VIEW(widget), path)) - gtk_tree_view_collapse_row(GTK_TREE_VIEW(widget), path); - else - gtk_tree_view_expand_row(GTK_TREE_VIEW(widget), path, - FALSE); - return; - } - gtk_tree_model_get(model, &iter, HSC_MANUAL_DIRECTORY, &manhtmldir, - HSC_MANUAL_SECTION, §ion, - HSC_MANUAL_FILENAME, &command, -1); - _helper_open_man(helper, section, command, manhtmldir); - g_free(manhtmldir); - g_free(section); - g_free(command); -} - - -/* helper_on_search */ -static void _helper_on_search(gpointer data) -{ - Helper * helper = data; - GtkTreeModel * model; - - model = gtk_tree_view_get_model(GTK_TREE_VIEW(helper->search)); - model = gtk_tree_model_sort_get_model(GTK_TREE_MODEL_SORT(model)); - gtk_tree_model_filter_refilter(GTK_TREE_MODEL_FILTER(model)); -} - - -/* helper_on_search_row_activated */ -static void _helper_on_search_row_activated(GtkWidget * widget, - GtkTreePath * path, GtkTreeViewColumn * column, gpointer data) -{ - Helper * helper = data; - GtkTreeModel * model; - GtkTreeIter iter; - GtkTreeIter parent; - unsigned int type; - - model = gtk_tree_view_get_model(GTK_TREE_VIEW(widget)); - gtk_tree_model_get_iter(model, &iter, path); - gtk_tree_model_sort_convert_iter_to_child_iter(GTK_TREE_MODEL_SORT( - model), &parent, &iter); - model = gtk_tree_model_sort_get_model(GTK_TREE_MODEL_SORT(model)); - gtk_tree_model_filter_convert_iter_to_child_iter(GTK_TREE_MODEL_FILTER( - model), &iter, &parent); - model = GTK_TREE_MODEL(helper->store); - if(gtk_tree_model_iter_parent(model, &parent, &iter) == FALSE) - { - if(gtk_tree_view_row_expanded(GTK_TREE_VIEW(widget), path)) - gtk_tree_view_collapse_row(GTK_TREE_VIEW(widget), path); - else - gtk_tree_view_expand_row(GTK_TREE_VIEW(widget), path, - FALSE); - return; - } - gtk_tree_model_get(model, &iter, HSC_TYPE, &type, -1); - switch(type) - { - case HST_CONTENTS: - _helper_on_contents_row_activated(widget, path, column, - helper); - break; - case HST_GTKDOC: - _helper_on_gtkdoc_row_activated(widget, path, column, - helper); - break; - case HST_MANUAL: - _helper_on_manual_row_activated(widget, path, column, - helper); - break; - } -} - - #ifdef EMBEDDED /* helper_on_open */ static void _helper_on_open(gpointer data) { Helper * helper = data; - _helper_open_dialog(helper); + helper_open_dialog(helper); } #endif @@ -1517,40 +683,6 @@ static void _helper_on_view_fullscreen(gpointer data) #endif -/* filters */ -/* helper_filter_contents */ -static gboolean _helper_filter_contents(GtkTreeModel * model, - GtkTreeIter * iter, gpointer data) -{ - unsigned int type; - - gtk_tree_model_get(model, iter, HSC_TYPE, &type, -1); - return (type == HST_CONTENTS) ? TRUE : FALSE; -} - - -/* helper_filter_gtkdoc */ -static gboolean _helper_filter_gtkdoc(GtkTreeModel * model, GtkTreeIter * iter, - gpointer data) -{ - unsigned int type; - - gtk_tree_model_get(model, iter, HSC_TYPE, &type, -1); - return (type == HST_GTKDOC) ? TRUE : FALSE; -} - - -/* helper_filter_manual */ -static gboolean _helper_filter_manual(GtkTreeModel * model, GtkTreeIter * iter, - gpointer data) -{ - unsigned int type; - - gtk_tree_model_get(model, iter, HSC_TYPE, &type, -1); - return (type == HST_MANUAL) ? TRUE : FALSE; -} - - /* error */ static int _error(char const * message, int ret) { @@ -1560,19 +692,6 @@ static int _error(char const * message, int ret) } -/* usage */ -static int _usage(void) -{ - fprintf(stderr, _("Usage: %s [-c][-p package] command\n" -" %s -d package\n" -" %s -s section page\n" -" -d Open an API reference\n" -" -s Section of the manual page to read from\n"), - PROGNAME, PROGNAME, PROGNAME); - return 1; -} - - /* public */ /* surfer */ /* essential */ @@ -1744,6 +863,8 @@ int surfer_error(Surfer * surfer, char const * message, int ret) Helper * helper = surfer; GtkWidget * dialog; + if(surfer == NULL) + return _error(message, ret); dialog = gtk_message_dialog_new((helper != NULL) ? GTK_WINDOW(helper->window) : NULL, GTK_DIALOG_DESTROY_WITH_PARENT, @@ -1914,59 +1035,3 @@ void surfer_warning(Surfer * surfer, char const * message) { fprintf(stderr, "%s: %s\n", PROGNAME, message); } - - -/* helper */ -/* main */ -int main(int argc, char * argv[]) -{ - int o; - int devel = 0; - char const * package = NULL; - char const * section = NULL; - Helper * helper; - - if(setlocale(LC_ALL, "") == NULL) - _error("setlocale", 1); - bindtextdomain(PACKAGE, LOCALEDIR); - textdomain(PACKAGE); -#if defined(WITH_GTKHTML) || defined(WITH_GTKTEXTVIEW) || defined(WITH_WEBKIT) - if(g_thread_supported() == FALSE) - g_thread_init(NULL); -#endif - gtk_init(&argc, &argv); - while((o = getopt(argc, argv, "cdp:s:")) != -1) - switch(o) - { - case 'c': - section = NULL; - devel = 0; - break; - case 'd': - section = NULL; - devel = 1; - break; - case 'p': - package = optarg; - break; - case 's': - section = optarg; - break; - default: - return _usage(); - } - if(optind != argc && (optind + 1) != argc) - return _usage(); - if((helper = _helper_new()) == NULL) - return 2; - if(section != NULL) - _helper_open_man(helper, section, argv[optind], NULL); - else if(argv[optind] != NULL && devel != 0) - _helper_open_gtkdoc(helper, NULL, argv[optind]); - else if(argv[optind] != NULL) - _helper_open_contents(helper, (package != NULL) ? package - : argv[optind], argv[optind]); - gtk_main(); - _helper_delete(helper); - return 0; -} diff --git a/tools/helper.h b/tools/helper.h new file mode 100644 index 0000000..457a021 --- /dev/null +++ b/tools/helper.h @@ -0,0 +1,38 @@ +/* $Id$ */ +/* Copyright (c) 2015 Pierre Pronchery */ +/* This file is part of DeforaOS Desktop Surfer */ +/* 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, version 3 of the License. + * + * 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, see . */ + + + +#ifndef HELPER_HELPER_H +# define HELPER_HELPER_H + + +/* Helper */ +/* public */ +/* types */ +typedef struct _Surfer Helper; + + +/* functions */ +Helper * helper_new(void); +void helper_delete(Helper * helper); + +/* useful */ +int helper_error(Helper * helper, char const * message, int ret); + +int helper_open(Helper * helper, char const * url); +int helper_open_dialog(Helper * helper); + +#endif /* !HELPER_HELPER_H */ diff --git a/tools/project.conf b/tools/project.conf index 2bdb2b2..bdb4378 100644 --- a/tools/project.conf +++ b/tools/project.conf @@ -5,7 +5,7 @@ cflags_force=`pkg-config --cflags libDesktop` cflags=-W -Wall -g -O2 -pedantic -fPIE -D_FORTIFY_SOURCE=2 -fstack-protector-all ldflags_force=`pkg-config --libs libDesktop` ldflags=-Wl,-pie -dist=Makefile +dist=Makefile,backend/contents.c,backend/gtkdoc.c,backend/manual.c,backend/search.c,helper.h [bookmark] type=binary @@ -31,7 +31,7 @@ ldflags=`pkg-config --libs webkit-1.0` #WebKit/Gtk+ 3 #cflags=`pkg-config --cflags webkitgtk-3.0` #ldflags=`pkg-config --libs webkitgtk-3.0` -sources=ghtml-helper.c,helper.c +sources=ghtml-helper.c,helper.c,helper-main.c install=$(BINDIR) [ghtml-helper.c] @@ -46,7 +46,10 @@ depends=../src/ghtml.h,../src/ghtml.c #cppflags=-D WITH_GTKHTML #cppflags=-D WITH_GTKTEXTVIEW cppflags=-D WITH_WEBKIT -depends=../src/common/find.c,../src/surfer.h,../config.h +depends=../src/common/find.c,../src/surfer.h,../config.h,backend/contents.c,backend/gtkdoc.c,backend/manual.c,backend/search.c,helper.h + +[helper-main.c] +depends=helper.h [htmlapp] type=binary