From git-noreply at xxxxx Thu Mar 1 15:50:01 2012 From: git-noreply at xxxxx (=?utf-8?q?Dominic_Hopf?=) Date: Thu, 01 Mar 2012 15:50:01 -0000 Subject: [geany/plugins.geany.org] 8bb262: Update an old reference to SourceForge with the actual current reference Message-ID: <20120301230001.1C25A25402E@uvena.de> Branch: refs/heads/master Author: Dominic Hopf Committer: Dominic Hopf Date: Thu, 01 Mar 2012 15:50:01 Commit: 8bb262610da23ba230c34a81b28fabf5e5e8a968 https://github.com/geany/plugins.geany.org/commit/8bb262610da23ba230c34a81b28fabf5e5e8a968 Log Message: ----------- Update an old reference to SourceForge with the actual current reference to GitHub (thanks, Lex). Fix a broken link to the GitHub repository of plugins.geany.org itself. Modified Paths: -------------- content/start.html Modified: content/start.html 12 files changed, 7 insertions(+), 5 deletions(-) =================================================================== @@ -4,7 +4,7 @@ "http://www.geany.org">Geany. There is a Geany Plugins project containing a lot of plugins, which is developed by various developers on SourceForge.

+href="https://github.com/geany/geany-plugins">GitHub.

Any plugin delivered with the Geany Plugins project is listed on the left sidebar (Or rather any plugin providing a valid README file written in @@ -30,10 +30,12 @@ "https://sourceforge.net/tracker/?group_id=222729&atid=1056532">report issues against the according plugin (or even this website) at -SourceForge .
The source code of this script -is available on GitHub - as well.

+SourceForge.
+ +The source code of +this script (including the whole source for the plugins.geany.org +website itself) is available on GitHub as well.

If you are a plugin developer and wonder why your plugin is not listed here, -------------- This E-Mail was brought to you by github_commit_mail.py (Source: TBD). From git-noreply at xxxxx Thu Mar 1 16:52:12 2012 From: git-noreply at xxxxx (=?utf-8?q?Dominic_Hopf?=) Date: Thu, 01 Mar 2012 16:52:12 -0000 Subject: [geany/plugins.geany.org] cc9122: add section "Download directly from version control" Message-ID: <20120301230008.9044E25404F@uvena.de> Branch: refs/heads/master Author: Dominic Hopf Committer: Dominic Hopf Date: Thu, 01 Mar 2012 16:52:12 Commit: cc9122d3b66680de3a46a4215b6e695a266fe04b https://github.com/geany/plugins.geany.org/commit/cc9122d3b66680de3a46a4215b6e695a266fe04b Log Message: ----------- add section "Download directly from version control" Modified Paths: -------------- content/downloads.html Modified: content/downloads.html 21 files changed, 21 insertions(+), 0 deletions(-) =================================================================== @@ -145,3 +145,24 @@ gpg --import < hyperair-pubkey.txt
gpg --verify geany-plugins-0.20.tar.bz2.sig geany-plugins-0.20.tar.bz2 + +

Download directly from version control

+

You can pull the sources for Geany-Plugins directly from version control +as well. To do this, just clone the Git repository like this:

+ + +git clone git://github.com/geany/geany-plugins.git geany-plugins + + +

You can build the plugins from those sources then using Waf:

+ +./waf configure
+./waf build -p -k +
+ +

You can either copy the resulting .so files to ~/.config/geany/plugins/ or +install them to /usr/share/geany/ with running following command as root:

+ +./waf install + -------------- This E-Mail was brought to you by github_commit_mail.py (Source: TBD). From git-noreply at xxxxx Thu Mar 1 16:40:29 2012 From: git-noreply at xxxxx (=?utf-8?q?Dominic_Hopf?=) Date: Thu, 01 Mar 2012 16:40:29 -0000 Subject: [geany/plugins.geany.org] c22a55: improvements for about.html Message-ID: <20120301230002.B772B254055@uvena.de> Branch: refs/heads/master Author: Dominic Hopf Committer: Dominic Hopf Date: Thu, 01 Mar 2012 16:40:29 Commit: c22a55509a6d9d2b978e9e637f5df79038d43676 https://github.com/geany/plugins.geany.org/commit/c22a55509a6d9d2b978e9e637f5df79038d43676 Log Message: ----------- improvements for about.html Modified Paths: -------------- content/about.html Modified: content/about.html 36 files changed, 24 insertions(+), 12 deletions(-) =================================================================== @@ -1,13 +1,25 @@

About

-

This site is maintained by Dominic Hopf. -Please contact him if you like to add some information or a new plugin or found -an error or anything else.

- -

You will find him and any other plugin developer either on the -Geany mailing lists or on -the Geany IRC channels.

- -

-Any detailed information on how to contact a specific plugin developer can be -found in the concerning README file of the plugin or on the concerning plugin -page on this site.

+

This site is mainly maintained by +Dominic Hopf. Feel free to contact him if you like to add some +information or a new plugin or found an error or anything else.

+ +

You will find him and any other plugin developer either on the Geany mailing lists or on the +Geany IRC channels.

+ +

Any detailed information on how to contact a specific plugin developer +can be found in the concerning README file of the plugin or on the +concerning plugin page on this site.

+ +

Contributing to this website

+

The sources of this +website are available on GitHub. You can clone your +own copy by running following command:

+ + +git clone git://github.com/geany/plugins.geany.org.git + + +

Feel free to send patches to Dominic or open pull requests on GitHub to +improve this site itself.

-------------- This E-Mail was brought to you by github_commit_mail.py (Source: TBD). From git-noreply at xxxxx Sun Mar 4 21:41:55 2012 From: git-noreply at xxxxx (=?utf-8?b?SmnFmcOtIFRlY2hldA==?=) Date: Sun, 04 Mar 2012 21:41:55 -0000 Subject: [geany/geany-plugins] 65de31: Use new project preference open/close signals Message-ID: <20120304215028.2402B25402E@uvena.de> Branch: refs/heads/master Author: Ji?? Techet Committer: Ji?? Techet Date: Sun, 04 Mar 2012 21:41:55 Commit: 65de310d8355ca8f31632bc9f1d4b776013d52f9 https://github.com/geany/geany-plugins/commit/65de310d8355ca8f31632bc9f1d4b776013d52f9 Log Message: ----------- Use new project preference open/close signals Modified Paths: -------------- gproject/src/gproject-main.c gproject/src/gproject-project.c gproject/src/gproject-project.h Modified: gproject/src/gproject-main.c 32 files changed, 26 insertions(+), 6 deletions(-) =================================================================== @@ -32,7 +32,7 @@ #include "gproject-sidebar.h" #include "gproject-menu.h" -PLUGIN_VERSION_CHECK(211); +PLUGIN_VERSION_CHECK(214); PLUGIN_SET_INFO(_("GProject"), _("Glob-pattern-based project management plugin for Geany."), VERSION, @@ -43,6 +43,9 @@ GeanyFunctions *geany_functions; +static gint page_index = -1; + + void plugin_init(G_GNUC_UNUSED GeanyData * data); void plugin_cleanup(void); @@ -94,18 +97,33 @@ static void on_build_start(GObject *obj, gpointer user_data) } -static void on_project_dialog_create(G_GNUC_UNUSED GObject * obj, GtkWidget * notebook, +static void on_project_dialog_open(G_GNUC_UNUSED GObject * obj, GtkWidget * notebook, G_GNUC_UNUSED gpointer user_data) { - gprj_project_add_properties_tab(notebook); + if (g_prj && page_index == -1) + page_index = gprj_project_add_properties_tab(notebook); } static void on_project_dialog_confirmed(G_GNUC_UNUSED GObject * obj, GtkWidget * notebook, G_GNUC_UNUSED gpointer user_data) { - gprj_project_read_properties_tab(); - gprj_sidebar_update(TRUE); + if (g_prj) + { + gprj_project_read_properties_tab(); + gprj_sidebar_update(TRUE); + } +} + + +static void on_project_dialog_close(G_GNUC_UNUSED GObject * obj, GtkWidget * notebook, + G_GNUC_UNUSED gpointer user_data) +{ + if (page_index != -1) + { + gtk_notebook_remove_page(GTK_NOTEBOOK(notebook), page_index); + page_index = -1; + } } @@ -119,6 +137,7 @@ static void on_project_open(G_GNUC_UNUSED GObject * obj, GKeyFile * config, } + static void on_project_close(G_GNUC_UNUSED GObject * obj, G_GNUC_UNUSED gpointer user_data) { gprj_project_close(); @@ -149,8 +168,9 @@ static void on_project_save(G_GNUC_UNUSED GObject * obj, GKeyFile * config, {"document-activate", (GCallback) & on_doc_activate, TRUE, NULL}, {"document-close", (GCallback) & on_doc_close, TRUE, NULL}, {"build-start", (GCallback) & on_build_start, TRUE, NULL}, - {"project-dialog-create", (GCallback) & on_project_dialog_create, TRUE, NULL}, + {"project-dialog-open", (GCallback) & on_project_dialog_open, TRUE, NULL}, {"project-dialog-confirmed", (GCallback) & on_project_dialog_confirmed, TRUE, NULL}, + {"project-dialog-close", (GCallback) & on_project_dialog_close, TRUE, NULL}, {"project-open", (GCallback) & on_project_open, TRUE, NULL}, {"project-close", (GCallback) & on_project_close, TRUE, NULL}, {"project-save", (GCallback) & on_project_save, TRUE, NULL}, Modified: gproject/src/gproject-project.c 8 files changed, 6 insertions(+), 2 deletions(-) =================================================================== @@ -387,12 +387,13 @@ void gprj_project_read_properties_tab() } -void gprj_project_add_properties_tab(GtkWidget *notebook) +gint gprj_project_add_properties_tab(GtkWidget *notebook) { GtkWidget *vbox, *hbox, *hbox1; GtkWidget *table; GtkWidget *label; gchar *str; + gint page_index; e = g_new0(PropertyDialogElements, 1); @@ -456,7 +457,10 @@ void gprj_project_add_properties_tab(GtkWidget *notebook) hbox = gtk_hbox_new(FALSE, 0); gtk_box_pack_start(GTK_BOX(hbox), vbox, TRUE, TRUE, 6); - gtk_notebook_append_page(GTK_NOTEBOOK(notebook), hbox, label); + page_index = gtk_notebook_append_page(GTK_NOTEBOOK(notebook), hbox, label); + gtk_widget_show_all(notebook); + + return page_index; } Modified: gproject/src/gproject-project.h 2 files changed, 1 insertions(+), 1 deletions(-) =================================================================== @@ -40,7 +40,7 @@ void gprj_project_open(GKeyFile * key_file); -void gprj_project_add_properties_tab(GtkWidget *notebook); +gint gprj_project_add_properties_tab(GtkWidget *notebook); void gprj_project_close(void); -------------- This E-Mail was brought to you by github_commit_mail.py (Source: TBD). From git-noreply at xxxxx Fri Mar 9 19:45:01 2012 From: git-noreply at xxxxx (=?utf-8?q?William_Fraser?=) Date: Fri, 09 Mar 2012 19:45:01 -0000 Subject: [geany/geany-plugins] de6015: broke long sentence up to make translation easier Message-ID: <20120309194524.A73C225401D@uvena.de> Branch: refs/heads/master Author: William Fraser Committer: Frank Lanitz Date: Fri, 09 Mar 2012 19:45:01 Commit: de601537422283eeb61b97bbe781c257c39403b2 https://github.com/geany/geany-plugins/commit/de601537422283eeb61b97bbe781c257c39403b2 Log Message: ----------- broke long sentence up to make translation easier Modified Paths: -------------- geanymacro/src/geanymacro.c Modified: geanymacro/src/geanymacro.c 65 files changed, 38 insertions(+), 27 deletions(-) =================================================================== @@ -768,32 +768,43 @@ void plugin_help(void) /* create label */ label=gtk_label_new( - _("This Plugin implements Macros in Geany.\n\n" - "This plugin allows you to record and use your own macros. These are sequences of \ -actions that can then be repeated with a single key combination. So if you had dozens of lines \ -where you wanted to delete the last 2 characters, you could simple start recording, press End, \ -Backspace, Backspace, down line and then stop recording. Then simply trigger the macro and it \ -would automatically edit the line and move to the next. Select Record Macro from the Tools menu \ -and you will be prompted with a dialog box. You need to specify a key combination that isn't being\ - used, and a name for the macro to help you identify it. Then press Record. What you do in the \ -editor is then recorded until you select Stop Recording Macro from the Tools menu. Simply pressing\ - the specified key combination will re-run the macro. To edit the macros you have, select Edit \ -Macro from the Tools menu. You can select a macro and delete it, or re-record it. You can also \ -click on a macro's name and change it, or the key combination and re-define that assuming that it's\ - not already in use. Selecting the edit option allows you to view all the individual elements that \ -make up the macro. You can select a diferent command for each element, move them, add new elements,\ - delete elements, or if it's replace/insert, you can edit the text that replaces the selected text,\ - or is inserted.\n\n" - "The only thing to bear in mind is that undo and redo actions are not recorded, and\ - won't be replayed when the macro is re-run.\n\n" - "You can alter the default behaviour of this plugin by selecting Plugin Manager under the \ -Tools menu, selecting this plugin, and cliking Preferences. You can change:\nSave Macros when \ -close Geany - If this is selected then Geany will save any recorded macros and reload them for use\ - the next time you open Geany, if not they will be lost when Geany is closed.\nAsk before \ -replaceing existing Macros - If this is selected then if you try recording a macro over an \ -existing one it will check before over-writing it, giving you the option of trying a different \ -name or key trigger combination, otherwise it will simply erase any existing macros with the same \ -name, or the same key trigger combination.")); + _("This Plugin implements Macros in Geany.\n\n") +_("This plugin allows you to record and use your own macros. ") +_("These are sequences of actions that can then be repeated with a single key combination. ") +_("So if you had dozens of lines where you wanted to delete the last 2 characters, you could simpl\ +y start recording, press End, Backspace, Backspace, down line and then stop recording. ") +_("Then simply trigger the macro and it would automatically edit the line and move to the next. ") +_("Select Record Macro from the Tools menu and you will be prompted with a dialog box. ") +_("You need to specify a key combination that isn't being used, and a name for the macro to help y\ +ou identify it. ") +_("Then press Record. ") +_("What you do in the editor is then recorded until you select Stop Recording Macro from the Tools\ + menu. ") +_("Simply pressing the specified key combination will re-run the macro. ") +_("To edit the macros you have, select Edit Macro from the Tools menu. ") +_("You can select a macro and delete it, or re-record it. ") +_("You can also click on a macro's name and change it, or the key combination and re-define that a\ +ssuming that it's not already in use. ") +_("Selecting the edit option allows you to view all the individual elements that make up the macro\ +. ") +_("You can select a diferent command for each element, move them, add new elements, delete element\ +s, or if it's replace/insert, you can edit the text that replaces the selected text, or is inserte\ +d.\n\n") + +_("The only thing to bear in mind is that undo and redo actions are not recorded, and won't be rep\ +layed when the macro is re-run.\n\n") + + +_("You can alter the default behaviour of this plugin by selecting Plugin Manager under the Tools \ +menu, selecting this plugin, and cliking Preferences. ") +_("You can change:\n") +_("Save Macros when close Geany - If this is selected then Geany will save any recorded macros and\ + reload them for use the next time you open Geany, if not they will be lost when Geany is closed.\ +\n") +_("Ask before replaceing existing Macros - If this is selected then if you try recording a macro o\ +ver an existing one it will check before over-writing it, giving you the option of trying a differ\ +ent name or key trigger combination, otherwise it will simply erase any existing macros with the s\ +ame name, or the same key trigger combination.")); gtk_label_set_line_wrap(GTK_LABEL(label),TRUE); gtk_widget_show(label); @@ -1909,4 +1920,4 @@ void plugin_cleanup(void) /* clean up memory used by macros */ ClearAllMacros(); -} \ No newline at end of file +} -------------- This E-Mail was brought to you by github_commit_mail.py (Source: TBD). From git-noreply at xxxxx Fri Mar 9 19:47:26 2012 From: git-noreply at xxxxx (=?utf-8?q?Frank_Lanitz?=) Date: Fri, 09 Mar 2012 19:47:26 -0000 Subject: [geany/geany-plugins] 984d5b: Revert "broke long sentence up to make translation easier" Message-ID: <20120309194803.BE707254021@uvena.de> Branch: refs/heads/master Author: Frank Lanitz Committer: Frank Lanitz Date: Fri, 09 Mar 2012 19:47:26 Commit: 984d5b6e0089d123d60fb89e52e06077969904f2 https://github.com/geany/geany-plugins/commit/984d5b6e0089d123d60fb89e52e06077969904f2 Log Message: ----------- Revert "broke long sentence up to make translation easier" Shouldn't have been pushed as it was pushed by error. This reverts commit de601537422283eeb61b97bbe781c257c39403b2. Modified Paths: -------------- geanymacro/src/geanymacro.c Modified: geanymacro/src/geanymacro.c 65 files changed, 27 insertions(+), 38 deletions(-) =================================================================== @@ -768,43 +768,32 @@ void plugin_help(void) /* create label */ label=gtk_label_new( - _("This Plugin implements Macros in Geany.\n\n") -_("This plugin allows you to record and use your own macros. ") -_("These are sequences of actions that can then be repeated with a single key combination. ") -_("So if you had dozens of lines where you wanted to delete the last 2 characters, you could simpl\ -y start recording, press End, Backspace, Backspace, down line and then stop recording. ") -_("Then simply trigger the macro and it would automatically edit the line and move to the next. ") -_("Select Record Macro from the Tools menu and you will be prompted with a dialog box. ") -_("You need to specify a key combination that isn't being used, and a name for the macro to help y\ -ou identify it. ") -_("Then press Record. ") -_("What you do in the editor is then recorded until you select Stop Recording Macro from the Tools\ - menu. ") -_("Simply pressing the specified key combination will re-run the macro. ") -_("To edit the macros you have, select Edit Macro from the Tools menu. ") -_("You can select a macro and delete it, or re-record it. ") -_("You can also click on a macro's name and change it, or the key combination and re-define that a\ -ssuming that it's not already in use. ") -_("Selecting the edit option allows you to view all the individual elements that make up the macro\ -. ") -_("You can select a diferent command for each element, move them, add new elements, delete element\ -s, or if it's replace/insert, you can edit the text that replaces the selected text, or is inserte\ -d.\n\n") - -_("The only thing to bear in mind is that undo and redo actions are not recorded, and won't be rep\ -layed when the macro is re-run.\n\n") - - -_("You can alter the default behaviour of this plugin by selecting Plugin Manager under the Tools \ -menu, selecting this plugin, and cliking Preferences. ") -_("You can change:\n") -_("Save Macros when close Geany - If this is selected then Geany will save any recorded macros and\ - reload them for use the next time you open Geany, if not they will be lost when Geany is closed.\ -\n") -_("Ask before replaceing existing Macros - If this is selected then if you try recording a macro o\ -ver an existing one it will check before over-writing it, giving you the option of trying a differ\ -ent name or key trigger combination, otherwise it will simply erase any existing macros with the s\ -ame name, or the same key trigger combination.")); + _("This Plugin implements Macros in Geany.\n\n" + "This plugin allows you to record and use your own macros. These are sequences of \ +actions that can then be repeated with a single key combination. So if you had dozens of lines \ +where you wanted to delete the last 2 characters, you could simple start recording, press End, \ +Backspace, Backspace, down line and then stop recording. Then simply trigger the macro and it \ +would automatically edit the line and move to the next. Select Record Macro from the Tools menu \ +and you will be prompted with a dialog box. You need to specify a key combination that isn't being\ + used, and a name for the macro to help you identify it. Then press Record. What you do in the \ +editor is then recorded until you select Stop Recording Macro from the Tools menu. Simply pressing\ + the specified key combination will re-run the macro. To edit the macros you have, select Edit \ +Macro from the Tools menu. You can select a macro and delete it, or re-record it. You can also \ +click on a macro's name and change it, or the key combination and re-define that assuming that it's\ + not already in use. Selecting the edit option allows you to view all the individual elements that \ +make up the macro. You can select a diferent command for each element, move them, add new elements,\ + delete elements, or if it's replace/insert, you can edit the text that replaces the selected text,\ + or is inserted.\n\n" + "The only thing to bear in mind is that undo and redo actions are not recorded, and\ + won't be replayed when the macro is re-run.\n\n" + "You can alter the default behaviour of this plugin by selecting Plugin Manager under the \ +Tools menu, selecting this plugin, and cliking Preferences. You can change:\nSave Macros when \ +close Geany - If this is selected then Geany will save any recorded macros and reload them for use\ + the next time you open Geany, if not they will be lost when Geany is closed.\nAsk before \ +replaceing existing Macros - If this is selected then if you try recording a macro over an \ +existing one it will check before over-writing it, giving you the option of trying a different \ +name or key trigger combination, otherwise it will simply erase any existing macros with the same \ +name, or the same key trigger combination.")); gtk_label_set_line_wrap(GTK_LABEL(label),TRUE); gtk_widget_show(label); @@ -1920,4 +1909,4 @@ void plugin_cleanup(void) /* clean up memory used by macros */ ClearAllMacros(); -} +} \ No newline at end of file -------------- This E-Mail was brought to you by github_commit_mail.py (Source: TBD). From git-noreply at xxxxx Mon Mar 12 20:53:22 2012 From: git-noreply at xxxxx (=?utf-8?q?Dominic_Hopf?=) Date: Mon, 12 Mar 2012 20:53:22 -0000 Subject: [geany/plugins.geany.org] 5ea168: describe the autotools way to build geany-plugins as well Message-ID: <20120312210327.C0480254021@uvena.de> Branch: refs/heads/master Author: Dominic Hopf Committer: Dominic Hopf Date: Mon, 12 Mar 2012 20:53:22 Commit: 5ea168ca1c5acb2c404dd730d8b0362324d0c2bb https://github.com/geany/plugins.geany.org/commit/5ea168ca1c5acb2c404dd730d8b0362324d0c2bb Log Message: ----------- describe the autotools way to build geany-plugins as well Modified Paths: -------------- content/downloads.html Modified: content/downloads.html 7 files changed, 7 insertions(+), 0 deletions(-) =================================================================== @@ -166,3 +166,10 @@ ./waf install + +

Or either do it the autotools way as well:

+ +./autogen.sh # Note this already runs ./configure
+make
+make install +
-------------- This E-Mail was brought to you by github_commit_mail.py (Source: TBD). From git-noreply at xxxxx Mon Mar 12 21:02:58 2012 From: git-noreply at xxxxx (=?utf-8?q?Dominic_Hopf?=) Date: Mon, 12 Mar 2012 21:02:58 -0000 Subject: [geany/plugins.geany.org] e37dff: remove third-party plugins from site Message-ID: <20120312210328.5263F254021@uvena.de> Branch: refs/heads/master Author: Dominic Hopf Committer: Dominic Hopf Date: Mon, 12 Mar 2012 21:02:58 Commit: e37dfff26249a106faf30cc7196496d379d5862f https://github.com/geany/plugins.geany.org/commit/e37dfff26249a106faf30cc7196496d379d5862f Log Message: ----------- remove third-party plugins from site Modified Paths: -------------- content/externdbg.html content/geany-mini-script.html content/geanyembrace.html index.php Modified: content/externdbg.html 1 files changed, 0 insertions(+), 1 deletions(-) =================================================================== @@ -1 +0,0 @@ -

externdbg

Modified: content/geany-mini-script.html 1 files changed, 0 insertions(+), 1 deletions(-) =================================================================== @@ -1 +0,0 @@ -

Geany Mini Script

Modified: content/geanyembrace.html 1 files changed, 0 insertions(+), 1 deletions(-) =================================================================== @@ -1 +0,0 @@ -

GeanyEmbrace

Modified: index.php 9 files changed, 0 insertions(+), 9 deletions(-) =================================================================== @@ -63,15 +63,6 @@
-

Other Third-Party plugins

- - -
-
  • Downloads
  • Installation
  • -------------- This E-Mail was brought to you by github_commit_mail.py (Source: TBD). From git-noreply at xxxxx Sun Mar 11 22:04:45 2012 From: git-noreply at xxxxx (=?utf-8?q?9reyfox?=) Date: Sun, 11 Mar 2012 22:04:45 -0000 Subject: [geany/geany-plugins] 616c26: New key bindings in Tree Browser (create new file and create new directory) Message-ID: <20120314195249.E246A25401D@uvena.de> Branch: refs/heads/master Author: 9reyfox <9reyfox at gmail.com> Committer: 9reyfox <9reyfox at gmail.com> Date: Sun, 11 Mar 2012 22:04:45 Commit: 616c26cca8308dd991f0d04b57ac25f1f090fe43 https://github.com/geany/geany-plugins/commit/616c26cca8308dd991f0d04b57ac25f1f090fe43 Log Message: ----------- New key bindings in Tree Browser (create new file and create new directory) Modified Paths: -------------- treebrowser/src/treebrowser.c Modified: treebrowser/src/treebrowser.c 22 files changed, 22 insertions(+), 0 deletions(-) =================================================================== @@ -100,6 +100,8 @@ enum KB_FOCUS_FILE_LIST, KB_FOCUS_PATH_ENTRY, KB_RENAME_OBJECT, + KB_CREATE_FILE, + KB_CREATE_DIR, KB_REFRESH, KB_COUNT }; @@ -147,6 +149,7 @@ enum static void treebrowser_load_bookmarks(); static void gtk_tree_store_iter_clear_nodes(gpointer iter, gboolean delete_root); static void treebrowser_rename_current(); +static void on_menu_create_new_object(GtkMenuItem *menuitem, gchar *type); static void load_settings(); static gboolean save_settings(); @@ -900,6 +903,13 @@ enum } } +static void +treebrowser_create_new_current(gchar *type) +{ + on_menu_create_new_object(NULL, type); +} + + /* ------------------ * RIGHTCLICK MENU EVENTS * ------------------*/ @@ -1966,6 +1976,14 @@ static void kb_activate(guint key_id) case KB_RENAME_OBJECT: treebrowser_rename_current(); break; + + case KB_CREATE_FILE: + treebrowser_create_new_current("file"); + break; + + case KB_CREATE_DIR: + treebrowser_create_new_current("directory"); + break; case KB_REFRESH: on_menu_refresh(NULL, NULL); @@ -1996,6 +2014,10 @@ static void kb_activate(guint key_id) 0, 0, "focus_path_entry", _("Focus Path Entry"), NULL); keybindings_set_item(key_group, KB_RENAME_OBJECT, kb_activate, 0, 0, "rename_object", _("Rename Object"), NULL); + keybindings_set_item(key_group, KB_CREATE_FILE, kb_activate, + 0, 0, "create_file", _("Create New File"), NULL); + keybindings_set_item(key_group, KB_CREATE_DIR, kb_activate, + 0, 0, "create_dir", _("Create New Directory"), NULL); keybindings_set_item(key_group, KB_REFRESH, kb_activate, 0, 0, "rename_refresh", _("Refresh"), NULL); -------------- This E-Mail was brought to you by github_commit_mail.py (Source: TBD). From git-noreply at xxxxx Wed Mar 14 19:57:09 2012 From: git-noreply at xxxxx (=?utf-8?q?Frank_Lanitz?=) Date: Wed, 14 Mar 2012 19:57:09 -0000 Subject: [geany/geany-plugins] 1310a1: Merge pull request #17 from WilliamFraser/master Message-ID: <20120314195716.3BAA025401D@uvena.de> Branch: refs/heads/master Author: Frank Lanitz Committer: Frank Lanitz Date: Wed, 14 Mar 2012 19:57:09 Commit: 1310a1e568e7047c774943821c139addb0e02958 https://github.com/geany/geany-plugins/commit/1310a1e568e7047c774943821c139addb0e02958 Log Message: ----------- Merge pull request #17 from WilliamFraser/master breaking up sentence for easier translation Modified Paths: -------------- geanymacro/src/geanymacro.c Modified: geanymacro/src/geanymacro.c 77 files changed, 48 insertions(+), 29 deletions(-) =================================================================== @@ -50,7 +50,7 @@ typedef struct { gint message; - gchar *description; + const gchar *description; } MacroDetailEntry; /* list of editor messages this plugin can handle & a description */ @@ -758,6 +758,7 @@ static void on_configure_response(GtkDialog *dialog, gint response, gpointer use void plugin_help(void) { GtkWidget *dialog,*label,*scroll; + gchar *cText; /* create dialog box */ dialog=gtk_dialog_new_with_buttons(_("Geany Macros help"), @@ -766,34 +767,48 @@ void plugin_help(void) GTK_STOCK_OK,GTK_RESPONSE_ACCEPT, NULL); +/* setup help text */ + cText=g_strconcat( +_("This Plugin implements Macros in Geany.\n\n"), +_("This plugin allows you to record and use your own macros. "), +_("These are sequences of actions that can then be repeated with a single key combination. "), +_("So if you had dozens of lines where you wanted to delete the last 2 characters, you could simpl\ +y start recording, press End, Backspace, Backspace, down line and then stop recording. "), +_("Then simply trigger the macro and it would automatically edit the line and move to the next. "), +_("Select Record Macro from the Tools menu and you will be prompted with a dialog box. "), +_("You need to specify a key combination that isn't being used, and a name for the macro to help y\ +ou identify it. "), +_("Then press Record. "), +_("What you do in the editor is then recorded until you select Stop Recording Macro from the Tools\ + menu. "), +_("Simply pressing the specified key combination will re-run the macro. "), +_("To edit the macros you have, select Edit Macro from the Tools menu. "), +_("You can select a macro and delete it, or re-record it. "), +_("You can also click on a macro's name and change it, or the key combination and re-define that a\ +ssuming that it's not already in use. "), +_("Selecting the edit option allows you to view all the individual elements that make up the macro\ +. "), +_("You can select a diferent command for each element, move them, add new elements, delete element\ +s, or if it's replace/insert, you can edit the text that replaces the selected text, or is inserte\ +d.\n\n"), + +_("The only thing to bear in mind is that undo and redo actions are not recorded, and won't be rep\ +layed when the macro is re-run.\n\n"), + +_("You can alter the default behaviour of this plugin by selecting Plugin Manager under the Tools \ +menu, selecting this plugin, and cliking Preferences. "), +_("You can change:\n"), +_("Save Macros when close Geany - If this is selected then Geany will save any recorded macros and\ + reload them for use the next time you open Geany, if not they will be lost when Geany is closed.\ +\n"), +_("Ask before replaceing existing Macros - If this is selected then if you try recording a macro o\ +ver an existing one it will check before over-writing it, giving you the option of trying a differ\ +ent name or key trigger combination, otherwise it will simply erase any existing macros with the s\ +ame name, or the same key trigger combination."), +NULL); + /* create label */ - label=gtk_label_new( - _("This Plugin implements Macros in Geany.\n\n" - "This plugin allows you to record and use your own macros. These are sequences of \ -actions that can then be repeated with a single key combination. So if you had dozens of lines \ -where you wanted to delete the last 2 characters, you could simple start recording, press End, \ -Backspace, Backspace, down line and then stop recording. Then simply trigger the macro and it \ -would automatically edit the line and move to the next. Select Record Macro from the Tools menu \ -and you will be prompted with a dialog box. You need to specify a key combination that isn't being\ - used, and a name for the macro to help you identify it. Then press Record. What you do in the \ -editor is then recorded until you select Stop Recording Macro from the Tools menu. Simply pressing\ - the specified key combination will re-run the macro. To edit the macros you have, select Edit \ -Macro from the Tools menu. You can select a macro and delete it, or re-record it. You can also \ -click on a macro's name and change it, or the key combination and re-define that assuming that it's\ - not already in use. Selecting the edit option allows you to view all the individual elements that \ -make up the macro. You can select a diferent command for each element, move them, add new elements,\ - delete elements, or if it's replace/insert, you can edit the text that replaces the selected text,\ - or is inserted.\n\n" - "The only thing to bear in mind is that undo and redo actions are not recorded, and\ - won't be replayed when the macro is re-run.\n\n" - "You can alter the default behaviour of this plugin by selecting Plugin Manager under the \ -Tools menu, selecting this plugin, and cliking Preferences. You can change:\nSave Macros when \ -close Geany - If this is selected then Geany will save any recorded macros and reload them for use\ - the next time you open Geany, if not they will be lost when Geany is closed.\nAsk before \ -replaceing existing Macros - If this is selected then if you try recording a macro over an \ -existing one it will check before over-writing it, giving you the option of trying a different \ -name or key trigger combination, otherwise it will simply erase any existing macros with the same \ -name, or the same key trigger combination.")); + label=gtk_label_new(cText); gtk_label_set_line_wrap(GTK_LABEL(label),TRUE); gtk_widget_show(label); @@ -812,6 +827,10 @@ void plugin_help(void) /* display the dialog */ gtk_dialog_run(GTK_DIALOG(dialog)); gtk_widget_destroy(dialog); + + /* free memory */ + g_free(cText); + } @@ -1909,4 +1928,4 @@ void plugin_cleanup(void) /* clean up memory used by macros */ ClearAllMacros(); -} \ No newline at end of file +} -------------- This E-Mail was brought to you by github_commit_mail.py (Source: TBD). From git-noreply at xxxxx Wed Mar 14 20:00:10 2012 From: git-noreply at xxxxx (=?utf-8?q?Frank_Lanitz?=) Date: Wed, 14 Mar 2012 20:00:10 -0000 Subject: [geany/geany-plugins] 093fdc: Merge pull request #18 from cesspit/master Message-ID: <20120314200018.A600325401D@uvena.de> Branch: refs/heads/master Author: Frank Lanitz Committer: Frank Lanitz Date: Wed, 14 Mar 2012 20:00:10 Commit: 093fdc6260681ea6baa5657bb1d8ca2ef9f9ced8 https://github.com/geany/geany-plugins/commit/093fdc6260681ea6baa5657bb1d8ca2ef9f9ced8 Log Message: ----------- Merge pull request #18 from cesspit/master switching between frames by clicking a frame arrow in the stack window Modified Paths: -------------- debugger/ChangeLog debugger/TODO debugger/src/Makefile.am debugger/src/breakpoints.h debugger/src/callbacks.c debugger/src/cell_renderers/cellrendererbreakicon.c debugger/src/cell_renderers/cellrendererbreakicon.h debugger/src/cell_renderers/cellrendererframeicon.c debugger/src/cell_renderers/cellrendererframeicon.h debugger/src/dbm_gdb.c debugger/src/debug.c debugger/src/debug.h debugger/src/debug_module.h debugger/src/pixbuf.h debugger/src/stree.c debugger/src/stree.h debugger/src/utils.h Modified: debugger/ChangeLog 4 files changed, 4 insertions(+), 0 deletions(-) =================================================================== @@ -1,3 +1,7 @@ +10-03-2012 Alexander Petukhov + + * switching between frames by clicking a frame arrow in the stack window + 18-02-2012 Alexander Petukhov * threads info added to the stack window Modified: debugger/TODO 4 files changed, 3 insertions(+), 1 deletions(-) =================================================================== @@ -2,12 +2,13 @@ BUGS: - terminal stops to produce any output after some debug seesions - tooltip appears even if a pointer in no longer inside editor window - check possible memory leaks on a)gtk_tree_row_reference_get_path b)missing unrefs on tree/list stores +- cell_renderer_toogle SIGSEGV in cell_renderer_toggle_activate when activating a cell using a keyboard (event->button == NULL) +- debug geany with debugger project. switch frames then step over -> continue instead, then close geany being debugged -> dbm_gdb.c:502 (no step reason, probably the record from the previos step command???) FEATURES: - custom tooltip with sticking facilities - don't hide a tooltip until run hasn't happent, move it if document is being scrolled - use lexer to lookup for a symbol under cursor when presenting a tooltip -- jump to a frame (change frame that affects locals, watch etc., caused by clicking a frame in the stack trace tab/margin stack marker) - geany menu integration - toolbar buttons - margin context menu @@ -22,3 +23,4 @@ FEATURES: - interrupt thread using stack window - custom tooltip on breaks and stack trace windows with code snippet around break or frame - font from the geany settings for a message window +- a button in the upper right path of a right notebook for a hiding/showing button panel Modified: debugger/src/Makefile.am 2 files changed, 2 insertions(+), 0 deletions(-) =================================================================== @@ -62,6 +62,8 @@ debugger_la_SOURCES = \ wtree.h \ cell_renderers/cellrendererbreakicon.c \ cell_renderers/cellrendererbreakicon.h \ + cell_renderers/cellrendererframeicon.c \ + cell_renderers/cellrendererframeicon.h \ cell_renderers/cellrenderertoggle.c \ cell_renderers/cellrenderertoggle.h Modified: debugger/src/breakpoints.h 3 files changed, 2 insertions(+), 1 deletions(-) =================================================================== @@ -27,7 +27,8 @@ BS_DISABLED } break_state; -typedef void (*move_to_line_cb)(char* file, int line); +typedef void (*move_to_line_cb)(const char* file, int line); +typedef void (*select_frame_cb)(int frame_number); gboolean breaks_init(move_to_line_cb callback); void breaks_destroy(); Modified: debugger/src/callbacks.c 26 files changed, 14 insertions(+), 12 deletions(-) =================================================================== @@ -67,24 +67,26 @@ void set_markers_for_file(const gchar* file) /* set frames markers if exists */ if (DBS_STOPPED == debug_get_state()) { + int active_frame_index = debug_get_active_frame(); + GList *iter = debug_get_stack(); - if (iter) + int frame_index = 0; + for (; iter; iter = iter->next, frame_index++) { - frame *f = (frame*)iter->data; - if (f->have_source && !strcmp(f->file, file)) - { - markers_add_current_instruction(f->file, f->line); - } - - iter = iter->next; - while (iter) + if (iter) { - f = (frame*)iter->data; + frame *f = (frame*)iter->data; if (f->have_source && !strcmp(f->file, file)) { - markers_add_frame(f->file, f->line); + if (active_frame_index == frame_index) + { + markers_add_current_instruction(f->file, f->line); + } + else + { + markers_add_frame(f->file, f->line); + } } - iter = iter->next; } } } Modified: debugger/src/cell_renderers/cellrendererbreakicon.c 2 files changed, 1 insertions(+), 1 deletions(-) =================================================================== @@ -205,7 +205,7 @@ static void cell_renderer_break_icon_render(GtkCellRenderer *cell, GdkDrawable * { CellRendererBreakIcon *cellbreakpoint = (CellRendererBreakIcon*) cell; - GdkPixbuf *pixbuf; + GdkPixbuf *pixbuf = NULL; GdkRectangle pix_rect; GdkRectangle draw_rect; Modified: debugger/src/cell_renderers/cellrendererbreakicon.h 2 files changed, 1 insertions(+), 1 deletions(-) =================================================================== @@ -54,7 +54,7 @@ struct _CellRendererBreakIconClass { GtkCellRendererClass parent_class; - void (*clicked)(GtkCellRendererToggle *cell_renderer_toggle, const gchar *path); + void (*clicked)(CellRendererBreakIcon *cell_renderer_toggle, const gchar *path); }; GType cell_renderer_break_icon_get_type(void); Modified: debugger/src/cell_renderers/cellrendererframeicon.c 343 files changed, 343 insertions(+), 0 deletions(-) =================================================================== @@ -0,0 +1,343 @@ +/* + * cellrendererframeicon.c + * + * Copyright 2012 Alexander Petukhov + * + * 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., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +/* + * cell renderer class that renders frame icon, that in turn depends on whether a + * row is the first vhildren (uppermost frame) and whether a renderer is under the cursor + */ + +#include +#include + +#include "cellrendererframeicon.h" + +enum { + PROP_0, + PROP_PIXBUF_ACTIVE, + PROP_PIXBUF_HIGHLIGHTED, + PROP_ACTIVE_FRAME, +}; + +static gpointer parent_class; +static guint clicked_signal; + +/* + * activate callback + */ +static gint cell_renderer_frame_icon_activate(GtkCellRenderer *cell, GdkEvent *event, GtkWidget *widget, const gchar *path, + GdkRectangle *background_area, GdkRectangle *cell_area, GtkCellRendererState flags) +{ + if (event->button.x >= cell_area->x && + event->button.x < (cell_area->x + cell_area->width)) + { + g_signal_emit (cell, clicked_signal, 0, path); + } + return TRUE; +} + +/* + * property getter + */ +static void cell_renderer_frame_icon_get_property(GObject *object, guint param_id, GValue *value, GParamSpec *pspec) +{ + CellRendererFrameIcon *cellframe = CELL_RENDERER_FRAME_ICON(object); + switch (param_id) + { + case PROP_PIXBUF_ACTIVE: + g_value_set_object (value, cellframe->pixbuf_active); + break; + case PROP_PIXBUF_HIGHLIGHTED: + g_value_set_object (value, cellframe->pixbuf_highlighted); + break; + case PROP_ACTIVE_FRAME: + g_value_set_boolean(value, cellframe->active_frame); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); + break; + } +} + +/* + * property setter + */ +static void cell_renderer_frame_icon_set_property (GObject *object, guint param_id, const GValue *value, GParamSpec *pspec) +{ + CellRendererFrameIcon *cellframe = CELL_RENDERER_FRAME_ICON(object); + switch (param_id) + { + case PROP_PIXBUF_ACTIVE: + if (cellframe->pixbuf_active) + { + g_object_unref(cellframe->pixbuf_active); + } + cellframe->pixbuf_active = (GdkPixbuf*)g_value_dup_object(value); + break; + case PROP_PIXBUF_HIGHLIGHTED: + if (cellframe->pixbuf_highlighted) + { + g_object_unref(cellframe->pixbuf_highlighted); + } + cellframe->pixbuf_highlighted = (GdkPixbuf*)g_value_dup_object(value); + break; + case PROP_ACTIVE_FRAME: + { + cellframe->active_frame = g_value_get_boolean(value); + break; + } + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); + break; + } +} + +/* + * get size of a cell + */ +static void cell_renderer_frame_icon_get_size(GtkCellRenderer *cell, GtkWidget *widget, GdkRectangle *cell_area, + gint *x_offset, gint *y_offset, gint *width, gint *height) +{ + CellRendererFrameIcon *cellframe = (CellRendererFrameIcon *) cell; + gint pixbuf_width = 0; + gint pixbuf_height = 0; + gint calc_width; + gint calc_height; + + if (cellframe->pixbuf_active) + { + pixbuf_width = gdk_pixbuf_get_width (cellframe->pixbuf_active); + pixbuf_height = gdk_pixbuf_get_height (cellframe->pixbuf_active); + } + if (cellframe->pixbuf_highlighted) + { + pixbuf_width = MAX (pixbuf_width, gdk_pixbuf_get_width (cellframe->pixbuf_highlighted)); + pixbuf_height = MAX (pixbuf_height, gdk_pixbuf_get_height (cellframe->pixbuf_highlighted)); + } + + calc_width = (gint) cell->xpad * 2 + pixbuf_width; + calc_height = (gint) cell->ypad * 2 + pixbuf_height; + + if (cell_area && pixbuf_width > 0 && pixbuf_height > 0) + { + if (x_offset) + { + *x_offset = (((gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL) ? + (1.0 - cell->xalign) : cell->xalign) * + (cell_area->width - calc_width)); + *x_offset = MAX (*x_offset, 0); + } + if (y_offset) + { + *y_offset = (cell->yalign * (cell_area->height - calc_height)); + *y_offset = MAX (*y_offset, 0); + } + } + else + { + if (x_offset) *x_offset = 0; + if (y_offset) *y_offset = 0; + } + + if (width) + *width = calc_width; + + if (height) + *height = calc_height; +} + +/* + * render a cell + */ +static void cell_renderer_frame_icon_render(GtkCellRenderer *cell, GdkDrawable *window, GtkWidget *widget, + GdkRectangle *background_area, GdkRectangle *cell_area, GdkRectangle *expose_area, GtkCellRendererState flags) +{ + CellRendererFrameIcon *cellframe = (CellRendererFrameIcon*) cell; + + GdkPixbuf *pixbuf = NULL; + + GdkRectangle pix_rect; + GdkRectangle draw_rect; + cairo_t *cr; + + cell_renderer_frame_icon_get_size (cell, widget, cell_area, + &pix_rect.x, + &pix_rect.y, + &pix_rect.width, + &pix_rect.height); + + pix_rect.x += cell_area->x + cell->xpad; + pix_rect.y += cell_area->y + cell->ypad; + pix_rect.width -= cell->xpad * 2; + pix_rect.height -= cell->ypad * 2; + + if (!gdk_rectangle_intersect (cell_area, &pix_rect, &draw_rect) || + !gdk_rectangle_intersect (expose_area, &draw_rect, &draw_rect)) + return; + + if (cellframe->active_frame) + { + pixbuf = cellframe->pixbuf_active; + } + else if (flags & GTK_CELL_RENDERER_PRELIT) + { + pixbuf = cellframe->pixbuf_highlighted; + } + + if (!pixbuf) + return; + + cr = gdk_cairo_create (window); + + gdk_cairo_set_source_pixbuf (cr, pixbuf, pix_rect.x, pix_rect.y); + gdk_cairo_rectangle (cr, &draw_rect); + cairo_fill (cr); + + cairo_destroy (cr); +} + +/* + * init instance + */ +static void cell_renderer_frame_icon_init (CellRendererFrameIcon *cell) +{ + cell->active_frame = FALSE; + + GtkCellRenderer *cell_renderer = (GtkCellRenderer*)cell; + + cell_renderer->mode = GTK_CELL_RENDERER_MODE_ACTIVATABLE; + + cell->pixbuf_active = cell->pixbuf_highlighted = 0; +} + +/* + * finalizes an instance (frees pixbuffers) + */ +static void cell_renderer_frame_icon_finalize (GObject *object) +{ + CellRendererFrameIcon *cell = (CellRendererFrameIcon*)object; + + GdkPixbuf *pixbufs[] = { cell->pixbuf_active, cell->pixbuf_highlighted }; + int i; + for(i = 0; i < 2; i++) + { + if (pixbufs[i]) + { + g_object_unref(pixbufs[i]); + } + } + + (*G_OBJECT_CLASS (parent_class)->finalize) (object); +} + +/* + * init class + */ +static void cell_renderer_frame_icon_class_init (CellRendererFrameIconClass *class) +{ + GObjectClass *object_class = G_OBJECT_CLASS(class); + GtkCellRendererClass *cell_class = GTK_CELL_RENDERER_CLASS(class); + + parent_class = g_type_class_peek_parent(class); + + object_class->get_property = cell_renderer_frame_icon_get_property; + object_class->set_property = cell_renderer_frame_icon_set_property; + + object_class->finalize = cell_renderer_frame_icon_finalize; + + cell_class->get_size = cell_renderer_frame_icon_get_size; + cell_class->render = cell_renderer_frame_icon_render; + + cell_class->activate = cell_renderer_frame_icon_activate; + + g_object_class_install_property (object_class, + PROP_PIXBUF_ACTIVE, + g_param_spec_object ( + "pixbuf_active", + "Pixbuf Object", + "Active frame image", + GDK_TYPE_PIXBUF, + G_PARAM_READWRITE) + ); + + g_object_class_install_property (object_class, + PROP_PIXBUF_HIGHLIGHTED, + g_param_spec_object ( + "pixbuf_highlighted", + "Pixbuf Object", + "Highlighted frame image", + GDK_TYPE_PIXBUF, + G_PARAM_READWRITE) + ); + + g_object_class_install_property (object_class, + PROP_ACTIVE_FRAME, + g_param_spec_boolean ("active_frame", "Activeness", "Is a frame active", FALSE, G_PARAM_READWRITE) + ); + + clicked_signal = g_signal_new ("clicked", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (CellRendererFrameIconClass, clicked), + NULL, NULL, + g_cclosure_marshal_VOID__STRING, + G_TYPE_NONE, 1, + G_TYPE_STRING); +} + +/* + * registers a type + */ +GType cell_renderer_frame_icon_get_type(void) +{ + static GType cell_frame_icon_type = 0; + + if(0 == cell_frame_icon_type) + { + static const GTypeInfo cell_frame_icon_info = + { + sizeof (CellRendererFrameIconClass), + NULL, /* base_init */ + NULL, /* base_finalize */ + (GClassInitFunc) cell_renderer_frame_icon_class_init, + NULL, /* class_finalize */ + NULL, /* class_data */ + sizeof (CellRendererFrameIcon), + 0, /* n_preallocs */ + (GInstanceInitFunc) cell_renderer_frame_icon_init, + }; + + /* Derive from GtkCellRenderer */ + cell_frame_icon_type = g_type_register_static (GTK_TYPE_CELL_RENDERER, + "CellRendererFrameIcon", + &cell_frame_icon_info, + 0); + } + + return cell_frame_icon_type; +} + +/* + * creates new renderer + */ +GtkCellRenderer* cell_renderer_frame_icon_new() +{ + return g_object_new(TYPE_CELL_RENDERER_FRAME_ICON, NULL); +} Modified: debugger/src/cell_renderers/cellrendererframeicon.h 61 files changed, 61 insertions(+), 0 deletions(-) =================================================================== @@ -0,0 +1,61 @@ +/* + * cellrendererframeicon.h + * + * Copyright 2012 Alexander Petukhov + * + * 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., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +#ifndef __CELL_RENDERER_FRAME_ICON_H__ +#define __CELL_RENDERER_FRAME_ICON_H__ + +#include + +G_BEGIN_DECLS + +#define TYPE_CELL_RENDERER_FRAME_ICON (cell_renderer_frame_icon_get_type ()) +#define CELL_RENDERER_FRAME_ICON(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TYPE_CELL_RENDERER_FRAME_ICON, CellRendererFrameIcon)) +#define CELL_RENDERER_FRAME_ICON_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TYPE_CELL_RENDERER_FRAME_ICON, CellRendererFrameIconClass)) +#define IS_CELL_RENDERER_FRAME_ICON(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TYPE_CELL_RENDERER_FRAME_ICON)) +#define IS_CELL_RENDERER_FRAME_ICON_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TYPE_CELL_RENDERER_FRAME_ICON)) +#define CELL_RENDERER_FRAME_ICON_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), TYPE_CELL_RENDERER_FRAME_ICON, CellRendererFrameIconClass)) + +typedef struct _CellRendererFrameIcon CellRendererFrameIcon; +typedef struct _CellRendererFrameIconClass CellRendererFrameIconClass; + +struct _CellRendererFrameIcon +{ + GtkCellRenderer parent; + + guint GSEAL (active_frame); + + GdkPixbuf *GSEAL (pixbuf_active); + GdkPixbuf *GSEAL (pixbuf_highlighted); +}; + +struct _CellRendererFrameIconClass +{ + GtkCellRendererClass parent_class; + + void (*clicked)(CellRendererFrameIcon *cell_renderer_toggle, const gchar *path); +}; + +GType cell_renderer_frame_icon_get_type(void); +GtkCellRenderer* cell_renderer_frame_icon_new (void); + +G_END_DECLS + +#endif /* __CELL_RENDERER_FRAME_ICON_H__ */ Modified: debugger/src/dbm_gdb.c 31 files changed, 30 insertions(+), 1 deletions(-) =================================================================== @@ -117,6 +117,9 @@ enum sr { and it's nessesary to refresh files list */ static gboolean file_refresh_needed = FALSE; +/* current frame number */ +static int active_frame = 0; + /* forward declarations */ void stop(); variable* add_watch(gchar* expression); @@ -499,6 +502,8 @@ static gboolean on_read_from_gdb(GIOChannel * src, GIOCondition cond, gpointer d gchar *thread_id = strstr(reason + strlen(reason) + 1,"thread-id=\"") + strlen("thread-id=\""); *(strchr(thread_id, '\"')) = '\0'; + active_frame = 0; + if (SR_BREAKPOINT_HIT == stop_reason || SR_END_STEPPING_RANGE == stop_reason) { /* update autos */ @@ -1029,6 +1034,29 @@ gboolean remove_break(breakpoint* bp) } /* + * get active frame + */ +int get_active_frame() +{ + return active_frame; +} + +/* + * select frame + */ +void set_active_frame(int frame_number) +{ + gchar *command = g_strdup_printf("-stack-select-frame %i", frame_number); + if (RC_DONE == exec_sync_command(command, TRUE, NULL)) + { + active_frame = frame_number; + update_autos(); + update_watches(); + } + g_free(command); +} + +/* * gets stack */ GList* get_stack() @@ -1452,7 +1480,7 @@ void update_autos() /* add current autos to the list */ GList *unevaluated = NULL; - const char *gdb_commands[] = { "-stack-list-arguments 0 0 0", "-stack-list-locals 0" }; + const char *gdb_commands[] = { g_strdup_printf("-stack-list-arguments 0 %i %i", active_frame, active_frame), "-stack-list-locals 0" }; int i, size = sizeof (gdb_commands) / sizeof(char*); for (i = 0; i < size; i++) { @@ -1498,6 +1526,7 @@ void update_autos() } g_free(record); } + g_free((void*)gdb_commands[0]); /* get values for the autos (without incorrect variables) */ get_variables(autos); Modified: debugger/src/debug.c 105 files changed, 77 insertions(+), 28 deletions(-) =================================================================== @@ -151,46 +151,60 @@ static GHashTable *calltips = NULL; /* - * removes stack margin markers + * remove stack margin markers */ void remove_stack_markers() { - frame *current = (frame*)stack->data; - if (current->have_source) - { - markers_remove_current_instruction(current->file, current->line); - } - GList *iter = stack->next; - while (iter) + int active_frame_index = active_module->get_active_frame(); + + GList *iter; + int frame_index; + for (iter = stack, frame_index = 0; iter; iter = iter->next, frame_index++) { - frame *next = (frame*)iter->data; - if (next->have_source) + if (iter) { - markers_remove_frame(next->file, next->line); + frame *f = (frame*)iter->data; + if (f->have_source) + { + if (active_frame_index == frame_index) + { + markers_remove_current_instruction(f->file, f->line); + } + else + { + markers_remove_frame(f->file, f->line); + } + } } - iter = iter->next; } } /* - * removes stack margin markers + * add stack margin markers */ - void add_stack_markers() +static void add_stack_markers() { - frame *current = (frame*)stack->data; - if (current->have_source) - { - markers_add_current_instruction(current->file, current->line); - } - GList *iter = stack->next; - while (iter) + int active_frame_index = active_module->get_active_frame(); + + GList *iter; + int frame_index; + for (iter = stack, frame_index = 0; iter; iter = iter->next, frame_index++) { - frame *next = (frame*)iter->data; - if (next->have_source) + if (iter) { - markers_add_frame(next->file, next->line); + frame *f = (frame*)iter->data; + if (f->have_source) + { + if (active_frame_index == frame_index) + { + markers_add_current_instruction(f->file, f->line); + } + else + { + markers_add_frame(f->file, f->line); + } + } } - iter = iter->next; } } @@ -643,7 +657,7 @@ static void on_debugger_stopped (int thread_id) } /* clear stack tree view */ - stree_set_current_thread_id(thread_id); + stree_set_active_thread_id(thread_id); /* get current stack trace and put in the tree view */ stack = active_module->get_stack(); @@ -806,7 +820,7 @@ static void on_debugger_exited (int code) /* * called from debugger module to show a message in debugger messages pane */ -static void on_debugger_message (const gchar* message, const gchar *color) +void on_debugger_message (const gchar* message, const gchar *color) { gchar *msg = g_strdup_printf("%s\n", message); @@ -873,6 +887,33 @@ static void on_thread_added (int thread_id) * Interface functions */ +/* + * called when a frame in the stack tree has been selected + */ +static void on_select_frame(int frame_number) +{ + frame *f = (frame*)g_list_nth(stack, active_module->get_active_frame())->data; + markers_remove_current_instruction(f->file, f->line); + markers_add_frame(f->file, f->line); + + active_module->set_active_frame(frame_number); + + /* clear calltips cache */ + g_hash_table_remove_all(calltips); + + /* autos */ + GList *autos = active_module->get_autos(); + update_variables(GTK_TREE_VIEW(atree), NULL, autos); + + /* watches */ + GList *watches = active_module->get_watches(); + update_variables(GTK_TREE_VIEW(wtree), NULL, watches); + + f = (frame*)g_list_nth(stack, frame_number)->data; + markers_remove_frame(f->file, f->line); + markers_add_current_instruction(f->file, f->line); +} + /* * init debug related GUI (watch tree view) * arguments: @@ -909,7 +950,7 @@ void debug_init() gtk_container_add(GTK_CONTAINER(tab_autos), atree); /* create stack trace page */ - stree = stree_init(editor_open_position); + stree = stree_init(editor_open_position, on_select_frame); tab_call_stack = gtk_scrolled_window_new( gtk_tree_view_get_hadjustment(GTK_TREE_VIEW(stree )), gtk_tree_view_get_vadjustment(GTK_TREE_VIEW(stree )) @@ -1314,3 +1355,11 @@ void debug_on_file_open(GeanyDocument *doc) if (g_list_find_custom(read_only_pages, (gpointer)file, (GCompareFunc)g_strcmp0)) scintilla_send_message(doc->editor->sci, SCI_SETREADONLY, 1, 0); } + +/* + * get active frame index + */ +int debug_get_active_frame() +{ + return active_module->get_active_frame(); +} Modified: debugger/src/debug.h 1 files changed, 1 insertions(+), 0 deletions(-) =================================================================== @@ -48,4 +48,5 @@ gchar* debug_get_calltip_for_expression(gchar* expression); GList* debug_get_stack(); void debug_restart(); +int debug_get_active_frame(); Modified: debugger/src/debug_module.h 8 files changed, 7 insertions(+), 1 deletions(-) =================================================================== @@ -108,8 +108,12 @@ enum dbs { gboolean (*set_break) (breakpoint* bp, break_set_activity bsa); gboolean (*remove_break) (breakpoint* bp); + GList* (*get_stack) (); - + + void (*set_active_frame)(int frame_number); + int (*get_active_frame)(); + GList* (*get_autos) (); GList* (*get_watches) (); @@ -141,6 +145,8 @@ enum dbs { set_break, \ remove_break, \ get_stack, \ + set_active_frame, \ + get_active_frame, \ get_autos, \ get_watches, \ get_files, \ Modified: debugger/src/pixbuf.h 1 files changed, 1 insertions(+), 0 deletions(-) =================================================================== @@ -27,6 +27,7 @@ extern GdkPixbuf *local_pixbuf; extern GdkPixbuf *watch_pixbuf; +extern GdkPixbuf *frame_pixbuf; extern GdkPixbuf *frame_current_pixbuf; void pixbufs_init(); Modified: debugger/src/stree.c 172 files changed, 112 insertions(+), 60 deletions(-) =================================================================== @@ -36,6 +36,8 @@ #include "debug_module.h" #include "pixbuf.h" +#include "cell_renderers/cellrendererframeicon.h" + /* Tree view columns */ enum { @@ -46,25 +48,57 @@ enum S_LAST_VISIBLE, S_HAVE_SOURCE, S_THREAD_ID, + S_ACTIVE, S_N_COLUMNS }; /* hash table to keep thread nodes in the tree */ static GHashTable *threads; -/* current_thread_id */ -static glong current_thread_id = 0; +/* active thread and frame */ +static glong active_thread_id = 0; +static int active_frame_index = 0; -/* double click callback pointer */ -static move_to_line_cb callback = NULL; +/* callbacks */ +static select_frame_cb select_frame = NULL; +static move_to_line_cb move_to_line = NULL; /* tree view, model and store handles */ -static GtkWidget* tree = NULL; -static GtkTreeModel* model = NULL; -static GtkTreeStore* store = NULL; +static GtkWidget *tree = NULL; +static GtkTreeModel *model = NULL; +static GtkTreeStore *store = NULL; -/* selection callback id */ -static gulong selection_callback = 0; +/* cell renderer for a frame arrow */ +static GtkCellRenderer *renderer_arrow = NULL; + +/* + * frame arrow clicked callback + */ +static void on_frame_arrow_clicked(CellRendererFrameIcon *cell_renderer, gchar *path, gpointer user_data) +{ + GtkTreePath *new_active_frame = gtk_tree_path_new_from_string (path); + if (gtk_tree_path_get_indices(new_active_frame)[1] != active_frame_index) + { + GtkTreeIter iter; + + GtkTreeRowReference *reference = (GtkTreeRowReference*)g_hash_table_lookup(threads, (gpointer)active_thread_id); + GtkTreePath *old_active_frame = gtk_tree_row_reference_get_path(reference); + gtk_tree_path_append_index(old_active_frame, active_frame_index); + + gtk_tree_model_get_iter(model, &iter, old_active_frame); + gtk_tree_store_set (store, &iter, S_ACTIVE, FALSE, -1); + + active_frame_index = gtk_tree_path_get_indices(new_active_frame)[1]; + select_frame(active_frame_index); + + gtk_tree_model_get_iter(model, &iter, new_active_frame); + gtk_tree_store_set (store, &iter, S_ACTIVE, TRUE, -1); + + gtk_tree_path_free(old_active_frame); + } + + gtk_tree_path_free(new_active_frame); +} /* * shows a tooltip for a file name @@ -79,21 +113,33 @@ static gboolean on_query_tooltip(GtkWidget *widget, gint x, gint y, gboolean key GtkTreeViewColumn *column = NULL; if (gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(widget), bx, by, &tpath, &column, NULL, NULL)) { - if (2 == gtk_tree_path_get_depth(tpath) && column == gtk_tree_view_get_column(GTK_TREE_VIEW(widget), S_FILEPATH)) + if (2 == gtk_tree_path_get_depth(tpath)) { - GtkTreeIter iter; - gtk_tree_model_get_iter(model, &iter, tpath); - - gchar *path = NULL; - gtk_tree_model_get(model, &iter, S_FILEPATH, &path, -1); - - gtk_tooltip_set_text(tooltip, path); - - gtk_tree_view_set_tooltip_row(GTK_TREE_VIEW(widget), tooltip, tpath); - - show = TRUE; + gint start_pos, width; + gtk_tree_view_column_cell_get_position(column, renderer_arrow, &start_pos, &width); + + if (column == gtk_tree_view_get_column(GTK_TREE_VIEW(widget), S_FILEPATH)) + { + GtkTreeIter iter; + gtk_tree_model_get_iter(model, &iter, tpath); + + gchar *path = NULL; + gtk_tree_model_get(model, &iter, S_FILEPATH, &path, -1); + + gtk_tooltip_set_text(tooltip, path); + + gtk_tree_view_set_tooltip_row(GTK_TREE_VIEW(widget), tooltip, tpath); + + show = TRUE; - g_free(path); + g_free(path); + } + else if (column == gtk_tree_view_get_column(GTK_TREE_VIEW(widget), S_ADRESS && bx >= start_pos && bx < start_pos + width)) + { + gtk_tooltip_set_text(tooltip, gtk_tree_path_get_indices(tpath)[1] == active_frame_index ? _("Active frame") : _("Switch to a frame")); + gtk_tree_view_set_tooltip_row(GTK_TREE_VIEW(widget), tooltip, tpath); + show = TRUE; + } } gtk_tree_path_free(tpath); } @@ -102,17 +148,13 @@ static gboolean on_query_tooltip(GtkWidget *widget, gint x, gint y, gboolean key } /* - * shows arrow icon for the current frame, hides renderer for a thread row + * shows arrow icon for the frame rows, hides renderer for a thread ones */ -static void on_render_icon(GtkTreeViewColumn *tree_column, GtkCellRenderer *cell, GtkTreeModel *tree_model, +static void on_render_arrow(GtkTreeViewColumn *tree_column, GtkCellRenderer *cell, GtkTreeModel *tree_model, GtkTreeIter *iter, gpointer data) { GtkTreePath *tpath = gtk_tree_model_get_path(model, iter); - gboolean frame_row = 1 != gtk_tree_path_get_depth(tpath); - - g_object_set(cell, "visible", frame_row, NULL); - g_object_set(cell, "pixbuf", (frame_row && 0 == gtk_tree_path_get_indices(tpath)[1]) ? (gpointer)frame_current_pixbuf : NULL, NULL); - + g_object_set(cell, "visible", 1 != gtk_tree_path_get_depth(tpath), NULL); gtk_tree_path_free(tpath); } @@ -123,7 +165,7 @@ static void on_render_line(GtkTreeViewColumn *tree_column, GtkCellRenderer *cell GtkTreeIter *iter, gpointer data) { GtkTreePath *tpath = gtk_tree_model_get_path(model, iter); - + if (1 == gtk_tree_path_get_depth(tpath)) { g_object_set(cell, "text", "", NULL); @@ -169,7 +211,8 @@ static gboolean on_msgwin_button_press(GtkWidget *widget, GdkEventButton *event, if (event->type == GDK_BUTTON_PRESS) { GtkTreePath *pressed_path = NULL; - if (gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(tree), (int)event->x, (int)event->y, &pressed_path, NULL, NULL, NULL)) + GtkTreeViewColumn *column = NULL; + if (gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(tree), (int)event->x, (int)event->y, &pressed_path, &column, NULL, NULL)) { if (2 == gtk_tree_path_get_depth(pressed_path)) { @@ -203,7 +246,7 @@ static gboolean on_msgwin_button_press(GtkWidget *widget, GdkEventButton *event, S_FILEPATH, &file, S_LINE, &line, -1); - callback(file, line); + move_to_line(file, line); g_free(file); } @@ -223,8 +266,13 @@ static gboolean on_msgwin_button_press(GtkWidget *widget, GdkEventButton *event, /* * Tree view selection changed callback */ -void on_selection_changed(GtkTreeSelection *treeselection, gpointer user_data) +static void on_selection_changed(GtkTreeSelection *treeselection, gpointer user_data) { + if (!gtk_tree_selection_count_selected_rows(treeselection)) + { + return; + } + GList *rows = gtk_tree_selection_get_selected_rows(treeselection, &model); GtkTreePath *path = (GtkTreePath*)rows->data; @@ -232,7 +280,7 @@ void on_selection_changed(GtkTreeSelection *treeselection, gpointer user_data) { GtkTreeIter iter; gtk_tree_model_get_iter ( - gtk_tree_view_get_model(GTK_TREE_VIEW(tree)), + model, &iter, path); gboolean have_source; @@ -253,8 +301,8 @@ void on_selection_changed(GtkTreeSelection *treeselection, gpointer user_data) S_FILEPATH, &file, S_LINE, &line, -1); - callback(file, line); - + + move_to_line(file, line); g_free(file); } } @@ -266,9 +314,10 @@ void on_selection_changed(GtkTreeSelection *treeselection, gpointer user_data) /* * inits stack trace tree */ -GtkWidget* stree_init(move_to_line_cb cb) +GtkWidget* stree_init(move_to_line_cb ml, select_frame_cb sf) { - callback = cb; + move_to_line = ml; + select_frame = sf; /* create tree view */ store = gtk_tree_store_new ( @@ -279,6 +328,7 @@ void on_selection_changed(GtkTreeSelection *treeselection, gpointer user_data) G_TYPE_INT, G_TYPE_STRING, G_TYPE_INT, + G_TYPE_INT, G_TYPE_INT); model = GTK_TREE_MODEL(store); @@ -290,12 +340,11 @@ void on_selection_changed(GtkTreeSelection *treeselection, gpointer user_data) gtk_tree_view_set_show_expanders(GTK_TREE_VIEW(tree), FALSE); /* connect signals */ - - selection_callback = g_signal_connect(G_OBJECT(gtk_tree_view_get_selection(GTK_TREE_VIEW(tree))), "changed", G_CALLBACK (on_selection_changed), NULL); + g_signal_connect(G_OBJECT(gtk_tree_view_get_selection(GTK_TREE_VIEW(tree))), "changed", G_CALLBACK (on_selection_changed), NULL); /* for clicking on already selected frame */ g_signal_connect(G_OBJECT(tree), "button-press-event", G_CALLBACK(on_msgwin_button_press), NULL); - + g_signal_connect(G_OBJECT(tree), "query-tooltip", G_CALLBACK (on_query_tooltip), NULL); /* creating columns */ @@ -305,15 +354,18 @@ void on_selection_changed(GtkTreeSelection *treeselection, gpointer user_data) column = gtk_tree_view_column_new(); gtk_tree_view_column_set_title(column, _("Address")); - GtkCellRenderer *renderer_arrow = gtk_cell_renderer_pixbuf_new (); + renderer_arrow = cell_renderer_frame_icon_new (); + g_object_set(renderer_arrow, "pixbuf_active", (gpointer)frame_current_pixbuf, NULL); + g_object_set(renderer_arrow, "pixbuf_highlighted", (gpointer)frame_pixbuf, NULL); gtk_tree_view_column_pack_start(column, renderer_arrow, TRUE); - gtk_tree_view_column_set_cell_data_func(column, renderer_arrow, on_render_icon, NULL, NULL); + gtk_tree_view_column_set_attributes(column, renderer_arrow, "active_frame", S_ACTIVE, NULL); + gtk_tree_view_column_set_cell_data_func(column, renderer_arrow, on_render_arrow, NULL, NULL); + g_signal_connect (G_OBJECT(renderer_arrow), "clicked", G_CALLBACK(on_frame_arrow_clicked), NULL); GtkCellRenderer *renderer_address = gtk_cell_renderer_text_new (); gtk_tree_view_column_pack_start(column, renderer_address, TRUE); gtk_tree_view_column_set_attributes(column, renderer_address, "text", S_ADRESS, NULL); - gtk_tree_view_column_set_resizable (column, TRUE); gtk_tree_view_append_column (GTK_TREE_VIEW (tree), column); /* function */ @@ -357,7 +409,7 @@ void on_selection_changed(GtkTreeSelection *treeselection, gpointer user_data) */ void stree_add(frame *f) { - GtkTreeRowReference *reference = (GtkTreeRowReference*)g_hash_table_lookup(threads, (gpointer)current_thread_id); + GtkTreeRowReference *reference = (GtkTreeRowReference*)g_hash_table_lookup(threads, (gpointer)active_thread_id); GtkTreeIter thread_iter; gtk_tree_model_get_iter(model, &thread_iter, gtk_tree_row_reference_get_path(reference)); @@ -378,12 +430,8 @@ void stree_add(frame *f) */ void stree_clear() { - g_signal_handler_disconnect(G_OBJECT(gtk_tree_view_get_selection(GTK_TREE_VIEW(tree))), selection_callback); - gtk_tree_store_clear(store); g_hash_table_remove_all(threads); - - selection_callback = g_signal_connect(G_OBJECT(gtk_tree_view_get_selection(GTK_TREE_VIEW(tree))), "changed", G_CALLBACK (on_selection_changed), NULL); } /* @@ -393,18 +441,22 @@ void stree_select_first_frame() { gtk_tree_view_expand_all(GTK_TREE_VIEW(tree)); - GtkTreeRowReference *reference = (GtkTreeRowReference*)g_hash_table_lookup(threads, (gpointer)current_thread_id); + GtkTreeRowReference *reference = (GtkTreeRowReference*)g_hash_table_lookup(threads, (gpointer)active_thread_id); GtkTreeIter thread_iter, frame_iter; gtk_tree_model_get_iter(model, &thread_iter, gtk_tree_row_reference_get_path(reference)); if(gtk_tree_model_iter_children(model, &frame_iter, &thread_iter)) { + gtk_tree_store_set (store, &frame_iter, S_ACTIVE, TRUE, -1); + GtkTreePath* path = gtk_tree_model_get_path(model, &frame_iter); gtk_tree_selection_select_path ( gtk_tree_view_get_selection(GTK_TREE_VIEW(tree)), path); - + gtk_tree_path_free(path); + + active_frame_index = 0; } } @@ -413,8 +465,11 @@ void stree_select_first_frame() */ void stree_destroy() { - g_hash_table_destroy(threads); - threads = NULL; + if (threads) + { + g_hash_table_destroy(threads); + threads = NULL; + } } /* @@ -477,6 +532,7 @@ void stree_remove_thread(int thread_id) gtk_tree_model_get_iter(model, &iter, tpath); gtk_tree_store_remove(store, &iter); + g_hash_table_remove(threads, (gpointer)(glong)thread_id); } @@ -485,26 +541,22 @@ void stree_remove_thread(int thread_id) */ void stree_remove_frames() { - GtkTreeRowReference *reference = (GtkTreeRowReference*)g_hash_table_lookup(threads, (gpointer)current_thread_id); + GtkTreeRowReference *reference = (GtkTreeRowReference*)g_hash_table_lookup(threads, (gpointer)active_thread_id); GtkTreeIter thread_iter; gtk_tree_model_get_iter(model, &thread_iter, gtk_tree_row_reference_get_path(reference)); - g_signal_handler_disconnect(G_OBJECT(gtk_tree_view_get_selection(GTK_TREE_VIEW(tree))), selection_callback); - GtkTreeIter child; if (gtk_tree_model_iter_children(model, &child, &thread_iter)) { while(gtk_tree_store_remove(GTK_TREE_STORE(model), &child)) ; } - - selection_callback = g_signal_connect(G_OBJECT(gtk_tree_view_get_selection(GTK_TREE_VIEW(tree))), "changed", G_CALLBACK (on_selection_changed), NULL); } /* * set current thread id */ -void stree_set_current_thread_id(int thread_id) +void stree_set_active_thread_id(int thread_id) { - current_thread_id = thread_id; + active_thread_id = thread_id; } Modified: debugger/src/stree.h 4 files changed, 2 insertions(+), 2 deletions(-) =================================================================== @@ -19,7 +19,7 @@ * MA 02110-1301, USA. */ -GtkWidget* stree_init(move_to_line_cb cb); +GtkWidget* stree_init(move_to_line_cb ml, select_frame_cb sf); void stree_destroy(); void stree_add(frame *f); @@ -31,4 +31,4 @@ void stree_select_first_frame(); void stree_remove_frames(); -void stree_set_current_thread_id(int thread_id); +void stree_set_active_thread_id(int thread_id); Modified: debugger/src/utils.h 2 files changed, 1 insertions(+), 1 deletions(-) =================================================================== @@ -19,5 +19,5 @@ * MA 02110-1301, USA. */ -void editor_open_position(char* file, int line); +void editor_open_position(const char* file, int line); GString* get_word_at_position(ScintillaObject *sci, int position); -------------- This E-Mail was brought to you by github_commit_mail.py (Source: TBD). From git-noreply at xxxxx Sun Mar 18 03:41:15 2012 From: git-noreply at xxxxx (=?utf-8?q?Colomban_Wendling?=) Date: Sun, 18 Mar 2012 03:41:15 -0000 Subject: [geany/geany-plugins] a6c0fc: Wrap Words Addon: fix an invalid memory write Message-ID: <20120321192726.9D311254011@uvena.de> Branch: refs/heads/master Author: Colomban Wendling Committer: Colomban Wendling Date: Sun, 18 Mar 2012 03:41:15 Commit: a6c0fc67b0e9c5c2dd345b6348cdc4ca567a1a99 https://github.com/geany/geany-plugins/commit/a6c0fc67b0e9c5c2dd345b6348cdc4ca567a1a99 Log Message: ----------- Wrap Words Addon: fix an invalid memory write key_name allocation was one byte too small (missing alloc for the trailing 0) and thus possibly leading to a crash. Modified Paths: -------------- addons/src/ao_wrapwords.c Modified: addons/src/ao_wrapwords.c 15 files changed, 3 insertions(+), 12 deletions(-) =================================================================== @@ -137,14 +137,12 @@ gboolean on_key_press (GtkWidget *widget, GdkEventKey *event, gpointer user_data void ao_enclose_words_init (gchar *config_file_name, GeanyKeyGroup *key_group) { GKeyFile *config = g_key_file_new(); - gchar *key_name = g_malloc0 (9); + gchar key_name[] = "Enclose_x"; gint i; config_file = g_strdup (config_file_name); g_key_file_load_from_file (config, config_file, G_KEY_FILE_NONE, NULL); - g_stpcpy (key_name, "Enclose_x"); - for (i = 0; i < 8; i++) { key_name [8] = (gchar) (i + '0'); @@ -157,8 +155,6 @@ void ao_enclose_words_init (gchar *config_file_name, GeanyKeyGroup *key_group) plugin_signal_connect(geany_plugin, G_OBJECT(geany->main_widgets->window), "key-press-event", FALSE, G_CALLBACK(on_key_press), NULL); - - g_free (key_name); } void ao_enclose_words_set_enabled (gboolean enabled_w, gboolean enabled_a) @@ -178,20 +174,16 @@ void configure_response (GtkDialog *dialog, gint response, gpointer char_tree_vi GKeyFile *config = g_key_file_new(); gchar *config_data = NULL; gchar *prior_char_str, *end_char_str; - gchar *key_name = g_malloc0 (9); + gchar key_name[] = "Enclose_x"; gint i; - if (response != GTK_RESPONSE_OK && response != GTK_RESPONSE_ACCEPT) { - g_free (key_name); + if (response != GTK_RESPONSE_OK && response != GTK_RESPONSE_ACCEPT) return; - } gtk_tree_model_get_iter_first (GTK_TREE_MODEL(chars_list), &char_iter); g_key_file_load_from_file(config, config_file, G_KEY_FILE_NONE, NULL); - g_stpcpy (key_name, "Enclose_x"); - for (i = 0; i < 8; i++) { key_name [8] = (gchar) (i + '0'); @@ -211,7 +203,6 @@ void configure_response (GtkDialog *dialog, gint response, gpointer char_tree_vi g_free (prior_char_str); g_free (end_char_str); g_free (config_data); - g_free (key_name); g_key_file_free(config); } -------------- This E-Mail was brought to you by github_commit_mail.py (Source: TBD). From git-noreply at xxxxx Sun Mar 18 03:41:15 2012 From: git-noreply at xxxxx (=?utf-8?q?Colomban_Wendling?=) Date: Sun, 18 Mar 2012 03:41:15 -0000 Subject: [geany/geany-plugins] fba329: Wrap Words Addon: don't mix declaration and code to be C89 compliant Message-ID: <20120321192727.301CB254011@uvena.de> Branch: refs/heads/master Author: Colomban Wendling Committer: Colomban Wendling Date: Sun, 18 Mar 2012 03:41:15 Commit: fba329e4a2a159e2ccf39a1ea7bc6ec5fc41ccd3 https://github.com/geany/geany-plugins/commit/fba329e4a2a159e2ccf39a1ea7bc6ec5fc41ccd3 Log Message: ----------- Wrap Words Addon: don't mix declaration and code to be C89 compliant Modified Paths: -------------- addons/src/ao_wrapwords.c Modified: addons/src/ao_wrapwords.c 8 files changed, 5 insertions(+), 3 deletions(-) =================================================================== @@ -48,12 +48,14 @@ enum void enclose_text_action (guint key_id) { + gint selection_end; + gchar insert_chars [2] = {0, 0}; + ScintillaObject *sci_obj; + if (!enclose_enabled) return; - gint selection_end; - gchar insert_chars [2] = {0, 0}; - ScintillaObject *sci_obj = document_get_current ()->editor->sci; + sci_obj = document_get_current ()->editor->sci; if (sci_get_selected_text_length (sci_obj) < 2) return; -------------- This E-Mail was brought to you by github_commit_mail.py (Source: TBD). From git-noreply at xxxxx Sun Mar 18 03:41:19 2012 From: git-noreply at xxxxx (=?utf-8?q?Colomban_Wendling?=) Date: Sun, 18 Mar 2012 03:41:19 -0000 Subject: [geany/geany-plugins] ec51ba: Wrap Words Addon: plug some memory leaks Message-ID: <20120321192727.C80305A048@uvena.de> Branch: refs/heads/master Author: Colomban Wendling Committer: Colomban Wendling Date: Sun, 18 Mar 2012 03:41:19 Commit: ec51ba318d2976c5c11da004ea0fa9340eea0e70 https://github.com/geany/geany-plugins/commit/ec51ba318d2976c5c11da004ea0fa9340eea0e70 Log Message: ----------- Wrap Words Addon: plug some memory leaks Modified Paths: -------------- addons/src/ao_wrapwords.c Modified: addons/src/ao_wrapwords.c 19 files changed, 11 insertions(+), 8 deletions(-) =================================================================== @@ -173,9 +173,8 @@ void ao_enclose_words_set_enabled (gboolean enabled_w, gboolean enabled_a) void configure_response (GtkDialog *dialog, gint response, gpointer char_tree_view) { GtkTreeIter char_iter; - GKeyFile *config = g_key_file_new(); + GKeyFile *config; gchar *config_data = NULL; - gchar *prior_char_str, *end_char_str; gchar key_name[] = "Enclose_x"; gint i; @@ -184,10 +183,13 @@ void configure_response (GtkDialog *dialog, gint response, gpointer char_tree_vi gtk_tree_model_get_iter_first (GTK_TREE_MODEL(chars_list), &char_iter); + config = g_key_file_new(); g_key_file_load_from_file(config, config_file, G_KEY_FILE_NONE, NULL); for (i = 0; i < 8; i++) { + gchar *prior_char_str, *end_char_str; + key_name [8] = (gchar) (i + '0'); gtk_tree_model_get (GTK_TREE_MODEL(chars_list), &char_iter, @@ -197,13 +199,14 @@ void configure_response (GtkDialog *dialog, gint response, gpointer char_tree_vi gtk_tree_model_iter_next (GTK_TREE_MODEL(chars_list), &char_iter); g_key_file_set_string (config, "addons", key_name, enclose_chars [i]); + + g_free (prior_char_str); + g_free (end_char_str); } config_data = g_key_file_to_data (config, NULL, NULL); utils_write_file (config_file, config_data); - g_free (prior_char_str); - g_free (end_char_str); g_free (config_data); g_key_file_free(config); } @@ -236,7 +239,6 @@ void ao_enclose_words_config (GtkButton *button, GtkWidget *config_window) GtkTreeViewColumn *label_column, *char_one_column, *char_two_column; GtkTreeView *chars_tree_view; gchar insert_chars [2] = {0, 0}; - gchar *title; gint i; dialog = gtk_dialog_new_with_buttons(_("Plugins"), GTK_WINDOW(config_window), @@ -250,13 +252,16 @@ void ao_enclose_words_config (GtkButton *button, GtkWidget *config_window) for (i = 0; i < 8; i++) { + gchar *title = g_strdup_printf (_("Enclose combo %d"), i + 1); + gtk_list_store_append (chars_list, &chars_iter); - title = g_strdup_printf (_("Enclose combo %d"), i + 1); gtk_list_store_set (chars_list, &chars_iter, COLUMN_TITLE, title, -1); insert_chars [0] = *enclose_chars [i]; gtk_list_store_set (chars_list, &chars_iter, COLUMN_PRIOR_CHAR, insert_chars, -1); insert_chars [0] = *(enclose_chars [i] + 1); gtk_list_store_set (chars_list, &chars_iter, COLUMN_END_CHAR, insert_chars, -1); + + g_free(title); } label_column = gtk_tree_view_column_new_with_attributes ("", renderer, "text", 0, NULL); @@ -286,7 +291,5 @@ void ao_enclose_words_config (GtkButton *button, GtkWidget *config_window) g_signal_connect (dialog, "response", G_CALLBACK (configure_response), NULL); while (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT); gtk_widget_destroy (GTK_WIDGET (dialog)); - - g_free (title); } -------------- This E-Mail was brought to you by github_commit_mail.py (Source: TBD). From git-noreply at xxxxx Sat Mar 24 13:07:11 2012 From: git-noreply at xxxxx (=?utf-8?q?Frank_Lanitz?=) Date: Sat, 24 Mar 2012 13:07:11 -0000 Subject: [geany/geany-plugins] e8887e: GeanyLaTeX: Added a feature to convert selection to lowercase in case of inserting \textsc{} Message-ID: <20120324130743.292C725401D@uvena.de> Branch: refs/heads/master Author: Frank Lanitz Committer: Frank Lanitz Date: Sat, 24 Mar 2012 13:07:11 Commit: e8887eaaa63d7cdff38472bf04c531b1625fea24 https://github.com/geany/geany-plugins/commit/e8887eaaa63d7cdff38472bf04c531b1625fea24 Log Message: ----------- GeanyLaTeX: Added a feature to convert selection to lowercase in case of inserting \textsc{} Modified Paths: -------------- geanylatex/doc/geanylatex.pdf geanylatex/doc/geanylatex.tex geanylatex/src/formatutils.c geanylatex/src/geanylatex.c geanylatex/src/geanylatex.h Modified: geanylatex/doc/geanylatex.pdf 0 files changed, 0 insertions(+), 0 deletions(-) =================================================================== No diff available, check online Modified: geanylatex/doc/geanylatex.tex 13 files changed, 12 insertions(+), 1 deletions(-) =================================================================== @@ -94,7 +94,8 @@ \section{About the plugin} \section{News \& ChangeLog} \subsection{Geany\LaTeX{} 0.7} \begin{itemize} - \item None by now. + \item Added a feature to lower selection before inserting + \texttt{\textbackslash{}textsc\{\}} \end{itemize} \subsection{Geany\LaTeX{} 0.6 -- 2011-10-15} \begin{itemize} @@ -538,6 +539,16 @@ \subsection{Inserting \textbackslash{}usepackage\{\}-entry to header} \caption{Dialog for inserting \textbackslash{}usepackage\{\}} \end{figure} +\subsection{Lower selection before inserting \textbackslash{}textsc\{\}} + +With this feature, converting a normal text to \LaTeX{} is getting a +bit easier. If you start a document as plain text, with +abbreviations in it like ABC. You import it into \LaTeX{}, and want +the abbreviations in small caps. Geany\LaTeX{} converts the +selection to just use lower case letters. So \texttt{ABC} is +becoming \texttt{\textbackslash{}textsc\{abc\}} and later \textsc +{abc}. This can be configured via the plugin configuration dialog +and default value is turned off. \section{Configuration} Modified: geanylatex/src/formatutils.c 10 files changed, 10 insertions(+), 0 deletions(-) =================================================================== @@ -20,6 +20,7 @@ */ #include "formatutils.h" +#include "string.h" void glatex_insert_latex_format(G_GNUC_UNUSED GtkMenuItem * menuitem, @@ -38,6 +39,15 @@ void glatex_insert_latex_format(G_GNUC_UNUSED GtkMenuItem * menuitem, selection = sci_get_selection_contents(doc->editor->sci); + if (format == LATEX_SMALLCAPS && + glatex_lowercase_on_smallcaps == TRUE) + { + gchar *new_selection = NULL; + new_selection = g_utf8_strdown(selection, -1); + g_free(selection); + selection = g_strdup(new_selection); + g_free(new_selection); + } replacement = g_strconcat(glatex_format_pattern[format],"{", selection, "}", NULL); Modified: geanylatex/src/geanylatex.c 15 files changed, 15 insertions(+), 0 deletions(-) =================================================================== @@ -93,6 +93,8 @@ static gint glatex_autocompletion_context_size; static gboolean glatex_autocompletion_only_for_latex; gboolean glatex_autobraces_active = TRUE; +gboolean glatex_lowercase_on_smallcaps = FALSE; + /* Function will be deactivated, when only loaded */ static gboolean toggle_active = FALSE; @@ -146,6 +148,7 @@ GtkWidget *glatex_autocompletion_active; GtkWidget *glatex_capitalize_sentence; GtkWidget *wizard_to_generic_toolbar; + GtkWidget *lower_selection_on_smallcaps; } config_widgets; @@ -201,6 +204,8 @@ gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(config_widgets.glatex_capitalize_sentence)); glatex_wizard_to_generic_toolbar = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(config_widgets.wizard_to_generic_toolbar)); + glatex_lowercase_on_smallcaps = + gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(config_widgets.lower_selection_on_smallcaps)); /* Check the response code for geanyLaTeX's autocompletion functions. * Due compatibility with oder Geany versions cass 0 will be treated @@ -221,6 +226,8 @@ glatex_set_toolbar_active); g_key_file_set_boolean(config, "general", "glatex_set_autocompletion", glatex_autocompletion_active); + g_key_file_set_boolean(config, "general", "glatex_lowercase_on_smallcaps", + glatex_lowercase_on_smallcaps); g_key_file_set_boolean(config, "autocompletion", "glatex_capitalize_sentence_starts", glatex_capitalize_sentence_starts); g_key_file_set_boolean(config, "toolbar", "glatex_wizard_to_generic_toolbar", @@ -295,6 +302,8 @@ _("Capitalize sentence on typing")); config_widgets.wizard_to_generic_toolbar = gtk_check_button_new_with_label( _("Add a wizard icon to Geany's main toolbar")); + config_widgets.lower_selection_on_smallcaps = gtk_check_button_new_with_label( + _("Lower selection when formating smallcaps (\\textsc{})")); config_widgets.glatex_autocompletion_active = gtk_combo_box_new_text(); gtk_combo_box_insert_text(GTK_COMBO_BOX(config_widgets.glatex_autocompletion_active), 0, @@ -310,6 +319,7 @@ tmp = 1; else tmp = 0; + gtk_combo_box_set_active(GTK_COMBO_BOX(config_widgets.glatex_autocompletion_active), tmp); label_autocompletion = gtk_label_new(_("Modus of autocompletion")); @@ -328,6 +338,9 @@ gtk_box_pack_start(GTK_BOX(vbox), config_widgets.glatex_capitalize_sentence, FALSE, FALSE, 2); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(config_widgets.wizard_to_generic_toolbar), glatex_wizard_to_generic_toolbar); + gtk_box_pack_start(GTK_BOX(vbox), config_widgets.lower_selection_on_smallcaps, FALSE, FALSE, 2); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(config_widgets.lower_selection_on_smallcaps), + glatex_lowercase_on_smallcaps); gtk_box_pack_start(GTK_BOX(vbox), config_widgets.wizard_to_generic_toolbar, FALSE, FALSE, 2); gtk_box_pack_start(GTK_BOX(vbox), hbox_autocompletion, FALSE, FALSE, 2); @@ -1998,6 +2011,8 @@ static void glatex_init_configuration() "glatex_set_autocompletion", TRUE); glatex_autobraces_active = utils_get_setting_boolean(config, "autocompletion", "glatex_set_autobraces", TRUE); + glatex_lowercase_on_smallcaps = utils_get_setting_boolean(config, "general", + "glatex_lowercase_on_smallcaps", FALSE); /* Hidden preferences. Can be set directly via configuration file*/ glatex_autocompletion_context_size = utils_get_setting_integer(config, "autocompletion", Modified: geanylatex/src/geanylatex.h 1 files changed, 1 insertions(+), 0 deletions(-) =================================================================== @@ -60,6 +60,7 @@ extern LaTeXWizard glatex_wizard; extern gboolean glatex_autobraces_active; +extern gboolean glatex_lowercase_on_smallcaps; gint glatex_count_menu_entries(SubMenuTemplate *tmp, gint categorie); void glatex_wizard_activated(G_GNUC_UNUSED GtkMenuItem * menuitem, -------------- This E-Mail was brought to you by github_commit_mail.py (Source: TBD). From git-noreply at xxxxx Sun Mar 25 18:42:54 2012 From: git-noreply at xxxxx (=?utf-8?q?Matthew_Brush?=) Date: Sun, 25 Mar 2012 18:42:54 -0000 Subject: [geany/geany-plugins] 32bec5: multiterm: Fix use of deprecated function Message-ID: <20120325201846.99B46254016@uvena.de> Branch: refs/heads/master Author: Matthew Brush Committer: Matthew Brush Date: Sun, 25 Mar 2012 18:42:54 Commit: 32bec5c6adf9a05c035f95852caa332f16af7364 https://github.com/geany/geany-plugins/commit/32bec5c6adf9a05c035f95852caa332f16af7364 Log Message: ----------- multiterm: Fix use of deprecated function Modified Paths: -------------- multiterm/src/terminal.vala Modified: multiterm/src/terminal.vala 4 files changed, 2 insertions(+), 2 deletions(-) =================================================================== @@ -130,9 +130,9 @@ namespace MultiTerm terminal.child_exited.connect(on_child_exited); if (this.sh.cfg != null) - terminal.set_font_from_string_full(this.sh.font, TerminalAntiAlias.FORCE_ENABLE); + terminal.set_font_from_string(this.sh.font); else - terminal.set_font_from_string_full("Monospace 9", TerminalAntiAlias.FORCE_ENABLE); + terminal.set_font_from_string("Monospace 9"); terminal.realize.connect(on_vte_realize); /* colors can only be set on realize (lame) */ run_command(this.sh.command); -------------- This E-Mail was brought to you by github_commit_mail.py (Source: TBD). From git-noreply at xxxxx Sun Mar 25 18:43:01 2012 From: git-noreply at xxxxx (=?utf-8?q?Quentin_Glidic?=) Date: Sun, 25 Mar 2012 18:43:01 -0000 Subject: [geany/geany-plugins] 38c3a9: multiterm: Do not call cppcheck Message-ID: <20120325201847.2AC96254016@uvena.de> Branch: refs/heads/master Author: Quentin Glidic Committer: Matthew Brush Date: Sun, 25 Mar 2012 18:43:01 Commit: 38c3a99c1bdd7e604c073e4e3e78c06430c86185 https://github.com/geany/geany-plugins/commit/38c3a99c1bdd7e604c073e4e3e78c06430c86185 Log Message: ----------- multiterm: Do not call cppcheck Modified Paths: -------------- multiterm/src/Makefile.am Modified: multiterm/src/Makefile.am 2 files changed, 0 insertions(+), 2 deletions(-) =================================================================== @@ -35,5 +35,3 @@ multiterm_la_LIBADD = \ $(MULTITERM_LIBS) EXTRA_DIST = multiterm.h - -include $(top_srcdir)/build/cppcheck.mk -------------- This E-Mail was brought to you by github_commit_mail.py (Source: TBD). From git-noreply at xxxxx Mon Mar 26 15:47:29 2012 From: git-noreply at xxxxx (=?utf-8?q?Matthew_Brush?=) Date: Mon, 26 Mar 2012 15:47:29 -0000 Subject: [geany/geany-plugins] 17adeb: geanyminiscript: Add headers to _SOURCES so they get distributed Message-ID: <20120326155221.A6A8925401D@uvena.de> Branch: refs/heads/master Author: Matthew Brush Committer: Frank Lanitz Date: Mon, 26 Mar 2012 15:47:29 Commit: 17adebb9512508eef0f764c002a9a59aa8695887 https://github.com/geany/geany-plugins/commit/17adebb9512508eef0f764c002a9a59aa8695887 Log Message: ----------- geanyminiscript: Add headers to _SOURCES so they get distributed Modified Paths: -------------- geanyminiscript/src/Makefile.am Modified: geanyminiscript/src/Makefile.am 2 files changed, 1 insertions(+), 1 deletions(-) =================================================================== @@ -6,7 +6,7 @@ else EXTRA_LTLIBRARIES = geanyminiscript.la endif -geanyminiscript_la_SOURCES = gms.c gms_gui.c +geanyminiscript_la_SOURCES = gms.c gms.h gms_gui.c gms_gui.h gms_debug.h geanyminiscript_la_LIBADD = $(COMMONLIBS) include $(top_srcdir)/build/cppcheck.mk -------------- This E-Mail was brought to you by github_commit_mail.py (Source: TBD). From git-noreply at xxxxx Wed Mar 28 04:26:18 2012 From: git-noreply at xxxxx (=?utf-8?q?Matthew_Brush?=) Date: Wed, 28 Mar 2012 04:26:18 -0000 Subject: [geany/geany-plugins] 6ab376: devhelp: Remove glob and list all source files in wscript_build Message-ID: <20120328193528.AAEB9254021@uvena.de> Branch: refs/heads/master Author: Matthew Brush Committer: Matthew Brush Date: Wed, 28 Mar 2012 04:26:18 Commit: 6ab37627bca2116df04dd5a827462a3184d08ba5 https://github.com/geany/geany-plugins/commit/6ab37627bca2116df04dd5a827462a3184d08ba5 Log Message: ----------- devhelp: Remove glob and list all source files in wscript_build Fixes files missing from compilation and causing undefined symbols. Modified Paths: -------------- devhelp/wscript_build devhelp/wscript_configure Modified: devhelp/wscript_build 28 files changed, 22 insertions(+), 6 deletions(-) =================================================================== @@ -23,14 +23,30 @@ from build.wafutils import build_plugin -import glob - name = 'Devhelp' includes = [ '../devhelp', 'devhelp/src', 'devhelp/devhelp' ] libraries = [ 'GTK', 'GTHREAD', 'WEBKIT', 'LIBWNCK', 'GCONF2', 'ZLIB' ] -sources = [ 'src/dhp-manpages.c', - 'src/dhp-object.c', - 'src/dhp-plugin.c' ] -sources += glob.glob('devhelp/*.c') +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 1 files changed, 1 insertions(+), 0 deletions(-) =================================================================== @@ -42,3 +42,4 @@ for package_name, package_version, uselib_store in packages: args='--cflags --libs') 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). From git-noreply at xxxxx Fri Mar 30 20:36:43 2012 From: git-noreply at xxxxx (=?utf-8?q?Frank_Lanitz?=) Date: Fri, 30 Mar 2012 20:36:43 -0000 Subject: [geany/geany-plugins] 056bbc: Removing an old, unused file from POTFILES Message-ID: <20120330203744.528E025402E@uvena.de> Branch: refs/heads/master Author: Frank Lanitz Committer: Frank Lanitz Date: Fri, 30 Mar 2012 20:36:43 Commit: 056bbcaa8c8bc08b56ecdaf496e27cd536b5c6b6 https://github.com/geany/geany-plugins/commit/056bbcaa8c8bc08b56ecdaf496e27cd536b5c6b6 Log Message: ----------- Removing an old, unused file from POTFILES Modified Paths: -------------- po/POTFILES.in Modified: po/POTFILES.in 1 files changed, 0 insertions(+), 1 deletions(-) =================================================================== @@ -50,7 +50,6 @@ debugger/src/atree.c devhelp/src/dhp.h devhelp/src/dhp-object.c devhelp/src/dhp-plugin.c -devhelp/src/dhp-codesearch.c devhelp/src/dhp-manpages.c devhelp/src/dhp-settings.c -------------- This E-Mail was brought to you by github_commit_mail.py (Source: TBD). From git-noreply at xxxxx Fri Mar 30 20:37:26 2012 From: git-noreply at xxxxx (=?utf-8?q?WilliamFraser?=) Date: Fri, 30 Mar 2012 20:37:26 -0000 Subject: [geany/geany-plugins] e6bedf: Merge pull request #2 from frlan/geanymacro_fix_a_warning Message-ID: <20120330204255.2F3ED25402E@uvena.de> Branch: refs/heads/master Author: WilliamFraser Committer: WilliamFraser Date: Fri, 30 Mar 2012 20:37:26 Commit: e6bedf633389c4cbd8c2854a8e4be679203139af https://github.com/geany/geany-plugins/commit/e6bedf633389c4cbd8c2854a8e4be679203139af Log Message: ----------- Merge pull request #2 from frlan/geanymacro_fix_a_warning Geanymacro fix a warning Modified Paths: -------------- geanymacro/src/geanymacro.c Modified: geanymacro/src/geanymacro.c 7 files changed, 3 insertions(+), 4 deletions(-) =================================================================== @@ -151,7 +151,7 @@ {SCI_SEARCHPREV,"Search for previous \"\""}, {SCI_SEARCHANCHOR,"Set start of search to beginning of selection"}, -/* editor commands that don't seem to work well in editing +/* editor commands that don't seem to work well in editing * {SCI_FORMFEED,N_("FormFeed")}, * * other commands ommited as they don't appear to do anything different to existing commands @@ -350,7 +350,7 @@ static void ReplayMacro(Macro *m) bFoundAnchor=TRUE; /* possibility that user edited macros might not have anchor before search */ - if((me->message==SCI_SEARCHNEXT || me->message==SCI_SEARCHPREV) && + if((me->message==SCI_SEARCHNEXT || me->message==SCI_SEARCHPREV) && bFoundAnchor==FALSE) { scintilla_send_message(sci,SCI_SEARCHANCHOR,0,0); @@ -2103,7 +2103,6 @@ static void DoEditMacro(GtkMenuItem *menuitem, gpointer gdata) GTK_SELECTION_SINGLE); /* add table to dialog */ - gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox),table); gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox),table,FALSE,FALSE,2); gtk_widget_show(table); @@ -2185,7 +2184,7 @@ static void DoEditMacro(GtkMenuItem *menuitem, gpointer gdata) /* Signal that macros have changed (and need to be saved) */ bMacrosHaveChanged=TRUE; } - + /* free memory */ g_free(cTemp); } -------------- This E-Mail was brought to you by github_commit_mail.py (Source: TBD). From git-noreply at xxxxx Fri Mar 30 20:42:49 2012 From: git-noreply at xxxxx (=?utf-8?q?Frank_Lanitz?=) Date: Fri, 30 Mar 2012 20:42:49 -0000 Subject: [geany/geany-plugins] 682e10: Merge pull request #22 from WilliamFraser/master Message-ID: <20120330204256.0BE4225402E@uvena.de> Branch: refs/heads/master Author: Frank Lanitz Committer: Frank Lanitz Date: Fri, 30 Mar 2012 20:42:49 Commit: 682e101cc9e06561f74f2fca0823ef26ed9273dc https://github.com/geany/geany-plugins/commit/682e101cc9e06561f74f2fca0823ef26ed9273dc Log Message: ----------- Merge pull request #22 from WilliamFraser/master Added search to macros and couple more little changes Modified Paths: -------------- geanymacro/src/geanymacro.c geanynumberedbookmarks/src/geanynumberedbookmarks.c Modified: geanymacro/src/geanymacro.c 636 files changed, 504 insertions(+), 132 deletions(-) =================================================================== @@ -29,10 +29,7 @@ typedef struct { gint message; - /* I'm leaving wparam commented out as this may prove useful if it's used by a Scintilla - * message that's recorded in a macro that I'm not aware of yet - */ - /* gulong wparam; */ + gulong wparam; glong lparam; } MacroEvent; @@ -100,39 +97,39 @@ {SCI_WORDLEFTEND,N_("Move Cursor to end of Word to the Left")}, {SCI_WORDRIGHTEND,N_("Move Cursor to end of Word to the Right")}, -{SCI_LINEDOWNEXTEND,N_("Move Selection down a line")}, -{SCI_LINEUPEXTEND,N_("Move Selection up a line")}, -{SCI_CHARLEFTEXTEND,N_("Move Selection Left a line")}, -{SCI_CHARRIGHTEXTEND,N_("Move Selection Right a line")}, -{SCI_WORDLEFTEXTEND,N_("Move Selection to start of Word to the Left")}, -{SCI_WORDRIGHTEXTEND,N_("Move Selection to start of Word to the Right")}, -{SCI_WORDPARTLEFTEXTEND,N_("Move Selection to start of Part of Word to the Left")}, -{SCI_WORDPARTRIGHTEXTEND,N_("Move Selection to start of Part of Word to the Right")}, -{SCI_HOMEEXTEND,N_("Move Selection to start of line")}, -{SCI_LINEENDEXTEND,N_("Move Selection to end of line")}, -{SCI_DOCUMENTSTARTEXTEND,N_("Move Selection to start of document")}, -{SCI_DOCUMENTENDEXTEND,N_("Move Selection to end of document")}, -{SCI_PAGEUPEXTEND,N_("Move Selection up one Page")}, -{SCI_PAGEDOWNEXTEND,N_("Move Selection down one Page")}, -{SCI_HOMEDISPLAYEXTEND,N_("Move Selection to fist visible character")}, -{SCI_LINEENDDISPLAYEXTEND,N_("Move Selection to last visible character")}, -{SCI_VCHOMEEXTEND,N_("Move Selection to 1st non-whitespace character of line, or 1st character of\ +{SCI_LINEDOWNEXTEND,N_("Extend Selection down a line")}, +{SCI_LINEUPEXTEND,N_("Extend Selection up a line")}, +{SCI_CHARLEFTEXTEND,N_("Extend Selection Left a line")}, +{SCI_CHARRIGHTEXTEND,N_("Extend Selection Right a line")}, +{SCI_WORDLEFTEXTEND,N_("Extend Selection to start of Word to the Left")}, +{SCI_WORDRIGHTEXTEND,N_("Extend Selection to start of Word to the Right")}, +{SCI_WORDPARTLEFTEXTEND,N_("Extend Selection to start of Part of Word to the Left")}, +{SCI_WORDPARTRIGHTEXTEND,N_("Extend Selection to start of Part of Word to the Right")}, +{SCI_HOMEEXTEND,N_("Extend Selection to start of line")}, +{SCI_LINEENDEXTEND,N_("Extend Selection to end of line")}, +{SCI_DOCUMENTSTARTEXTEND,N_("Extend Selection to start of document")}, +{SCI_DOCUMENTENDEXTEND,N_("Extend Selection to end of document")}, +{SCI_PAGEUPEXTEND,N_("Extend Selection up one Page")}, +{SCI_PAGEDOWNEXTEND,N_("Extend Selection down one Page")}, +{SCI_HOMEDISPLAYEXTEND,N_("Extend Selection to fist visible character")}, +{SCI_LINEENDDISPLAYEXTEND,N_("Extend Selection to last visible character")}, +{SCI_VCHOMEEXTEND,N_("Extend Selection to 1st non-whitespace character of line, or 1st character of\ line if already at 1st non-whitespace character")}, -{SCI_PARADOWNEXTEND,N_("Move Selection to begining of next paragraph")}, -{SCI_PARAUPEXTEND,N_("Move Selection up to beginning of current/previous paragraph")}, -{SCI_WORDLEFTENDEXTEND,N_("Move Selection to end of Word to the Left")}, -{SCI_WORDRIGHTENDEXTEND,N_("Move Selection to end of Word to the Right")}, - -{SCI_LINEDOWNRECTEXTEND,N_("Move Rectangular Selection down a line")}, -{SCI_LINEUPRECTEXTEND,N_("Move Rectangular Selection up a line")}, -{SCI_CHARLEFTRECTEXTEND,N_("Move Rectangular Selection Left a line")}, -{SCI_CHARRIGHTRECTEXTEND,N_("Move Rectangular Selection Right a line")}, -{SCI_HOMERECTEXTEND,N_("Move Rectangular Selection to start of line")}, -{SCI_LINEENDRECTEXTEND,N_("Move Rectangular Selection to end of line")}, -{SCI_PAGEUPRECTEXTEND,N_("Move Rectangular Selection up one Page")}, -{SCI_PAGEDOWNRECTEXTEND,N_("Move Rectangular Selection down one Page")}, -{SCI_VCHOMERECTEXTEND,N_("Move Rectangular Selection to 1st non-whitespace character of line, or 1st\ - character of line if already at 1st non-whitespace character")}, +{SCI_PARADOWNEXTEND,N_("Extend Selection to begining of next paragraph")}, +{SCI_PARAUPEXTEND,N_("Extend Selection up to beginning of current/previous paragraph")}, +{SCI_WORDLEFTENDEXTEND,N_("Extend Selection to end of Word to the Left")}, +{SCI_WORDRIGHTENDEXTEND,N_("Extend Selection to end of Word to the Right")}, + +{SCI_LINEDOWNRECTEXTEND,N_("Extend Rectangular Selection down a line")}, +{SCI_LINEUPRECTEXTEND,N_("Extend Rectangular Selection up a line")}, +{SCI_CHARLEFTRECTEXTEND,N_("Extend Rectangular Selection Left a line")}, +{SCI_CHARRIGHTRECTEXTEND,N_("Extend Rectangular Selection Right a line")}, +{SCI_HOMERECTEXTEND,N_("Extend Rectangular Selection to start of line")}, +{SCI_LINEENDRECTEXTEND,N_("Extend Rectangular Selection to end of line")}, +{SCI_PAGEUPRECTEXTEND,N_("Extend Rectangular Selection up one Page")}, +{SCI_PAGEDOWNRECTEXTEND,N_("Extend Rectangular Selection down one Page")}, +{SCI_VCHOMERECTEXTEND,N_("Extend Rectangular Selection to 1st non-whitespace character of line, or\ + 1st character of line if already at 1st non-whitespace character")}, {SCI_CANCEL,N_("Cancel Selection")}, @@ -150,7 +147,11 @@ {SCI_SELECTIONDUPLICATE,N_("Insert duplicate of selected text after selection. If nothing selected,\ duplicate line")}, -/* editor commands that don't seem to work well in editing +{SCI_SEARCHNEXT,"Search for next \"\""}, +{SCI_SEARCHPREV,"Search for previous \"\""}, +{SCI_SEARCHANCHOR,"Set start of search to beginning of selection"}, + +/* editor commands that don't seem to work well in editing * {SCI_FORMFEED,N_("FormFeed")}, * * other commands ommited as they don't appear to do anything different to existing commands @@ -178,7 +179,7 @@ enum GEANY_MACRO_BUTTON { PLUGIN_VERSION_CHECK(147) PLUGIN_SET_INFO(_("Macros"),_("Macros for Geany"), - "1.0","William Fraser "); + "1.1","William Fraser "); /* Plugin user alterable settings */ static gboolean bSaveMacros=TRUE; @@ -207,20 +208,27 @@ enum GEANY_MACRO_BUTTON { MacroEvent *me; GSList * gslTemp=gsl; + /* free data held in GSLIST structure */ while(gslTemp!=NULL) { me=gslTemp->data; - /* check to see if it's a message that has string attached, and free it if so */ - if(me->message==SCI_REPLACESEL) + /* check to see if it's a message that has string attached, and free it if so + * lparam might be NULL for SCI_SEARCHNEXT or SCI_SEARCHPREV but g_free is ok + * with this + */ + if(me->message==SCI_REPLACESEL || + me->message==SCI_SEARCHNEXT || + me->message==SCI_SEARCHPREV) g_free((void*)(me->lparam)); g_free((void*)(gslTemp->data)); gslTemp=g_slist_next(gslTemp); } - g_slist_free(gsl); + /* free SLIST structure */ + g_slist_free(gsl); - return NULL; + return NULL; } @@ -316,6 +324,7 @@ static void ClearAllMacros(void) FreeMacro((Macro*)(gsl->data)); gsl=g_slist_next(gsl); } + g_slist_free(mList); mList=NULL; } @@ -327,15 +336,46 @@ static void ReplayMacro(Macro *m) MacroEvent *me; GSList *gsl=m->MacroEvents; ScintillaObject* sci=document_get_current()->editor->sci; + gchar *clipboardcontents; + gboolean bFoundAnchor=FALSE; scintilla_send_message(sci,SCI_BEGINUNDOACTION,0,0); while(gsl!=NULL) { me=gsl->data; -/* may be needed if come across any scintilla messages that use wparam */ -/* scintilla_send_message(sci,me->message,me->wparam,me->lparam); */ - scintilla_send_message(sci,me->message,0,me->lparam); + + /* make not if anchor has been found */ + if(me->message==SCI_SEARCHANCHOR) + bFoundAnchor=TRUE; + + /* possibility that user edited macros might not have anchor before search */ + if((me->message==SCI_SEARCHNEXT || me->message==SCI_SEARCHPREV) && + bFoundAnchor==FALSE) + { + scintilla_send_message(sci,SCI_SEARCHANCHOR,0,0); + bFoundAnchor=TRUE; + } + + /* search might use clipboard to look for: check & hanndle */ + if((me->message==SCI_SEARCHNEXT || me->message==SCI_SEARCHPREV) && + ((gchar*)me->lparam)==NULL) + { + clipboardcontents=gtk_clipboard_wait_for_text(gtk_clipboard_get( + GDK_SELECTION_CLIPBOARD)); + /* ensure there is something in the clipboard */ + if(clipboardcontents==NULL) + { + dialogs_show_msgbox(GTK_MESSAGE_INFO,_("No text in clipboard!")); + break; + } + + scintilla_send_message(sci,me->message,me->wparam,(glong)clipboardcontents); + } + else + scintilla_send_message(sci,me->message,me->wparam,me->lparam); + + /* move to next macro event */ gsl=g_slist_next(gsl); } @@ -382,9 +422,26 @@ static void ReplayMacro(Macro *m) /* get event number */ me->message=strtoll(s[(*k)++],NULL,10); + /* default to 0 */ + me->wparam=0; + /* now handle lparam if required */ switch(me->message) { + case SCI_SEARCHNEXT: + case SCI_SEARCHPREV: + /* get text */ + me->lparam=(glong)(g_strcompress(s[(*k)++])); + /* if text is empty string replace with NULL to signify use clipboard */ + if((*((gchar*)(me->lparam)))==0) + { + g_free((gchar*)me->lparam); + me->lparam=(glong)NULL; + } + + /* get search flags */ + me->wparam=strtoll(s[(*k)++],NULL,10); + break; case SCI_REPLACESEL: /* get text */ me->lparam=(glong)(g_strcompress(s[(*k)++])); @@ -415,6 +472,27 @@ static void ReplayMacro(Macro *m) /* now handle lparam if required */ switch(me->message) { + case SCI_SEARCHNEXT: + case SCI_SEARCHPREV: + /* check if string is NULL */ + if(((gchar*)(me->lparam))==NULL) + { + /* now merge code and data */ + szNumberAndData=g_strdup_printf("%s,,%lu",szMacroNumber,me->wparam); + /* free memory */ + g_free(szMacroNumber); + return szNumberAndData; + } + + /* first get string reprisentation of data */ + pTemp=MakeStringSaveable((gchar*)(me->lparam)); + /* now merge code and data */ + szNumberAndData=g_strdup_printf("%s,%s,%lu",szMacroNumber,pTemp,me->wparam); + /* free memory */ + g_free(szMacroNumber); + g_free(pTemp); + return szNumberAndData; + case SCI_REPLACESEL: /* first get string reprisentation of data */ pTemp=MakeStringSaveable((gchar*)(me->lparam)); @@ -424,6 +502,7 @@ static void ReplayMacro(Macro *m) g_free(szMacroNumber); g_free(pTemp); return szNumberAndData; + /* default handler for messages without extra data */ default: return szMacroNumber; @@ -431,9 +510,15 @@ static void ReplayMacro(Macro *m) } +/* Is there a document open in the editor */ +static gboolean DocumentPresent() +{ + return (document_get_current()!=NULL); +} + + /* check editor notifications and remember editor events */ -static gboolean Notification_Handler(GObject *obj, GeanyEditor *editor, SCNotification *nt, - gpointer user_data) +static gboolean Notification_Handler(GObject *obj,GeanyEditor *ed,SCNotification *nt,gpointer ud) { MacroEvent *me; gint i; @@ -466,9 +551,12 @@ static gboolean Notification_Handler(GObject *obj, GeanyEditor *editor, SCNotifi } me=g_new0(MacroEvent,1); me->message=nt->message; -/* me->wparam=nt->wParam; */ - /* Special handling for text inserting, duplicate inserted string */ - me->lparam=(me->message==SCI_REPLACESEL)?((glong) g_strdup((gchar *)(nt->lParam))) : nt->lParam; + me->wparam=nt->wParam; + /* Special handling for text in lparam */ + me->lparam=(me->message==SCI_SEARCHNEXT || + me->message==SCI_SEARCHPREV || + me->message==SCI_REPLACESEL) + ?((glong) g_strdup((gchar *)(nt->lParam))) : nt->lParam; /* more efficient to create reverse list and reverse it at the end */ RecordingMacro->MacroEvents=g_slist_prepend(RecordingMacro->MacroEvents,me); @@ -641,7 +729,7 @@ static void LoadSettings(void) /* extract settings */ bQueryOverwriteMacros=utils_get_setting_boolean(config,"Settings", - "Question_Macro_Overwrite",FALSE); + "Question_Macro_Overwrite",FALSE); bSaveMacros=utils_get_setting_boolean(config,"Settings","Save_Macros",FALSE); /* extract macros */ @@ -676,8 +764,10 @@ static void LoadSettings(void) g_free(pcTemp); /* now go through macro data generating macros */ for(k=0,m->MacroEvents=NULL;pcMacroCommands[k]!=NULL;) - m->MacroEvents=g_slist_prepend(m->MacroEvents,GetMacroEventFromString(pcMacroCommands, - &k)); + m->MacroEvents=g_slist_prepend(m->MacroEvents, + GetMacroEventFromString(pcMacroCommands, + &k)); + /* list created in reverse as more efficient, now turn it around */ m->MacroEvents=g_slist_reverse(m->MacroEvents); /* macro now complete, add it to the list */ @@ -692,13 +782,6 @@ static void LoadSettings(void) } -PluginCallback plugin_callbacks[] = -{ - { "editor-notify", (GCallback) &Notification_Handler, FALSE, NULL }, - { NULL, NULL, FALSE, NULL } -}; - - /* handle button presses in the preferences dialog box */ static void on_configure_response(GtkDialog *dialog, gint response, gpointer user_data) { @@ -767,7 +850,7 @@ void plugin_help(void) GTK_STOCK_OK,GTK_RESPONSE_ACCEPT, NULL); -/* setup help text */ + /* setup help text */ cText=g_strconcat( _("This Plugin implements Macros in Geany.\n\n"), _("This plugin allows you to record and use your own macros. "), @@ -830,7 +913,6 @@ void plugin_help(void) /* free memory */ g_free(cText); - } @@ -1093,34 +1175,65 @@ static gboolean InitializeMacroRecord(void) } +/* function to start the macro recording process */ +static void StartRecordingMacro() +{ + /* start recording process, but quit if error, or user cancels */ + if(!InitializeMacroRecord()) + return; + + /* start actual recording */ + scintilla_send_message(document_get_current()->editor->sci,SCI_STARTRECORD,0,0); + gtk_widget_hide(Record_Macro_menu_item); + gtk_widget_show(Stop_Record_Macro_menu_item); +} + + +/* function to finish recording a macro */ +static void StopRecordingMacro() +{ + scintilla_send_message(document_get_current()->editor->sci,SCI_STOPRECORD,0,0); + /* Recorded in reverse as more efficient */ + RecordingMacro->MacroEvents=g_slist_reverse(RecordingMacro->MacroEvents); + /* add macro to list */ + AddMacroToList(RecordingMacro); + /* set ready to record new macro (don't free as macro has been saved in macrolist) */ + RecordingMacro=NULL; + gtk_widget_show(Record_Macro_menu_item); + gtk_widget_hide(Stop_Record_Macro_menu_item); + + /* Macros have been changed */ + bMacrosHaveChanged=TRUE; +} + + +/* check to see if we are recording a macro and stop it if we are */ +static void on_document_close(GObject *obj, GeanyDocument *doc, gpointer user_data) +{ + if(RecordingMacro!=NULL) + StopRecordingMacro(); +} + + +PluginCallback plugin_callbacks[] = +{ + { "editor-notify", (GCallback) &Notification_Handler, FALSE, NULL }, + { "document-close", (GCallback) &on_document_close, FALSE, NULL }, + { NULL, NULL, FALSE, NULL } +}; + + /* handle starting and stopping macro recording */ static void DoMacroRecording(GtkMenuItem *menuitem, gpointer gdata) { - if(RecordingMacro==NULL) - { - /* start recording process, but quit if error, or user cancels */ - if(!InitializeMacroRecord()) - return; + /* can't record if in an empty editor */ + if(!DocumentPresent()) + return; - /* start actual recording */ - scintilla_send_message(document_get_current()->editor->sci,SCI_STARTRECORD,0,0); - gtk_widget_hide(Record_Macro_menu_item); - gtk_widget_show(Stop_Record_Macro_menu_item); - } - else { - scintilla_send_message(document_get_current()->editor->sci,SCI_STOPRECORD,0,0); - /* Recorded in reverse as more efficient */ - RecordingMacro->MacroEvents=g_slist_reverse(RecordingMacro->MacroEvents); - /* add macro to list */ - AddMacroToList(RecordingMacro); - /* set ready to record new macro (don't free as macro has been saved in macrolist) */ - RecordingMacro=NULL; - gtk_widget_show(Record_Macro_menu_item); - gtk_widget_hide(Stop_Record_Macro_menu_item); - - /* Macros have been changed */ - bMacrosHaveChanged=TRUE; - } + if(RecordingMacro==NULL) + StartRecordingMacro(); + else + StopRecordingMacro(); } @@ -1214,6 +1327,200 @@ static void Accel_Render_Edited_CallBack(GtkCellRendererAccel *cell,gchar *iter_ } +/* Get Search Description string with search text and flags at end*/ +static gchar * GetSearchDescription(gint message,gchar *text,gint flags) +{ + return g_strdup_printf(_("Search %s, looking for %s%s%s.%s%s%s%s%s"), + message==SCI_SEARCHNEXT?"forewards":"backwards", + text==NULL?"":"\"", + text==NULL?"clipboard contents":text, + text==NULL?"":"\"", + (flags&SCFIND_MATCHCASE)==SCFIND_MATCHCASE?" Match case.":"", + (flags&SCFIND_WHOLEWORD)==SCFIND_WHOLEWORD?" Match whole word.":"", + (flags&SCFIND_WORDSTART)==SCFIND_WORDSTART?" Match start of word.":"", + (flags&SCFIND_REGEXP)==SCFIND_REGEXP?" Search by Regular Expression.":"", + (flags&SCFIND_POSIX)==SCFIND_POSIX?" Regular Expression is POSIX.":""); +} + + +/* handle button presses in the preferences dialog box */ +static void on_search_toggle(GtkToggleButton *cb,gpointer user_data) +{ + GtkEntry *gtke; + GtkLabel *gtkl; + gboolean bUseClipboard; + + /* retreive pointers to entry & label */ + gtke=(GtkEntry*)(g_object_get_data(G_OBJECT(cb),"GeanyMacros_e")); + gtkl=(GtkLabel*)(g_object_get_data(G_OBJECT(cb),"GeanyMacros_l")); + + /* find out what we're searching for */ + bUseClipboard=gtk_toggle_button_get_active(cb); + + /* set entry & label depending on if we're looking for text or not */ + gtk_widget_set_sensitive((GtkWidget*)gtke,!bUseClipboard); + gtk_widget_set_sensitive((GtkWidget*)gtkl,!bUseClipboard); +} + + +/* Handle editing of options for search */ +static void EditSearchOptions(GtkTreeModel *model,GtkTreeIter *iter) +{ + GtkWidget *dialog,*gtke,*hbox,*gtkl; + gchar *cTemp,*cData,*cText,*cTemp2; + gint iReply=GTK_RESPONSE_OK,i; + GtkWidget *vbox,*gtkcb; + GtkWidget *cbA,*cbB,*cbC,*cbD,*cbE,*cbF; + MacroDetailEntry *mde; + gulong flags; + + /* get MacroDetail and data for this line */ + gtk_tree_model_get(model,iter,2,&mde,3,&cData,-1); + + /* make cText point to search text */ + cText=strchr(cData,','); + cText++; + + /* get search flags */ + flags=strtoll(cData,NULL,10); + + /* create dialog box */ + dialog=gtk_dialog_new_with_buttons(_("Search Options:"), + GTK_WINDOW(geany->main_widgets->window), + GTK_DIALOG_DESTROY_WITH_PARENT,NULL); + + /* create buttons */ + gtk_dialog_add_button(GTK_DIALOG(dialog),_("_Ok"),GTK_RESPONSE_OK); + gtk_dialog_add_button(GTK_DIALOG(dialog),_("_Cancel"),GTK_RESPONSE_CANCEL); + + /* create box to hold widgets */ + vbox=gtk_vbox_new(FALSE, 6); + gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox),vbox); + gtk_widget_show(vbox); + + /* create combobox to hold search direction */ + gtkcb=gtk_combo_box_new_text(); + gtk_combo_box_append_text((GtkComboBox*)gtkcb,_("Search Forwards")); + gtk_combo_box_append_text((GtkComboBox*)gtkcb,_("Search Backwards")); + gtk_combo_box_set_active((GtkComboBox*)gtkcb,(mde->message==SCI_SEARCHNEXT)?0:1); + gtk_box_pack_start(GTK_BOX(vbox),gtkcb,FALSE,FALSE,2); + gtk_widget_show(gtkcb); + + /* create checkbox to check for search options */ + cbA=gtk_check_button_new_with_label(_("Seach for contents of clipboard")); + /* if search text is empty then to seach for clipboard contents */ + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cbA),(*cText)==0); + gtk_box_pack_start(GTK_BOX(vbox),cbA,FALSE,FALSE,2); + /* ensure we monitor for change in this button */ + g_signal_connect(cbA,"toggled",G_CALLBACK(on_search_toggle),dialog); + gtk_widget_show(cbA); + + + /* create box to hold search text entry box, and label */ + hbox=gtk_hbox_new(FALSE,0); + gtk_box_pack_start(GTK_BOX(vbox),hbox,FALSE,FALSE,2); + gtk_widget_show(hbox); + + gtkl=gtk_label_new(_("Seach for:")); + gtk_box_pack_start(GTK_BOX(hbox),gtkl,FALSE,FALSE,2); + gtk_widget_show(gtkl); + /* save pointer to label */ + g_object_set_data(G_OBJECT(cbA),"GeanyMacros_l",gtkl); + gtk_widget_set_sensitive((GtkWidget*)gtkl,(*cText)!=0); + + gtke=gtk_entry_new(); + if((*cText)!=0) + gtk_entry_set_text(GTK_ENTRY(gtke),cText); + + gtk_box_pack_start(GTK_BOX(hbox),gtke,FALSE,FALSE,2); + gtk_widget_show(gtke); + /* save pointer to entry */ + g_object_set_data(G_OBJECT(cbA),"GeanyMacros_e",gtke); + gtk_widget_set_sensitive((GtkWidget*)gtke,(*cText)!=0); + + /* create checkbox to check for search options */ + cbB=gtk_check_button_new_with_label(_("Seach is case sensitive")); + /* if search text is empty then to seach for clipboard contents */ + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cbB),(flags&SCFIND_MATCHCASE)==SCFIND_MATCHCASE); + gtk_box_pack_start(GTK_BOX(vbox),cbB,FALSE,FALSE,2); + + cbC=gtk_check_button_new_with_label(_("Seach for whole word")); + /* if search text is empty then to seach for clipboard contents */ + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cbC),(flags&SCFIND_WHOLEWORD)==SCFIND_WHOLEWORD); + gtk_box_pack_start(GTK_BOX(vbox),cbC,FALSE,FALSE,2); + + cbD=gtk_check_button_new_with_label(_("Seach for start of word")); + /* if search text is empty then to seach for clipboard contents */ + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cbD),(flags&SCFIND_WORDSTART)==SCFIND_WORDSTART); + gtk_box_pack_start(GTK_BOX(vbox),cbD,FALSE,FALSE,2); + + cbE=gtk_check_button_new_with_label(_("Seach text is regular expression")); + /* if search text is empty then to seach for clipboard contents */ + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cbE),(flags&SCFIND_REGEXP)==SCFIND_REGEXP); + gtk_box_pack_start(GTK_BOX(vbox),cbE,FALSE,FALSE,2); + + cbF=gtk_check_button_new_with_label(_("Seach text is POSIX compatible")); + /* if search text is empty then to seach for clipboard contents */ + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cbF),(flags&SCFIND_POSIX)==SCFIND_POSIX); + gtk_box_pack_start(GTK_BOX(vbox),cbF,FALSE,FALSE,2); + + gtk_widget_show_all(vbox); + + while(iReply==GTK_RESPONSE_OK) + { + iReply=gtk_dialog_run(GTK_DIALOG(dialog)); + + if(iReply==GTK_RESPONSE_OK) + { + /* handle change in options */ + + /* check search direction 0=foreward, 1=backwards */ + iReply=gtk_combo_box_get_active((GtkComboBox*)gtkcb); + + /* calculate macro detail of relavent detail */ + i=0; + while(MacroDetails[i].message!=SCI_SEARCHNEXT) i++; + mde=(MacroDetailEntry *)(&MacroDetails[i+iReply]); + + /* calculate flags */ + flags=gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(cbB))?SCFIND_MATCHCASE:0; + flags|=gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(cbC))?SCFIND_WHOLEWORD:0; + flags|=gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(cbD))?SCFIND_WORDSTART:0; + flags|=gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(cbE))?SCFIND_REGEXP:0; + flags|=gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(cbF))?SCFIND_POSIX:0; + + /* get search string or NULL if using clipboard */ + cText=(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(cbA)))? + NULL:(gchar*)gtk_entry_get_text((GtkEntry*)(gtke)); + + /* get new data */ + cData=g_strdup_printf("%lu,%s",flags,(cText==NULL)?"":cText); + + /* get new text */ + cText=GetSearchDescription(mde->message,cText,flags); + + /* get old data for this line */ + gtk_tree_model_get(model,iter,0,&cTemp,3,&cTemp2,-1); + + /* set text and macro detail */ + gtk_list_store_set(GTK_LIST_STORE(model),iter,0,cText,2,mde,3,cData,-1); + + /* free up old text */ + g_free(cTemp); + g_free(cTemp2); + + /* break out of loop */ + break; + } + + } + + /* tidy up */ + gtk_widget_destroy(dialog); +} + + +/* Handle editing of text for SCI_REPLACESEL */ static void EditSCIREPLACESELText(GtkTreeModel *model,GtkTreeIter *iter) { GtkWidget *dialog,*gtke,*hbox,*gtkl; @@ -1286,6 +1593,7 @@ static void combo_edited(GtkCellRendererText *cell,gchar *iter_id,gchar *new_tex MacroDetailEntry *mde; gint i; gchar *cTemp,*cTemp2; + gboolean bNeedButtonUpdate=FALSE; /* find MacroDetails that has the setting of new setting */ i=0; @@ -1301,16 +1609,35 @@ static void combo_edited(GtkCellRendererText *cell,gchar *iter_id,gchar *new_tex /* handle freeing of string if needed */ g_free(cTemp); - if(mde->message==SCI_REPLACESEL) + if(mde->message==SCI_REPLACESEL || + mde->message==SCI_SEARCHNEXT || + mde->message==SCI_SEARCHPREV) + { g_free(cTemp2); + bNeedButtonUpdate=TRUE; + } + + /* see what text will have to change into */ + cTemp=(gchar*)(MacroDetails[i].description); + cTemp2=NULL; + if(MacroDetails[i].message==SCI_REPLACESEL) + { + cTemp=g_strdup_printf(_("Insert/replace with \"\"")); + bNeedButtonUpdate=TRUE; + } + else if(MacroDetails[i].message==SCI_SEARCHNEXT || + MacroDetails[i].message==SCI_SEARCHPREV) + { + cTemp=GetSearchDescription(MacroDetails[i].message,NULL,0); + cTemp2=g_strdup("0,"); + bNeedButtonUpdate=TRUE; + } /* Update the model */ - gtk_list_store_set(GTK_LIST_STORE(model),&iter,0,(MacroDetails[i].message==SCI_REPLACESEL? - g_strdup_printf(_("Insert/replace with \"\"")):MacroDetails[i].description),2, - &(MacroDetails[i]),3,NULL,-1); + gtk_list_store_set(GTK_LIST_STORE(model),&iter,0,cTemp,2,&(MacroDetails[i]),3,cTemp2,-1); /* check if changing to or from SCI_REPLACESEL and enable/disable edit button as needed */ - if(mde->message==SCI_REPLACESEL || MacroDetails[i].message==SCI_REPLACESEL) + if(bNeedButtonUpdate) g_signal_emit_by_name(gtk_tree_view_get_selection(GTK_TREE_VIEW(treeview)),"changed", G_TYPE_NONE); } @@ -1335,21 +1662,23 @@ static void DoEditMacroElementsSelectionChanged(GtkTreeSelection *selection,gpoi gtk_tree_model_get(GTK_TREE_MODEL(model),&iter,2,&mde,-1); /* find delete button & enable it*/ - button=gtk_dialog_get_widget_for_response(dialog,GEANY_MACRO_BUTTON_DELETE); + button=(GtkWidget*)(g_object_get_data(G_OBJECT(dialog),"GeanyMacros_bD")); gtk_widget_set_sensitive(button,TRUE); /* find edit text button & enable it if looking at a SCI_REPLACESEL item*/ - button=gtk_dialog_get_widget_for_response(dialog,GEANY_MACRO_BUTTON_EDIT); - gtk_widget_set_sensitive(button,mde->message==SCI_REPLACESEL); + button=(GtkWidget*)(g_object_get_data(G_OBJECT(dialog),"GeanyMacros_bC")); + gtk_widget_set_sensitive(button,mde->message==SCI_REPLACESEL || + mde->message==SCI_SEARCHNEXT || + mde->message==SCI_SEARCHPREV); /* get copy of iteraton */ iter2=iter; /* if can move to next node then it's not the last. use to set Move down */ - button=gtk_dialog_get_widget_for_response(dialog,GEANY_MACRO_BUTTON_DOWN); + button=(GtkWidget*)(g_object_get_data(G_OBJECT(dialog),"GeanyMacros_bB")); gtk_widget_set_sensitive(button,gtk_tree_model_iter_next(GTK_TREE_MODEL(model),&iter2)); /* find Move up button & enable/disable it */ - button=gtk_dialog_get_widget_for_response(dialog,GEANY_MACRO_BUTTON_UP); + button=(GtkWidget*)(g_object_get_data(G_OBJECT(dialog),"GeanyMacros_bA")); /* get the path of the current selected line */ tpTemp=gtk_tree_model_get_path(GTK_TREE_MODEL(model),&iter); /* if has previous then can be moved up a line */ @@ -1361,19 +1690,19 @@ static void DoEditMacroElementsSelectionChanged(GtkTreeSelection *selection,gpoi else { /* find delete button & diable it*/ - button=gtk_dialog_get_widget_for_response(dialog,GEANY_MACRO_BUTTON_DELETE); + button=(GtkWidget*)(g_object_get_data(G_OBJECT(dialog),"GeanyMacros_bD")); gtk_widget_set_sensitive(button,FALSE); /* find edit text button & diable it*/ - button=gtk_dialog_get_widget_for_response(dialog,GEANY_MACRO_BUTTON_EDIT); + button=(GtkWidget*)(g_object_get_data(G_OBJECT(dialog),"GeanyMacros_bC")); gtk_widget_set_sensitive(button,FALSE); /* find Move up button & diable it*/ - button=gtk_dialog_get_widget_for_response(dialog,GEANY_MACRO_BUTTON_UP); + button=(GtkWidget*)(g_object_get_data(G_OBJECT(dialog),"GeanyMacros_bA")); gtk_widget_set_sensitive(button,FALSE); /* find Move Down button & diable it*/ - button=gtk_dialog_get_widget_for_response(dialog,GEANY_MACRO_BUTTON_DOWN); + button=(GtkWidget*)(g_object_get_data(G_OBJECT(dialog),"GeanyMacros_bB")); gtk_widget_set_sensitive(button,FALSE); } @@ -1383,7 +1712,7 @@ static void DoEditMacroElementsSelectionChanged(GtkTreeSelection *selection,gpoi /* edit individual existing macro */ static void EditMacroElements(Macro *m) { - GtkWidget *table,*dialog; + GtkWidget *table,*dialog,*button; GtkTreeViewColumn *column; GtkCellRenderer *renderer; GtkTreeSelection *selection; @@ -1411,26 +1740,43 @@ static void EditMacroElements(Macro *m) { me=(MacroEvent*)(gsl->data); i=0; - while(MacroDetails[i].description!=NULL) { + while(MacroDetails[i].description!=NULL) + { if(MacroDetails[i].message==me->message) break; i++; } gtk_list_store_append(ls,&iter); /* Acquire an iterator */ /* set text, pointer to macro detail, and any ascociated string */ - gtk_list_store_set(ls,&iter,0,(me->message==SCI_REPLACESEL? - g_strdup_printf(_("Insert/replace with \"%s\""),(gchar*)(me->lparam)): - MacroDetails[i].description),2,&(MacroDetails[i]),3, - (me->message==SCI_REPLACESEL?g_strdup((gchar*)(me->lparam)):NULL),-1); + cTemp=(gchar*)(MacroDetails[i].description); + cTemp2=NULL; + if(me->message==SCI_REPLACESEL) + { + cTemp=g_strdup_printf(_("Insert/replace with \"%s\""), + (gchar*)(me->lparam)); + cTemp2=g_strdup((gchar*)(me->lparam)); + } + else if(MacroDetails[i].message==SCI_SEARCHNEXT || + MacroDetails[i].message==SCI_SEARCHPREV) + { + cTemp=GetSearchDescription(MacroDetails[i].message,(gchar*)(me->lparam), + me->wparam); + cTemp2=g_strdup_printf("%lu,%s",me->wparam,((gchar*)(me->lparam)==NULL)? + "":((gchar*)(me->lparam))); + } + + gtk_list_store_set(ls,&iter,0,cTemp,2,&(MacroDetails[i]),3,cTemp2,-1); gsl=g_slist_next(gsl); } /* create list store for combo renderer */ lsCombo=gtk_list_store_new(2,G_TYPE_STRING,G_TYPE_POINTER); i=0; - while(MacroDetails[i].description!=NULL) { + while(MacroDetails[i].description!=NULL) + { gtk_list_store_append(lsCombo,&iter); - gtk_list_store_set(lsCombo,&iter,0,MacroDetails[i].description,1,&(MacroDetails[i]),-1); + gtk_list_store_set(lsCombo,&iter,0,MacroDetails[i].description,1, + &(MacroDetails[i]),-1); i++; } @@ -1445,8 +1791,8 @@ static void EditMacroElements(Macro *m) gtk_tree_view_set_grid_lines(GTK_TREE_VIEW(table),GTK_TREE_VIEW_GRID_LINES_BOTH); /* add column */ - column=gtk_tree_view_column_new_with_attributes(_("Event"),renderer,"text",0,"text-column",1, - NULL); + column=gtk_tree_view_column_new_with_attributes(_("Event"),renderer,"text",0,"text-column" + ,1,NULL); g_signal_connect(renderer,"edited",G_CALLBACK(combo_edited),table); gtk_tree_view_append_column(GTK_TREE_VIEW(table),column); @@ -1456,23 +1802,27 @@ static void EditMacroElements(Macro *m) /* add table to dialog */ gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox),table); - gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox),table,FALSE,FALSE,2); +// gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox),table,FALSE,FALSE,2); gtk_widget_show(table); /* add buttons */ - gtk_dialog_add_button(GTK_DIALOG(dialog),_("Move _Up"),GEANY_MACRO_BUTTON_UP); - gtk_dialog_add_button(GTK_DIALOG(dialog),_("Move Do_wn"),GEANY_MACRO_BUTTON_DOWN); + button=gtk_dialog_add_button(GTK_DIALOG(dialog),_("Move _Up"),GEANY_MACRO_BUTTON_UP); + g_object_set_data(G_OBJECT(dialog),"GeanyMacros_bA",button); + button=gtk_dialog_add_button(GTK_DIALOG(dialog),_("Move Do_wn"),GEANY_MACRO_BUTTON_DOWN); + g_object_set_data(G_OBJECT(dialog),"GeanyMacros_bB",button); gtk_dialog_add_button(GTK_DIALOG(dialog),_("New _Above"),GEANY_MACRO_BUTTON_ABOVE); gtk_dialog_add_button(GTK_DIALOG(dialog),_("New _Below"),GEANY_MACRO_BUTTON_BELOW); - gtk_dialog_add_button(GTK_DIALOG(dialog),_("_Edit Text"),GEANY_MACRO_BUTTON_EDIT); - gtk_dialog_add_button(GTK_DIALOG(dialog),_("_Delete"),GEANY_MACRO_BUTTON_DELETE); + button=gtk_dialog_add_button(GTK_DIALOG(dialog),_("_Edit"),GEANY_MACRO_BUTTON_EDIT); + g_object_set_data(G_OBJECT(dialog),"GeanyMacros_bC",button); + button=gtk_dialog_add_button(GTK_DIALOG(dialog),_("_Delete"),GEANY_MACRO_BUTTON_DELETE); + g_object_set_data(G_OBJECT(dialog),"GeanyMacros_bD",button); gtk_dialog_add_button(GTK_DIALOG(dialog),_("_Ok"),GEANY_MACRO_BUTTON_APPLY); gtk_dialog_add_button(GTK_DIALOG(dialog),_("_Cancel"),GEANY_MACRO_BUTTON_CANCEL); /* listen for changes in selection */ selection=gtk_tree_view_get_selection(GTK_TREE_VIEW(table)); - g_signal_connect(G_OBJECT(selection),"changed",G_CALLBACK(DoEditMacroElementsSelectionChanged), - dialog); + g_signal_connect(G_OBJECT(selection),"changed", + G_CALLBACK(DoEditMacroElementsSelectionChanged),dialog); /* call callback: this will set buttons acordingly */ DoEditMacroElementsSelectionChanged(selection,dialog); @@ -1494,9 +1844,14 @@ static void EditMacroElements(Macro *m) if(i==GEANY_MACRO_BUTTON_DELETE) { /* see if need to free non-static string */ - gtk_tree_model_get(GTK_TREE_MODEL(ls),&iter,0,&cTemp,2,&mde,-1); - if(mde->message==SCI_REPLACESEL) + gtk_tree_model_get(GTK_TREE_MODEL(ls),&iter,0,&cTemp,2,&mde,3,&cTemp2,-1); + if(mde->message==SCI_REPLACESEL || + mde->message==SCI_SEARCHNEXT || + mde->message==SCI_SEARCHPREV) + { g_free(cTemp); + g_free(cTemp2); + } /* remove element */ gtk_list_store_remove(ls,&iter); @@ -1569,6 +1924,9 @@ static void EditMacroElements(Macro *m) gtk_tree_model_get(GTK_TREE_MODEL(ls),&iter,2,&mde,-1); if(mde->message==SCI_REPLACESEL) EditSCIREPLACESELText(GTK_TREE_MODEL(ls),&iter); + else if(mde->message==SCI_SEARCHNEXT || mde->message==SCI_SEARCHPREV) + EditSearchOptions(GTK_TREE_MODEL(ls),&iter); + } } //end of commands that require line to be selected @@ -1602,10 +1960,21 @@ static void EditMacroElements(Macro *m) me->message=mde->message; me->lparam=0; + me->wparam=0; /* Special handling for text inserting, duplicate inserted string */ if(me->message==SCI_REPLACESEL) - me->lparam=(glong)((cTemp!=NULL)?g_strdup(cTemp):g_strdup_printf("")); + me->lparam=(glong)((cTemp!=NULL)?g_strdup(cTemp):g_strdup("")); + + /* Special handling for search */ + if(me->message==SCI_SEARCHNEXT || me->message==SCI_SEARCHPREV) + { + cTemp2=strchr(cTemp,','); + cTemp2++; + + me->lparam=(glong)(((*cTemp2)==0)?NULL:g_strdup(cTemp2)); + me->wparam=strtoll(cTemp,NULL,10); + } /* more efficient to create reverse list and reverse it at the end */ m->MacroEvents=g_slist_prepend(m->MacroEvents,me); @@ -1631,7 +2000,8 @@ static void EditMacroElements(Macro *m) /* free any non-static text */ g_free((void*)(cTemp)); - if(mde->message==SCI_REPLACESEL) + if(mde->message==SCI_REPLACESEL || mde->message==SCI_SEARCHNEXT || + mde->message==SCI_SEARCHPREV) g_free(cTemp2); /* get next event */ @@ -1661,11 +2031,11 @@ static void DoEditMacroSelectionChanged(GtkTreeSelection *selection,gpointer dat bHasItemSelected=gtk_tree_selection_get_selected(selection,&model,&iter); /* now set button sensitive or not depending if there is something for them to act on */ - button=gtk_dialog_get_widget_for_response(dialog,GEANY_MACRO_BUTTON_RERECORD); + button=(GtkWidget*)(g_object_get_data(G_OBJECT(dialog),"GeanyMacros_bA")); gtk_widget_set_sensitive(button,bHasItemSelected); - button=gtk_dialog_get_widget_for_response(dialog,GEANY_MACRO_BUTTON_EDIT); + button=(GtkWidget*)(g_object_get_data(G_OBJECT(dialog),"GeanyMacros_bB")); gtk_widget_set_sensitive(button,bHasItemSelected); - button=gtk_dialog_get_widget_for_response(dialog,GEANY_MACRO_BUTTON_DELETE); + button=(GtkWidget*)(g_object_get_data(G_OBJECT(dialog),"GeanyMacros_bC")); gtk_widget_set_sensitive(button,bHasItemSelected); } @@ -1673,7 +2043,7 @@ static void DoEditMacroSelectionChanged(GtkTreeSelection *selection,gpointer dat /* do editing of existing macros */ static void DoEditMacro(GtkMenuItem *menuitem, gpointer gdata) { - GtkWidget *table,*dialog; + GtkWidget *table,*dialog,*button; GtkTreeViewColumn *column; GtkCellRenderer *renderer; GtkTreeSelection *selection; @@ -1733,14 +2103,16 @@ static void DoEditMacro(GtkMenuItem *menuitem, gpointer gdata) GTK_SELECTION_SINGLE); /* add table to dialog */ - gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox),table); gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox),table,FALSE,FALSE,2); gtk_widget_show(table); /* add buttons */ - gtk_dialog_add_button(GTK_DIALOG(dialog),_("_Re-Record"),GEANY_MACRO_BUTTON_RERECORD); - gtk_dialog_add_button(GTK_DIALOG(dialog),_("_Edit"),GEANY_MACRO_BUTTON_EDIT); - gtk_dialog_add_button(GTK_DIALOG(dialog),_("_Delete"),GEANY_MACRO_BUTTON_DELETE); + button=gtk_dialog_add_button(GTK_DIALOG(dialog),_("_Re-Record"),GEANY_MACRO_BUTTON_RERECORD); + g_object_set_data(G_OBJECT(dialog),"GeanyMacros_bA",button); + button=gtk_dialog_add_button(GTK_DIALOG(dialog),_("_Edit"),GEANY_MACRO_BUTTON_EDIT); + g_object_set_data(G_OBJECT(dialog),"GeanyMacros_bB",button); + button=gtk_dialog_add_button(GTK_DIALOG(dialog),_("_Delete"),GEANY_MACRO_BUTTON_DELETE); + g_object_set_data(G_OBJECT(dialog),"GeanyMacros_bC",button); gtk_dialog_add_button(GTK_DIALOG(dialog),_("_Ok"),GEANY_MACRO_BUTTON_CANCEL); /* listen for changes in selection */ @@ -1783,7 +2155,7 @@ static void DoEditMacro(GtkMenuItem *menuitem, gpointer gdata) } /* handle re-record macro */ - if(i==GEANY_MACRO_BUTTON_RERECORD && bEditable) + if(i==GEANY_MACRO_BUTTON_RERECORD && bEditable && DocumentPresent()) { m=FindMacroByName(cTemp); /* ensure have empty recording macro */ @@ -1812,7 +2184,7 @@ static void DoEditMacro(GtkMenuItem *menuitem, gpointer gdata) /* Signal that macros have changed (and need to be saved) */ bMacrosHaveChanged=TRUE; } - + /* free memory */ g_free(cTemp); } @@ -1835,7 +2207,7 @@ void plugin_init(GeanyData *data) /* Calculate what shift '0' to '9 will be (? is above 3 on uk keyboard, but it's # or ~ on us * keyboard.) * there must be an easier way than this of working this out, but I've not figured it out. - * This is needed to play nicely with the Geany Numbered Bookmarks plugin + * This is needed to play nicely with the Geany Numbered Bookmarks plugin */ /* go through '0' to '9', work out hardware keycode, then find out what shift+this keycode Modified: geanynumberedbookmarks/src/geanynumberedbookmarks.c 81 files changed, 41 insertions(+), 40 deletions(-) =================================================================== @@ -81,7 +81,7 @@ "[FileData]"; /* Definitions for bookmark images */ -static gchar * aszMarkerImage0[] = +static const gchar * aszMarkerImage0[] = { "17 14 3 1", /* width height colours characters-per-pixel */ ". c None", @@ -102,7 +102,7 @@ "..B**********B...", "...BBBBBBBBBB...." }; -static gchar * aszMarkerImage1[] = +static const gchar * aszMarkerImage1[] = { "17 14 3 1", /* width height colours characters-per-pixel */ ". c None", @@ -123,7 +123,7 @@ "..B**********B...", "...BBBBBBBBBB...." }; -static gchar * aszMarkerImage2[] = +static const gchar * aszMarkerImage2[] = { "17 14 3 1", /* width height colours characters-per-pixel */ ". c None", @@ -144,7 +144,7 @@ "..B**********B...", "...BBBBBBBBBB...." }; -static gchar * aszMarkerImage3[] = +static const gchar * aszMarkerImage3[] = { "17 14 3 1", /* width height colours characters-per-pixel */ ". c None", @@ -165,7 +165,7 @@ "..B**********B...", "...BBBBBBBBBB...." }; -static gchar * aszMarkerImage4[] = +static const gchar * aszMarkerImage4[] = { "17 14 3 1", /* width height colours characters-per-pixel */ ". c None", @@ -186,7 +186,7 @@ "..B**********B...", "...BBBBBBBBBB...." }; -static gchar * aszMarkerImage5[] = +static const gchar * aszMarkerImage5[] = { "17 14 3 1", /* width height colours characters-per-pixel */ ". c None", @@ -207,7 +207,7 @@ "..B**********B...", "...BBBBBBBBBB...." }; -static gchar * aszMarkerImage6[] = +static const gchar * aszMarkerImage6[] = { "17 14 3 1", /* width height colours characters-per-pixel */ ". c None", @@ -228,7 +228,7 @@ "..B**********B...", "...BBBBBBBBBB...." }; -static gchar * aszMarkerImage7[] = +static const gchar * aszMarkerImage7[] = { "17 14 3 1", /* width height colours characters-per-pixel */ ". c None", @@ -249,7 +249,7 @@ "..B**********B...", "...BBBBBBBBBB...." }; -static gchar * aszMarkerImage8[] = +static const gchar * aszMarkerImage8[] = { "17 14 3 1", /* width height colours characters-per-pixel */ ". c None", @@ -270,7 +270,7 @@ "..B**********B...", "...BBBBBBBBBB...." }; -static gchar * aszMarkerImage9[] = +static const gchar * aszMarkerImage9[] = { "17 14 3 1", /* width height colours characters-per-pixel */ ". c None", @@ -292,7 +292,7 @@ "...BBBBBBBBBB...." }; -static gchar ** aszMarkerImages[]= +static const gchar ** aszMarkerImages[]= { aszMarkerImage0,aszMarkerImage1,aszMarkerImage2,aszMarkerImage3,aszMarkerImage4, aszMarkerImage5,aszMarkerImage6,aszMarkerImage7,aszMarkerImage8,aszMarkerImage9 @@ -463,7 +463,7 @@ static void LoadSettings(void) /* extract settings */ bCenterWhenGotoBookmark=utils_get_setting_boolean(config,"Settings", - "Center_When_Goto_Bookmark",FALSE); + "Center_When_Goto_Bookmark",FALSE); bRememberFolds=utils_get_setting_boolean(config,"Settings","Remember_Folds",FALSE); /* extract data about files */ @@ -521,7 +521,7 @@ static void DefineMarkers(ScintillaObject* sci) gint i; for(i=0;i<10;i++) scintilla_send_message(sci,SCI_MARKERDEFINEPIXMAP,i+BOOKMARK_BASE, - (glong)(aszMarkerImages[i])); + (glong)(aszMarkerImages[i])); } @@ -586,7 +586,8 @@ static void on_document_open(GObject *obj, GeanyDocument *doc, gpointer user_dat struct stat sBuf; GtkWidget *dialog; gchar *cFoldData=NULL; - gint iBits,iFlags,iBitCounter; + /* keep compiler happy & initialise iBits: will logically be initiated anyway */ + gint iBits=0,iFlags,iBitCounter; /* ensure have markers set */ CheckEditorSetup(); @@ -595,16 +596,16 @@ static void on_document_open(GObject *obj, GeanyDocument *doc, gpointer user_dat /* check to see if file has changed since geany last saved it */ fd=GetFileData(doc->file_name); if(stat(doc->file_name,&sBuf)==0 && fd!=NULL && fd->LastChangedTime!=-1 && - fd->LastChangedTime!=sBuf.st_mtime) + fd->LastChangedTime!=sBuf.st_mtime) { /* notify user that file has been changed */ dialog=gtk_message_dialog_new(GTK_WINDOW(geany->main_widgets->window), - GTK_DIALOG_DESTROY_WITH_PARENT, - GTK_MESSAGE_ERROR, - GTK_BUTTONS_NONE, - _("'%s' has been edited since it was last saved by geany. Marker positions may \ -be unreliable and will not be loaded.\nPress Ignore to try an load markers anyway."), - doc->file_name); + GTK_DIALOG_DESTROY_WITH_PARENT,GTK_MESSAGE_ERROR, + GTK_BUTTONS_NONE, + _("'%s' has been edited since it was last saved by g\ + eany. Marker positions may be unreliable and will \ + not be loaded.\nPress Ignore to try an load marker\ + s anyway."),doc->file_name); gtk_dialog_add_button(GTK_DIALOG(dialog),_("_Okay"),GTK_RESPONSE_OK); gtk_dialog_add_button(GTK_DIALOG(dialog),_("_Ignore"),GTK_RESPONSE_REJECT); l=gtk_dialog_run(GTK_DIALOG(dialog)); @@ -624,9 +625,9 @@ static void on_document_open(GObject *obj, GeanyDocument *doc, gpointer user_dat if(fd->pcFolding==NULL || bRememberFolds==FALSE) break; - cFoldData=fd->pcFolding; + cFoldData=fd->pcFolding; - /* first ensure fold positions exist */ + /* first ensure fold positions exist */ scintilla_send_message(sci,SCI_COLOURISE,0,-1); iLineCount=scintilla_send_message(sci,SCI_GETLINECOUNT,0,0); @@ -637,14 +638,14 @@ static void on_document_open(GObject *obj, GeanyDocument *doc, gpointer user_dat iFlags=scintilla_send_message(sci,SCI_GETFOLDLEVEL,i,0); /* ignore non-folding lines */ if((iFlags & SC_FOLDLEVELHEADERFLAG)==0) - continue; + continue; - /* get next 6 fold states if needed */ + /* get next 6 fold states if needed */ if(iBitCounter==6) { - iBitCounter=0; - iBits=base64_char_to_int[(gint)(*cFoldData)]; - cFoldData++; + iBitCounter=0; + iBits=base64_char_to_int[(gint)(*cFoldData)]; + cFoldData++; } /* set fold if needed */ @@ -715,8 +716,8 @@ static void on_document_save(GObject *obj, GeanyDocument *doc, gpointer user_dat if(iBitCounter!=0) { guiFold=(guint8)base64_int_to_char[guiFold]; - g_byte_array_append(gbaFoldData,&guiFold,1); - } + g_byte_array_append(gbaFoldData,&guiFold,1); + } /* transfer data to text string */ fdTemp->pcFolding=g_strndup((gchar*)(gbaFoldData->data),gbaFoldData->len); @@ -745,7 +746,7 @@ static void on_document_save(GObject *obj, GeanyDocument *doc, gpointer user_dat static gint GetLine(ScintillaObject* sci) { return scintilla_send_message(sci,SCI_LINEFROMPOSITION, - scintilla_send_message(sci,SCI_GETCURRENTPOS,10,0),0); + scintilla_send_message(sci,SCI_GETCURRENTPOS,10,0),0); } @@ -765,7 +766,7 @@ static void on_configure_response(GtkDialog *dialog, gint response, gpointer use /* first see if settings are going to change */ bSettingsHaveChanged=(bRememberFolds!=gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(cb1))); bSettingsHaveChanged|=(bCenterWhenGotoBookmark!=gtk_toggle_button_get_active( - GTK_TOGGLE_BUTTON(cb2))); + GTK_TOGGLE_BUTTON(cb2))); /* set new settings settings */ bRememberFolds=gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(cb1)); @@ -811,11 +812,10 @@ void plugin_help(void) GtkWidget *dialog,*label,*scroll; /* create dialog box */ - dialog=gtk_dialog_new_with_buttons(_("Numbered Bookmarks help"), - GTK_WINDOW(geany->main_widgets->window), - GTK_DIALOG_DESTROY_WITH_PARENT, - GTK_STOCK_OK,GTK_RESPONSE_ACCEPT, - NULL); + dialog=gtk_dialog_new_with_buttons(_("Numbered Bookmarks help"), + GTK_WINDOW(geany->main_widgets->window), + GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_STOCK_OK,GTK_RESPONSE_ACCEPT,NULL); /* create label */ label=gtk_label_new( @@ -842,7 +842,7 @@ void plugin_help(void) /* create scrolled window to display label */ scroll=gtk_scrolled_window_new(NULL,NULL); gtk_scrolled_window_set_policy((GtkScrolledWindow*)scroll,GTK_POLICY_NEVER, - GTK_POLICY_AUTOMATIC); + GTK_POLICY_AUTOMATIC); gtk_scrolled_window_add_with_viewport((GtkScrolledWindow*)scroll,label); gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox),scroll); @@ -882,6 +882,7 @@ static void GotoBookMark(gint iBookMark) /* make sure view is not beyond start or end of document */ if(iLine+iLinesVisible>iLineCount) iLine=iLineCount-iLinesVisible; + if(iLine<0) iLine=0; @@ -1019,7 +1020,7 @@ void plugin_init(GeanyData *data) /* set key press monitor handle */ key_release_signal_id=g_signal_connect(geany->main_widgets->window,"key-release-event", - G_CALLBACK(Key_Released_CallBack),NULL); + G_CALLBACK(Key_Released_CallBack),NULL); } @@ -1042,7 +1043,7 @@ void plugin_cleanup(void) if(documents[i]->is_valid) { sci=documents[i]->editor->sci; for(k=0;k<9;k++) - scintilla_send_message(sci,SCI_MARKERDELETEALL,BOOKMARK_BASE+k,0); + scintilla_send_message(sci,SCI_MARKERDELETEALL,BOOKMARK_BASE+k,0); } -------------- This E-Mail was brought to you by github_commit_mail.py (Source: TBD). From git-noreply at xxxxx Wed Mar 28 19:35:19 2012 From: git-noreply at xxxxx (=?utf-8?q?Frank_Lanitz?=) Date: Wed, 28 Mar 2012 19:35:19 -0000 Subject: [geany/geany-plugins] b0cb3b: Merge pull request #25 from codebrainz/devhelp-fixes Message-ID: <20120328193529.ED09125401D@uvena.de> Branch: refs/heads/master Author: Frank Lanitz Committer: Frank Lanitz 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 +#include +#include +#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 (""; + + start = find_in_buffer (start, + start_key, + length, + strlen (start_key)); + + end_key = "
    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 ( + "" + "" + "" + "" + "" + "" + "" + "
    %s %s
    " + "
    %s
    " + "" + "", + 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 +#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 +#include +#include +#include +#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 +#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 + * 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 +#include + +#ifdef GDK_WINDOWING_X11 +#include +#include +#define WNCK_I_KNOW_THIS_IS_UNSTABLE +#include +#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 + * 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 + +#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 + * 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 + +#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 + +#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 + * 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 +#include +#include + +#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 + * + * 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 +#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 + * 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 + +#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 + * 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 + +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 + +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 + +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 + * + * 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 + * + * 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 + +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 + * 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 +#include + +#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 + * + * 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 +#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 + * 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 +#include +#include +#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 + * 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 + +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 + + +#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 + +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 + * 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 +#include +#include +#include + +#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 instead of . */ + 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 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 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 + * + * 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 + +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 +#include +#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 + +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 + * 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 +#include +#include +#include +#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 + * + * 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 +#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 + * 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 +#include +#include +#ifdef GDK_WINDOWING_QUARTZ +#include +#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 + * 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 +#include +#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 +#include +#include +#include +#include + +#ifdef GDK_WINDOWING_QUARTZ +#include +#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 ", + "Richard Hult ", + "Johan Dahlin ", + "Ross Burton ", + "Aleksander Morgado ", + 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"), "N", NULL, + G_CALLBACK (window_activate_new_window) }, + { "NewTab", GTK_STOCK_NEW, N_("New _Tab"), "T", NULL, + G_CALLBACK (window_activate_new_tab) }, + { "Print", GTK_STOCK_PRINT, N_("_Print?"), "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, "C", NULL, + G_CALLBACK (window_activate_copy) }, + { "Find", GTK_STOCK_FIND, NULL, "F", NULL, + G_CALLBACK (window_activate_find) }, + { "Find Next", GTK_STOCK_GO_FORWARD, N_("Find Next"), "G", NULL, + G_CALLBACK (window_find_next_cb) }, + { "Find Previous", GTK_STOCK_GO_BACK, N_("Find Previous"), "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, "Left", + N_("Go to the previous page"), + G_CALLBACK (window_activate_back) }, + { "Forward", GTK_STOCK_GO_FORWARD, NULL, "Right", + N_("Go to the next page"), + G_CALLBACK (window_activate_forward) }, + + { "ShowContentsTab", NULL, N_("_Contents Tab"), "B", NULL, + G_CALLBACK (window_activate_show_contents) }, + + { "ShowSearchTab", NULL, N_("_Search Tab"), "S", NULL, + G_CALLBACK (window_activate_show_search) }, + + /* View menu */ + { "ZoomIn", GTK_STOCK_ZOOM_IN, N_("_Larger Text"), "plus", + N_("Increase the text size"), + G_CALLBACK (window_activate_zoom_in) }, + { "ZoomOut", GTK_STOCK_ZOOM_OUT, N_("S_maller Text"), "minus", + N_("Decrease the text size"), + G_CALLBACK (window_activate_zoom_out) }, + { "ZoomDefault", GTK_STOCK_ZOOM_100, N_("_Normal Size"), "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 ("%s", + _("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; ipriv->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 + * 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 +#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 + +#include +#include +#include + +#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 + +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 +#include +#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 +#include +#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 +#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 +#include +#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 + +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 -#include - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif -#include - -#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). From git-noreply at xxxxx Wed Mar 28 19:32:09 2012 From: git-noreply at xxxxx (=?utf-8?q?Frank_Lanitz?=) Date: Wed, 28 Mar 2012 19:32:09 -0000 Subject: [geany/geany-plugins] ce45ff: Devhelp: Several fixes Message-ID: <20120330202250.C310025402E@uvena.de> Branch: refs/heads/master Author: Frank Lanitz Committer: Frank Lanitz Date: Wed, 28 Mar 2012 19:32:09 Commit: ce45ffcfc19f68caa1f38d142962a594e417a8eb https://github.com/geany/geany-plugins/commit/ce45ffcfc19f68caa1f38d142962a594e417a8eb Log Message: ----------- Devhelp: Several fixes 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 +#include +#include +#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 (""; + + start = find_in_buffer (start, + start_key, + length, + strlen (start_key)); + + end_key = "
    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 ( + "" + "" + "" + "" + "" + "" + "" + "
    %s %s
    " + "
    %s
    " + "" + "", + 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 +#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 +#include +#include +#include +#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 +#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 + * 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 +#include + +#ifdef GDK_WINDOWING_X11 +#include +#include +#define WNCK_I_KNOW_THIS_IS_UNSTABLE +#include +#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 + * 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 + +#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 + * 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 + +#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 + +#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 + * 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 +#include +#include + +#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 + * + * 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 +#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 + * 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 + +#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 + * 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 + +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 + +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 + +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 + * + * 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 + * + * 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 + +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 + * 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 +#include + +#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 + * + * 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 +#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 + * 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 +#include +#include +#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 + * 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 + +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 + + +#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 + +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 + * 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 +#include +#include +#include + +#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 instead of . */ + 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 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 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 + * + * 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 + +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 +#include +#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 + +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 + * 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 +#include +#include +#include +#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 + * + * 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 +#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 + * 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 +#include +#include +#ifdef GDK_WINDOWING_QUARTZ +#include +#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 + * 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 +#include +#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 +#include +#include +#include +#include + +#ifdef GDK_WINDOWING_QUARTZ +#include +#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 ", + "Richard Hult ", + "Johan Dahlin ", + "Ross Burton ", + "Aleksander Morgado ", + 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"), "N", NULL, + G_CALLBACK (window_activate_new_window) }, + { "NewTab", GTK_STOCK_NEW, N_("New _Tab"), "T", NULL, + G_CALLBACK (window_activate_new_tab) }, + { "Print", GTK_STOCK_PRINT, N_("_Print?"), "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, "C", NULL, + G_CALLBACK (window_activate_copy) }, + { "Find", GTK_STOCK_FIND, NULL, "F", NULL, + G_CALLBACK (window_activate_find) }, + { "Find Next", GTK_STOCK_GO_FORWARD, N_("Find Next"), "G", NULL, + G_CALLBACK (window_find_next_cb) }, + { "Find Previous", GTK_STOCK_GO_BACK, N_("Find Previous"), "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, "Left", + N_("Go to the previous page"), + G_CALLBACK (window_activate_back) }, + { "Forward", GTK_STOCK_GO_FORWARD, NULL, "Right", + N_("Go to the next page"), + G_CALLBACK (window_activate_forward) }, + + { "ShowContentsTab", NULL, N_("_Contents Tab"), "B", NULL, + G_CALLBACK (window_activate_show_contents) }, + + { "ShowSearchTab", NULL, N_("_Search Tab"), "S", NULL, + G_CALLBACK (window_activate_show_search) }, + + /* View menu */ + { "ZoomIn", GTK_STOCK_ZOOM_IN, N_("_Larger Text"), "plus", + N_("Increase the text size"), + G_CALLBACK (window_activate_zoom_in) }, + { "ZoomOut", GTK_STOCK_ZOOM_OUT, N_("S_maller Text"), "minus", + N_("Decrease the text size"), + G_CALLBACK (window_activate_zoom_out) }, + { "ZoomDefault", GTK_STOCK_ZOOM_100, N_("_Normal Size"), "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 ("%s", + _("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; ipriv->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 + * 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 +#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 + +#include +#include +#include + +#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 + +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 +#include +#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 +#include +#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 +#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 +#include +#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 + +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 -#include - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif -#include - -#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).