[gnome-builder/wip/chergert/perspective] libide: start on tool abstraction
- From: Christian Hergert <chergert src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-builder/wip/chergert/perspective] libide: start on tool abstraction
- Date: Wed, 18 Nov 2015 12:55:23 +0000 (UTC)
commit eac271cfcf1e2e2d792c28e40b6091eb873c6d3f
Author: Christian Hergert <chergert redhat com>
Date: Wed Nov 18 04:55:06 2015 -0800
libide: start on tool abstraction
One of the last major parts to get solved is how we will handle tools/
now that libgnome-builder is gone.
To simplify the creation of tools, they can now be implemented as plugins.
Simply define X-Tool-Name: in your plugin definition and implement
IdeApplicationTool. Then the `ide' program can be used to execute your
tool such as "ide build <args>".
We still need to port the tools over, but this lays the framework for that
to happen and continue using IdeApplication.
data/icons/hicolor/Makefile.am | 10 +-
data/keybindings/shared.css | 9 +
libide/Makefile.am | 6 +
libide/ide-application-command-line.c | 369 ++++++++++++++
libide/ide-application-plugins.c | 189 +++++++
libide/ide-application-private.h | 42 +-
libide/ide-application-tool.c | 51 ++
libide/ide-application-tool.h | 55 ++
libide/ide-application.c | 906 +++++++++------------------------
libide/ide-application.h | 45 +-
libide/ide-css-provider.c | 2 +-
libide/ide-keybindings.c | 2 +-
libide/ide-workbench.c | 20 +
src/main.c | 34 +--
14 files changed, 990 insertions(+), 750 deletions(-)
---
diff --git a/data/icons/hicolor/Makefile.am b/data/icons/hicolor/Makefile.am
index 57f3591..2e9b36f 100644
--- a/data/icons/hicolor/Makefile.am
+++ b/data/icons/hicolor/Makefile.am
@@ -6,16 +6,16 @@ EXTRA_DIST =
noinst_LTLIBRARIES = libicons.la
nodist_libicons_la_SOURCES = \
- gb-icons-resources.c \
- gb-icons-resources.h
+ ide-icons-resources.c \
+ ide-icons-resources.h
libicons_la_CFLAGS = $(ICONS_CFLAGS)
libicons_la_LIBADD = $(ICONS_LIBS)
-glib_resources_c = gb-icons-resources.c
-glib_resources_h = gb-icons-resources.h
+glib_resources_c = ide-icons-resources.c
+glib_resources_h = ide-icons-resources.h
glib_resources_xml = icons.gresource.xml
-glib_resources_namespace = gb_icons
+glib_resources_namespace = ide_icons
include $(top_srcdir)/build/autotools/Makefile.am.gresources
-include $(top_srcdir)/git.mk
diff --git a/data/keybindings/shared.css b/data/keybindings/shared.css
index ace9992..db2d02a 100644
--- a/data/keybindings/shared.css
+++ b/data/keybindings/shared.css
@@ -29,6 +29,15 @@ VteTerminal {
}
+ binding-set builder-workbench-bindings
+{
+ bind "<ctrl>comma" { "set-perspective" ("preferences") };
+}
+
entry.gb-command-bar-entry {
gtk-key-bindings: builder-command-bar-entry;
}
+
+workbench {
+ gtk-key-bindings: builder-workbench-bindings;
+}
diff --git a/libide/Makefile.am b/libide/Makefile.am
index 1d5d3a7..e488eb4 100644
--- a/libide/Makefile.am
+++ b/libide/Makefile.am
@@ -27,6 +27,8 @@ libide_1_0_la_public_sources = \
ide-application.h \
ide-application-addin.c \
ide-application-addin.h \
+ ide-application-tool.c \
+ ide-application-tool.h \
ide-back-forward-item.c \
ide-back-forward-item.h \
ide-back-forward-list.c \
@@ -260,8 +262,10 @@ libide_1_0_la_SOURCES = \
gsettings/ide-gsettings-file-settings.h \
gsettings/ide-language-defaults.c \
gsettings/ide-language-defaults.h \
+ ide-application-command-line.c \
ide-application-actions.c \
ide-application-actions.h \
+ ide-application-plugins.c \
ide-application-private.h \
ide-async-helper.c \
ide-async-helper.h \
@@ -370,6 +374,7 @@ libide_1_0_la_includes = \
-I$(top_srcdir)/contrib/libeditorconfig \
-I$(top_srcdir)/contrib/search \
-I$(top_srcdir)/contrib/xml \
+ -I$(top_srcdir)/data/icons/hicolor \
-I$(srcdir) \
-I$(srcdir)/directory \
-I$(srcdir)/doap \
@@ -417,6 +422,7 @@ libide_1_0_la_LIBADD = \
$(LIBIDE_LIBS) \
$(SHM_LIB) \
-lm \
+ $(top_builddir)/data/icons/hicolor/libicons.la \
$(top_builddir)/contrib/egg/libegg-private.la \
$(top_builddir)/contrib/gd/libgd.la \
$(top_builddir)/contrib/libeditorconfig/libeditorconfig.la \
diff --git a/libide/ide-application-command-line.c b/libide/ide-application-command-line.c
new file mode 100644
index 0000000..d48f1c2
--- /dev/null
+++ b/libide/ide-application-command-line.c
@@ -0,0 +1,369 @@
+/* ide-application-command-line.c
+ *
+ * Copyright (C) 2015 Christian Hergert <christian hergert me>
+ *
+ * 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 3 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <glib/gi18n.h>
+#include <girepository.h>
+#include <libpeas/peas.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "ide-application.h"
+#include "ide-application-private.h"
+#include "ide-log.h"
+
+static PeasPluginInfo *
+ide_application_locate_tool (IdeApplication *self,
+ const gchar *tool_name)
+{
+ PeasEngine *engine;
+ const GList *list;
+
+ g_assert (IDE_IS_APPLICATION (self));
+ g_assert (tool_name != NULL);
+
+ engine = peas_engine_get_default ();
+ list = peas_engine_get_plugin_list (engine);
+
+ for (; list != NULL; list = list->next)
+ {
+ PeasPluginInfo *plugin_info = list->data;
+ const gchar *name;
+
+ name = peas_plugin_info_get_external_data (plugin_info, "Tool-Name");
+ if (g_strcmp0 (name, tool_name) == 0)
+ return plugin_info;
+ }
+
+ return NULL;
+}
+
+static PeasPluginInfo *
+ide_application_locate_worker (IdeApplication *self,
+ const gchar *worker_name)
+{
+ PeasEngine *engine;
+ const GList *list;
+
+ g_assert (IDE_IS_APPLICATION (self));
+ g_assert (worker_name != NULL);
+
+ engine = peas_engine_get_default ();
+ list = peas_engine_get_plugin_list (engine);
+
+ for (; list != NULL; list = list->next)
+ {
+ PeasPluginInfo *plugin_info = list->data;
+ const gchar *name;
+
+ name = peas_plugin_info_get_module_name (plugin_info);
+ if (g_strcmp0 (name, worker_name) == 0)
+ return plugin_info;
+ }
+
+ return NULL;
+}
+
+static gchar *
+ide_application_get_command_help (IdeApplication *self,
+ gboolean long_form)
+{
+ PeasEngine *engine;
+ const GList *list;
+ GString *str;
+ gint count = 0;
+
+ g_assert (IDE_IS_APPLICATION (self));
+
+ engine = peas_engine_get_default ();
+ list = peas_engine_get_plugin_list (engine);
+
+ str = g_string_new (NULL);
+
+ if (long_form)
+ g_string_append_printf (str, "%s\n", _("Commands:"));
+
+ for (; list != NULL; list = list->next)
+ {
+ PeasPluginInfo *plugin_info = list->data;
+ const gchar *name;
+ const gchar *desc;
+
+ name = peas_plugin_info_get_external_data (plugin_info, "Tool-Name");
+ desc = peas_plugin_info_get_external_data (plugin_info, "Tool-Description");
+
+ if (name != NULL)
+ {
+ if (long_form)
+ g_string_append_printf (str, " %-25s %s\n", name, desc);
+ else
+ g_string_append_printf (str, "%s\n", name);
+
+ count++;
+ }
+ }
+
+ if (count == 0)
+ {
+ g_string_free (str, TRUE);
+ return NULL;
+ }
+
+ return g_strstrip (g_string_free (str, FALSE));
+}
+
+static gboolean
+ide_application_increase_verbosity (void)
+{
+ ide_log_increase_verbosity ();
+ return TRUE;
+}
+
+gboolean
+ide_application_local_command_line (GApplication *application,
+ gchar ***arguments,
+ gint *exit_status)
+{
+ IdeApplication *self = (IdeApplication *)application;
+ GOptionContext *context = NULL;
+ GOptionGroup *group;
+ const gchar *shortdesc = NULL;
+ GError *error = NULL;
+ gchar *type = NULL;
+ gchar *dbus_address = NULL;
+ gboolean standalone = FALSE;
+ gboolean version = FALSE;
+ gboolean list_commands = FALSE;
+
+ GOptionEntry entries[] = {
+ { "list-commands",
+ 0,
+ G_OPTION_FLAG_HIDDEN,
+ G_OPTION_ARG_NONE,
+ &list_commands},
+
+ { "standalone",
+ 's',
+ G_OPTION_FLAG_NONE,
+ G_OPTION_ARG_NONE,
+ &standalone,
+ N_("Run Builder in standalone mode") },
+
+ { "version",
+ 'V',
+ G_OPTION_FLAG_NONE,
+ G_OPTION_ARG_NONE,
+ &version,
+ N_("Show the application's version") },
+
+ { "type",
+ 0,
+ G_OPTION_FLAG_HIDDEN,
+ G_OPTION_ARG_STRING,
+ &type },
+
+ { "dbus-address",
+ 0,
+ G_OPTION_FLAG_HIDDEN,
+ G_OPTION_ARG_STRING,
+ &dbus_address},
+
+ { "verbose",
+ 'v',
+ G_OPTION_FLAG_NO_ARG | G_OPTION_FLAG_IN_MAIN,
+ G_OPTION_ARG_CALLBACK,
+ ide_application_increase_verbosity,
+ N_("Increase verbosity. May be specified multiple times.") },
+
+ { NULL }
+ };
+
+ g_assert (IDE_IS_APPLICATION (self));
+ g_assert (arguments != NULL);
+ g_assert (exit_status != NULL);
+
+ *exit_status = EXIT_SUCCESS;
+
+ if (g_str_equal (g_get_prgname (), "ide"))
+ shortdesc = _("COMMAND");
+
+ context = g_option_context_new (shortdesc);
+
+ g_option_context_add_main_entries (context, entries, GETTEXT_PACKAGE);
+
+ group = gtk_get_option_group (TRUE);
+ g_option_context_add_group (context, group);
+
+ group = g_irepository_get_option_group ();
+ g_option_context_add_group (context, group);
+
+ ide_application_discover_plugins (self);
+
+ /*
+ * If we are the "ide" program, then we want to setup ourselves for
+ * verb style commands and add a commands group for help.
+ */
+ if (g_str_equal (g_get_prgname (), "ide"))
+ {
+ gchar *command_help;
+
+ self->mode = IDE_APPLICATION_MODE_TOOL;
+
+ g_option_context_set_strict_posix (context, TRUE);
+
+ command_help = ide_application_get_command_help (self, TRUE);
+ g_option_context_set_summary (context, command_help);
+ g_free (command_help);
+ }
+ else if (g_str_equal (g_get_prgname (), "gnome-builder-worker"))
+ {
+ self->mode = IDE_APPLICATION_MODE_WORKER;
+ }
+
+ if (!g_option_context_parse_strv (context, arguments, &error))
+ {
+ g_printerr ("%s\n", error->message);
+ *exit_status = EXIT_FAILURE;
+ goto cleanup;
+ }
+
+ if (list_commands)
+ {
+ gchar *command_help;
+
+ command_help = ide_application_get_command_help (self, FALSE);
+ g_print ("%s\n", command_help ?: _("No commands available"));
+ g_free (command_help);
+
+ *exit_status = 0;
+ goto cleanup;
+ }
+
+ if (standalone || (self->mode != IDE_APPLICATION_MODE_PRIMARY))
+ {
+ GApplicationFlags flags;
+
+ flags = g_application_get_flags (application);
+ g_application_set_flags (application, flags | G_APPLICATION_NON_UNIQUE);
+ }
+
+ if (version)
+ {
+ g_print (PACKAGE_STRING"\n");
+ *exit_status = EXIT_SUCCESS;
+ goto cleanup;
+ }
+
+ if (self->mode == IDE_APPLICATION_MODE_TOOL)
+ {
+ PeasPluginInfo *tool_plugin;
+ const gchar *tool_name;
+
+ if (g_strv_length (*arguments) < 2)
+ {
+ g_printerr ("%s\n", _("Please provide a command"));
+ *exit_status = EXIT_FAILURE;
+ goto cleanup;
+ }
+
+ tool_name = (*arguments) [1];
+ tool_plugin = ide_application_locate_tool (self, tool_name);
+
+ if (tool_plugin == NULL)
+ {
+ g_printerr ("%s: \"%s\"\n", _("No such tool"), tool_name);
+ *exit_status = EXIT_FAILURE;
+ goto cleanup;
+ }
+
+ self->tool = tool_plugin;
+ self->tool_arguments = g_strdupv (*arguments);
+ }
+ else if (self->mode == IDE_APPLICATION_MODE_WORKER)
+ {
+ PeasPluginInfo *worker_plugin;
+
+ if (type == NULL)
+ {
+ g_printerr ("%s\n", _("Please provide a worker type"));
+ *exit_status = EXIT_FAILURE;
+ goto cleanup;
+ }
+
+ if (dbus_address== NULL)
+ {
+ g_printerr ("%s\n", _("Please provide a dbus address"));
+ *exit_status = EXIT_FAILURE;
+ goto cleanup;
+ }
+
+ worker_plugin = ide_application_locate_worker (self, type);
+
+ if (worker_plugin == NULL)
+ {
+ g_printerr ("%s: \"%s\"\n", _("No such worker"), type);
+ *exit_status = EXIT_FAILURE;
+ goto cleanup;
+ }
+
+ self->worker = worker_plugin;
+ self->dbus_address = g_strdup (dbus_address);
+ }
+
+ ide_application_load_plugins (self);
+
+ if (!g_application_register (application, NULL, &error))
+ {
+ g_printerr ("%s\n", error->message);
+ *exit_status = EXIT_FAILURE;
+ goto cleanup;
+ }
+
+ if (self->mode == IDE_APPLICATION_MODE_PRIMARY)
+ {
+ g_autoptr(GPtrArray) files = NULL;
+ gint i;
+
+ files = g_ptr_array_new_with_free_func (g_object_unref);
+
+ for (i = 1; (*arguments) [i]; i++)
+ {
+ GFile *file;
+
+ file = g_file_new_for_commandline_arg ((*arguments) [i]);
+ if (file != NULL)
+ g_ptr_array_add (files, file);
+ }
+
+ if (files->len > 0)
+ g_application_open (G_APPLICATION (self), (GFile **)files->pdata, files->len, "");
+ }
+
+ g_application_activate (application);
+
+cleanup:
+ g_clear_pointer (&type, g_free);
+ g_clear_pointer (&dbus_address, g_free);
+ g_clear_error (&error);
+ g_option_context_free (context);
+
+ return TRUE;
+}
diff --git a/libide/ide-application-plugins.c b/libide/ide-application-plugins.c
new file mode 100644
index 0000000..1ae1f98
--- /dev/null
+++ b/libide/ide-application-plugins.c
@@ -0,0 +1,189 @@
+/* ide-application-plugins.c
+ *
+ * Copyright (C) 2015 Christian Hergert <christian hergert me>
+ *
+ * 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 3 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <libpeas/peas.h>
+#include <girepository.h>
+
+#include "ide-application.h"
+#include "ide-application-addin.h"
+#include "ide-application-private.h"
+#include "ide-macros.h"
+
+static gboolean
+ide_application_can_load_plugin (IdeApplication *self,
+ PeasPluginInfo *plugin_info)
+{
+ g_assert (IDE_IS_APPLICATION (self));
+ g_assert (plugin_info != NULL);
+
+ if (self->mode == IDE_APPLICATION_MODE_WORKER)
+ {
+ if (self->worker != plugin_info)
+ return FALSE;
+ }
+
+ if (self->mode == IDE_APPLICATION_MODE_TOOL)
+ {
+ if (self->tool != plugin_info)
+ return FALSE;
+ }
+
+ /*
+ * TODO: Do ABI check on external data.
+ */
+
+ return TRUE;
+}
+
+void
+ide_application_discover_plugins (IdeApplication *self)
+{
+ PeasEngine *engine = peas_engine_get_default ();
+ const GList *list;
+
+ g_return_if_fail (IDE_IS_APPLICATION (self));
+
+ peas_engine_enable_loader (engine, "python3");
+
+ if (g_getenv ("GB_IN_TREE_PLUGINS") != NULL)
+ {
+ GDir *dir;
+
+ g_irepository_require_private (g_irepository_get_default (),
+ BUILDDIR"/libide",
+ "Ide", "1.0", 0, NULL);
+
+ if ((dir = g_dir_open (BUILDDIR"/plugins", 0, NULL)))
+ {
+ const gchar *name;
+
+ while ((name = g_dir_read_name (dir)))
+ {
+ gchar *path;
+
+ path = g_build_filename (BUILDDIR, "plugins", name, NULL);
+ peas_engine_prepend_search_path (engine, path, path);
+ g_free (path);
+ }
+
+ g_dir_close (dir);
+ }
+ }
+ else
+ {
+ peas_engine_prepend_search_path (engine,
+ PACKAGE_LIBDIR"/gnome-builder/plugins",
+ PACKAGE_DATADIR"/gnome-builder/plugins");
+ }
+
+ peas_engine_prepend_search_path (engine,
+ "resource:///org/gnome/builder/plugins/editor",
+ "resource:///org/gnome/builder/plugins/editor");
+
+ peas_engine_rescan_plugins (engine);
+
+ list = peas_engine_get_plugin_list (engine);
+
+ for (; list; list = list->next)
+ {
+ PeasPluginInfo *plugin_info = list->data;
+
+ g_debug ("Discovered plugin \"%s\"",
+ peas_plugin_info_get_module_name (plugin_info));
+ }
+}
+
+void
+ide_application_load_plugins (IdeApplication *self)
+{
+ PeasEngine *engine;
+ const GList *list;
+
+ g_return_if_fail (IDE_IS_APPLICATION (self));
+
+ engine = peas_engine_get_default ();
+ list = peas_engine_get_plugin_list (engine);
+
+ for (; list; list = list->next)
+ {
+ PeasPluginInfo *plugin_info = list->data;
+
+ if (ide_application_can_load_plugin (self, plugin_info))
+ {
+ g_debug ("Loading plugin \"%s\"",
+ peas_plugin_info_get_module_name (plugin_info));
+ peas_engine_load_plugin (engine, plugin_info);
+ }
+ }
+}
+
+static void
+ide_application_addin_added (PeasExtensionSet *set,
+ PeasPluginInfo *plugin_info,
+ PeasExtension *extension,
+ gpointer user_data)
+{
+ IdeApplication *self = user_data;
+
+ g_assert (PEAS_IS_EXTENSION_SET (set));
+ g_assert (plugin_info != NULL);
+ g_assert (IDE_IS_APPLICATION_ADDIN (extension));
+
+ ide_application_addin_load (IDE_APPLICATION_ADDIN (extension), self);
+}
+
+static void
+ide_application_addin_removed (PeasExtensionSet *set,
+ PeasPluginInfo *plugin_info,
+ PeasExtension *extension,
+ gpointer user_data)
+{
+ IdeApplication *self = user_data;
+
+ g_assert (PEAS_IS_EXTENSION_SET (set));
+ g_assert (plugin_info != NULL);
+ g_assert (IDE_IS_APPLICATION_ADDIN (extension));
+
+ ide_application_addin_unload (IDE_APPLICATION_ADDIN (extension), self);
+}
+
+void
+ide_application_load_addins (IdeApplication *self)
+{
+ g_return_if_fail (IDE_IS_APPLICATION (self));
+
+ self->addins = peas_extension_set_new (peas_engine_get_default (),
+ IDE_TYPE_APPLICATION_ADDIN,
+ NULL);
+
+ g_signal_connect_object (self->addins,
+ "extension-added",
+ G_CALLBACK (ide_application_addin_added),
+ self,
+ 0);
+
+ g_signal_connect_object (self->addins,
+ "extension-removed",
+ G_CALLBACK (ide_application_addin_removed),
+ self,
+ 0);
+
+ peas_extension_set_foreach (self->addins,
+ ide_application_addin_added,
+ self);
+}
diff --git a/libide/ide-application-private.h b/libide/ide-application-private.h
index cf3856f..911d350 100644
--- a/libide/ide-application-private.h
+++ b/libide/ide-application-private.h
@@ -1,4 +1,4 @@
-/* gb-application-private.h
+/* ide-application-private.h
*
* Copyright (C) 2015 Christian Hergert <christian hergert me>
*
@@ -19,10 +19,10 @@
#ifndef IDE_APPLICATION_PRIVATE_H
#define IDE_APPLICATION_PRIVATE_H
-#include <gtk/gtk.h>
#include <gio/gio.h>
#include <libpeas/peas.h>
+#include "ide-application.h"
#include "ide-keybindings.h"
#include "ide-recent-projects.h"
#include "ide-worker-manager.h"
@@ -31,20 +31,32 @@ G_BEGIN_DECLS
struct _IdeApplication
{
- GtkApplication parent_instance;
-
- gchar *argv0;
- gchar *dbus_address;
- PeasExtensionSet *extensions;
- GtkWindowGroup *greeter_group;
- IdeKeybindings *keybindings;
- GtkWindow *preferences_window;
- IdeRecentProjects *recent_projects;
- GDateTime *startup_time;
- gchar *type;
- IdeWorkerManager *worker_manager;
+ GtkApplication parent_instance;
+
+ IdeApplicationMode mode;
+
+ PeasExtensionSet *addins;
+ gchar *dbus_address;
+
+ PeasPluginInfo *tool;
+ gchar **tool_arguments;
+
+ PeasPluginInfo *worker;
+
+ IdeWorkerManager *worker_manager;
+
+ IdeKeybindings *keybindings;
+
+ IdeRecentProjects *recent_projects;
};
+void ide_application_discover_plugins (IdeApplication *self) G_GNUC_INTERNAL;
+void ide_application_load_plugins (IdeApplication *self) G_GNUC_INTERNAL;
+void ide_application_load_addins (IdeApplication *self) G_GNUC_INTERNAL;
+gboolean ide_application_local_command_line (GApplication *application,
+ gchar ***arguments,
+ gint *exit_status) G_GNUC_INTERNAL;
+
G_END_DECLS
-#endif /* GB_APPLICATION_PRIVATE_H */
+#endif /* IDE_APPLICATION_PRIVATE_H */
diff --git a/libide/ide-application-tool.c b/libide/ide-application-tool.c
new file mode 100644
index 0000000..fe0d43f
--- /dev/null
+++ b/libide/ide-application-tool.c
@@ -0,0 +1,51 @@
+/* ide-application-tool.c
+ *
+ * Copyright (C) 2015 Christian Hergert <christian hergert me>
+ *
+ * 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 3 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "ide-application-tool.h"
+
+G_DEFINE_INTERFACE (IdeApplicationTool, ide_application_tool, G_TYPE_OBJECT)
+
+static void
+ide_application_tool_default_init (IdeApplicationToolInterface *iface)
+{
+}
+
+void
+ide_application_tool_run_async (IdeApplicationTool *self,
+ const gchar * const *arguments,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ g_return_if_fail (IDE_IS_APPLICATION_TOOL (self));
+ g_return_if_fail (arguments != NULL);
+ g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable));
+
+ IDE_APPLICATION_TOOL_GET_IFACE (self)->run_async (self, arguments, cancellable, callback, user_data);
+}
+
+gint
+ide_application_tool_run_finish (IdeApplicationTool *self,
+ GAsyncResult *result,
+ GError **error)
+{
+ g_return_val_if_fail (IDE_IS_APPLICATION_TOOL (self), 0);
+ g_return_val_if_fail (G_IS_ASYNC_RESULT (result), 0);
+
+ return IDE_APPLICATION_TOOL_GET_IFACE (self)->run_finish (self, result, error);
+}
diff --git a/libide/ide-application-tool.h b/libide/ide-application-tool.h
new file mode 100644
index 0000000..6ccabee
--- /dev/null
+++ b/libide/ide-application-tool.h
@@ -0,0 +1,55 @@
+/* ide-application-tool.h
+ *
+ * Copyright (C) 2015 Christian Hergert <christian hergert me>
+ *
+ * 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 3 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef IDE_APPLICATION_TOOL_H
+#define IDE_APPLICATION_TOOL_H
+
+#include <gio/gio.h>
+
+G_BEGIN_DECLS
+
+#define IDE_TYPE_APPLICATION_TOOL (ide_application_tool_get_type())
+
+G_DECLARE_INTERFACE (IdeApplicationTool, ide_application_tool, IDE, APPLICATION_TOOL, GObject)
+
+struct _IdeApplicationToolInterface
+{
+ GTypeInterface parent_interface;
+
+ void (*run_async) (IdeApplicationTool *self,
+ const gchar * const *arguments,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+ gint (*run_finish) (IdeApplicationTool *self,
+ GAsyncResult *result,
+ GError **error);
+};
+
+void ide_application_tool_run_async (IdeApplicationTool *self,
+ const gchar * const *arguments,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+gint ide_application_tool_run_finish (IdeApplicationTool *self,
+ GAsyncResult *result,
+ GError **error);
+
+G_END_DECLS
+
+#endif /* IDE_APPLICATION_TOOL_H */
diff --git a/libide/ide-application.c b/libide/ide-application.c
index 6881346..ab03738 100644
--- a/libide/ide-application.c
+++ b/libide/ide-application.c
@@ -1,6 +1,6 @@
/* ide-application.c
*
- * Copyright (C) 2014 Christian Hergert <christian hergert me>
+ * Copyright (C) 2015 Christian Hergert <christian hergert me>
*
* 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
@@ -16,32 +16,28 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#define G_LOG_DOMAIN "ide-application"
-
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
-#ifdef __linux
-# include <sys/prctl.h>
-#endif
-
#include <glib/gi18n.h>
+#include <girepository.h>
#include <gtksourceview/gtksource.h>
#include <libgit2-glib/ggit.h>
+#include <locale.h>
+#include <stdlib.h>
+#include <sys/prctl.h>
#include "ide-application.h"
-#include "ide-application-actions.h"
-#include "ide-application-addin.h"
#include "ide-application-private.h"
+#include "ide-application-tool.h"
#include "ide-css-provider.h"
#include "ide-debug.h"
+#include "ide-global.h"
+#include "ide-icons-resources.h"
#include "ide-internal.h"
-#include "ide-file.h"
-#include "ide-log.h"
#include "ide-macros.h"
#include "ide-resources.h"
-#include "ide-vcs.h"
#include "ide-workbench.h"
#include "ide-worker.h"
@@ -49,211 +45,32 @@
G_DEFINE_TYPE (IdeApplication, ide_application, GTK_TYPE_APPLICATION)
-static gboolean
-ide_application_can_load_plugin (IdeApplication *self,
- PeasPluginInfo *plugin_info)
-{
- const gchar *plugin_name;
-
- g_assert (IDE_IS_APPLICATION (self));
- g_assert (plugin_info != NULL);
-
- /* Currently we only allow in-tree plugins */
- if (!peas_plugin_info_is_builtin (plugin_info))
- return FALSE;
-
- plugin_name = peas_plugin_info_get_module_name (plugin_info);
-
- /* If --type was specified, only that plugin may be loaded */
- if ((self->type != NULL) && !ide_str_equal0 (plugin_name, self->type))
- return FALSE;
-
- return TRUE;
-}
-
-static void
-ide_application_load_plugins (IdeApplication *self)
-{
- PeasEngine *engine = peas_engine_get_default ();
- const GList *list;
- const GList *iter;
-
- peas_engine_enable_loader (engine, "python3");
-
- if (g_getenv ("GB_IN_TREE_PLUGINS") != NULL)
- {
- GDir *dir;
-
- g_irepository_require_private (g_irepository_get_default (),
- BUILDDIR"/libide",
- "Ide", "1.0", 0, NULL);
-
- if ((dir = g_dir_open (BUILDDIR"/plugins", 0, NULL)))
- {
- const gchar *name;
-
- while ((name = g_dir_read_name (dir)))
- {
- gchar *path;
-
- path = g_build_filename (BUILDDIR, "plugins", name, NULL);
- peas_engine_prepend_search_path (engine, path, path);
- g_free (path);
- }
-
- g_dir_close (dir);
- }
- }
- else
- {
- peas_engine_prepend_search_path (engine,
- PACKAGE_LIBDIR"/gnome-builder/plugins",
- PACKAGE_DATADIR"/gnome-builder/plugins");
- }
-
- peas_engine_prepend_search_path (engine,
- "resource:///org/gnome/builder/plugins/editor",
- "resource:///org/gnome/builder/plugins/editor");
-
- peas_engine_rescan_plugins (engine);
-
- list = peas_engine_get_plugin_list (engine);
-
- for (iter = list; iter; iter = iter->next)
- g_debug ("Discovered plugin \"%s\"", peas_plugin_info_get_module_name (iter->data));
-
- for (iter = list; iter; iter = iter->next)
- {
- PeasPluginInfo *plugin_info = iter->data;
-
- if (ide_application_can_load_plugin (self, plugin_info))
- {
- g_debug ("Loading plugin \"%s\"", peas_plugin_info_get_module_name (plugin_info));
- peas_engine_load_plugin (engine, plugin_info);
- }
- }
-}
-
-static gboolean
-ide_application_is_worker (IdeApplication *self)
-{
- g_assert (IDE_IS_APPLICATION (self));
-
- return (self->type != NULL) && (self->dbus_address != NULL);
-}
-
-static void
-ide_application_load_worker (IdeApplication *self)
-{
- g_autoptr(GDBusConnection) connection = NULL;
- PeasEngine *engine;
- PeasPluginInfo *plugin_info;
- GError *error = NULL;
-
- IDE_ENTRY;
-
- g_assert (IDE_IS_APPLICATION (self));
- g_assert (ide_application_is_worker (self));
-
-#ifdef __linux
- /* Ensure we are killed with our parent */
- prctl (PR_SET_PDEATHSIG, 15);
-#endif
-
- IDE_TRACE_MSG ("Connecting to %s", self->dbus_address);
-
- connection = g_dbus_connection_new_for_address_sync (self->dbus_address,
- (G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT |
- G_DBUS_CONNECTION_FLAGS_DELAY_MESSAGE_PROCESSING),
- NULL, NULL, &error);
-
- if (error != NULL)
- {
- g_error ("DBus failure: %s", error->message);
- g_clear_error (&error);
- IDE_EXIT;
- }
-
- g_assert (G_IS_DBUS_CONNECTION (connection));
-
- engine = peas_engine_get_default ();
- plugin_info = peas_engine_get_plugin_info (engine, self->type);
-
- if ((plugin_info != NULL) && peas_plugin_info_is_loaded (plugin_info))
- {
- PeasExtension *exten;
-
- exten = peas_engine_create_extension (engine, plugin_info, IDE_TYPE_WORKER, NULL);
-
- if (exten != NULL)
- {
- ide_worker_register_service (IDE_WORKER (exten), connection);
- IDE_GOTO (success);
- }
- }
-
- g_error ("Failed to create \"%s\" worker.", self->type);
-
- IDE_EXIT;
-
-success:
- g_application_hold (G_APPLICATION (self));
- g_dbus_connection_start_message_processing (connection);
-
- IDE_EXIT;
-}
-
-static void
-ide_application_setup_search_paths (void)
-{
- GtkSourceStyleSchemeManager *style_scheme_manager;
- static gboolean initialized;
-
- if (initialized)
- return;
-
- style_scheme_manager = gtk_source_style_scheme_manager_get_default ();
- gtk_source_style_scheme_manager_append_search_path (style_scheme_manager,
- PACKAGE_DATADIR"/gtksourceview-3.0/styles/");
- initialized = TRUE;
-}
-
-/**
- * ide_application_make_skeleton_dirs:
- * @self: A #IdeApplication.
- *
- * Creates all the directories we might need later. Simpler to just ensure they
- * are created during startup.
- */
static void
ide_application_make_skeleton_dirs (IdeApplication *self)
{
gchar *path;
+ IDE_ENTRY;
+
g_return_if_fail (IDE_IS_APPLICATION (self));
- path = g_build_filename (g_get_user_data_dir (),
- "gnome-builder",
- NULL);
+ path = g_build_filename (g_get_user_data_dir (), "gnome-builder", NULL);
g_mkdir_with_parents (path, 0750);
g_free (path);
- path = g_build_filename (g_get_user_config_dir (),
- "gnome-builder",
- NULL);
+ path = g_build_filename (g_get_user_config_dir (), "gnome-builder", NULL);
g_mkdir_with_parents (path, 0750);
g_free (path);
- path = g_build_filename (g_get_user_config_dir (),
- "gnome-builder",
- "snippets",
- NULL);
+ path = g_build_filename (g_get_user_config_dir (), "gnome-builder", "snippets", NULL);
g_mkdir_with_parents (path, 0750);
g_free (path);
+
+ IDE_EXIT;
}
static void
-ide_application_register_theme_overrides (IdeApplication *application)
+ide_application_register_theme_overrides (IdeApplication *self)
{
g_autoptr(GSettings) settings = NULL;
g_autoptr(GtkCssProvider) provider = NULL;
@@ -262,7 +79,10 @@ ide_application_register_theme_overrides (IdeApplication *application)
IDE_ENTRY;
- gtk_icon_theme_add_resource_path (gtk_icon_theme_get_default (), "/org/gnome/builder/icons/");
+ g_assert (IDE_IS_APPLICATION (self));
+
+ gtk_icon_theme_add_resource_path (gtk_icon_theme_get_default (),
+ "/org/gnome/builder/icons/");
provider = ide_css_provider_new ();
screen = gdk_screen_get_default ();
@@ -271,40 +91,20 @@ ide_application_register_theme_overrides (IdeApplication *application)
gtk_settings = gtk_settings_get_for_screen (screen);
settings = g_settings_new ("org.gnome.builder");
- g_settings_bind (settings, "night-mode", gtk_settings, "gtk-application-prefer-dark-theme",
+ g_settings_bind (settings, "night-mode",
+ gtk_settings, "gtk-application-prefer-dark-theme",
G_SETTINGS_BIND_DEFAULT);
IDE_EXIT;
}
static void
-ide_application_load_keybindings (IdeApplication *self)
+ide_application_register_keybindings (IdeApplication *self)
{
g_autoptr(GSettings) settings = NULL;
g_autofree gchar *name = NULL;
- /* TODO: Move this to keybindings */
- static const struct { gchar *name; gchar *binding; } shared_bindings[] = {
- { "workbench.show-left-pane", "F9" },
- { "workbench.show-right-pane", "<shift>F9" },
- { "workbench.show-bottom-pane", "<ctrl>F9" },
- { "workbench.toggle-panels", "<ctrl><shift>F9" },
- { "workbench.focus-left", "<ctrl>grave" },
- { "workbench.focus-right", "<ctrl>9" },
- { "workbench.focus-stack(1)", "<ctrl>1" },
- { "workbench.focus-stack(2)", "<ctrl>2" },
- { "workbench.focus-stack(3)", "<ctrl>3" },
- { "workbench.focus-stack(4)", "<ctrl>4" },
- { "workbench.focus-stack(5)", "<ctrl>5" },
- { "workbench.show-gear-menu", "F10" },
- { "perspective.global-search", "<ctrl>period" },
- { "app.preferences", "<Primary>comma" },
- { "app.shortcuts", "<ctrl>question" },
- { "workbench.new-document", "<ctrl>n" },
- { "workbench.open-document", "<ctrl>o" },
- { NULL }
- };
- gsize i;
+ IDE_ENTRY;
g_assert (IDE_IS_APPLICATION (self));
@@ -313,267 +113,45 @@ ide_application_load_keybindings (IdeApplication *self)
self->keybindings = ide_keybindings_new (GTK_APPLICATION (self), name);
g_settings_bind (settings, "keybindings", self->keybindings, "mode", G_SETTINGS_BIND_GET);
- for (i = 0; shared_bindings [i].name; i++)
- {
- const gchar *accels[2] = { shared_bindings [i].binding, NULL };
- gtk_application_set_accels_for_action (GTK_APPLICATION (self),
- shared_bindings [i].name,
- accels);
- }
+ IDE_EXIT;
}
-static IdeWorkbench *
-ide_application_find_workbench_for_file (IdeApplication *self,
- GFile *file)
+static void
+ide_application_register_search_paths (IdeApplication *self)
{
- GList *iter;
- GList *workbenches;
-
g_assert (IDE_IS_APPLICATION (self));
- g_assert (G_IS_FILE (file));
-
- workbenches = gtk_application_get_windows (GTK_APPLICATION (self));
-
- /*
- * Find the a project that contains this file in its working directory.
- */
- for (iter = workbenches; iter; iter = iter->next)
- {
- if (IDE_IS_WORKBENCH (iter->data))
- {
- IdeWorkbench *workbench = iter->data;
- g_autofree gchar *relpath = NULL;
- IdeContext *context;
- IdeVcs *vcs;
- GFile *workdir;
- context = ide_workbench_get_context (workbench);
- vcs = ide_context_get_vcs (context);
- workdir = ide_vcs_get_working_directory (vcs);
-
- relpath = g_file_get_relative_path (workdir, file);
-
- if (relpath != NULL)
- return workbench;
- }
- }
-
- /*
- * No matches found, take the first workbench we find.
- */
- for (iter = workbenches; iter; iter = iter->next)
- if (IDE_IS_WORKBENCH (iter->data))
- return iter->data;
-
- return NULL;
+ gtk_source_style_scheme_manager_append_search_path (gtk_source_style_scheme_manager_get_default (),
+ PACKAGE_DATADIR"/gtksourceview-3.0/styles/");
+ g_irepository_prepend_search_path (PACKAGE_LIBDIR"/gnome-builder/girepository-1.0");
}
static void
-ide_application__context_new_cb (GObject *object,
- GAsyncResult *result,
- gpointer user_data)
+ide_application_register_ggit (IdeApplication *self)
{
- g_autoptr(GTask) task = user_data;
- g_autoptr(IdeContext) context = NULL;
- IdeApplication *self;
- IdeWorkbench *workbench;
- GPtrArray *ar;
- GError *error = NULL;
- gsize i;
-
- g_assert (G_IS_TASK (task));
-
- self = g_task_get_source_object (task);
- ar = g_task_get_task_data (task);
+ GgitFeatureFlags ggit_flags;
g_assert (IDE_IS_APPLICATION (self));
- g_assert (ar);
-
- context = ide_context_new_finish (result, &error);
-
- if (!context)
- {
- g_task_return_error (task, error);
- goto cleanup;
- }
-
- {
- IdeVcs *vcs;
- GFile *workdir;
- g_autofree gchar *path = NULL;
- vcs = ide_context_get_vcs (context);
- workdir = ide_vcs_get_working_directory (vcs);
- path = g_file_get_path (workdir);
-
- g_debug ("Project working directory: %s", path);
- }
+ ggit_init ();
- workbench = g_object_new (IDE_TYPE_WORKBENCH,
- "application", self,
- "context", context,
- NULL);
+ ggit_flags = ggit_get_features ();
- for (i = 0; i < ar->len; i++)
+ if ((ggit_flags & GGIT_FEATURE_THREADS) == 0)
{
- GFile *file;
-
- file = g_ptr_array_index (ar, i);
- g_assert (G_IS_FILE (file));
-
- //ide_workbench_open (workbench, file);
+ g_error (_("Builder requires libgit2-glib with threading support."));
+ exit (EXIT_FAILURE);
}
- gtk_window_present (GTK_WINDOW (workbench));
-
- g_task_return_boolean (task, TRUE);
-
-cleanup:
- g_application_unmark_busy (G_APPLICATION (self));
- g_application_release (G_APPLICATION (self));
-}
-
-/**
- * ide_application_open_project_async:
- * @self: A #IdeApplication.
- * @file: A #GFile.
- * @additional_files: (element-type GFile) (nullable): A #GPtrArray of #GFile or %NULL.
- *
- */
-void
-ide_application_open_project_async (IdeApplication *self,
- GFile *file,
- GPtrArray *additional_files,
- GCancellable *cancellable,
- GAsyncReadyCallback callback,
- gpointer user_data)
-{
- g_autoptr(GFile) directory = NULL;
- g_autoptr(GTask) task = NULL;
- g_autoptr(GPtrArray) ar = NULL;
- GList *windows;
- GList *iter;
-
- g_return_if_fail (IDE_IS_APPLICATION (self));
- g_return_if_fail (G_IS_FILE (file));
- g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable));
-
- task = g_task_new (self, cancellable, callback, user_data);
-
- windows = gtk_application_get_windows (GTK_APPLICATION (self));
-
- for (iter = windows; iter; iter = iter->next)
+ if ((ggit_flags & GGIT_FEATURE_SSH) == 0)
{
- if (IDE_IS_WORKBENCH (iter->data))
- {
- IdeContext *context;
-
- context = ide_workbench_get_context (iter->data);
-
- if (context != NULL)
- {
- GFile *project_file;
-
- project_file = ide_context_get_project_file (context);
-
- if (g_file_equal (file, project_file))
- {
- gtk_window_present (iter->data);
- g_task_return_boolean (task, TRUE);
- return;
- }
- }
- }
+ g_error (_("Builder requires libgit2-glib with SSH support."));
+ exit (EXIT_FAILURE);
}
-
- if (additional_files)
- ar = g_ptr_array_ref (additional_files);
- else
- ar = g_ptr_array_new ();
-
- g_task_set_task_data (task, g_ptr_array_ref (ar), (GDestroyNotify)g_ptr_array_unref);
-
- if (g_file_query_file_type (file, 0, NULL) == G_FILE_TYPE_DIRECTORY)
- directory = g_object_ref (file);
- else
- directory = g_file_get_parent (file);
-
- g_application_mark_busy (G_APPLICATION (self));
- g_application_hold (G_APPLICATION (self));
-
- ide_context_new_async (directory,
- NULL,
- ide_application__context_new_cb,
- g_object_ref (task));
-}
-
-gboolean
-ide_application_open_project_finish (IdeApplication *self,
- GAsyncResult *result,
- GError **error)
-{
- GTask *task = (GTask *)result;
-
- g_return_val_if_fail (IDE_IS_APPLICATION (self), FALSE);
- g_return_val_if_fail (G_IS_ASYNC_RESULT (result), FALSE);
- g_return_val_if_fail (G_IS_TASK (task), FALSE);
-
- return g_task_propagate_boolean (task, error);
}
static void
-ide_application_open (GApplication *application,
- GFile **files,
- gint n_files,
- const gchar *hint)
-{
- IdeApplication *self = (IdeApplication *)application;
- IdeWorkbench *workbench;
- g_autoptr(GPtrArray) ar = NULL;
- guint i;
-
- IDE_ENTRY;
-
- g_assert (IDE_IS_APPLICATION (self));
-
- /*
- * Try to open the files using an existing workbench.
- */
- for (i = 0; i < n_files; i++)
- {
- GFile *file = files [i];
-
- g_assert (G_IS_FILE (file));
-
- workbench = ide_application_find_workbench_for_file (self, file);
-
- if (workbench != NULL)
- {
- //ide_workbench_open (workbench, file);
- gtk_window_present (GTK_WINDOW (workbench));
- continue;
- }
-
- if (!ar)
- ar = g_ptr_array_new_with_free_func (g_object_unref);
- g_ptr_array_add (ar, g_object_ref (file));
- }
-
- /*
- * No workbench found for these files, let's create one!
- */
- if (ar && ar->len)
- {
- GFile *file = g_ptr_array_index (ar, 0);
-
- ide_application_open_project_async (self, file, ar, NULL, NULL, NULL);
- }
-
- IDE_EXIT;
-}
-
-void
-ide_application_show_projects_window (IdeApplication *self)
+ide_application_activate_primary (IdeApplication *self)
{
GtkWindow *window;
GList *windows;
@@ -588,15 +166,8 @@ ide_application_show_projects_window (IdeApplication *self)
if (IDE_IS_WORKBENCH (window))
{
- const gchar *name;
-
- name = ide_workbench_get_visible_perspective_name (IDE_WORKBENCH (window));
-
- if (ide_str_equal0 ("greeter", name))
- {
- gtk_window_present (windows->data);
- return;
- }
+ gtk_window_present (window);
+ return;
}
}
@@ -607,195 +178,169 @@ ide_application_show_projects_window (IdeApplication *self)
}
static void
-ide_application_activate (GApplication *application)
+ide_application_activate_worker (IdeApplication *self)
{
- IdeApplication *self = (IdeApplication *)application;
- IdeWorkbench *workbench;
- GList *list;
+ g_autoptr(GDBusConnection) connection = NULL;
+ PeasExtension *extension;
+ PeasEngine *engine;
+ GError *error = NULL;
+
+ IDE_ENTRY;
g_assert (IDE_IS_APPLICATION (self));
+ g_assert (self->worker != NULL);
+ g_assert (self->dbus_address != NULL);
+
+#ifdef __linux
+ /* Ensure we are killed with our parent */
+ prctl (PR_SET_PDEATHSIG, 15);
+#endif
+
+ IDE_TRACE_MSG ("Connecting to %s", self->dbus_address);
- if (ide_application_is_worker (self))
+ connection = g_dbus_connection_new_for_address_sync (self->dbus_address,
+ (G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT |
+ G_DBUS_CONNECTION_FLAGS_DELAY_MESSAGE_PROCESSING),
+ NULL, NULL, &error);
+
+ if (error != NULL)
{
- ide_application_load_worker (self);
- return;
+ g_error ("DBus failure: %s", error->message);
+ g_clear_error (&error);
+ IDE_EXIT;
}
- list = gtk_application_get_windows (GTK_APPLICATION (application));
+ engine = peas_engine_get_default ();
+ extension = peas_engine_create_extension (engine, self->worker, IDE_TYPE_WORKER, NULL);
- for (; list; list = list->next)
+ if (extension == NULL)
{
- if (IDE_IS_WORKBENCH (list->data))
- {
- gtk_window_present (GTK_WINDOW (list->data));
- return;
- }
+ g_error ("Failed to create \"%s\" worker",
+ peas_plugin_info_get_module_name (self->worker));
+ IDE_EXIT;
}
- workbench = g_object_new (IDE_TYPE_WORKBENCH,
- "application", self,
- NULL);
- gtk_window_present (GTK_WINDOW (workbench));
+ ide_worker_register_service (IDE_WORKER (extension), connection);
+ g_application_hold (G_APPLICATION (self));
+ g_dbus_connection_start_message_processing (connection);
+
+ IDE_EXIT;
}
static void
-ide_application__extension_added (PeasExtensionSet *extensions,
- PeasPluginInfo *plugin_info,
- IdeApplicationAddin *addin,
- IdeApplication *self)
+ide_application_activate_tool_cb (GObject *object,
+ GAsyncResult *result,
+ gpointer user_data)
{
+ IdeApplicationTool *tool = (IdeApplicationTool *)object;
+ g_autoptr(IdeApplication) self = user_data;
+ GError *error = NULL;
+ gint exit_code;
+
g_assert (IDE_IS_APPLICATION (self));
- g_assert (plugin_info != NULL);
- g_assert (IDE_IS_APPLICATION_ADDIN (addin));
- g_assert (PEAS_IS_EXTENSION_SET (extensions));
+ g_assert (IDE_IS_APPLICATION_TOOL (tool));
- ide_application_addin_load (addin, self);
-}
+ exit_code = ide_application_tool_run_finish (tool, result, &error);
-static void
-ide_application__extension_removed (PeasExtensionSet *extensions,
- PeasPluginInfo *plugin_info,
- IdeApplicationAddin *addin,
- IdeApplication *self)
-{
- g_assert (IDE_IS_APPLICATION (self));
- g_assert (plugin_info != NULL);
- g_assert (IDE_IS_APPLICATION_ADDIN (addin));
- g_assert (PEAS_IS_EXTENSION_SET (extensions));
+ if (error != NULL)
+ {
+ g_printerr ("%s\n", error->message);
+ g_clear_error (&error);
+ }
- ide_application_addin_unload (addin, self);
+ /* GApplication does not provide a way to pass exit code. */
+ if (exit_code != 0)
+ exit (exit_code);
+
+ g_application_release (G_APPLICATION (self));
}
static void
-ide_application_load_addins (IdeApplication *self)
+ide_application_activate_tool (IdeApplication *self)
{
PeasEngine *engine;
+ PeasExtension *tool;
g_assert (IDE_IS_APPLICATION (self));
+ g_assert (self->tool != NULL);
+ g_assert (self->tool_arguments != NULL);
engine = peas_engine_get_default ();
+ tool = peas_engine_create_extension (engine,
+ self->tool,
+ IDE_TYPE_APPLICATION_TOOL,
+ NULL);
+ if (tool == NULL)
+ return;
- self->extensions = peas_extension_set_new (engine, IDE_TYPE_APPLICATION_ADDIN, NULL);
-
- peas_extension_set_foreach (self->extensions,
- (PeasExtensionSetForeachFunc)ide_application__extension_added,
- self);
+ g_application_hold (G_APPLICATION (self));
- g_signal_connect_object (self->extensions,
- "extension-added",
- G_CALLBACK (ide_application__extension_added),
- self,
- 0);
+ ide_application_tool_run_async (IDE_APPLICATION_TOOL (tool),
+ (const gchar * const *)self->tool_arguments,
+ NULL,
+ ide_application_activate_tool_cb,
+ g_object_ref (self));
- g_signal_connect_object (self->extensions,
- "extension-removed",
- G_CALLBACK (ide_application__extension_removed),
- self,
- 0);
+ g_object_unref (tool);
}
static void
-ide_application_startup (GApplication *app)
+ide_application_activate (GApplication *application)
{
- IdeApplication *self = (IdeApplication *)app;
- GgitFeatureFlags ggit_flags;
-
- IDE_ENTRY;
+ IdeApplication *self = (IdeApplication *)application;
g_assert (IDE_IS_APPLICATION (self));
- self->startup_time = g_date_time_new_now_utc ();
-
- g_resources_register (ide_get_resource ());
-
- g_application_set_resource_base_path (app, "/org/gnome/builder");
-
- g_irepository_prepend_search_path (PACKAGE_LIBDIR"/gnome-builder/girepository-1.0");
-
- if (!ide_application_is_worker (self))
- self->greeter_group = gtk_window_group_new ();
-
- _ide_battery_monitor_init ();
- _ide_thread_pool_init (ide_application_is_worker (self));
-
- modeline_parser_init ();
+ if (self->mode == IDE_APPLICATION_MODE_PRIMARY)
+ ide_application_activate_primary (self);
+ else if (self->mode == IDE_APPLICATION_MODE_WORKER)
+ ide_application_activate_worker (self);
+ else if (self->mode == IDE_APPLICATION_MODE_TOOL)
+ ide_application_activate_tool (self);
+}
- ggit_init ();
+static void
+ide_application_startup (GApplication *application)
+{
+ IdeApplication *self = (IdeApplication *)application;
+ gboolean small_thread_pool;
- ggit_flags = ggit_get_features ();
+ g_assert (IDE_IS_APPLICATION (self));
- if ((ggit_flags & GGIT_FEATURE_THREADS) == 0)
- {
- g_error (_("Builder requires libgit2-glib with threading support."));
- exit (EXIT_FAILURE);
- }
+ g_resources_register (ide_get_resource ());
+ g_resources_register (ide_icons_get_resource ());
- if ((ggit_flags & GGIT_FEATURE_SSH) == 0)
- {
- g_error (_("Builder requires libgit2-glib with SSH support."));
- exit (EXIT_FAILURE);
- }
+ g_application_set_resource_base_path (application, "/org/gnome/builder");
+ ide_application_register_search_paths (self);
- G_APPLICATION_CLASS (ide_application_parent_class)->startup (app);
+ small_thread_pool = (self->mode != IDE_APPLICATION_MODE_PRIMARY);
+ _ide_thread_pool_init (small_thread_pool);
- if (!ide_application_is_worker (self))
+ if (self->mode == IDE_APPLICATION_MODE_PRIMARY)
{
ide_application_make_skeleton_dirs (self);
- ide_application_actions_init (self);
ide_application_register_theme_overrides (self);
- ide_application_setup_search_paths ();
- ide_application_load_keybindings (self);
- ide_application_load_plugins (self);
- ide_application_load_addins (self);
- }
-
- IDE_EXIT;
-}
-
-static gboolean
-ide_application_increase_verbosity (void)
-{
- ide_log_increase_verbosity ();
- return TRUE;
-}
+ ide_application_register_keybindings (self);
+ ide_application_register_ggit (self);
-static gint
-ide_application_handle_local_options (GApplication *app,
- GVariantDict *options)
-{
- if (g_variant_dict_contains (options, "version"))
- {
- g_print ("%s - Version %s\n", g_get_application_name (), VERSION);
- return 0;
+ modeline_parser_init ();
}
- if (g_variant_dict_contains (options, "standalone") || g_variant_dict_contains (options, "type"))
- {
- GApplicationFlags flags;
+ _ide_battery_monitor_init ();
- flags = g_application_get_flags (app);
- g_application_set_flags (app, flags | G_APPLICATION_NON_UNIQUE);
- }
+ G_APPLICATION_CLASS (ide_application_parent_class)->startup (application);
- return -1;
+ ide_application_load_addins (self);
}
-static gboolean
-ide_application_local_command_line (GApplication *application,
- gchar ***arguments,
- int *exit_status)
+static void
+ide_application_open (GApplication *application,
+ GFile **files,
+ gint n_files,
+ const gchar *hint)
{
- IdeApplication *self = (IdeApplication *)application;
-
- g_assert (IDE_IS_APPLICATION (self));
- g_assert (arguments != NULL);
- g_assert (*arguments != NULL);
- g_assert (exit_status != NULL);
-
- self->argv0 = g_strdup ((*arguments) [0]);
+ g_assert (IDE_IS_APPLICATION (application));
- return G_APPLICATION_CLASS (ide_application_parent_class)->
- local_command_line (application, arguments, exit_status);
}
static void
@@ -803,102 +348,61 @@ ide_application_finalize (GObject *object)
{
IdeApplication *self = (IdeApplication *)object;
- IDE_ENTRY;
-
- g_clear_object (&self->extensions);
- g_clear_pointer (&self->startup_time, g_date_time_unref);
- g_clear_pointer (&self->argv0, g_free);
+ g_clear_pointer (&self->dbus_address, g_free);
+ g_clear_pointer (&self->tool_arguments, g_strfreev);
+ g_clear_object (&self->worker_manager);
g_clear_object (&self->keybindings);
g_clear_object (&self->recent_projects);
- g_clear_object (&self->greeter_group);
G_OBJECT_CLASS (ide_application_parent_class)->finalize (object);
-
- IDE_EXIT;
}
static void
ide_application_class_init (IdeApplicationClass *klass)
{
- GApplicationClass *app_class = G_APPLICATION_CLASS (klass);
GObjectClass *object_class = G_OBJECT_CLASS (klass);
-
- IDE_ENTRY;
+ GApplicationClass *g_app_class = G_APPLICATION_CLASS (klass);
object_class->finalize = ide_application_finalize;
- app_class->activate = ide_application_activate;
- app_class->startup = ide_application_startup;
- app_class->open = ide_application_open;
- app_class->local_command_line = ide_application_local_command_line;
- app_class->handle_local_options = ide_application_handle_local_options;
-
- IDE_EXIT;
+ g_app_class->activate = ide_application_activate;
+ g_app_class->local_command_line = ide_application_local_command_line;
+ g_app_class->open = ide_application_open;
+ g_app_class->startup = ide_application_startup;
}
static void
-ide_application_init (IdeApplication *app)
+ide_application_init (IdeApplication *self)
{
- GOptionEntry options[] = {
- { "standalone",
- 's',
- G_OPTION_FLAG_IN_MAIN,
- G_OPTION_ARG_NONE,
- NULL,
- N_("Run Builder in standalone mode") },
-
- { "version",
- 0,
- G_OPTION_FLAG_IN_MAIN,
- G_OPTION_ARG_NONE,
- NULL,
- N_("Show the application's version") },
-
- { "verbose",
- 'v',
- G_OPTION_FLAG_NO_ARG | G_OPTION_FLAG_IN_MAIN | G_OPTION_FLAG_HIDDEN,
- G_OPTION_ARG_CALLBACK,
- ide_application_increase_verbosity,
- N_("Increase verbosity. May be specified multiple times.") },
-
- { "dbus-address",
- 0,
- G_OPTION_FLAG_HIDDEN,
- G_OPTION_ARG_STRING,
- &app->dbus_address,
- N_("The DBus server address for which to connect.") },
-
- { "type",
- 0,
- G_OPTION_FLAG_HIDDEN,
- G_OPTION_ARG_STRING,
- &app->type,
- N_("The type of plugin worker process to run.") },
-
- { NULL }
- };
+ ide_set_program_name (PACKAGE_NAME);
- IDE_ENTRY;
+ self->mode = IDE_APPLICATION_MODE_PRIMARY;
- g_application_add_main_option_entries (G_APPLICATION (app), options);
+ setlocale (LC_ALL, "");
- IDE_EXIT;
+ bindtextdomain (GETTEXT_PACKAGE, PACKAGE_LOCALE_DIR);
+ bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
+ textdomain (GETTEXT_PACKAGE);
+
+ g_set_application_name (_("Builder"));
}
-GDateTime *
-ide_application_get_startup_time (IdeApplication *self)
+IdeApplication *
+ide_application_new (void)
{
- g_return_val_if_fail (IDE_IS_APPLICATION (self), NULL);
+ return g_object_new (IDE_TYPE_APPLICATION,
+ "application-id", "org.gnome.Builder",
+ "flags", G_APPLICATION_HANDLES_OPEN,
+ NULL);
- return self->startup_time;
}
-const gchar *
-ide_application_get_keybindings_mode (IdeApplication *self)
+IdeApplicationMode
+ide_application_get_mode (IdeApplication *self)
{
- g_return_val_if_fail (IDE_IS_APPLICATION (self), NULL);
+ g_return_val_if_fail (IDE_IS_APPLICATION (self), 0);
- return ide_keybindings_get_mode (self->keybindings);
+ return self->mode;
}
static void
@@ -952,8 +456,11 @@ ide_application_get_worker_async (IdeApplication *self,
g_return_if_fail (plugin_name != NULL);
g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable));
+ if (self->mode != IDE_APPLICATION_MODE_PRIMARY)
+ return NULL;
+
if (self->worker_manager == NULL)
- self->worker_manager = ide_worker_manager_new (self->argv0);
+ self->worker_manager = ide_worker_manager_new ("gnome-builder-worker");
task = g_task_new (self, cancellable, callback, user_data);
@@ -1007,6 +514,9 @@ ide_application_get_recent_projects (IdeApplication *self)
{
g_return_val_if_fail (IDE_IS_APPLICATION (self), NULL);
+ if (self->mode != IDE_APPLICATION_MODE_PRIMARY)
+ return NULL;
+
if (self->recent_projects == NULL)
{
self->recent_projects = ide_recent_projects_new ();
@@ -1015,3 +525,51 @@ ide_application_get_recent_projects (IdeApplication *self)
return self->recent_projects;
}
+
+void
+ide_application_show_projects_window (IdeApplication *self)
+{
+ GtkWindow *window;
+ GList *windows;
+
+ g_assert (IDE_IS_APPLICATION (self));
+
+ if (self->mode != IDE_APPLICATION_MODE_PRIMARY)
+ return;
+
+ windows = gtk_application_get_windows (GTK_APPLICATION (self));
+
+ for (; windows; windows = windows->next)
+ {
+ window = windows->data;
+
+ if (IDE_IS_WORKBENCH (window))
+ {
+ const gchar *name;
+
+ name = ide_workbench_get_visible_perspective_name (IDE_WORKBENCH (window));
+
+ if (ide_str_equal0 ("greeter", name))
+ {
+ gtk_window_present (windows->data);
+ return;
+ }
+ }
+ }
+
+ window = g_object_new (IDE_TYPE_WORKBENCH,
+ "application", self,
+ NULL);
+ gtk_window_present (window);
+}
+
+const gchar *
+ide_application_get_keybindings_mode (IdeApplication *self)
+{
+ g_return_val_if_fail (IDE_IS_APPLICATION (self), NULL);
+
+ if (self->mode == IDE_APPLICATION_MODE_PRIMARY)
+ return ide_keybindings_get_mode (self->keybindings);
+
+ return NULL;
+}
diff --git a/libide/ide-application.h b/libide/ide-application.h
index ba2282c..35140fd 100644
--- a/libide/ide-application.h
+++ b/libide/ide-application.h
@@ -1,6 +1,6 @@
/* ide-application.h
*
- * Copyright (C) 2014 Christian Hergert <christian hergert me>
+ * Copyright (C) 2015 Christian Hergert <christian hergert me>
*
* 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
@@ -25,32 +25,31 @@
G_BEGIN_DECLS
-#define IDE_APPLICATION_DEFAULT (IDE_APPLICATION(g_application_get_default()))
#define IDE_TYPE_APPLICATION (ide_application_get_type())
+#define IDE_APPLICATION_DEFAULT (IDE_APPLICATION (g_application_get_default()))
G_DECLARE_FINAL_TYPE (IdeApplication, ide_application, IDE, APPLICATION, GtkApplication)
-const gchar *ide_application_get_keybindings_mode (IdeApplication *self);
-GDateTime *ide_application_get_startup_time (IdeApplication *self);
-IdeRecentProjects *ide_application_get_recent_projects (IdeApplication *self);
-void ide_application_show_projects_window (IdeApplication *self);
-void ide_application_open_project_async (IdeApplication *self,
- GFile *file,
- GPtrArray *additional_files,
- GCancellable *cancellable,
- GAsyncReadyCallback callback,
- gpointer user_data);
-gboolean ide_application_open_project_finish (IdeApplication *self,
- GAsyncResult *result,
- GError **error);
-void ide_application_get_worker_async (IdeApplication *self,
- const gchar *plugin_name,
- GCancellable *cancellable,
- GAsyncReadyCallback callback,
- gpointer user_data);
-GDBusProxy *ide_application_get_worker_finish (IdeApplication *self,
- GAsyncResult *result,
- GError **error);
+typedef enum
+{
+ IDE_APPLICATION_MODE_PRIMARY,
+ IDE_APPLICATION_MODE_WORKER,
+ IDE_APPLICATION_MODE_TOOL,
+} IdeApplicationMode;
+
+IdeApplicationMode ide_application_get_mode (IdeApplication *self);
+IdeApplication *ide_application_new (void);
+IdeRecentProjects *ide_application_get_recent_projects (IdeApplication *self);
+void ide_application_show_projects_window (IdeApplication *self);
+const gchar *ide_application_get_keybindings_mode (IdeApplication *self);
+void ide_application_get_worker_async (IdeApplication *self,
+ const gchar *plugin_name,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+GDBusProxy *ide_application_get_worker_finish (IdeApplication *self,
+ GAsyncResult *result,
+ GError **error);
G_END_DECLS
diff --git a/libide/ide-css-provider.c b/libide/ide-css-provider.c
index 5c84204..7495399 100644
--- a/libide/ide-css-provider.c
+++ b/libide/ide-css-provider.c
@@ -19,9 +19,9 @@
#define G_LOG_DOMAIN "ide-css-provider"
#include <glib/gi18n.h>
-#include <ide.h>
#include "ide-css-provider.h"
+#include "ide-debug.h"
struct _IdeCssProvider
{
diff --git a/libide/ide-keybindings.c b/libide/ide-keybindings.c
index 37b2b32..0f2eaef 100644
--- a/libide/ide-keybindings.c
+++ b/libide/ide-keybindings.c
@@ -19,8 +19,8 @@
#define G_LOG_DOMAIN "ide-keybindings"
#include <glib/gi18n.h>
-#include <ide.h>
+#include "ide-debug.h"
#include "ide-keybindings.h"
struct _IdeKeybindings
diff --git a/libide/ide-workbench.c b/libide/ide-workbench.c
index dc47565..bc38036 100644
--- a/libide/ide-workbench.c
+++ b/libide/ide-workbench.c
@@ -36,7 +36,13 @@ enum {
LAST_PROP
};
+enum {
+ SET_PERSPECTIVE,
+ LAST_SIGNAL
+};
+
static GParamSpec *properties [LAST_PROP];
+static guint signals [LAST_SIGNAL];
static void
ide_workbench_notify_visible_child (IdeWorkbench *self,
@@ -214,6 +220,17 @@ ide_workbench_class_init (IdeWorkbenchClass *klass)
g_object_class_install_properties (object_class, LAST_PROP, properties);
+ /**
+ * IdeWorkbench::set-perspective:
+ */
+ signals [SET_PERSPECTIVE] =
+ g_signal_new_class_handler ("set-perspective",
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
+ G_CALLBACK (ide_workbench_set_visible_perspective_name),
+ NULL, NULL, NULL,
+ G_TYPE_NONE, 1, G_TYPE_STRING);
+
gtk_widget_class_set_css_name (widget_class, "workbench");
gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/builder/ui/ide-workbench.ui");
gtk_widget_class_bind_template_child (widget_class, IdeWorkbench, perspectives_stack);
@@ -332,6 +349,9 @@ ide_workbench_addin_added (PeasExtensionSet *set,
IDE_TRACE_MSG ("Loading workbench addin for %s",
peas_plugin_info_get_module_name (plugin_info));
+ g_print ("================ ADDED: %s\n",
+ peas_plugin_info_get_module_name (plugin_info));
+
ide_workbench_addin_load (IDE_WORKBENCH_ADDIN (extension), self);
}
diff --git a/src/main.c b/src/main.c
index 175851b..06df1a8 100644
--- a/src/main.c
+++ b/src/main.c
@@ -16,38 +16,15 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#define G_LOG_DOMAIN "Builder"
-
-#ifdef HAVE_CONFIG_H
-# include "config.h"
-#endif
-
-#include <glib.h>
-#include <glib/gi18n.h>
-#include <gtk/gtk.h>
#include <ide.h>
-#include <locale.h>
-
-#include "gb-icons-resources.h"
int
main (int argc,
char *argv[])
{
- GApplication *app;
+ IdeApplication *app;
int ret;
- setlocale (LC_ALL, "");
-
- bindtextdomain (GETTEXT_PACKAGE, PACKAGE_LOCALE_DIR);
- bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
- textdomain (GETTEXT_PACKAGE);
-
- g_set_prgname (PACKAGE_TARNAME);
- g_set_application_name (_("Builder"));
-
- ide_set_program_name ("gnome-builder");
-
ide_log_init (TRUE, NULL);
g_message ("Initializing with Gtk+ version %d.%d.%d.",
@@ -55,13 +32,8 @@ main (int argc,
gtk_get_minor_version (),
gtk_get_micro_version ());
- g_resources_register (gb_icons_get_resource ());
-
- app = g_object_new (IDE_TYPE_APPLICATION,
- "application-id", "org.gnome.Builder",
- "flags", G_APPLICATION_HANDLES_OPEN,
- NULL);
- ret = g_application_run (app, argc, argv);
+ app = ide_application_new ();
+ ret = g_application_run (G_APPLICATION (app), argc, argv);
g_clear_object (&app);
ide_log_shutdown ();
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]