[geany/geany-plugins] b0cb3b: Merge pull request #25 from codebrainz/devhelp-fixes
Frank Lanitz
git-noreply at xxxxx
Wed Mar 28 19:35:19 UTC 2012
Branch: refs/heads/master
Author: Frank Lanitz <frank at frank.uvena.de>
Committer: Frank Lanitz <frank at frank.uvena.de>
Date: Wed, 28 Mar 2012 19:35:19
Commit: b0cb3b1f0662a8263b73206a945f3ffd2be74066
https://github.com/geany/geany-plugins/commit/b0cb3b1f0662a8263b73206a945f3ffd2be74066
Log Message:
-----------
Merge pull request #25 from codebrainz/devhelp-fixes
Devhelp fixes
e.g. make devhelp run also if only gtk3-libdevhelp is available
Modified Paths:
--------------
build/devhelp.m4
devhelp/Makefile.am
devhelp/devhelp/Makefile.am
devhelp/devhelp/dh-assistant-view.c
devhelp/devhelp/dh-assistant-view.h
devhelp/devhelp/dh-assistant.c
devhelp/devhelp/dh-assistant.h
devhelp/devhelp/dh-base.c
devhelp/devhelp/dh-base.h
devhelp/devhelp/dh-book-manager.c
devhelp/devhelp/dh-book-manager.h
devhelp/devhelp/dh-book-tree.c
devhelp/devhelp/dh-book-tree.h
devhelp/devhelp/dh-book.c
devhelp/devhelp/dh-book.h
devhelp/devhelp/dh-enum-types.c
devhelp/devhelp/dh-enum-types.c.template
devhelp/devhelp/dh-enum-types.h
devhelp/devhelp/dh-enum-types.h.template
devhelp/devhelp/dh-error.c
devhelp/devhelp/dh-error.h
devhelp/devhelp/dh-keyword-model.c
devhelp/devhelp/dh-keyword-model.h
devhelp/devhelp/dh-link.c
devhelp/devhelp/dh-link.h
devhelp/devhelp/dh-marshal.c
devhelp/devhelp/dh-marshal.h
devhelp/devhelp/dh-marshal.list
devhelp/devhelp/dh-parser.c
devhelp/devhelp/dh-parser.h
devhelp/devhelp/dh-preferences.c
devhelp/devhelp/dh-preferences.h
devhelp/devhelp/dh-search.c
devhelp/devhelp/dh-search.h
devhelp/devhelp/dh-util.c
devhelp/devhelp/dh-util.h
devhelp/devhelp/dh-window.c
devhelp/devhelp/dh-window.h
devhelp/devhelp/eggfindbar.c
devhelp/devhelp/eggfindbar.h
devhelp/devhelp/ige-conf-gconf.c
devhelp/devhelp/ige-conf-mac.c
devhelp/devhelp/ige-conf-private.h
devhelp/devhelp/ige-conf.c
devhelp/devhelp/ige-conf.h
devhelp/src/Makefile.am
devhelp/src/dhp-codesearch.c
devhelp/src/dhp-manpages.c
devhelp/src/dhp-object.c
devhelp/src/dhp-plugin.c
devhelp/src/dhp.h
devhelp/wscript_build
devhelp/wscript_configure
Modified: build/devhelp.m4
25 files changed, 10 insertions(+), 15 deletions(-)
===================================================================
@@ -3,31 +3,26 @@ AC_DEFUN([GP_CHECK_DEVHELP],
GP_ARG_DISABLE([devhelp], [auto])
GTK_VERSION=2.16
- GLIB_VERSION=2.16
- WEBKIT_VERSION=1.1.18
- DEVHELP1_VERSION=2.30.1
- DEVHELP2_VERSION=2.32.0
+ WEBKIT_VERSION=1.1.13
+ GCONF_VERSION=2.6.0
+ LIBWNCK_VERSION=2.10.0
- # Use newer libdevhelp-2.0 if present, and fallback on older libdevhelp-1.0
- libdevhelp_pkg=libdevhelp-2.0
- libdevhelp_version=${DEVHELP2_VERSION}
- AS_IF([test "x$enable_devhelp" != "xno"],
- [PKG_CHECK_EXISTS([${libdevhelp_pkg} >= ${libdevhelp_version}],
- [AC_DEFINE([HAVE_BOOK_MANAGER], [1], [Use libdevhelp-2.0])],
- [libdevhelp_pkg=libdevhelp-1.0
- libdevhelp_version=${DEVHELP1_VERSION}])])
+ AC_PATH_PROG(GLIB_GENMARSHAL, glib-genmarshal)
+ AC_PATH_PROG(GLIB_MKENUMS, glib-mkenums)
GP_CHECK_PLUGIN_DEPS([devhelp], [DEVHELP],
[gtk+-2.0 >= ${GTK_VERSION}
- glib-2.0 >= ${GLIB_VERSION}
webkit-1.0 >= ${WEBKIT_VERSION}
- ${libdevhelp_pkg} >= ${libdevhelp_version}
- gthread-2.0])
+ libwnck-1.0 >= ${LIBWNCK_VERSION}
+ gconf-2.0 >= ${GCONF_VERSION}
+ gthread-2.0
+ zlib])
GP_STATUS_PLUGIN_ADD([DevHelp], [$enable_devhelp])
AC_CONFIG_FILES([
devhelp/Makefile
+ devhelp/devhelp/Makefile
devhelp/src/Makefile
devhelp/data/Makefile
])
Modified: devhelp/Makefile.am
2 files changed, 1 insertions(+), 1 deletions(-)
===================================================================
@@ -4,5 +4,5 @@ else
include $(top_srcdir)/build/vars.docs.mk
endif
-SUBDIRS = src data
+SUBDIRS = devhelp src data
plugin = devhelp
Modified: devhelp/devhelp/Makefile.am
84 files changed, 84 insertions(+), 0 deletions(-)
===================================================================
@@ -0,0 +1,84 @@
+dh_headers = \
+ dh-assistant.h \
+ dh-assistant-view.h \
+ dh-base.h \
+ dh-book-manager.h \
+ dh-book.h \
+ dh-book-tree.h \
+ dh-error.h \
+ dh-keyword-model.h \
+ dh-link.h \
+ dh-search.h \
+ dh-window.h
+
+dh-enum-types.h: dh-enum-types.h.template $(dh_headers) $(GLIB_MKENUMS)
+ $(AM_V_GEN) (cd $(srcdir) && $(GLIB_MKENUMS) --template dh-enum-types.h.template $(dh_headers)) > $@
+
+dh-enum-types.c: dh-enum-types.c.template $(dh_headers) $(GLIB_MKENUMS)
+ $(AM_V_GEN) (cd $(srcdir) && $(GLIB_MKENUMS) --template dh-enum-types.c.template $(dh_headers)) > $@
+
+BUILT_SOURCES = \
+ dh-marshal.h \
+ dh-marshal.c \
+ dh-enum-types.h \
+ dh-enum-types.c
+
+EXTRA_DIST = \
+ dh-marshal.list \
+ dh-enum-types.c.template \
+ dh-enum-types.h.template
+
+noinst_LTLIBRARIES = libdevhelp-2.la
+
+libdevhelp_2_la_SOURCES = \
+ dh-assistant.c \
+ dh-assistant-view.c \
+ dh-base.c \
+ dh-book.c \
+ dh-book-manager.c \
+ dh-book-tree.c \
+ dh-enum-types.c \
+ dh-enum-types.h \
+ dh-error.c \
+ dh-keyword-model.c \
+ dh-link.c \
+ dh-marshal.c \
+ dh-marshal.h \
+ dh-parser.c \
+ dh-parser.h \
+ dh-preferences.c \
+ dh-preferences.h \
+ dh-search.c \
+ dh-util.c \
+ dh-util.h \
+ dh-window.c \
+ eggfindbar.c \
+ eggfindbar.h \
+ ige-conf.c \
+ ige-conf-gconf.c \
+ ige-conf.h \
+ ige-conf-private.h \
+ $(dh_headers)
+
+libdevhelp_2_la_CPPFLAGS = \
+ -I$(top_srcdir) \
+ -DLOCALEDIR=\""$(datadir)/locale"\" \
+ -DDATADIR=\""$(datadir)"\" \
+ -DG_LOG_DOMAIN=\"Devhelp\" \
+ $(DEVHELP_CPPFLAGS)
+
+libdevhelp_2_la_CFLAGS = \
+ $(DEVHELP_CFLAGS)
+
+libdevhelp_2_la_LIBADD = \
+ $(DEVHELP_LIBS)
+
+libdevhelp_2_la_LDFLAGS = \
+ -no-undefined
+
+dh-marshal.h: dh-marshal.list
+ $(AM_V_GEN) $(GLIB_GENMARSHAL) $< --header --prefix=_dh_marshal dh-marshal.list > $@
+
+dh-marshal.c: dh-marshal.list
+ $(AM_V_GEN) echo "#include \"dh-marshal.h\"" > $@ && \
+ $(GLIB_GENMARSHAL) $< --body --prefix=_dh_marshal dh-marshal.list >> $@
Modified: devhelp/devhelp/dh-assistant-view.c
465 files changed, 465 insertions(+), 0 deletions(-)
===================================================================
@@ -0,0 +1,465 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2008 Imendio AB
+ * Copyright (C) 2008 Sven Herzberg
+ *
+ * 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
+ */
+
+#include "config.h"
+#include <string.h>
+#include <glib/gi18n-lib.h>
+#include <webkit/webkit.h>
+#include "dh-assistant-view.h"
+#include "dh-link.h"
+#include "dh-util.h"
+#include "dh-book-manager.h"
+#include "dh-book.h"
+#include "dh-window.h"
+
+typedef struct {
+ DhBase *base;
+ DhLink *link;
+ gchar *current_search;
+ gboolean snippet_loaded;
+} DhAssistantViewPriv;
+
+G_DEFINE_TYPE (DhAssistantView, dh_assistant_view, WEBKIT_TYPE_WEB_VIEW);
+
+#define GET_PRIVATE(instance) G_TYPE_INSTANCE_GET_PRIVATE \
+ (instance, DH_TYPE_ASSISTANT_VIEW, DhAssistantViewPriv)
+
+static void
+view_finalize (GObject *object)
+{
+ DhAssistantViewPriv *priv = GET_PRIVATE (object);
+
+ if (priv->link) {
+ g_object_unref (priv->link);
+ }
+
+ if (priv->base) {
+ g_object_unref (priv->base);
+ }
+
+ g_free (priv->current_search);
+
+ G_OBJECT_CLASS (dh_assistant_view_parent_class)->finalize (object);
+}
+
+static WebKitNavigationResponse
+assistant_navigation_requested (WebKitWebView *web_view,
+ WebKitWebFrame *frame,
+ WebKitNetworkRequest *request)
+{
+ DhAssistantViewPriv *priv;
+ const gchar *uri;
+
+ priv = GET_PRIVATE (web_view);
+
+ uri = webkit_network_request_get_uri (request);
+ if (strcmp (uri, "about:blank") == 0) {
+ return WEBKIT_NAVIGATION_RESPONSE_ACCEPT;
+ }
+ else if (! priv->snippet_loaded) {
+ priv->snippet_loaded = TRUE;
+ return WEBKIT_NAVIGATION_RESPONSE_ACCEPT;
+ }
+ else if (g_str_has_prefix (uri, "file://")) {
+ GtkWidget *window;
+
+ window = dh_base_get_window (priv->base);
+ _dh_window_display_uri (DH_WINDOW (window), uri);
+ }
+
+ return WEBKIT_NAVIGATION_RESPONSE_IGNORE;
+}
+
+static gboolean
+assistant_button_press_event (GtkWidget *widget,
+ GdkEventButton *event)
+{
+ /* Block webkit's builtin context menu. */
+ if (event->button != 1) {
+ return TRUE;
+ }
+
+ return GTK_WIDGET_CLASS (dh_assistant_view_parent_class)->button_press_event (widget, event);
+}
+
+static void
+dh_assistant_view_class_init (DhAssistantViewClass* klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+ WebKitWebViewClass *web_view_class = WEBKIT_WEB_VIEW_CLASS (klass);
+
+ object_class->finalize = view_finalize;
+
+ widget_class->button_press_event = assistant_button_press_event;
+
+ web_view_class->navigation_requested = assistant_navigation_requested;
+
+ g_type_class_add_private (klass, sizeof (DhAssistantViewPriv));
+}
+
+static void
+dh_assistant_view_init (DhAssistantView *view)
+{
+}
+
+DhBase*
+dh_assistant_view_get_base (DhAssistantView *view)
+{
+ DhAssistantViewPriv *priv;
+
+ g_return_val_if_fail (DH_IS_ASSISTANT_VIEW (view), NULL);
+
+ priv = GET_PRIVATE (view);
+
+ return priv->base;
+}
+
+GtkWidget*
+dh_assistant_view_new (void)
+{
+ return g_object_new (DH_TYPE_ASSISTANT_VIEW, NULL);
+}
+
+static const gchar *
+find_in_buffer (const gchar *buffer,
+ const gchar *key,
+ gsize length,
+ gsize key_length)
+{
+ gsize m = 0;
+ gsize i = 0;
+
+ while (i < length) {
+ if (key[m] == buffer[i]) {
+ m++;
+ if (m == key_length) {
+ return buffer + i - m + 1;
+ }
+ } else {
+ m = 0;
+ }
+ i++;
+ }
+
+ return NULL;
+}
+
+/**
+ * dh_assistant_view_set_link:
+ * @view: an devhelp assistant view
+ * @link: the #DhLink
+ *
+ * Open @link in the assistant view, if %NULL the view will be blanked.
+ *
+ * Return value: %TRUE if the requested link is open, %FALSE otherwise.
+ **/
+gboolean
+dh_assistant_view_set_link (DhAssistantView *view,
+ DhLink *link)
+{
+ DhAssistantViewPriv *priv;
+ gchar *uri;
+ const gchar *anchor;
+ gchar *filename;
+ GMappedFile *file;
+ const gchar *contents;
+ gsize length;
+ gchar *key;
+ gsize key_length;
+ gsize offset = 0;
+ const gchar *start;
+ const gchar *end;
+
+ g_return_val_if_fail (DH_IS_ASSISTANT_VIEW (view), FALSE);
+
+ priv = GET_PRIVATE (view);
+
+ if (priv->link == link) {
+ return TRUE;
+ }
+
+ if (priv->link) {
+ dh_link_unref (priv->link);
+ priv->link = NULL;
+ }
+
+ if (link) {
+ link = dh_link_ref (link);
+ } else {
+ webkit_web_view_load_uri (WEBKIT_WEB_VIEW (view), "about:blank");
+ return TRUE;
+ }
+
+ uri = dh_link_get_uri (link);
+ anchor = strrchr (uri, '#');
+ if (anchor) {
+ filename = g_strndup (uri, anchor - uri);
+ anchor++;
+ g_free (uri);
+ } else {
+ g_free (uri);
+ return FALSE;
+ }
+
+ if (g_str_has_prefix (filename, "file://"))
+ offset = 7;
+
+ file = g_mapped_file_new (filename + offset, FALSE, NULL);
+ if (!file) {
+ g_free (filename);
+ return FALSE;
+ }
+
+ contents = g_mapped_file_get_contents (file);
+ length = g_mapped_file_get_length (file);
+
+ key = g_strdup_printf ("<a name=\"%s\"", anchor);
+ key_length = strlen (key);
+
+ start = find_in_buffer (contents, key, length, key_length);
+ g_free (key);
+
+ end = NULL;
+
+ if (start) {
+ const gchar *start_key;
+ const gchar *end_key;
+
+ length -= start - contents;
+
+ start_key = "<pre class=\"programlisting\">";
+
+ start = find_in_buffer (start,
+ start_key,
+ length,
+ strlen (start_key));
+
+ end_key = "<div class=\"refsect";
+
+ if (start) {
+ end = find_in_buffer (start, end_key,
+ length - strlen (start_key),
+ strlen (end_key));
+ if (!end) {
+ end_key = "<div class=\"footer";
+ end = find_in_buffer (start, end_key,
+ length - strlen (start_key),
+ strlen (end_key));
+ }
+ }
+ }
+
+ if (start && end) {
+ gchar *buf;
+ gboolean break_line;
+ const gchar *function;
+ gchar *stylesheet;
+ gchar *javascript;
+ gchar *html;
+
+ buf = g_strndup (start, end-start);
+
+ /* Try to reformat function signatures so they take less
+ * space and look nicer. Don't reformat things that don't
+ * look like functions.
+ */
+ switch (dh_link_get_link_type (link)) {
+ case DH_LINK_TYPE_FUNCTION:
+ break_line = TRUE;
+ function = "onload=\"reformatSignature()\"";
+ break;
+ case DH_LINK_TYPE_MACRO:
+ break_line = TRUE;
+ function = "onload=\"cleanupSignature()\"";
+ break;
+ default:
+ break_line = FALSE;
+ function = "";
+ break;
+ }
+
+ if (break_line) {
+ gchar *name;
+
+ name = strstr (buf, dh_link_get_name (link));
+ if (name && name > buf) {
+ name[-1] = '\n';
+ }
+ }
+
+ stylesheet = dh_util_build_data_filename ("devhelp",
+ "assistant",
+ "assistant.css",
+ NULL);
+ javascript = dh_util_build_data_filename ("devhelp",
+ "assistant",
+ "assistant.js",
+ NULL);
+
+ html = g_strdup_printf (
+ "<html>"
+ "<head>"
+ "<link rel=\"stylesheet\" type=\"text/css\" href=\"file://%s\"/>"
+ "<script src=\"file://%s\"></script>"
+ "</head>"
+ "<body %s>"
+ "<div class=\"title\">%s: <a href=\"%s\">%s</a></div>"
+ "<div class=\"subtitle\">%s %s</div>"
+ "<div class=\"content\">%s</div>"
+ "</body>"
+ "</html>",
+ stylesheet,
+ javascript,
+ function,
+ dh_link_get_type_as_string (link),
+ dh_link_get_uri (link),
+ dh_link_get_name (link),
+ _("Book:"),
+ dh_link_get_book_name (link),
+ buf);
+ g_free (buf);
+
+ g_free (stylesheet);
+ g_free (javascript);
+
+ priv->snippet_loaded = FALSE;
+ webkit_web_view_load_string (
+ WEBKIT_WEB_VIEW (view),
+ html,
+ "text/html",
+ NULL,
+ filename);
+
+ g_free (html);
+ } else {
+ webkit_web_view_load_uri (WEBKIT_WEB_VIEW (view), "about:blank");
+ }
+
+#if GLIB_CHECK_VERSION(2,21,3)
+ g_mapped_file_unref (file);
+#else
+ g_mapped_file_free (file);
+#endif
+
+ g_free (filename);
+
+ return TRUE;
+}
+
+gboolean
+dh_assistant_view_search (DhAssistantView *view,
+ const gchar *str)
+{
+ DhAssistantViewPriv *priv;
+ const gchar *name;
+ DhLink *link;
+ DhLink *exact_link;
+ DhLink *prefix_link;
+ DhBookManager *book_manager;
+ GList *books;
+
+ g_return_val_if_fail (DH_IS_ASSISTANT_VIEW (view), FALSE);
+ g_return_val_if_fail (str, FALSE);
+
+ priv = GET_PRIVATE (view);
+
+ /* Filter out very short strings. */
+ if (strlen (str) < 4) {
+ return FALSE;
+ }
+
+ if (priv->current_search && strcmp (priv->current_search, str) == 0) {
+ return FALSE;
+ }
+ g_free (priv->current_search);
+ priv->current_search = g_strdup (str);
+
+ book_manager = dh_base_get_book_manager (dh_assistant_view_get_base (view));
+
+ prefix_link = NULL;
+ exact_link = NULL;
+
+ for (books = dh_book_manager_get_books (book_manager);
+ !exact_link && books;
+ books = g_list_next (books)) {
+ GList *l;
+
+ for (l = dh_book_get_keywords (DH_BOOK (books->data));
+ l && exact_link == NULL;
+ l = l->next) {
+ DhLinkType type;
+
+ link = l->data;
+
+ type = dh_link_get_link_type (link);
+
+ if (type == DH_LINK_TYPE_BOOK ||
+ type == DH_LINK_TYPE_PAGE ||
+ type == DH_LINK_TYPE_KEYWORD) {
+ continue;
+ }
+
+ name = dh_link_get_name (link);
+ if (strcmp (name, str) == 0) {
+ exact_link = link;
+ }
+ else if (g_str_has_prefix (name, str)) {
+ /* Prefer shorter prefix matches. */
+ if (!prefix_link) {
+ prefix_link = link;
+ }
+ else if (strlen (dh_link_get_name (prefix_link)) > strlen (name)) {
+ prefix_link = link;
+ }
+ }
+ }
+ }
+
+ if (exact_link) {
+ /*g_print ("exact hit: '%s' '%s'\n", exact_link->name, str);*/
+ dh_assistant_view_set_link (view, exact_link);
+ }
+ else if (prefix_link) {
+ /*g_print ("prefix hit: '%s' '%s'\n", prefix_link->name, str);*/
+ dh_assistant_view_set_link (view, prefix_link);
+ } else {
+ /*g_print ("no hit\n");*/
+ /*assistant_view_set_link (view, NULL);*/
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+void
+dh_assistant_view_set_base (DhAssistantView *view,
+ DhBase *base)
+{
+ DhAssistantViewPriv *priv;
+
+ g_return_if_fail (DH_IS_ASSISTANT_VIEW (view));
+ g_return_if_fail (DH_IS_BASE (base));
+
+ priv = GET_PRIVATE (view);
+
+ priv->base = g_object_ref (base);
+}
Modified: devhelp/devhelp/dh-assistant-view.h
59 files changed, 59 insertions(+), 0 deletions(-)
===================================================================
@@ -0,0 +1,59 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2008 Sven Herzberg
+ *
+ * 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
+ */
+
+#ifndef __DH_ASSISTANT_VIEW_H__
+#define __DH_ASSISTANT_VIEW_H__
+
+#include <webkit/webkit.h>
+#include "dh-base.h"
+#include "dh-link.h"
+
+G_BEGIN_DECLS
+
+#define DH_TYPE_ASSISTANT_VIEW (dh_assistant_view_get_type ())
+#define DH_ASSISTANT_VIEW(i) (G_TYPE_CHECK_INSTANCE_CAST ((i), DH_TYPE_ASSISTANT_VIEW, DhAssistantView))
+#define DH_ASSISTANT_VIEW_CLASS(c) (G_TYPE_CHECK_CLASS_CAST ((c), DH_TYPE_ASSISTANT_VIEW, DhAssistantViewClass))
+#define DH_IS_ASSISTANT_VIEW(i) (G_TYPE_CHECK_INSTANCE_TYPE ((i), DH_TYPE_ASSISTANT_VIEW))
+#define DH_IS_ASSISTANT_VIEW_CLASS(c) (G_TYPE_CHECK_CLASS_TYPE ((c), DH_ASSISTANT_VIEW))
+#define DH_ASSISTANT_VIEW_GET_CLASS(i) (G_TYPE_INSTANCE_GET_CLASS ((i), DH_TYPE_ASSISTANT_VIEW, DhAssistantView))
+
+typedef struct _DhAssistantView DhAssistantView;
+typedef struct _DhAssistantViewClass DhAssistantViewClass;
+
+struct _DhAssistantView {
+ WebKitWebView parent_instance;
+};
+
+struct _DhAssistantViewClass {
+ WebKitWebViewClass parent_class;
+};
+
+GType dh_assistant_view_get_type (void) G_GNUC_CONST;
+GtkWidget* dh_assistant_view_new (void);
+gboolean dh_assistant_view_search (DhAssistantView *view,
+ const gchar *str);
+DhBase* dh_assistant_view_get_base (DhAssistantView *view);
+void dh_assistant_view_set_base (DhAssistantView *view,
+ DhBase *base);
+gboolean dh_assistant_view_set_link (DhAssistantView *view,
+ DhLink *link);
+G_END_DECLS
+
+#endif /* __DH_ASSISTANT_VIEW_H__ */
Modified: devhelp/devhelp/dh-assistant.c
130 files changed, 130 insertions(+), 0 deletions(-)
===================================================================
@@ -0,0 +1,130 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2008 Imendio AB
+ *
+ * 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.
+ */
+
+#include "config.h"
+#include <string.h>
+#include <glib/gi18n-lib.h>
+#include <gdk/gdkkeysyms.h>
+#include <gtk/gtk.h>
+#include "dh-window.h"
+#include "dh-util.h"
+#include "dh-assistant-view.h"
+#include "dh-assistant.h"
+
+typedef struct {
+ GtkWidget *main_box;
+ GtkWidget *view;
+} DhAssistantPriv;
+
+static void dh_assistant_class_init (DhAssistantClass *klass);
+static void dh_assistant_init (DhAssistant *assistant);
+
+G_DEFINE_TYPE (DhAssistant, dh_assistant, GTK_TYPE_WINDOW);
+
+#define GET_PRIVATE(instance) G_TYPE_INSTANCE_GET_PRIVATE \
+ (instance, DH_TYPE_ASSISTANT, DhAssistantPriv)
+
+static gboolean
+assistant_key_press_event_cb (GtkWidget *widget,
+ GdkEventKey *event,
+ DhAssistant *assistant)
+{
+ if (event->keyval == GDK_Escape) {
+ gtk_widget_destroy (GTK_WIDGET (assistant));
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static void
+dh_assistant_class_init (DhAssistantClass *klass)
+{
+ g_type_class_add_private (klass, sizeof (DhAssistantPriv));
+}
+
+static void
+dh_assistant_init (DhAssistant *assistant)
+{
+ DhAssistantPriv *priv = GET_PRIVATE (assistant);
+ GtkWidget *scrolled_window;
+
+ priv->main_box = gtk_vbox_new (FALSE, 0);
+ gtk_widget_show (priv->main_box);
+ gtk_container_add (GTK_CONTAINER (assistant), priv->main_box);
+
+ /* i18n: Please don't translate "Devhelp". */
+ gtk_window_set_title (GTK_WINDOW (assistant), _("Devhelp — Assistant"));
+ gtk_window_set_icon_name (GTK_WINDOW (assistant), "devhelp");
+
+ priv->view = dh_assistant_view_new ();
+
+ g_signal_connect (assistant, "key-press-event",
+ G_CALLBACK (assistant_key_press_event_cb),
+ assistant);
+
+ scrolled_window = gtk_scrolled_window_new (NULL, NULL);
+ gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window),
+ GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
+
+ gtk_container_add (GTK_CONTAINER (scrolled_window), priv->view);
+
+ gtk_widget_show_all (scrolled_window);
+
+ gtk_box_pack_start (GTK_BOX (priv->main_box),
+ scrolled_window, TRUE, TRUE, 0);
+
+ dh_util_state_manage_window (GTK_WINDOW (assistant),
+ "assistant/window");
+}
+
+GtkWidget *
+dh_assistant_new (DhBase *base)
+{
+ GtkWidget *assistant;
+ DhAssistantPriv *priv;
+
+ assistant = g_object_new (DH_TYPE_ASSISTANT, NULL);
+
+ priv = GET_PRIVATE (assistant);
+
+ dh_assistant_view_set_base (DH_ASSISTANT_VIEW (priv->view), base);
+
+ return assistant;
+}
+
+gboolean
+dh_assistant_search (DhAssistant *assistant,
+ const gchar *str)
+{
+ DhAssistantPriv *priv;
+
+ g_return_val_if_fail (DH_IS_ASSISTANT (assistant), FALSE);
+ g_return_val_if_fail (str != NULL, FALSE);
+
+ priv = GET_PRIVATE (assistant);
+
+ if (dh_assistant_view_search (DH_ASSISTANT_VIEW (priv->view), str)) {
+ gtk_widget_show (GTK_WIDGET (assistant));
+ return TRUE;
+ }
+
+ return FALSE;
+}
Modified: devhelp/devhelp/dh-assistant.h
54 files changed, 54 insertions(+), 0 deletions(-)
===================================================================
@@ -0,0 +1,54 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2008 Imendio AB
+ *
+ * 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.
+ */
+
+#ifndef __DH_ASSISTANT_H__
+#define __DH_ASSISTANT_H__
+
+#include <gtk/gtk.h>
+#include "dh-base.h"
+
+G_BEGIN_DECLS
+
+#define DH_TYPE_ASSISTANT (dh_assistant_get_type ())
+#define DH_ASSISTANT(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), DH_TYPE_ASSISTANT, DhAssistant))
+#define DH_ASSISTANT_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), DH_TYPE_ASSISTANT, DhAssistantClass))
+#define DH_IS_ASSISTANT(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), DH_TYPE_ASSISTANT))
+#define DH_IS_ASSISTANT_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), DH_TYPE_ASSISTANT))
+#define DH_ASSISTANT_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), DH_TYPE_ASSISTANT, DhAssistantClass))
+
+typedef struct _DhAssistant DhAssistant;
+typedef struct _DhAssistantClass DhAssistantClass;
+
+struct _DhAssistant {
+ GtkWindow parent_instance;
+};
+
+struct _DhAssistantClass {
+ GtkWindowClass parent_class;
+};
+
+GType dh_assistant_get_type (void) G_GNUC_CONST;
+GtkWidget *dh_assistant_new (DhBase *base);
+gboolean dh_assistant_search (DhAssistant *assistant,
+ const gchar *str);
+
+G_END_DECLS
+
+#endif /* __DH_ASSISTANT_H__ */
Modified: devhelp/devhelp/dh-base.c
307 files changed, 307 insertions(+), 0 deletions(-)
===================================================================
@@ -0,0 +1,307 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2002 CodeFactory AB
+ * Copyright (C) 2002 Mikael Hallendal <micke at imendio.com>
+ * Copyright (C) 2004-2008 Imendio AB
+ *
+ * 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.
+ */
+
+#include "config.h"
+#include <string.h>
+#include <gtk/gtk.h>
+
+#ifdef GDK_WINDOWING_X11
+#include <unistd.h>
+#include <gdk/gdkx.h>
+#define WNCK_I_KNOW_THIS_IS_UNSTABLE
+#include <libwnck/libwnck.h>
+#endif
+
+#include "dh-window.h"
+#include "dh-link.h"
+#include "dh-parser.h"
+#include "dh-preferences.h"
+#include "dh-assistant.h"
+#include "dh-util.h"
+#include "ige-conf.h"
+#include "dh-base.h"
+#include "dh-book-manager.h"
+
+typedef struct {
+ GSList *windows;
+ GSList *assistants;
+ DhBookManager *book_manager;
+} DhBasePriv;
+
+G_DEFINE_TYPE (DhBase, dh_base, G_TYPE_OBJECT);
+
+#define GET_PRIVATE(instance) G_TYPE_INSTANCE_GET_PRIVATE \
+ (instance, DH_TYPE_BASE, DhBasePriv)
+
+static void dh_base_init (DhBase *base);
+static void dh_base_class_init (DhBaseClass *klass);
+
+static DhBase *base_instance;
+
+static void
+base_finalize (GObject *object)
+{
+ G_OBJECT_CLASS (dh_base_parent_class)->finalize (object);
+}
+
+static void
+base_dispose (GObject *object)
+{
+ DhBasePriv *priv;
+
+ priv = GET_PRIVATE (object);
+
+ if (priv->book_manager) {
+ g_object_unref (priv->book_manager);
+ priv->book_manager = NULL;
+ }
+}
+
+
+static void
+dh_base_class_init (DhBaseClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->finalize = base_finalize;
+ object_class->dispose = base_dispose;
+
+ g_type_class_add_private (klass, sizeof (DhBasePriv));
+}
+
+static void
+dh_base_init (DhBase *base)
+{
+ DhBasePriv *priv = GET_PRIVATE (base);
+ IgeConf *conf;
+ gchar *path;
+
+ conf = ige_conf_get ();
+ path = dh_util_build_data_filename ("devhelp", "devhelp.defaults", NULL);
+ ige_conf_add_defaults (conf, path);
+ g_free (path);
+
+ priv->book_manager = dh_book_manager_new ();
+ dh_book_manager_populate (priv->book_manager);
+
+#ifdef GDK_WINDOWING_X11
+ {
+ gint n_screens, i;
+
+ /* For some reason, libwnck doesn't seem to update its list of
+ * workspaces etc if we don't do this.
+ */
+ n_screens = gdk_display_get_n_screens (gdk_display_get_default ());
+ for (i = 0; i < n_screens; i++)
+ wnck_screen_get (i);
+ }
+#endif
+}
+
+static void
+base_window_or_assistant_finalized_cb (DhBase *base,
+ gpointer window_or_assistant)
+{
+ DhBasePriv *priv = GET_PRIVATE (base);
+
+ priv->windows = g_slist_remove (priv->windows, window_or_assistant);
+ priv->assistants = g_slist_remove (priv->assistants, window_or_assistant);
+
+ if (priv->windows == NULL && priv->assistants == NULL) {
+ gtk_main_quit ();
+ }
+}
+
+DhBase *
+dh_base_get (void)
+{
+ if (!base_instance) {
+ base_instance = g_object_new (DH_TYPE_BASE, NULL);
+ }
+
+ return base_instance;
+}
+
+DhBase *
+dh_base_new (void)
+{
+ if (base_instance) {
+ g_error ("You can only have one DhBase instance.");
+ }
+
+ return dh_base_get ();
+}
+
+GtkWidget *
+dh_base_new_window (DhBase *base)
+{
+ DhBasePriv *priv;
+ GtkWidget *window;
+
+ g_return_val_if_fail (DH_IS_BASE (base), NULL);
+
+ priv = GET_PRIVATE (base);
+
+ window = dh_window_new (base);
+
+ priv->windows = g_slist_prepend (priv->windows, window);
+
+ g_object_weak_ref (G_OBJECT (window),
+ (GWeakNotify) base_window_or_assistant_finalized_cb,
+ base);
+
+ return window;
+}
+
+GtkWidget *
+dh_base_new_assistant (DhBase *base)
+{
+ DhBasePriv *priv;
+ GtkWidget *assistant;
+
+ g_return_val_if_fail (DH_IS_BASE (base), NULL);
+
+ priv = GET_PRIVATE (base);
+
+ assistant = dh_assistant_new (base);
+
+ priv->assistants = g_slist_prepend (priv->assistants, assistant);
+
+ g_object_weak_ref (G_OBJECT (assistant),
+ (GWeakNotify) base_window_or_assistant_finalized_cb,
+ base);
+
+ return assistant;
+}
+
+DhBookManager *
+dh_base_get_book_manager (DhBase *base)
+{
+ DhBasePriv *priv;
+
+ g_return_val_if_fail (DH_IS_BASE (base), NULL);
+
+ priv = GET_PRIVATE (base);
+
+ return priv->book_manager;
+}
+
+GtkWidget *
+dh_base_get_window_on_current_workspace (DhBase *base)
+{
+ DhBasePriv *priv;
+
+ g_return_val_if_fail (DH_IS_BASE (base), NULL);
+
+ priv = GET_PRIVATE (base);
+
+ if (!priv->windows) {
+ return NULL;
+ }
+
+#ifdef GDK_WINDOWING_X11
+ {
+ WnckWorkspace *workspace;
+ WnckScreen *screen;
+ GtkWidget *window;
+ GList *windows, *w;
+ GSList *l;
+ gulong xid;
+ pid_t pid;
+
+ screen = wnck_screen_get (0);
+ if (!screen) {
+ return NULL;
+ }
+
+ workspace = wnck_screen_get_active_workspace (screen);
+ if (!workspace) {
+ return NULL;
+ }
+
+ xid = 0;
+ pid = getpid ();
+
+ /* Use _stacked so we can use the one on top. */
+ windows = wnck_screen_get_windows_stacked (screen);
+ windows = g_list_last (windows);
+
+ for (w = windows; w; w = w->prev) {
+ if (wnck_window_is_on_workspace (w->data, workspace) &&
+ wnck_window_get_pid (w->data) == pid) {
+ xid = wnck_window_get_xid (w->data);
+ break;
+ }
+ }
+
+ if (!xid) {
+ return NULL;
+ }
+
+ /* Return the first matching window we have. */
+ for (l = priv->windows; l; l = l->next) {
+ window = l->data;
+
+#if GTK_CHECK_VERSION (2,14,0)
+ if (GDK_WINDOW_XID (gtk_widget_get_window (window)) == xid) {
+#else
+ if (GDK_WINDOW_XID (window->window) == xid) {
+#endif
+ return window;
+ }
+ }
+ }
+
+ return NULL;
+#else
+ return priv->windows->data;
+#endif
+}
+
+GtkWidget *
+dh_base_get_window (DhBase *base)
+{
+ GtkWidget *window;
+
+ g_return_val_if_fail (DH_IS_BASE (base), NULL);
+
+ window = dh_base_get_window_on_current_workspace (base);
+ if (!window) {
+ window = dh_base_new_window (base);
+ gtk_window_present (GTK_WINDOW (window));
+ }
+
+ return window;
+}
+
+void
+dh_base_quit (DhBase *base)
+{
+ DhBasePriv *priv = GET_PRIVATE (base);
+
+ /* Make sure all of the windows get a chance to release their resources
+ * properly. As they get destroyed,
+ * base_window_or_assistant_finalized_cb() will be called, and when the
+ * last one is removed, we will quit */
+ g_slist_foreach (priv->windows, (GFunc)gtk_widget_destroy, NULL);
+ g_slist_foreach (priv->assistants, (GFunc)gtk_widget_destroy, NULL);
+}
Modified: devhelp/devhelp/dh-base.h
62 files changed, 62 insertions(+), 0 deletions(-)
===================================================================
@@ -0,0 +1,62 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2002 CodeFactory AB
+ * Copyright (C) 2002 Mikael Hallendal <micke at imendio.com>
+ * Copyright (C) 2005-2008 Imendio AB
+ *
+ * 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.
+ */
+
+#ifndef __DH_BASE_H__
+#define __DH_BASE_H__
+
+#include <gtk/gtk.h>
+
+#include "dh-book-manager.h"
+
+G_BEGIN_DECLS
+
+typedef struct _DhBase DhBase;
+typedef struct _DhBaseClass DhBaseClass;
+
+#define DH_TYPE_BASE (dh_base_get_type ())
+#define DH_BASE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), DH_TYPE_BASE, DhBase))
+#define DH_BASE_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), DH_TYPE_BASE, DhBaseClass))
+#define DH_IS_BASE(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), DH_TYPE_BASE))
+#define DH_IS_BASE_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), DH_TYPE_BASE))
+#define DH_BASE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), DH_TYPE_BASE, DhBaseClass))
+
+struct _DhBase {
+ GObject parent_instance;
+};
+
+struct _DhBaseClass {
+ GObjectClass parent_class;
+};
+
+GType dh_base_get_type (void) G_GNUC_CONST;
+DhBase * dh_base_get (void);
+DhBase * dh_base_new (void);
+GtkWidget * dh_base_new_window (DhBase *base);
+GtkWidget * dh_base_new_assistant (DhBase *base);
+GtkWidget * dh_base_get_window (DhBase *base);
+GtkWidget * dh_base_get_window_on_current_workspace (DhBase *base);
+DhBookManager *dh_base_get_book_manager (DhBase *base);
+void dh_base_quit (DhBase *base);
+
+G_END_DECLS
+
+#endif /* __DH_BASE_H__ */
Modified: devhelp/devhelp/dh-book-manager.c
408 files changed, 408 insertions(+), 0 deletions(-)
===================================================================
@@ -0,0 +1,408 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2002 CodeFactory AB
+ * Copyright (C) 2002 Mikael Hallendal <micke at imendio.com>
+ * Copyright (C) 2004-2008 Imendio AB
+ * Copyright (C) 2010 Lanedo GmbH
+ *
+ * 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.
+ */
+
+#include "config.h"
+#include <string.h>
+
+#include "dh-link.h"
+#include "dh-util.h"
+#include "dh-book.h"
+#include "dh-book-manager.h"
+#include "dh-marshal.h"
+
+typedef struct {
+ /* The list of all DhBooks found in the system */
+ GList *books;
+} DhBookManagerPriv;
+
+enum {
+ DISABLED_BOOK_LIST_UPDATED,
+ LAST_SIGNAL
+};
+
+static gint signals[LAST_SIGNAL] = { 0 };
+
+G_DEFINE_TYPE (DhBookManager, dh_book_manager, G_TYPE_OBJECT);
+
+#define GET_PRIVATE(instance) G_TYPE_INSTANCE_GET_PRIVATE \
+ (instance, DH_TYPE_BOOK_MANAGER, DhBookManagerPriv)
+
+static void dh_book_manager_init (DhBookManager *book_manager);
+static void dh_book_manager_class_init (DhBookManagerClass *klass);
+
+static void book_manager_add_from_filepath (DhBookManager *book_manager,
+ const gchar *book_path);
+static void book_manager_add_from_dir (DhBookManager *book_manager,
+ const gchar *dir_path);
+
+#ifdef GDK_WINDOWING_QUARTZ
+static void book_manager_add_from_xcode_docset (DhBookManager *book_manager,
+ const gchar *dir_path);
+#endif
+
+static void
+book_manager_finalize (GObject *object)
+{
+ DhBookManagerPriv *priv;
+ GList *l;
+
+ priv = GET_PRIVATE (object);
+
+ /* Destroy all books */
+ for (l = priv->books; l; l = g_list_next (l)) {
+ g_object_unref (l->data);
+ }
+ g_list_free (priv->books);
+
+ G_OBJECT_CLASS (dh_book_manager_parent_class)->finalize (object);
+}
+
+static void
+dh_book_manager_class_init (DhBookManagerClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->finalize = book_manager_finalize;
+
+ signals[DISABLED_BOOK_LIST_UPDATED] =
+ g_signal_new ("disabled-book-list-updated",
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (DhBookManagerClass, disabled_book_list_updated),
+ NULL, NULL,
+ _dh_marshal_VOID__VOID,
+ G_TYPE_NONE,
+ 0);
+
+ g_type_class_add_private (klass, sizeof (DhBookManagerPriv));
+}
+
+static void
+dh_book_manager_init (DhBookManager *book_manager)
+{
+ DhBookManagerPriv *priv = GET_PRIVATE (book_manager);
+
+ priv->books = NULL;
+}
+
+static void
+book_manager_clean_list_of_books_disabled (GSList *books_disabled)
+{
+ GSList *sl;
+
+ for (sl = books_disabled; sl; sl = g_slist_next (sl)) {
+ g_free (sl->data);
+ }
+ g_slist_free (sl);
+}
+
+static void
+book_manager_check_status_from_conf (DhBookManager *book_manager)
+{
+ GSList *books_disabled, *sl;
+
+ books_disabled = dh_util_state_load_books_disabled ();
+
+ for (sl = books_disabled; sl; sl = g_slist_next (sl)) {
+ DhBook *book;
+
+ book = dh_book_manager_get_book_by_name (book_manager,
+ (const gchar *)sl->data);
+ if (book) {
+ dh_book_set_enabled (book, FALSE);
+ }
+ }
+
+ book_manager_clean_list_of_books_disabled (books_disabled);
+}
+
+static void
+book_manager_add_books_in_data_dir (DhBookManager *book_manager,
+ const gchar *data_dir)
+{
+ gchar *dir;
+
+ dir = g_build_filename (data_dir, "gtk-doc", "html", NULL);
+ book_manager_add_from_dir (book_manager, dir);
+ g_free (dir);
+
+ dir = g_build_filename (data_dir, "devhelp", "books", NULL);
+ book_manager_add_from_dir (book_manager, dir);
+ g_free (dir);
+}
+
+void
+dh_book_manager_populate (DhBookManager *book_manager)
+{
+ const gchar * const * system_dirs;
+
+ book_manager_add_books_in_data_dir (book_manager,
+ g_get_user_data_dir ());
+
+ system_dirs = g_get_system_data_dirs ();
+ while (*system_dirs) {
+ book_manager_add_books_in_data_dir (book_manager,
+ *system_dirs);
+ system_dirs++;
+ }
+
+#ifdef GDK_WINDOWING_QUARTZ
+ book_manager_add_from_xcode_docset (
+ book_manager,
+ "/Library/Developer/Shared/Documentation/DocSets");
+#endif
+
+ /* Once all books are loaded, check enabled status from conf */
+ book_manager_check_status_from_conf (book_manager);
+}
+
+static gchar *
+book_manager_get_book_path (const gchar *base_path,
+ const gchar *name)
+{
+ static const gchar *suffixes[] = {
+ "devhelp2",
+ "devhelp2.gz",
+ "devhelp",
+ "devhelp.gz",
+ NULL
+ };
+ gchar *tmp;
+ gchar *book_path;
+ guint i;
+
+ for (i = 0; suffixes[i]; i++) {
+ tmp = g_build_filename (base_path, name, name, NULL);
+ book_path = g_strconcat (tmp, ".", suffixes[i], NULL);
+ g_free (tmp);
+
+ if (g_file_test (book_path, G_FILE_TEST_EXISTS)) {
+ return book_path;;
+ }
+ g_free (book_path);
+ }
+ return NULL;
+}
+
+static void
+book_manager_add_from_dir (DhBookManager *book_manager,
+ const gchar *dir_path)
+{
+ GDir *dir;
+ const gchar *name;
+
+ g_return_if_fail (book_manager);
+ g_return_if_fail (dir_path);
+
+ /* Open directory */
+ dir = g_dir_open (dir_path, 0, NULL);
+ if (!dir) {
+ return;
+ }
+
+ /* And iterate it */
+ while ((name = g_dir_read_name (dir)) != NULL) {
+ gchar *book_path;
+
+ book_path = book_manager_get_book_path (dir_path, name);
+ if (book_path) {
+ /* Add book from filepath */
+ book_manager_add_from_filepath (book_manager,
+ book_path);
+ g_free (book_path);
+ }
+ }
+
+ g_dir_close (dir);
+}
+
+#ifdef GDK_WINDOWING_QUARTZ
+static gboolean
+seems_docset_dir (const gchar *path)
+{
+ gchar *tmp;
+ gboolean seems_like_devhelp = FALSE;
+
+ g_return_val_if_fail (path, FALSE);
+
+ /* Do some sanity checking on the directory first so we don't have
+ * to go through several hundreds of files in every docset.
+ */
+ tmp = g_build_filename (path, "style.css", NULL);
+ if (g_file_test (tmp, G_FILE_TEST_EXISTS)) {
+ gchar *tmp;
+
+ tmp = g_build_filename (path, "index.sgml", NULL);
+ if (g_file_test (tmp, G_FILE_TEST_EXISTS)) {
+ seems_like_devhelp = TRUE;
+ }
+ g_free (tmp);
+ }
+ g_free (tmp);
+
+ return seems_like_devhelp;
+}
+
+static void
+book_manager_add_from_xcode_docset (DhBookManager *book_manager,
+ const gchar *dir_path)
+{
+ GDir *dir;
+ const gchar *name;
+
+ g_return_if_fail (book_manager);
+ g_return_if_fail (dir_path);
+
+ if (!seems_docset_dir (dir_path)) {
+ return;
+ }
+
+ /* Open directory */
+ dir = g_dir_open (dir_path, 0, NULL);
+ if (!dir) {
+ return;
+ }
+
+ /* And iterate it, looking for files ending with .devhelp2 */
+ while ((name = g_dir_read_name (dir)) != NULL) {
+ if (g_strcmp0 (strrchr (name, '.'),
+ ".devhelp2") == 0) {
+ gchar *book_path;
+
+ book_path = g_build_filename (path, name, NULL);
+ /* Add book from filepath */
+ book_manager_add_from_filepath (book_manager,
+ book_path);
+ g_free (book_path);
+ }
+ }
+
+ g_dir_close (dir);
+}
+#endif
+
+static void
+book_manager_add_from_filepath (DhBookManager *book_manager,
+ const gchar *book_path)
+{
+ DhBookManagerPriv *priv;
+ DhBook *book;
+
+ g_return_if_fail (book_manager);
+ g_return_if_fail (book_path);
+
+ priv = GET_PRIVATE (book_manager);
+
+ /* Allocate new book struct */
+ book = dh_book_new (book_path);
+
+ /* Check if book with same path was already loaded in the manager */
+ if (g_list_find_custom (priv->books,
+ book,
+ (GCompareFunc)dh_book_cmp_by_path)) {
+ g_object_unref (book);
+ return;
+ }
+
+ /* Check if book with same bookname was already loaded in the manager
+ * (we need to force unique book names) */
+ if (g_list_find_custom (priv->books,
+ book,
+ (GCompareFunc)dh_book_cmp_by_name)) {
+ g_object_unref (book);
+ return;
+ }
+
+ /* Add the book to the book list */
+ priv->books = g_list_insert_sorted (priv->books,
+ book,
+ (GCompareFunc)dh_book_cmp_by_title);
+}
+
+GList *
+dh_book_manager_get_books (DhBookManager *book_manager)
+{
+ g_return_val_if_fail (book_manager, NULL);
+
+ return GET_PRIVATE (book_manager)->books;
+}
+
+DhBook *
+dh_book_manager_get_book_by_name (DhBookManager *book_manager,
+ const gchar *name)
+{
+ DhBook *book = NULL;
+ GList *l;
+
+ g_return_val_if_fail (book_manager, NULL);
+
+ for (l = GET_PRIVATE (book_manager)->books;
+ l && !book;
+ l = g_list_next (l)) {
+ if (g_strcmp0 (name,
+ dh_book_get_name (DH_BOOK (l->data))) == 0) {
+ book = l->data;
+ }
+ }
+
+ return book;
+}
+
+void
+dh_book_manager_update (DhBookManager *book_manager)
+{
+ DhBookManagerPriv *priv;
+ GSList *books_disabled = NULL;
+ GList *l;
+
+ g_return_if_fail (book_manager);
+
+ priv = GET_PRIVATE (book_manager);
+
+ /* Create list of disabled books */
+ for (l = priv->books; l; l = g_list_next (l)) {
+ DhBook *book = DH_BOOK (l->data);
+
+ if (!dh_book_get_enabled (book)) {
+ books_disabled = g_slist_append (books_disabled,
+ g_strdup (dh_book_get_name (book)));
+ }
+ }
+
+ /* Store in conf */
+ dh_util_state_store_books_disabled (books_disabled);
+
+ /* Emit signal to notify others */
+ g_signal_emit (book_manager,
+ signals[DISABLED_BOOK_LIST_UPDATED],
+ 0);
+
+ book_manager_clean_list_of_books_disabled (books_disabled);
+}
+
+DhBookManager *
+dh_book_manager_new (void)
+{
+ return g_object_new (DH_TYPE_BOOK_MANAGER, NULL);
+}
+
Modified: devhelp/devhelp/dh-book-manager.h
61 files changed, 61 insertions(+), 0 deletions(-)
===================================================================
@@ -0,0 +1,61 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2010 Lanedo GmbH
+ *
+ * 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.
+ */
+
+#ifndef __DH_BOOK_MANAGER_H__
+#define __DH_BOOK_MANAGER_H__
+
+#include <gtk/gtk.h>
+
+#include "dh-book.h"
+
+G_BEGIN_DECLS
+
+typedef struct _DhBookManager DhBookManager;
+typedef struct _DhBookManagerClass DhBookManagerClass;
+
+#define DH_TYPE_BOOK_MANAGER (dh_book_manager_get_type ())
+#define DH_BOOK_MANAGER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), DH_TYPE_BOOK_MANAGER, DhBookManager))
+#define DH_BOOK_MANAGER_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), DH_TYPE_BOOK_MANAGER, DhBookManagerClass))
+#define DH_IS_BOOK_MANAGER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), DH_TYPE_BOOK_MANAGER))
+#define DH_IS_BOOK_MANAGER_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), DH_TYPE_BOOK_MANAGER))
+#define DH_BOOK_MANAGER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), DH_TYPE_BOOK_MANAGER, DhBookManagerClass))
+
+struct _DhBookManager {
+ GObject parent_instance;
+};
+
+struct _DhBookManagerClass {
+ GObjectClass parent_class;
+
+ /* Signals */
+ void (* disabled_book_list_updated) (DhBookManager *book_manager);
+};
+
+GType dh_book_manager_get_type (void) G_GNUC_CONST;
+DhBookManager *dh_book_manager_new (void);
+void dh_book_manager_populate (DhBookManager *book_manager);
+GList *dh_book_manager_get_books (DhBookManager *book_manager);
+DhBook *dh_book_manager_get_book_by_name (DhBookManager *book_manager,
+ const gchar *name);
+void dh_book_manager_update (DhBookManager *book_manager);
+
+G_END_DECLS
+
+#endif /* __DH_BOOK_MANAGER_H__ */
Modified: devhelp/devhelp/dh-book-tree.c
385 files changed, 385 insertions(+), 0 deletions(-)
===================================================================
@@ -0,0 +1,385 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2001-2003 Mikael Hallendal <micke at imendio.com>
+ * Copyright (C) 2003 CodeFactory AB
+ * Copyright (C) 2008 Imendio AB
+ *
+ * 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.
+ */
+
+#include "config.h"
+#include <string.h>
+#include <gdk/gdkkeysyms.h>
+#include <gtk/gtk.h>
+
+#include "dh-marshal.h"
+#include "dh-book-tree.h"
+#include "dh-book.h"
+
+typedef struct {
+ const gchar *uri;
+ gboolean found;
+ GtkTreeIter iter;
+ GtkTreePath *path;
+} FindURIData;
+
+typedef struct {
+ GtkTreeStore *store;
+ DhBookManager *book_manager;
+ DhLink *selected_link;
+} DhBookTreePriv;
+
+static void dh_book_tree_class_init (DhBookTreeClass *klass);
+static void dh_book_tree_init (DhBookTree *tree);
+static void book_tree_add_columns (DhBookTree *tree);
+static void book_tree_setup_selection (DhBookTree *tree);
+static void book_tree_populate_tree (DhBookTree *tree);
+static void book_tree_insert_node (DhBookTree *tree,
+ GNode *node,
+ GtkTreeIter *parent_iter);
+static void book_tree_selection_changed_cb (GtkTreeSelection *selection,
+ DhBookTree *tree);
+
+enum {
+ LINK_SELECTED,
+ LAST_SIGNAL
+};
+
+enum {
+ COL_TITLE,
+ COL_LINK,
+ COL_WEIGHT,
+ N_COLUMNS
+};
+
+G_DEFINE_TYPE (DhBookTree, dh_book_tree, GTK_TYPE_TREE_VIEW);
+
+#define GET_PRIVATE(instance) G_TYPE_INSTANCE_GET_PRIVATE \
+ (instance, DH_TYPE_BOOK_TREE, DhBookTreePriv);
+
+static gint signals[LAST_SIGNAL] = { 0 };
+
+static void
+book_tree_finalize (GObject *object)
+{
+ DhBookTreePriv *priv = GET_PRIVATE (object);
+
+ g_object_unref (priv->store);
+ g_object_unref (priv->book_manager);
+
+ G_OBJECT_CLASS (dh_book_tree_parent_class)->finalize (object);
+}
+
+static void
+dh_book_tree_class_init (DhBookTreeClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->finalize = book_tree_finalize;
+
+ signals[LINK_SELECTED] =
+ g_signal_new ("link-selected",
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST,
+ 0,
+ NULL, NULL,
+ _dh_marshal_VOID__POINTER,
+ G_TYPE_NONE,
+ 1, G_TYPE_POINTER);
+
+ g_type_class_add_private (klass, sizeof (DhBookTreePriv));
+}
+
+static void
+dh_book_tree_init (DhBookTree *tree)
+{
+ DhBookTreePriv *priv;
+
+ priv = GET_PRIVATE (tree);
+
+ priv->store = gtk_tree_store_new (N_COLUMNS,
+ G_TYPE_STRING,
+ G_TYPE_POINTER,
+ PANGO_TYPE_WEIGHT);
+ priv->selected_link = NULL;
+ gtk_tree_view_set_model (GTK_TREE_VIEW (tree),
+ GTK_TREE_MODEL (priv->store));
+
+ gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (tree), FALSE);
+
+ book_tree_add_columns (tree);
+
+ book_tree_setup_selection (tree);
+}
+
+static void
+book_tree_add_columns (DhBookTree *tree)
+{
+ GtkCellRenderer *cell;
+ GtkTreeViewColumn *column;
+
+ column = gtk_tree_view_column_new ();
+
+ cell = gtk_cell_renderer_text_new ();
+ g_object_set (cell,
+ "ellipsize", PANGO_ELLIPSIZE_END,
+ NULL);
+ gtk_tree_view_column_pack_start (column, cell, TRUE);
+ gtk_tree_view_column_set_attributes (column, cell,
+ "text", COL_TITLE,
+ "weight", COL_WEIGHT,
+ NULL);
+
+ gtk_tree_view_append_column (GTK_TREE_VIEW (tree), column);
+}
+
+static void
+book_tree_setup_selection (DhBookTree *tree)
+{
+ GtkTreeSelection *selection;
+
+ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (tree));
+
+ gtk_tree_selection_set_mode (selection, GTK_SELECTION_BROWSE);
+
+ g_signal_connect (selection, "changed",
+ G_CALLBACK (book_tree_selection_changed_cb),
+ tree);
+}
+
+static void
+book_tree_populate_tree (DhBookTree *tree)
+{
+ DhBookTreePriv *priv = GET_PRIVATE (tree);
+ GList *l;
+
+ gtk_tree_store_clear (priv->store);
+
+ for (l = dh_book_manager_get_books (priv->book_manager);
+ l;
+ l = g_list_next (l)) {
+ DhBook *book = DH_BOOK (l->data);
+ GNode *node;
+
+ node = dh_book_get_tree (book);
+ while(node) {
+ book_tree_insert_node (tree, node, NULL);
+ node = g_node_next_sibling (node);
+ }
+ }
+}
+
+static void
+book_manager_disabled_book_list_changed_cb (DhBookManager *book_manager,
+ gpointer user_data)
+{
+ DhBookTree *tree = user_data;
+ book_tree_populate_tree (tree);
+}
+
+static void
+book_tree_insert_node (DhBookTree *tree,
+ GNode *node,
+ GtkTreeIter *parent_iter)
+
+{
+ DhBookTreePriv *priv = GET_PRIVATE (tree);
+ DhLink *link;
+ GtkTreeIter iter;
+ PangoWeight weight;
+ GNode *child;
+
+ link = node->data;
+
+ gtk_tree_store_append (priv->store, &iter, parent_iter);
+
+ if (dh_link_get_link_type (link) == DH_LINK_TYPE_BOOK) {
+ weight = PANGO_WEIGHT_BOLD;
+ } else {
+ weight = PANGO_WEIGHT_NORMAL;
+ }
+
+ gtk_tree_store_set (priv->store, &iter,
+ COL_TITLE, dh_link_get_name (link),
+ COL_LINK, link,
+ COL_WEIGHT, weight,
+ -1);
+
+ for (child = g_node_first_child (node);
+ child;
+ child = g_node_next_sibling (child)) {
+ book_tree_insert_node (tree, child, &iter);
+ }
+}
+
+static void
+book_tree_selection_changed_cb (GtkTreeSelection *selection,
+ DhBookTree *tree)
+{
+ DhBookTreePriv *priv = GET_PRIVATE (tree);
+ GtkTreeIter iter;
+
+ if (gtk_tree_selection_get_selected (selection, NULL, &iter)) {
+ DhLink *link;
+
+ gtk_tree_model_get (GTK_TREE_MODEL (priv->store),
+ &iter,
+ COL_LINK, &link,
+ -1);
+ if (link != priv->selected_link) {
+ g_signal_emit (tree, signals[LINK_SELECTED], 0, link);
+ }
+ priv->selected_link = link;
+ }
+}
+
+GtkWidget *
+dh_book_tree_new (DhBookManager *book_manager)
+{
+ DhBookTree *tree;
+ DhBookTreePriv *priv;
+ GtkTreeSelection *selection;
+ GtkTreeIter iter;
+ DhLink *link;
+
+ tree = g_object_new (DH_TYPE_BOOK_TREE, NULL);
+ priv = GET_PRIVATE (tree);
+
+ priv->book_manager = g_object_ref (book_manager);
+ g_signal_connect (priv->book_manager,
+ "disabled-book-list-updated",
+ G_CALLBACK (book_manager_disabled_book_list_changed_cb),
+ tree);
+
+ book_tree_populate_tree (tree);
+
+ /* Mark the first item as selected, or it would get automatically
+ * selected when the treeview will get focus; but that's not even
+ * enough as a selection changed would still be emitted when there
+ * is no change, hence the manual tracking of selection in
+ * selected_link.
+ * https://bugzilla.gnome.org/show_bug.cgi?id=492206
+ */
+ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (tree));
+ g_signal_handlers_block_by_func (selection,
+ book_tree_selection_changed_cb,
+ tree);
+ gtk_tree_model_get_iter_first ( GTK_TREE_MODEL (priv->store), &iter);
+ gtk_tree_model_get (GTK_TREE_MODEL (priv->store),
+ &iter, COL_LINK, &link, -1);
+ priv->selected_link = link;
+ gtk_tree_selection_select_iter (selection, &iter);
+ g_signal_handlers_unblock_by_func (selection,
+ book_tree_selection_changed_cb,
+ tree);
+
+ return GTK_WIDGET (tree);
+}
+
+static gboolean
+book_tree_find_uri_foreach (GtkTreeModel *model,
+ GtkTreePath *path,
+ GtkTreeIter *iter,
+ FindURIData *data)
+{
+ DhLink *link;
+ gchar *link_uri;
+
+ gtk_tree_model_get (model, iter,
+ COL_LINK, &link,
+ -1);
+
+ link_uri = dh_link_get_uri (link);
+ if (g_str_has_prefix (data->uri, link_uri)) {
+ data->found = TRUE;
+ data->iter = *iter;
+ data->path = gtk_tree_path_copy (path);
+ }
+ g_free (link_uri);
+
+ return data->found;
+}
+
+void
+dh_book_tree_select_uri (DhBookTree *tree,
+ const gchar *uri)
+{
+ DhBookTreePriv *priv = GET_PRIVATE (tree);
+ GtkTreeSelection *selection;
+ FindURIData data;
+
+ data.found = FALSE;
+ data.uri = uri;
+
+ gtk_tree_model_foreach (GTK_TREE_MODEL (priv->store),
+ (GtkTreeModelForeachFunc) book_tree_find_uri_foreach,
+ &data);
+
+ if (!data.found) {
+ return;
+ }
+
+ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (tree));
+
+ g_signal_handlers_block_by_func (selection,
+ book_tree_selection_changed_cb,
+ tree);
+
+ gtk_tree_view_expand_to_path (GTK_TREE_VIEW (tree), data.path);
+ gtk_tree_selection_select_iter (selection, &data.iter);
+ gtk_tree_view_set_cursor (GTK_TREE_VIEW (tree), data.path, NULL, 0);
+
+ g_signal_handlers_unblock_by_func (selection,
+ book_tree_selection_changed_cb,
+ tree);
+
+ gtk_tree_path_free (data.path);
+}
+
+const gchar *
+dh_book_tree_get_selected_book_title (DhBookTree *tree)
+{
+ GtkTreeSelection *selection;
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+ GtkTreePath *path;
+ DhLink *link;
+
+ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (tree));
+ if (!gtk_tree_selection_get_selected (selection, &model, &iter)) {
+ return NULL;
+ }
+
+ path = gtk_tree_model_get_path (model, &iter);
+
+ /* Get the book node for this link. */
+ while (1) {
+ if (gtk_tree_path_get_depth (path) <= 1) {
+ break;
+ }
+
+ gtk_tree_path_up (path);
+ }
+
+ gtk_tree_model_get_iter (model, &iter, path);
+ gtk_tree_path_free (path);
+
+ gtk_tree_model_get (model, &iter,
+ COL_LINK, &link,
+ -1);
+
+ return dh_link_get_name (link);
+}
Modified: devhelp/devhelp/dh-book-tree.h
55 files changed, 55 insertions(+), 0 deletions(-)
===================================================================
@@ -0,0 +1,55 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2001 Mikael Hallendal <micke at imendio.com>
+ *
+ * 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.
+ */
+
+#ifndef __DH_BOOK_TREE_H__
+#define __DH_BOOK_TREE_H__
+
+#include <gtk/gtk.h>
+#include "dh-link.h"
+#include "dh-book-manager.h"
+
+G_BEGIN_DECLS
+
+#define DH_TYPE_BOOK_TREE (dh_book_tree_get_type ())
+#define DH_BOOK_TREE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), DH_TYPE_BOOK_TREE, DhBookTree))
+#define DH_BOOK_TREE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), DH_TYPE_BOOK_TREE, DhBookTreeClass))
+#define DH_IS_BOOK_TREE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), DH_TYPE_BOOK_TREE))
+#define DH_IS_BOOK_TREE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), DH_TYPE_BOOK_TREE))
+
+typedef struct _DhBookTree DhBookTree;
+typedef struct _DhBookTreeClass DhBookTreeClass;
+
+struct _DhBookTree {
+ GtkTreeView parent_instance;
+};
+
+struct _DhBookTreeClass {
+ GtkTreeViewClass parent_class;
+};
+
+GType dh_book_tree_get_type (void) G_GNUC_CONST;
+GtkWidget * dh_book_tree_new (DhBookManager *book_manager);
+void dh_book_tree_select_uri (DhBookTree *book_tree,
+ const gchar *uri);
+const gchar *dh_book_tree_get_selected_book_title (DhBookTree *tree);
+
+G_END_DECLS
+
+#endif /* __DH_BOOK_TREE_H__ */
Modified: devhelp/devhelp/dh-book.c
246 files changed, 246 insertions(+), 0 deletions(-)
===================================================================
@@ -0,0 +1,246 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2002 CodeFactory AB
+ * Copyright (C) 2002 Mikael Hallendal <micke at imendio.com>
+ * Copyright (C) 2004-2008 Imendio AB
+ * Copyright (C) 2010 Lanedo GmbH
+ *
+ * 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.
+ */
+
+#include "config.h"
+#include <string.h>
+
+#include "dh-link.h"
+#include "dh-parser.h"
+#include "dh-book.h"
+
+/* Structure defining basic contents to store about every book */
+typedef struct {
+ /* File path of the book */
+ gchar *path;
+ /* Enable or disabled? */
+ gboolean enabled;
+ /* Book name */
+ gchar *name;
+ /* Book title */
+ gchar *title;
+ /* Generated book tree */
+ GNode *tree;
+ /* Generated list of keywords in the book */
+ GList *keywords;
+} DhBookPriv;
+
+G_DEFINE_TYPE (DhBook, dh_book, G_TYPE_OBJECT);
+
+#define GET_PRIVATE(instance) G_TYPE_INSTANCE_GET_PRIVATE \
+ (instance, DH_TYPE_BOOK, DhBookPriv)
+
+static void dh_book_init (DhBook *book);
+static void dh_book_class_init (DhBookClass *klass);
+
+static void unref_node_link (GNode *node,
+ gpointer data);
+
+static void
+book_finalize (GObject *object)
+{
+ DhBookPriv *priv;
+
+ priv = GET_PRIVATE (object);
+
+ if (priv->tree) {
+ g_node_traverse (priv->tree,
+ G_IN_ORDER,
+ G_TRAVERSE_ALL,
+ -1,
+ (GNodeTraverseFunc)unref_node_link,
+ NULL);
+ g_node_destroy (priv->tree);
+ }
+
+ if (priv->keywords) {
+ g_list_foreach (priv->keywords, (GFunc)dh_link_unref, NULL);
+ g_list_free (priv->keywords);
+ }
+
+ g_free (priv->title);
+
+ g_free (priv->path);
+
+ G_OBJECT_CLASS (dh_book_parent_class)->finalize (object);
+}
+
+static void
+dh_book_class_init (DhBookClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->finalize = book_finalize;
+
+ g_type_class_add_private (klass, sizeof (DhBookPriv));
+}
+
+static void
+dh_book_init (DhBook *book)
+{
+ DhBookPriv *priv = GET_PRIVATE (book);
+
+ priv->name = NULL;
+ priv->path = NULL;
+ priv->title = NULL;
+ priv->enabled = TRUE;
+ priv->tree = NULL;
+ priv->keywords = NULL;
+}
+
+static void
+unref_node_link (GNode *node,
+ gpointer data)
+{
+ dh_link_unref (node->data);
+}
+
+DhBook *
+dh_book_new (const gchar *book_path)
+{
+ DhBookPriv *priv;
+ DhBook *book;
+ GError *error = NULL;
+
+ g_return_val_if_fail (book_path, NULL);
+
+ book = g_object_new (DH_TYPE_BOOK, NULL);
+ priv = GET_PRIVATE (book);
+
+ /* Parse file storing contents in the book struct */
+ if (!dh_parser_read_file (book_path,
+ &priv->tree,
+ &priv->keywords,
+ &error)) {
+ g_warning ("Failed to read '%s': %s",
+ priv->path, error->message);
+ g_error_free (error);
+
+ /* Deallocate the book, as we are not going to add it
+ * in the manager */
+ g_object_unref (book);
+ return NULL;
+ }
+
+ /* Store path */
+ priv->path = g_strdup (book_path);
+
+ /* Setup title */
+ priv->title = g_strdup (dh_link_get_name ((DhLink *)priv->tree->data));
+
+ /* Setup name */
+ priv->name = g_strdup (dh_link_get_book_id ((DhLink *)priv->tree->data));
+
+ return book;
+}
+
+GList *
+dh_book_get_keywords (DhBook *book)
+{
+ DhBookPriv *priv;
+
+ g_return_val_if_fail (DH_IS_BOOK (book), NULL);
+
+ priv = GET_PRIVATE (book);
+
+ return priv->enabled ? priv->keywords : NULL;
+}
+
+GNode *
+dh_book_get_tree (DhBook *book)
+{
+ DhBookPriv *priv;
+
+ g_return_val_if_fail (DH_IS_BOOK (book), NULL);
+
+ priv = GET_PRIVATE (book);
+
+ return priv->enabled ? priv->tree : NULL;
+}
+
+const gchar *
+dh_book_get_name (DhBook *book)
+{
+ DhBookPriv *priv;
+
+ g_return_val_if_fail (DH_IS_BOOK (book), NULL);
+
+ priv = GET_PRIVATE (book);
+
+ return priv->name;
+}
+
+const gchar *
+dh_book_get_title (DhBook *book)
+{
+ DhBookPriv *priv;
+
+ g_return_val_if_fail (DH_IS_BOOK (book), NULL);
+
+ priv = GET_PRIVATE (book);
+
+ return priv->title;
+}
+
+gboolean
+dh_book_get_enabled (DhBook *book)
+{
+ g_return_val_if_fail (DH_IS_BOOK (book), FALSE);
+
+ return GET_PRIVATE (book)->enabled;
+}
+
+void
+dh_book_set_enabled (DhBook *book,
+ gboolean enabled)
+{
+ g_return_if_fail (DH_IS_BOOK (book));
+
+ GET_PRIVATE (book)->enabled = enabled;
+}
+
+gint
+dh_book_cmp_by_path (const DhBook *a,
+ const DhBook *b)
+{
+ return ((a && b) ?
+ g_strcmp0 (GET_PRIVATE (a)->path, GET_PRIVATE (b)->path) :
+ -1);
+}
+
+gint
+dh_book_cmp_by_name (const DhBook *a,
+ const DhBook *b)
+{
+ return ((a && b) ?
+ g_ascii_strcasecmp (GET_PRIVATE (a)->name, GET_PRIVATE (b)->name) :
+ -1);
+}
+
+gint
+dh_book_cmp_by_title (const DhBook *a,
+ const DhBook *b)
+{
+ return ((a && b) ?
+ g_utf8_collate (GET_PRIVATE (a)->title, GET_PRIVATE (b)->title) :
+ -1);
+}
Modified: devhelp/devhelp/dh-book.h
67 files changed, 67 insertions(+), 0 deletions(-)
===================================================================
@@ -0,0 +1,67 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2002 CodeFactory AB
+ * Copyright (C) 2002 Mikael Hallendal <micke at imendio.com>
+ * Copyright (C) 2005-2008 Imendio AB
+ * Copyright (C) 2010 Lanedo GmbH
+ *
+ * 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.
+ */
+
+#ifndef _DH_BOOK_H_
+#define _DH_BOOK_H_
+
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+typedef struct _DhBook DhBook;
+typedef struct _DhBookClass DhBookClass;
+
+#define DH_TYPE_BOOK (dh_book_get_type ())
+#define DH_BOOK(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), DH_TYPE_BOOK, DhBook))
+#define DH_BOOK_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), DH_TYPE_BOOK, DhBookClass))
+#define DH_IS_BOOK(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), DH_TYPE_BOOK))
+#define DH_IS_BOOK_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), DH_TYPE_BOOK))
+#define DH_BOOK_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), DH_TYPE_BOOK, DhBookClass))
+
+struct _DhBook {
+ GObject parent_instance;
+};
+
+struct _DhBookClass {
+ GObjectClass parent_class;
+};
+
+GType dh_book_get_type (void) G_GNUC_CONST;
+DhBook *dh_book_new (const gchar *book_path);
+GList *dh_book_get_keywords (DhBook *book);
+GNode *dh_book_get_tree (DhBook *book);
+const gchar *dh_book_get_name (DhBook *book);
+const gchar *dh_book_get_title (DhBook *book);
+gboolean dh_book_get_enabled (DhBook *book);
+void dh_book_set_enabled (DhBook *book,
+ gboolean enabled);
+gint dh_book_cmp_by_path (const DhBook *a,
+ const DhBook *b);
+gint dh_book_cmp_by_name (const DhBook *a,
+ const DhBook *b);
+gint dh_book_cmp_by_title (const DhBook *a,
+ const DhBook *b);
+
+G_END_DECLS
+
+#endif /* _DH_BOOK_H_ */
Modified: devhelp/devhelp/dh-enum-types.c
137 files changed, 137 insertions(+), 0 deletions(-)
===================================================================
@@ -0,0 +1,137 @@
+
+/* Generated data (by glib-mkenums) */
+
+#include "dh-enum-types.h"
+#include "dh-assistant.h"
+#include "dh-assistant-view.h"
+#include "dh-base.h"
+#include "dh-book-manager.h"
+#include "dh-book.h"
+#include "dh-book-tree.h"
+#include "dh-error.h"
+#include "dh-keyword-model.h"
+#include "dh-link.h"
+#include "dh-search.h"
+#include "dh-window.h"
+
+GType
+dh_error_get_type (void)
+{
+ static GType the_type = 0;
+
+ if (the_type == 0)
+ {
+ static const GEnumValue values[] = {
+ { DH_ERROR_FILE_NOT_FOUND,
+ "DH_ERROR_FILE_NOT_FOUND",
+ "file-not-found" },
+ { DH_ERROR_MALFORMED_BOOK,
+ "DH_ERROR_MALFORMED_BOOK",
+ "malformed-book" },
+ { DH_ERROR_INVALID_BOOK_TYPE,
+ "DH_ERROR_INVALID_BOOK_TYPE",
+ "invalid-book-type" },
+ { DH_ERROR_INTERNAL_ERROR,
+ "DH_ERROR_INTERNAL_ERROR",
+ "internal-error" },
+ { 0, NULL, NULL }
+ };
+ the_type = g_enum_register_static (
+ g_intern_static_string ("DhError"),
+ values);
+ }
+ return the_type;
+}
+
+
+GType
+dh_link_type_get_type (void)
+{
+ static GType the_type = 0;
+
+ if (the_type == 0)
+ {
+ static const GEnumValue values[] = {
+ { DH_LINK_TYPE_BOOK,
+ "DH_LINK_TYPE_BOOK",
+ "book" },
+ { DH_LINK_TYPE_PAGE,
+ "DH_LINK_TYPE_PAGE",
+ "page" },
+ { DH_LINK_TYPE_KEYWORD,
+ "DH_LINK_TYPE_KEYWORD",
+ "keyword" },
+ { DH_LINK_TYPE_FUNCTION,
+ "DH_LINK_TYPE_FUNCTION",
+ "function" },
+ { DH_LINK_TYPE_STRUCT,
+ "DH_LINK_TYPE_STRUCT",
+ "struct" },
+ { DH_LINK_TYPE_MACRO,
+ "DH_LINK_TYPE_MACRO",
+ "macro" },
+ { DH_LINK_TYPE_ENUM,
+ "DH_LINK_TYPE_ENUM",
+ "enum" },
+ { DH_LINK_TYPE_TYPEDEF,
+ "DH_LINK_TYPE_TYPEDEF",
+ "typedef" },
+ { 0, NULL, NULL }
+ };
+ the_type = g_enum_register_static (
+ g_intern_static_string ("DhLinkType"),
+ values);
+ }
+ return the_type;
+}
+
+GType
+dh_link_flags_get_type (void)
+{
+ static GType the_type = 0;
+
+ if (the_type == 0)
+ {
+ static const GFlagsValue values[] = {
+ { DH_LINK_FLAGS_NONE,
+ "DH_LINK_FLAGS_NONE",
+ "none" },
+ { DH_LINK_FLAGS_DEPRECATED,
+ "DH_LINK_FLAGS_DEPRECATED",
+ "deprecated" },
+ { 0, NULL, NULL }
+ };
+ the_type = g_flags_register_static (
+ g_intern_static_string ("DhLinkFlags"),
+ values);
+ }
+ return the_type;
+}
+
+
+GType
+dh_open_link_flags_get_type (void)
+{
+ static GType the_type = 0;
+
+ if (the_type == 0)
+ {
+ static const GFlagsValue values[] = {
+ { DH_OPEN_LINK_NEW_WINDOW,
+ "DH_OPEN_LINK_NEW_WINDOW",
+ "window" },
+ { DH_OPEN_LINK_NEW_TAB,
+ "DH_OPEN_LINK_NEW_TAB",
+ "tab" },
+ { 0, NULL, NULL }
+ };
+ the_type = g_flags_register_static (
+ g_intern_static_string ("DhOpenLinkFlags"),
+ values);
+ }
+ return the_type;
+}
+
+
+/* Generated data ends here */
+
Modified: devhelp/devhelp/dh-enum-types.c.template
47 files changed, 47 insertions(+), 0 deletions(-)
===================================================================
@@ -0,0 +1,47 @@
+/*** BEGIN file-header ***/
+#include "dh-enum-types.h"
+#include "dh-assistant.h"
+#include "dh-assistant-view.h"
+#include "dh-base.h"
+#include "dh-book-manager.h"
+#include "dh-book.h"
+#include "dh-book-tree.h"
+#include "dh-error.h"
+#include "dh-keyword-model.h"
+#include "dh-link.h"
+#include "dh-search.h"
+#include "dh-window.h"
+/*** END file-header ***/
+
+/*** BEGIN file-production ***/
+
+/*** END file-production ***/
+
+/*** BEGIN value-header ***/
+GType
+ at enum_name@_get_type (void)
+{
+ static GType the_type = 0;
+
+ if (the_type == 0)
+ {
+ static const G at Type@Value values[] = {
+/*** END value-header ***/
+
+/*** BEGIN value-production ***/
+ { @VALUENAME@,
+ "@VALUENAME@",
+ "@valuenick@" },
+/*** END value-production ***/
+
+/*** BEGIN value-tail ***/
+ { 0, NULL, NULL }
+ };
+ the_type = g_ at type@_register_static (
+ g_intern_static_string ("@EnumName@"),
+ values);
+ }
+ return the_type;
+}
+
+/*** END value-tail ***/
Modified: devhelp/devhelp/dh-enum-types.h
34 files changed, 34 insertions(+), 0 deletions(-)
===================================================================
@@ -0,0 +1,34 @@
+
+/* Generated data (by glib-mkenums) */
+
+#ifndef __DH_ENUM_TYPES_H__
+#define __DH_ENUM_TYPES_H__
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+/* Enumerations from "dh-error.h" */
+
+#define DH_TYPE_ERROR (dh_error_get_type())
+GType dh_error_get_type (void) G_GNUC_CONST;
+
+/* Enumerations from "dh-link.h" */
+
+#define DH_TYPE_LINK_TYPE (dh_link_type_get_type())
+GType dh_link_type_get_type (void) G_GNUC_CONST;
+
+#define DH_TYPE_LINK_FLAGS (dh_link_flags_get_type())
+GType dh_link_flags_get_type (void) G_GNUC_CONST;
+
+/* Enumerations from "dh-window.h" */
+
+#define DH_TYPE_OPEN_LINK_FLAGS (dh_open_link_flags_get_type())
+GType dh_open_link_flags_get_type (void) G_GNUC_CONST;
+
+G_END_DECLS
+
+#endif /* __DH_ENUM_TYPES_H__ */
+
+/* Generated data ends here */
+
Modified: devhelp/devhelp/dh-enum-types.h.template
27 files changed, 27 insertions(+), 0 deletions(-)
===================================================================
@@ -0,0 +1,27 @@
+/*** BEGIN file-header ***/
+#ifndef __DH_ENUM_TYPES_H__
+#define __DH_ENUM_TYPES_H__
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+/*** END file-header ***/
+
+/*** BEGIN file-production ***/
+/* Enumerations from "@filename@" */
+
+/*** END file-production ***/
+
+/*** BEGIN enumeration-production ***/
+#define DH_TYPE_ at ENUMSHORT@ (@enum_name at _get_type())
+GType @enum_name at _get_type (void) G_GNUC_CONST;
+
+/*** END enumeration-production ***/
+
+/*** BEGIN file-tail ***/
+G_END_DECLS
+
+#endif /* __DH_ENUM_TYPES_H__ */
+/*** END file-tail ***/
+
Modified: devhelp/devhelp/dh-error.c
35 files changed, 35 insertions(+), 0 deletions(-)
===================================================================
@@ -0,0 +1,35 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2002 CodeFactory AB
+ * Copyright (C) 2002 Mikael Hallendal <micke at imendio.com>
+ *
+ * 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.
+ */
+
+#include "config.h"
+#include "dh-error.h"
+
+GQuark
+dh_error_quark (void)
+{
+ static GQuark q = 0;
+
+ if (q == 0) {
+ q = g_quark_from_static_string ("dh-error-quark");
+ }
+
+ return q;
+}
Modified: devhelp/devhelp/dh-error.h
42 files changed, 42 insertions(+), 0 deletions(-)
===================================================================
@@ -0,0 +1,42 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2002 CodeFactory AB
+ * Copyright (C) 2002 Mikael Hallendal <micke at imendio.com>
+ *
+ * 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.
+ */
+
+#ifndef __DH_ERROR_H__
+#define __DH_ERROR_H__
+
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+#define DH_ERROR dh_error_quark ()
+
+typedef enum {
+ DH_ERROR_FILE_NOT_FOUND,
+ DH_ERROR_MALFORMED_BOOK,
+ DH_ERROR_INVALID_BOOK_TYPE,
+ DH_ERROR_INTERNAL_ERROR
+} DhError;
+
+GQuark dh_error_quark (void) G_GNUC_CONST;
+
+G_END_DECLS
+
+#endif /* __DH_ERROR_H__ */
Modified: devhelp/devhelp/dh-keyword-model.c
545 files changed, 545 insertions(+), 0 deletions(-)
===================================================================
@@ -0,0 +1,545 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2002 CodeFactory AB
+ * Copyright (C) 2002 Mikael Hallendal <micke at imendio.com>
+ * Copyright (C) 2008 Imendio AB
+ *
+ * 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.
+ */
+
+#include "config.h"
+#include <gtk/gtk.h>
+#include <string.h>
+
+#include "dh-link.h"
+#include "dh-book.h"
+#include "dh-keyword-model.h"
+
+struct _DhKeywordModelPriv {
+ DhBookManager *book_manager;
+
+ GList *keyword_words;
+ gint keyword_words_length;
+
+ gint stamp;
+};
+
+#define G_LIST(x) ((GList *) x)
+#define MAX_HITS 100
+
+static void dh_keyword_model_init (DhKeywordModel *list_store);
+static void dh_keyword_model_class_init (DhKeywordModelClass *class);
+static void dh_keyword_model_tree_model_init (GtkTreeModelIface *iface);
+
+G_DEFINE_TYPE_WITH_CODE (DhKeywordModel, dh_keyword_model, G_TYPE_OBJECT,
+ G_IMPLEMENT_INTERFACE (GTK_TYPE_TREE_MODEL,
+ dh_keyword_model_tree_model_init));
+
+static void
+keyword_model_dispose (GObject *object)
+{
+ DhKeywordModel *model = DH_KEYWORD_MODEL (object);
+ DhKeywordModelPriv *priv = model->priv;
+
+ if (priv->book_manager) {
+ g_object_unref (priv->book_manager);
+ priv->book_manager = NULL;
+ }
+
+ G_OBJECT_CLASS (dh_keyword_model_parent_class)->dispose (object);
+}
+
+static void
+keyword_model_finalize (GObject *object)
+{
+ DhKeywordModel *model = DH_KEYWORD_MODEL (object);
+ DhKeywordModelPriv *priv = model->priv;
+
+ g_list_free (priv->keyword_words);
+
+ g_free (model->priv);
+
+ G_OBJECT_CLASS (dh_keyword_model_parent_class)->finalize (object);
+}
+
+static void
+dh_keyword_model_class_init (DhKeywordModelClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);;
+
+ object_class->finalize = keyword_model_finalize;
+ object_class->dispose = keyword_model_dispose;
+}
+
+static void
+dh_keyword_model_init (DhKeywordModel *model)
+{
+ DhKeywordModelPriv *priv;
+
+ priv = g_new0 (DhKeywordModelPriv, 1);
+ model->priv = priv;
+
+ do {
+ priv->stamp = g_random_int ();
+ } while (priv->stamp == 0);
+}
+
+static GtkTreeModelFlags
+keyword_model_get_flags (GtkTreeModel *tree_model)
+{
+ return GTK_TREE_MODEL_ITERS_PERSIST | GTK_TREE_MODEL_LIST_ONLY;
+}
+
+static gint
+keyword_model_get_n_columns (GtkTreeModel *tree_model)
+{
+ return DH_KEYWORD_MODEL_NUM_COLS;
+}
+
+static GType
+keyword_model_get_column_type (GtkTreeModel *tree_model,
+ gint column)
+{
+ switch (column) {
+ case DH_KEYWORD_MODEL_COL_NAME:
+ return G_TYPE_STRING;
+ break;
+ case DH_KEYWORD_MODEL_COL_LINK:
+ return G_TYPE_POINTER;
+ default:
+ return G_TYPE_INVALID;
+ }
+}
+
+static gboolean
+keyword_model_get_iter (GtkTreeModel *tree_model,
+ GtkTreeIter *iter,
+ GtkTreePath *path)
+{
+ DhKeywordModel *model;
+ DhKeywordModelPriv *priv;
+ GList *node;
+ const gint *indices;
+
+ model = DH_KEYWORD_MODEL (tree_model);
+ priv = model->priv;
+
+ indices = gtk_tree_path_get_indices (path);
+
+ if (indices == NULL) {
+ return FALSE;
+ }
+
+ if (indices[0] >= priv->keyword_words_length) {
+ return FALSE;
+ }
+
+ node = g_list_nth (priv->keyword_words, indices[0]);
+
+ iter->stamp = priv->stamp;
+ iter->user_data = node;
+
+ return TRUE;
+}
+
+static GtkTreePath *
+keyword_model_get_path (GtkTreeModel *tree_model,
+ GtkTreeIter *iter)
+{
+ DhKeywordModel *model = DH_KEYWORD_MODEL (tree_model);
+ DhKeywordModelPriv *priv;
+ GtkTreePath *path;
+ gint i = 0;
+
+ g_return_val_if_fail (iter->stamp == model->priv->stamp, NULL);
+
+ priv = model->priv;
+
+ i = g_list_position (priv->keyword_words, iter->user_data);
+ if (i < 0) {
+ return NULL;
+ }
+
+ path = gtk_tree_path_new ();
+ gtk_tree_path_append_index (path, i);
+
+ return path;
+}
+
+static void
+keyword_model_get_value (GtkTreeModel *tree_model,
+ GtkTreeIter *iter,
+ gint column,
+ GValue *value)
+{
+ DhLink *link;
+
+ link = G_LIST (iter->user_data)->data;
+
+ switch (column) {
+ case DH_KEYWORD_MODEL_COL_NAME:
+ g_value_init (value, G_TYPE_STRING);
+ g_value_set_string (value, dh_link_get_name (link));
+ break;
+ case DH_KEYWORD_MODEL_COL_LINK:
+ g_value_init (value, G_TYPE_POINTER);
+ g_value_set_pointer (value, link);
+ break;
+ default:
+ g_warning ("Bad column %d requested", column);
+ }
+}
+
+static gboolean
+keyword_model_iter_next (GtkTreeModel *tree_model,
+ GtkTreeIter *iter)
+{
+ DhKeywordModel *model = DH_KEYWORD_MODEL (tree_model);
+
+ g_return_val_if_fail (model->priv->stamp == iter->stamp, FALSE);
+
+ iter->user_data = G_LIST (iter->user_data)->next;
+
+ return (iter->user_data != NULL);
+}
+
+static gboolean
+keyword_model_iter_children (GtkTreeModel *tree_model,
+ GtkTreeIter *iter,
+ GtkTreeIter *parent)
+{
+ DhKeywordModelPriv *priv;
+
+ priv = DH_KEYWORD_MODEL (tree_model)->priv;
+
+ /* This is a list, nodes have no children. */
+ if (parent) {
+ return FALSE;
+ }
+
+ /* But if parent == NULL we return the list itself as children of
+ * the "root".
+ */
+ if (priv->keyword_words) {
+ iter->stamp = priv->stamp;
+ iter->user_data = priv->keyword_words;
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static gboolean
+keyword_model_iter_has_child (GtkTreeModel *tree_model,
+ GtkTreeIter *iter)
+{
+ return FALSE;
+}
+
+static gint
+keyword_model_iter_n_children (GtkTreeModel *tree_model,
+ GtkTreeIter *iter)
+{
+ DhKeywordModelPriv *priv;
+
+ priv = DH_KEYWORD_MODEL (tree_model)->priv;
+
+ if (iter == NULL) {
+ return priv->keyword_words_length;
+ }
+
+ g_return_val_if_fail (priv->stamp == iter->stamp, -1);
+
+ return 0;
+}
+
+static gboolean
+keyword_model_iter_nth_child (GtkTreeModel *tree_model,
+ GtkTreeIter *iter,
+ GtkTreeIter *parent,
+ gint n)
+{
+ DhKeywordModelPriv *priv;
+ GList *child;
+
+ priv = DH_KEYWORD_MODEL (tree_model)->priv;
+
+ if (parent) {
+ return FALSE;
+ }
+
+ child = g_list_nth (priv->keyword_words, n);
+
+ if (child) {
+ iter->stamp = priv->stamp;
+ iter->user_data = child;
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static gboolean
+keyword_model_iter_parent (GtkTreeModel *tree_model,
+ GtkTreeIter *iter,
+ GtkTreeIter *child)
+{
+ return FALSE;
+}
+
+static void
+dh_keyword_model_tree_model_init (GtkTreeModelIface *iface)
+{
+ iface->get_flags = keyword_model_get_flags;
+ iface->get_n_columns = keyword_model_get_n_columns;
+ iface->get_column_type = keyword_model_get_column_type;
+ iface->get_iter = keyword_model_get_iter;
+ iface->get_path = keyword_model_get_path;
+ iface->get_value = keyword_model_get_value;
+ iface->iter_next = keyword_model_iter_next;
+ iface->iter_children = keyword_model_iter_children;
+ iface->iter_has_child = keyword_model_iter_has_child;
+ iface->iter_n_children = keyword_model_iter_n_children;
+ iface->iter_nth_child = keyword_model_iter_nth_child;
+ iface->iter_parent = keyword_model_iter_parent;
+}
+
+DhKeywordModel *
+dh_keyword_model_new (void)
+{
+ DhKeywordModel *model;
+
+ model = g_object_new (DH_TYPE_KEYWORD_MODEL, NULL);
+
+ return model;
+}
+
+void
+dh_keyword_model_set_words (DhKeywordModel *model,
+ DhBookManager *book_manager)
+{
+ g_return_if_fail (DH_IS_KEYWORD_MODEL (model));
+
+ model->priv->book_manager = g_object_ref (book_manager);
+}
+
+static GList *
+keyword_model_search (DhKeywordModel *model,
+ const gchar *string,
+ gchar **stringv,
+ const gchar *book_id,
+ gboolean case_sensitive,
+ DhLink **exact_link)
+{
+ DhKeywordModelPriv *priv;
+ GList *new_list = NULL, *b;
+ gint hits = 0;
+ gchar *page_id = NULL;
+ gchar *page_filename_prefix = NULL;
+
+ priv = model->priv;
+
+ /* The search string may be prefixed by a page:foobar qualifier, it
+ * will be matched against the filenames of the hits to limit the
+ * search to pages whose filename is prefixed by "foobar.
+ */
+ if (stringv && g_str_has_prefix(stringv[0], "page:")) {
+ page_id = stringv[0] + 5;
+ page_filename_prefix = g_strdup_printf("%s.", page_id);
+ stringv++;
+ }
+
+ for (b = dh_book_manager_get_books (priv->book_manager);
+ b && hits < MAX_HITS;
+ b = g_list_next (b)) {
+ DhBook *book;
+ GList *l;
+
+ book = DH_BOOK (b->data);
+
+ for (l = dh_book_get_keywords (book);
+ l && hits < MAX_HITS;
+ l = g_list_next (l)) {
+ DhLink *link;
+ gboolean found;
+ gchar *name;
+
+ link = l->data;
+ found = FALSE;
+
+ if (book_id &&
+ dh_link_get_book_id (link) &&
+ strcmp (dh_link_get_book_id (link), book_id) != 0) {
+ continue;
+ }
+
+ if (page_id &&
+ (dh_link_get_link_type (link) != DH_LINK_TYPE_PAGE &&
+ !g_str_has_prefix (dh_link_get_file_name (link), page_filename_prefix))) {
+ continue;
+ }
+
+ if (!case_sensitive) {
+ name = g_ascii_strdown (dh_link_get_name (link), -1);
+ } else {
+ name = g_strdup (dh_link_get_name (link));
+ }
+
+ if (!found) {
+ gint i;
+
+ if (stringv[0] == NULL) {
+ /* means only a page was specified, no keyword */
+ if (g_strrstr (dh_link_get_name(link), page_id))
+ found = TRUE;
+ } else {
+ found = TRUE;
+ for (i = 0; stringv[i] != NULL; i++) {
+ if (!g_strrstr (name, stringv[i])) {
+ found = FALSE;
+ break;
+ }
+ }
+ }
+ }
+
+ g_free (name);
+
+ if (found) {
+ /* Include in the new list. */
+ new_list = g_list_prepend (new_list, link);
+ hits++;
+
+ if (!*exact_link &&
+ dh_link_get_name (link) && (
+ (dh_link_get_link_type (link) == DH_LINK_TYPE_PAGE &&
+ page_id && strcmp (dh_link_get_name (link), page_id) == 0) ||
+ (strcmp (dh_link_get_name (link), string) == 0))) {
+ *exact_link = link;
+ }
+ }
+ }
+ }
+
+ g_free (page_filename_prefix);
+
+ return g_list_sort (new_list, dh_link_compare);
+}
+
+DhLink *
+dh_keyword_model_filter (DhKeywordModel *model,
+ const gchar *string,
+ const gchar *book_id)
+{
+ DhKeywordModelPriv *priv;
+ GList *new_list = NULL;
+ gint old_length;
+ DhLink *exact_link = NULL;
+ gint hits;
+ gint i;
+ GtkTreePath *path;
+ GtkTreeIter iter;
+
+ g_return_val_if_fail (DH_IS_KEYWORD_MODEL (model), NULL);
+ g_return_val_if_fail (string != NULL, NULL);
+
+ priv = model->priv;
+
+ /* Do the minimum amount of work: call update on all rows that are
+ * kept and remove the rest.
+ */
+ old_length = priv->keyword_words_length;
+ new_list = NULL;
+ hits = 0;
+
+ if (string[0] != '\0') {
+ gchar **stringv;
+ gboolean case_sensitive;
+
+ stringv = g_strsplit (string, " ", -1);
+
+ case_sensitive = FALSE;
+
+ /* Search for any parameters and position search cursor to
+ * the next element in the search string.
+ */
+ for (i = 0; stringv[i] != NULL; i++) {
+ gchar *lower;
+
+ /* Searches are case sensitive when any uppercase
+ * letter is used in the search terms, matching vim
+ * smartcase behaviour.
+ */
+ lower = g_ascii_strdown (stringv[i], -1);
+ if (strcmp (lower, stringv[i]) != 0) {
+ case_sensitive = TRUE;
+ g_free (lower);
+ break;
+ }
+ g_free (lower);
+ }
+
+ new_list = keyword_model_search (model,
+ string,
+ stringv,
+ book_id,
+ case_sensitive,
+ &exact_link);
+ hits = g_list_length (new_list);
+
+ g_strfreev (stringv);
+ }
+
+ /* Update the list of hits. */
+ g_list_free (priv->keyword_words);
+ priv->keyword_words = new_list;
+ priv->keyword_words_length = hits;
+
+ /* Update model: rows 0 -> hits. */
+ for (i = 0; i < hits; ++i) {
+ path = gtk_tree_path_new ();
+ gtk_tree_path_append_index (path, i);
+ keyword_model_get_iter (GTK_TREE_MODEL (model), &iter, path);
+ gtk_tree_model_row_changed (GTK_TREE_MODEL (model), path, &iter);
+ gtk_tree_path_free (path);
+ }
+
+ if (old_length > hits) {
+ /* Update model: remove rows hits -> old_length. */
+ for (i = old_length - 1; i >= hits; i--) {
+ path = gtk_tree_path_new ();
+ gtk_tree_path_append_index (path, i);
+ gtk_tree_model_row_deleted (GTK_TREE_MODEL (model), path);
+ gtk_tree_path_free (path);
+ }
+ }
+ else if (old_length < hits) {
+ /* Update model: add rows old_length -> hits. */
+ for (i = old_length; i < hits; i++) {
+ path = gtk_tree_path_new ();
+ gtk_tree_path_append_index (path, i);
+ keyword_model_get_iter (GTK_TREE_MODEL (model), &iter, path);
+ gtk_tree_model_row_inserted (GTK_TREE_MODEL (model), path, &iter);
+ gtk_tree_path_free (path);
+ }
+ }
+
+ if (hits == 1) {
+ return priv->keyword_words->data;
+ }
+
+ return exact_link;
+}
Modified: devhelp/devhelp/dh-keyword-model.h
69 files changed, 69 insertions(+), 0 deletions(-)
===================================================================
@@ -0,0 +1,69 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2002 CodeFactory AB
+ * Copyright (C) 2002 Mikael Hallendal <micke at imendio.com>
+ *
+ * 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.
+ */
+
+#ifndef __DH_KEYWORD_MODEL_H__
+#define __DH_KEYWORD_MODEL_H__
+
+#include <gtk/gtk.h>
+#include "dh-link.h"
+#include "dh-book-manager.h"
+
+G_BEGIN_DECLS
+
+#define DH_TYPE_KEYWORD_MODEL (dh_keyword_model_get_type ())
+#define DH_KEYWORD_MODEL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), DH_TYPE_KEYWORD_MODEL, DhKeywordModel))
+#define DH_KEYWORD_MODEL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), DH_TYPE_KEYWORD_MODEL, DhKeywordModelClass))
+#define DH_IS_KEYWORD_MODEL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), DH_TYPE_KEYWORD_MODEL))
+#define DH_IS_KEYWORD_MODEL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), DH_TYPE_KEYWORD_MODEL))
+#define DH_KEYWORD_MODEL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), DH_TYPE_KEYWORD_MODEL, DhKeywordModelClass))
+
+typedef struct _DhKeywordModel DhKeywordModel;
+typedef struct _DhKeywordModelClass DhKeywordModelClass;
+typedef struct _DhKeywordModelPriv DhKeywordModelPriv;
+
+struct _DhKeywordModel
+{
+ GObject parent_instance;
+ DhKeywordModelPriv *priv;
+};
+
+struct _DhKeywordModelClass
+{
+ GObjectClass parent_class;
+};
+
+enum {
+ DH_KEYWORD_MODEL_COL_NAME,
+ DH_KEYWORD_MODEL_COL_LINK,
+ DH_KEYWORD_MODEL_NUM_COLS
+};
+
+GType dh_keyword_model_get_type (void);
+DhKeywordModel *dh_keyword_model_new (void);
+void dh_keyword_model_set_words (DhKeywordModel *model,
+ DhBookManager *book_manager);
+DhLink * dh_keyword_model_filter (DhKeywordModel *model,
+ const gchar *string,
+ const gchar *book_id);
+
+G_END_DECLS
+
+#endif /* __DH_KEYWORD_MODEL_H__ */
Modified: devhelp/devhelp/dh-link.c
291 files changed, 291 insertions(+), 0 deletions(-)
===================================================================
@@ -0,0 +1,291 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2001-2002 Mikael Hallendal <micke at imendio.com>
+ * Copyright (C) 2008 Imendio AB
+ *
+ * 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.
+ */
+
+#include "config.h"
+#include <string.h>
+#include <glib-object.h>
+#include <glib/gi18n-lib.h>
+#include "dh-link.h"
+
+struct _DhLink {
+ /* FIXME: Those two could exist only for book to save some
+ * memory.
+ */
+ gchar *id;
+ gchar *base;
+
+ gchar *name;
+ gchar *filename;
+
+ DhLink *book;
+ DhLink *page;
+
+ guint ref_count;
+
+ DhLinkType type : 8;
+ DhLinkFlags flags : 8;
+};
+
+GType
+dh_link_get_type (void)
+{
+ static GType type = 0;
+
+ if (G_UNLIKELY (type == 0)) {
+ type = g_boxed_type_register_static (
+ "DhLink",
+ (GBoxedCopyFunc) dh_link_ref,
+ (GBoxedFreeFunc) dh_link_unref);
+ }
+ return type;
+}
+
+static void
+link_free (DhLink *link)
+{
+ g_free (link->base);
+ g_free (link->id);
+ g_free (link->name);
+ g_free (link->filename);
+
+ if (link->book) {
+ dh_link_unref (link->book);
+ }
+ if (link->page) {
+ dh_link_unref (link->page);
+ }
+
+ g_slice_free (DhLink, link);
+}
+
+DhLink *
+dh_link_new (DhLinkType type,
+ const gchar *base,
+ const gchar *id,
+ const gchar *name,
+ DhLink *book,
+ DhLink *page,
+ const gchar *filename)
+{
+ DhLink *link;
+
+ g_return_val_if_fail (name != NULL, NULL);
+ g_return_val_if_fail (filename != NULL, NULL);
+
+ if (type == DH_LINK_TYPE_BOOK) {
+ g_return_val_if_fail (base != NULL, NULL);
+ g_return_val_if_fail (id != NULL, NULL);
+ }
+ if (type != DH_LINK_TYPE_BOOK && type != DH_LINK_TYPE_PAGE) {
+ g_return_val_if_fail (book != NULL, NULL);
+ g_return_val_if_fail (page != NULL, NULL);
+ }
+
+ link = g_slice_new0 (DhLink);
+
+ link->ref_count = 1;
+ link->type = type;
+
+ if (type == DH_LINK_TYPE_BOOK) {
+ link->base = g_strdup (base);
+ link->id = g_strdup (id);
+ }
+
+ link->name = g_strdup (name);
+ link->filename = g_strdup (filename);
+
+ if (book) {
+ link->book = dh_link_ref (book);
+ }
+ if (page) {
+ link->page = dh_link_ref (page);
+ }
+
+ return link;
+}
+
+gint
+dh_link_compare (gconstpointer a,
+ gconstpointer b)
+{
+ DhLink *la = (DhLink *) a;
+ DhLink *lb = (DhLink *) b;
+ gint flags_diff;
+
+ /* Sort deprecated hits last. */
+ flags_diff = (la->flags & DH_LINK_FLAGS_DEPRECATED) -
+ (lb->flags & DH_LINK_FLAGS_DEPRECATED);
+ if (flags_diff != 0) {
+ return flags_diff;
+ }
+
+ return strcmp (la->name, lb->name);
+}
+
+DhLink *
+dh_link_ref (DhLink *link)
+{
+ g_return_val_if_fail (link != NULL, NULL);
+
+ link->ref_count++;
+
+ return link;
+}
+
+void
+dh_link_unref (DhLink *link)
+{
+ g_return_if_fail (link != NULL);
+
+ link->ref_count--;
+
+ if (link->ref_count == 0) {
+ link_free (link);
+ }
+}
+
+const gchar *
+dh_link_get_name (DhLink *link)
+{
+ return link->name;
+}
+
+const gchar *
+dh_link_get_book_name (DhLink *link)
+{
+ if (link->book) {
+ return link->book->name;
+ }
+
+ return "";
+}
+
+const gchar *
+dh_link_get_page_name (DhLink *link)
+{
+ if (link->page) {
+ return link->page->name;
+ }
+
+ return "";
+}
+
+const gchar *
+dh_link_get_file_name (DhLink *link)
+{
+ if (link->page) {
+ return link->filename;
+ }
+
+ return "";
+}
+
+const gchar *
+dh_link_get_book_id (DhLink *link)
+{
+ if (link->type == DH_LINK_TYPE_BOOK) {
+ return link->id;
+ }
+
+ if (link->book) {
+ return link->book->id;
+ }
+
+ return "";
+}
+
+gchar *
+dh_link_get_uri (DhLink *link)
+{
+ gchar *base, *uri;
+
+ if (link->type == DH_LINK_TYPE_BOOK)
+ base = link->base;
+ else
+ base = link->book->base;
+
+ uri = g_strconcat ("file://", base, "/", link->filename, NULL, NULL);
+
+ return uri;
+}
+
+DhLinkType
+dh_link_get_link_type (DhLink *link)
+{
+ return link->type;
+}
+
+DhLinkFlags
+dh_link_get_flags (DhLink *link)
+{
+ return link->flags;
+}
+
+void
+dh_link_set_flags (DhLink *link,
+ DhLinkFlags flags)
+{
+ link->flags = flags;
+}
+
+const gchar *
+dh_link_get_type_as_string (DhLink *link)
+{
+ switch (link->type) {
+ case DH_LINK_TYPE_BOOK:
+ /* i18n: a documentation book */
+ return _("Book");
+ case DH_LINK_TYPE_PAGE:
+ /* i18n: a "page" in a documentation book */
+ return _("Page");
+ case DH_LINK_TYPE_KEYWORD:
+ /* i18n: a search hit in the documentation, could be a
+ * function, macro, struct, etc */
+ return _("Keyword");
+ case DH_LINK_TYPE_FUNCTION:
+ /* i18n: in the programming language context, if you don't
+ * have an ESTABLISHED term for it, leave it
+ * untranslated. */
+ return _("Function");
+ case DH_LINK_TYPE_STRUCT:
+ /* i18n: in the programming language context, if you don't
+ * have an ESTABLISHED term for it, leave it
+ * untranslated. */
+ return _("Struct");
+ case DH_LINK_TYPE_MACRO:
+ /* i18n: in the programming language context, if you don't
+ * have an ESTABLISHED term for it, leave it
+ * untranslated. */
+ return _("Macro");
+ case DH_LINK_TYPE_ENUM:
+ /* i18n: in the programming language context, if you don't
+ * have an ESTABLISHED term for it, leave it
+ * untranslated. */
+ return _("Enum");
+ case DH_LINK_TYPE_TYPEDEF:
+ /* i18n: in the programming language context, if you don't
+ * have an ESTABLISHED term for it, leave it
+ * untranslated. */
+ return _("Type");
+ }
+
+ return "";
+}
Modified: devhelp/devhelp/dh-link.h
72 files changed, 72 insertions(+), 0 deletions(-)
===================================================================
@@ -0,0 +1,72 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2002 Mikael Hallendal <micke at imendio.com>
+ * Copyright (C) 2008 Imendio AB
+ *
+ * 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.
+ */
+
+#ifndef __DH_LINK_H__
+#define __DH_LINK_H__
+
+#include <glib-object.h>
+
+typedef enum {
+ DH_LINK_TYPE_BOOK,
+ DH_LINK_TYPE_PAGE,
+ DH_LINK_TYPE_KEYWORD,
+ DH_LINK_TYPE_FUNCTION,
+ DH_LINK_TYPE_STRUCT,
+ DH_LINK_TYPE_MACRO,
+ DH_LINK_TYPE_ENUM,
+ DH_LINK_TYPE_TYPEDEF
+} DhLinkType;
+
+typedef enum {
+ DH_LINK_FLAGS_NONE = 0,
+ DH_LINK_FLAGS_DEPRECATED = 1 << 0
+} DhLinkFlags;
+
+typedef struct _DhLink DhLink;
+
+#define DH_TYPE_LINK (dh_link_get_type ())
+
+GType dh_link_get_type (void);
+DhLink * dh_link_new (DhLinkType type,
+ const gchar *base,
+ const gchar *id,
+ const gchar *name,
+ DhLink *book,
+ DhLink *page,
+ const gchar *filename);
+void dh_link_free (DhLink *link);
+gint dh_link_compare (gconstpointer a,
+ gconstpointer b);
+DhLink * dh_link_ref (DhLink *link);
+void dh_link_unref (DhLink *link);
+const gchar *dh_link_get_name (DhLink *link);
+const gchar *dh_link_get_book_name (DhLink *link);
+const gchar *dh_link_get_page_name (DhLink *link);
+const gchar *dh_link_get_file_name (DhLink *link);
+const gchar *dh_link_get_book_id (DhLink *link);
+gchar *dh_link_get_uri (DhLink *link);
+DhLinkFlags dh_link_get_flags (DhLink *link);
+void dh_link_set_flags (DhLink *link,
+ DhLinkFlags flags);
+DhLinkType dh_link_get_link_type (DhLink *link);
+const gchar *dh_link_get_type_as_string (DhLink *link);
+
+#endif /* __DH_LINK_H__ */
Modified: devhelp/devhelp/dh-marshal.c
148 files changed, 148 insertions(+), 0 deletions(-)
===================================================================
@@ -0,0 +1,148 @@
+#include "dh-marshal.h"
+
+#include <glib-object.h>
+
+
+#ifdef G_ENABLE_DEBUG
+#define g_marshal_value_peek_boolean(v) g_value_get_boolean (v)
+#define g_marshal_value_peek_char(v) g_value_get_char (v)
+#define g_marshal_value_peek_uchar(v) g_value_get_uchar (v)
+#define g_marshal_value_peek_int(v) g_value_get_int (v)
+#define g_marshal_value_peek_uint(v) g_value_get_uint (v)
+#define g_marshal_value_peek_long(v) g_value_get_long (v)
+#define g_marshal_value_peek_ulong(v) g_value_get_ulong (v)
+#define g_marshal_value_peek_int64(v) g_value_get_int64 (v)
+#define g_marshal_value_peek_uint64(v) g_value_get_uint64 (v)
+#define g_marshal_value_peek_enum(v) g_value_get_enum (v)
+#define g_marshal_value_peek_flags(v) g_value_get_flags (v)
+#define g_marshal_value_peek_float(v) g_value_get_float (v)
+#define g_marshal_value_peek_double(v) g_value_get_double (v)
+#define g_marshal_value_peek_string(v) (char*) g_value_get_string (v)
+#define g_marshal_value_peek_param(v) g_value_get_param (v)
+#define g_marshal_value_peek_boxed(v) g_value_get_boxed (v)
+#define g_marshal_value_peek_pointer(v) g_value_get_pointer (v)
+#define g_marshal_value_peek_object(v) g_value_get_object (v)
+#define g_marshal_value_peek_variant(v) g_value_get_variant (v)
+#else /* !G_ENABLE_DEBUG */
+/* WARNING: This code accesses GValues directly, which is UNSUPPORTED API.
+ * Do not access GValues directly in your code. Instead, use the
+ * g_value_get_*() functions
+ */
+#define g_marshal_value_peek_boolean(v) (v)->data[0].v_int
+#define g_marshal_value_peek_char(v) (v)->data[0].v_int
+#define g_marshal_value_peek_uchar(v) (v)->data[0].v_uint
+#define g_marshal_value_peek_int(v) (v)->data[0].v_int
+#define g_marshal_value_peek_uint(v) (v)->data[0].v_uint
+#define g_marshal_value_peek_long(v) (v)->data[0].v_long
+#define g_marshal_value_peek_ulong(v) (v)->data[0].v_ulong
+#define g_marshal_value_peek_int64(v) (v)->data[0].v_int64
+#define g_marshal_value_peek_uint64(v) (v)->data[0].v_uint64
+#define g_marshal_value_peek_enum(v) (v)->data[0].v_long
+#define g_marshal_value_peek_flags(v) (v)->data[0].v_ulong
+#define g_marshal_value_peek_float(v) (v)->data[0].v_float
+#define g_marshal_value_peek_double(v) (v)->data[0].v_double
+#define g_marshal_value_peek_string(v) (v)->data[0].v_pointer
+#define g_marshal_value_peek_param(v) (v)->data[0].v_pointer
+#define g_marshal_value_peek_boxed(v) (v)->data[0].v_pointer
+#define g_marshal_value_peek_pointer(v) (v)->data[0].v_pointer
+#define g_marshal_value_peek_object(v) (v)->data[0].v_pointer
+#define g_marshal_value_peek_variant(v) (v)->data[0].v_pointer
+#endif /* !G_ENABLE_DEBUG */
+
+
+/* VOID:BOOLEAN (dh-marshal.list:1) */
+
+/* VOID:POINTER (dh-marshal.list:2) */
+
+/* VOID:STRING (dh-marshal.list:3) */
+
+/* VOID:VOID (dh-marshal.list:4) */
+
+/* BOOLEAN:STRING (dh-marshal.list:5) */
+void
+_dh_marshal_BOOLEAN__STRING (GClosure *closure,
+ GValue *return_value G_GNUC_UNUSED,
+ guint n_param_values,
+ const GValue *param_values,
+ gpointer invocation_hint G_GNUC_UNUSED,
+ gpointer marshal_data)
+{
+ typedef gboolean (*GMarshalFunc_BOOLEAN__STRING) (gpointer data1,
+ gpointer arg_1,
+ gpointer data2);
+ register GMarshalFunc_BOOLEAN__STRING callback;
+ register GCClosure *cc = (GCClosure*) closure;
+ register gpointer data1, data2;
+ gboolean v_return;
+
+ g_return_if_fail (return_value != NULL);
+ g_return_if_fail (n_param_values == 2);
+
+ if (G_CCLOSURE_SWAP_DATA (closure))
+ {
+ data1 = closure->data;
+ data2 = g_value_peek_pointer (param_values + 0);
+ }
+ else
+ {
+ data1 = g_value_peek_pointer (param_values + 0);
+ data2 = closure->data;
+ }
+ callback = (GMarshalFunc_BOOLEAN__STRING) (marshal_data ? marshal_data : cc->callback);
+
+ v_return = callback (data1,
+ g_marshal_value_peek_string (param_values + 1),
+ data2);
+
+ g_value_set_boolean (return_value, v_return);
+}
+
+/* VOID:STRING,FLAGS (dh-marshal.list:6) */
+void
+_dh_marshal_VOID__STRING_FLAGS (GClosure *closure,
+ GValue *return_value G_GNUC_UNUSED,
+ guint n_param_values,
+ const GValue *param_values,
+ gpointer invocation_hint G_GNUC_UNUSED,
+ gpointer marshal_data)
+{
+ typedef void (*GMarshalFunc_VOID__STRING_FLAGS) (gpointer data1,
+ gpointer arg_1,
+ guint arg_2,
+ gpointer data2);
+ register GMarshalFunc_VOID__STRING_FLAGS callback;
+ register GCClosure *cc = (GCClosure*) closure;
+ register gpointer data1, data2;
+
+ g_return_if_fail (n_param_values == 3);
+
+ if (G_CCLOSURE_SWAP_DATA (closure))
+ {
+ data1 = closure->data;
+ data2 = g_value_peek_pointer (param_values + 0);
+ }
+ else
+ {
+ data1 = g_value_peek_pointer (param_values + 0);
+ data2 = closure->data;
+ }
+ callback = (GMarshalFunc_VOID__STRING_FLAGS) (marshal_data ? marshal_data : cc->callback);
+
+ callback (data1,
+ g_marshal_value_peek_string (param_values + 1),
+ g_marshal_value_peek_flags (param_values + 2),
+ data2);
+}
+
+/* VOID:BOOLEAN (dh-marshal.list:1) */
+
+/* VOID:POINTER (dh-marshal.list:2) */
+
+/* VOID:STRING (dh-marshal.list:3) */
+
+/* VOID:VOID (dh-marshal.list:4) */
+
+/* BOOLEAN:STRING (dh-marshal.list:5) */
+
+/* VOID:STRING,FLAGS (dh-marshal.list:6) */
+
Modified: devhelp/devhelp/dh-marshal.h
52 files changed, 52 insertions(+), 0 deletions(-)
===================================================================
@@ -0,0 +1,52 @@
+
+#ifndef ___dh_marshal_MARSHAL_H__
+#define ___dh_marshal_MARSHAL_H__
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+/* VOID:BOOLEAN (dh-marshal.list:1) */
+#define _dh_marshal_VOID__BOOLEAN g_cclosure_marshal_VOID__BOOLEAN
+
+/* VOID:POINTER (dh-marshal.list:2) */
+#define _dh_marshal_VOID__POINTER g_cclosure_marshal_VOID__POINTER
+
+/* VOID:STRING (dh-marshal.list:3) */
+#define _dh_marshal_VOID__STRING g_cclosure_marshal_VOID__STRING
+
+/* VOID:VOID (dh-marshal.list:4) */
+#define _dh_marshal_VOID__VOID g_cclosure_marshal_VOID__VOID
+
+/* BOOLEAN:STRING (dh-marshal.list:5) */
+extern void _dh_marshal_BOOLEAN__STRING (GClosure *closure,
+ GValue *return_value,
+ guint n_param_values,
+ const GValue *param_values,
+ gpointer invocation_hint,
+ gpointer marshal_data);
+
+/* VOID:STRING,FLAGS (dh-marshal.list:6) */
+extern void _dh_marshal_VOID__STRING_FLAGS (GClosure *closure,
+ GValue *return_value,
+ guint n_param_values,
+ const GValue *param_values,
+ gpointer invocation_hint,
+ gpointer marshal_data);
+
+/* VOID:BOOLEAN (dh-marshal.list:1) */
+
+/* VOID:POINTER (dh-marshal.list:2) */
+
+/* VOID:STRING (dh-marshal.list:3) */
+
+/* VOID:VOID (dh-marshal.list:4) */
+
+/* BOOLEAN:STRING (dh-marshal.list:5) */
+
+/* VOID:STRING,FLAGS (dh-marshal.list:6) */
+
+G_END_DECLS
+
+#endif /* ___dh_marshal_MARSHAL_H__ */
+
Modified: devhelp/devhelp/dh-marshal.list
6 files changed, 6 insertions(+), 0 deletions(-)
===================================================================
@@ -0,0 +1,6 @@
+VOID:BOOLEAN
+VOID:POINTER
+VOID:STRING
+VOID:VOID
+BOOLEAN:STRING
+VOID:STRING,FLAGS
Modified: devhelp/devhelp/dh-parser.c
611 files changed, 611 insertions(+), 0 deletions(-)
===================================================================
@@ -0,0 +1,611 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
+/*
+ * Copyright (c) 2002-2003 Mikael Hallendal <micke at imendio.com>
+ * Copyright (c) 2002-2003 CodeFactory AB
+ * Copyright (C) 2005,2008 Imendio AB
+ *
+ * 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.
+ */
+
+#include "config.h"
+#include <string.h>
+#include <errno.h>
+#include <zlib.h>
+#include <glib/gi18n-lib.h>
+
+#include "dh-error.h"
+#include "dh-link.h"
+#include "dh-parser.h"
+
+#define NAMESPACE "http://www.devhelp.net/book"
+#define BYTES_PER_READ 4096
+
+typedef struct {
+ GMarkupParser *m_parser;
+ GMarkupParseContext *context;
+
+ const gchar *path;
+
+ /* Top node of book */
+ GNode *book_node;
+
+ /* Current sub section node */
+ GNode *parent;
+
+ gboolean parsing_chapters;
+ gboolean parsing_keywords;
+
+ GNode **book_tree;
+ GList **keywords;
+
+ /* Version 2 uses <keyword> instead of <function>. */
+ gint version;
+} DhParser;
+
+static void
+dh_parser_free (DhParser *parser)
+{
+ // NOTE: priv->book_tree and priv->keywords do not need to be freed
+ // because they're only used to store the locations for the return
+ // params of dh_parser_read_file()
+
+ g_markup_parse_context_free (parser->context);
+ g_free (parser->m_parser);
+ g_free (parser);
+}
+
+static void
+parser_start_node_book (DhParser *parser,
+ GMarkupParseContext *context,
+ const gchar *node_name,
+ const gchar **attribute_names,
+ const gchar **attribute_values,
+ GError **error)
+{
+ gint i, j;
+ gint line, col;
+ gchar *title = NULL;
+ gchar *base = NULL;
+ const gchar *name = NULL;
+ const gchar *uri = NULL;
+ DhLink *link;
+
+ if (g_ascii_strcasecmp (node_name, "book") != 0) {
+ g_markup_parse_context_get_position (context, &line, &col);
+ g_set_error (error,
+ DH_ERROR,
+ DH_ERROR_MALFORMED_BOOK,
+ _("Expected '%s', got '%s' at line %d, column %d"),
+ "book", node_name, line, col);
+ return;
+ }
+
+ for (i = 0; attribute_names[i]; ++i) {
+ const gchar *xmlns;
+
+ if (g_ascii_strcasecmp (attribute_names[i], "xmlns") == 0) {
+ xmlns = attribute_values[i];
+ if (g_ascii_strcasecmp (xmlns, NAMESPACE) != 0) {
+ g_markup_parse_context_get_position (context,
+ &line,
+ &col);
+ g_set_error (error,
+ DH_ERROR,
+ DH_ERROR_MALFORMED_BOOK,
+ _("Invalid namespace '%s' at"
+ " line %d, column %d"),
+ xmlns, line, col);
+ return;
+ }
+ }
+ else if (g_ascii_strcasecmp (attribute_names[i], "name") == 0) {
+ name = attribute_values[i];
+ }
+ else if (g_ascii_strcasecmp (attribute_names[i], "title") == 0) {
+ title = g_strdup(attribute_values[i]);
+ for (j = 0; title[j]; j++) {
+ if (title[j] == '\n') title[j] = ' ';
+ }
+ }
+ else if (g_ascii_strcasecmp (attribute_names[i], "base") == 0) {
+ base = g_strdup (attribute_values[i]);
+ }
+ else if (g_ascii_strcasecmp (attribute_names[i], "link") == 0) {
+ uri = attribute_values[i];
+ }
+ }
+
+ if (!title || !name || !uri) {
+ g_markup_parse_context_get_position (context, &line, &col);
+ g_set_error (error,
+ DH_ERROR,
+ DH_ERROR_MALFORMED_BOOK,
+ _("\"title\", \"name\" and \"link\" elements are "
+ "required at line %d, column %d"),
+ line, col);
+ g_free (title);
+ return;
+ }
+
+ if (!base) {
+ base = g_path_get_dirname (parser->path);
+ }
+
+ link = dh_link_new (DH_LINK_TYPE_BOOK,
+ base,
+ name,
+ title,
+ NULL,
+ NULL,
+ uri);
+ g_free (base);
+
+ *parser->keywords = g_list_prepend (*parser->keywords, dh_link_ref (link));
+
+ parser->book_node = g_node_new (dh_link_ref (link));
+ *parser->book_tree = parser->book_node;
+ parser->parent = parser->book_node;
+ g_free (title);
+ dh_link_unref (link);
+}
+
+static void
+parser_start_node_chapter (DhParser *parser,
+ GMarkupParseContext *context,
+ const gchar *node_name,
+ const gchar **attribute_names,
+ const gchar **attribute_values,
+ GError **error)
+{
+ gint i;
+ gint line, col;
+ const gchar *name = NULL;
+ const gchar *uri = NULL;
+ DhLink *link;
+ GNode *node;
+
+ if (g_ascii_strcasecmp (node_name, "sub") != 0) {
+ g_markup_parse_context_get_position (context, &line, &col);
+ g_set_error (error,
+ DH_ERROR,
+ DH_ERROR_MALFORMED_BOOK,
+ _("Expected '%s', got '%s' at line %d, column %d"),
+ "sub", node_name, line, col);
+ return;
+ }
+
+ for (i = 0; attribute_names[i]; ++i) {
+ if (g_ascii_strcasecmp (attribute_names[i], "name") == 0) {
+ name = attribute_values[i];
+ }
+ else if (g_ascii_strcasecmp (attribute_names[i], "link") == 0) {
+ uri = attribute_values[i];
+ }
+ }
+
+ if (!name || !uri) {
+ g_markup_parse_context_get_position (context, &line, &col);
+ g_set_error (error,
+ DH_ERROR,
+ DH_ERROR_MALFORMED_BOOK,
+ _("\"name\" and \"link\" elements are required "
+ "inside <sub> on line %d, column %d"),
+ line, col);
+ return;
+ }
+
+ link = dh_link_new (DH_LINK_TYPE_PAGE,
+ NULL,
+ NULL,
+ name,
+ parser->book_node->data,
+ NULL,
+ uri);
+
+ *parser->keywords = g_list_prepend (*parser->keywords, link);
+
+ node = g_node_new (link);
+ g_node_prepend (parser->parent, node);
+ parser->parent = node;
+}
+
+static void
+parser_start_node_keyword (DhParser *parser,
+ GMarkupParseContext *context,
+ const gchar *node_name,
+ const gchar **attribute_names,
+ const gchar **attribute_values,
+ GError **error)
+{
+ gint i;
+ gint line, col;
+ const gchar *name = NULL;
+ const gchar *uri = NULL;
+ const gchar *type = NULL;
+ const gchar *deprecated = NULL;
+ DhLinkType link_type;
+ DhLink *link;
+ gchar *tmp;
+
+ if (parser->version == 2 &&
+ g_ascii_strcasecmp (node_name, "keyword") != 0) {
+ g_markup_parse_context_get_position (context, &line, &col);
+ g_set_error (error,
+ DH_ERROR,
+ DH_ERROR_MALFORMED_BOOK,
+ _("Expected '%s', got '%s' at line %d, column %d"),
+ "keyword", node_name, line, col);
+ return;
+ }
+ else if (parser->version == 1 &&
+ g_ascii_strcasecmp (node_name, "function") != 0) {
+ g_markup_parse_context_get_position (context, &line, &col);
+ g_set_error (error,
+ DH_ERROR,
+ DH_ERROR_MALFORMED_BOOK,
+ _("Expected '%s', got '%s' at line %d, column %d"),
+ "function", node_name, line, col);
+ return;
+ }
+
+ for (i = 0; attribute_names[i]; ++i) {
+ if (g_ascii_strcasecmp (attribute_names[i], "type") == 0) {
+ type = attribute_values[i];
+ }
+ else if (g_ascii_strcasecmp (attribute_names[i], "name") == 0) {
+ name = attribute_values[i];
+ }
+ else if (g_ascii_strcasecmp (attribute_names[i], "link") == 0) {
+ uri = attribute_values[i];
+ }
+ else if (g_ascii_strcasecmp (attribute_names[i], "deprecated") == 0) {
+ deprecated = attribute_values[i];
+ }
+ }
+
+ if (!name || !uri) {
+ g_markup_parse_context_get_position (context, &line, &col);
+ g_set_error (error,
+ DH_ERROR,
+ DH_ERROR_MALFORMED_BOOK,
+ _("\"name\" and \"link\" elements are required "
+ "inside '%s' on line %d, column %d"),
+ parser->version == 2 ? "keyword" : "function",
+ line, col);
+ return;
+ }
+
+ if (parser->version == 2 && !type) {
+ /* Required */
+ g_markup_parse_context_get_position (context, &line, &col);
+ g_set_error (error,
+ DH_ERROR,
+ DH_ERROR_MALFORMED_BOOK,
+ _("\"type\" element is required "
+ "inside <keyword> on line %d, column %d"),
+ line, col);
+ return;
+ }
+
+ if (parser->version == 2) {
+ if (strcmp (type, "function") == 0) {
+ link_type = DH_LINK_TYPE_FUNCTION;
+ }
+ else if (strcmp (type, "struct") == 0) {
+ link_type = DH_LINK_TYPE_STRUCT;
+ }
+ else if (strcmp (type, "macro") == 0) {
+ link_type = DH_LINK_TYPE_MACRO;
+ }
+ else if (strcmp (type, "enum") == 0) {
+ link_type = DH_LINK_TYPE_ENUM;
+ }
+ else if (strcmp (type, "typedef") == 0) {
+ link_type = DH_LINK_TYPE_TYPEDEF;
+ } else {
+ link_type = DH_LINK_TYPE_KEYWORD;
+ }
+ } else {
+ link_type = DH_LINK_TYPE_KEYWORD;
+ }
+
+ /* Strip out trailing " () or "()". */
+ if (g_str_has_suffix (name, " ()")) {
+ tmp = g_strndup (name, strlen (name) - 3);
+
+ if (link_type == DH_LINK_TYPE_KEYWORD) {
+ link_type = DH_LINK_TYPE_FUNCTION;
+ }
+ name = tmp;
+ }
+ else if (g_str_has_suffix (name, "()")) {
+ tmp = g_strndup (name, strlen (name) - 2);
+
+ /* With old devhelp format, take a guess that this is a
+ * macro.
+ */
+ if (link_type == DH_LINK_TYPE_KEYWORD) {
+ link_type = DH_LINK_TYPE_MACRO;
+ }
+ name = tmp;
+ } else {
+ tmp = NULL;
+ }
+
+ /* Strip out prefixing "struct", "union", "enum", to make searching
+ * easier. Also fix up the link type (only applies for old devhelp
+ * format).
+ */
+ if (g_str_has_prefix (name, "struct ")) {
+ name = name + 7;
+ if (link_type == DH_LINK_TYPE_KEYWORD) {
+ link_type = DH_LINK_TYPE_STRUCT;
+ }
+ }
+ else if (g_str_has_prefix (name, "union ")) {
+ name = name + 6;
+ if (link_type == DH_LINK_TYPE_KEYWORD) {
+ link_type = DH_LINK_TYPE_STRUCT;
+ }
+ }
+ else if (g_str_has_prefix (name, "enum ")) {
+ name = name + 5;
+ if (link_type == DH_LINK_TYPE_KEYWORD) {
+ link_type = DH_LINK_TYPE_ENUM;
+ }
+ }
+
+ link = dh_link_new (link_type,
+ NULL,
+ NULL,
+ name,
+ parser->book_node->data,
+ parser->parent->data,
+ uri);
+
+ g_free (tmp);
+
+ if (deprecated) {
+ dh_link_set_flags (
+ link,
+ dh_link_get_flags (link) | DH_LINK_FLAGS_DEPRECATED);
+ }
+
+ *parser->keywords = g_list_prepend (*parser->keywords, link);
+}
+
+static void
+parser_start_node_cb (GMarkupParseContext *context,
+ const gchar *node_name,
+ const gchar **attribute_names,
+ const gchar **attribute_values,
+ gpointer user_data,
+ GError **error)
+{
+ DhParser *parser = user_data;
+
+ if (parser->parsing_keywords) {
+ parser_start_node_keyword (parser,
+ context,
+ node_name,
+ attribute_names,
+ attribute_values,
+ error);
+ return;
+ }
+ else if (parser->parsing_chapters) {
+ parser_start_node_chapter (parser,
+ context,
+ node_name,
+ attribute_names,
+ attribute_values,
+ error);
+ return;
+ }
+ else if (g_ascii_strcasecmp (node_name, "functions") == 0) {
+ parser->parsing_keywords = TRUE;
+ }
+ else if (g_ascii_strcasecmp (node_name, "chapters") == 0) {
+ parser->parsing_chapters = TRUE;
+ }
+ if (!parser->book_node) {
+ parser_start_node_book (parser,
+ context,
+ node_name,
+ attribute_names,
+ attribute_values,
+ error);
+ return;
+ }
+}
+
+static void
+parser_end_node_cb (GMarkupParseContext *context,
+ const gchar *node_name,
+ gpointer user_data,
+ GError **error)
+{
+ DhParser *parser = user_data;
+
+ if (parser->parsing_keywords) {
+ if (g_ascii_strcasecmp (node_name, "functions") == 0) {
+ parser->parsing_keywords = FALSE;
+ }
+ }
+ else if (parser->parsing_chapters) {
+ g_node_reverse_children (parser->parent);
+ if (g_ascii_strcasecmp (node_name, "sub") == 0) {
+ parser->parent = parser->parent->parent;
+ /* Move up in the tree */
+ }
+ else if (g_ascii_strcasecmp (node_name, "chapters") == 0) {
+ parser->parsing_chapters = FALSE;
+ }
+ }
+}
+
+static void
+parser_error_cb (GMarkupParseContext *context,
+ GError *error,
+ gpointer user_data)
+{
+ DhParser *parser = user_data;
+
+ g_markup_parse_context_free (parser->context);
+ parser->context = NULL;
+}
+
+static gboolean
+parser_read_gz_file (DhParser *parser,
+ const gchar *path,
+ GError **error)
+{
+ gchar buf[BYTES_PER_READ];
+ gzFile file;
+
+ file = gzopen (path, "r");
+ if (!file) {
+ g_set_error (error,
+ DH_ERROR,
+ DH_ERROR_FILE_NOT_FOUND,
+ "%s", g_strerror (errno));
+ return FALSE;
+ }
+
+ while (TRUE) {
+ gssize bytes_read;
+
+ bytes_read = gzread (file, buf, BYTES_PER_READ);
+ if (bytes_read == -1) {
+ gint err;
+ const gchar *message;
+
+ message = gzerror (file, &err);
+ g_set_error (error,
+ DH_ERROR,
+ DH_ERROR_INTERNAL_ERROR,
+ _("Cannot uncompress book '%s': %s"),
+ path, message);
+ return FALSE;
+ }
+
+ g_markup_parse_context_parse (parser->context, buf,
+ bytes_read, error);
+ if (error != NULL && *error != NULL) {
+ return FALSE;
+ }
+ if (bytes_read < BYTES_PER_READ) {
+ break;
+ }
+ }
+
+ gzclose (file);
+
+ return TRUE;
+}
+
+gboolean
+dh_parser_read_file (const gchar *path,
+ GNode **book_tree,
+ GList **keywords,
+ GError **error)
+{
+ DhParser *parser;
+ gboolean gz;
+ GIOChannel *io = NULL;
+ gchar buf[BYTES_PER_READ];
+ gboolean result = TRUE;
+
+ parser = g_new0 (DhParser, 1);
+
+ if (g_str_has_suffix (path, ".devhelp2")) {
+ parser->version = 2;
+ gz = FALSE;
+ }
+ else if (g_str_has_suffix (path, ".devhelp")) {
+ parser->version = 1;
+ gz = FALSE;
+ }
+ else if (g_str_has_suffix (path, ".devhelp2.gz")) {
+ parser->version = 2;
+ gz = TRUE;
+ } else {
+ parser->version = 1;
+ gz = TRUE;
+ }
+
+ parser->m_parser = g_new0 (GMarkupParser, 1);
+
+ parser->m_parser->start_element = parser_start_node_cb;
+ parser->m_parser->end_element = parser_end_node_cb;
+ parser->m_parser->error = parser_error_cb;
+
+ parser->context = g_markup_parse_context_new (parser->m_parser, 0,
+ parser, NULL);
+
+ parser->path = path;
+ parser->book_tree = book_tree;
+ parser->keywords = keywords;
+
+ if (gz) {
+ if (!parser_read_gz_file (parser,
+ path,
+ error)) {
+ result = FALSE;
+ }
+ goto exit;
+ } else {
+ io = g_io_channel_new_file (path, "r", error);
+ if (!io) {
+ result = FALSE;
+ goto exit;
+ }
+
+ while (TRUE) {
+ GIOStatus io_status;
+ gsize bytes_read;
+
+ io_status = g_io_channel_read_chars (io, buf, BYTES_PER_READ,
+ &bytes_read, error);
+ if (io_status == G_IO_STATUS_ERROR) {
+ result = FALSE;
+ goto exit;
+ }
+ if (io_status != G_IO_STATUS_NORMAL) {
+ break;
+ }
+
+ g_markup_parse_context_parse (parser->context, buf,
+ bytes_read, error);
+ if (error != NULL && *error != NULL) {
+ result = FALSE;
+ goto exit;
+ }
+
+ if (bytes_read < BYTES_PER_READ) {
+ break;
+ }
+ }
+ }
+
+ exit:
+ if (io) {
+ g_io_channel_unref (io);
+ }
+ dh_parser_free (parser);
+
+ return result;
+}
Modified: devhelp/devhelp/dh-parser.h
36 files changed, 36 insertions(+), 0 deletions(-)
===================================================================
@@ -0,0 +1,36 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2003 CodeFactory AB
+ * Copyright (C) 2003 Mikael Hallendal <micke at imendio.com>
+ *
+ * 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.
+ */
+
+#ifndef __DH_PARSER_H__
+#define __DH_PARSER_H__
+
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+gboolean dh_parser_read_file (const gchar *path,
+ GNode **book_tree,
+ GList **keywords,
+ GError **error);
+
+G_END_DECLS
+
+#endif /* __DH_PARSER_H__ */
Modified: devhelp/devhelp/dh-preferences.c
417 files changed, 417 insertions(+), 0 deletions(-)
===================================================================
@@ -0,0 +1,417 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2004-2008 Imendio AB
+ * Copyright (C) 2010 Lanedo GmbH
+ *
+ * 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.
+ */
+
+#include "config.h"
+#include <gtk/gtk.h>
+#include <string.h>
+#include "dh-util.h"
+#include "dh-preferences.h"
+#include "ige-conf.h"
+#include "dh-base.h"
+
+typedef struct {
+ GtkWidget *dialog;
+
+ /* Fonts tab */
+ GtkWidget *system_fonts_button;
+ GtkWidget *fonts_table;
+ GtkWidget *variable_font_button;
+ GtkWidget *fixed_font_button;
+ guint use_system_fonts_id;
+ guint system_var_id;
+ guint system_fixed_id;
+ guint var_id;
+ guint fixed_id;
+
+ /* Book Shelf tab */
+ DhBookManager *book_manager;
+ GtkTreeView *booklist_treeview;
+ GtkListStore *booklist_store;
+} DhPreferences;
+
+/* Fonts-tab related */
+static void preferences_fonts_font_set_cb (GtkFontButton *button,
+ gpointer user_data);
+static void preferences_fonts_system_fonts_toggled_cb (GtkToggleButton *button,
+ gpointer user_data);
+#if 0
+static void preferences_fonts_var_font_notify_cb (IgeConf *client,
+ const gchar *path,
+ gpointer user_data);
+static void preferences_fonts_fixed_font_notify_cb (IgeConf *client,
+ const gchar *path,
+ gpointer user_data);
+static void preferences_fonts_use_system_font_notify_cb (IgeConf *client,
+ const gchar *path,
+ gpointer user_data);
+static void preferences_connect_conf_listeners (void);
+#endif
+static void preferences_fonts_get_font_names (gboolean use_system_fonts,
+ gchar **variable,
+ gchar **fixed);
+
+/* Bookshelf-tab related */
+static void preferences_bookshelf_tree_selection_toggled_cb (GtkCellRendererToggle *cell_renderer,
+ gchar *path,
+ gpointer user_data);
+static void preferences_bookshelf_populate_store (void);
+
+/* Common */
+static void preferences_close_cb (GtkButton *button,
+ gpointer user_data);
+
+#define DH_CONF_PATH "/apps/devhelp"
+#define DH_CONF_USE_SYSTEM_FONTS DH_CONF_PATH "/ui/use_system_fonts"
+#define DH_CONF_VARIABLE_FONT DH_CONF_PATH "/ui/variable_font"
+#define DH_CONF_FIXED_FONT DH_CONF_PATH "/ui/fixed_font"
+#define DH_CONF_SYSTEM_VARIABLE_FONT "/desktop/gnome/interface/font_name"
+#define DH_CONF_SYSTEM_FIXED_FONT "/desktop/gnome/interface/monospace_font_name"
+
+/* Book list store columns... */
+#define LTCOLUMN_ENABLED 0
+#define LTCOLUMN_TITLE 1
+#define LTCOLUMN_BOOK 2
+
+static DhPreferences *prefs;
+
+static void
+preferences_init (void)
+{
+ if (!prefs) {
+ prefs = g_new0 (DhPreferences, 1);
+ prefs->book_manager = dh_base_get_book_manager (dh_base_get ());
+ }
+}
+
+static void
+preferences_close_cb (GtkButton *button, gpointer user_data)
+{
+ DhPreferences *prefs = user_data;
+
+ gtk_widget_destroy (GTK_WIDGET (prefs->dialog));
+ prefs->dialog = NULL;
+
+ prefs->system_fonts_button = NULL;
+ prefs->fonts_table = NULL;
+ prefs->variable_font_button = NULL;
+ prefs->fixed_font_button = NULL;
+
+ prefs->booklist_treeview = NULL;
+ prefs->booklist_store = NULL;
+}
+
+static void
+preferences_fonts_font_set_cb (GtkFontButton *button,
+ gpointer user_data)
+{
+ DhPreferences *prefs = user_data;
+ const gchar *font_name;
+ const gchar *key;
+
+ font_name = gtk_font_button_get_font_name (button);
+
+ if (GTK_WIDGET (button) == prefs->variable_font_button) {
+ key = DH_CONF_VARIABLE_FONT;
+ } else {
+ key = DH_CONF_FIXED_FONT;
+ }
+
+ ige_conf_set_string (ige_conf_get (), key, font_name);
+}
+
+static void
+preferences_fonts_system_fonts_toggled_cb (GtkToggleButton *button,
+ gpointer user_data)
+{
+ DhPreferences *prefs = user_data;
+ gboolean active;
+
+ active = gtk_toggle_button_get_active (button);
+
+ ige_conf_set_bool (ige_conf_get (),
+ DH_CONF_USE_SYSTEM_FONTS,
+ active);
+
+ gtk_widget_set_sensitive (prefs->fonts_table, !active);
+}
+
+#if 0
+static void
+preferences_fonts_var_font_notify_cb (IgeConf *client,
+ const gchar *path,
+ gpointer user_data)
+{
+ DhPreferences *prefs = user_data;
+ gboolean use_system_fonts;
+ gchar *font_name;
+
+ ige_conf_get_bool (ige_conf_get (),
+ DH_CONF_USE_SYSTEM_FONTS,
+ &use_system_fonts);
+
+ if (prefs->variable_font_button) {
+ ige_conf_get_string (ige_conf_get (), path, &font_name);
+ gtk_font_button_set_font_name (GTK_FONT_BUTTON (prefs->variable_font_button),
+ font_name);
+ g_free (font_name);
+ }
+}
+
+static void
+preferences_fonts_fixed_font_notify_cb (IgeConf *client,
+ const gchar *path,
+ gpointer user_data)
+{
+ DhPreferences *prefs = user_data;
+ gboolean use_system_fonts;
+ gchar *font_name;
+
+ ige_conf_get_bool (ige_conf_get (),
+ DH_CONF_USE_SYSTEM_FONTS,
+ &use_system_fonts);
+
+ if (prefs->fixed_font_button) {
+ ige_conf_get_string (ige_conf_get (), path, &font_name);
+ gtk_font_button_set_font_name (GTK_FONT_BUTTON (prefs->fixed_font_button),
+ font_name);
+ g_free (font_name);
+ }
+}
+
+static void
+preferences_fonts_use_system_font_notify_cb (IgeConf *client,
+ const gchar *path,
+ gpointer user_data)
+{
+ DhPreferences *prefs = user_data;
+ gboolean use_system_fonts;
+
+ ige_conf_get_bool (ige_conf_get (), path, &use_system_fonts);
+
+ if (prefs->system_fonts_button) {
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (prefs->system_fonts_button),
+ use_system_fonts);
+ }
+
+ if (prefs->fonts_table) {
+ gtk_widget_set_sensitive (prefs->fonts_table, !use_system_fonts);
+ }
+}
+
+/* FIXME: This is not hooked up yet (to update the dialog if the values are
+ * changed outside of devhelp).
+ */
+static void
+preferences_connect_conf_listeners (void)
+{
+ IgeConf *conf;
+
+ conf = ige_conf_get ();
+
+ prefs->use_system_fonts_id =
+ ige_conf_notify_add (conf,
+ DH_CONF_USE_SYSTEM_FONTS,
+ preferences_use_system_font_notify_cb,
+ prefs);
+ prefs->system_var_id =
+ ige_conf_notify_add (conf,
+ DH_CONF_SYSTEM_VARIABLE_FONT,
+ preferences_var_font_notify_cb,
+ prefs);
+ prefs->system_fixed_id =
+ ige_conf_notify_add (conf,
+ DH_CONF_SYSTEM_FIXED_FONT,
+ preferences_fixed_font_notify_cb,
+ prefs);
+ prefs->var_id =
+ ige_conf_notify_add (conf,
+ DH_CONF_VARIABLE_FONT,
+ preferences_var_font_notify_cb,
+ prefs);
+ prefs->fixed_id =
+ ige_conf_notify_add (conf,
+ DH_CONF_FIXED_FONT,
+ preferences_fixed_font_notify_cb,
+ prefs);
+}
+#endif
+
+/* FIXME: Use the functions in dh-util.c for this. */
+static void
+preferences_fonts_get_font_names (gboolean use_system_fonts,
+ gchar **variable,
+ gchar **fixed)
+{
+ gchar *var_font_name, *fixed_font_name;
+ IgeConf *conf;
+
+ conf = ige_conf_get ();
+
+ if (use_system_fonts) {
+#ifdef GDK_WINDOWING_QUARTZ
+ var_font_name = g_strdup ("Lucida Grande 14");
+ fixed_font_name = g_strdup ("Monaco 14");
+#else
+ ige_conf_get_string (conf,
+ DH_CONF_SYSTEM_VARIABLE_FONT,
+ &var_font_name);
+ ige_conf_get_string (conf,
+ DH_CONF_SYSTEM_FIXED_FONT,
+ &fixed_font_name);
+#endif
+ } else {
+ ige_conf_get_string (conf,
+ DH_CONF_VARIABLE_FONT,
+ &var_font_name);
+ ige_conf_get_string (conf,
+ DH_CONF_FIXED_FONT,
+ &fixed_font_name);
+ }
+
+ *variable = var_font_name;
+ *fixed = fixed_font_name;
+}
+
+static void
+preferences_bookshelf_tree_selection_toggled_cb (GtkCellRendererToggle *cell_renderer,
+ gchar *path,
+ gpointer user_data)
+{
+ GtkTreeIter iter;
+
+ if (gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (prefs->booklist_store),
+ &iter,
+ path))
+ {
+ gpointer book = NULL;
+ gboolean enabled;
+
+ gtk_tree_model_get (GTK_TREE_MODEL (prefs->booklist_store),
+ &iter,
+ LTCOLUMN_BOOK, &book,
+ LTCOLUMN_ENABLED, &enabled,
+ -1);
+
+ if (book) {
+ /* Update book conf */
+ dh_book_set_enabled (book, !enabled);
+
+ gtk_list_store_set (prefs->booklist_store, &iter,
+ LTCOLUMN_ENABLED, !enabled,
+ -1);
+
+ dh_book_manager_update (prefs->book_manager);
+ }
+ }
+}
+
+static void
+preferences_bookshelf_populate_store (void)
+{
+ GList *l;
+
+ for (l = dh_book_manager_get_books (prefs->book_manager);
+ l;
+ l = g_list_next (l)) {
+ GtkTreeIter iter;
+ DhBook *book;
+
+ book = DH_BOOK (l->data);
+
+ gtk_list_store_append (prefs->booklist_store, &iter);
+ gtk_list_store_set (prefs->booklist_store, &iter,
+ LTCOLUMN_ENABLED, dh_book_get_enabled (book),
+ LTCOLUMN_TITLE, dh_book_get_title (book),
+ LTCOLUMN_BOOK, book,
+ -1);
+ }
+}
+
+void
+dh_preferences_show_dialog (GtkWindow *parent)
+{
+ gchar *path;
+ GtkBuilder *builder;
+ gboolean use_system_fonts;
+ gchar *var_font_name, *fixed_font_name;
+
+ preferences_init ();
+
+ if (prefs->dialog != NULL) {
+ gtk_window_present (GTK_WINDOW (prefs->dialog));
+ return;
+ }
+
+ path = dh_util_build_data_filename ("devhelp", "ui",
+ "devhelp.builder",
+ NULL);
+ builder = dh_util_builder_get_file (
+ path,
+ "preferences_dialog",
+ NULL,
+ "preferences_dialog", &prefs->dialog,
+ "fonts_table", &prefs->fonts_table,
+ "system_fonts_button", &prefs->system_fonts_button,
+ "variable_font_button", &prefs->variable_font_button,
+ "fixed_font_button", &prefs->fixed_font_button,
+ "book_manager_store", &prefs->booklist_store,
+ "book_manager_treeview", &prefs->booklist_treeview,
+ NULL);
+ g_free (path);
+
+ dh_util_builder_connect (
+ builder,
+ prefs,
+ "variable_font_button", "font_set", preferences_fonts_font_set_cb,
+ "fixed_font_button", "font_set", preferences_fonts_font_set_cb,
+ "system_fonts_button", "toggled", preferences_fonts_system_fonts_toggled_cb,
+ "book_manager_toggle", "toggled", preferences_bookshelf_tree_selection_toggled_cb,
+ "preferences_close_button", "clicked", preferences_close_cb,
+ NULL);
+
+ ige_conf_get_bool (ige_conf_get (),
+ DH_CONF_USE_SYSTEM_FONTS,
+ &use_system_fonts);
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (prefs->system_fonts_button),
+ use_system_fonts);
+ gtk_widget_set_sensitive (prefs->fonts_table, !use_system_fonts);
+
+ preferences_fonts_get_font_names (FALSE, &var_font_name, &fixed_font_name);
+
+ if (var_font_name) {
+ gtk_font_button_set_font_name (GTK_FONT_BUTTON (prefs->variable_font_button),
+ var_font_name);
+ g_free (var_font_name);
+ }
+
+ if (fixed_font_name) {
+ gtk_font_button_set_font_name (GTK_FONT_BUTTON (prefs->fixed_font_button),
+ fixed_font_name);
+ g_free (fixed_font_name);
+ }
+
+ preferences_bookshelf_populate_store ();
+
+ g_object_unref (builder);
+
+ gtk_window_set_transient_for (GTK_WINDOW (prefs->dialog), parent);
+ gtk_widget_show_all (prefs->dialog);
+}
Modified: devhelp/devhelp/dh-preferences.h
34 files changed, 34 insertions(+), 0 deletions(-)
===================================================================
@@ -0,0 +1,34 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2004-2008 Imendio AB
+ * Copyright (C) 2010 Lanedo GmbH
+ *
+ * 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.
+ */
+
+#ifndef __DH_PREFERENCES_H__
+#define __DH_PREFERENCES_H__
+
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+void dh_preferences_show_dialog (GtkWindow *parent);
+
+G_END_DECLS
+
+#endif /* __DH_PREFERENCES_H__ */
+
Modified: devhelp/devhelp/dh-search.c
725 files changed, 725 insertions(+), 0 deletions(-)
===================================================================
@@ -0,0 +1,725 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2001-2003 CodeFactory AB
+ * Copyright (C) 2001-2003 Mikael Hallendal <micke at imendio.com>
+ * Copyright (C) 2005-2008 Imendio AB
+ *
+ * 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.
+ */
+
+#include "config.h"
+#include <string.h>
+#include <glib/gi18n-lib.h>
+#include <gdk/gdkkeysyms.h>
+#include <gtk/gtk.h>
+#include "dh-marshal.h"
+#include "dh-keyword-model.h"
+#include "dh-search.h"
+#include "dh-preferences.h"
+#include "dh-base.h"
+#include "dh-util.h"
+#include "dh-book-manager.h"
+#include "dh-book.h"
+
+typedef struct {
+ DhKeywordModel *model;
+
+ DhBookManager *book_manager;
+
+ DhLink *selected_link;
+
+ GtkWidget *book_combo;
+ GtkWidget *entry;
+ GtkWidget *hitlist;
+
+ GCompletion *completion;
+
+ guint idle_complete;
+ guint idle_filter;
+} DhSearchPriv;
+
+static void dh_search_init (DhSearch *search);
+static void dh_search_class_init (DhSearchClass *klass);
+static void search_grab_focus (GtkWidget *widget);
+static void search_selection_changed_cb (GtkTreeSelection *selection,
+ DhSearch *content);
+static gboolean search_tree_button_press_cb (GtkTreeView *view,
+ GdkEventButton *event,
+ DhSearch *search);
+static gboolean search_entry_key_press_event_cb (GtkEntry *entry,
+ GdkEventKey *event,
+ DhSearch *search);
+static void search_combo_changed_cb (GtkComboBox *combo,
+ DhSearch *search);
+static void search_entry_changed_cb (GtkEntry *entry,
+ DhSearch *search);
+static void search_entry_activated_cb (GtkEntry *entry,
+ DhSearch *search);
+static void search_entry_text_inserted_cb (GtkEntry *entry,
+ const gchar *text,
+ gint length,
+ gint *position,
+ DhSearch *search);
+static gboolean search_complete_idle (DhSearch *search);
+static gboolean search_filter_idle (DhSearch *search);
+static const gchar *search_complete_func (DhLink *link);
+
+enum {
+ LINK_SELECTED,
+ LAST_SIGNAL
+};
+
+G_DEFINE_TYPE (DhSearch, dh_search, GTK_TYPE_VBOX);
+
+#define GET_PRIVATE(instance) G_TYPE_INSTANCE_GET_PRIVATE \
+ (instance, DH_TYPE_SEARCH, DhSearchPriv);
+
+static gint signals[LAST_SIGNAL] = { 0 };
+
+static void
+search_finalize (GObject *object)
+{
+ DhSearchPriv *priv;
+
+ priv = GET_PRIVATE (object);
+
+ g_completion_free (priv->completion);
+ g_object_unref (priv->book_manager);
+
+ G_OBJECT_CLASS (dh_search_parent_class)->finalize (object);
+}
+
+static void
+dh_search_class_init (DhSearchClass *klass)
+{
+ GObjectClass *object_class = (GObjectClass *) klass;;
+ GtkWidgetClass *widget_class = (GtkWidgetClass *) klass;;
+
+ object_class->finalize = search_finalize;
+
+ widget_class->grab_focus = search_grab_focus;
+
+ signals[LINK_SELECTED] =
+ g_signal_new ("link_selected",
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (DhSearchClass, link_selected),
+ NULL, NULL,
+ _dh_marshal_VOID__POINTER,
+ G_TYPE_NONE,
+ 1, G_TYPE_POINTER);
+
+ g_type_class_add_private (klass, sizeof (DhSearchPriv));
+}
+
+static void
+dh_search_init (DhSearch *search)
+{
+ DhSearchPriv *priv = GET_PRIVATE (search);
+
+ priv->completion = g_completion_new (
+ (GCompletionFunc) search_complete_func);
+
+ priv->hitlist = gtk_tree_view_new ();
+ priv->model = dh_keyword_model_new ();
+
+ gtk_tree_view_set_model (GTK_TREE_VIEW (priv->hitlist),
+ GTK_TREE_MODEL (priv->model));
+
+ gtk_tree_view_set_enable_search (GTK_TREE_VIEW (priv->hitlist), FALSE);
+
+ gtk_box_set_spacing (GTK_BOX (search), 4);
+}
+
+static void
+search_grab_focus (GtkWidget *widget)
+{
+ DhSearchPriv *priv = GET_PRIVATE (widget);
+
+ gtk_widget_grab_focus (priv->entry);
+}
+
+static void
+search_selection_changed_cb (GtkTreeSelection *selection,
+ DhSearch *search)
+{
+ DhSearchPriv *priv;
+ GtkTreeIter iter;
+
+ priv = GET_PRIVATE (search);
+
+ if (gtk_tree_selection_get_selected (selection, NULL, &iter)) {
+ DhLink *link;
+
+ gtk_tree_model_get (GTK_TREE_MODEL (priv->model), &iter,
+ DH_KEYWORD_MODEL_COL_LINK, &link,
+ -1);
+
+ if (link != priv->selected_link) {
+ priv->selected_link = link;
+ g_signal_emit (search, signals[LINK_SELECTED], 0, link);
+ }
+ }
+}
+
+/* Make it possible to jump back to the currently selected item, useful when the
+ * html view has been scrolled away.
+ */
+static gboolean
+search_tree_button_press_cb (GtkTreeView *view,
+ GdkEventButton *event,
+ DhSearch *search)
+{
+ GtkTreePath *path;
+ GtkTreeIter iter;
+ DhSearchPriv *priv;
+ DhLink *link;
+
+ priv = GET_PRIVATE (search);
+
+ gtk_tree_view_get_path_at_pos (view, event->x, event->y, &path,
+ NULL, NULL, NULL);
+ if (!path) {
+ return FALSE;
+ }
+
+ gtk_tree_model_get_iter (GTK_TREE_MODEL (priv->model), &iter, path);
+ gtk_tree_path_free (path);
+
+ gtk_tree_model_get (GTK_TREE_MODEL (priv->model),
+ &iter,
+ DH_KEYWORD_MODEL_COL_LINK, &link,
+ -1);
+
+ priv->selected_link = link;
+
+ g_signal_emit (search, signals[LINK_SELECTED], 0, link);
+
+ /* Always return FALSE so the tree view gets the event and can update
+ * the selection etc.
+ */
+ return FALSE;
+}
+
+static gboolean
+search_entry_key_press_event_cb (GtkEntry *entry,
+ GdkEventKey *event,
+ DhSearch *search)
+{
+ DhSearchPriv *priv = GET_PRIVATE (search);
+
+ if (event->keyval == GDK_Tab) {
+ if (event->state & GDK_CONTROL_MASK) {
+ gtk_widget_grab_focus (priv->hitlist);
+ } else {
+ gtk_editable_set_position (GTK_EDITABLE (entry), -1);
+ gtk_editable_select_region (GTK_EDITABLE (entry), -1, -1);
+ }
+ return TRUE;
+ }
+
+ if (event->keyval == GDK_Return ||
+ event->keyval == GDK_KP_Enter) {
+ GtkTreeIter iter;
+ DhLink *link;
+ gchar *name;
+
+ /* Get the first entry found. */
+ if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL (priv->model), &iter)) {
+ gtk_tree_model_get (GTK_TREE_MODEL (priv->model),
+ &iter,
+ DH_KEYWORD_MODEL_COL_LINK, &link,
+ DH_KEYWORD_MODEL_COL_NAME, &name,
+ -1);
+
+ gtk_entry_set_text (GTK_ENTRY (entry), name);
+ g_free (name);
+
+ gtk_editable_set_position (GTK_EDITABLE (entry), -1);
+ gtk_editable_select_region (GTK_EDITABLE (entry), -1, -1);
+
+ g_signal_emit (search, signals[LINK_SELECTED], 0, link);
+
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+static void
+search_combo_set_active_id (DhSearch *search,
+ const gchar *book_id)
+{
+ DhSearchPriv *priv = GET_PRIVATE (search);
+ GtkTreeIter iter;
+ GtkTreeModel *model;
+ gboolean has_next;
+
+ g_signal_handlers_block_by_func (priv->book_combo,
+ search_combo_changed_cb,
+ search);
+
+ if (book_id != NULL) {
+ model = gtk_combo_box_get_model (GTK_COMBO_BOX (priv->book_combo));
+
+ has_next = gtk_tree_model_get_iter_first (model, &iter);
+ while (has_next) {
+ gchar *id;
+
+ gtk_tree_model_get (model, &iter,
+ 1, &id,
+ -1);
+
+ if (id && strcmp (book_id, id) == 0) {
+ g_free (id);
+
+ gtk_combo_box_set_active_iter (GTK_COMBO_BOX (priv->book_combo),
+ &iter);
+ break;
+ }
+
+ g_free (id);
+
+ has_next = gtk_tree_model_iter_next (model, &iter);
+ }
+ } else {
+ gtk_combo_box_set_active (GTK_COMBO_BOX (priv->book_combo), 0);
+ }
+
+ g_signal_handlers_unblock_by_func (priv->book_combo,
+ search_combo_changed_cb,
+ search);
+}
+
+static gchar *
+search_combo_get_active_id (DhSearch *search)
+{
+ DhSearchPriv *priv = GET_PRIVATE (search);
+ GtkTreeIter iter;
+ GtkTreeModel *model;
+ gchar *id;
+
+ if (!gtk_combo_box_get_active_iter (GTK_COMBO_BOX (priv->book_combo),
+ &iter)) {
+ return NULL;
+ }
+
+ model = gtk_combo_box_get_model (GTK_COMBO_BOX (priv->book_combo));
+
+ gtk_tree_model_get (model, &iter,
+ 1, &id,
+ -1);
+
+ return id;
+}
+
+static void
+search_combo_changed_cb (GtkComboBox *combo,
+ DhSearch *search)
+{
+ DhSearchPriv *priv = GET_PRIVATE (search);
+
+ if (!priv->idle_filter) {
+ priv->idle_filter =
+ g_idle_add ((GSourceFunc) search_filter_idle, search);
+ }
+}
+
+static void
+search_entry_changed_cb (GtkEntry *entry,
+ DhSearch *search)
+{
+ DhSearchPriv *priv = GET_PRIVATE (search);
+
+ if (!priv->idle_filter) {
+ priv->idle_filter =
+ g_idle_add ((GSourceFunc) search_filter_idle, search);
+ }
+}
+
+static void
+search_entry_activated_cb (GtkEntry *entry,
+ DhSearch *search)
+{
+ DhSearchPriv *priv = GET_PRIVATE (search);
+ gchar *id;
+ const gchar *str;
+
+ id = search_combo_get_active_id (search);
+ str = gtk_entry_get_text (GTK_ENTRY (priv->entry));
+ dh_keyword_model_filter (priv->model, str, id);
+ g_free (id);
+}
+
+static void
+search_entry_text_inserted_cb (GtkEntry *entry,
+ const gchar *text,
+ gint length,
+ gint *position,
+ DhSearch *search)
+{
+ DhSearchPriv *priv = GET_PRIVATE (search);
+
+ if (!priv->idle_complete) {
+ priv->idle_complete =
+ g_idle_add ((GSourceFunc) search_complete_idle,
+ search);
+ }
+}
+
+static gboolean
+search_complete_idle (DhSearch *search)
+{
+ DhSearchPriv *priv = GET_PRIVATE (search);
+ const gchar *str;
+ gchar *completed = NULL;
+ gsize length;
+
+ str = gtk_entry_get_text (GTK_ENTRY (priv->entry));
+
+ g_completion_complete (priv->completion, str, &completed);
+ if (completed) {
+ length = strlen (str);
+
+ gtk_entry_set_text (GTK_ENTRY (priv->entry), completed);
+ gtk_editable_set_position (GTK_EDITABLE (priv->entry), length);
+ gtk_editable_select_region (GTK_EDITABLE (priv->entry),
+ length, -1);
+ g_free (completed);
+ }
+
+ priv->idle_complete = 0;
+
+ return FALSE;
+}
+
+static gboolean
+search_filter_idle (DhSearch *search)
+{
+ DhSearchPriv *priv = GET_PRIVATE (search);
+ const gchar *str;
+ gchar *id;
+ DhLink *link;
+
+ str = gtk_entry_get_text (GTK_ENTRY (priv->entry));
+ id = search_combo_get_active_id (search);
+ link = dh_keyword_model_filter (priv->model, str, id);
+ g_free (id);
+
+ priv->idle_filter = 0;
+
+ if (link) {
+ g_signal_emit (search, signals[LINK_SELECTED], 0, link);
+ }
+
+ return FALSE;
+}
+
+static const gchar *
+search_complete_func (DhLink *link)
+{
+ return dh_link_get_name (link);
+}
+
+static void
+search_cell_data_func (GtkTreeViewColumn *tree_column,
+ GtkCellRenderer *cell,
+ GtkTreeModel *tree_model,
+ GtkTreeIter *iter,
+ gpointer data)
+{
+ DhLink *link;
+ PangoStyle style;
+
+ gtk_tree_model_get (tree_model, iter,
+ DH_KEYWORD_MODEL_COL_LINK, &link,
+ -1);
+
+ style = PANGO_STYLE_NORMAL;
+
+ if (dh_link_get_flags (link) & DH_LINK_FLAGS_DEPRECATED) {
+ style |= PANGO_STYLE_ITALIC;
+ }
+
+ g_object_set (cell,
+ "text", dh_link_get_name (link),
+ "style", style,
+ NULL);
+}
+
+static gboolean
+search_combo_row_separator_func (GtkTreeModel *model,
+ GtkTreeIter *iter,
+ gpointer data)
+{
+ char *label;
+ char *link;
+ gboolean result;
+
+ gtk_tree_model_get (model, iter, 0, &label, 1, &link, -1);
+
+ result = (link == NULL && label == NULL);
+ g_free (label);
+ g_free (link);
+
+ return result;
+}
+
+static void
+search_combo_populate (DhSearch *search)
+{
+ DhSearchPriv *priv;
+ GtkListStore *store;
+ GtkTreeIter iter;
+ GList *l;
+
+ priv = GET_PRIVATE (search);
+
+ store = GTK_LIST_STORE (gtk_combo_box_get_model (GTK_COMBO_BOX (priv->book_combo)));
+
+ gtk_list_store_clear (store);
+
+ gtk_list_store_append (store, &iter);
+ gtk_list_store_set (store, &iter,
+ 0, _("All books"),
+ 1, NULL,
+ -1);
+
+ /* Add a separator */
+ gtk_list_store_append (store, &iter);
+ gtk_list_store_set (store, &iter,
+ 0, NULL,
+ 1, NULL,
+ -1);
+
+ for (l = dh_book_manager_get_books (priv->book_manager);
+ l;
+ l = g_list_next (l)) {
+ DhBook *book = DH_BOOK (l->data);
+ GNode *node;
+
+ node = dh_book_get_tree (book);
+ if (node) {
+ DhLink *link;
+
+ link = node->data;
+
+ gtk_list_store_append (store, &iter);
+ gtk_list_store_set (store, &iter,
+ 0, dh_link_get_name (link),
+ 1, dh_link_get_book_id (link),
+ -1);
+ }
+ }
+
+ gtk_combo_box_set_active (GTK_COMBO_BOX (priv->book_combo), 0);
+}
+
+
+static void
+search_combo_create (DhSearch *search)
+{
+ GtkListStore *store;
+ GtkCellRenderer *cell;
+ DhSearchPriv *priv;
+
+ priv = GET_PRIVATE (search);
+
+ store = gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_STRING);
+ priv->book_combo = gtk_combo_box_new_with_model (GTK_TREE_MODEL (store));
+ g_object_unref (store);
+
+ search_combo_populate (search);
+
+ gtk_combo_box_set_row_separator_func (GTK_COMBO_BOX (priv->book_combo),
+ search_combo_row_separator_func,
+ NULL, NULL);
+
+ cell = gtk_cell_renderer_text_new ();
+ gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (priv->book_combo),
+ cell,
+ TRUE);
+ gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (priv->book_combo),
+ cell,
+ "text", 0);
+}
+
+static void
+completion_add_items (DhSearch *search)
+{
+ DhSearchPriv *priv;
+ GList *l;
+
+ priv = GET_PRIVATE (search);
+
+ for (l = dh_book_manager_get_books (priv->book_manager);
+ l;
+ l = g_list_next (l)) {
+ DhBook *book = DH_BOOK (l->data);
+ GList *keywords;
+
+ keywords = dh_book_get_keywords(book);
+
+ if (keywords) {
+ g_completion_add_items (priv->completion,
+ keywords);
+ }
+ }
+}
+
+static void
+book_manager_disabled_book_list_changed_cb (DhBookManager *book_manager,
+ gpointer user_data)
+{
+ DhSearch *search = user_data;
+ search_combo_populate (search);
+}
+
+GtkWidget *
+dh_search_new (DhBookManager *book_manager)
+{
+ DhSearch *search;
+ DhSearchPriv *priv;
+ GtkTreeSelection *selection;
+ GtkWidget *list_sw;
+ GtkWidget *hbox;
+ GtkWidget *book_label;
+ GtkCellRenderer *cell;
+
+ search = g_object_new (DH_TYPE_SEARCH, NULL);
+
+ priv = GET_PRIVATE (search);
+
+ priv->book_manager = g_object_ref (book_manager);
+ g_signal_connect (priv->book_manager,
+ "disabled-book-list-updated",
+ G_CALLBACK (book_manager_disabled_book_list_changed_cb),
+ search);
+
+ gtk_container_set_border_width (GTK_CONTAINER (search), 2);
+
+ search_combo_create (search);
+ g_signal_connect (priv->book_combo, "changed",
+ G_CALLBACK (search_combo_changed_cb),
+ search);
+
+ book_label = gtk_label_new_with_mnemonic (_("Search in:"));
+ gtk_label_set_mnemonic_widget (GTK_LABEL (book_label), priv->book_combo);
+
+ hbox = gtk_hbox_new (FALSE, 6);
+ gtk_box_pack_start (GTK_BOX (hbox), book_label, FALSE, FALSE, 0);
+ gtk_box_pack_start (GTK_BOX (hbox), priv->book_combo, TRUE, TRUE, 0);
+ gtk_box_pack_start (GTK_BOX (search), hbox, FALSE, FALSE, 0);
+
+ /* Setup the keyword box. */
+ priv->entry = gtk_entry_new ();
+ g_signal_connect (priv->entry, "key-press-event",
+ G_CALLBACK (search_entry_key_press_event_cb),
+ search);
+
+ g_signal_connect (priv->hitlist, "button-press-event",
+ G_CALLBACK (search_tree_button_press_cb),
+ search);
+
+ g_signal_connect (priv->entry, "changed",
+ G_CALLBACK (search_entry_changed_cb),
+ search);
+
+ g_signal_connect (priv->entry, "activate",
+ G_CALLBACK (search_entry_activated_cb),
+ search);
+
+ g_signal_connect (priv->entry, "insert-text",
+ G_CALLBACK (search_entry_text_inserted_cb),
+ search);
+
+ gtk_box_pack_start (GTK_BOX (search), priv->entry, FALSE, FALSE, 0);
+
+ /* Setup the hitlist */
+ list_sw = gtk_scrolled_window_new (NULL, NULL);
+ gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (list_sw), GTK_SHADOW_IN);
+ gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (list_sw),
+ GTK_POLICY_NEVER,
+ GTK_POLICY_AUTOMATIC);
+
+ cell = gtk_cell_renderer_text_new ();
+ g_object_set (cell,
+ "ellipsize", PANGO_ELLIPSIZE_END,
+ NULL);
+
+ gtk_tree_view_insert_column_with_data_func (
+ GTK_TREE_VIEW (priv->hitlist),
+ -1,
+ NULL,
+ cell,
+ search_cell_data_func,
+ search, NULL);
+
+ gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (priv->hitlist),
+ FALSE);
+ gtk_tree_view_set_search_column (GTK_TREE_VIEW (priv->hitlist),
+ DH_KEYWORD_MODEL_COL_NAME);
+
+ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->hitlist));
+
+ g_signal_connect (selection, "changed",
+ G_CALLBACK (search_selection_changed_cb),
+ search);
+
+ gtk_container_add (GTK_CONTAINER (list_sw), priv->hitlist);
+
+ gtk_box_pack_end (GTK_BOX (search), list_sw, TRUE, TRUE, 0);
+
+ completion_add_items (search);
+ dh_keyword_model_set_words (priv->model, book_manager);
+
+ gtk_widget_show_all (GTK_WIDGET (search));
+
+ return GTK_WIDGET (search);
+}
+
+void
+dh_search_set_search_string (DhSearch *search,
+ const gchar *str,
+ const gchar *book_id)
+{
+ DhSearchPriv *priv;
+
+ g_return_if_fail (DH_IS_SEARCH (search));
+
+ priv = GET_PRIVATE (search);
+
+ g_signal_handlers_block_by_func (priv->entry,
+ search_entry_changed_cb,
+ search);
+
+ gtk_entry_set_text (GTK_ENTRY (priv->entry), str);
+
+ gtk_editable_set_position (GTK_EDITABLE (priv->entry), -1);
+ gtk_editable_select_region (GTK_EDITABLE (priv->entry), -1, -1);
+
+ g_signal_handlers_unblock_by_func (priv->entry,
+ search_entry_changed_cb,
+ search);
+
+ search_combo_set_active_id (search, book_id);
+
+ if (!priv->idle_filter) {
+ priv->idle_filter =
+ g_idle_add ((GSourceFunc) search_filter_idle, search);
+ }
+}
Modified: devhelp/devhelp/dh-search.h
60 files changed, 60 insertions(+), 0 deletions(-)
===================================================================
@@ -0,0 +1,60 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2001-2002 CodeFactory AB
+ * Copyright (C) 2001-2002 Mikael Hallendal <micke at imendio.com>
+ *
+ * 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.
+ */
+
+#ifndef __DH_SEARCH_H__
+#define __DH_SEARCH_H__
+
+#include <gtk/gtk.h>
+#include "dh-link.h"
+#include "dh-book-manager.h"
+
+G_BEGIN_DECLS
+
+#define DH_TYPE_SEARCH (dh_search_get_type ())
+#define DH_SEARCH(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), DH_TYPE_SEARCH, DhSearch))
+#define DH_SEARCH_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), DH_TYPE_SEARCH, DhSearchClass))
+#define DH_IS_SEARCH(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), DH_TYPE_SEARCH))
+#define DH_IS_SEARCH_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), DH_TYPE_SEARCH))
+
+typedef struct _DhSearch DhSearch;
+typedef struct _DhSearchClass DhSearchClass;
+
+struct _DhSearch {
+ GtkVBox parent_instance;
+};
+
+struct _DhSearchClass {
+ GtkVBoxClass parent_class;
+
+ /* Signals */
+ void (*link_selected) (DhSearch *search,
+ DhLink *link);
+};
+
+GType dh_search_get_type (void);
+GtkWidget *dh_search_new (DhBookManager *book_manager);
+void dh_search_set_search_string (DhSearch *search,
+ const gchar *str,
+ const gchar *book_id);
+
+G_END_DECLS
+
+#endif /* __DH_SEARCH_H__ */
Modified: devhelp/devhelp/dh-util.c
812 files changed, 812 insertions(+), 0 deletions(-)
===================================================================
@@ -0,0 +1,812 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2001 Mikael Hallendal <micke at imendio.com>
+ * Copyright (C) 2004,2008 Imendio AB
+ *
+ * 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.
+ */
+
+#include "config.h"
+#include <string.h>
+#include <stdlib.h>
+#include <gtk/gtk.h>
+#ifdef GDK_WINDOWING_QUARTZ
+#include <CoreFoundation/CoreFoundation.h>
+#endif
+#include "ige-conf.h"
+#include "dh-util.h"
+
+static GList *views;
+
+static GtkBuilder *
+get_builder_file (const gchar *filename,
+ const gchar *root,
+ const gchar *domain,
+ const gchar *first_required_widget,
+ va_list args)
+{
+ GtkBuilder *builder;
+ const char *name;
+ GObject **object_ptr;
+
+ builder = gtk_builder_new ();
+ if (!gtk_builder_add_from_file (builder, filename, NULL)) {
+ g_warning ("Couldn't find necessary UI file '%s'", filename);
+ g_object_unref (builder);
+ return NULL;
+ }
+
+ for (name = first_required_widget; name; name = va_arg (args, char *)) {
+ object_ptr = va_arg (args, void *);
+ *object_ptr = gtk_builder_get_object (builder, name);
+
+ if (!*object_ptr) {
+ g_warning ("UI file '%s' is missing widget '%s'.",
+ filename, name);
+ continue;
+ }
+ }
+
+ return builder;
+}
+
+GtkBuilder *
+dh_util_builder_get_file (const gchar *filename,
+ const gchar *root,
+ const gchar *domain,
+ const gchar *first_required_widget,
+ ...)
+{
+ va_list args;
+ GtkBuilder *builder;
+
+ va_start (args, first_required_widget);
+ builder = get_builder_file (filename,
+ root,
+ domain,
+ first_required_widget,
+ args);
+ va_end (args);
+
+ return builder;
+}
+
+void
+dh_util_builder_connect (GtkBuilder *builder,
+ gpointer user_data,
+ gchar *first_widget,
+ ...)
+{
+ va_list args;
+ const gchar *name;
+ const gchar *signal;
+ GObject *object;
+ gpointer *callback;
+
+ va_start (args, first_widget);
+
+ for (name = first_widget; name; name = va_arg (args, char *)) {
+ signal = va_arg (args, void *);
+ callback = va_arg (args, void *);
+
+ object = gtk_builder_get_object (builder, name);
+ if (!object) {
+ g_warning ("UI file is missing widget '%s', aborting",
+ name);
+ continue;
+ }
+
+ g_signal_connect (object,
+ signal,
+ G_CALLBACK (callback),
+ user_data);
+ }
+
+ va_end (args);
+}
+
+#ifdef GDK_WINDOWING_QUARTZ
+static gchar *
+cf_string_to_utf8 (CFStringRef str)
+{
+ CFIndex len;
+ gchar *ret;
+
+ len = CFStringGetMaximumSizeForEncoding (CFStringGetLength (str),
+ kCFStringEncodingUTF8) + 1;
+
+ ret = g_malloc (len);
+ ret[len] = '\0';
+
+ if (CFStringGetCString (str, ret, len, kCFStringEncodingUTF8))
+ return ret;
+
+ g_free (ret);
+ return NULL;
+}
+
+static gchar *
+util_get_mac_data_dir (void)
+{
+ const gchar *env;
+ CFBundleRef cf_bundle;
+ UInt32 type;
+ UInt32 creator;
+ CFURLRef cf_url;
+ CFStringRef cf_string;
+ gchar *ret, *tmp;
+
+ /* The environment variable overrides all. */
+ env = g_getenv ("DEVHELP_DATADIR");
+ if (env) {
+ return g_strdup (env);
+ }
+
+ cf_bundle = CFBundleGetMainBundle ();
+ if (!cf_bundle) {
+ return NULL;
+ }
+
+ /* Only point into the bundle if it's an application. */
+ CFBundleGetPackageInfo (cf_bundle, &type, &creator);
+ if (type != 'APPL') {
+ return NULL;
+ }
+
+ cf_url = CFBundleCopyBundleURL (cf_bundle);
+ cf_string = CFURLCopyFileSystemPath (cf_url, kCFURLPOSIXPathStyle);
+ ret = cf_string_to_utf8 (cf_string);
+ CFRelease (cf_string);
+ CFRelease (cf_url);
+
+ tmp = g_build_filename (ret, "Contents", "Resources", NULL);
+ g_free (ret);
+
+ return tmp;
+}
+#endif
+
+gchar *
+dh_util_build_data_filename (const gchar *first_part,
+ ...)
+{
+ gchar *datadir = NULL;
+ va_list args;
+ const gchar *part;
+ gchar **strv;
+ gint i;
+ gchar *ret;
+
+ va_start (args, first_part);
+
+#ifdef GDK_WINDOWING_QUARTZ
+ datadir = util_get_mac_data_dir ();
+#endif
+
+ if (datadir == NULL) {
+ datadir = g_strdup (DATADIR);
+ }
+
+ /* 2 = 1 initial component + terminating NULL element. */
+ strv = g_malloc (sizeof (gchar *) * 2);
+ strv[0] = (gchar *) datadir;
+
+ i = 1;
+ for (part = first_part; part; part = va_arg (args, char *), i++) {
+ /* +2 = 1 new element + terminating NULL element. */
+ strv = g_realloc (strv, sizeof (gchar*) * (i + 2));
+ strv[i] = (gchar *) part;
+ }
+
+ strv[i] = NULL;
+ ret = g_build_filenamev (strv);
+ g_free (strv);
+
+ g_free (datadir);
+
+ va_end (args);
+
+ return ret;
+}
+
+typedef struct {
+ gchar *name;
+ guint timeout_id;
+} DhUtilStateItem;
+
+static void
+util_state_item_free (DhUtilStateItem *item)
+{
+ g_free (item->name);
+ if (item->timeout_id) {
+ g_source_remove (item->timeout_id);
+ }
+ g_slice_free (DhUtilStateItem, item);
+}
+
+static void
+util_state_setup_widget (GtkWidget *widget,
+ const gchar *name)
+{
+ DhUtilStateItem *item;
+
+ item = g_slice_new0 (DhUtilStateItem);
+ item->name = g_strdup (name);
+
+ g_object_set_data_full (G_OBJECT (widget),
+ "dh-util-state",
+ item,
+ (GDestroyNotify) util_state_item_free);
+}
+
+static gchar *
+util_state_get_key (const gchar *name,
+ const gchar *key)
+{
+ return g_strdup_printf ("/apps/devhelp/state/%s/%s", name, key);
+}
+
+static void
+util_state_schedule_save (GtkWidget *widget,
+ GSourceFunc func)
+
+{
+ DhUtilStateItem *item;
+
+ item = g_object_get_data (G_OBJECT (widget), "dh-util-state");
+ if (item->timeout_id) {
+ g_source_remove (item->timeout_id);
+ }
+
+ item->timeout_id = g_timeout_add (500,
+ func,
+ widget);
+}
+
+static void
+util_state_save_window (GtkWindow *window,
+ const gchar *name)
+{
+ gchar *key;
+ GdkWindowState state;
+ gboolean maximized;
+ gint width, height;
+ gint x, y;
+
+#if GTK_CHECK_VERSION (2,14,0)
+ state = gdk_window_get_state (gtk_widget_get_window (GTK_WIDGET (window)));
+#else
+ state = gdk_window_get_state (GTK_WIDGET (window)->window);
+#endif
+ if (state & GDK_WINDOW_STATE_MAXIMIZED) {
+ maximized = TRUE;
+ } else {
+ maximized = FALSE;
+ }
+
+ key = util_state_get_key (name, "maximized");
+ ige_conf_set_bool (ige_conf_get (), key, maximized);
+ g_free (key);
+
+ /* If maximized don't save the size and position. */
+ if (maximized) {
+ return;
+ }
+
+ gtk_window_get_size (GTK_WINDOW (window), &width, &height);
+
+ key = util_state_get_key (name, "width");
+ ige_conf_set_int (ige_conf_get (), key, width);
+ g_free (key);
+
+ key = util_state_get_key (name, "height");
+ ige_conf_set_int (ige_conf_get (), key, height);
+ g_free (key);
+
+ gtk_window_get_position (GTK_WINDOW (window), &x, &y);
+
+ key = util_state_get_key (name, "x_position");
+ ige_conf_set_int (ige_conf_get (), key, x);
+ g_free (key);
+
+ key = util_state_get_key (name, "y_position");
+ ige_conf_set_int (ige_conf_get (), key, y);
+ g_free (key);
+}
+
+static void
+util_state_restore_window (GtkWindow *window,
+ const gchar *name)
+{
+ gchar *key;
+ gboolean maximized;
+ gint width, height;
+ gint x, y;
+ GdkScreen *screen;
+ gint max_width, max_height;
+
+ key = util_state_get_key (name, "width");
+ ige_conf_get_int (ige_conf_get (), key, &width);
+ g_free (key);
+
+ key = util_state_get_key (name, "height");
+ ige_conf_get_int (ige_conf_get (), key, &height);
+ g_free (key);
+
+ key = util_state_get_key (name, "x_position");
+ ige_conf_get_int (ige_conf_get (), key, &x);
+ g_free (key);
+
+ key = util_state_get_key (name, "y_position");
+ ige_conf_get_int (ige_conf_get (), key, &y);
+ g_free (key);
+
+ if (width > 1 && height > 1) {
+ screen = gtk_widget_get_screen (GTK_WIDGET (window));
+ max_width = gdk_screen_get_width (screen);
+ max_height = gdk_screen_get_height (screen);
+
+ width = CLAMP (width, 0, max_width);
+ height = CLAMP (height, 0, max_height);
+
+ x = CLAMP (x, 0, max_width - width);
+ y = CLAMP (y, 0, max_height - height);
+
+ gtk_window_set_default_size (window, width, height);
+ }
+
+ gtk_window_move (window, x, y);
+
+ key = util_state_get_key (name, "maximized");
+ ige_conf_get_bool (ige_conf_get (), key, &maximized);
+ g_free (key);
+
+ if (maximized) {
+ gtk_window_maximize (window);
+ }
+}
+
+static gboolean
+util_state_window_timeout_cb (gpointer window)
+{
+ DhUtilStateItem *item;
+
+ item = g_object_get_data (window, "dh-util-state");
+ if (item) {
+ item->timeout_id = 0;
+ util_state_save_window (window, item->name);
+ }
+
+ return FALSE;
+}
+
+static gboolean
+util_state_window_configure_event_cb (GtkWidget *window,
+ GdkEventConfigure *event,
+ gpointer user_data)
+{
+ util_state_schedule_save (window, util_state_window_timeout_cb);
+ return FALSE;
+}
+
+static gboolean
+util_state_paned_timeout_cb (gpointer paned)
+{
+ DhUtilStateItem *item;
+
+ item = g_object_get_data (paned, "dh-util-state");
+ if (item) {
+ gchar *key;
+
+ item->timeout_id = 0;
+
+ key = util_state_get_key (item->name, "position");
+ ige_conf_set_int (ige_conf_get (),
+ key,
+ gtk_paned_get_position (paned));
+ g_free (key);
+ }
+
+ return FALSE;
+}
+
+static gboolean
+util_state_paned_changed_cb (GtkWidget *paned,
+ gpointer user_data)
+{
+ util_state_schedule_save (paned, util_state_paned_timeout_cb);
+ return FALSE;
+}
+
+void
+dh_util_state_manage_window (GtkWindow *window,
+ const gchar *name)
+{
+ util_state_setup_widget (GTK_WIDGET (window), name);
+
+ g_signal_connect (window, "configure-event",
+ G_CALLBACK (util_state_window_configure_event_cb),
+ NULL);
+
+ util_state_restore_window (window, name);
+}
+
+void
+dh_util_state_manage_paned (GtkPaned *paned,
+ const gchar *name)
+{
+ gchar *key;
+ gint position;
+
+ util_state_setup_widget (GTK_WIDGET (paned), name);
+
+ key = util_state_get_key (name, "position");
+ if (ige_conf_get_int (ige_conf_get (), key, &position)) {
+ gtk_paned_set_position (paned, position);
+ }
+ g_free (key);
+
+ g_signal_connect (paned, "notify::position",
+ G_CALLBACK (util_state_paned_changed_cb),
+ NULL);
+}
+
+GSList *
+dh_util_state_load_books_disabled (void)
+{
+ gchar *key;
+ GSList *books_disabled = NULL;
+
+ key = util_state_get_key ("main/contents", "books_disabled");
+ ige_conf_get_string_list (ige_conf_get (), key, &books_disabled);
+ g_free(key);
+
+ return books_disabled;
+}
+
+void
+dh_util_state_store_books_disabled (GSList *books_disabled)
+{
+ gchar *key;
+
+ key = util_state_get_key ("main/contents", "books_disabled");
+ ige_conf_set_string_list (ige_conf_get (), key, books_disabled);
+ g_free(key);
+}
+
+static gboolean
+util_state_notebook_timeout_cb (gpointer notebook)
+{
+ DhUtilStateItem *item;
+
+ item = g_object_get_data (notebook, "dh-util-state");
+ if (item) {
+ GtkWidget *page;
+ const gchar *page_name;
+
+ item->timeout_id = 0;
+
+ page = gtk_notebook_get_nth_page (
+ notebook,
+ gtk_notebook_get_current_page (notebook));
+ page_name = dh_util_state_get_notebook_page_name (page);
+ if (page_name) {
+ gchar *key;
+
+ key = util_state_get_key (item->name, "selected_tab");
+ ige_conf_set_string (ige_conf_get (), key, page_name);
+ g_free (key);
+ }
+ }
+
+ return FALSE;
+}
+
+static void
+util_state_notebook_switch_page_cb (GtkWidget *notebook,
+ gpointer page,
+ guint page_num,
+ gpointer user_data)
+{
+ util_state_schedule_save (notebook, util_state_notebook_timeout_cb);
+}
+
+void
+dh_util_state_set_notebook_page_name (GtkWidget *page,
+ const gchar *page_name)
+{
+ g_object_set_data_full (G_OBJECT (page),
+ "dh-util-state-tab-name",
+ g_strdup (page_name),
+ g_free);
+}
+
+const gchar *
+dh_util_state_get_notebook_page_name (GtkWidget *page)
+{
+ return g_object_get_data (G_OBJECT (page),
+ "dh-util-state-tab-name");
+}
+
+void
+dh_util_state_manage_notebook (GtkNotebook *notebook,
+ const gchar *name,
+ const gchar *default_tab)
+{
+ gchar *key;
+ gchar *tab;
+ gint i;
+
+ util_state_setup_widget (GTK_WIDGET (notebook), name);
+
+ key = util_state_get_key (name, "selected_tab");
+ if (!ige_conf_get_string (ige_conf_get (), key, &tab)) {
+ tab = g_strdup (default_tab);
+ }
+ g_free (key);
+
+ for (i = 0; i < gtk_notebook_get_n_pages (notebook); i++) {
+ GtkWidget *page;
+ const gchar *page_name;
+
+ page = gtk_notebook_get_nth_page (notebook, i);
+ page_name = dh_util_state_get_notebook_page_name (page);
+ if (page_name && strcmp (page_name, tab) == 0) {
+ gtk_notebook_set_current_page (notebook, i);
+ gtk_widget_grab_focus (page);
+ break;
+ }
+ }
+
+ g_free (tab);
+
+ g_signal_connect (notebook, "switch-page",
+ G_CALLBACK (util_state_notebook_switch_page_cb),
+ NULL);
+}
+
+static gboolean
+split_font_string (const gchar *name_and_size,
+ gchar **name,
+ gdouble *size)
+{
+ PangoFontDescription *desc;
+ PangoFontMask mask;
+ gboolean retval = FALSE;
+
+ desc = pango_font_description_from_string (name_and_size);
+ if (!desc) {
+ return FALSE;
+ }
+
+ mask = (PANGO_FONT_MASK_FAMILY | PANGO_FONT_MASK_SIZE);
+ if ((pango_font_description_get_set_fields (desc) & mask) == mask) {
+ *size = PANGO_PIXELS (pango_font_description_get_size (desc));
+ *name = g_strdup (pango_font_description_get_family (desc));
+ retval = TRUE;
+ }
+
+ pango_font_description_free (desc);
+
+ return retval;
+}
+
+#define DH_CONF_PATH "/apps/devhelp"
+#define DH_CONF_USE_SYSTEM_FONTS DH_CONF_PATH "/ui/use_system_fonts"
+#define DH_CONF_VARIABLE_FONT DH_CONF_PATH "/ui/variable_font"
+#define DH_CONF_FIXED_FONT DH_CONF_PATH "/ui/fixed_font"
+#define DH_CONF_SYSTEM_VARIABLE_FONT "/desktop/gnome/interface/font_name"
+#define DH_CONF_SYSTEM_FIXED_FONT "/desktop/gnome/interface/monospace_font_name"
+
+void
+dh_util_font_get_variable (gchar **name,
+ gdouble *size,
+ gboolean use_system_fonts)
+{
+ IgeConf *conf;
+ gchar *name_and_size;
+
+ conf = ige_conf_get ();
+
+ if (use_system_fonts) {
+#ifdef GDK_WINDOWING_QUARTZ
+ name_and_size = g_strdup ("Lucida Grande 14");
+#else
+ ige_conf_get_string (conf,
+ DH_CONF_SYSTEM_VARIABLE_FONT,
+ &name_and_size);
+#endif
+ } else {
+ ige_conf_get_string (conf,
+ DH_CONF_VARIABLE_FONT,
+ &name_and_size);
+ }
+
+ if (!split_font_string (name_and_size, name, size)) {
+ *name = g_strdup ("sans");
+ *size = 12;
+ }
+
+ g_free (name_and_size);
+}
+
+void
+dh_util_font_get_fixed (gchar **name,
+ gdouble *size,
+ gboolean use_system_fonts)
+{
+ IgeConf *conf;
+ gchar *name_and_size;
+
+ conf = ige_conf_get ();
+
+ if (use_system_fonts) {
+#ifdef GDK_WINDOWING_QUARTZ
+ name_and_size = g_strdup ("Monaco 14");
+#else
+ ige_conf_get_string (conf,
+ DH_CONF_SYSTEM_FIXED_FONT,
+ &name_and_size);
+#endif
+ } else {
+ ige_conf_get_string (conf,
+ DH_CONF_FIXED_FONT,
+ &name_and_size);
+ }
+
+ if (!split_font_string (name_and_size, name, size)) {
+ *name = g_strdup ("monospace");
+ *size = 12;
+ }
+
+ g_free (name_and_size);
+}
+
+static void
+view_destroy_cb (GtkWidget *view,
+ gpointer user_data)
+{
+ views = g_list_remove (views, view);
+}
+
+static void
+view_setup_fonts (WebKitWebView *view)
+{
+ IgeConf *conf;
+ WebKitWebSettings *settings;
+ gboolean use_system_fonts;
+ gchar *variable_name;
+ gdouble variable_size;
+ gchar *fixed_name;
+ gdouble fixed_size;
+
+ conf = ige_conf_get ();
+
+ settings = webkit_web_view_get_settings (WEBKIT_WEB_VIEW (view));
+
+ ige_conf_get_bool (conf,
+ DH_CONF_USE_SYSTEM_FONTS,
+ &use_system_fonts);
+
+ dh_util_font_get_variable (&variable_name, &variable_size,
+ use_system_fonts);
+ dh_util_font_get_fixed (&fixed_name, &fixed_size,
+ use_system_fonts);
+
+ g_object_set (settings,
+ "monospace-font-family", fixed_name,
+ "default-monospace-font-size", (guint) fixed_size,
+ "sans-serif-font-family", variable_name,
+ "serif-font-family", variable_name,
+ "default-font-size", (guint) variable_size,
+ NULL);
+
+ g_free (variable_name);
+ g_free (fixed_name);
+}
+
+static void
+font_notify_cb (IgeConf *conf,
+ const gchar *path,
+ gpointer user_data)
+{
+ GList *l;
+
+ for (l = views; l; l = l->next) {
+ view_setup_fonts (l->data);
+ }
+}
+
+void
+dh_util_font_add_web_view (WebKitWebView *view)
+{
+ static gboolean setup;
+
+ if (!setup) {
+ IgeConf *conf;
+
+ conf = ige_conf_get ();
+
+ ige_conf_notify_add (conf,
+ DH_CONF_USE_SYSTEM_FONTS,
+ font_notify_cb,
+ NULL);
+ ige_conf_notify_add (conf,
+ DH_CONF_SYSTEM_VARIABLE_FONT,
+ font_notify_cb,
+ NULL);
+ ige_conf_notify_add (conf,
+ DH_CONF_SYSTEM_FIXED_FONT,
+ font_notify_cb,
+ NULL);
+ ige_conf_notify_add (conf,
+ DH_CONF_VARIABLE_FONT,
+ font_notify_cb,
+ NULL);
+ ige_conf_notify_add (conf,
+ DH_CONF_FIXED_FONT,
+ font_notify_cb,
+ NULL);
+
+ setup = TRUE;
+ }
+
+ views = g_list_prepend (views, view);
+
+ g_signal_connect (view, "destroy",
+ G_CALLBACK (view_destroy_cb),
+ NULL);
+
+ view_setup_fonts (view);
+}
+
+gint
+dh_util_cmp_book (DhLink *a, DhLink *b)
+{
+ const gchar *name_a;
+ const gchar *name_b;
+ gchar *name_a_casefold;
+ gchar *name_b_casefold;
+ int rc;
+
+ name_a = dh_link_get_name (a);
+ if (!name_a) {
+ name_a = "";
+ }
+
+ name_b = dh_link_get_name (b);
+ if (!name_b) {
+ name_b = "";
+ }
+
+ if (g_ascii_strncasecmp (name_a, "the ", 4) == 0) {
+ name_a += 4;
+ }
+ if (g_ascii_strncasecmp (name_b, "the ", 4) == 0) {
+ name_b += 4;
+ }
+
+ name_a_casefold = g_utf8_casefold (name_a, -1);
+ name_b_casefold = g_utf8_casefold (name_b, -1);
+
+ rc = strcmp (name_a_casefold, name_b_casefold);
+
+ g_free (name_a_casefold);
+ g_free (name_b_casefold);
+
+ return rc;
+}
+
Modified: devhelp/devhelp/dh-util.h
67 files changed, 67 insertions(+), 0 deletions(-)
===================================================================
@@ -0,0 +1,67 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2001-2002 Mikael Hallendal <micke at imendio.com>
+ * Copyright (C) 2004,2008 Imendio AB
+ *
+ * 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.
+ */
+
+#ifndef __DH_UTIL_H__
+#define __DH_UTIL_H__
+
+#include <gtk/gtk.h>
+#include <webkit/webkit.h>
+#include "dh-link.h"
+
+G_BEGIN_DECLS
+
+GtkBuilder * dh_util_builder_get_file (const gchar *filename,
+ const gchar *root,
+ const gchar *domain,
+ const gchar *first_required_widget,
+ ...);
+void dh_util_builder_connect (GtkBuilder *gui,
+ gpointer user_data,
+ gchar *first_widget,
+ ...);
+gchar * dh_util_build_data_filename (const gchar *first_part,
+ ...);
+void dh_util_state_manage_window (GtkWindow *window,
+ const gchar *name);
+void dh_util_state_manage_paned (GtkPaned *paned,
+ const gchar *name);
+void dh_util_state_manage_notebook (GtkNotebook *notebook,
+ const gchar *name,
+ const gchar *default_tab);
+void dh_util_state_set_notebook_page_name (GtkWidget *page,
+ const gchar *page_name);
+const gchar *dh_util_state_get_notebook_page_name (GtkWidget *page);
+GSList * dh_util_state_load_books_disabled (void);
+void dh_util_state_store_books_disabled (GSList *books_disabled);
+
+void dh_util_font_get_variable (gchar **name,
+ gdouble *size,
+ gboolean use_system_font);
+void dh_util_font_get_fixed (gchar **name,
+ gdouble *size,
+ gboolean use_system_font);
+void dh_util_font_add_web_view (WebKitWebView *view);
+gint dh_util_cmp_book (DhLink *a,
+ DhLink *b);
+
+G_END_DECLS
+
+#endif /* __DH_UTIL_H__ */
Modified: devhelp/devhelp/dh-window.c
1982 files changed, 1982 insertions(+), 0 deletions(-)
===================================================================
@@ -0,0 +1,1982 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2001-2008 Imendio AB
+ *
+ * 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.
+ */
+
+/*
+ * Fullscreen mode code adapted from gedit
+ * Copyright (C) 1998, 1999 Alex Roberts, Evan Lawrence
+ * Copyright (C) 2000, 2001 Chema Celorio, Paolo Maggi
+ * Copyright (C) 2002-2005 Paolo Maggi
+ */
+
+#include "config.h"
+#include <string.h>
+#include <glib/gi18n-lib.h>
+#include <gdk/gdkkeysyms.h>
+#include <gtk/gtk.h>
+#include <webkit/webkit.h>
+
+#ifdef GDK_WINDOWING_QUARTZ
+#include <ige-mac-integration.h>
+#endif
+
+#include "dh-book-tree.h"
+#include "dh-book-manager.h"
+#include "dh-book.h"
+#include "dh-preferences.h"
+#include "dh-search.h"
+#include "dh-window.h"
+#include "dh-util.h"
+#include "dh-marshal.h"
+#include "dh-enum-types.h"
+#include "eggfindbar.h"
+#include "ige-conf.h"
+
+#define FULLSCREEN_ANIMATION_SPEED 4
+
+struct _DhWindowPriv {
+ DhBase *base;
+
+ GtkWidget *main_box;
+ GtkWidget *menu_box;
+ GtkWidget *hpaned;
+ GtkWidget *control_notebook;
+ GtkWidget *book_tree;
+ GtkWidget *search;
+ GtkWidget *notebook;
+
+ GtkWidget *vbox;
+ GtkWidget *findbar;
+
+ GtkWidget *fullscreen_controls;
+ guint fullscreen_animation_timeout_id;
+ gboolean fullscreen_animation_enter;
+
+ GtkUIManager *manager;
+ GtkActionGroup *action_group;
+
+ DhLink *selected_search_link;
+ guint find_source_id;
+};
+
+enum {
+ OPEN_LINK,
+ LAST_SIGNAL
+};
+
+static gint signals[LAST_SIGNAL] = { 0 };
+
+static guint tab_accel_keys[] = {
+ GDK_1, GDK_2, GDK_3, GDK_4, GDK_5,
+ GDK_6, GDK_7, GDK_8, GDK_9, GDK_0
+};
+
+static const
+struct
+{
+ gchar *name;
+ int level;
+}
+zoom_levels[] =
+{
+ { N_("50%"), 70 },
+ { N_("75%"), 84 },
+ { N_("100%"), 100 },
+ { N_("125%"), 119 },
+ { N_("150%"), 141 },
+ { N_("175%"), 168 },
+ { N_("200%"), 200 },
+ { N_("300%"), 283 },
+ { N_("400%"), 400 }
+};
+
+#define ZOOM_MINIMAL (zoom_levels[0].level)
+#define ZOOM_MAXIMAL (zoom_levels[8].level)
+#define ZOOM_DEFAULT (zoom_levels[2].level)
+
+#if GTK_CHECK_VERSION (2,17,5)
+#define ERRORS_IN_INFOBAR
+#endif
+
+static void dh_window_class_init (DhWindowClass *klass);
+static void dh_window_init (DhWindow *window);
+static void window_populate (DhWindow *window);
+static void window_tree_link_selected_cb (GObject *ignored,
+ DhLink *link,
+ DhWindow *window);
+static void window_search_link_selected_cb (GObject *ignored,
+ DhLink *link,
+ DhWindow *window);
+static void window_check_history (DhWindow *window,
+ WebKitWebView *web_view);
+static void window_web_view_tab_accel_cb (GtkAccelGroup *accel_group,
+ GObject *object,
+ guint key,
+ GdkModifierType mod,
+ DhWindow *window);
+static void window_find_search_changed_cb (GObject *object,
+ GParamSpec *arg1,
+ DhWindow *window);
+static void window_find_case_changed_cb (GObject *object,
+ GParamSpec *arg1,
+ DhWindow *window);
+static void window_find_previous_cb (GtkEntry *entry,
+ DhWindow *window);
+static void window_find_next_cb (GtkEntry *entry,
+ DhWindow *window);
+static void window_findbar_close_cb (GtkWidget *widget,
+ DhWindow *window);
+static GtkWidget * window_new_tab_label (DhWindow *window,
+ const gchar *label,
+ const GtkWidget *parent);
+static int window_open_new_tab (DhWindow *window,
+ const gchar *location,
+ gboolean switch_focus);
+static WebKitWebView *window_get_active_web_view (DhWindow *window);
+#ifdef ERRORS_IN_INFOBAR
+static GtkWidget * window_get_active_info_bar (DhWindow *window);
+#endif
+static void window_update_title (DhWindow *window,
+ WebKitWebView *web_view,
+ const gchar *title);
+static void window_tab_set_title (DhWindow *window,
+ WebKitWebView *web_view,
+ const gchar *title);
+static void window_close_tab (DhWindow *window,
+ gint page_num);
+
+G_DEFINE_TYPE (DhWindow, dh_window, GTK_TYPE_WINDOW);
+
+#define GET_PRIVATE(instance) G_TYPE_INSTANCE_GET_PRIVATE \
+ (instance, DH_TYPE_WINDOW, DhWindowPriv);
+
+static void
+window_activate_new_window (GtkAction *action,
+ DhWindow *window)
+{
+ DhWindowPriv *priv;
+ GtkWidget *new_window;
+
+ priv = window->priv;
+
+ new_window = dh_base_new_window (priv->base);
+ gtk_widget_show (new_window);
+}
+
+static void
+window_activate_new_tab (GtkAction *action,
+ DhWindow *window)
+{
+ window_open_new_tab (window, NULL, TRUE);
+}
+
+static void
+window_activate_print (GtkAction *action,
+ DhWindow *window)
+{
+ WebKitWebView *web_view;
+
+ web_view = window_get_active_web_view (window);
+ webkit_web_view_execute_script (web_view, "print();");
+}
+
+static void
+window_close_tab (DhWindow *window,
+ gint page_num)
+{
+ DhWindowPriv *priv;
+ gint pages;
+
+ priv = window->priv;
+
+ gtk_notebook_remove_page (GTK_NOTEBOOK (priv->notebook), page_num);
+
+ pages = gtk_notebook_get_n_pages (GTK_NOTEBOOK (priv->notebook));
+
+ if (pages == 0) {
+ gtk_widget_destroy (GTK_WIDGET (window));
+ }
+ else if (pages == 1) {
+ gtk_notebook_set_show_tabs (GTK_NOTEBOOK (priv->notebook), FALSE);
+ }
+}
+
+static void
+window_activate_close (GtkAction *action,
+ DhWindow *window)
+{
+ gint page_num;
+
+ page_num = gtk_notebook_get_current_page (GTK_NOTEBOOK (window->priv->notebook));
+ window_close_tab (window, page_num);
+}
+
+static void
+window_activate_quit (GtkAction *action,
+ DhWindow *window)
+{
+ dh_base_quit (window->priv->base);
+}
+
+static void
+window_activate_copy (GtkAction *action,
+ DhWindow *window)
+{
+ GtkWidget *widget;
+ DhWindowPriv *priv;
+
+ priv = window->priv;
+
+ widget = gtk_window_get_focus (GTK_WINDOW (window));
+
+ if (GTK_IS_EDITABLE (widget)) {
+ gtk_editable_copy_clipboard (GTK_EDITABLE (widget));
+ } else if (GTK_IS_TREE_VIEW (widget) &&
+ gtk_widget_is_ancestor (widget, priv->search) &&
+ priv->selected_search_link) {
+ GtkClipboard *clipboard;
+ clipboard = gtk_widget_get_clipboard (widget, GDK_SELECTION_CLIPBOARD);
+ gtk_clipboard_set_text (clipboard,
+ dh_link_get_name(priv->selected_search_link), -1);
+ } else {
+ WebKitWebView *web_view;
+
+ web_view = window_get_active_web_view (window);
+ webkit_web_view_copy_clipboard (web_view);
+ }
+}
+
+static void
+window_activate_find (GtkAction *action,
+ DhWindow *window)
+{
+ DhWindowPriv *priv;
+ WebKitWebView *web_view;
+
+ priv = window->priv;
+ web_view = window_get_active_web_view (window);
+
+ gtk_widget_show (priv->findbar);
+ gtk_widget_grab_focus (priv->findbar);
+
+ webkit_web_view_set_highlight_text_matches (web_view, TRUE);
+}
+
+static int
+window_get_current_zoom_level_index (DhWindow *window)
+{
+ WebKitWebView *web_view;
+ float zoom_level;
+ int zoom_level_as_int = ZOOM_DEFAULT;
+ int i;
+
+ web_view = window_get_active_web_view (window);
+ if (web_view) {
+ g_object_get (web_view, "zoom-level", &zoom_level, NULL);
+ zoom_level_as_int = (int)(zoom_level*100);
+ }
+
+ for (i=0; zoom_levels[i].level != ZOOM_MAXIMAL; i++) {
+ if (zoom_levels[i].level == zoom_level_as_int)
+ return i;
+ }
+ return i;
+}
+
+static void
+window_update_zoom_actions_sensitiveness (DhWindow *window)
+{
+ DhWindowPriv *priv;
+ GtkAction *zoom_in, *zoom_out, *zoom_default;
+ int zoom_level_idx;
+
+ priv = window->priv;
+ zoom_in = gtk_action_group_get_action (priv->action_group, "ZoomIn");
+ zoom_out = gtk_action_group_get_action (priv->action_group, "ZoomOut");
+ zoom_default = gtk_action_group_get_action (priv->action_group, "ZoomDefault");
+
+ zoom_level_idx = window_get_current_zoom_level_index (window);
+
+ gtk_action_set_sensitive (zoom_in,
+ zoom_levels[zoom_level_idx].level < ZOOM_MAXIMAL);
+ gtk_action_set_sensitive (zoom_out,
+ zoom_levels[zoom_level_idx].level > ZOOM_MINIMAL);
+ gtk_action_set_sensitive (zoom_default,
+ zoom_levels[zoom_level_idx].level != ZOOM_DEFAULT);
+}
+
+static void
+window_activate_zoom_in (GtkAction *action,
+ DhWindow *window)
+{
+ int zoom_level_idx;
+
+ zoom_level_idx = window_get_current_zoom_level_index (window);
+ if (zoom_levels[zoom_level_idx].level < ZOOM_MAXIMAL) {
+ WebKitWebView *web_view;
+
+ web_view = window_get_active_web_view (window);
+ g_object_set (web_view,
+ "zoom-level", (float)(zoom_levels[zoom_level_idx+1].level)/100,
+ NULL);
+ window_update_zoom_actions_sensitiveness (window);
+ }
+
+}
+
+static void
+window_activate_zoom_out (GtkAction *action,
+ DhWindow *window)
+{
+ int zoom_level_idx;
+
+ zoom_level_idx = window_get_current_zoom_level_index (window);
+ if (zoom_levels[zoom_level_idx].level > ZOOM_MINIMAL) {
+ WebKitWebView *web_view;
+
+ web_view = window_get_active_web_view (window);
+ g_object_set (web_view,
+ "zoom-level", (float)(zoom_levels[zoom_level_idx-1].level)/100,
+ NULL);
+ window_update_zoom_actions_sensitiveness (window);
+ }
+}
+
+static void
+window_activate_zoom_default (GtkAction *action,
+ DhWindow *window)
+{
+ WebKitWebView *web_view;
+
+ web_view = window_get_active_web_view (window);
+ g_object_set (web_view, "zoom-level", (float)(ZOOM_DEFAULT)/100, NULL);
+ window_update_zoom_actions_sensitiveness (window);
+}
+
+static gboolean
+run_fullscreen_animation (gpointer data)
+{
+ DhWindow *window = DH_WINDOW (data);
+ GdkScreen *screen;
+ GdkRectangle fs_rect;
+ gint x, y;
+
+ screen = gtk_window_get_screen (GTK_WINDOW (window));
+ gdk_screen_get_monitor_geometry (screen,
+ gdk_screen_get_monitor_at_window (screen,
+ gtk_widget_get_window (GTK_WIDGET (window))),
+ &fs_rect);
+
+ gtk_window_get_position (GTK_WINDOW (window->priv->fullscreen_controls),
+ &x, &y);
+
+ if (window->priv->fullscreen_animation_enter)
+ {
+ if (y == fs_rect.y)
+ {
+ window->priv->fullscreen_animation_timeout_id = 0;
+ return FALSE;
+ }
+ else
+ {
+ gtk_window_move (GTK_WINDOW (window->priv->fullscreen_controls),
+ x, y + 1);
+ return TRUE;
+ }
+ }
+ else
+ {
+ gint w, h;
+
+ gtk_window_get_size (GTK_WINDOW (window->priv->fullscreen_controls),
+ &w, &h);
+
+ if (y == fs_rect.y - h + 1)
+ {
+ window->priv->fullscreen_animation_timeout_id = 0;
+ return FALSE;
+ }
+ else
+ {
+ gtk_window_move (GTK_WINDOW (window->priv->fullscreen_controls),
+ x, y - 1);
+ return TRUE;
+ }
+ }
+}
+
+static void
+show_hide_fullscreen_toolbar (DhWindow *window,
+ gboolean show,
+ gint height)
+{
+ GtkSettings *settings;
+ gboolean enable_animations;
+
+ settings = gtk_widget_get_settings (GTK_WIDGET (window));
+ g_object_get (G_OBJECT (settings),
+ "gtk-enable-animations",
+ &enable_animations,
+ NULL);
+
+ if (enable_animations)
+ {
+ window->priv->fullscreen_animation_enter = show;
+
+ if (window->priv->fullscreen_animation_timeout_id == 0)
+ {
+ window->priv->fullscreen_animation_timeout_id =
+ g_timeout_add (FULLSCREEN_ANIMATION_SPEED,
+ (GSourceFunc) run_fullscreen_animation,
+ window);
+ }
+ }
+ else
+ {
+ GdkRectangle fs_rect;
+ GdkScreen *screen;
+
+ screen = gtk_window_get_screen (GTK_WINDOW (window));
+ gdk_screen_get_monitor_geometry (screen,
+ gdk_screen_get_monitor_at_window (screen,
+ gtk_widget_get_window (GTK_WIDGET (window))),
+ &fs_rect);
+
+ if (show)
+ gtk_window_move (GTK_WINDOW (window->priv->fullscreen_controls),
+ fs_rect.x, fs_rect.y);
+ else
+ gtk_window_move (GTK_WINDOW (window->priv->fullscreen_controls),
+ fs_rect.x, fs_rect.y - height + 1);
+ }
+
+}
+
+
+static gboolean
+on_fullscreen_controls_enter_notify_event (GtkWidget *widget,
+ GdkEventCrossing *event,
+ DhWindow *window)
+{
+ show_hide_fullscreen_toolbar (window, TRUE, 0);
+
+ return FALSE;
+}
+
+static gboolean
+on_fullscreen_controls_leave_notify_event (GtkWidget *widget,
+ GdkEventCrossing *event,
+ DhWindow *window)
+{
+ GdkDisplay *display;
+ GdkScreen *screen;
+ gint w, h;
+ gint x, y;
+
+ display = gdk_display_get_default ();
+ screen = gtk_window_get_screen (GTK_WINDOW (window));
+
+ gtk_window_get_size (GTK_WINDOW (window->priv->fullscreen_controls), &w, &h);
+ gdk_display_get_pointer (display, &screen, &x, &y, NULL);
+
+ /* gtk seems to emit leave notify when clicking on tool items,
+ * work around it by checking the coordinates
+ */
+ if (y >= h)
+ {
+ show_hide_fullscreen_toolbar (window, FALSE, h);
+ }
+
+ return FALSE;
+}
+
+static gboolean
+window_is_fullscreen (DhWindow *window)
+{
+ GdkWindowState state;
+
+ g_return_val_if_fail (DH_IS_WINDOW (window), FALSE);
+
+#if GTK_CHECK_VERSION (2,14,0)
+ state = gdk_window_get_state (gtk_widget_get_window (GTK_WIDGET (window)));
+#else
+ state = gdk_window_get_state (GTK_WIDGET (window)->window);
+#endif
+
+ return state & GDK_WINDOW_STATE_FULLSCREEN;
+}
+
+static void
+window_fullscreen_controls_build (DhWindow *window)
+{
+ GtkWidget *toolbar;
+ GtkAction *action;
+ DhWindowPriv *priv;
+
+ priv = window->priv;
+ if (priv->fullscreen_controls != NULL)
+ return;
+
+ priv->fullscreen_controls = gtk_window_new (GTK_WINDOW_POPUP);
+ gtk_window_set_transient_for (GTK_WINDOW (priv->fullscreen_controls),
+ GTK_WINDOW (window));
+
+ toolbar = gtk_ui_manager_get_widget (priv->manager, "/FullscreenToolBar");
+ gtk_container_add (GTK_CONTAINER (priv->fullscreen_controls),
+ toolbar);
+ action = gtk_action_group_get_action (priv->action_group,
+ "LeaveFullscreen");
+ g_object_set (action, "is-important", TRUE, NULL);
+
+ /* Set the toolbar style */
+ gtk_toolbar_set_style (GTK_TOOLBAR (toolbar),
+ GTK_TOOLBAR_BOTH_HORIZ);
+
+ g_signal_connect (priv->fullscreen_controls, "enter-notify-event",
+ G_CALLBACK (on_fullscreen_controls_enter_notify_event),
+ window);
+ g_signal_connect (priv->fullscreen_controls, "leave-notify-event",
+ G_CALLBACK (on_fullscreen_controls_leave_notify_event),
+ window);
+}
+
+static void
+window_fullscreen_controls_show (DhWindow *window)
+{
+ GdkScreen *screen;
+ GdkRectangle fs_rect;
+ gint w, h;
+
+ screen = gtk_window_get_screen (GTK_WINDOW (window));
+ gdk_screen_get_monitor_geometry (screen,
+ gdk_screen_get_monitor_at_window (
+ screen,
+ gtk_widget_get_window (GTK_WIDGET (window))),
+ &fs_rect);
+
+ gtk_window_get_size (GTK_WINDOW (window->priv->fullscreen_controls), &w, &h);
+
+ gtk_window_resize (GTK_WINDOW (window->priv->fullscreen_controls),
+ fs_rect.width, h);
+
+ gtk_window_move (GTK_WINDOW (window->priv->fullscreen_controls),
+ fs_rect.x, fs_rect.y - h + 1);
+
+ gtk_widget_show_all (window->priv->fullscreen_controls);
+}
+
+static void
+window_fullscreen (DhWindow *window)
+{
+ if (window_is_fullscreen (window))
+ return;
+
+ gtk_window_fullscreen (GTK_WINDOW (window));
+ gtk_widget_hide (gtk_ui_manager_get_widget (window->priv->manager, "/MenuBar"));
+ gtk_widget_hide (gtk_ui_manager_get_widget (window->priv->manager, "/Toolbar"));
+
+ window_fullscreen_controls_build (window);
+ window_fullscreen_controls_show (window);
+}
+
+static void
+window_unfullscreen (DhWindow *window)
+{
+ if (! window_is_fullscreen (window))
+ return;
+
+ gtk_window_unfullscreen (GTK_WINDOW (window));
+ gtk_widget_show (gtk_ui_manager_get_widget (window->priv->manager, "/MenuBar"));
+ gtk_widget_show (gtk_ui_manager_get_widget (window->priv->manager, "/Toolbar"));
+
+ gtk_widget_hide (window->priv->fullscreen_controls);
+}
+
+
+static void
+window_toggle_fullscreen_mode (GtkAction *action,
+ DhWindow *window)
+{
+ if (window_is_fullscreen (window)) {
+ window_unfullscreen (window);
+ } else {
+ window_fullscreen (window);
+ }
+}
+
+static void
+window_leave_fullscreen_mode (GtkAction *action,
+ DhWindow *window)
+{
+ GtkAction *view_action;
+
+ view_action = gtk_action_group_get_action (window->priv->action_group,
+ "ViewFullscreen");
+ g_signal_handlers_block_by_func (view_action,
+ G_CALLBACK (window_toggle_fullscreen_mode),
+ window);
+ gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (view_action),
+ FALSE);
+ window_unfullscreen (window);
+ g_signal_handlers_unblock_by_func (view_action,
+ G_CALLBACK (window_toggle_fullscreen_mode),
+ window);
+}
+
+static void
+window_activate_preferences (GtkAction *action,
+ DhWindow *window)
+{
+ dh_preferences_show_dialog (GTK_WINDOW (window));
+}
+
+static void
+window_activate_back (GtkAction *action,
+ DhWindow *window)
+{
+ DhWindowPriv *priv;
+ WebKitWebView *web_view;
+ GtkWidget *frame;
+
+ priv = window->priv;
+
+ frame = gtk_notebook_get_nth_page (
+ GTK_NOTEBOOK (priv->notebook),
+ gtk_notebook_get_current_page (GTK_NOTEBOOK (priv->notebook)));
+ web_view = g_object_get_data (G_OBJECT (frame), "web_view");
+
+ webkit_web_view_go_back (web_view);
+}
+
+static void
+window_activate_forward (GtkAction *action,
+ DhWindow *window)
+{
+ DhWindowPriv *priv;
+ WebKitWebView *web_view;
+ GtkWidget *frame;
+
+ priv = window->priv;
+
+ frame = gtk_notebook_get_nth_page (GTK_NOTEBOOK (priv->notebook),
+ gtk_notebook_get_current_page (GTK_NOTEBOOK (priv->notebook))
+ );
+ web_view = g_object_get_data (G_OBJECT (frame), "web_view");
+
+ webkit_web_view_go_forward (web_view);
+}
+
+static void
+window_activate_show_contents (GtkAction *action,
+ DhWindow *window)
+{
+ DhWindowPriv *priv;
+
+ priv = window->priv;
+
+ gtk_notebook_set_current_page (GTK_NOTEBOOK (priv->control_notebook), 0);
+ gtk_widget_grab_focus (priv->book_tree);
+}
+
+static void
+window_activate_show_search (GtkAction *action,
+ DhWindow *window)
+{
+ DhWindowPriv *priv;
+
+ priv = window->priv;
+
+ gtk_notebook_set_current_page (GTK_NOTEBOOK (priv->control_notebook), 1);
+ gtk_widget_grab_focus (priv->search);
+}
+
+static void
+window_activate_about (GtkAction *action,
+ DhWindow *window)
+{
+ const gchar *authors[] = {
+ "Mikael Hallendal <micke at imendio.com>",
+ "Richard Hult <richard at imendio.com>",
+ "Johan Dahlin <johan at gnome.org>",
+ "Ross Burton <ross at burtonini.com>",
+ "Aleksander Morgado <aleksander at lanedo.com>",
+ NULL
+ };
+ const gchar **documenters = NULL;
+ const gchar *translator_credits = _("translator_credits");
+
+ /* i18n: Please don't translate "Devhelp" (it's marked as translatable
+ * for transliteration only) */
+ gtk_show_about_dialog (GTK_WINDOW (window),
+ "name", _("Devhelp"),
+ "version", PACKAGE_VERSION,
+ "comments", _("A developers' help browser for GNOME"),
+ "authors", authors,
+ "documenters", documenters,
+ "translator-credits",
+ strcmp (translator_credits, "translator_credits") != 0 ?
+ translator_credits : NULL,
+ "website", "http://live.gnome.org/devhelp",
+ "logo-icon-name", "devhelp",
+ NULL);
+}
+
+static void
+window_open_link_cb (DhWindow *window,
+ const char *location,
+ DhOpenLinkFlags flags)
+{
+ DhWindowPriv *priv;
+ priv = window->priv;
+
+ if (flags & DH_OPEN_LINK_NEW_TAB) {
+ window_open_new_tab (window, location, FALSE);
+ }
+ else if (flags & DH_OPEN_LINK_NEW_WINDOW) {
+ GtkWidget *new_window;
+ new_window = dh_base_new_window (priv->base);
+ gtk_widget_show (new_window);
+ }
+}
+
+static const GtkActionEntry actions[] = {
+ { "FileMenu", NULL, N_("_File"), NULL, NULL, NULL },
+ { "EditMenu", NULL, N_("_Edit"), NULL, NULL, NULL },
+ { "ViewMenu", NULL, N_("_View"), NULL, NULL, NULL },
+ { "GoMenu", NULL, N_("_Go"), NULL, NULL, NULL },
+ { "HelpMenu", NULL, N_("_Help"), NULL, NULL, NULL },
+
+ /* File menu */
+ { "NewWindow", GTK_STOCK_NEW, N_("_New Window"), "<control>N", NULL,
+ G_CALLBACK (window_activate_new_window) },
+ { "NewTab", GTK_STOCK_NEW, N_("New _Tab"), "<control>T", NULL,
+ G_CALLBACK (window_activate_new_tab) },
+ { "Print", GTK_STOCK_PRINT, N_("_Print…"), "<control>P", NULL,
+ G_CALLBACK (window_activate_print) },
+ { "Close", GTK_STOCK_CLOSE, NULL, NULL, NULL,
+ G_CALLBACK (window_activate_close) },
+ { "Quit", GTK_STOCK_QUIT, NULL, NULL, NULL,
+ G_CALLBACK (window_activate_quit) },
+
+ /* Edit menu */
+ { "Copy", GTK_STOCK_COPY, NULL, "<control>C", NULL,
+ G_CALLBACK (window_activate_copy) },
+ { "Find", GTK_STOCK_FIND, NULL, "<control>F", NULL,
+ G_CALLBACK (window_activate_find) },
+ { "Find Next", GTK_STOCK_GO_FORWARD, N_("Find Next"), "<control>G", NULL,
+ G_CALLBACK (window_find_next_cb) },
+ { "Find Previous", GTK_STOCK_GO_BACK, N_("Find Previous"), "<shift><control>G", NULL,
+ G_CALLBACK (window_find_previous_cb) },
+ { "Preferences", GTK_STOCK_PREFERENCES, NULL, NULL, NULL,
+ G_CALLBACK (window_activate_preferences) },
+
+ /* Go menu */
+ { "Back", GTK_STOCK_GO_BACK, NULL, "<alt>Left",
+ N_("Go to the previous page"),
+ G_CALLBACK (window_activate_back) },
+ { "Forward", GTK_STOCK_GO_FORWARD, NULL, "<alt>Right",
+ N_("Go to the next page"),
+ G_CALLBACK (window_activate_forward) },
+
+ { "ShowContentsTab", NULL, N_("_Contents Tab"), "<ctrl>B", NULL,
+ G_CALLBACK (window_activate_show_contents) },
+
+ { "ShowSearchTab", NULL, N_("_Search Tab"), "<ctrl>S", NULL,
+ G_CALLBACK (window_activate_show_search) },
+
+ /* View menu */
+ { "ZoomIn", GTK_STOCK_ZOOM_IN, N_("_Larger Text"), "<ctrl>plus",
+ N_("Increase the text size"),
+ G_CALLBACK (window_activate_zoom_in) },
+ { "ZoomOut", GTK_STOCK_ZOOM_OUT, N_("S_maller Text"), "<ctrl>minus",
+ N_("Decrease the text size"),
+ G_CALLBACK (window_activate_zoom_out) },
+ { "ZoomDefault", GTK_STOCK_ZOOM_100, N_("_Normal Size"), "<ctrl>0",
+ N_("Use the normal text size"),
+ G_CALLBACK (window_activate_zoom_default) },
+
+ /* About menu */
+ { "About", GTK_STOCK_ABOUT, NULL, NULL, NULL,
+ G_CALLBACK (window_activate_about) },
+
+ /* Fullscreen toolbar */
+ { "LeaveFullscreen", GTK_STOCK_LEAVE_FULLSCREEN, NULL,
+ NULL, N_("Leave fullscreen mode"),
+ G_CALLBACK (window_leave_fullscreen_mode) }
+};
+
+static const GtkToggleActionEntry always_sensitive_toggle_menu_entries[] =
+{
+ { "ViewFullscreen", GTK_STOCK_FULLSCREEN, NULL, "F11",
+ N_("Display in full screen"),
+ G_CALLBACK (window_toggle_fullscreen_mode), FALSE },
+};
+
+static const gchar* important_actions[] = {
+ "Back",
+ "Forward"
+};
+
+static void
+window_finalize (GObject *object)
+{
+ DhWindowPriv *priv = GET_PRIVATE (object);
+
+ g_object_unref (priv->base);
+
+ G_OBJECT_CLASS (dh_window_parent_class)->finalize (object);
+}
+
+static void
+dh_window_class_init (DhWindowClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->finalize = window_finalize;
+
+ signals[OPEN_LINK] =
+ g_signal_new ("open-link",
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (DhWindowClass, open_link),
+ NULL, NULL,
+ _dh_marshal_VOID__STRING_FLAGS,
+ G_TYPE_NONE,
+ 2,
+ G_TYPE_STRING,
+ DH_TYPE_OPEN_LINK_FLAGS);
+
+ gtk_rc_parse_string ("style \"devhelp-tab-close-button-style\"\n"
+ "{\n"
+ "GtkWidget::focus-padding = 0\n"
+ "GtkWidget::focus-line-width = 0\n"
+ "xthickness = 0\n"
+ "ythickness = 0\n"
+ "}\n"
+ "widget \"*.devhelp-tab-close-button\" "
+ "style \"devhelp-tab-close-button-style\"");
+
+ g_type_class_add_private (klass, sizeof (DhWindowPriv));
+}
+
+static void
+dh_window_init (DhWindow *window)
+{
+ DhWindowPriv *priv;
+ GtkAction *action;
+ GtkAccelGroup *accel_group;
+ GClosure *closure;
+ guint i;
+
+ priv = GET_PRIVATE (window);
+ window->priv = priv;
+
+ priv->selected_search_link = NULL;
+
+ priv->manager = gtk_ui_manager_new ();
+
+ accel_group = gtk_ui_manager_get_accel_group (priv->manager);
+ gtk_window_add_accel_group (GTK_WINDOW (window), accel_group);
+
+ priv->main_box = gtk_vbox_new (FALSE, 0);
+ gtk_widget_show (priv->main_box);
+
+ priv->menu_box = gtk_vbox_new (FALSE, 0);
+ gtk_widget_show (priv->menu_box);
+ gtk_container_set_border_width (GTK_CONTAINER (priv->menu_box), 0);
+ gtk_box_pack_start (GTK_BOX (priv->main_box), priv->menu_box,
+ FALSE, TRUE, 0);
+
+ gtk_container_add (GTK_CONTAINER (window), priv->main_box);
+
+ g_signal_connect (window,
+ "open-link",
+ G_CALLBACK (window_open_link_cb),
+ window);
+
+ priv->action_group = gtk_action_group_new ("MainWindow");
+
+ gtk_action_group_set_translation_domain (priv->action_group,
+ GETTEXT_PACKAGE);
+
+ gtk_action_group_add_actions (priv->action_group,
+ actions,
+ G_N_ELEMENTS (actions),
+ window);
+ gtk_action_group_add_toggle_actions (priv->action_group,
+ always_sensitive_toggle_menu_entries,
+ G_N_ELEMENTS (always_sensitive_toggle_menu_entries),
+ window);
+
+ for (i = 0; i < G_N_ELEMENTS (important_actions); i++) {
+ action = gtk_action_group_get_action (priv->action_group,
+ important_actions[i]);
+ g_object_set (action, "is-important", TRUE, NULL);
+ }
+
+ gtk_ui_manager_insert_action_group (priv->manager,
+ priv->action_group,
+ 0);
+
+ action = gtk_action_group_get_action (priv->action_group,
+ "Back");
+ g_object_set (action, "sensitive", FALSE, NULL);
+
+ action = gtk_action_group_get_action (priv->action_group,
+ "Forward");
+ g_object_set (action, "sensitive", FALSE, NULL);
+
+ action = gtk_action_group_get_action (priv->action_group, "ZoomIn");
+ /* Translators: This refers to text size */
+ g_object_set (action, "short_label", _("Larger"), NULL);
+ action = gtk_action_group_get_action (priv->action_group, "ZoomOut");
+ /* Translators: This refers to text size */
+ g_object_set (action, "short_label", _("Smaller"), NULL);
+
+ accel_group = gtk_accel_group_new ();
+ gtk_window_add_accel_group (GTK_WINDOW (window), accel_group);
+
+ for (i = 0; i < G_N_ELEMENTS (tab_accel_keys); i++) {
+ closure = g_cclosure_new (G_CALLBACK (window_web_view_tab_accel_cb),
+ window,
+ NULL);
+ gtk_accel_group_connect (accel_group,
+ tab_accel_keys[i],
+ GDK_MOD1_MASK,
+ 0,
+ closure);
+ }
+}
+
+/* The ugliest hack. When switching tabs, the selection and cursor is changed
+ * for the tree view so the web_view content is changed. Block the signal during
+ * switch.
+ */
+static void
+window_control_switch_page_cb (GtkWidget *notebook,
+ gpointer page,
+ guint page_num,
+ DhWindow *window)
+{
+ DhWindowPriv *priv;
+
+ priv = window->priv;
+
+ g_signal_handlers_block_by_func (priv->book_tree,
+ window_tree_link_selected_cb,
+ window);
+}
+
+static void
+window_control_after_switch_page_cb (GtkWidget *notebook,
+ gpointer page,
+ guint page_num,
+ DhWindow *window)
+{
+ DhWindowPriv *priv;
+
+ priv = window->priv;
+
+ g_signal_handlers_unblock_by_func (priv->book_tree,
+ window_tree_link_selected_cb,
+ window);
+}
+
+static void
+window_web_view_switch_page_cb (GtkNotebook *notebook,
+ gpointer page,
+ guint new_page_num,
+ DhWindow *window)
+{
+ DhWindowPriv *priv;
+ GtkWidget *new_page;
+
+ priv = window->priv;
+
+ new_page = gtk_notebook_get_nth_page (notebook, new_page_num);
+ if (new_page) {
+ WebKitWebView *new_web_view;
+ WebKitWebFrame *web_frame;
+ const gchar *location;
+
+ new_web_view = g_object_get_data (G_OBJECT (new_page), "web_view");
+
+ /* Sync the book tree. */
+ web_frame = webkit_web_view_get_main_frame (new_web_view);
+ location = webkit_web_frame_get_uri (web_frame);
+
+ if (location) {
+ dh_book_tree_select_uri (DH_BOOK_TREE (priv->book_tree),
+ location);
+ }
+ window_check_history (window, new_web_view);
+
+ window_update_title (window, new_web_view, NULL);
+ } else {
+ /* i18n: Please don't translate "Devhelp" (it's marked as translatable
+ * for transliteration only) */
+ gtk_window_set_title (GTK_WINDOW (window), _("Devhelp"));
+ window_check_history (window, NULL);
+ }
+}
+
+static void
+window_web_view_switch_page_after_cb (GtkNotebook *notebook,
+ gpointer page,
+ guint new_page_num,
+ DhWindow *window)
+{
+ window_update_zoom_actions_sensitiveness (window);
+}
+
+static void
+window_populate (DhWindow *window)
+{
+ DhWindowPriv *priv;
+ gchar *path;
+ GtkWidget *book_tree_sw;
+ DhBookManager *book_manager;
+ GtkWidget *menubar;
+ GtkWidget *toolbar;
+
+ priv = window->priv;
+
+ path = dh_util_build_data_filename ("devhelp", "ui", "window.ui", NULL);
+ gtk_ui_manager_add_ui_from_file (priv->manager,
+ path,
+ NULL);
+ g_free (path);
+ gtk_ui_manager_ensure_update (priv->manager);
+
+ menubar = gtk_ui_manager_get_widget (priv->manager, "/MenuBar");
+ gtk_box_pack_start (GTK_BOX (priv->menu_box), menubar,
+ FALSE, FALSE, 0);
+ toolbar = gtk_ui_manager_get_widget (priv->manager, "/Toolbar");
+ gtk_box_pack_start (GTK_BOX (priv->menu_box), toolbar,
+ FALSE, FALSE, 0);
+
+#ifdef GDK_WINDOWING_QUARTZ
+ {
+ GtkWidget *widget;
+ IgeMacMenuGroup *group;
+
+ /* Hide toolbar labels. */
+ gtk_toolbar_set_style (GTK_TOOLBAR (toolbar), GTK_TOOLBAR_ICONS);
+
+ /* Setup menubar. */
+ ige_mac_menu_set_menu_bar (GTK_MENU_SHELL (menubar));
+ gtk_widget_hide (menubar);
+
+ widget = gtk_ui_manager_get_widget (priv->manager, "/MenuBar/FileMenu/Quit");
+ ige_mac_menu_set_quit_menu_item (GTK_MENU_ITEM (widget));
+
+ group = ige_mac_menu_add_app_menu_group ();
+ widget = gtk_ui_manager_get_widget (priv->manager, "/MenuBar/HelpMenu/About");
+ ige_mac_menu_add_app_menu_item (group, GTK_MENU_ITEM (widget),
+ /* i18n: please don't translate
+ * "Devhelp", it's a name, not a
+ * generic word. */
+ _("About Devhelp"));
+
+ group = ige_mac_menu_add_app_menu_group ();
+ widget = gtk_ui_manager_get_widget (priv->manager, "/MenuBar/EditMenu/Preferences");
+ ige_mac_menu_add_app_menu_item (group, GTK_MENU_ITEM (widget),
+ _("Preferences…"));
+
+ ige_mac_menu_set_global_key_handler_enabled (TRUE);
+ }
+#endif
+
+ priv->hpaned = gtk_hpaned_new ();
+
+ gtk_box_pack_start (GTK_BOX (priv->main_box), priv->hpaned, TRUE, TRUE, 0);
+
+ /* Search and contents notebook. */
+ priv->control_notebook = gtk_notebook_new ();
+
+ gtk_paned_add1 (GTK_PANED (priv->hpaned), priv->control_notebook);
+
+ g_signal_connect (priv->control_notebook,
+ "switch-page",
+ G_CALLBACK (window_control_switch_page_cb),
+ window);
+
+ g_signal_connect_after (priv->control_notebook,
+ "switch-page",
+ G_CALLBACK (window_control_after_switch_page_cb),
+ window);
+
+ book_tree_sw = gtk_scrolled_window_new (NULL, NULL);
+
+ gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (book_tree_sw),
+ GTK_POLICY_NEVER,
+ GTK_POLICY_AUTOMATIC);
+ gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (book_tree_sw),
+ GTK_SHADOW_IN);
+ gtk_container_set_border_width (GTK_CONTAINER (book_tree_sw), 2);
+
+ book_manager = dh_base_get_book_manager (priv->base);
+
+ priv->book_tree = dh_book_tree_new (book_manager);
+ gtk_container_add (GTK_CONTAINER (book_tree_sw),
+ priv->book_tree);
+ dh_util_state_set_notebook_page_name (book_tree_sw, "content");
+ gtk_notebook_append_page (GTK_NOTEBOOK (priv->control_notebook),
+ book_tree_sw,
+ gtk_label_new (_("Contents")));
+ g_signal_connect (priv->book_tree,
+ "link-selected",
+ G_CALLBACK (window_tree_link_selected_cb),
+ window);
+
+ priv->search = dh_search_new (book_manager);
+ dh_util_state_set_notebook_page_name (priv->search, "search");
+ gtk_notebook_append_page (GTK_NOTEBOOK (priv->control_notebook),
+ priv->search,
+ gtk_label_new (_("Search")));
+ g_signal_connect (priv->search,
+ "link-selected",
+ G_CALLBACK (window_search_link_selected_cb),
+ window);
+
+ priv->vbox = gtk_vbox_new (FALSE, 0);
+ gtk_paned_add2 (GTK_PANED (priv->hpaned), priv->vbox);
+
+ /* HTML tabs notebook. */
+ priv->notebook = gtk_notebook_new ();
+ gtk_container_set_border_width (GTK_CONTAINER (priv->notebook), 0);
+ gtk_notebook_set_show_border (GTK_NOTEBOOK (priv->notebook), FALSE);
+ gtk_notebook_set_scrollable (GTK_NOTEBOOK (priv->notebook), TRUE);
+ gtk_box_pack_start (GTK_BOX (priv->vbox), priv->notebook, TRUE, TRUE, 0);
+
+ g_signal_connect (priv->notebook,
+ "switch-page",
+ G_CALLBACK (window_web_view_switch_page_cb),
+ window);
+ g_signal_connect_after (priv->notebook,
+ "switch-page",
+ G_CALLBACK (window_web_view_switch_page_after_cb),
+ window);
+
+
+ /* Create findbar. */
+ priv->findbar = egg_find_bar_new ();
+ gtk_widget_set_no_show_all (priv->findbar, TRUE);
+ gtk_box_pack_start (GTK_BOX (priv->vbox), priv->findbar, FALSE, FALSE, 0);
+
+ g_signal_connect (priv->findbar,
+ "notify::search-string",
+ G_CALLBACK(window_find_search_changed_cb),
+ window);
+ g_signal_connect (priv->findbar,
+ "notify::case-sensitive",
+ G_CALLBACK (window_find_case_changed_cb),
+ window);
+ g_signal_connect (priv->findbar,
+ "previous",
+ G_CALLBACK (window_find_previous_cb),
+ window);
+ g_signal_connect (priv->findbar,
+ "next",
+ G_CALLBACK (window_find_next_cb),
+ window);
+ g_signal_connect (priv->findbar,
+ "close",
+ G_CALLBACK (window_findbar_close_cb),
+ window);
+
+ gtk_widget_show_all (priv->hpaned);
+
+ window_update_zoom_actions_sensitiveness (window);
+ window_open_new_tab (window, NULL, TRUE);
+}
+
+
+static gchar *
+find_library_equivalent (DhWindow *window,
+ const gchar *uri)
+{
+ DhWindowPriv *priv;
+ gchar **components;
+ GList *iter;
+ DhLink *link;
+ DhBookManager *book_manager;
+ gchar *book_id;
+ gchar *filename;
+ gchar *local_uri = NULL;
+ GList *books;
+
+ components = g_strsplit (uri, "/", 0);
+ book_id = components[4];
+ filename = components[6];
+
+ priv = window->priv;
+ book_manager = dh_base_get_book_manager (priv->base);
+
+ /* use list pointer to iterate */
+ for (books = dh_book_manager_get_books (book_manager);
+ !local_uri && books;
+ books = g_list_next (books)) {
+ DhBook *book = DH_BOOK (books->data);
+
+ for (iter = dh_book_get_keywords (book);
+ iter;
+ iter = g_list_next (iter)) {
+ link = iter->data;
+ if (g_strcmp0 (dh_link_get_book_id (link), book_id) != 0) {
+ continue;
+ }
+ if (g_strcmp0 (dh_link_get_file_name (link), filename) != 0) {
+ continue;
+ }
+ local_uri = dh_link_get_uri (link);
+ break;
+ }
+ }
+
+ g_strfreev (components);
+
+ return local_uri;
+}
+
+
+static gboolean
+window_web_view_navigation_policy_decision_requested (WebKitWebView *web_view,
+ WebKitWebFrame *frame,
+ WebKitNetworkRequest *request,
+ WebKitWebNavigationAction *navigation_action,
+ WebKitWebPolicyDecision *policy_decision,
+ DhWindow *window)
+{
+ DhWindowPriv *priv;
+ const char *uri;
+
+ priv = window->priv;
+
+ uri = webkit_network_request_get_uri (request);
+
+#ifdef ERRORS_IN_INFOBAR
+ /* make sure to hide the info bar on page change */
+ gtk_widget_hide (window_get_active_info_bar (window));
+#endif
+
+ if (webkit_web_navigation_action_get_button (navigation_action) == 2) { /* middle click */
+ webkit_web_policy_decision_ignore (policy_decision);
+ g_signal_emit (window, signals[OPEN_LINK], 0, uri, DH_OPEN_LINK_NEW_TAB);
+ return TRUE;
+ }
+
+ if (strcmp (uri, "about:blank") == 0) {
+ return FALSE;
+ }
+
+ if (strncmp (uri, "http://library.gnome.org/devel/", 31) == 0) {
+ gchar *local_uri = find_library_equivalent (window, uri);
+ if (local_uri) {
+ webkit_web_policy_decision_ignore (policy_decision);
+ _dh_window_display_uri (window, local_uri);
+ g_free (local_uri);
+ return TRUE;
+ }
+ }
+
+ if (strncmp (uri, "file://", 7) != 0) {
+ webkit_web_policy_decision_ignore (policy_decision);
+ gtk_show_uri (NULL, uri, GDK_CURRENT_TIME, NULL);
+ return TRUE;
+ }
+
+ if (web_view == window_get_active_web_view (window)) {
+ dh_book_tree_select_uri (DH_BOOK_TREE (priv->book_tree), uri);
+ window_check_history (window, web_view);
+ }
+
+ return FALSE;
+}
+
+
+static gboolean
+window_web_view_load_error_cb (WebKitWebView *web_view,
+ WebKitWebFrame *frame,
+ gchar *uri,
+ gpointer *web_error,
+ DhWindow *window)
+{
+#ifdef ERRORS_IN_INFOBAR
+ GtkWidget *info_bar;
+ GtkWidget *content_area;
+ GtkWidget *message_label;
+ GList *children;
+ gchar *markup;
+
+ info_bar = window_get_active_info_bar (window);
+ markup = g_strdup_printf ("<b>%s</b>",
+ _("Error opening the requested link."));
+ message_label = gtk_label_new (markup);
+ gtk_misc_set_alignment (GTK_MISC (message_label), 0, 0.5);
+ gtk_label_set_use_markup (GTK_LABEL (message_label), TRUE);
+ content_area = gtk_info_bar_get_content_area (GTK_INFO_BAR (info_bar));
+ children = gtk_container_get_children (GTK_CONTAINER (content_area));
+ if (children) {
+ gtk_container_remove (GTK_CONTAINER (content_area), children->data);
+ g_list_free (children);
+ }
+ gtk_container_add (GTK_CONTAINER (content_area), message_label);
+ gtk_widget_show (message_label);
+
+ gtk_widget_show (info_bar);
+ g_free (markup);
+
+ return TRUE;
+#else
+ return FALSE;
+#endif
+}
+
+static void
+window_tree_link_selected_cb (GObject *ignored,
+ DhLink *link,
+ DhWindow *window)
+{
+ WebKitWebView *view;
+ gchar *uri;
+
+ view = window_get_active_web_view (window);
+
+ uri = dh_link_get_uri (link);
+ webkit_web_view_load_uri (view, uri);
+ g_free (uri);
+
+ window_check_history (window, view);
+}
+
+static void
+window_search_link_selected_cb (GObject *ignored,
+ DhLink *link,
+ DhWindow *window)
+{
+ DhWindowPriv *priv;
+ WebKitWebView *view;
+ gchar *uri;
+
+ priv = window->priv;
+
+ priv->selected_search_link = link;
+
+ view = window_get_active_web_view (window);
+
+ uri = dh_link_get_uri (link);
+ webkit_web_view_load_uri (view, uri);
+ g_free (uri);
+
+ window_check_history (window, view);
+}
+
+static void
+window_check_history (DhWindow *window,
+ WebKitWebView *web_view)
+{
+ DhWindowPriv *priv;
+ GtkAction *action;
+
+ priv = window->priv;
+
+ action = gtk_action_group_get_action (priv->action_group, "Forward");
+ g_object_set (action,
+ "sensitive", web_view ? webkit_web_view_can_go_forward (web_view) : FALSE,
+ NULL);
+
+ action = gtk_action_group_get_action (priv->action_group, "Back");
+ g_object_set (action,
+ "sensitive", web_view ? webkit_web_view_can_go_back (web_view) : FALSE,
+ NULL);
+}
+
+static void
+window_web_view_title_changed_cb (WebKitWebView *web_view,
+ WebKitWebFrame *web_frame,
+ const gchar *title,
+ DhWindow *window)
+{
+ if (web_view == window_get_active_web_view (window)) {
+ window_update_title (window, web_view, title);
+ }
+
+ window_tab_set_title (window, web_view, title);
+}
+
+static gboolean
+window_web_view_button_press_event_cb (WebKitWebView *web_view,
+ GdkEventButton *event,
+ DhWindow *window)
+{
+ if (event->button == 3) {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static gboolean
+do_search (DhWindow *window)
+{
+ DhWindowPriv *priv = window->priv;
+ WebKitWebView *web_view;
+
+ priv->find_source_id = 0;
+
+ web_view = window_get_active_web_view (window);
+
+ webkit_web_view_unmark_text_matches (web_view);
+ webkit_web_view_mark_text_matches (
+ web_view,
+ egg_find_bar_get_search_string (EGG_FIND_BAR (priv->findbar)),
+ egg_find_bar_get_case_sensitive (EGG_FIND_BAR (priv->findbar)), 0);
+ webkit_web_view_set_highlight_text_matches (web_view, TRUE);
+
+ webkit_web_view_search_text (
+ web_view, egg_find_bar_get_search_string (EGG_FIND_BAR (priv->findbar)),
+ egg_find_bar_get_case_sensitive (EGG_FIND_BAR (priv->findbar)),
+ TRUE, TRUE);
+
+ return FALSE;
+}
+
+static void
+window_find_search_changed_cb (GObject *object,
+ GParamSpec *pspec,
+ DhWindow *window)
+{
+ DhWindowPriv *priv = window->priv;
+
+ if (priv->find_source_id != 0) {
+ g_source_remove (priv->find_source_id);
+ priv->find_source_id = 0;
+ }
+
+ priv->find_source_id = g_timeout_add (300, (GSourceFunc)do_search, window);
+}
+
+static void
+window_find_case_changed_cb (GObject *object,
+ GParamSpec *pspec,
+ DhWindow *window)
+{
+ DhWindowPriv *priv = window->priv;;
+ WebKitWebView *view;
+ const gchar *string;
+ gboolean case_sensitive;
+
+ view = window_get_active_web_view (window);
+
+ string = egg_find_bar_get_search_string (EGG_FIND_BAR (priv->findbar));
+ case_sensitive = egg_find_bar_get_case_sensitive (EGG_FIND_BAR (priv->findbar));
+
+ webkit_web_view_unmark_text_matches (view);
+ webkit_web_view_mark_text_matches (view, string, case_sensitive, 0);
+ webkit_web_view_set_highlight_text_matches (view, TRUE);
+}
+
+static void
+window_find_next_cb (GtkEntry *entry,
+ DhWindow *window)
+{
+ DhWindowPriv *priv = window->priv;
+ WebKitWebView *view;
+ const gchar *string;
+ gboolean case_sensitive;
+
+ view = window_get_active_web_view (window);
+
+ gtk_widget_show (priv->findbar);
+
+ string = egg_find_bar_get_search_string (EGG_FIND_BAR (priv->findbar));
+ case_sensitive = egg_find_bar_get_case_sensitive (EGG_FIND_BAR (priv->findbar));
+
+ webkit_web_view_search_text (view, string, case_sensitive, TRUE, TRUE);
+}
+
+static void
+window_find_previous_cb (GtkEntry *entry,
+ DhWindow *window)
+{
+ DhWindowPriv *priv = window->priv;
+ WebKitWebView *view;
+ const gchar *string;
+ gboolean case_sensitive;
+
+ view = window_get_active_web_view (window);
+
+ gtk_widget_show (priv->findbar);
+
+ string = egg_find_bar_get_search_string (EGG_FIND_BAR (priv->findbar));
+ case_sensitive = egg_find_bar_get_case_sensitive (EGG_FIND_BAR (priv->findbar));
+
+ webkit_web_view_search_text (view, string, case_sensitive, FALSE, TRUE);
+}
+
+static void
+window_findbar_close_cb (GtkWidget *widget,
+ DhWindow *window)
+{
+ DhWindowPriv *priv = window->priv;
+ WebKitWebView *view;
+
+ view = window_get_active_web_view (window);
+
+ gtk_widget_hide (priv->findbar);
+
+ webkit_web_view_set_highlight_text_matches (view, FALSE);
+}
+
+#if 0
+static void
+window_web_view_open_new_tab_cb (WebKitWebView *web_view,
+ const gchar *location,
+ DhWindow *window)
+{
+ window_open_new_tab (window, location);
+}
+#endif
+
+static void
+window_web_view_tab_accel_cb (GtkAccelGroup *accel_group,
+ GObject *object,
+ guint key,
+ GdkModifierType mod,
+ DhWindow *window)
+{
+ DhWindowPriv *priv;
+ gint i, num;
+
+ priv = window->priv;
+
+ num = -1;
+ for (i = 0; i < (gint) G_N_ELEMENTS (tab_accel_keys); i++) {
+ if (tab_accel_keys[i] == key) {
+ num = i;
+ break;
+ }
+ }
+
+ if (num != -1) {
+ gtk_notebook_set_current_page (
+ GTK_NOTEBOOK (priv->notebook), num);
+ }
+}
+
+static int
+window_open_new_tab (DhWindow *window,
+ const gchar *location,
+ gboolean switch_focus)
+{
+ DhWindowPriv *priv;
+ GtkWidget *view;
+ GtkWidget *vbox;
+ GtkWidget *scrolled_window;
+ GtkWidget *label;
+ gint num;
+#ifdef ERRORS_IN_INFOBAR
+ GtkWidget *info_bar;
+#endif
+
+ priv = window->priv;
+
+ /* Prepare the web view */
+ view = webkit_web_view_new ();
+ gtk_widget_show (view);
+ dh_util_font_add_web_view (WEBKIT_WEB_VIEW (view));
+
+#ifdef ERRORS_IN_INFOBAR
+ /* Prepare the info bar */
+ info_bar = gtk_info_bar_new ();
+ gtk_widget_set_no_show_all (info_bar, TRUE);
+ gtk_info_bar_add_button (GTK_INFO_BAR (info_bar),
+ GTK_STOCK_CLOSE, GTK_RESPONSE_OK);
+ gtk_info_bar_set_message_type (GTK_INFO_BAR (info_bar),
+ GTK_MESSAGE_ERROR);
+ g_signal_connect (info_bar, "response",
+ G_CALLBACK (gtk_widget_hide), NULL);
+#endif
+
+#if 0
+ /* Leave this in for now to make it easier to experiment. */
+ {
+ WebKitWebSettings *settings;
+ settings = webkit_web_view_get_settings (WEBKIT_WEB_VIEW (view));
+
+ g_object_set (settings,
+ "user-stylesheet-uri", "file://" DATADIR "/devhelp/devhelp.css",
+ NULL);
+ }
+#endif
+
+ vbox = gtk_vbox_new (0, FALSE);
+ gtk_widget_show (vbox);
+
+ /* XXX: Really it would be much better to use real structures */
+ g_object_set_data (G_OBJECT (vbox), "web_view", view);
+#ifdef ERRORS_IN_INFOBAR
+ g_object_set_data (G_OBJECT (vbox), "info_bar", info_bar);
+
+ gtk_box_pack_start (GTK_BOX(vbox), info_bar, FALSE, TRUE, 0);
+#endif
+
+ scrolled_window = gtk_scrolled_window_new (NULL, NULL);
+ gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window),
+ GTK_POLICY_AUTOMATIC,
+ GTK_POLICY_AUTOMATIC);
+ gtk_container_add (GTK_CONTAINER (scrolled_window), view);
+ gtk_widget_show (scrolled_window);
+ gtk_box_pack_start (GTK_BOX(vbox), scrolled_window, TRUE, TRUE, 0);
+
+ label = window_new_tab_label (window, _("Empty Page"), vbox);
+ gtk_widget_show_all (label);
+
+ g_signal_connect (view, "title-changed",
+ G_CALLBACK (window_web_view_title_changed_cb),
+ window);
+ g_signal_connect (view, "button-press-event",
+ G_CALLBACK (window_web_view_button_press_event_cb),
+ window);
+ g_signal_connect (view, "navigation-policy-decision-requested",
+ G_CALLBACK (window_web_view_navigation_policy_decision_requested),
+ window);
+ g_signal_connect (view, "load-error",
+ G_CALLBACK (window_web_view_load_error_cb),
+ window);
+
+ num = gtk_notebook_append_page (GTK_NOTEBOOK (priv->notebook),
+ vbox, NULL);
+
+ gtk_notebook_set_tab_label (GTK_NOTEBOOK (priv->notebook),
+ vbox, label);
+
+ if (gtk_notebook_get_n_pages (GTK_NOTEBOOK (priv->notebook)) > 1) {
+ gtk_notebook_set_show_tabs (GTK_NOTEBOOK (priv->notebook), TRUE);
+ } else {
+ gtk_notebook_set_show_tabs (GTK_NOTEBOOK (priv->notebook), FALSE);
+ }
+
+ if (location) {
+ webkit_web_view_load_uri (WEBKIT_WEB_VIEW (view), location);
+ } else {
+ webkit_web_view_load_uri (WEBKIT_WEB_VIEW (view), "about:blank");
+ }
+
+ if (switch_focus) {
+ gtk_notebook_set_current_page (GTK_NOTEBOOK (priv->notebook), num);
+ }
+
+ return num;
+}
+
+#ifndef GDK_WINDOWING_QUARTZ
+static void
+close_button_clicked_cb (GtkButton *button,
+ DhWindow *window)
+{
+ GtkWidget *parent_tab;
+ gint pages;
+ gint i;
+
+ parent_tab = g_object_get_data (G_OBJECT (button), "parent_tab");
+ pages = gtk_notebook_get_n_pages (GTK_NOTEBOOK (window->priv->notebook));
+ for (i=0; i<pages; i++) {
+ if (gtk_notebook_get_nth_page (GTK_NOTEBOOK (window->priv->notebook), i) == parent_tab) {
+ window_close_tab (window, i);
+ break;
+ }
+ }
+}
+
+static void
+tab_label_style_set_cb (GtkWidget *hbox,
+ GtkStyle *previous_style,
+ gpointer user_data)
+{
+ PangoFontMetrics *metrics;
+ PangoContext *context;
+ GtkWidget *button;
+ GtkStyle *style;
+ gint char_width;
+ gint h, w;
+
+ context = gtk_widget_get_pango_context (hbox);
+ style = gtk_widget_get_style (hbox);
+ metrics = pango_context_get_metrics (context,
+ style->font_desc,
+ pango_context_get_language (context));
+
+ char_width = pango_font_metrics_get_approximate_digit_width (metrics);
+ pango_font_metrics_unref (metrics);
+
+ gtk_icon_size_lookup_for_settings (gtk_widget_get_settings (hbox),
+ GTK_ICON_SIZE_MENU, &w, &h);
+
+ gtk_widget_set_size_request (hbox, 15 * PANGO_PIXELS (char_width) + 2 * w, -1);
+
+ button = g_object_get_data (G_OBJECT (hbox), "close-button");
+ gtk_widget_set_size_request (button, w + 2, h + 2);
+}
+#endif
+
+/* Don't create a close button on quartz, it looks very much out of
+ * place.
+ */
+static GtkWidget*
+window_new_tab_label (DhWindow *window,
+ const gchar *str,
+ const GtkWidget *parent)
+{
+ GtkWidget *label;
+#ifndef GDK_WINDOWING_QUARTZ
+ GtkWidget *hbox;
+ GtkWidget *close_button;
+ GtkWidget *image;
+
+ hbox = gtk_hbox_new (FALSE, 4);
+
+ label = gtk_label_new (str);
+ gtk_label_set_ellipsize (GTK_LABEL (label), PANGO_ELLIPSIZE_END);
+ gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
+ gtk_box_pack_start (GTK_BOX (hbox), label, TRUE, TRUE, 0);
+
+ close_button = gtk_button_new ();
+ gtk_button_set_relief (GTK_BUTTON (close_button), GTK_RELIEF_NONE);
+ gtk_button_set_focus_on_click (GTK_BUTTON (close_button), FALSE);
+ gtk_widget_set_name (close_button, "devhelp-tab-close-button");
+ g_object_set_data (G_OBJECT (close_button), "parent_tab", (gpointer) parent);
+
+ image = gtk_image_new_from_stock (GTK_STOCK_CLOSE, GTK_ICON_SIZE_MENU);
+ g_signal_connect (close_button, "clicked",
+ G_CALLBACK (close_button_clicked_cb),
+ window);
+ gtk_container_add (GTK_CONTAINER (close_button), image);
+
+ gtk_box_pack_start (GTK_BOX (hbox), close_button, FALSE, FALSE, 0);
+
+ /* Set minimal size */
+ g_signal_connect (hbox, "style-set",
+ G_CALLBACK (tab_label_style_set_cb),
+ NULL);
+
+ g_object_set_data (G_OBJECT (hbox), "label", label);
+ g_object_set_data (G_OBJECT (hbox), "close-button", close_button);
+
+ return hbox;
+#else
+ label = gtk_label_new (str);
+ g_object_set_data (G_OBJECT (label), "label", label);
+
+ return label;
+#endif
+}
+
+static WebKitWebView *
+window_get_active_web_view (DhWindow *window)
+{
+ DhWindowPriv *priv;
+ gint page_num;
+ GtkWidget *page;
+
+ priv = window->priv;
+
+ page_num = gtk_notebook_get_current_page (GTK_NOTEBOOK (priv->notebook));
+ if (page_num == -1) {
+ return NULL;
+ }
+
+ page = gtk_notebook_get_nth_page (GTK_NOTEBOOK (priv->notebook), page_num);
+
+ return g_object_get_data (G_OBJECT (page), "web_view");
+}
+
+#ifdef ERRORS_IN_INFOBAR
+static GtkWidget *
+window_get_active_info_bar (DhWindow *window)
+{
+ DhWindowPriv *priv;
+ gint page_num;
+ GtkWidget *page;
+
+ priv = window->priv;
+
+ page_num = gtk_notebook_get_current_page (GTK_NOTEBOOK (priv->notebook));
+ if (page_num == -1) {
+ return NULL;
+ }
+
+ page = gtk_notebook_get_nth_page (GTK_NOTEBOOK (priv->notebook), page_num);
+
+ return g_object_get_data (G_OBJECT (page), "info_bar");
+}
+#endif
+
+static void
+window_update_title (DhWindow *window,
+ WebKitWebView *web_view,
+ const gchar *web_view_title)
+{
+ DhWindowPriv *priv;
+ const gchar *book_title;
+
+ priv = window->priv;
+
+ if (!web_view_title) {
+ WebKitWebFrame *web_frame;
+
+ web_frame = webkit_web_view_get_main_frame (web_view);
+ web_view_title = webkit_web_frame_get_title (web_frame);
+ }
+
+ if (web_view_title && *web_view_title == '\0') {
+ web_view_title = NULL;
+ }
+
+ book_title = dh_book_tree_get_selected_book_title (DH_BOOK_TREE (priv->book_tree));
+
+ /* Don't use both titles if they are the same. */
+ if (book_title && web_view_title && strcmp (book_title, web_view_title) == 0) {
+ web_view_title = NULL;
+ }
+
+ if (!book_title) {
+ /* i18n: Please don't translate "Devhelp" (it's marked as translatable
+ * for transliteration only) */
+ book_title = _("Devhelp");
+ }
+
+ if (web_view_title) {
+ gchar *full_title;
+ full_title = g_strdup_printf ("%s - %s", book_title, web_view_title);
+ gtk_window_set_title (GTK_WINDOW (window), full_title);
+ g_free (full_title);
+ } else {
+ gtk_window_set_title (GTK_WINDOW (window), book_title);
+ }
+}
+
+static void
+window_tab_set_title (DhWindow *window,
+ WebKitWebView *web_view,
+ const gchar *title)
+{
+ DhWindowPriv *priv;
+ gint num_pages, i;
+ GtkWidget *page;
+ GtkWidget *hbox;
+ GtkWidget *label;
+ GtkWidget *page_web_view;
+
+ priv = window->priv;
+
+ if (!title || title[0] == '\0') {
+ title = _("Empty Page");
+ }
+
+ num_pages = gtk_notebook_get_n_pages (GTK_NOTEBOOK (priv->notebook));
+ for (i = 0; i < num_pages; i++) {
+ page = gtk_notebook_get_nth_page (
+ GTK_NOTEBOOK (priv->notebook), i);
+ page_web_view = g_object_get_data (G_OBJECT (page), "web_view");
+
+ /* The web_view widget is inside a frame. */
+ if (page_web_view == GTK_WIDGET (web_view)) {
+ hbox = gtk_notebook_get_tab_label (
+ GTK_NOTEBOOK (priv->notebook), page);
+
+ if (hbox) {
+ label = g_object_get_data (G_OBJECT (hbox), "label");
+ gtk_label_set_text (GTK_LABEL (label), title);
+ }
+ break;
+ }
+ }
+}
+
+GtkWidget *
+dh_window_new (DhBase *base)
+{
+ DhWindow *window;
+ DhWindowPriv *priv;
+
+ window = g_object_new (DH_TYPE_WINDOW, NULL);
+ priv = window->priv;
+
+ priv->base = g_object_ref (base);
+
+ window_populate (window);
+
+ gtk_window_set_icon_name (GTK_WINDOW (window), "devhelp");
+
+ dh_util_state_manage_window (GTK_WINDOW (window), "main/window");
+ dh_util_state_manage_paned (GTK_PANED (priv->hpaned), "main/paned");
+ dh_util_state_manage_notebook (GTK_NOTEBOOK (priv->control_notebook),
+ "main/search_notebook",
+ "content");
+
+ return GTK_WIDGET (window);
+}
+
+void
+dh_window_search (DhWindow *window,
+ const gchar *str,
+ const gchar *book_id)
+{
+ DhWindowPriv *priv;
+
+ g_return_if_fail (DH_IS_WINDOW (window));
+
+ priv = window->priv;
+
+ gtk_notebook_set_current_page (GTK_NOTEBOOK (priv->control_notebook), 1);
+ dh_search_set_search_string (DH_SEARCH (priv->search), str, book_id);
+}
+
+void
+dh_window_focus_search (DhWindow *window)
+{
+ DhWindowPriv *priv;
+
+ g_return_if_fail (DH_IS_WINDOW (window));
+
+ priv = window->priv;
+
+ gtk_notebook_set_current_page (GTK_NOTEBOOK (priv->control_notebook), 1);
+ gtk_widget_grab_focus (priv->search);
+}
+
+/* Only call this with a URI that is known to be in the docs. */
+void
+_dh_window_display_uri (DhWindow *window,
+ const gchar *uri)
+{
+ DhWindowPriv *priv;
+ WebKitWebView *web_view;
+
+ g_return_if_fail (DH_IS_WINDOW (window));
+ g_return_if_fail (uri != NULL);
+
+ priv = window->priv;
+
+ web_view = window_get_active_web_view (window);
+ webkit_web_view_load_uri (web_view, uri);
+ dh_book_tree_select_uri (DH_BOOK_TREE (priv->book_tree), uri);
+}
Modified: devhelp/devhelp/dh-window.h
73 files changed, 73 insertions(+), 0 deletions(-)
===================================================================
@@ -0,0 +1,73 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2002 CodeFactory AB
+ * Copyright (C) 2001-2002 Mikael Hallendal <micke at imendio.com>
+ * Copyright (C) 2005 Imendio AB
+ *
+ * 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.
+ */
+
+#ifndef __DH_WINDOW_H__
+#define __DH_WINDOW_H__
+
+#include <gtk/gtk.h>
+#include "dh-base.h"
+
+G_BEGIN_DECLS
+
+#define DH_TYPE_WINDOW (dh_window_get_type ())
+#define DH_WINDOW(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), DH_TYPE_WINDOW, DhWindow))
+#define DH_WINDOW_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), DH_TYPE_WINDOW, DhWindowClass))
+#define DH_IS_WINDOW(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), DH_TYPE_WINDOW))
+#define DH_IS_WINDOW_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), DH_TYPE_WINDOW))
+#define DH_WINDOW_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), DH_TYPE_WINDOW, DhWindowClass))
+
+typedef struct _DhWindow DhWindow;
+typedef struct _DhWindowClass DhWindowClass;
+typedef struct _DhWindowPriv DhWindowPriv;
+
+typedef enum
+{
+ DH_OPEN_LINK_NEW_WINDOW = 1 << 0,
+ DH_OPEN_LINK_NEW_TAB = 1 << 1
+} DhOpenLinkFlags;
+
+struct _DhWindow {
+ GtkWindow parent_instance;
+ DhWindowPriv *priv;
+};
+
+struct _DhWindowClass {
+ GtkWindowClass parent_class;
+
+ /* Signals */
+ void (*open_link) (DhWindow *window,
+ const char *location,
+ DhOpenLinkFlags flags);
+};
+
+GType dh_window_get_type (void) G_GNUC_CONST;
+GtkWidget *dh_window_new (DhBase *base);
+void dh_window_search (DhWindow *window,
+ const gchar *str,
+ const gchar *book_id);
+void dh_window_focus_search (DhWindow *window);
+void _dh_window_display_uri (DhWindow *window,
+ const gchar *uri);
+
+G_END_DECLS
+
+#endif /* __DH_WINDOW_H__ */
Modified: devhelp/devhelp/eggfindbar.c
755 files changed, 755 insertions(+), 0 deletions(-)
===================================================================
@@ -0,0 +1,755 @@
+/* Copyright (C) 2004 Red Hat, Inc.
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public License as
+published by the Free Software Foundation; either version 2 of the
+License, or (at your option) any later version.
+
+This library 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
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with the Gnome Library; see the file COPYING.LIB. If not,
+write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.
+*/
+
+#include "config.h"
+
+#include <string.h>
+
+#include <glib/gi18n-lib.h>
+#include <gtk/gtk.h>
+#include <gdk/gdkkeysyms.h>
+
+#include "eggfindbar.h"
+
+struct _EggFindBarPrivate
+{
+ gchar *search_string;
+
+ GtkToolItem *next_button;
+ GtkToolItem *previous_button;
+ GtkToolItem *status_separator;
+ GtkToolItem *status_item;
+ GtkToolItem *case_button;
+
+ GtkWidget *find_entry;
+ GtkWidget *status_label;
+
+ gulong set_focus_handler;
+ guint case_sensitive : 1;
+};
+
+#define EGG_FIND_BAR_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), EGG_TYPE_FIND_BAR, EggFindBarPrivate))
+
+enum {
+ PROP_0,
+ PROP_SEARCH_STRING,
+ PROP_CASE_SENSITIVE
+};
+
+static void egg_find_bar_finalize (GObject *object);
+static void egg_find_bar_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec);
+static void egg_find_bar_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec);
+static void egg_find_bar_show (GtkWidget *widget);
+static void egg_find_bar_hide (GtkWidget *widget);
+static void egg_find_bar_grab_focus (GtkWidget *widget);
+
+G_DEFINE_TYPE (EggFindBar, egg_find_bar, GTK_TYPE_TOOLBAR);
+
+enum
+ {
+ NEXT,
+ PREVIOUS,
+ CLOSE,
+ SCROLL,
+ LAST_SIGNAL
+ };
+
+static guint find_bar_signals[LAST_SIGNAL] = { 0 };
+
+static void
+egg_find_bar_class_init (EggFindBarClass *klass)
+{
+ GObjectClass *object_class;
+ GtkWidgetClass *widget_class;
+ GtkBindingSet *binding_set;
+
+ egg_find_bar_parent_class = g_type_class_peek_parent (klass);
+
+ object_class = (GObjectClass *)klass;
+ widget_class = (GtkWidgetClass *)klass;
+
+ object_class->set_property = egg_find_bar_set_property;
+ object_class->get_property = egg_find_bar_get_property;
+
+ object_class->finalize = egg_find_bar_finalize;
+
+ widget_class->show = egg_find_bar_show;
+ widget_class->hide = egg_find_bar_hide;
+
+ widget_class->grab_focus = egg_find_bar_grab_focus;
+
+ find_bar_signals[NEXT] =
+ g_signal_new ("next",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET (EggFindBarClass, next),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+ find_bar_signals[PREVIOUS] =
+ g_signal_new ("previous",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET (EggFindBarClass, previous),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+ find_bar_signals[CLOSE] =
+ g_signal_new ("close",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
+ G_STRUCT_OFFSET (EggFindBarClass, close),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+ find_bar_signals[SCROLL] =
+ g_signal_new ("scroll",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
+ G_STRUCT_OFFSET (EggFindBarClass, scroll),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__ENUM,
+ G_TYPE_NONE, 1,
+ GTK_TYPE_SCROLL_TYPE);
+
+ /**
+ * EggFindBar:search_string:
+ *
+ * The current string to search for. NULL or empty string
+ * both mean no current string.
+ *
+ */
+ g_object_class_install_property (object_class,
+ PROP_SEARCH_STRING,
+ g_param_spec_string ("search_string",
+ ("Search string"),
+ ("The name of the string to be found"),
+ NULL,
+ G_PARAM_READWRITE));
+
+ /**
+ * EggFindBar:case_sensitive:
+ *
+ * TRUE for a case sensitive search.
+ *
+ */
+ g_object_class_install_property (object_class,
+ PROP_CASE_SENSITIVE,
+ g_param_spec_boolean ("case_sensitive",
+ ("Case sensitive"),
+ ("TRUE for a case sensitive search"),
+ FALSE,
+ G_PARAM_READWRITE));
+
+ /* Style properties */
+ gtk_widget_class_install_style_property (widget_class,
+ g_param_spec_boxed ("all_matches_color",
+ ("Highlight color"),
+ ("Color of highlight for all matches"),
+ GDK_TYPE_COLOR,
+ G_PARAM_READABLE));
+
+ gtk_widget_class_install_style_property (widget_class,
+ g_param_spec_boxed ("current_match_color",
+ ("Current color"),
+ ("Color of highlight for the current match"),
+ GDK_TYPE_COLOR,
+ G_PARAM_READABLE));
+
+ g_type_class_add_private (object_class, sizeof (EggFindBarPrivate));
+
+ binding_set = gtk_binding_set_by_class (klass);
+
+ gtk_binding_entry_add_signal (binding_set, GDK_Escape, 0,
+ "close", 0);
+
+ gtk_binding_entry_add_signal (binding_set, GDK_Up, 0,
+ "scroll", 1,
+ GTK_TYPE_SCROLL_TYPE, GTK_SCROLL_STEP_BACKWARD);
+ gtk_binding_entry_add_signal (binding_set, GDK_Down, 0,
+ "scroll", 1,
+ GTK_TYPE_SCROLL_TYPE, GTK_SCROLL_STEP_FORWARD);
+ gtk_binding_entry_add_signal (binding_set, GDK_Page_Up, 0,
+ "scroll", 1,
+ GTK_TYPE_SCROLL_TYPE, GTK_SCROLL_PAGE_BACKWARD);
+ gtk_binding_entry_add_signal (binding_set, GDK_KP_Page_Up, 0,
+ "scroll", 1,
+ GTK_TYPE_SCROLL_TYPE, GTK_SCROLL_PAGE_BACKWARD);
+ gtk_binding_entry_add_signal (binding_set, GDK_Page_Down, 0,
+ "scroll", 1,
+ GTK_TYPE_SCROLL_TYPE, GTK_SCROLL_PAGE_FORWARD);
+ gtk_binding_entry_add_signal (binding_set, GDK_KP_Page_Down, 0,
+ "scroll", 1,
+ GTK_TYPE_SCROLL_TYPE, GTK_SCROLL_PAGE_FORWARD);
+}
+
+static void
+egg_find_bar_emit_next (EggFindBar *find_bar)
+{
+ g_signal_emit (find_bar, find_bar_signals[NEXT], 0);
+}
+
+static void
+egg_find_bar_emit_previous (EggFindBar *find_bar)
+{
+ g_signal_emit (find_bar, find_bar_signals[PREVIOUS], 0);
+}
+
+static void
+next_clicked_callback (GtkButton *button,
+ void *data)
+{
+ EggFindBar *find_bar = EGG_FIND_BAR (data);
+
+ egg_find_bar_emit_next (find_bar);
+}
+
+static void
+previous_clicked_callback (GtkButton *button,
+ void *data)
+{
+ EggFindBar *find_bar = EGG_FIND_BAR (data);
+
+ egg_find_bar_emit_previous (find_bar);
+}
+
+static void
+case_sensitive_toggled_callback (GtkCheckButton *button,
+ void *data)
+{
+ EggFindBar *find_bar = EGG_FIND_BAR (data);
+
+ egg_find_bar_set_case_sensitive (find_bar,
+ gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button)));
+}
+
+static void
+entry_activate_callback (GtkEntry *entry,
+ void *data)
+{
+ EggFindBar *find_bar = EGG_FIND_BAR (data);
+
+ if (find_bar->priv->search_string != NULL)
+ egg_find_bar_emit_next (find_bar);
+}
+
+static void
+entry_changed_callback (GtkEntry *entry,
+ void *data)
+{
+ EggFindBar *find_bar = EGG_FIND_BAR (data);
+ char *text;
+
+ /* paranoid strdup because set_search_string() sets
+ * the entry text
+ */
+ text = g_strdup (gtk_entry_get_text (entry));
+
+ egg_find_bar_set_search_string (find_bar, text);
+
+ g_free (text);
+}
+
+static void
+set_focus_cb (GtkWidget *window,
+ GtkWidget *widget,
+ EggFindBar *bar)
+{
+ GtkWidget *wbar = GTK_WIDGET (bar);
+
+ while (widget != NULL && widget != wbar)
+ {
+ widget = gtk_widget_get_parent (widget);
+ }
+
+ /* if widget == bar, the new focus widget is in the bar, so we
+ * don't deactivate.
+ */
+ if (widget != wbar)
+ {
+ g_signal_emit (bar, find_bar_signals[CLOSE], 0);
+ }
+}
+
+static void
+egg_find_bar_init (EggFindBar *find_bar)
+{
+ EggFindBarPrivate *priv;
+ GtkWidget *label;
+ GtkWidget *alignment;
+ GtkWidget *box;
+ GtkToolItem *item;
+ GtkWidget *arrow;
+
+ /* Data */
+ priv = EGG_FIND_BAR_GET_PRIVATE (find_bar);
+
+ find_bar->priv = priv;
+ priv->search_string = NULL;
+
+ gtk_toolbar_set_style (GTK_TOOLBAR (find_bar), GTK_TOOLBAR_BOTH_HORIZ);
+
+ /* Find: |_____| */
+ item = gtk_tool_item_new ();
+ box = gtk_hbox_new (FALSE, 12);
+
+ alignment = gtk_alignment_new (0.0, 0.5, 1.0, 0.0);
+ gtk_alignment_set_padding (GTK_ALIGNMENT (alignment), 0, 0, 2, 2);
+
+ label = gtk_label_new_with_mnemonic (_("Find:"));
+
+ priv->find_entry = gtk_entry_new ();
+ gtk_entry_set_width_chars (GTK_ENTRY (priv->find_entry), 32);
+ gtk_entry_set_max_length (GTK_ENTRY (priv->find_entry), 512);
+ gtk_label_set_mnemonic_widget (GTK_LABEL (label), priv->find_entry);
+
+ /* Prev */
+ arrow = gtk_arrow_new (GTK_ARROW_LEFT, GTK_SHADOW_NONE);
+ priv->previous_button = gtk_tool_button_new (arrow, Q_("Find Previous"));
+ gtk_tool_item_set_is_important (priv->previous_button, TRUE);
+#if GTK_CHECK_VERSION (2, 11, 5)
+ gtk_widget_set_tooltip_text (GTK_WIDGET (priv->previous_button),
+ _("Find previous occurrence of the search string"));
+#else
+ gtk_tool_item_set_tooltip (priv->previous_button, GTK_TOOLBAR (find_bar)->tooltips,
+ _("Find previous occurrence of the search string"),
+ NULL);
+#endif
+
+ /* Next */
+ arrow = gtk_arrow_new (GTK_ARROW_RIGHT, GTK_SHADOW_NONE);
+ priv->next_button = gtk_tool_button_new (arrow, Q_("Find Next"));
+ gtk_tool_item_set_is_important (priv->next_button, TRUE);
+#if GTK_CHECK_VERSION (2, 11, 5)
+ gtk_widget_set_tooltip_text (GTK_WIDGET (priv->next_button),
+ _("Find next occurrence of the search string"));
+#else
+ gtk_tool_item_set_tooltip (priv->next_button, GTK_TOOLBAR (find_bar)->tooltips,
+ _("Find next occurrence of the search string"),
+ NULL);
+#endif
+
+ /* Separator*/
+ priv->status_separator = gtk_separator_tool_item_new();
+
+ /* Case button */
+ priv->case_button = gtk_toggle_tool_button_new ();
+ g_object_set (G_OBJECT (priv->case_button), "label", _("C_ase Sensitive"), NULL);
+ gtk_tool_item_set_is_important (priv->case_button, TRUE);
+#if GTK_CHECK_VERSION (2, 11, 5)
+ gtk_widget_set_tooltip_text (GTK_WIDGET (priv->case_button),
+ _("Toggle case sensitive search"));
+#else
+ gtk_tool_item_set_tooltip (priv->case_button, GTK_TOOLBAR (find_bar)->tooltips,
+ _("Toggle case sensitive search"),
+ NULL);
+#endif
+ /* Status */
+ priv->status_item = gtk_tool_item_new();
+ gtk_tool_item_set_expand (priv->status_item, TRUE);
+ priv->status_label = gtk_label_new (NULL);
+ gtk_label_set_ellipsize (GTK_LABEL (priv->status_label),
+ PANGO_ELLIPSIZE_END);
+ gtk_misc_set_alignment (GTK_MISC (priv->status_label), 0.0, 0.5);
+
+
+ g_signal_connect (priv->find_entry, "changed",
+ G_CALLBACK (entry_changed_callback),
+ find_bar);
+ g_signal_connect (priv->find_entry, "activate",
+ G_CALLBACK (entry_activate_callback),
+ find_bar);
+ g_signal_connect (priv->next_button, "clicked",
+ G_CALLBACK (next_clicked_callback),
+ find_bar);
+ g_signal_connect (priv->previous_button, "clicked",
+ G_CALLBACK (previous_clicked_callback),
+ find_bar);
+ g_signal_connect (priv->case_button, "toggled",
+ G_CALLBACK (case_sensitive_toggled_callback),
+ find_bar);
+
+ gtk_box_pack_start (GTK_BOX (box), label, FALSE, FALSE, 0);
+ gtk_box_pack_start (GTK_BOX (box), priv->find_entry, TRUE, TRUE, 0);
+ gtk_container_add (GTK_CONTAINER (alignment), box);
+ gtk_container_add (GTK_CONTAINER (item), alignment);
+ gtk_toolbar_insert (GTK_TOOLBAR (find_bar), item, -1);
+ gtk_toolbar_insert (GTK_TOOLBAR (find_bar), priv->previous_button, -1);
+ gtk_toolbar_insert (GTK_TOOLBAR (find_bar), priv->next_button, -1);
+ gtk_toolbar_insert (GTK_TOOLBAR (find_bar), priv->case_button, -1);
+ gtk_toolbar_insert (GTK_TOOLBAR (find_bar), priv->status_separator, -1);
+ gtk_container_add (GTK_CONTAINER (priv->status_item), priv->status_label);
+ gtk_toolbar_insert (GTK_TOOLBAR (find_bar), priv->status_item, -1);
+
+ /* don't show status separator/label until they are set */
+
+ gtk_widget_show_all (GTK_WIDGET (item));
+ gtk_widget_show_all (GTK_WIDGET (priv->next_button));
+ gtk_widget_show_all (GTK_WIDGET (priv->previous_button));
+ gtk_widget_show (priv->status_label);
+}
+
+static void
+egg_find_bar_finalize (GObject *object)
+{
+ EggFindBar *find_bar = EGG_FIND_BAR (object);
+ EggFindBarPrivate *priv = (EggFindBarPrivate *)find_bar->priv;
+
+ g_free (priv->search_string);
+
+ G_OBJECT_CLASS (egg_find_bar_parent_class)->finalize (object);
+}
+
+static void
+egg_find_bar_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ EggFindBar *find_bar = EGG_FIND_BAR (object);
+
+ switch (prop_id)
+ {
+ case PROP_SEARCH_STRING:
+ egg_find_bar_set_search_string (find_bar, g_value_get_string (value));
+ break;
+ case PROP_CASE_SENSITIVE:
+ egg_find_bar_set_case_sensitive (find_bar, g_value_get_boolean (value));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+egg_find_bar_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ EggFindBar *find_bar = EGG_FIND_BAR (object);
+ EggFindBarPrivate *priv = (EggFindBarPrivate *)find_bar->priv;
+
+ switch (prop_id)
+ {
+ case PROP_SEARCH_STRING:
+ g_value_set_string (value, priv->search_string);
+ break;
+ case PROP_CASE_SENSITIVE:
+ g_value_set_boolean (value, priv->case_sensitive);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+egg_find_bar_show (GtkWidget *widget)
+{
+ EggFindBar *bar = EGG_FIND_BAR (widget);
+ EggFindBarPrivate *priv = bar->priv;
+
+ GTK_WIDGET_CLASS (egg_find_bar_parent_class)->show (widget);
+
+ if (priv->set_focus_handler == 0)
+ {
+ GtkWidget *toplevel;
+
+ toplevel = gtk_widget_get_toplevel (widget);
+
+ priv->set_focus_handler =
+ g_signal_connect (toplevel, "set-focus",
+ G_CALLBACK (set_focus_cb), bar);
+ }
+}
+
+static void
+egg_find_bar_hide (GtkWidget *widget)
+{
+ EggFindBar *bar = EGG_FIND_BAR (widget);
+ EggFindBarPrivate *priv = bar->priv;
+
+ if (priv->set_focus_handler != 0)
+ {
+ GtkWidget *toplevel;
+
+ toplevel = gtk_widget_get_toplevel (widget);
+
+ g_signal_handlers_disconnect_by_func
+ (toplevel, (void (*)) G_CALLBACK (set_focus_cb), bar);
+ priv->set_focus_handler = 0;
+ }
+
+ GTK_WIDGET_CLASS (egg_find_bar_parent_class)->hide (widget);
+}
+
+static void
+egg_find_bar_grab_focus (GtkWidget *widget)
+{
+ EggFindBar *find_bar = EGG_FIND_BAR (widget);
+ EggFindBarPrivate *priv = find_bar->priv;
+
+ gtk_widget_grab_focus (priv->find_entry);
+}
+
+/**
+ * egg_find_bar_new:
+ *
+ * Creates a new #EggFindBar.
+ *
+ * Returns: a newly created #EggFindBar
+ *
+ * Since: 2.6
+ */
+GtkWidget *
+egg_find_bar_new (void)
+{
+ EggFindBar *find_bar;
+
+ find_bar = g_object_new (EGG_TYPE_FIND_BAR, NULL);
+
+ return GTK_WIDGET (find_bar);
+}
+
+/**
+ * egg_find_bar_set_search_string:
+ *
+ * Sets the string that should be found/highlighted in the document.
+ * Empty string is converted to NULL.
+ *
+ * Since: 2.6
+ */
+void
+egg_find_bar_set_search_string (EggFindBar *find_bar,
+ const char *search_string)
+{
+ EggFindBarPrivate *priv;
+
+ g_return_if_fail (EGG_IS_FIND_BAR (find_bar));
+
+ priv = (EggFindBarPrivate *)find_bar->priv;
+
+ g_object_freeze_notify (G_OBJECT (find_bar));
+
+ if (priv->search_string != search_string)
+ {
+ char *old;
+
+ old = priv->search_string;
+
+ if (search_string && *search_string == '\0')
+ search_string = NULL;
+
+ /* Only update if the string has changed; setting the entry
+ * will emit changed on the entry which will re-enter
+ * this function, but we'll handle that fine with this
+ * short-circuit.
+ */
+ if ((old && search_string == NULL) ||
+ (old == NULL && search_string) ||
+ (old && search_string &&
+ strcmp (old, search_string) != 0))
+ {
+ gboolean not_empty;
+
+ priv->search_string = g_strdup (search_string);
+ g_free (old);
+
+ gtk_entry_set_text (GTK_ENTRY (priv->find_entry),
+ priv->search_string ?
+ priv->search_string :
+ "");
+
+ not_empty = (search_string == NULL) ? FALSE : TRUE;
+
+ gtk_widget_set_sensitive (GTK_WIDGET (find_bar->priv->next_button), not_empty);
+ gtk_widget_set_sensitive (GTK_WIDGET (find_bar->priv->previous_button), not_empty);
+
+ g_object_notify (G_OBJECT (find_bar),
+ "search_string");
+ }
+ }
+
+ g_object_thaw_notify (G_OBJECT (find_bar));
+}
+
+
+/**
+ * egg_find_bar_get_search_string:
+ *
+ * Gets the string that should be found/highlighted in the document.
+ *
+ * Returns: the string
+ *
+ * Since: 2.6
+ */
+const char*
+egg_find_bar_get_search_string (EggFindBar *find_bar)
+{
+ EggFindBarPrivate *priv;
+
+ g_return_val_if_fail (EGG_IS_FIND_BAR (find_bar), NULL);
+
+ priv = find_bar->priv;
+
+ return priv->search_string ? priv->search_string : "";
+}
+
+/**
+ * egg_find_bar_set_case_sensitive:
+ *
+ * Sets whether the search is case sensitive
+ *
+ * Since: 2.6
+ */
+void
+egg_find_bar_set_case_sensitive (EggFindBar *find_bar,
+ gboolean case_sensitive)
+{
+ EggFindBarPrivate *priv;
+
+ g_return_if_fail (EGG_IS_FIND_BAR (find_bar));
+
+ priv = (EggFindBarPrivate *)find_bar->priv;
+
+ g_object_freeze_notify (G_OBJECT (find_bar));
+
+ case_sensitive = case_sensitive != FALSE;
+
+ if (priv->case_sensitive != case_sensitive)
+ {
+ priv->case_sensitive = case_sensitive;
+
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->case_button),
+ priv->case_sensitive);
+
+ g_object_notify (G_OBJECT (find_bar),
+ "case_sensitive");
+ }
+
+ g_object_thaw_notify (G_OBJECT (find_bar));
+}
+
+/**
+ * egg_find_bar_get_case_sensitive:
+ *
+ * Gets whether the search is case sensitive
+ *
+ * Returns: TRUE if it's case sensitive
+ *
+ * Since: 2.6
+ */
+gboolean
+egg_find_bar_get_case_sensitive (EggFindBar *find_bar)
+{
+ EggFindBarPrivate *priv;
+
+ g_return_val_if_fail (EGG_IS_FIND_BAR (find_bar), FALSE);
+
+ priv = (EggFindBarPrivate *)find_bar->priv;
+
+ return priv->case_sensitive;
+}
+
+static void
+get_style_color (EggFindBar *find_bar,
+ const char *style_prop_name,
+ GdkColor *color)
+{
+ GdkColor *style_color;
+
+ gtk_widget_ensure_style (GTK_WIDGET (find_bar));
+ gtk_widget_style_get (GTK_WIDGET (find_bar),
+ "color", &style_color, NULL);
+ if (style_color)
+ {
+ *color = *style_color;
+ gdk_color_free (style_color);
+ }
+}
+
+/**
+ * egg_find_bar_get_all_matches_color:
+ *
+ * Gets the color to use to highlight all the
+ * known matches.
+ *
+ * Since: 2.6
+ */
+void
+egg_find_bar_get_all_matches_color (EggFindBar *find_bar,
+ GdkColor *color)
+{
+ GdkColor found_color = { 0, 0, 0, 0x0f0f };
+
+ get_style_color (find_bar, "all_matches_color", &found_color);
+
+ *color = found_color;
+}
+
+/**
+ * egg_find_bar_get_current_match_color:
+ *
+ * Gets the color to use to highlight the match
+ * we're currently on.
+ *
+ * Since: 2.6
+ */
+void
+egg_find_bar_get_current_match_color (EggFindBar *find_bar,
+ GdkColor *color)
+{
+ GdkColor found_color = { 0, 0, 0, 0xffff };
+
+ get_style_color (find_bar, "current_match_color", &found_color);
+
+ *color = found_color;
+}
+
+/**
+ * egg_find_bar_set_status_text:
+ *
+ * Sets some text to display if there's space; typical text would
+ * be something like "5 results on this page" or "No results"
+ *
+ * @text: the text to display
+ *
+ * Since: 2.6
+ */
+void
+egg_find_bar_set_status_text (EggFindBar *find_bar,
+ const char *text)
+{
+ EggFindBarPrivate *priv;
+
+ g_return_if_fail (EGG_IS_FIND_BAR (find_bar));
+
+ priv = (EggFindBarPrivate *)find_bar->priv;
+
+ gtk_label_set_text (GTK_LABEL (priv->status_label), text);
+ g_object_set (priv->status_separator, "visible", text != NULL && *text != '\0', NULL);
+ g_object_set (priv->status_item, "visible", text != NULL && *text !='\0', NULL);
+}
Modified: devhelp/devhelp/eggfindbar.h
81 files changed, 81 insertions(+), 0 deletions(-)
===================================================================
@@ -0,0 +1,81 @@
+/* Copyright (C) 2004 Red Hat, Inc.
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public License as
+published by the Free Software Foundation; either version 2 of the
+License, or (at your option) any later version.
+
+This library 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
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with the Gnome Library; see the file COPYING.LIB. If not,
+write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.
+*/
+
+#ifndef __EGG_FIND_BAR_H__
+#define __EGG_FIND_BAR_H__
+
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+#define EGG_TYPE_FIND_BAR (egg_find_bar_get_type ())
+#define EGG_FIND_BAR(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), EGG_TYPE_FIND_BAR, EggFindBar))
+#define EGG_FIND_BAR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), EGG_TYPE_FIND_BAR, EggFindBarClass))
+#define EGG_IS_FIND_BAR(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), EGG_TYPE_FIND_BAR))
+#define EGG_IS_FIND_BAR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), EGG_TYPE_FIND_BAR))
+#define EGG_FIND_BAR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), EGG_TYPE_FIND_BAR, EggFindBarClass))
+
+typedef struct _EggFindBar EggFindBar;
+typedef struct _EggFindBarClass EggFindBarClass;
+typedef struct _EggFindBarPrivate EggFindBarPrivate;
+
+struct _EggFindBar
+{
+ GtkToolbar parent;
+
+ /*< private >*/
+ EggFindBarPrivate *priv;
+};
+
+struct _EggFindBarClass
+{
+ GtkToolbarClass parent_class;
+
+ void (* next) (EggFindBar *find_bar);
+ void (* previous) (EggFindBar *find_bar);
+ void (* close) (EggFindBar *find_bar);
+ void (* scroll) (EggFindBar *find_bar, GtkScrollType* scroll);
+
+ /* Padding for future expansion */
+ void (*_gtk_reserved1) (void);
+ void (*_gtk_reserved2) (void);
+ void (*_gtk_reserved3) (void);
+ void (*_gtk_reserved4) (void);
+};
+
+GType egg_find_bar_get_type (void) G_GNUC_CONST;
+GtkWidget *egg_find_bar_new (void);
+
+void egg_find_bar_set_search_string (EggFindBar *find_bar,
+ const char *search_string);
+const char* egg_find_bar_get_search_string (EggFindBar *find_bar);
+void egg_find_bar_set_case_sensitive (EggFindBar *find_bar,
+ gboolean case_sensitive);
+gboolean egg_find_bar_get_case_sensitive (EggFindBar *find_bar);
+void egg_find_bar_get_all_matches_color (EggFindBar *find_bar,
+ GdkColor *color);
+void egg_find_bar_get_current_match_color (EggFindBar *find_bar,
+ GdkColor *color);
+void egg_find_bar_set_status_text (EggFindBar *find_bar,
+ const char *text);
+
+G_END_DECLS
+
+#endif /* __EGG_FIND_BAR_H__ */
+
+
Modified: devhelp/devhelp/ige-conf-gconf.c
387 files changed, 387 insertions(+), 0 deletions(-)
===================================================================
@@ -0,0 +1,387 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2008 Imendio AB
+ *
+ * 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.
+ */
+
+#include "config.h"
+#include <string.h>
+#include <gconf/gconf-client.h>
+#include "ige-conf-private.h"
+
+typedef struct {
+ GConfClient *gconf_client;
+ GList *defaults;
+} IgeConfPriv;
+
+typedef struct {
+ IgeConf *conf;
+ IgeConfNotifyFunc func;
+ gpointer user_data;
+} IgeConfNotifyData;
+
+G_DEFINE_TYPE (IgeConf, ige_conf, G_TYPE_OBJECT);
+
+#define GET_PRIVATE(instance) G_TYPE_INSTANCE_GET_PRIVATE \
+ (instance, IGE_TYPE_CONF, IgeConfPriv);
+
+static IgeConf *global_conf = NULL;
+
+static void
+conf_finalize (GObject *object)
+{
+ IgeConfPriv *priv;
+
+ priv = GET_PRIVATE (object);
+
+ /* FIXME: Remove added dirs.
+ gconf_client_remove_dir (priv->gconf_client,
+ CONF_PATH,
+ NULL);
+ */
+
+ g_object_unref (priv->gconf_client);
+
+ _ige_conf_defaults_free_list (priv->defaults);
+
+ G_OBJECT_CLASS (ige_conf_parent_class)->finalize (object);
+}
+
+static void
+ige_conf_class_init (IgeConfClass *class)
+{
+ GObjectClass *object_class;
+
+ object_class = G_OBJECT_CLASS (class);
+
+ object_class->finalize = conf_finalize;
+
+ g_type_class_add_private (object_class, sizeof (IgeConfPriv));
+}
+
+static void
+ige_conf_init (IgeConf *conf)
+{
+ IgeConfPriv *priv;
+
+ priv = GET_PRIVATE (conf);
+
+ priv->gconf_client = gconf_client_get_default ();
+}
+
+IgeConf *
+ige_conf_get (void)
+{
+ if (!global_conf) {
+ global_conf = g_object_new (IGE_TYPE_CONF, NULL);
+ }
+
+ return global_conf;
+}
+
+void
+ige_conf_add_defaults (IgeConf *conf,
+ const gchar *path)
+{
+ IgeConfPriv *priv = GET_PRIVATE (conf);
+ gchar *root;
+
+ priv->defaults = _ige_conf_defaults_read_file (path, NULL);
+ root = _ige_conf_defaults_get_root (priv->defaults);
+
+ gconf_client_add_dir (priv->gconf_client,
+ root,
+ GCONF_CLIENT_PRELOAD_ONELEVEL,
+ NULL);
+
+ g_free (root);
+}
+
+static GConfEntry *
+conf_get_entry (IgeConf *conf,
+ const gchar *key)
+{
+ IgeConfPriv *priv;
+
+ priv = GET_PRIVATE (conf);
+
+ return gconf_client_get_entry (priv->gconf_client, key,
+ NULL, TRUE, NULL);
+}
+
+gboolean
+ige_conf_set_int (IgeConf *conf,
+ const gchar *key,
+ gint value)
+{
+ IgeConfPriv *priv;
+
+ g_return_val_if_fail (IGE_IS_CONF (conf), FALSE);
+
+ priv = GET_PRIVATE (conf);
+
+ return gconf_client_set_int (priv->gconf_client,
+ key,
+ value,
+ NULL);
+}
+
+gboolean
+ige_conf_get_int (IgeConf *conf,
+ const gchar *key,
+ gint *value)
+{
+ IgeConfPriv *priv;
+ GConfEntry *entry;
+ gboolean got_value = FALSE;
+
+ *value = 0;
+
+ g_return_val_if_fail (IGE_IS_CONF (conf), FALSE);
+ g_return_val_if_fail (value != NULL, FALSE);
+
+ priv = GET_PRIVATE (conf);
+
+ entry = conf_get_entry (conf, key);
+ if (entry) {
+ GConfValue *v;
+
+ v = gconf_entry_get_value (entry);
+ if (v) {
+ *value = gconf_value_get_int (v);
+ got_value = TRUE;
+ }
+ }
+
+ gconf_entry_free (entry);
+
+ if (!got_value) {
+ *value = _ige_conf_defaults_get_int (priv->defaults, key);
+ }
+
+ return TRUE;
+}
+
+gboolean
+ige_conf_set_bool (IgeConf *conf,
+ const gchar *key,
+ gboolean value)
+{
+ IgeConfPriv *priv;
+
+ g_return_val_if_fail (IGE_IS_CONF (conf), FALSE);
+
+ priv = GET_PRIVATE (conf);
+
+ return gconf_client_set_bool (priv->gconf_client,
+ key,
+ value,
+ NULL);
+}
+
+gboolean
+ige_conf_get_bool (IgeConf *conf,
+ const gchar *key,
+ gboolean *value)
+{
+ IgeConfPriv *priv;
+ GConfEntry *entry;
+ gboolean got_value = FALSE;
+
+ *value = 0;
+
+ g_return_val_if_fail (IGE_IS_CONF (conf), FALSE);
+ g_return_val_if_fail (value != NULL, FALSE);
+
+ priv = GET_PRIVATE (conf);
+
+ entry = conf_get_entry (conf, key);
+ if (entry) {
+ GConfValue *v;
+
+ v = gconf_entry_get_value (entry);
+ if (v) {
+ *value = gconf_value_get_bool (v);
+ got_value = TRUE;
+ }
+ }
+
+ gconf_entry_free (entry);
+
+ if (!got_value) {
+ *value = _ige_conf_defaults_get_bool (priv->defaults, key);
+ }
+
+ return TRUE;
+}
+
+gboolean
+ige_conf_set_string (IgeConf *conf,
+ const gchar *key,
+ const gchar *value)
+{
+ IgeConfPriv *priv;
+
+ g_return_val_if_fail (IGE_IS_CONF (conf), FALSE);
+
+ priv = GET_PRIVATE (conf);
+
+ return gconf_client_set_string (priv->gconf_client,
+ key,
+ value,
+ NULL);
+}
+
+gboolean
+ige_conf_get_string (IgeConf *conf,
+ const gchar *key,
+ gchar **value)
+{
+ IgeConfPriv *priv;
+ GError *error = NULL;
+
+ *value = NULL;
+
+ g_return_val_if_fail (IGE_IS_CONF (conf), FALSE);
+
+ priv = GET_PRIVATE (conf);
+
+ *value = gconf_client_get_string (priv->gconf_client,
+ key,
+ &error);
+
+ if (error) {
+ g_error_free (error);
+ return FALSE;
+ }
+
+ if (*value == NULL) {
+ *value = g_strdup (_ige_conf_defaults_get_string (priv->defaults, key));
+ }
+
+ return TRUE;
+}
+
+gboolean
+ige_conf_set_string_list (IgeConf *conf,
+ const gchar *key,
+ GSList *value)
+{
+ IgeConfPriv *priv;
+
+ g_return_val_if_fail (IGE_IS_CONF (conf), FALSE);
+
+ priv = GET_PRIVATE (conf);
+
+ return gconf_client_set_list (priv->gconf_client,
+ key,
+ GCONF_VALUE_STRING,
+ value,
+ NULL);
+}
+
+gboolean
+ige_conf_get_string_list (IgeConf *conf,
+ const gchar *key,
+ GSList **value)
+{
+ IgeConfPriv *priv;
+ GError *error = NULL;
+
+ *value = NULL;
+
+ g_return_val_if_fail (IGE_IS_CONF (conf), FALSE);
+
+ priv = GET_PRIVATE (conf);
+
+ *value = gconf_client_get_list (priv->gconf_client,
+ key,
+ GCONF_VALUE_STRING,
+ &error);
+ if (error) {
+ g_error_free (error);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static void
+conf_notify_data_free (IgeConfNotifyData *data)
+{
+ g_object_unref (data->conf);
+ g_slice_free (IgeConfNotifyData, data);
+}
+
+static void
+conf_notify_func (GConfClient *client,
+ guint id,
+ GConfEntry *entry,
+ gpointer user_data)
+{
+ IgeConfNotifyData *data;
+
+ data = user_data;
+
+ data->func (data->conf,
+ gconf_entry_get_key (entry),
+ data->user_data);
+}
+
+guint
+ige_conf_notify_add (IgeConf *conf,
+ const gchar *key,
+ IgeConfNotifyFunc func,
+ gpointer user_data)
+{
+ IgeConfPriv *priv;
+ guint id;
+ IgeConfNotifyData *data;
+
+ g_return_val_if_fail (IGE_IS_CONF (conf), 0);
+
+ priv = GET_PRIVATE (conf);
+
+ data = g_slice_new (IgeConfNotifyData);
+ data->func = func;
+ data->user_data = user_data;
+ data->conf = g_object_ref (conf);
+
+ id = gconf_client_notify_add (priv->gconf_client,
+ key,
+ conf_notify_func,
+ data,
+ (GFreeFunc) conf_notify_data_free,
+ NULL);
+
+ return id;
+}
+
+gboolean
+ige_conf_notify_remove (IgeConf *conf,
+ guint id)
+{
+ IgeConfPriv *priv;
+
+ g_return_val_if_fail (IGE_IS_CONF (conf), FALSE);
+
+ priv = GET_PRIVATE (conf);
+
+ gconf_client_notify_remove (priv->gconf_client, id);
+
+ return TRUE;
+}
Modified: devhelp/devhelp/ige-conf-mac.c
342 files changed, 342 insertions(+), 0 deletions(-)
===================================================================
@@ -0,0 +1,342 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2008 Imendio AB
+ *
+ * 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.
+ */
+
+#include "config.h"
+#import <Cocoa/Cocoa.h>
+#include <string.h>
+#include "ige-conf-private.h"
+
+typedef struct {
+ NSUserDefaults *defaults;
+} IgeConfPriv;
+
+typedef struct {
+ IgeConf *conf;
+ IgeConfNotifyFunc func;
+ gpointer user_data;
+} IgeConfNotifyData;
+
+G_DEFINE_TYPE (IgeConf, ige_conf, G_TYPE_OBJECT);
+
+#define GET_PRIVATE(instance) G_TYPE_INSTANCE_GET_PRIVATE \
+ (instance, IGE_TYPE_CONF, IgeConfPriv);
+
+static IgeConf *global_conf = NULL;
+
+static void
+conf_finalize (GObject *object)
+{
+ IgeConfPriv *priv = GET_PRIVATE (object);
+
+ [priv->defaults synchronize];
+
+ if (IGE_CONF (object) == global_conf) {
+ global_conf = NULL;
+ }
+
+ G_OBJECT_CLASS (ige_conf_parent_class)->finalize (object);
+}
+
+static void
+ige_conf_class_init (IgeConfClass *class)
+{
+ GObjectClass *object_class;
+
+ object_class = G_OBJECT_CLASS (class);
+
+ object_class->finalize = conf_finalize;
+
+ g_type_class_add_private (object_class, sizeof (IgeConfPriv));
+}
+
+static void
+ige_conf_init (IgeConf *conf)
+{
+}
+
+static void
+conf_atexit (void)
+{
+ if (global_conf) {
+ IgeConfPriv *priv = GET_PRIVATE (global_conf);
+
+ [priv->defaults synchronize];
+ }
+}
+
+IgeConf *
+ige_conf_get (void)
+{
+ if (!global_conf) {
+ global_conf = g_object_new (IGE_TYPE_CONF, NULL);
+ g_atexit (conf_atexit);
+ }
+
+ return global_conf;
+}
+
+void
+ige_conf_add_defaults (IgeConf *conf,
+ const gchar *path)
+{
+ IgeConfPriv *priv = GET_PRIVATE (conf);
+ NSDictionary *dict;
+ GList *defaults, *l;
+
+ priv->defaults = [NSUserDefaults standardUserDefaults];
+
+ dict = [NSMutableDictionary dictionaryWithCapacity: 10];
+
+ defaults = _ige_conf_defaults_read_file (path, NULL);
+ for (l = defaults; l; l = l->next) {
+ IgeConfDefaultItem *item = l->data;
+ NSString *key;
+ NSString *value;
+
+ key = [NSString stringWithUTF8String: item->key];
+ value = [NSString stringWithUTF8String: item->value];
+ [dict setValue:value forKey:key];
+ }
+
+ _ige_conf_defaults_free_list (defaults);
+
+ [priv->defaults registerDefaults: dict];
+}
+
+gboolean
+ige_conf_set_int (IgeConf *conf,
+ const gchar *key,
+ gint value)
+{
+ IgeConfPriv *priv;
+ NSString *string;
+
+ g_return_val_if_fail (IGE_IS_CONF (conf), FALSE);
+
+ priv = GET_PRIVATE (conf);
+
+ string = [NSString stringWithUTF8String: key];
+ [priv->defaults setInteger: value forKey: string];
+
+ return TRUE;
+}
+
+gboolean
+ige_conf_get_int (IgeConf *conf,
+ const gchar *key,
+ gint *value)
+{
+ IgeConfPriv *priv;
+ NSString *string;
+
+ g_return_val_if_fail (IGE_IS_CONF (conf), FALSE);
+
+ priv = GET_PRIVATE (conf);
+
+ string = [NSString stringWithUTF8String: key];
+ *value = [priv->defaults integerForKey: string];
+
+ return TRUE;
+}
+
+gboolean
+ige_conf_set_bool (IgeConf *conf,
+ const gchar *key,
+ gboolean value)
+{
+ IgeConfPriv *priv;
+ NSString *string;
+
+ g_return_val_if_fail (IGE_IS_CONF (conf), FALSE);
+
+ priv = GET_PRIVATE (conf);
+
+ string = [NSString stringWithUTF8String: key];
+ [priv->defaults setBool: value forKey: string];
+
+ return TRUE;
+}
+
+gboolean
+ige_conf_get_bool (IgeConf *conf,
+ const gchar *key,
+ gboolean *value)
+{
+ IgeConfPriv *priv;
+ NSString *string;
+
+ g_return_val_if_fail (IGE_IS_CONF (conf), FALSE);
+
+ priv = GET_PRIVATE (conf);
+
+ string = [NSString stringWithUTF8String: key];
+ *value = [priv->defaults boolForKey: string];
+
+ return TRUE;
+}
+
+gboolean
+ige_conf_set_string (IgeConf *conf,
+ const gchar *key,
+ const gchar *value)
+{
+ IgeConfPriv *priv;
+ NSString *string, *nsvalue;
+
+ g_return_val_if_fail (IGE_IS_CONF (conf), FALSE);
+
+ priv = GET_PRIVATE (conf);
+
+ string = [NSString stringWithUTF8String: key];
+ nsvalue = [NSString stringWithUTF8String: value];
+
+ [priv->defaults setObject: nsvalue forKey: string];
+
+ return TRUE;
+}
+
+gboolean
+ige_conf_get_string (IgeConf *conf,
+ const gchar *key,
+ gchar **value)
+{
+ IgeConfPriv *priv;
+ NSString *string, *nsvalue;
+
+ g_return_val_if_fail (IGE_IS_CONF (conf), FALSE);
+
+ priv = GET_PRIVATE (conf);
+
+ *value = NULL;
+
+ string = [NSString stringWithUTF8String: key];
+ nsvalue = [priv->defaults stringForKey: string];
+ if (nsvalue == NULL) {
+ return FALSE;
+ }
+
+ *value = g_strdup ([nsvalue UTF8String]);
+
+ return TRUE;
+}
+
+gboolean
+ige_conf_set_string_list (IgeConf *conf,
+ const gchar *key,
+ GSList *value)
+{
+ IgeConfPriv *priv;
+
+ g_return_val_if_fail (IGE_IS_CONF (conf), FALSE);
+
+ priv = GET_PRIVATE (conf);
+
+ return TRUE; /*gconf_client_set_string_list (priv->gconf_client,
+ key,
+ value,
+ NULL);
+ */
+}
+
+gboolean
+ige_conf_get_string_list (IgeConf *conf,
+ const gchar *key,
+ GSList **value)
+{
+ IgeConfPriv *priv;
+
+ g_return_val_if_fail (IGE_IS_CONF (conf), FALSE);
+
+ priv = GET_PRIVATE (conf);
+
+ *value = NULL; /*gconf_client_get_string_list (priv->gconf_client,
+ key,
+ &error);
+ */
+ return TRUE;
+}
+
+/*
+static void
+conf_notify_data_free (IgeConfNotifyData *data)
+{
+ g_object_unref (data->conf);
+ g_slice_free (IgeConfNotifyData, data);
+}
+
+static void
+conf_notify_func (GConfClient *client,
+ guint id,
+ GConfEntry *entry,
+ gpointer user_data)
+{
+ IgeConfNotifyData *data;
+
+ data = user_data;
+
+ data->func (data->conf,
+ gconf_entry_get_key (entry),
+ data->user_data);
+}
+*/
+
+guint
+ige_conf_notify_add (IgeConf *conf,
+ const gchar *key,
+ IgeConfNotifyFunc func,
+ gpointer user_data)
+{
+ IgeConfPriv *priv;
+ guint id;
+ IgeConfNotifyData *data;
+
+ g_return_val_if_fail (IGE_IS_CONF (conf), 0);
+
+ priv = GET_PRIVATE (conf);
+
+ data = g_slice_new (IgeConfNotifyData);
+ data->func = func;
+ data->user_data = user_data;
+ data->conf = g_object_ref (conf);
+
+ id = 0; /*gconf_client_notify_add (priv->gconf_client,
+ key,
+ conf_notify_func,
+ data,
+ (GFreeFunc) conf_notify_data_free,
+ NULL);
+ */
+ return id;
+}
+
+gboolean
+ige_conf_notify_remove (IgeConf *conf,
+ guint id)
+{
+ IgeConfPriv *priv;
+
+ g_return_val_if_fail (IGE_IS_CONF (conf), FALSE);
+
+ priv = GET_PRIVATE (conf);
+
+ /*gconf_client_notify_remove (priv->gconf_client, id);*/
+
+ return TRUE;
+}
Modified: devhelp/devhelp/ige-conf-private.h
54 files changed, 54 insertions(+), 0 deletions(-)
===================================================================
@@ -0,0 +1,54 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2008 Imendio AB
+ *
+ * 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.
+ */
+
+#ifndef __IGE_CONF_PRIVATE_H__
+#define __IGE_CONF_PRIVATE_H__
+
+#include <glib.h>
+#include "ige-conf.h"
+
+G_BEGIN_DECLS
+
+typedef enum {
+ IGE_CONF_TYPE_INT,
+ IGE_CONF_TYPE_BOOLEAN,
+ IGE_CONF_TYPE_STRING
+} IgeConfType;
+
+typedef struct {
+ IgeConfType type;
+ gchar *key;
+ gchar *value;
+} IgeConfDefaultItem;
+
+GList * _ige_conf_defaults_read_file (const gchar *path,
+ GError **error);
+void _ige_conf_defaults_free_list (GList *defaults);
+gchar * _ige_conf_defaults_get_root (GList *defaults);
+const gchar *_ige_conf_defaults_get_string (GList *defaults,
+ const gchar *key);
+gint _ige_conf_defaults_get_int (GList *defaults,
+ const gchar *key);
+gboolean _ige_conf_defaults_get_bool (GList *defaults,
+ const gchar *key);
+
+G_END_DECLS
+
+#endif /* __IGE_CONF_PRIVATE_H__ */
Modified: devhelp/devhelp/ige-conf.c
337 files changed, 337 insertions(+), 0 deletions(-)
===================================================================
@@ -0,0 +1,337 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2008 Imendio AB
+ *
+ * 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.
+ */
+
+#include "config.h"
+#include <string.h>
+#include <stdlib.h>
+#include "ige-conf-private.h"
+
+typedef struct {
+ GString *text;
+
+ gchar *current_key;
+ gchar *current_value;
+ IgeConfType current_type;
+
+ GList *defaults;
+} DefaultData;
+
+#define BYTES_PER_READ 4096
+
+static void
+parser_start_cb (GMarkupParseContext *context,
+ const gchar *node_name,
+ const gchar **attribute_names,
+ const gchar **attribute_values,
+ gpointer user_data,
+ GError **error)
+{
+ DefaultData *data = user_data;
+
+ if (g_ascii_strcasecmp (node_name, "applyto") == 0) {
+ data->text = g_string_new (NULL);
+ }
+ else if (g_ascii_strcasecmp (node_name, "type") == 0) {
+ data->text = g_string_new (NULL);
+ }
+ else if (g_ascii_strcasecmp (node_name, "default") == 0) {
+ data->text = g_string_new (NULL);
+ }
+}
+
+static void
+parser_end_cb (GMarkupParseContext *context,
+ const gchar *node_name,
+ gpointer user_data,
+ GError **error)
+{
+ DefaultData *data = user_data;
+
+ if (g_ascii_strcasecmp (node_name, "schema") == 0) {
+ IgeConfDefaultItem *item;
+
+ item = g_slice_new0 (IgeConfDefaultItem);
+ item->key = data->current_key;
+ item->type = data->current_type;
+
+ switch (item->type) {
+ case IGE_CONF_TYPE_INT:
+ case IGE_CONF_TYPE_STRING:
+ item->value = g_strdup (data->current_value);
+ break;
+ case IGE_CONF_TYPE_BOOLEAN:
+ if (strcmp (data->current_value, "true") == 0) {
+ item->value = g_strdup ("YES");
+ } else {
+ item->value = g_strdup ("NO");
+ }
+ break;
+ }
+
+ data->defaults = g_list_prepend (data->defaults, item);
+
+ data->current_key = NULL;
+
+ g_free (data->current_value);
+ data->current_value = NULL;
+ }
+ else if (g_ascii_strcasecmp (node_name, "applyto") == 0) {
+ data->current_key = g_string_free (data->text, FALSE);
+ data->text = NULL;
+ }
+ else if (g_ascii_strcasecmp (node_name, "type") == 0) {
+ gchar *str;
+
+ str = g_string_free (data->text, FALSE);
+ if (strcmp (str, "int") == 0) {
+ data->current_type = IGE_CONF_TYPE_INT;
+ }
+ else if (strcmp (str, "bool") == 0) {
+ data->current_type = IGE_CONF_TYPE_BOOLEAN;
+ }
+ else if (strcmp (str, "string") == 0) {
+ data->current_type = IGE_CONF_TYPE_STRING;
+ }
+
+ g_free (str);
+ data->text = NULL;
+ }
+ else if (g_ascii_strcasecmp (node_name, "default") == 0) {
+ data->current_value = g_string_free (data->text, FALSE);
+ data->text = NULL;
+ }
+}
+
+static void
+parser_text_cb (GMarkupParseContext *context,
+ const gchar *text,
+ gsize text_len,
+ gpointer user_data,
+ GError **error)
+{
+ DefaultData *data = user_data;
+
+ if (data->text) {
+ g_string_append_len (data->text, text, text_len);
+ }
+}
+
+static void
+parser_error_cb (GMarkupParseContext *context,
+ GError *error,
+ gpointer user_data)
+{
+ g_warning ("Error: %s\n", error->message);
+}
+
+GList *
+_ige_conf_defaults_read_file (const gchar *path,
+ GError **error)
+{
+ DefaultData data;
+ GMarkupParser *parser;
+ GMarkupParseContext *context;
+ GIOChannel *io = NULL;
+ gchar buf[BYTES_PER_READ];
+
+ io = g_io_channel_new_file (path, "r", error);
+ if (!io) {
+ return NULL;
+ }
+
+ parser = g_new0 (GMarkupParser, 1);
+
+ parser->start_element = parser_start_cb;
+ parser->end_element = parser_end_cb;
+ parser->text = parser_text_cb;
+ parser->error = parser_error_cb;
+
+ memset (&data, 0, sizeof (DefaultData));
+
+ context = g_markup_parse_context_new (parser,
+ 0,
+ &data,
+ NULL);
+
+ while (TRUE) {
+ GIOStatus io_status;
+ gsize bytes_read;
+
+ io_status = g_io_channel_read_chars (io, buf, BYTES_PER_READ,
+ &bytes_read, error);
+ if (io_status == G_IO_STATUS_ERROR) {
+ goto exit;
+ }
+ if (io_status != G_IO_STATUS_NORMAL) {
+ break;
+ }
+
+ g_markup_parse_context_parse (context, buf, bytes_read, error);
+ if (error != NULL && *error != NULL) {
+ goto exit;
+ }
+
+ if (bytes_read < BYTES_PER_READ) {
+ break;
+ }
+ }
+
+ exit:
+ g_io_channel_unref (io);
+ g_markup_parse_context_free (context);
+ g_free (parser);
+
+ return data.defaults;
+}
+
+void
+_ige_conf_defaults_free_list (GList *defaults)
+{
+ GList *l;
+
+ for (l = defaults; l; l = l->next) {
+ IgeConfDefaultItem *item = l->data;
+
+ g_free (item->value);
+ g_slice_free (IgeConfDefaultItem, item);
+ }
+
+ g_list_free (defaults);
+}
+
+gchar *
+_ige_conf_defaults_get_root (GList *defaults)
+{
+ GList *l;
+ gchar *root;
+ gchar **strv_prev = NULL;
+ gint i;
+ gint last_common = G_MAXINT;
+
+ for (l = defaults; l; l = l->next) {
+ IgeConfDefaultItem *item = l->data;
+ gchar **strv;
+
+ strv = g_strsplit (item->key, "/", 0);
+ if (strv_prev == NULL) {
+ strv_prev = strv;
+ continue;
+ }
+
+ i = 0;
+ while (strv[i] && strv_prev[i] && i < last_common) {
+ if (strcmp (strv[i], strv_prev[i]) != 0) {
+ last_common = i;
+ break;
+ }
+ i++;
+ }
+
+ g_strfreev (strv_prev);
+ strv_prev = strv;
+ }
+
+ if (strv_prev) {
+ GString *str;
+
+ str = g_string_new (NULL);
+ i = 0;
+ while (strv_prev[i] && i < last_common) {
+ if (strv_prev[i][0] != '\0') {
+ g_string_append_c (str, '/');
+ g_string_append (str, strv_prev[i]);
+ }
+ i++;
+ }
+ root = g_string_free (str, FALSE);
+ g_strfreev (strv_prev);
+ } else {
+ root = g_strdup ("/");
+ }
+
+ return root;
+}
+
+static IgeConfDefaultItem *
+defaults_get_item (GList *defaults,
+ const gchar *key)
+{
+ GList *l;
+
+ for (l = defaults; l; l = l->next) {
+ IgeConfDefaultItem *item = l->data;
+
+ if (strcmp (item->key, key) == 0) {
+ return item;
+ }
+ }
+
+ return NULL;
+}
+
+const gchar *
+_ige_conf_defaults_get_string (GList *defaults,
+ const gchar *key)
+{
+ IgeConfDefaultItem *item;
+
+ item = defaults_get_item (defaults, key);
+
+ if (item) {
+ return item->value;
+ }
+
+ return NULL;
+}
+
+gint
+_ige_conf_defaults_get_int (GList *defaults,
+ const gchar *key)
+{
+ IgeConfDefaultItem *item;
+
+ item = defaults_get_item (defaults, key);
+
+ if (item) {
+ return strtol (item->value, NULL, 10);
+ }
+
+ return 0;
+}
+
+gboolean
+_ige_conf_defaults_get_bool (GList *defaults,
+ const gchar *key)
+{
+ IgeConfDefaultItem *item;
+
+ item = defaults_get_item (defaults, key);
+
+ if (item) {
+ if (strcmp (item->value, "false") == 0) {
+ return FALSE;
+ }
+ else if (strcmp (item->value, "true") == 0) {
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
Modified: devhelp/devhelp/ige-conf.h
87 files changed, 87 insertions(+), 0 deletions(-)
===================================================================
@@ -0,0 +1,87 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2008 Imendio AB
+ *
+ * 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.
+ */
+
+#ifndef __IGE_CONF_H__
+#define __IGE_CONF_H__
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define IGE_TYPE_CONF (ige_conf_get_type ())
+#define IGE_CONF(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), IGE_TYPE_CONF, IgeConf))
+#define IGE_CONF_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), IGE_TYPE_CONF, IgeConfClass))
+#define IGE_IS_CONF(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), IGE_TYPE_CONF))
+#define IGE_IS_CONF_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), IGE_TYPE_CONF))
+#define IGE_CONF_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), IGE_TYPE_CONF, IgeConfClass))
+
+typedef struct _IgeConf IgeConf;
+typedef struct _IgeConfClass IgeConfClass;
+
+struct _IgeConf {
+ GObject parent_instance;
+};
+
+struct _IgeConfClass {
+ GObjectClass parent_class;
+};
+
+typedef void (*IgeConfNotifyFunc) (IgeConf *conf,
+ const gchar *key,
+ gpointer user_data);
+
+GType ige_conf_get_type (void);
+IgeConf *ige_conf_get (void);
+void ige_conf_add_defaults (IgeConf *conf,
+ const gchar *path);
+guint ige_conf_notify_add (IgeConf *conf,
+ const gchar *key,
+ IgeConfNotifyFunc func,
+ gpointer data);
+gboolean ige_conf_notify_remove (IgeConf *conf,
+ guint id);
+gboolean ige_conf_set_int (IgeConf *conf,
+ const gchar *key,
+ gint value);
+gboolean ige_conf_get_int (IgeConf *conf,
+ const gchar *key,
+ gint *value);
+gboolean ige_conf_set_bool (IgeConf *conf,
+ const gchar *key,
+ gboolean value);
+gboolean ige_conf_get_bool (IgeConf *conf,
+ const gchar *key,
+ gboolean *value);
+gboolean ige_conf_set_string (IgeConf *conf,
+ const gchar *key,
+ const gchar *value);
+gboolean ige_conf_get_string (IgeConf *conf,
+ const gchar *key,
+ gchar **value);
+gboolean ige_conf_set_string_list (IgeConf *conf,
+ const gchar *key,
+ GSList *value);
+gboolean ige_conf_get_string_list (IgeConf *conf,
+ const gchar *key,
+ GSList **value);
+
+G_END_DECLS
+
+#endif /* __IGE_CONF_H__ */
Modified: devhelp/src/Makefile.am
9 files changed, 6 insertions(+), 3 deletions(-)
===================================================================
@@ -10,7 +10,6 @@ EXTRA_LTLIBRARIES = devhelp.la
endif
devhelp_la_SOURCES = \
- dhp-codesearch.c \
dhp-manpages.c \
dhp-object.c \
dhp-plugin.c
@@ -24,9 +23,13 @@ noinst_HEADERS = \
devhelp_la_CFLAGS = \
$(AM_CFLAGS) \
+ -I$(top_srcdir)/devhelp \
$(DEVHELP_CFLAGS) \
- -DDHPLUG_DATA_DIR=\"$(plugindatadir)\"
+ -DDHPLUG_DATA_DIR=\"$(plugindatadir)\" \
+ -DHAVE_BOOK_MANAGER=1
-devhelp_la_LIBADD = $(DEVHELP_LIBS)
+devhelp_la_LIBADD = \
+ $(DEVHELP_LIBS) \
+ $(top_builddir)/devhelp/devhelp/libdevhelp-2.la
include $(top_srcdir)/build/cppcheck.mk
Modified: devhelp/src/dhp-codesearch.c
101 files changed, 0 insertions(+), 101 deletions(-)
===================================================================
@@ -1,101 +0,0 @@
-#include <glib.h>
-#include <webkit/webkitwebview.h>
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-#include <geanyplugin.h>
-
-#include "dhp.h"
-
-
-struct LangMapEnt
-{
- const gchar *geany_name;
- const gchar *google_name;
-};
-
-
-#define GOOGLE_CODE_SEARCH_URI "http://www.google.com/codesearch"
-
-#define LANG_MAP_MAX 33 /* update this with lang_map[] size below */
-
-/* maps Geany language names to Google Code language names */
-static const struct LangMapEnt lang_map[LANG_MAP_MAX] = {
- { "ActionScript", "actionscript" },
- { "Ada", "ada" },
- { "ASM", "assembly" },
- { "FreeBasic", "basic" },
- { "C", "c" },
- { "C++", "c++" },
- { "C#", "c#" },
- { "COBOL", "cobol" },
- { "CSS", "css" },
- { "D", "d" },
- { "Erlang", "erlang" },
- { "Fortran", "fortran" },
- { "Haskell", "haskell" },
- { "Java", "java" },
- { "Javascript", "javascript" },
- { "Lisp", "lisp" },
- { "Lua", "lua" },
- { "Make", "makefile" },
- { "Matlab/Octave", "matlab" },
- { "CAML", "ocaml" },
- { "Pascal", "pascal" },
- { "Perl", "perl" },
- { "PHP", "php" },
- { "Python", "python" },
- { "R", "r" },
- { "Ruby", "ruby" },
- { "Sh", "shell" },
- { "SQL", "sql" },
- { "Tcl", "tcl" },
- { "LaTeX", "tex" },
- { "Verilog", "verilog" },
- { "VHDL", "vhdl" },
- { "None", NULL }
-};
-
-
-void devhelp_plugin_search_code(DevhelpPlugin *self, const gchar *term, const gchar *lang)
-{
- gint i;
- gchar *uri, *term_enc, *lang_enc;
- const gchar *google_lang = NULL;
-
- g_return_if_fail(self != NULL);
- g_return_if_fail(term != NULL);
-
- if (lang != NULL)
- {
- for (i = 0; i < LANG_MAP_MAX; i++)
- {
- if (g_strcmp0(lang, lang_map[i].geany_name) == 0)
- {
- google_lang = lang_map[i].google_name;
- break;
- }
- }
- }
-
- if (google_lang != NULL)
- {
- lang_enc = g_uri_escape_string(google_lang, NULL, TRUE);
- term_enc = g_uri_escape_string(term, NULL, TRUE);
- uri = g_strdup_printf("%s?as_q=%s&as_lang=%s", GOOGLE_CODE_SEARCH_URI, term_enc, lang_enc);
- g_free(lang_enc);
- g_free(term_enc);
- }
- else
- {
- term_enc = g_uri_escape_string(term, NULL, TRUE);
- uri = g_strdup_printf("%s?as_q=%s", GOOGLE_CODE_SEARCH_URI, term_enc);
- g_free(term_enc);
- }
-
- webkit_web_view_open(devhelp_plugin_get_webview(self), uri);
- g_free(uri);
-
- devhelp_plugin_activate_webview_tab(self);
-}
Modified: devhelp/src/dhp-manpages.c
3 files changed, 2 insertions(+), 1 deletions(-)
===================================================================
@@ -120,7 +120,8 @@
gchar *devhelp_plugin_manpages_search(DevhelpPlugin *self, const gchar *term, const gchar *section)
{
FILE *fp = NULL;
- gint fd = -1, len;
+ gint fd = -1;
+ gsize len;
gchar *man_fn = NULL, *tmp_fn = NULL, *uri = NULL;
gchar *text = NULL, *html_text = NULL;
const gchar *tmpl = "devhelp_manpage_XXXXXX.html";
Modified: devhelp/src/dhp-object.c
29 files changed, 1 insertions(+), 28 deletions(-)
===================================================================
@@ -119,7 +119,6 @@ enum
/* Internal callbacks */
static void on_search_help_activate(GtkMenuItem * menuitem, DevhelpPlugin *self);
static void on_search_help_man_activate(GtkMenuItem * menuitem, DevhelpPlugin *self);
-static void on_search_help_code_activate(GtkMenuItem *menuitem, DevhelpPlugin *self);
static void on_editor_menu_popup(GtkWidget * widget, DevhelpPlugin *self);
static void on_link_clicked(GObject * ignored, DhLink * dhlink, DevhelpPlugin *self);
static void on_back_button_clicked(GtkToolButton * btn, DevhelpPlugin *self);
@@ -377,7 +376,7 @@ static void devhelp_plugin_init_dh(DevhelpPlugin *self)
/* Initialize the stuff in the editor's context menu */
static void devhelp_plugin_init_edit_menu(DevhelpPlugin *self)
{
- GtkWidget *doc_menu, *devhelp_item, *code_item, *man_item;
+ GtkWidget *doc_menu, *devhelp_item, *man_item;
DevhelpPluginPrivate *p;
g_return_if_fail(self != NULL);
@@ -401,11 +400,6 @@ static void devhelp_plugin_init_edit_menu(DevhelpPlugin *self)
gtk_widget_show(man_item);
}
- code_item = gtk_menu_item_new_with_label(_("Google Code"));
- gtk_menu_shell_append(GTK_MENU_SHELL(doc_menu), code_item);
- g_signal_connect(code_item, "activate", G_CALLBACK(on_search_help_code_activate), self);
- gtk_widget_show(code_item);
-
g_signal_connect(geany->main_widgets->editor_menu, "show", G_CALLBACK(on_editor_menu_popup), self);
gtk_menu_item_set_submenu(GTK_MENU_ITEM(p->editor_menu_item), doc_menu);
gtk_menu_shell_append(GTK_MENU_SHELL(geany->main_widgets->editor_menu), p->editor_menu_sep);
@@ -1277,27 +1271,6 @@ static void on_search_help_man_activate(GtkMenuItem * menuitem, DevhelpPlugin *s
}
-static void on_search_help_code_activate(GtkMenuItem *menuitem, DevhelpPlugin *self)
-{
- gchar *current_tag;
- const gchar *lang = NULL;
- GeanyDocument *doc;
-
- g_return_if_fail(self != NULL);
-
- if ((current_tag = devhelp_plugin_get_current_word(self)) == NULL)
- return;
-
- doc = document_get_current();
- if (doc != NULL && doc->file_type != NULL && doc->file_type->name != NULL)
- lang = doc->file_type->name;
-
- devhelp_plugin_search_code(self, current_tag, lang);
-
- g_free(current_tag);
-}
-
-
/*
* Called when the editor context menu is shown so that the devhelp
* search item can be disabled if there isn't a selected tag.
Modified: devhelp/src/dhp-plugin.c
20 files changed, 0 insertions(+), 20 deletions(-)
===================================================================
@@ -60,7 +60,6 @@ enum
KB_DEVHELP_ACTIVATE_DEVHELP,
KB_DEVHELP_SEARCH_SYMBOL,
KB_DEVHELP_SEARCH_MANPAGES,
- KB_DEVHELP_SEARCH_CODESEARCH,
KB_COUNT
};
@@ -101,23 +100,6 @@ static void kb_activate(guint key_id)
g_free(current_tag);
break;
}
- case KB_DEVHELP_SEARCH_CODESEARCH:
- {
- const gchar *lang = NULL;
- GeanyDocument *doc;
-
- if ((current_tag = devhelp_plugin_get_current_word(plugin.devhelp)) == NULL)
- return;
-
- doc = document_get_current();
- if (doc == NULL || doc->file_type == NULL || doc->file_type->name == NULL)
- lang = doc->file_type->name;
-
- devhelp_plugin_search_code(plugin.devhelp, current_tag, lang);
-
- g_free(current_tag);
- break;
- }
}
}
@@ -201,8 +183,6 @@ void plugin_init(GeanyData *data)
keybindings_set_item(key_group, KB_DEVHELP_SEARCH_MANPAGES, kb_activate,
0, 0, "devhelp_search_manpages", _("Search for current tag in Manual Pages"), NULL);
}
- keybindings_set_item(key_group, KB_DEVHELP_SEARCH_CODESEARCH, kb_activate,
- 0, 0, "devhelp_search_codesearch", _("Search for current tag in Google Code Search"), NULL);
}
Modified: devhelp/src/dhp.h
4 files changed, 0 insertions(+), 4 deletions(-)
===================================================================
@@ -125,10 +125,6 @@ struct _DevhelpPluginClass
void devhelp_plugin_remove_manpages_temp_files (DevhelpPlugin *self);
-/* Google Code Search (see codesearch.c) */
-void devhelp_plugin_search_code(DevhelpPlugin *self, const gchar *term, const gchar *lang);
-
-
/* TODO: make properties for these */
gboolean devhelp_plugin_get_devhelp_sidebar_visible(DevhelpPlugin *self);
void devhelp_plugin_set_devhelp_sidebar_visible(DevhelpPlugin *self, gboolean visible);
Modified: devhelp/wscript_build
31 files changed, 24 insertions(+), 7 deletions(-)
===================================================================
@@ -23,13 +23,30 @@
from build.wafutils import build_plugin
-
name = 'Devhelp'
-includes = ['devhelp/src']
-libraries = [ 'GTK', 'GLIB', 'GTHREAD', 'LIBDEVHELP', 'WEBKIT' ]
-sources = [ 'src/dhp-codesearch.c',
- 'src/dhp-manpages.c',
- 'src/dhp-object.c',
- 'src/dhp-plugin.c' ]
+includes = [ '../devhelp', 'devhelp/src', 'devhelp/devhelp' ]
+libraries = [ 'GTK', 'GTHREAD', 'WEBKIT', 'LIBWNCK', 'GCONF2', 'ZLIB' ]
+sources = [ "devhelp/dh-assistant.c",
+ "devhelp/dh-assistant-view.c",
+ "devhelp/dh-base.c",
+ "devhelp/dh-book.c",
+ "devhelp/dh-book-manager.c",
+ "devhelp/dh-book-tree.c",
+ "devhelp/dh-enum-types.c",
+ "devhelp/dh-error.c",
+ "devhelp/dh-keyword-model.c",
+ "devhelp/dh-link.c",
+ "devhelp/dh-marshal.c",
+ "devhelp/dh-parser.c",
+ "devhelp/dh-preferences.c",
+ "devhelp/dh-search.c",
+ "devhelp/dh-util.c",
+ "devhelp/dh-window.c",
+ "devhelp/eggfindbar.c",
+ "devhelp/ige-conf.c",
+ "devhelp/ige-conf-gconf.c",
+ "src/dhp-manpages.c",
+ "src/dhp-object.c",
+ "src/dhp-plugin.c" ]
build_plugin(bld, name, sources=sources, includes=includes, libraries=libraries)
Modified: devhelp/wscript_configure
31 files changed, 6 insertions(+), 25 deletions(-)
===================================================================
@@ -26,9 +26,11 @@ from build.wafutils import add_to_env_and_define, check_cfg_cached
packages = [
('gtk+-2.0', '2.16', 'GTK'),
- ('glib-2.0', '2.16', 'GLIB'),
('gthread-2.0','','GTHREAD'),
- ('webkit-1.0', '1.1.18', 'WEBKIT')
+ ('webkit-1.0', '1.1.13', 'WEBKIT'),
+ ('libwnck-1.0', '2.10.0', 'LIBWNCK'),
+ ('gconf-2.0', '2.6.0', 'GCONF2'),
+ ('zlib', '', 'ZLIB'),
]
for package_name, package_version, uselib_store in packages:
@@ -39,26 +41,5 @@ for package_name, package_version, uselib_store in packages:
mandatory=True,
args='--cflags --libs')
-
-# Use newer libdevhelp-2.0 if present, and fallback on older libdevhelp-1.0
-check_cfg_cached(conf,
- package='libdevhelp-2.0',
- atleast_version='2.32.0',
- uselib_store='LIBDEVHELP',
- mandatory=False,
- args='--cflags --libs')
-
-
-if conf.env['HAVE_LIBDEVHELP'] == 1:
- add_to_env_and_define(conf, 'HAVE_BOOK_MANAGER', 1)
-else:
- # fallback
- check_cfg_cached(conf,
- package='libdevhelp-1.0',
- atleast_version='2.30.1',
- uselib_store='LIBDEVHELP',
- mandatory=False,
- args='--cflags --libs')
- # finally raise an error if we didn't find any suitable devhelp library to disable this plugin
- if not conf.env['HAVE_LIBDEVHELP'] == 1:
- raise ConfigurationError('libdevhelp is necessary for the devhelp plugin')
+add_to_env_and_define(conf, 'HAVE_BOOK_MANAGER', 1)
+add_to_env_and_define(conf, 'PACKAGE_VERSION', 1)
--------------
This E-Mail was brought to you by github_commit_mail.py (Source: TBD).
More information about the Plugins-Commits
mailing list