[gnome-builder/wip/chergert/runtimes] wip: runtimes
- From: Christian Hergert <chergert src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-builder/wip/chergert/runtimes] wip: runtimes
- Date: Sat, 30 Jan 2016 12:59:47 +0000 (UTC)
commit 362577d80f781174bbf9c710b590fc54844a92f0
Author: Christian Hergert <chergert redhat com>
Date: Fri Jan 29 18:37:38 2016 +0100
wip: runtimes
configure.ac | 3 +-
libide/Makefile.am | 6 +
libide/ide-build-system.c | 21 ++-
libide/ide-build-system.h | 3 +
libide/ide-context.c | 42 ++++
libide/ide-context.h | 1 +
libide/ide-device-manager.c | 3 +
libide/ide-internal.h | 1 +
libide/ide-runtime-manager.c | 236 +++++++++++++++++++++++
libide/ide-runtime-manager.h | 39 ++++
libide/ide-runtime-provider.c | 61 ++++++
libide/ide-runtime-provider.h | 49 +++++
libide/ide-runtime.c | 186 ++++++++++++++++++
libide/ide-runtime.h | 46 +++++
libide/ide-types.h | 3 +
libide/ide.h | 3 +
plugins/Makefile.am | 1 +
plugins/autotools/ide-autotools-build-system.c | 14 ++-
plugins/build-tools/gbp-build-panel.c | 124 ++++++++++++-
plugins/build-tools/gbp-build-panel.ui | 59 ++++++-
plugins/build-tools/gbp-build-tool.c | 14 ++-
plugins/build-tools/gbp-build-workbench-addin.c | 74 +++++++-
plugins/xdg-app/Makefile.am | 38 ++++
plugins/xdg-app/configure.ac | 24 +++
plugins/xdg-app/gbp-xdg-plugin.c | 30 +++
plugins/xdg-app/gbp-xdg-runtime-provider.c | 179 +++++++++++++++++
plugins/xdg-app/gbp-xdg-runtime-provider.h | 32 +++
plugins/xdg-app/xdg-app.plugin | 7 +
28 files changed, 1285 insertions(+), 14 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index 98ac633..5ada452 100644
--- a/configure.ac
+++ b/configure.ac
@@ -239,6 +239,7 @@ m4_include([plugins/sysmon/configure.ac])
m4_include([plugins/todo/configure.ac])
m4_include([plugins/terminal/configure.ac])
m4_include([plugins/vala-pack/configure.ac])
+m4_include([plugins/xdg-app/configure.ac])
m4_include([plugins/xml-pack/configure.ac])
@@ -249,7 +250,6 @@ enable_python_scripting=no
AS_IF([test "x$have_pygobject" = "xyes"],[
AM_PATH_PYTHON([3.2.3])
AC_PATH_TOOL(PYTHON3_CONFIG, "python3-config")
-
AS_IF([test -z "${PYTHON3_CONFIG}"],[
AC_MSG_RESULT([Failed to locate python3-config.])
],[
@@ -503,6 +503,7 @@ echo " Symbol Tree .......................... : ${enable_symbol_tree_plugin}"
echo " Todo ................................. : ${enable_todo_plugin}"
echo " Terminal ............................. : ${enable_terminal_plugin}"
echo " Vala Language Pack ................... : ${enable_vala_pack_plugin}"
+echo " Xdg-App .............................. : ${enable_xdg_app_plugin}"
echo " XML Language Pack .................... : ${enable_xml_pack_plugin}"
echo ""
echo " Templates"
diff --git a/libide/Makefile.am b/libide/Makefile.am
index 657d914..1e8eae3 100644
--- a/libide/Makefile.am
+++ b/libide/Makefile.am
@@ -150,6 +150,12 @@ libide_1_0_la_public_sources = \
ide-project.h \
ide-recent-projects.c \
ide-recent-projects.h \
+ ide-runtime.c \
+ ide-runtime.h \
+ ide-runtime-manager.c \
+ ide-runtime-manager.h \
+ ide-runtime-provider.c \
+ ide-runtime-provider.h \
ide-refactory.c \
ide-refactory.h \
ide-script-manager.c \
diff --git a/libide/ide-build-system.c b/libide/ide-build-system.c
index 90b7f33..2eeb62b 100644
--- a/libide/ide-build-system.c
+++ b/libide/ide-build-system.c
@@ -21,8 +21,11 @@
#include "ide-build-system.h"
#include "ide-context.h"
#include "ide-device.h"
+#include "ide-device-manager.h"
#include "ide-file.h"
#include "ide-object.h"
+#include "ide-runtime.h"
+#include "ide-runtime-manager.h"
typedef struct
{
@@ -197,7 +200,8 @@ ide_build_system_new_finish (GAsyncResult *result,
* ide_build_system_get_builder:
* @system: The #IdeBuildSystem to perform the build.
* @config: (nullable): The configuration options for the build.
- * @device: The #IdeDevice the result should be able to run on.
+ * @device: (nullable): The #IdeDevice the result should be able to run on.
+ * @runtime: (nullable): The #IdeRuntime to build with.
*
* This function should return an #IdeBuilder that can be used to perform a
* build of the project using the configuration specified. @device may be
@@ -209,22 +213,33 @@ IdeBuilder *
ide_build_system_get_builder (IdeBuildSystem *system,
GKeyFile *config,
IdeDevice *device,
+ IdeRuntime *runtime,
GError **error)
{
IdeBuildSystemInterface *iface;
IdeBuilder *ret = NULL;
+ IdeContext *context;
g_autoptr(GKeyFile) local = NULL;
g_return_val_if_fail (IDE_IS_BUILD_SYSTEM (system), NULL);
- g_return_val_if_fail (IDE_IS_DEVICE (device), NULL);
+ g_return_val_if_fail (!device || IDE_IS_DEVICE (device), NULL);
+ g_return_val_if_fail (!runtime || IDE_IS_RUNTIME (runtime), NULL);
+
+ context = ide_object_get_context (IDE_OBJECT (system));
if (config == NULL)
config = local = g_key_file_new ();
+ if (device == NULL)
+ device = ide_device_manager_get_device (ide_context_get_device_manager (context), "local");
+
+ if (runtime == NULL)
+ runtime = ide_runtime_manager_get_runtime (ide_context_get_runtime_manager (context), "system");
+
iface = IDE_BUILD_SYSTEM_GET_IFACE (system);
if (iface->get_builder)
- ret = iface->get_builder (system, config, device, error);
+ ret = iface->get_builder (system, config, device, runtime, error);
else
g_set_error (error,
G_IO_ERROR,
diff --git a/libide/ide-build-system.h b/libide/ide-build-system.h
index ef286c6..ebe79ea 100644
--- a/libide/ide-build-system.h
+++ b/libide/ide-build-system.h
@@ -22,6 +22,7 @@
#include <gio/gio.h>
#include "ide-object.h"
+#include "ide-runtime.h"
G_BEGIN_DECLS
@@ -37,6 +38,7 @@ struct _IdeBuildSystemInterface
IdeBuilder *(*get_builder) (IdeBuildSystem *system,
GKeyFile *config,
IdeDevice *device,
+ IdeRuntime *runtime,
GError **error);
void (*get_build_flags_async) (IdeBuildSystem *self,
IdeFile *file,
@@ -67,6 +69,7 @@ IdeBuildSystem *ide_build_system_new_finish (GAsyncResult *r
IdeBuilder *ide_build_system_get_builder (IdeBuildSystem *system,
GKeyFile *config,
IdeDevice *device,
+ IdeRuntime *runtime,
GError **error);
G_END_DECLS
diff --git a/libide/ide-context.c b/libide/ide-context.c
index 5196892..8f1b673 100644
--- a/libide/ide-context.c
+++ b/libide/ide-context.c
@@ -35,6 +35,7 @@
#include "ide-project.h"
#include "ide-project-item.h"
#include "ide-project-files.h"
+#include "ide-runtime-manager.h"
#include "ide-script-manager.h"
#include "ide-search-engine.h"
#include "ide-search-provider.h"
@@ -60,6 +61,7 @@ struct _IdeContext
IdeDeviceManager *device_manager;
IdeDoap *doap;
GtkRecentManager *recent_manager;
+ IdeRuntimeManager *runtime_manager;
IdeScriptManager *script_manager;
IdeSearchEngine *search_engine;
IdeSourceSnippetsManager *snippets_manager;
@@ -95,6 +97,7 @@ enum {
PROP_PROJECT_FILE,
PROP_PROJECT,
PROP_ROOT_BUILD_DIR,
+ PROP_RUNTIME_MANAGER,
PROP_SCRIPT_MANAGER,
PROP_SEARCH_ENGINE,
PROP_SNIPPETS_MANAGER,
@@ -536,6 +539,7 @@ ide_context_finalize (GObject *object)
g_clear_object (&self->project);
g_clear_object (&self->project_file);
g_clear_object (&self->recent_manager);
+ g_clear_object (&self->runtime_manager);
g_clear_object (&self->unsaved_files);
g_clear_object (&self->vcs);
@@ -586,6 +590,10 @@ ide_context_get_property (GObject *object,
g_value_set_string (value, ide_context_get_root_build_dir (self));
break;
+ case PROP_RUNTIME_MANAGER:
+ g_value_set_object (value, ide_context_get_runtime_manager (self));
+ break;
+
case PROP_SCRIPT_MANAGER:
g_value_set_object (value, ide_context_get_script_manager (self));
break;
@@ -695,6 +703,13 @@ ide_context_class_init (IdeContextClass *klass)
NULL,
(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+ properties [PROP_RUNTIME_MANAGER] =
+ g_param_spec_object ("runtime-manager",
+ "Runtime Manager",
+ "Runtime Manager",
+ IDE_TYPE_RUNTIME_MANAGER,
+ (G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+
properties [PROP_SCRIPT_MANAGER] =
g_param_spec_object ("script-manager",
"Script Manager",
@@ -786,6 +801,10 @@ ide_context_init (IdeContext *self)
"context", self,
NULL);
+ self->runtime_manager = g_object_new (IDE_TYPE_RUNTIME_MANAGER,
+ "context", self,
+ NULL);
+
self->unsaved_files = g_object_new (IDE_TYPE_UNSAVED_FILES,
"context", self,
NULL);
@@ -1618,6 +1637,9 @@ ide_context_do_unload_locked (IdeContext *self)
task = self->delayed_unload_task;
self->delayed_unload_task = NULL;
+ g_clear_object (&self->device_manager);
+ g_clear_object (&self->runtime_manager);
+
ide_async_helper_run (self,
g_task_get_cancellable (task),
ide_context_unload_cb,
@@ -1915,3 +1937,23 @@ ide_context_release (IdeContext *self)
g_object_unref (self);
}
+
+/**
+ * ide_context_get_runtime_manager:
+ * @self: An #IdeContext
+ *
+ * Gets the #IdeRuntimeManager for the LibIDE context.
+ *
+ * The runtime manager provies access to #IdeRuntime instances via the
+ * #GListModel interface. These can provide support for building projects
+ * in various runtimes such as xdg-app.
+ *
+ * Returns: (transfer none): An #IdeRuntimeManager.
+ */
+IdeRuntimeManager *
+ide_context_get_runtime_manager (IdeContext *self)
+{
+ g_return_val_if_fail (IDE_IS_CONTEXT (self), NULL);
+
+ return self->runtime_manager;
+}
diff --git a/libide/ide-context.h b/libide/ide-context.h
index ef249ee..d1c6604 100644
--- a/libide/ide-context.h
+++ b/libide/ide-context.h
@@ -37,6 +37,7 @@ IdeBuildSystem *ide_context_get_build_system (IdeContext
IdeDeviceManager *ide_context_get_device_manager (IdeContext *self);
IdeProject *ide_context_get_project (IdeContext *self);
GtkRecentManager *ide_context_get_recent_manager (IdeContext *self);
+IdeRuntimeManager *ide_context_get_runtime_manager (IdeContext *self);
IdeScriptManager *ide_context_get_script_manager (IdeContext *self);
IdeSearchEngine *ide_context_get_search_engine (IdeContext *self);
IdeSettings *ide_context_get_settings (IdeContext *self,
diff --git a/libide/ide-device-manager.c b/libide/ide-device-manager.c
index 58a952b..8df4f56 100644
--- a/libide/ide-device-manager.c
+++ b/libide/ide-device-manager.c
@@ -128,6 +128,9 @@ ide_device_manager__provider_device_removed (IdeDeviceManager *self,
g_return_if_fail (IDE_IS_DEVICE (device));
g_return_if_fail (IDE_IS_DEVICE_PROVIDER (provider));
+ if (self->devices == NULL)
+ return;
+
for (i = 0; i < self->devices->len; i++)
{
IdeDevice *current = g_ptr_array_index (self->devices, i);
diff --git a/libide/ide-internal.h b/libide/ide-internal.h
index c9c5c9b..c040fde 100644
--- a/libide/ide-internal.h
+++ b/libide/ide-internal.h
@@ -59,6 +59,7 @@ IdeFixit *_ide_fixit_new (IdeSourceRange
const gchar *replacement_text);
void _ide_project_set_name (IdeProject *project,
const gchar *name);
+void _ide_runtime_manager_unload (IdeRuntimeManager *self);
void _ide_search_context_add_provider (IdeSearchContext *context,
IdeSearchProvider *provider,
gsize max_results);
diff --git a/libide/ide-runtime-manager.c b/libide/ide-runtime-manager.c
new file mode 100644
index 0000000..29960e9
--- /dev/null
+++ b/libide/ide-runtime-manager.c
@@ -0,0 +1,236 @@
+/* ide-runtime-manager.c
+ *
+ * Copyright (C) 2016 Christian Hergert <chergert redhat com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 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/>.
+ */
+
+#define G_LOG_DOMAIN "ide-runtime-manager"
+
+#include <glib/gi18n.h>
+#include <libpeas/peas.h>
+
+#include "ide-runtime.h"
+#include "ide-runtime-manager.h"
+#include "ide-runtime-provider.h"
+
+struct _IdeRuntimeManager
+{
+ IdeObject parent_instance;
+ PeasExtensionSet *extensions;
+ GPtrArray *runtimes;
+};
+
+static void list_model_iface_init (GListModelInterface *iface);
+
+G_DEFINE_TYPE_EXTENDED (IdeRuntimeManager, ide_runtime_manager, IDE_TYPE_OBJECT, 0,
+ G_IMPLEMENT_INTERFACE (G_TYPE_LIST_MODEL, list_model_iface_init))
+
+static void
+ide_runtime_manager_extension_added (PeasExtensionSet *set,
+ PeasPluginInfo *plugin_info,
+ PeasExtension *exten,
+ gpointer user_data)
+{
+ IdeRuntimeManager *self = user_data;
+ IdeRuntimeProvider *provider = (IdeRuntimeProvider *)exten;
+
+ g_assert (PEAS_IS_EXTENSION_SET (set));
+ g_assert (plugin_info != NULL);
+ g_assert (IDE_IS_RUNTIME_PROVIDER (provider));
+
+ ide_runtime_provider_load (provider, self);
+}
+
+static void
+ide_runtime_manager_extension_removed (PeasExtensionSet *set,
+ PeasPluginInfo *plugin_info,
+ PeasExtension *exten,
+ gpointer user_data)
+{
+ IdeRuntimeManager *self = user_data;
+ IdeRuntimeProvider *provider = (IdeRuntimeProvider *)exten;
+
+ g_assert (PEAS_IS_EXTENSION_SET (set));
+ g_assert (plugin_info != NULL);
+ g_assert (IDE_IS_RUNTIME_PROVIDER (provider));
+
+ ide_runtime_provider_unload (provider, self);
+}
+
+static void
+ide_runtime_manager_constructed (GObject *object)
+{
+ IdeRuntimeManager *self = (IdeRuntimeManager *)object;
+
+ G_OBJECT_CLASS (ide_runtime_manager_parent_class)->constructed (object);
+
+ self->extensions = peas_extension_set_new (peas_engine_get_default (),
+ IDE_TYPE_RUNTIME_PROVIDER,
+ NULL);
+
+ g_signal_connect (self->extensions,
+ "extension-added",
+ G_CALLBACK (ide_runtime_manager_extension_added),
+ self);
+
+ g_signal_connect (self->extensions,
+ "extension-removed",
+ G_CALLBACK (ide_runtime_manager_extension_removed),
+ self);
+
+ peas_extension_set_foreach (self->extensions,
+ ide_runtime_manager_extension_added,
+ self);
+}
+
+void
+_ide_runtime_manager_unload (IdeRuntimeManager *self)
+{
+ g_return_if_fail (IDE_IS_RUNTIME_MANAGER (self));
+
+ g_clear_object (&self->extensions);
+}
+
+static void
+ide_runtime_manager_dispose (GObject *object)
+{
+ IdeRuntimeManager *self = (IdeRuntimeManager *)object;
+
+ g_clear_object (&self->extensions);
+ g_clear_pointer (&self->runtimes, g_ptr_array_unref);
+
+ G_OBJECT_CLASS (ide_runtime_manager_parent_class)->dispose (object);
+}
+
+static void
+ide_runtime_manager_class_init (IdeRuntimeManagerClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->constructed = ide_runtime_manager_constructed;
+ object_class->dispose = ide_runtime_manager_dispose;
+}
+
+static void
+ide_runtime_manager_init (IdeRuntimeManager *self)
+{
+ self->runtimes = g_ptr_array_new_with_free_func (g_object_unref);
+
+ ide_runtime_manager_add (self, ide_runtime_new ("system", _("System")));
+}
+
+static GType
+ide_runtime_manager_get_item_type (GListModel *model)
+{
+ return IDE_TYPE_RUNTIME;
+}
+
+static guint
+ide_runtime_manager_get_n_items (GListModel *model)
+{
+ IdeRuntimeManager *self = (IdeRuntimeManager *)model;
+
+ g_return_val_if_fail (IDE_IS_RUNTIME_MANAGER (self), 0);
+
+ return self->runtimes->len;
+}
+
+static gpointer
+ide_runtime_manager_get_item (GListModel *model,
+ guint position)
+{
+ IdeRuntimeManager *self = (IdeRuntimeManager *)model;
+
+ g_return_val_if_fail (IDE_IS_RUNTIME_MANAGER (self), NULL);
+ g_return_val_if_fail (position < self->runtimes->len, NULL);
+
+ return g_object_ref (g_ptr_array_index (self->runtimes, position));
+}
+
+static void
+list_model_iface_init (GListModelInterface *iface)
+{
+ iface->get_item_type = ide_runtime_manager_get_item_type;
+ iface->get_n_items = ide_runtime_manager_get_n_items;
+ iface->get_item = ide_runtime_manager_get_item;
+}
+
+void
+ide_runtime_manager_add (IdeRuntimeManager *self,
+ IdeRuntime *runtime)
+{
+ guint idx;
+
+ g_return_if_fail (IDE_IS_RUNTIME_MANAGER (self));
+ g_return_if_fail (IDE_IS_RUNTIME (runtime));
+
+ idx = self->runtimes->len;
+ g_ptr_array_add (self->runtimes, g_object_ref (runtime));
+ g_list_model_items_changed (G_LIST_MODEL (self), idx, 0, 1);
+}
+
+void
+ide_runtime_manager_remove (IdeRuntimeManager *self,
+ IdeRuntime *runtime)
+{
+ guint i;
+
+ g_return_if_fail (IDE_IS_RUNTIME_MANAGER (self));
+ g_return_if_fail (IDE_IS_RUNTIME (runtime));
+
+ for (i = 0; i < self->runtimes->len; i++)
+ {
+ IdeRuntime *item = g_ptr_array_index (self->runtimes, i);
+
+ if (runtime == item)
+ {
+ g_ptr_array_remove_index (self->runtimes, i);
+ g_list_model_items_changed (G_LIST_MODEL (self), i, 1, 0);
+ break;
+ }
+ }
+}
+
+/**
+ * ide_runtime_manager_get_runtime:
+ * @self: An #IdeRuntimeManager
+ * @id: the identifier of the runtime
+ *
+ * Gets the runtime by it's internal identifier.
+ *
+ * Returns: (transfer none): An #IdeRuntime.
+ */
+IdeRuntime *
+ide_runtime_manager_get_runtime (IdeRuntimeManager *self,
+ const gchar *id)
+{
+ guint i;
+
+ g_return_val_if_fail (IDE_IS_RUNTIME_MANAGER (self), NULL);
+ g_return_val_if_fail (id != NULL, NULL);
+
+ for (i = 0; i < self->runtimes->len; i++)
+ {
+ IdeRuntime *runtime = g_ptr_array_index (self->runtimes, i);
+ const gchar *runtime_id;
+
+ runtime_id = ide_runtime_get_id (runtime);
+
+ if (g_strcmp0 (runtime_id, id) == 0)
+ return runtime;
+ }
+
+ return NULL;
+}
diff --git a/libide/ide-runtime-manager.h b/libide/ide-runtime-manager.h
new file mode 100644
index 0000000..f7fd591
--- /dev/null
+++ b/libide/ide-runtime-manager.h
@@ -0,0 +1,39 @@
+/* ide-runtime-manager.h
+ *
+ * Copyright (C) 2016 Christian Hergert <chergert redhat com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 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_RUNTIME_MANAGER_H
+#define IDE_RUNTIME_MANAGER_H
+
+#include "ide-object.h"
+
+G_BEGIN_DECLS
+
+#define IDE_TYPE_RUNTIME_MANAGER (ide_runtime_manager_get_type())
+
+G_DECLARE_FINAL_TYPE (IdeRuntimeManager, ide_runtime_manager, IDE, RUNTIME_MANAGER, IdeObject)
+
+IdeRuntime *ide_runtime_manager_get_runtime (IdeRuntimeManager *self,
+ const gchar *id);
+void ide_runtime_manager_add (IdeRuntimeManager *self,
+ IdeRuntime *runtime);
+void ide_runtime_manager_remove (IdeRuntimeManager *self,
+ IdeRuntime *runtime);
+
+G_END_DECLS
+
+#endif /* IDE_RUNTIME_MANAGER_H */
diff --git a/libide/ide-runtime-provider.c b/libide/ide-runtime-provider.c
new file mode 100644
index 0000000..41483e6
--- /dev/null
+++ b/libide/ide-runtime-provider.c
@@ -0,0 +1,61 @@
+/* ide-runtime-provider.c
+ *
+ * Copyright (C) 2016 Christian Hergert <chergert redhat com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 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-runtime-manager.h"
+#include "ide-runtime-provider.h"
+
+G_DEFINE_INTERFACE (IdeRuntimeProvider, ide_runtime_provider, G_TYPE_OBJECT)
+
+static void
+ide_runtime_provider_real_load (IdeRuntimeProvider *self,
+ IdeRuntimeManager *manager)
+{
+}
+
+static void
+ide_runtime_provider_real_unload (IdeRuntimeProvider *self,
+ IdeRuntimeManager *manager)
+{
+}
+
+static void
+ide_runtime_provider_default_init (IdeRuntimeProviderInterface *iface)
+{
+ iface->load = ide_runtime_provider_real_load;
+ iface->unload = ide_runtime_provider_real_unload;
+}
+
+void
+ide_runtime_provider_load (IdeRuntimeProvider *self,
+ IdeRuntimeManager *manager)
+{
+ g_return_if_fail (IDE_IS_RUNTIME_PROVIDER (self));
+ g_return_if_fail (IDE_IS_RUNTIME_MANAGER (manager));
+
+ IDE_RUNTIME_PROVIDER_GET_IFACE (self)->load (self, manager);
+}
+
+void
+ide_runtime_provider_unload (IdeRuntimeProvider *self,
+ IdeRuntimeManager *manager)
+{
+ g_return_if_fail (IDE_IS_RUNTIME_PROVIDER (self));
+ g_return_if_fail (IDE_IS_RUNTIME_MANAGER (manager));
+
+ IDE_RUNTIME_PROVIDER_GET_IFACE (self)->unload (self, manager);
+}
diff --git a/libide/ide-runtime-provider.h b/libide/ide-runtime-provider.h
new file mode 100644
index 0000000..15098d9
--- /dev/null
+++ b/libide/ide-runtime-provider.h
@@ -0,0 +1,49 @@
+/* ide-runtime-provider.h
+ *
+ * Copyright (C) 2016 Christian Hergert <chergert redhat com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 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_RUNTIME_PROVIDER_H
+#define IDE_RUNTIME_PROVIDER_H
+
+#include <gio/gio.h>
+
+#include "ide-types.h"
+
+G_BEGIN_DECLS
+
+#define IDE_TYPE_RUNTIME_PROVIDER (ide_runtime_provider_get_type ())
+
+G_DECLARE_INTERFACE (IdeRuntimeProvider, ide_runtime_provider, IDE, RUNTIME_PROVIDER, GObject)
+
+struct _IdeRuntimeProviderInterface
+{
+ GTypeInterface parent;
+
+ void (*load) (IdeRuntimeProvider *self,
+ IdeRuntimeManager *manager);
+ void (*unload) (IdeRuntimeProvider *self,
+ IdeRuntimeManager *manager);
+};
+
+void ide_runtime_provider_load (IdeRuntimeProvider *self,
+ IdeRuntimeManager *manager);
+void ide_runtime_provider_unload (IdeRuntimeProvider *self,
+ IdeRuntimeManager *manager);
+
+G_END_DECLS
+
+#endif /* IDE_RUNTIME_PROVIDER_H */
diff --git a/libide/ide-runtime.c b/libide/ide-runtime.c
new file mode 100644
index 0000000..1f164b8
--- /dev/null
+++ b/libide/ide-runtime.c
@@ -0,0 +1,186 @@
+/* ide-runtime.c
+ *
+ * Copyright (C) 2016 Christian Hergert <chergert redhat com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 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-runtime.h"
+
+typedef struct
+{
+ gchar *id;
+ gchar *title;
+} IdeRuntimePrivate;
+
+G_DEFINE_TYPE_WITH_PRIVATE (IdeRuntime, ide_runtime, G_TYPE_OBJECT)
+
+enum {
+ PROP_0,
+ PROP_ID,
+ PROP_TITLE,
+ N_PROPS
+};
+
+static GParamSpec *properties [N_PROPS];
+
+static void
+ide_runtime_finalize (GObject *object)
+{
+ IdeRuntime *self = (IdeRuntime *)object;
+ IdeRuntimePrivate *priv = ide_runtime_get_instance_private (self);
+
+ g_clear_pointer (&priv->title, g_free);
+
+ G_OBJECT_CLASS (ide_runtime_parent_class)->finalize (object);
+}
+
+static void
+ide_runtime_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ IdeRuntime *self = IDE_RUNTIME (object);
+
+ switch (prop_id)
+ {
+ case PROP_ID:
+ g_value_set_string (value, ide_runtime_get_id (self));
+ break;
+
+ case PROP_TITLE:
+ g_value_set_string (value, ide_runtime_get_title (self));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+}
+
+static void
+ide_runtime_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ IdeRuntime *self = IDE_RUNTIME (object);
+
+ switch (prop_id)
+ {
+ case PROP_ID:
+ ide_runtime_set_id (self, g_value_get_string (value));
+ break;
+
+ case PROP_TITLE:
+ ide_runtime_set_title (self, g_value_get_string (value));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+}
+
+static void
+ide_runtime_class_init (IdeRuntimeClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->finalize = ide_runtime_finalize;
+ object_class->get_property = ide_runtime_get_property;
+ object_class->set_property = ide_runtime_set_property;
+
+ properties [PROP_ID] =
+ g_param_spec_string ("id",
+ "Id",
+ "The runtime identifier",
+ NULL,
+ (G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
+
+ properties [PROP_TITLE] =
+ g_param_spec_string ("title",
+ "Title",
+ "Title",
+ NULL,
+ (G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_properties (object_class, N_PROPS, properties);
+}
+
+static void
+ide_runtime_init (IdeRuntime *self)
+{
+}
+
+const gchar *
+ide_runtime_get_id (IdeRuntime *self)
+{
+ IdeRuntimePrivate *priv = ide_runtime_get_instance_private (self);
+
+ g_return_val_if_fail (IDE_IS_RUNTIME (self), NULL);
+
+ return priv->id;
+}
+
+void
+ide_runtime_set_id (IdeRuntime *self,
+ const gchar *id)
+{
+ IdeRuntimePrivate *priv = ide_runtime_get_instance_private (self);
+
+ g_return_if_fail (IDE_IS_RUNTIME (self));
+ g_return_if_fail (id != NULL);
+
+ if (0 != g_strcmp0 (id, priv->id))
+ {
+ g_free (priv->id);
+ priv->id = g_strdup (id);
+ }
+}
+
+const gchar *
+ide_runtime_get_title (IdeRuntime *self)
+{
+ IdeRuntimePrivate *priv = ide_runtime_get_instance_private (self);
+
+ g_return_val_if_fail (IDE_IS_RUNTIME (self), NULL);
+
+ return priv->title;
+}
+
+void
+ide_runtime_set_title (IdeRuntime *self,
+ const gchar *title)
+{
+ IdeRuntimePrivate *priv = ide_runtime_get_instance_private (self);
+
+ g_return_if_fail (IDE_IS_RUNTIME (self));
+ g_return_if_fail (title != NULL);
+
+ if (g_strcmp0 (title, priv->title) != 0)
+ {
+ g_free (priv->title);
+ priv->title = g_strdup (title);
+ }
+}
+
+IdeRuntime *
+ide_runtime_new (const gchar *id,
+ const gchar *title)
+{
+ return g_object_new (IDE_TYPE_RUNTIME,
+ "id", id,
+ "title", title,
+ NULL);
+}
diff --git a/libide/ide-runtime.h b/libide/ide-runtime.h
new file mode 100644
index 0000000..c1b8570
--- /dev/null
+++ b/libide/ide-runtime.h
@@ -0,0 +1,46 @@
+/* ide-runtime.h
+ *
+ * Copyright (C) 2016 Christian Hergert <chergert redhat com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 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_RUNTIME_H
+#define IDE_RUNTIME_H
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define IDE_TYPE_RUNTIME (ide_runtime_get_type())
+
+G_DECLARE_DERIVABLE_TYPE (IdeRuntime, ide_runtime, IDE, RUNTIME, GObject)
+
+struct _IdeRuntimeClass
+{
+ GObjectClass parent;
+};
+
+IdeRuntime *ide_runtime_new (const gchar *id,
+ const gchar *title);
+const gchar *ide_runtime_get_id (IdeRuntime *self);
+void ide_runtime_set_id (IdeRuntime *self,
+ const gchar *id);
+const gchar *ide_runtime_get_title (IdeRuntime *self);
+void ide_runtime_set_title (IdeRuntime *self,
+ const gchar *title);
+
+G_END_DECLS
+
+#endif /* IDE_RUNTIME_H */
diff --git a/libide/ide-types.h b/libide/ide-types.h
index 43ce39a..a49bf52 100644
--- a/libide/ide-types.h
+++ b/libide/ide-types.h
@@ -98,6 +98,9 @@ typedef struct _IdeProjectFiles IdeProjectFiles;
typedef struct _IdeRefactory IdeRefactory;
typedef struct _IdeRefactoryInterface IdeRefactoryInterface;
+typedef struct _IdeRuntime IdeRuntime;
+typedef struct _IdeRuntimeManager IdeRuntimeManager;
+
typedef struct _IdeScript IdeScript;
typedef struct _IdeScriptManager IdeScriptManager;
diff --git a/libide/ide.h b/libide/ide.h
index 7ec2f35..732e829 100644
--- a/libide/ide.h
+++ b/libide/ide.h
@@ -80,6 +80,9 @@ G_BEGIN_DECLS
#include "ide-project-item.h"
#include "ide-recent-projects.h"
#include "ide-refactory.h"
+#include "ide-runtime.h"
+#include "ide-runtime-manager.h"
+#include "ide-runtime-provider.h"
#include "ide-script.h"
#include "ide-script-manager.h"
#include "ide-search-context.h"
diff --git a/plugins/Makefile.am b/plugins/Makefile.am
index b316c78..22e70c4 100644
--- a/plugins/Makefile.am
+++ b/plugins/Makefile.am
@@ -27,6 +27,7 @@ SUBDIRS = \
terminal \
todo \
vala-pack \
+ xdg-app \
xml-pack \
$(NULL)
diff --git a/plugins/autotools/ide-autotools-build-system.c b/plugins/autotools/ide-autotools-build-system.c
index 3df3824..f388162 100644
--- a/plugins/autotools/ide-autotools-build-system.c
+++ b/plugins/autotools/ide-autotools-build-system.c
@@ -39,6 +39,8 @@
#include "ide-file.h"
#include "ide-internal.h"
#include "ide-makecache.h"
+#include "ide-runtime.h"
+#include "ide-runtime-manager.h"
#include "ide-tags-builder.h"
#define MAKECACHE_KEY "makecache"
@@ -87,6 +89,7 @@ static IdeBuilder *
ide_autotools_build_system_get_builder (IdeBuildSystem *build_system,
GKeyFile *config,
IdeDevice *device,
+ IdeRuntime *runtime,
GError **error)
{
IdeBuilder *ret;
@@ -102,6 +105,7 @@ ide_autotools_build_system_get_builder (IdeBuildSystem *build_system,
"context", context,
"config", config,
"device", device,
+ "runtime", runtime,
NULL);
return ret;
@@ -247,6 +251,8 @@ ide_autotools_build_system_get_local_makefile_async (IdeAutotoolsBuildSystem *se
IdeContext *context;
IdeDeviceManager *device_manager;
IdeDevice *device;
+ IdeRuntimeManager *runtime_manager;
+ IdeRuntime *runtime;
g_autoptr(GTask) task = NULL;
g_autoptr(IdeBuilder) builder = NULL;
g_autoptr(GKeyFile) config = NULL;
@@ -260,10 +266,16 @@ ide_autotools_build_system_get_local_makefile_async (IdeAutotoolsBuildSystem *se
task = g_task_new (self, cancellable, callback, user_data);
context = ide_object_get_context (IDE_OBJECT (self));
+
device_manager = ide_context_get_device_manager (context);
device = ide_device_manager_get_device (device_manager, "local");
+
+ runtime_manager = ide_context_get_runtime_manager (context);
+ runtime = ide_runtime_manager_get_runtime (runtime_manager, "system");
+
config = g_key_file_new ();
- builder = ide_autotools_build_system_get_builder (IDE_BUILD_SYSTEM (self), config, device, &error);
+
+ builder = ide_autotools_build_system_get_builder (IDE_BUILD_SYSTEM (self), config, device, runtime,
&error);
if (builder == NULL)
{
diff --git a/plugins/build-tools/gbp-build-panel.c b/plugins/build-tools/gbp-build-panel.c
index 4a84da0..481da28 100644
--- a/plugins/build-tools/gbp-build-panel.c
+++ b/plugins/build-tools/gbp-build-panel.c
@@ -34,6 +34,7 @@ struct _GbpBuildPanel
EggBindingGroup *bindings;
IdeDevice *device;
+ IdeRuntime *runtime;
GtkListBox *diagnostics;
GtkRevealer *status_revealer;
@@ -44,6 +45,9 @@ struct _GbpBuildPanel
GtkListBox *devices;
GtkPopover *device_popover;
GtkLabel *errors_label;
+ GtkListBox *runtimes;
+ GtkLabel *runtime_label;
+ GtkPopover *runtime_popover;
GtkLabel *warnings_label;
guint running_time_source;
@@ -58,6 +62,8 @@ enum {
PROP_0,
PROP_DEVICE,
PROP_DEVICE_MANAGER,
+ PROP_RUNTIME,
+ PROP_RUNTIME_MANAGER,
PROP_RESULT,
LAST_PROP
};
@@ -65,6 +71,36 @@ enum {
static GParamSpec *properties [LAST_PROP];
static GtkWidget *
+create_runtime_row (gpointer item,
+ gpointer user_data)
+{
+ IdeRuntime *runtime = item;
+ GtkListBoxRow *row;
+ const gchar *name;
+ const gchar *id;
+ GtkLabel *label;
+
+ g_assert (IDE_IS_RUNTIME (runtime));
+
+ row = g_object_new (GTK_TYPE_LIST_BOX_ROW,
+ "visible", TRUE,
+ NULL);
+
+ id = ide_runtime_get_id (runtime);
+ g_object_set_data_full (G_OBJECT (row), "IDE_RUNTIME_ID", g_strdup (id), g_free);
+
+ name = ide_runtime_get_title (runtime);
+ label = g_object_new (GTK_TYPE_LABEL,
+ "label", name,
+ "xalign", 0.0f,
+ "visible", TRUE,
+ NULL);
+ gtk_container_add (GTK_CONTAINER (row), GTK_WIDGET (label));
+
+ return GTK_WIDGET (row);
+}
+
+static GtkWidget *
create_device_row (gpointer item,
gpointer user_data)
{
@@ -123,14 +159,43 @@ static void
gbp_build_panel_set_device_manager (GbpBuildPanel *self,
IdeDeviceManager *device_manager)
{
- g_return_if_fail (GBP_IS_BUILD_PANEL (self));
- g_return_if_fail (!device_manager || IDE_IS_DEVICE_MANAGER (device_manager));
+ g_assert (GBP_IS_BUILD_PANEL (self));
+ g_assert (!device_manager || IDE_IS_DEVICE_MANAGER (device_manager));
gtk_list_box_bind_model (self->devices,
G_LIST_MODEL (device_manager),
create_device_row, NULL, NULL);
}
+static void
+gbp_build_panel_set_runtime (GbpBuildPanel *self,
+ IdeRuntime *runtime)
+{
+ g_return_if_fail (GBP_IS_BUILD_PANEL (self));
+ g_return_if_fail (!runtime || IDE_IS_RUNTIME (runtime));
+
+ if (g_set_object (&self->runtime, runtime))
+ {
+ const gchar *name = NULL;
+
+ if (runtime != NULL)
+ name = ide_runtime_get_title (runtime);
+ gtk_label_set_label (self->runtime_label, name);
+ }
+}
+
+static void
+gbp_build_panel_set_runtime_manager (GbpBuildPanel *self,
+ IdeRuntimeManager *runtime_manager)
+{
+ g_assert (GBP_IS_BUILD_PANEL (self));
+ g_assert (IDE_IS_RUNTIME_MANAGER (runtime_manager));
+
+ gtk_list_box_bind_model (self->runtimes,
+ G_LIST_MODEL (runtime_manager),
+ create_runtime_row, NULL, NULL);
+}
+
void
gbp_build_panel_add_error (GbpBuildPanel *self,
const gchar *message)
@@ -300,6 +365,25 @@ gbp_build_panel_device_activated (GbpBuildPanel *self,
}
static void
+gbp_build_panel_runtime_activated (GbpBuildPanel *self,
+ GtkListBoxRow *row,
+ GtkListBox *list_box)
+{
+ const gchar *id;
+
+ g_assert (GBP_IS_BUILD_PANEL (self));
+ g_assert (GTK_IS_LIST_BOX_ROW (row));
+ g_assert (GTK_IS_LIST_BOX (list_box));
+
+ if ((id = g_object_get_data (G_OBJECT (row), "IDE_RUNTIME_ID")))
+ ide_widget_action (GTK_WIDGET (self),
+ "build-tools", "runtime",
+ g_variant_new_string (id));
+
+ gtk_widget_hide (GTK_WIDGET (self->runtime_popover));
+}
+
+static void
gbp_build_panel_diagnostic_activated (GbpBuildPanel *self,
GtkListBoxRow *row,
GtkListBox *list_box)
@@ -340,6 +424,7 @@ gbp_build_panel_destroy (GtkWidget *widget)
g_clear_object (&self->bindings);
g_clear_object (&self->signals);
g_clear_object (&self->device);
+ g_clear_object (&self->runtime);
GTK_WIDGET_CLASS (gbp_build_panel_parent_class)->destroy (widget);
}
@@ -362,6 +447,10 @@ gbp_build_panel_get_property (GObject *object,
g_value_set_object (value, self->result);
break;
+ case PROP_RUNTIME:
+ g_value_set_object (value, self->runtime);
+ break;
+
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
}
@@ -389,6 +478,14 @@ gbp_build_panel_set_property (GObject *object,
gbp_build_panel_set_result (self, g_value_get_object (value));
break;
+ case PROP_RUNTIME_MANAGER:
+ gbp_build_panel_set_runtime_manager (self, g_value_get_object (value));
+ break;
+
+ case PROP_RUNTIME:
+ gbp_build_panel_set_runtime (self, g_value_get_object (value));
+ break;
+
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
}
@@ -419,6 +516,20 @@ gbp_build_panel_class_init (GbpBuildPanelClass *klass)
IDE_TYPE_DEVICE_MANAGER,
(G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS));
+ properties [PROP_RUNTIME_MANAGER] =
+ g_param_spec_object ("runtime-manager",
+ "Runtime Manager",
+ "Runtime Manager",
+ IDE_TYPE_RUNTIME_MANAGER,
+ (G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS));
+
+ properties [PROP_RUNTIME] =
+ g_param_spec_object ("runtime",
+ "Runtime",
+ "Runtime",
+ IDE_TYPE_RUNTIME,
+ (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
properties [PROP_RESULT] =
g_param_spec_object ("result",
"Result",
@@ -437,6 +548,9 @@ gbp_build_panel_class_init (GbpBuildPanelClass *klass)
gtk_widget_class_bind_template_child (widget_class, GbpBuildPanel, diagnostics);
gtk_widget_class_bind_template_child (widget_class, GbpBuildPanel, errors_label);
gtk_widget_class_bind_template_child (widget_class, GbpBuildPanel, running_time_label);
+ gtk_widget_class_bind_template_child (widget_class, GbpBuildPanel, runtimes);
+ gtk_widget_class_bind_template_child (widget_class, GbpBuildPanel, runtime_label);
+ gtk_widget_class_bind_template_child (widget_class, GbpBuildPanel, runtime_popover);
gtk_widget_class_bind_template_child (widget_class, GbpBuildPanel, status_label);
gtk_widget_class_bind_template_child (widget_class, GbpBuildPanel, status_revealer);
gtk_widget_class_bind_template_child (widget_class, GbpBuildPanel, warnings_label);
@@ -467,6 +581,12 @@ gbp_build_panel_init (GbpBuildPanel *self)
self,
G_CONNECT_SWAPPED);
+ g_signal_connect_object (self->runtimes,
+ "row-activated",
+ G_CALLBACK (gbp_build_panel_runtime_activated),
+ self,
+ G_CONNECT_SWAPPED);
+
g_signal_connect_object (self->diagnostics,
"row-activated",
G_CALLBACK (gbp_build_panel_diagnostic_activated),
diff --git a/plugins/build-tools/gbp-build-panel.ui b/plugins/build-tools/gbp-build-panel.ui
index 8cbc219..a28464c 100644
--- a/plugins/build-tools/gbp-build-panel.ui
+++ b/plugins/build-tools/gbp-build-panel.ui
@@ -27,9 +27,9 @@
</child>
<child>
<object class="GtkLabel" id="label2">
- <property name="label" translatable="yes">Framework:</property>
+ <property name="label" translatable="yes">Runtime:</property>
<property name="xalign">1.0</property>
- <property name="visible">false</property>
+ <property name="visible">true</property>
<style>
<class name="dim-label"/>
</style>
@@ -120,6 +120,9 @@
<property name="visible">true</property>
<property name="hexpand">false</property>
<property name="xalign">0.0</property>
+ <style>
+ <class name="dim-label"/>
+ </style>
</object>
</child>
</object>
@@ -132,8 +135,37 @@
</child>
<child>
<object class="GtkMenuButton">
- <property name="label" translatable="yes">framework</property>
- <property name="visible">false</property>
+ <property name="focus-on-click">false</property>
+ <property name="popover">runtime_popover</property>
+ <property name="visible">true</property>
+ <style>
+ <class name="flat"/>
+ </style>
+ <child>
+ <object class="GtkBox">
+ <property name="spacing">6</property>
+ <property name="visible">true</property>
+ <child>
+ <object class="GtkLabel" id="runtime_label">
+ <property name="visible">true</property>
+ <property name="ellipsize">end</property>
+ <property name="hexpand">false</property>
+ <property name="xalign">0.0</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkImage">
+ <property name="icon-name">pan-down-symbolic</property>
+ <property name="visible">true</property>
+ <property name="hexpand">false</property>
+ <property name="xalign">0.0</property>
+ <style>
+ <class name="dim-label"/>
+ </style>
+ </object>
+ </child>
+ </object>
+ </child>
</object>
<packing>
<property name="left-attach">1</property>
@@ -359,4 +391,23 @@
</object>
</child>
</object>
+ <object class="GtkPopover" id="runtime_popover">
+ <child>
+ <object class="EggScrolledWindow">
+ <property name="min-content-width">100</property>
+ <property name="max-content-width">300</property>
+ <property name="max-content-height">300</property>
+ <property name="visible">true</property>
+ <child>
+ <object class="GtkListBox" id="runtimes">
+ <property name="selection-mode">none</property>
+ <property name="visible">true</property>
+ <style>
+ <class name="buildpanel"/>
+ </style>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
</interface>
diff --git a/plugins/build-tools/gbp-build-tool.c b/plugins/build-tools/gbp-build-tool.c
index 784f62c..56a3faa 100644
--- a/plugins/build-tools/gbp-build-tool.c
+++ b/plugins/build-tools/gbp-build-tool.c
@@ -156,11 +156,14 @@ gbp_build_tool_new_context_cb (GObject *object,
g_autoptr(IdeBuildResult) build_result = NULL;
g_autoptr(IdeDevice) device = NULL;
IdeDeviceManager *device_manager;
+ IdeRuntimeManager *runtime_manager;
IdeBuildSystem *build_system;
GbpBuildTool *self;
IdeBuilderBuildFlags flags;
+ IdeRuntime *runtime;
GKeyFile *config;
const gchar *device_id;
+ const gchar *runtime_id;
GError *error = NULL;
g_assert (G_IS_TASK (task));
@@ -182,6 +185,10 @@ gbp_build_tool_new_context_cb (GObject *object,
device_manager = ide_context_get_device_manager (context);
device = ide_device_manager_get_device (device_manager, device_id);
+ runtime_id = g_object_get_data (G_OBJECT (task), "RUNTIME_ID");
+ runtime_manager = ide_context_get_runtime_manager (context);
+ runtime = ide_runtime_manager_get_runtime (runtime_manager, runtime_id);
+
if (device == NULL)
{
/* TODO: Wait for devices to settle. */
@@ -198,7 +205,7 @@ gbp_build_tool_new_context_cb (GObject *object,
/* TODO: Support custom configs */
build_system = ide_context_get_build_system (context);
- builder = ide_build_system_get_builder (build_system, config, device, &error);
+ builder = ide_build_system_get_builder (build_system, config, device, runtime, &error);
if (builder == NULL)
{
@@ -241,6 +248,7 @@ gbp_build_tool_run_async (IdeApplicationTool *tool,
g_autoptr(GTask) task = NULL;
g_autofree gchar *project_path = NULL;
g_autofree gchar *device_id = NULL;
+ g_autofree gchar *runtime_id = NULL;
g_autoptr(GFile) project_file = NULL;
g_autoptr(GOptionContext) opt_context = NULL;
g_autoptr(GKeyFile) config = NULL;
@@ -255,6 +263,9 @@ gbp_build_tool_run_async (IdeApplicationTool *tool,
{ "device", 'd', 0, G_OPTION_ARG_STRING, &device_id,
N_("The id of the device to build for"),
N_("local") },
+ { "runtime", 'd', 0, G_OPTION_ARG_STRING, &runtime_id,
+ N_("The runtime to use for building"),
+ N_("system") },
{ "parallel", 'j', 0, G_OPTION_ARG_INT, ¶llel,
N_("Number of workers to use when building"),
N_("N") },
@@ -297,6 +308,7 @@ gbp_build_tool_run_async (IdeApplicationTool *tool,
flags |= IDE_BUILDER_BUILD_FLAGS_CLEAN;
g_object_set_data_full (G_OBJECT (task), "DEVICE_ID", g_strdup (device_id), g_free);
+ g_object_set_data_full (G_OBJECT (task), "RUNTIME_ID", g_strdup (runtime_id), g_free);
g_object_set_data_full (G_OBJECT (task), "CONFIG", g_key_file_ref (config),
(GDestroyNotify)g_key_file_unref);
g_object_set_data (G_OBJECT (task), "FLAGS", GINT_TO_POINTER (flags));
diff --git a/plugins/build-tools/gbp-build-workbench-addin.c b/plugins/build-tools/gbp-build-workbench-addin.c
index df558f8..3003d4c 100644
--- a/plugins/build-tools/gbp-build-workbench-addin.c
+++ b/plugins/build-tools/gbp-build-workbench-addin.c
@@ -39,6 +39,7 @@ struct _GbpBuildWorkbenchAddin
GSimpleActionGroup *actions;
GCancellable *cancellable;
IdeDevice *device;
+ IdeRuntime *runtime;
};
static void workbench_addin_iface_init (IdeWorkbenchAddinInterface *iface);
@@ -51,6 +52,7 @@ enum {
PROP_0,
PROP_DEVICE,
PROP_RESULT,
+ PROP_RUNTIME,
LAST_PROP
};
@@ -76,6 +78,25 @@ gbp_build_workbench_addin_set_device (GbpBuildWorkbenchAddin *self,
}
static void
+gbp_build_workbench_addin_set_runtime (GbpBuildWorkbenchAddin *self,
+ IdeRuntime *runtime)
+{
+ g_assert (GBP_IS_BUILD_WORKBENCH_ADDIN (self));
+ g_assert (IDE_IS_RUNTIME (runtime));
+
+ if (g_set_object (&self->runtime, runtime))
+ {
+ const gchar *id = ide_runtime_get_id (runtime);
+ GAction *action;
+
+ action = g_action_map_lookup_action (G_ACTION_MAP (self->actions), "runtime");
+ g_simple_action_set_state (G_SIMPLE_ACTION (action), g_variant_new_string (id));
+
+ g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_RUNTIME]);
+ }
+}
+
+static void
gbp_build_workbench_addin_set_result (GbpBuildWorkbenchAddin *self,
IdeBuildResult *result)
{
@@ -164,7 +185,7 @@ gbp_build_workbench_addin_do_build (GbpBuildWorkbenchAddin *self,
workbench = ide_widget_get_workbench (GTK_WIDGET (self->panel));
context = ide_workbench_get_context (workbench);
build_system = ide_context_get_build_system (context);
- builder = ide_build_system_get_builder (build_system, NULL, self->device, &error);
+ builder = ide_build_system_get_builder (build_system, NULL, self->device, self->runtime, &error);
if (error != NULL)
{
@@ -288,6 +309,31 @@ gbp_build_workbench_addin_device (GSimpleAction *action,
gbp_build_workbench_addin_set_device (self, device);
}
+static void
+gbp_build_workbench_addin_runtime (GSimpleAction *action,
+ GVariant *param,
+ gpointer user_data)
+{
+ GbpBuildWorkbenchAddin *self = user_data;
+ IdeRuntimeManager *runtime_manager;
+ IdeContext *context;
+ IdeRuntime *runtime;
+ const gchar *id;
+
+ g_assert (GBP_IS_BUILD_WORKBENCH_ADDIN (self));
+ g_assert (IDE_IS_WORKBENCH (self->workbench));
+
+ id = g_variant_get_string (param, NULL);
+ if (id == NULL)
+ id = "system";
+
+ context = ide_workbench_get_context (self->workbench);
+ runtime_manager = ide_context_get_runtime_manager (context);
+ runtime = ide_runtime_manager_get_runtime (runtime_manager, id);
+
+ gbp_build_workbench_addin_set_runtime (self, runtime);
+}
+
static const GActionEntry actions[] = {
{ "build", gbp_build_workbench_addin_build },
{ "rebuild", gbp_build_workbench_addin_rebuild },
@@ -296,6 +342,7 @@ static const GActionEntry actions[] = {
{ "deploy", gbp_build_workbench_addin_deploy },
{ "export", gbp_build_workbench_addin_export },
{ "device", NULL, "s", "'local'", gbp_build_workbench_addin_device },
+ { "runtime", NULL, "s", "'system'", gbp_build_workbench_addin_runtime },
};
static void
@@ -308,6 +355,8 @@ gbp_build_workbench_addin_load (IdeWorkbenchAddin *addin,
IdeContext *context;
IdeDeviceManager *device_manager;
IdeDevice *device;
+ IdeRuntimeManager *runtime_manager;
+ IdeRuntime *runtime;
g_assert (IDE_IS_WORKBENCH_ADDIN (addin));
g_assert (GBP_IS_BUILD_WORKBENCH_ADDIN (self));
@@ -318,12 +367,16 @@ gbp_build_workbench_addin_load (IdeWorkbenchAddin *addin,
context = ide_workbench_get_context (workbench);
device_manager = ide_context_get_device_manager (context);
device = ide_device_manager_get_device (device_manager, "local");
+ runtime_manager = ide_context_get_runtime_manager (context);
+ runtime = ide_runtime_manager_get_runtime (runtime_manager, "system");
editor = ide_workbench_get_perspective_by_name (workbench, "editor");
pane = ide_layout_get_right_pane (IDE_LAYOUT (editor));
self->panel = g_object_new (GBP_TYPE_BUILD_PANEL,
- "device", device,
"device-manager", device_manager,
+ "device", device,
+ "runtime-manager", runtime_manager,
+ "runtime", runtime,
"visible", TRUE,
NULL);
ide_layout_pane_add_page (IDE_LAYOUT_PANE (pane),
@@ -341,6 +394,7 @@ gbp_build_workbench_addin_load (IdeWorkbenchAddin *addin,
g_object_bind_property (self, "result", self->panel, "result", 0);
g_object_bind_property (self, "device", self->panel, "device", 0);
+ g_object_bind_property (self, "runtime", self->panel, "runtime", 0);
gbp_build_workbench_addin_set_device (self, device);
}
@@ -387,6 +441,10 @@ gbp_build_workbench_addin_get_property (GObject *object,
g_value_set_object (value, self->result);
break;
+ case PROP_RUNTIME:
+ g_value_set_object (value, self->runtime);
+ break;
+
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
}
@@ -406,6 +464,10 @@ gbp_build_workbench_addin_set_property (GObject *object,
gbp_build_workbench_addin_set_device (self, g_value_get_object (value));
break;
+ case PROP_RUNTIME:
+ gbp_build_workbench_addin_set_runtime (self, g_value_get_object (value));
+ break;
+
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
}
@@ -420,6 +482,7 @@ gbp_build_workbench_addin_finalize (GObject *object)
g_clear_object (&self->bindings);
g_clear_object (&self->actions);
g_clear_object (&self->result);
+ g_clear_object (&self->runtime);
g_clear_object (&self->cancellable);
G_OBJECT_CLASS (gbp_build_workbench_addin_parent_class)->finalize (object);
@@ -448,6 +511,13 @@ gbp_build_workbench_addin_class_init (GbpBuildWorkbenchAddinClass *klass)
IDE_TYPE_BUILD_RESULT,
(G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+ properties [PROP_RUNTIME] =
+ g_param_spec_object ("runtime",
+ "Runtime",
+ "Runtime",
+ IDE_TYPE_RUNTIME,
+ (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
g_object_class_install_properties (object_class, LAST_PROP, properties);
}
diff --git a/plugins/xdg-app/Makefile.am b/plugins/xdg-app/Makefile.am
new file mode 100644
index 0000000..c2061d9
--- /dev/null
+++ b/plugins/xdg-app/Makefile.am
@@ -0,0 +1,38 @@
+if ENABLE_XDG_APP_PLUGIN
+
+DISTCLEANFILES =
+BUILT_SOURCES =
+CLEANFILES =
+EXTRA_DIST = $(plugin_DATA)
+
+plugindir = $(libdir)/gnome-builder/plugins
+plugin_LTLIBRARIES = libxdg-app-plugin.la
+dist_plugin_DATA = xdg-app.plugin
+
+libxdg_app_plugin_la_SOURCES = \
+ gbp-xdg-runtime-provider.c \
+ gbp-xdg-runtime-provider.h \
+ gbp-xdg-plugin.c \
+ $(NULL)
+
+libxdg_app_plugin_la_CFLAGS = \
+ $(LIBIDE_CFLAGS) \
+ $(XDG_APP_CFLAGS) \
+ $(OPTIMIZE_CFLAGS) \
+ -I$(top_srcdir)/libide \
+ $(NULL)
+
+libxdg_app_plugin_la_LIBADD = $(XDG_APP_LIBS)
+
+libxdg_app_plugin_la_LDFLAGS = \
+ $(OPTIMIZE_LDFLAGS) \
+ -avoid-version \
+ -module \
+ -export-regex peas_register_types \
+ $(NULL)
+
+include $(top_srcdir)/plugins/Makefile.plugin
+
+endif
+
+-include $(top_srcdir)/git.mk
diff --git a/plugins/xdg-app/configure.ac b/plugins/xdg-app/configure.ac
new file mode 100644
index 0000000..53875d6
--- /dev/null
+++ b/plugins/xdg-app/configure.ac
@@ -0,0 +1,24 @@
+m4_define([xdg_app_required_version], [0.4.8])
+
+# --enable-xdg-app-plugin=yes/no/auto
+AC_ARG_ENABLE([xdg-app-plugin],
+ [AS_HELP_STRING([--enable-xdg-app-plugin=@<:@yes/no/auto@:>@],
+ [Build with support for xdg-app.])],
+ [enable_xdg_app_plugin=$enableval],
+ [enable_xdg_app_plugin=auto])
+
+AS_IF([test "$enable_xdg_app_plugin" != no],[
+ PKG_CHECK_MODULES(XDG_APP,
+ [xdg-app >= xdg_app_required_version],
+ [have_xdg_app=yes],
+ [have_xdg_app=no])
+
+ AS_IF([test "$enable_xdg_app_plugin" = "yes" && "$have_xdg_app" = "no"],[
+ AC_MSG_ERROR([--enable-xdg-app-plugin requires xdg-app >= xdg_app_required_version])
+ ])
+
+ enable_xdg_app_plugin=yes
+])
+
+AM_CONDITIONAL(ENABLE_XDG_APP_PLUGIN, test x$enable_xdg_app_plugin = xyes)
+AC_CONFIG_FILES([plugins/xdg-app/Makefile])
diff --git a/plugins/xdg-app/gbp-xdg-plugin.c b/plugins/xdg-app/gbp-xdg-plugin.c
new file mode 100644
index 0000000..5fb941f
--- /dev/null
+++ b/plugins/xdg-app/gbp-xdg-plugin.c
@@ -0,0 +1,30 @@
+/* gbp-xdg-plugin.c
+ *
+ * Copyright (C) 2016 Christian Hergert <chergert redhat com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 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 <ide.h>
+
+#include "gbp-xdg-runtime-provider.h"
+
+void
+peas_register_types (PeasObjectModule *module)
+{
+ peas_object_module_register_extension_type (module,
+ IDE_TYPE_RUNTIME_PROVIDER,
+ GBP_TYPE_XDG_RUNTIME_PROVIDER);
+}
diff --git a/plugins/xdg-app/gbp-xdg-runtime-provider.c b/plugins/xdg-app/gbp-xdg-runtime-provider.c
new file mode 100644
index 0000000..e87ad91
--- /dev/null
+++ b/plugins/xdg-app/gbp-xdg-runtime-provider.c
@@ -0,0 +1,179 @@
+/* gbp-xdg-runtime-provider.c
+ *
+ * Copyright (C) 2016 Christian Hergert <chergert redhat com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 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 <xdg-app.h>
+
+#include "gbp-xdg-runtime-provider.h"
+
+struct _GbpXdgRuntimeProvider
+{
+ GObject parent_instance;
+ IdeRuntimeManager *manager;
+ XdgAppInstallation *installation;
+ GCancellable *cancellable;
+ GPtrArray *runtimes;
+};
+
+static void runtime_provider_iface_init (IdeRuntimeProviderInterface *);
+
+G_DEFINE_TYPE_EXTENDED (GbpXdgRuntimeProvider, gbp_xdg_runtime_provider, G_TYPE_OBJECT, 0,
+ G_IMPLEMENT_INTERFACE (IDE_TYPE_RUNTIME_PROVIDER,
+ runtime_provider_iface_init))
+
+static void
+gbp_xdg_runtime_provider_load_worker (GTask *task,
+ gpointer source_object,
+ gpointer task_data,
+ GCancellable *cancellable)
+{
+ GbpXdgRuntimeProvider *self = source_object;
+ GPtrArray *ret;
+ GPtrArray *ar;
+ GError *error = NULL;
+ guint i;
+
+ g_assert (G_IS_TASK (task));
+ g_assert (GBP_IS_XDG_RUNTIME_PROVIDER (self));
+
+ self->installation = xdg_app_installation_new_user (cancellable, &error);
+
+ if (self->installation == NULL)
+ {
+ g_task_return_error (task, error);
+ return;
+ }
+
+ ar = xdg_app_installation_list_installed_refs_by_kind (self->installation,
+ XDG_APP_REF_KIND_RUNTIME,
+ cancellable,
+ &error);
+
+ if (ar == NULL)
+ {
+ g_task_return_error (task, error);
+ return;
+ }
+
+ ret = g_ptr_array_new_with_free_func (g_object_unref);
+
+ for (i = 0; i < ar->len; i++)
+ {
+ XdgAppInstalledRef *ref = g_ptr_array_index (ar, i);
+ g_autofree gchar *str = NULL;
+ g_autofree gchar *id = NULL;
+ const gchar *name;
+ const gchar *arch;
+ const gchar *branch;
+
+ g_assert (XDG_APP_IS_INSTALLED_REF (ref));
+
+ name = xdg_app_ref_get_name (XDG_APP_REF (ref));
+ arch = xdg_app_ref_get_arch (XDG_APP_REF (ref));
+ branch = xdg_app_ref_get_branch (XDG_APP_REF (ref));
+
+ id = g_strdup_printf ("%s-%s-%s", name, branch, arch);
+ str = g_strdup_printf ("%s %s (%s)", name, branch, arch);
+
+ g_ptr_array_add (ret, ide_runtime_new (id, str));
+ }
+
+ g_ptr_array_unref (ar);
+
+ g_task_return_pointer (task, ret, (GDestroyNotify)g_ptr_array_unref);
+}
+
+static void
+gbp_xdg_runtime_provider_load_cb (GObject *object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ GbpXdgRuntimeProvider *self = (GbpXdgRuntimeProvider *)object;
+ GPtrArray *ret;
+ GError *error = NULL;
+ guint i;
+
+ g_assert (GBP_IS_XDG_RUNTIME_PROVIDER (self));
+ g_assert (G_IS_TASK (result));
+
+ if (!(ret = g_task_propagate_pointer (G_TASK (result), &error)))
+ {
+ g_warning ("%s", error->message);
+ g_clear_error (&error);
+ return;
+ }
+
+ for (i = 0; i < ret->len; i++)
+ {
+ IdeRuntime *runtime = g_ptr_array_index (ret, i);
+
+ ide_runtime_manager_add (self->manager, runtime);
+ }
+
+ self->runtimes = ret;
+}
+
+static void
+gbp_xdg_runtime_provider_load (IdeRuntimeProvider *provider,
+ IdeRuntimeManager *manager)
+{
+ GbpXdgRuntimeProvider *self = (GbpXdgRuntimeProvider *)provider;
+ g_autoptr(GTask) task = NULL;
+
+ g_assert (GBP_IS_XDG_RUNTIME_PROVIDER (self));
+ g_assert (IDE_IS_RUNTIME_MANAGER (manager));
+
+ ide_set_weak_pointer (&self->manager, manager);
+
+ self->cancellable = g_cancellable_new ();
+
+ task = g_task_new (self, self->cancellable, gbp_xdg_runtime_provider_load_cb, NULL);
+ g_task_run_in_thread (task, gbp_xdg_runtime_provider_load_worker);
+}
+
+static void
+gbp_xdg_runtime_provider_unload (IdeRuntimeProvider *provider,
+ IdeRuntimeManager *manager)
+{
+ GbpXdgRuntimeProvider *self = (GbpXdgRuntimeProvider *)provider;
+
+ g_assert (GBP_IS_XDG_RUNTIME_PROVIDER (self));
+ g_assert (IDE_IS_RUNTIME_MANAGER (manager));
+
+ if (self->cancellable != NULL)
+ g_cancellable_cancel (self->cancellable);
+
+ ide_clear_weak_pointer (&self->manager);
+ g_clear_object (&self->cancellable);
+}
+
+static void
+gbp_xdg_runtime_provider_class_init (GbpXdgRuntimeProviderClass *klass)
+{
+}
+
+static void
+gbp_xdg_runtime_provider_init (GbpXdgRuntimeProvider *self)
+{
+}
+
+static void
+runtime_provider_iface_init (IdeRuntimeProviderInterface *iface)
+{
+ iface->load = gbp_xdg_runtime_provider_load;
+ iface->unload = gbp_xdg_runtime_provider_unload;
+}
diff --git a/plugins/xdg-app/gbp-xdg-runtime-provider.h b/plugins/xdg-app/gbp-xdg-runtime-provider.h
new file mode 100644
index 0000000..d1440e6
--- /dev/null
+++ b/plugins/xdg-app/gbp-xdg-runtime-provider.h
@@ -0,0 +1,32 @@
+/* gbp-xdg-runtime-provider.h
+ *
+ * Copyright (C) 2016 Christian Hergert <chergert redhat com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 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 GBP_XDG_RUNTIME_PROVIDER_H
+#define GBP_XDG_RUNTIME_PROVIDER_H
+
+#include <ide.h>
+
+G_BEGIN_DECLS
+
+#define GBP_TYPE_XDG_RUNTIME_PROVIDER (gbp_xdg_runtime_provider_get_type())
+
+G_DECLARE_FINAL_TYPE (GbpXdgRuntimeProvider, gbp_xdg_runtime_provider, GBP, XDG_RUNTIME_PROVIDER, GObject)
+
+G_END_DECLS
+
+#endif /* GBP_XDG_RUNTIME_PROVIDER_H */
diff --git a/plugins/xdg-app/xdg-app.plugin b/plugins/xdg-app/xdg-app.plugin
new file mode 100644
index 0000000..b8b3d19
--- /dev/null
+++ b/plugins/xdg-app/xdg-app.plugin
@@ -0,0 +1,7 @@
+[Plugin]
+Module=xdg-app-plugin
+Name=Xdg-App
+Description=Provides support for building with Xdg-App
+Authors=Christian Hergert <christian hergert me>
+Copyright=Copyright © 2016 Christian Hergert
+Builtin=true
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]