[gnome-builder/wip/cosimoc/flatpak-greeter: 2/10] Loading a project and set it up from a given flatpak manifest
- From: Cosimo Cecchi <cosimoc src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-builder/wip/cosimoc/flatpak-greeter: 2/10] Loading a project and set it up from a given flatpak manifest
- Date: Sat, 17 Dec 2016 21:12:38 +0000 (UTC)
commit cda7f780919f931c4d4fa21febe31facb54d7906
Author: Simon Schampijer <simon schampijer endlessm com>
Date: Fri Dec 9 12:02:38 2016 +0000
Loading a project and set it up from a given flatpak manifest
This adds a command line option (-m) to pass a flatpak manifest
when starting GNOME Builder. A greeter with progress feedback
is displayed while the workbench is created and flatpak-builder
downloads the sources in the background.
This works currently for git sources only. Support for archives
and file sources (patches) will be handled in a follow up
commit.
libide/application/ide-application-actions.c | 38 ++-
libide/application/ide-application-command-line.c | 17 +
libide/greeter/ide-greeter-perspective.c | 31 +-
libide/greeter/ide-greeter-perspective.h | 3 +-
plugins/flatpak/Makefile.am | 18 +-
plugins/flatpak/configure.ac | 46 ++-
plugins/flatpak/flatpak.plugin | 1 +
plugins/flatpak/gbp-flatpak-clone-widget.c | 508 ++++++++++++++++++++
plugins/flatpak/gbp-flatpak-clone-widget.h | 40 ++
plugins/flatpak/gbp-flatpak-clone-widget.ui | 51 ++
plugins/flatpak/gbp-flatpak-genesis-addin.c | 204 ++++++++
plugins/flatpak/gbp-flatpak-genesis-addin.h | 32 ++
plugins/flatpak/gbp-flatpak-plugin.c | 4 +
.../flatpak/gbp-flatpak-resources.gresource.xml | 6 +
plugins/git/ide-git-plugin.c | 6 +
plugins/git/ide-git-remote-callbacks.c | 11 +
16 files changed, 999 insertions(+), 17 deletions(-)
---
diff --git a/libide/application/ide-application-actions.c b/libide/application/ide-application-actions.c
index fb8b872..243ae47 100644
--- a/libide/application/ide-application-actions.c
+++ b/libide/application/ide-application-actions.c
@@ -175,17 +175,14 @@ ide_application_actions_open_project (GSimpleAction *action,
static void
-ide_application_actions_new_project (GSimpleAction *action,
- GVariant *variant,
- gpointer user_data)
+ide_application_actions_load_workbench_view (IdeApplication *self,
+ const char *genesis_view,
+ const char *manifest)
{
- IdeApplication *self = user_data;
IdeWorkbench *workbench = NULL;
IdePerspective *greeter;
const GList *list;
- g_assert (IDE_IS_APPLICATION (self));
-
list = gtk_application_get_windows (GTK_APPLICATION (self));
for (; list != NULL; list = list->next)
@@ -214,13 +211,25 @@ ide_application_actions_new_project (GSimpleAction *action,
if (greeter)
{
ide_greeter_perspective_show_genesis_view (IDE_GREETER_PERSPECTIVE (greeter),
- "GbpCreateProjectGenesisAddin");
+ genesis_view, manifest);
}
gtk_window_present (GTK_WINDOW (workbench));
}
static void
+ide_application_actions_new_project (GSimpleAction *action,
+ GVariant *variant,
+ gpointer user_data)
+{
+ IdeApplication *self = user_data;
+
+ g_assert (IDE_IS_APPLICATION (self));
+
+ ide_application_actions_load_workbench_view (self, "GbpCreateProjectGenesisAddin", NULL);
+}
+
+static void
ide_application_actions_shortcuts (GSimpleAction *action,
GVariant *variant,
gpointer user_data)
@@ -307,6 +316,20 @@ ide_application_actions_load_project (GSimpleAction *action,
}
}
+static void
+ide_application_actions_load_flatpak (GSimpleAction *action,
+ GVariant *args,
+ gpointer user_data)
+{
+ IdeApplication *self = user_data;
+ const gchar *manifest = NULL;
+
+ g_assert (IDE_IS_APPLICATION (self));
+
+ manifest = g_variant_get_string (args, NULL);
+ ide_application_actions_load_workbench_view (self, "GbpFlatpakGenesisAddin", manifest);
+}
+
static const GActionEntry IdeApplicationActions[] = {
{ "about", ide_application_actions_about },
{ "dayhack", ide_application_actions_dayhack },
@@ -314,6 +337,7 @@ static const GActionEntry IdeApplicationActions[] = {
{ "open-project", ide_application_actions_open_project },
{ "new-project", ide_application_actions_new_project },
{ "load-project", ide_application_actions_load_project, "s"},
+ { "load-flatpak", ide_application_actions_load_flatpak, "s"},
{ "preferences", ide_application_actions_preferences },
{ "quit", ide_application_actions_quit },
{ "shortcuts", ide_application_actions_shortcuts },
diff --git a/libide/application/ide-application-command-line.c
b/libide/application/ide-application-command-line.c
index f673385..c722e32 100644
--- a/libide/application/ide-application-command-line.c
+++ b/libide/application/ide-application-command-line.c
@@ -164,6 +164,7 @@ ide_application_local_command_line (GApplication *application,
IdeApplication *self = (IdeApplication *)application;
g_autofree gchar *path_copy = NULL;
g_autofree gchar *filename = NULL;
+ g_autofree gchar *manifest = NULL;
GOptionContext *context = NULL;
GOptionGroup *group;
const gchar *shortdesc = NULL;
@@ -233,6 +234,14 @@ ide_application_local_command_line (GApplication *application,
N_("Opens the project specified by PATH"),
N_("PATH") },
+ { "manifest",
+ 'm',
+ G_OPTION_FLAG_IN_MAIN,
+ G_OPTION_ARG_FILENAME,
+ &manifest,
+ N_("Clones the project specified by MANIFEST"),
+ N_("MANIFEST") },
+
{ NULL }
};
@@ -458,6 +467,14 @@ ide_application_local_command_line (GApplication *application,
goto cleanup;
}
+ if (manifest != NULL)
+ {
+ GVariant *file;
+ file = g_variant_new ("s", manifest);
+ g_action_group_activate_action ((GActionGroup *) application, "load-flatpak", file);
+ goto cleanup;
+ }
+
g_application_activate (application);
cleanup:
diff --git a/libide/greeter/ide-greeter-perspective.c b/libide/greeter/ide-greeter-perspective.c
index 636f6b4..418c3b9 100644
--- a/libide/greeter/ide-greeter-perspective.c
+++ b/libide/greeter/ide-greeter-perspective.c
@@ -74,6 +74,7 @@ struct _IdeGreeterPerspective
};
static void ide_perspective_iface_init (IdePerspectiveInterface *iface);
+static void ide_greeter_perspective_genesis_continue (IdeGreeterPerspective *self);
G_DEFINE_TYPE_EXTENDED (IdeGreeterPerspective, ide_greeter_perspective, GTK_TYPE_BIN, 0,
G_IMPLEMENT_INTERFACE (IDE_TYPE_PERSPECTIVE,
@@ -749,12 +750,24 @@ ide_greeter_perspective_open_clicked (IdeGreeterPerspective *self,
void
ide_greeter_perspective_show_genesis_view (IdeGreeterPerspective *self,
- const gchar *genesis_addin_name)
+ const gchar *genesis_addin_name,
+ const gchar *manifest)
{
+ GtkWidget *addin;
+
g_assert (IDE_IS_GREETER_PERSPECTIVE (self));
- gtk_stack_set_visible_child_name (self->genesis_stack, genesis_addin_name);
+ addin = gtk_stack_get_child_by_name (self->genesis_stack, genesis_addin_name);
+ gtk_stack_set_visible_child (self->genesis_stack, addin);
egg_state_machine_set_state (self->state_machine, "genesis");
+
+ if (manifest != NULL)
+ {
+ g_object_set (addin, "manifest", manifest, NULL);
+
+ gtk_widget_hide (GTK_WIDGET (self->genesis_continue_button));
+ ide_greeter_perspective_genesis_continue (self);
+ }
}
static void
@@ -767,7 +780,7 @@ genesis_button_clicked (IdeGreeterPerspective *self,
g_assert (GTK_IS_BUTTON (button));
name = gtk_widget_get_name (GTK_WIDGET (button));
- ide_greeter_perspective_show_genesis_view (self, name);
+ ide_greeter_perspective_show_genesis_view (self, name, NULL);
}
static void
@@ -922,8 +935,7 @@ run_genesis_addin (PeasExtensionSet *set,
}
static void
-ide_greeter_perspective_genesis_continue_clicked (IdeGreeterPerspective *self,
- GtkButton *button)
+ide_greeter_perspective_genesis_continue (IdeGreeterPerspective *self)
{
struct {
IdeGreeterPerspective *self;
@@ -931,7 +943,6 @@ ide_greeter_perspective_genesis_continue_clicked (IdeGreeterPerspective *self,
} state = { 0 };
g_assert (IDE_IS_GREETER_PERSPECTIVE (self));
- g_assert (GTK_IS_BUTTON (button));
state.self = self;
state.name = gtk_stack_get_visible_child_name (self->genesis_stack);
@@ -940,6 +951,14 @@ ide_greeter_perspective_genesis_continue_clicked (IdeGreeterPerspective *self,
}
static void
+ide_greeter_perspective_genesis_continue_clicked (IdeGreeterPerspective *self,
+ GtkButton *button)
+{
+ g_assert (GTK_IS_BUTTON (button));
+ ide_greeter_perspective_genesis_continue (self);
+}
+
+static void
update_title_for_matching_addin (PeasExtensionSet *set,
PeasPluginInfo *plugin_info,
PeasExtension *exten,
diff --git a/libide/greeter/ide-greeter-perspective.h b/libide/greeter/ide-greeter-perspective.h
index 122bbd7..d0f86ea 100644
--- a/libide/greeter/ide-greeter-perspective.h
+++ b/libide/greeter/ide-greeter-perspective.h
@@ -30,7 +30,8 @@ G_BEGIN_DECLS
G_DECLARE_FINAL_TYPE (IdeGreeterPerspective, ide_greeter_perspective, IDE, GREETER_PERSPECTIVE, GtkBin)
void ide_greeter_perspective_show_genesis_view (IdeGreeterPerspective *self,
- const gchar *genesis_addin_name);
+ const gchar *genesis_addin_name,
+ const gchar *manifest);
G_END_DECLS
diff --git a/plugins/flatpak/Makefile.am b/plugins/flatpak/Makefile.am
index 3f31772..935f59f 100644
--- a/plugins/flatpak/Makefile.am
+++ b/plugins/flatpak/Makefile.am
@@ -21,12 +21,26 @@ libflatpak_plugin_la_SOURCES = \
gbp-flatpak-runner.h \
gbp-flatpak-application-addin.c \
gbp-flatpak-application-addin.h \
+ gbp-flatpak-clone-widget.c \
+ gbp-flatpak-clone-widget.h \
+ gbp-flatpak-genesis-addin.c \
+ gbp-flatpak-genesis-addin.h \
$(NULL)
-libflatpak_plugin_la_CFLAGS = $(PLUGIN_CFLAGS) $(FLATPAK_CFLAGS)
-libflatpak_plugin_la_LIBADD = $(FLATPAK_LIBS)
+nodist_libflatpak_plugin_la_SOURCES = \
+ gbp-flatpak-resources.c \
+ gbp-flatpak-resources.h
+
+libflatpak_plugin_la_CFLAGS = $(PLUGIN_CFLAGS) $(FLATPAK_CFLAGS) $(GIT_CFLAGS)
+libflatpak_plugin_la_LIBADD = $(FLATPAK_LIBS) $(GIT_LIBS)
libflatpak_plugin_la_LDFLAGS = $(PLUGIN_LDFLAGS)
+glib_resources_c = gbp-flatpak-resources.c
+glib_resources_h = gbp-flatpak-resources.h
+glib_resources_xml = gbp-flatpak-resources.gresource.xml
+glib_resources_namespace = gbp_flatpak
+include $(top_srcdir)/build/autotools/Makefile.am.gresources
+
include $(top_srcdir)/plugins/Makefile.plugin
endif
diff --git a/plugins/flatpak/configure.ac b/plugins/flatpak/configure.ac
index d820b50..d21a4d1 100644
--- a/plugins/flatpak/configure.ac
+++ b/plugins/flatpak/configure.ac
@@ -1,4 +1,5 @@
m4_define([flatpak_required_version], [0.6.9])
+m4_define([ggit_required_version], [0.24.0])
# --enable-flatpak-plugin=yes/no/auto
AC_ARG_ENABLE([flatpak-plugin],
@@ -18,7 +19,50 @@ AS_IF([test "$enable_flatpak_plugin" != no],[
AC_MSG_ERROR([--enable-flatpak-plugin requires flatpak >= flatpak_required_version])
])
- enable_flatpak_plugin=$have_flatpak
+ PKG_CHECK_MODULES(GIT,
+ [libgit2-glib-1.0 >= ggit_required_version],
+ [have_git=yes],
+ [have_git=no])
+
+ AS_IF([test "$enable_flatpak_plugin" = "yes" && test "$have_git" = "no"],[
+ AC_MSG_ERROR([--enable-flatpak-plugin requires libgit2-glib-1.0 >= ggit_required_version])
+ ])
+
+ AS_IF([test "$have_flatpak" = "yes" && test "$have_git" = "yes"],[
+ [enable_flatpak_plugin=yes]
+ ])
+
+ dnl ***********************************************************************
+ dnl Be extra careful about libgit2-glib requirements
+ dnl ***********************************************************************
+ cflags_save="${CFLAGS}"
+ libs_save="${LIBS}"
+ CFLAGS="${CFLAGS} ${GIT_CFLAGS}"
+ LIBS="${LIBS} ${GIT_LIBS}"
+ # Thread-Safe
+ AC_MSG_CHECKING([for thread-safe support in libgit2])
+ AC_TRY_RUN([
+ #include <libgit2-glib/ggit.h>
+ int
+ main(int argc, const char *argv[])
+ {
+ ggit_init ();
+ return ((ggit_get_features() & GGIT_FEATURE_THREADS) != 0) ? 0 : 1;
+ }
+ ],[AC_MSG_RESULT([yes])],[AC_MSG_ERROR([no, please recompile a threadsafe version of libgit2
(-DTHREADSAFE:BOOL=ON)])])
+ # SSH
+ AC_MSG_CHECKING([for SSH support in libgit2])
+ AC_TRY_RUN([
+ #include <libgit2-glib/ggit.h>
+ int
+ main(int argc, const char *argv[])
+ {
+ ggit_init ();
+ return ((ggit_get_features() & GGIT_FEATURE_SSH) != 0) ? 0 : 1;
+ }
+ ],[AC_MSG_RESULT([yes])],[AC_MSG_ERROR([no, please recompile a libgit2 with ssh support])])
+ CFLAGS="${cflags_save}"
+ LIBS="${libs_save}"
])
AM_CONDITIONAL(ENABLE_FLATPAK_PLUGIN, [test "x$enable_flatpak_plugin" = "xyes"])
diff --git a/plugins/flatpak/flatpak.plugin b/plugins/flatpak/flatpak.plugin
index 03e199a..4f11f19 100644
--- a/plugins/flatpak/flatpak.plugin
+++ b/plugins/flatpak/flatpak.plugin
@@ -5,3 +5,4 @@ Description=Provides support for building with Flatpak
Authors=Christian Hergert <christian hergert me>
Copyright=Copyright © 2016 Christian Hergert
Builtin=true
+Depends=git-plugin
diff --git a/plugins/flatpak/gbp-flatpak-clone-widget.c b/plugins/flatpak/gbp-flatpak-clone-widget.c
new file mode 100644
index 0000000..8e8decf
--- /dev/null
+++ b/plugins/flatpak/gbp-flatpak-clone-widget.c
@@ -0,0 +1,508 @@
+/* gbp-flatpak-clone-widget.c
+ *
+ * Copyright (C) 2016 Endless Mobile, Inc.
+ *
+ * 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 <glib/gi18n.h>
+#include <libgit2-glib/ggit.h>
+#include <ide.h>
+
+#include "egg-animation.h"
+
+#include "gbp-flatpak-clone-widget.h"
+
+#define ANIMATION_DURATION_MSEC 250
+
+struct _GbpFlatpakCloneWidget
+{
+ GtkBin parent_instance;
+
+ GtkProgressBar *clone_progress;
+
+ guint is_ready : 1;
+
+ gchar *child_name;
+ gchar *id;
+ gchar *manifest;
+};
+
+typedef enum {
+ TYPE_GIT,
+ TYPE_ARCHIVE
+} SourceType;
+
+typedef struct
+{
+ SourceType type;
+ IdeVcsUri *uri;
+ gchar *branch;
+ gchar *sha;
+} ModuleSource;
+
+typedef struct
+{
+ ModuleSource *src;
+ GFile *destination;
+ GFile *project_file;
+} DownloadRequest;
+
+enum {
+ PROP_0,
+ PROP_IS_READY,
+ PROP_MANIFEST,
+ LAST_PROP
+};
+
+G_DEFINE_TYPE (GbpFlatpakCloneWidget, gbp_flatpak_clone_widget, GTK_TYPE_BIN)
+
+static void
+module_source_free (void *data)
+{
+ ModuleSource *src = data;
+
+ g_clear_pointer (&src->uri, ide_vcs_uri_unref);
+ g_free (src->branch);
+ g_free (src->sha);
+ g_slice_free (ModuleSource, src);
+}
+
+static void
+download_request_free (gpointer data)
+{
+ DownloadRequest *req = data;
+
+ module_source_free (req->src);
+ g_clear_object (&req->destination);
+ g_clear_object (&req->project_file);
+ g_slice_free (DownloadRequest, req);
+}
+
+static DownloadRequest *
+download_request_new (ModuleSource *src,
+ GFile *destination)
+{
+ DownloadRequest *req;
+
+ g_assert (src);
+ g_assert (destination);
+
+ req = g_slice_new0 (DownloadRequest);
+ req->src = src;
+ req->destination = g_object_ref (destination);
+
+ return req;
+}
+
+static void
+gbp_flatpak_clone_widget_finalize (GObject *object)
+{
+ GbpFlatpakCloneWidget *self = (GbpFlatpakCloneWidget *)object;
+
+ g_clear_pointer (&self->child_name, g_free);
+ g_clear_pointer (&self->id, g_free);
+ g_clear_pointer (&self->manifest, g_free);
+
+ G_OBJECT_CLASS (gbp_flatpak_clone_widget_parent_class)->finalize (object);
+}
+
+static void
+gbp_flatpak_clone_widget_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GbpFlatpakCloneWidget *self = GBP_FLATPAK_CLONE_WIDGET(object);
+ switch (prop_id)
+ {
+ case PROP_MANIFEST:
+ g_free (self->manifest);
+ self->manifest = g_value_dup_string (value);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
+ }
+}
+
+static void
+gbp_flatpak_clone_widget_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GbpFlatpakCloneWidget *self = GBP_FLATPAK_CLONE_WIDGET(object);
+
+ switch (prop_id)
+ {
+ case PROP_IS_READY:
+ g_value_set_boolean (value, self->is_ready);
+ break;
+
+ case PROP_MANIFEST:
+ g_value_set_string (value, self->manifest);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+}
+
+static void
+gbp_flatpak_clone_widget_class_init (GbpFlatpakCloneWidgetClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+
+ object_class->finalize = gbp_flatpak_clone_widget_finalize;
+ object_class->get_property = gbp_flatpak_clone_widget_get_property;
+ object_class->set_property = gbp_flatpak_clone_widget_set_property;
+
+ g_object_class_install_property (object_class,
+ PROP_IS_READY,
+ g_param_spec_boolean ("is-ready",
+ "Is Ready",
+ "If the widget is ready to continue.",
+ FALSE,
+ (G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)));
+
+ g_object_class_install_property (object_class,
+ PROP_MANIFEST,
+ g_param_spec_string ("manifest",
+ "Manifest",
+ "Name of the flatpak manifest to load.",
+ NULL,
+ (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
+
+ gtk_widget_class_set_css_name (widget_class, "flatpakclonewidget");
+ gtk_widget_class_set_template_from_resource (widget_class,
"/org/gnome/builder/plugins/flatpak-plugin/gbp-flatpak-clone-widget.ui");
+ gtk_widget_class_bind_template_child (widget_class, GbpFlatpakCloneWidget, clone_progress);
+}
+
+static void
+gbp_flatpak_clone_widget_init (GbpFlatpakCloneWidget *self)
+{
+ gtk_widget_init_template (GTK_WIDGET (self));
+}
+
+static void
+ide_workbench_open_project_async_cb (GObject *object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ GbpFlatpakCloneWidget *self = user_data;
+ IdeWorkbench *workbench = IDE_WORKBENCH (object);
+ IdeConfigurationManager *configmgr;
+ IdeConfiguration *config;
+ IdeContext *context;
+ IdeContext *config_context;
+ IdeRuntimeManager *runtime_manager;
+
+ g_assert (IDE_IS_WORKBENCH (workbench));
+ g_assert (GBP_IS_FLATPAK_CLONE_WIDGET (self));
+
+ context = ide_workbench_get_context (IDE_WORKBENCH (workbench));
+ configmgr = ide_context_get_configuration_manager (context);
+ config = ide_configuration_manager_get_current (configmgr);
+
+ config_context = ide_object_get_context (IDE_OBJECT (config));
+ runtime_manager = ide_context_get_runtime_manager (config_context);
+
+ if (g_list_model_get_n_items (G_LIST_MODEL (runtime_manager)) > 0)
+ {
+ g_autoptr(IdeRuntime) last =
+ g_list_model_get_item (G_LIST_MODEL (runtime_manager),
+ g_list_model_get_n_items (G_LIST_MODEL (runtime_manager)) - 1);
+ ide_configuration_set_runtime_id (config, ide_runtime_get_id (last));
+ }
+}
+
+static gboolean
+open_after_timeout (gpointer user_data)
+{
+ g_autoptr(GTask) task = user_data;
+ DownloadRequest *req;
+ GbpFlatpakCloneWidget *self;
+ IdeWorkbench *workbench;
+
+ IDE_ENTRY;
+
+ req = g_task_get_task_data (task);
+ self = g_task_get_source_object (task);
+ g_assert (GBP_IS_FLATPAK_CLONE_WIDGET (self));
+
+ workbench = ide_widget_get_workbench (GTK_WIDGET (self));
+ g_assert (IDE_IS_WORKBENCH (workbench));
+
+ ide_workbench_open_project_async (workbench, req->project_file, NULL,
+ ide_workbench_open_project_async_cb, g_object_ref (self));
+
+ IDE_RETURN (G_SOURCE_REMOVE);
+}
+
+static void
+gbp_flatpak_clone_widget_worker_completed (GTask *task,
+ GParamSpec *pspec,
+ gpointer user_data)
+{
+ GbpFlatpakCloneWidget *self = user_data;
+
+ if (!g_task_get_completed (task))
+ return;
+
+ egg_object_animate_full (self->clone_progress,
+ EGG_ANIMATION_EASE_IN_OUT_QUAD,
+ ANIMATION_DURATION_MSEC,
+ NULL,
+ (GDestroyNotify)ide_widget_hide_with_fade,
+ self->clone_progress,
+ "fraction", 1.0,
+ NULL);
+
+ /* Wait for a second so animations can complete before opening
+ * the project. Otherwise, it's pretty jarring to the user.
+ */
+ g_timeout_add (ANIMATION_DURATION_MSEC, open_after_timeout, g_object_ref (task));
+}
+
+static void
+gbp_flatpak_clone_widget_worker (GTask *task,
+ gpointer source_object,
+ gpointer task_data,
+ GCancellable *cancellable)
+{
+ GbpFlatpakCloneWidget *self = source_object;
+ DownloadRequest *req = task_data;
+ g_autofree gchar *uristr = NULL;
+ GgitFetchOptions *fetch_options;
+ g_autoptr(GgitCloneOptions) clone_options = NULL;
+ g_autoptr(GgitRemoteCallbacks) callbacks = NULL;
+ g_autoptr(GgitRepository) repository = NULL;
+ g_autoptr(IdeProgress) progress = NULL;
+ g_autoptr(GFile) src = NULL;
+ g_autoptr(GFile) dst = NULL;
+ GError *error = NULL;
+ GType git_callbacks_type;
+
+ g_assert (G_IS_TASK (task));
+ g_assert (GBP_IS_FLATPAK_CLONE_WIDGET (self));
+ g_assert (req != NULL);
+ g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
+
+ /* First, try to open an existing repository at this path */
+ repository = ggit_repository_open (req->destination, &error);
+
+ /* Ignore errors when the repository is not found, but fail the
+ * task otherwise.
+ */
+ if (repository == NULL &&
+ !g_error_matches (error, GGIT_ERROR, GGIT_ERROR_NOTFOUND))
+ {
+ g_task_return_error (task, error);
+ return;
+ }
+
+ g_clear_error (&error);
+
+ if (repository == NULL)
+ {
+ /* HACK: we don't want libide to depend on libgit2 just yet, so for
+ * now, we just lookup the GType of the object we need from the git
+ * plugin by name.
+ */
+ git_callbacks_type = g_type_from_name ("IdeGitRemoteCallbacks");
+ g_assert (git_callbacks_type != 0);
+
+ callbacks = g_object_new (git_callbacks_type, NULL);
+ g_object_get (callbacks, "progress", &progress, NULL);
+ g_object_bind_property (progress, "fraction", self->clone_progress, "fraction", 0);
+
+ fetch_options = ggit_fetch_options_new ();
+ ggit_fetch_options_set_remote_callbacks (fetch_options, callbacks);
+
+ clone_options = ggit_clone_options_new ();
+ ggit_clone_options_set_is_bare (clone_options, FALSE);
+ ggit_clone_options_set_checkout_branch (clone_options, req->src->branch);
+ ggit_clone_options_set_fetch_options (clone_options, fetch_options);
+ g_clear_pointer (&fetch_options, ggit_fetch_options_free);
+
+ uristr = ide_vcs_uri_to_string (req->src->uri);
+ ggit_repository_clone (uristr, req->destination, clone_options, &error);
+ if (repository == NULL)
+ {
+ g_task_return_error (task, error);
+ return;
+ }
+ }
+
+ req->project_file = ggit_repository_get_workdir (repository);
+
+ /* copy manifest into the source directory */
+ src = g_file_new_for_path (self->manifest);
+ dst = g_file_get_child (req->project_file,
+ g_strjoin (".", self->id, "json", NULL));
+ g_clear_pointer (&self->id, g_free);
+ if (!g_file_copy (src, dst, G_FILE_COPY_OVERWRITE, NULL,
+ NULL, NULL, &error))
+ {
+ g_task_return_error (task, error);
+ return;
+ }
+
+ g_task_return_boolean (task, TRUE);
+}
+
+static ModuleSource *
+get_source (GbpFlatpakCloneWidget *self,
+ GError **error)
+{
+ g_autoptr(JsonParser) parser = NULL;
+ JsonNode *root_node;
+ JsonObject *root_object;
+ JsonObject *app_object;
+ JsonArray *modules = NULL;
+ JsonArray *sources = NULL;
+ guint num_modules;
+ ModuleSource *src;
+ g_autoptr(IdeVcsUri) uri = NULL;
+
+ parser = json_parser_new ();
+ if (!json_parser_load_from_file (parser, self->manifest, error))
+ return NULL;
+
+ root_node = json_parser_get_root (parser);
+ root_object = json_node_get_object (root_node);
+
+ self->id = g_strdup (json_object_get_string_member (root_object, "app-id"));
+
+ modules = json_object_get_array_member (root_object, "modules");
+ num_modules = json_array_get_length (modules);
+
+ /* guess that the primary module is always the last one */
+ app_object = json_array_get_object_element (modules, num_modules - 1);
+ sources = json_object_get_array_member (app_object, "sources");
+
+ for (guint i = 0; i < json_array_get_length (sources); i++)
+ {
+ JsonNode *source;
+ JsonObject *source_object;
+ const gchar *url;
+
+ source = json_array_get_element (sources, i);
+ source_object = json_node_get_object (source);
+ src = g_slice_new0 (ModuleSource);
+
+ if (g_strcmp0 (json_object_get_string_member (source_object, "type"), "git") == 0)
+ {
+ src->type = TYPE_GIT;
+ if (json_object_has_member (source_object, "branch"))
+ src->branch = g_strdup (json_object_get_string_member (source_object, "branch"));
+ }
+
+ url = json_object_get_string_member (source_object, "url");
+ src->uri = ide_vcs_uri_new (url);
+ }
+
+ return src;
+}
+
+void
+gbp_flatpak_clone_widget_clone_async (GbpFlatpakCloneWidget *self,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ g_autoptr(GTask) task = NULL;
+ g_autoptr(GSettings) settings = NULL;
+ g_autoptr(GFile) destination = NULL;
+ g_autofree gchar *path = NULL;
+ g_autofree gchar *projects_dir = NULL;
+ DownloadRequest *req;
+ ModuleSource *src;
+ GError *error = NULL;
+
+ g_return_if_fail (GBP_IS_FLATPAK_CLONE_WIDGET (self));
+ g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable));
+
+ task = g_task_new (self, cancellable, callback, user_data);
+
+ src = get_source (self, &error);
+ if (src == NULL)
+ {
+ g_task_return_error (task, error);
+ return;
+ }
+
+ if (src->uri != NULL)
+ {
+ const gchar *uri_path;
+ gchar *name = NULL;
+
+ uri_path = ide_vcs_uri_get_path (src->uri);
+ if (uri_path != NULL)
+ {
+ name = g_path_get_basename (uri_path);
+
+ if (g_str_has_suffix (name, ".git"))
+ *(strrchr (name, '.')) = '\0';
+
+ if (!g_str_equal (name, "/"))
+ {
+ g_free (self->child_name);
+ self->child_name = g_steal_pointer (&name);
+ }
+
+ g_free (name);
+ }
+ }
+
+ settings = g_settings_new ("org.gnome.builder");
+ path = g_settings_get_string (settings, "projects-directory");
+
+ if (ide_str_empty0 (path))
+ path = g_build_filename (g_get_home_dir (), "Projects", NULL);
+
+ if (!g_path_is_absolute (path))
+ projects_dir = g_build_filename (g_get_home_dir (), path, NULL);
+ else
+ projects_dir = g_steal_pointer (&path);
+
+ destination = g_file_new_for_path (projects_dir);
+
+ if (self->child_name)
+ {
+ g_autoptr(GFile) child = g_file_get_child (destination, self->child_name);
+ g_set_object (&destination, child);
+ }
+
+ req = download_request_new (src, destination);
+
+ g_task_set_task_data (task, req, download_request_free);
+ g_task_run_in_thread (task, gbp_flatpak_clone_widget_worker);
+
+ g_signal_connect (task, "notify::completed",
+ G_CALLBACK (gbp_flatpak_clone_widget_worker_completed), self);
+}
+
+gboolean
+gbp_flatpak_clone_widget_clone_finish (GbpFlatpakCloneWidget *self,
+ GAsyncResult *result,
+ GError **error)
+{
+ g_return_val_if_fail (GBP_IS_FLATPAK_CLONE_WIDGET (self), FALSE);
+ g_return_val_if_fail (G_IS_TASK (result), FALSE);
+
+ return g_task_propagate_boolean (G_TASK (result), error);
+}
diff --git a/plugins/flatpak/gbp-flatpak-clone-widget.h b/plugins/flatpak/gbp-flatpak-clone-widget.h
new file mode 100644
index 0000000..3b29155
--- /dev/null
+++ b/plugins/flatpak/gbp-flatpak-clone-widget.h
@@ -0,0 +1,40 @@
+/* gbp-flatpak-clone-widget.h
+ *
+ * Copyright (C) 2016 Endless Mobile, Inc.
+ *
+ * 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_FLATPAK_CLONE_WIDGET_H
+#define GBP_FLATPAK_CLONE_WIDGET_H
+
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+#define GBP_TYPE_FLATPAK_CLONE_WIDGET (gbp_flatpak_clone_widget_get_type())
+
+G_DECLARE_FINAL_TYPE (GbpFlatpakCloneWidget, gbp_flatpak_clone_widget, GBP, FLATPAK_CLONE_WIDGET, GtkBin)
+
+void gbp_flatpak_clone_widget_clone_async (GbpFlatpakCloneWidget *self,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+gboolean gbp_flatpak_clone_widget_clone_finish (GbpFlatpakCloneWidget *self,
+ GAsyncResult *result,
+ GError **error);
+
+G_END_DECLS
+
+#endif /* GBP_FLATPAK_CLONE_WIDGET_H */
diff --git a/plugins/flatpak/gbp-flatpak-clone-widget.ui b/plugins/flatpak/gbp-flatpak-clone-widget.ui
new file mode 100644
index 0000000..6d7baa9
--- /dev/null
+++ b/plugins/flatpak/gbp-flatpak-clone-widget.ui
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+ <!-- interface-requires gtk+ 3.18 -->
+ <template class="GbpFlatpakCloneWidget" parent="GtkBin">
+ <child>
+ <object class="GtkOverlay" id="page_clone_remote">
+ <property name="visible">true</property>
+ <child type="overlay">
+ <object class="GtkProgressBar" id="clone_progress">
+ <property name="valign">start</property>
+ <property name="fraction">0.0</property>
+ <property name="visible">true</property>
+ <style>
+ <class name="osd"/>
+ </style>
+ </object>
+ </child>
+ <child>
+ <object class="GtkBox">
+ <property name="orientation">vertical</property>
+ <property name="spacing">12</property>
+ <property name="valign">center</property>
+ <property name="vexpand">true</property>
+ <property name="visible">true</property>
+ <child>
+ <object class="GtkImage">
+ <property name="icon-name">document-save-symbolic</property>
+ <property name="pixel-size">128</property>
+ <property name="visible">true</property>
+ <property name="margin">12</property>
+ <style>
+ <class name="dim-label"/>
+ </style>
+ </object>
+ </child>
+ <child>
+ <object class="GtkLabel">
+ <property name="label" translatable="yes">Downloading application sources...</property>
+ <property name="margin-bottom">24</property>
+ <property name="visible">true</property>
+ <style>
+ <class name="dim-label"/>
+ </style>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ </template>
+</interface>
diff --git a/plugins/flatpak/gbp-flatpak-genesis-addin.c b/plugins/flatpak/gbp-flatpak-genesis-addin.c
new file mode 100644
index 0000000..4656a49
--- /dev/null
+++ b/plugins/flatpak/gbp-flatpak-genesis-addin.c
@@ -0,0 +1,204 @@
+/* gbp-flatpak-genesis-addin.c
+ *
+ * Copyright (C) 2016 Endless
+ *
+ * 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 <glib/gi18n.h>
+#include <ide.h>
+
+#include "gbp-flatpak-clone-widget.h"
+#include "gbp-flatpak-genesis-addin.h"
+
+struct _GbpFlatpakGenesisAddin
+{
+ GObject parent_instance;
+ GbpFlatpakCloneWidget *clone_widget;
+};
+
+static void genesis_addin_iface_init (IdeGenesisAddinInterface *iface);
+
+G_DEFINE_TYPE_EXTENDED (GbpFlatpakGenesisAddin, gbp_flatpak_genesis_addin, G_TYPE_OBJECT, 0,
+ G_IMPLEMENT_INTERFACE (IDE_TYPE_GENESIS_ADDIN, genesis_addin_iface_init))
+
+enum {
+ PROP_0,
+ PROP_IS_READY
+};
+
+static void
+gbp_flatpak_genesis_addin_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GbpFlatpakGenesisAddin *self = GBP_FLATPAK_GENESIS_ADDIN(object);
+
+ switch (prop_id)
+ {
+ case PROP_IS_READY:
+ if (self->clone_widget != NULL)
+ g_object_get_property (G_OBJECT (self->clone_widget), "is-ready", value);
+ else
+ g_value_set_boolean (value, FALSE);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
+ }
+}
+
+static void
+gbp_flatpak_genesis_addin_class_init (GbpFlatpakGenesisAddinClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->get_property = gbp_flatpak_genesis_addin_get_property;
+
+ g_object_class_install_property (object_class,
+ PROP_IS_READY,
+ g_param_spec_boolean ("is-ready",
+ "Is Ready",
+ "If the widget is ready to continue.",
+ FALSE,
+ (G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)));
+}
+
+static void
+gbp_flatpak_genesis_addin_init (GbpFlatpakGenesisAddin *self)
+{
+}
+
+static gchar *
+gbp_flatpak_genesis_addin_get_icon_name (IdeGenesisAddin *addin)
+{
+ return g_strdup ("gitg-symbolic");
+}
+
+static gchar *
+gbp_flatpak_genesis_addin_get_title (IdeGenesisAddin *addin)
+{
+ return g_strdup (_("Clone App"));
+}
+
+static void
+widget_is_ready (GtkWidget *widget,
+ GParamSpec *pspec,
+ GbpFlatpakGenesisAddin *self)
+{
+ g_assert (GBP_IS_FLATPAK_GENESIS_ADDIN (self));
+
+ g_object_notify (G_OBJECT (self), "is-ready");
+}
+
+static GtkWidget *
+gbp_flatpak_genesis_addin_get_widget (IdeGenesisAddin *addin)
+{
+ GbpFlatpakGenesisAddin *self = (GbpFlatpakGenesisAddin *)addin;
+
+ g_assert (GBP_IS_FLATPAK_GENESIS_ADDIN (self));
+
+ if (self->clone_widget == NULL)
+ {
+ self->clone_widget = g_object_new (GBP_TYPE_FLATPAK_CLONE_WIDGET,
+ "visible", TRUE,
+ NULL);
+ g_signal_connect (self->clone_widget,
+ "notify::is-ready",
+ G_CALLBACK (widget_is_ready),
+ self);
+ }
+
+ return GTK_WIDGET (self->clone_widget);
+}
+
+static void
+gbp_flatpak_genesis_addin_run_cb (GObject *object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ GbpFlatpakCloneWidget *widget = (GbpFlatpakCloneWidget *)object;
+ g_autoptr(GTask) task = user_data;
+ GError *error = NULL;
+
+ g_assert (G_IS_TASK (task));
+ g_assert (GBP_IS_FLATPAK_CLONE_WIDGET (widget));
+
+ if (!gbp_flatpak_clone_widget_clone_finish (widget, result, &error))
+ g_task_return_error (task, error);
+ else
+ g_task_return_boolean (task, TRUE);
+}
+
+static void
+gbp_flatpak_genesis_addin_run_async (IdeGenesisAddin *addin,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GbpFlatpakGenesisAddin *self = (GbpFlatpakGenesisAddin *)addin;
+ GTask *task;
+
+ g_return_if_fail (GBP_IS_FLATPAK_GENESIS_ADDIN (addin));
+ g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable));
+
+ task = g_task_new (self, cancellable, callback, user_data);
+ gbp_flatpak_clone_widget_clone_async (self->clone_widget,
+ cancellable,
+ gbp_flatpak_genesis_addin_run_cb,
+ task);
+}
+
+static gboolean
+gbp_flatpak_genesis_addin_run_finish (IdeGenesisAddin *addin,
+ GAsyncResult *result,
+ GError **error)
+{
+ g_return_val_if_fail (GBP_IS_FLATPAK_GENESIS_ADDIN (addin), FALSE);
+ g_return_val_if_fail (G_IS_TASK (result), FALSE);
+
+ return g_task_propagate_boolean (G_TASK (result), error);
+}
+
+static gint
+gbp_flatpak_genesis_addin_get_priority (IdeGenesisAddin *addin)
+{
+ return 100;
+}
+
+static gchar *
+gbp_flatpak_genesis_addin_get_label (IdeGenesisAddin *addin)
+{
+ return NULL;
+}
+
+static gchar *
+gbp_flatpak_genesis_addin_get_next_label (IdeGenesisAddin *addin)
+{
+ return g_strdup (_("Clone"));
+}
+
+static void
+genesis_addin_iface_init (IdeGenesisAddinInterface *iface)
+{
+ iface->get_title = gbp_flatpak_genesis_addin_get_title;
+ iface->get_icon_name = gbp_flatpak_genesis_addin_get_icon_name;
+ iface->get_widget = gbp_flatpak_genesis_addin_get_widget;
+ iface->run_async = gbp_flatpak_genesis_addin_run_async;
+ iface->run_finish = gbp_flatpak_genesis_addin_run_finish;
+ iface->get_priority = gbp_flatpak_genesis_addin_get_priority;
+ iface->get_label = gbp_flatpak_genesis_addin_get_label;
+ iface->get_next_label = gbp_flatpak_genesis_addin_get_next_label;
+}
diff --git a/plugins/flatpak/gbp-flatpak-genesis-addin.h b/plugins/flatpak/gbp-flatpak-genesis-addin.h
new file mode 100644
index 0000000..c812e46
--- /dev/null
+++ b/plugins/flatpak/gbp-flatpak-genesis-addin.h
@@ -0,0 +1,32 @@
+/* gbp-flatpak-genesis-addin.h
+ *
+ * Copyright (C) 2016 Endless
+ *
+ * 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_FLATPAK_GENESIS_ADDIN_H
+#define GBP_FLATPAK_GENESIS_ADDIN_H
+
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+#define GBP_TYPE_FLATPAK_GENESIS_ADDIN (gbp_flatpak_genesis_addin_get_type())
+
+G_DECLARE_FINAL_TYPE (GbpFlatpakGenesisAddin, gbp_flatpak_genesis_addin, GBP, FLATPAK_GENESIS_ADDIN, GObject)
+
+G_END_DECLS
+
+#endif /* GBP_FLATPAK_GENESIS_ADDIN_H */
diff --git a/plugins/flatpak/gbp-flatpak-plugin.c b/plugins/flatpak/gbp-flatpak-plugin.c
index 2ea41ab..fb9bb72 100644
--- a/plugins/flatpak/gbp-flatpak-plugin.c
+++ b/plugins/flatpak/gbp-flatpak-plugin.c
@@ -21,6 +21,7 @@
#include "gbp-flatpak-runtime-provider.h"
#include "gbp-flatpak-application-addin.h"
+#include "gbp-flatpak-genesis-addin.h"
void
peas_register_types (PeasObjectModule *module)
@@ -31,4 +32,7 @@ peas_register_types (PeasObjectModule *module)
peas_object_module_register_extension_type (module,
IDE_TYPE_APPLICATION_ADDIN,
GBP_TYPE_FLATPAK_APPLICATION_ADDIN);
+ peas_object_module_register_extension_type (module,
+ IDE_TYPE_GENESIS_ADDIN,
+ GBP_TYPE_FLATPAK_GENESIS_ADDIN);
}
diff --git a/plugins/flatpak/gbp-flatpak-resources.gresource.xml
b/plugins/flatpak/gbp-flatpak-resources.gresource.xml
new file mode 100644
index 0000000..52c931d
--- /dev/null
+++ b/plugins/flatpak/gbp-flatpak-resources.gresource.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<gresources>
+ <gresource prefix="/org/gnome/builder/plugins/flatpak-plugin">
+ <file>gbp-flatpak-clone-widget.ui</file>
+ </gresource>
+</gresources>
diff --git a/plugins/git/ide-git-plugin.c b/plugins/git/ide-git-plugin.c
index e8b5c6a..a33b0fb 100644
--- a/plugins/git/ide-git-plugin.c
+++ b/plugins/git/ide-git-plugin.c
@@ -20,6 +20,7 @@
#include <ide.h>
#include "ide-git-genesis-addin.h"
+#include "ide-git-remote-callbacks.h"
#include "ide-git-vcs.h"
#include "ide-git-vcs-config.h"
#include "ide-git-vcs-initializer.h"
@@ -54,6 +55,11 @@ peas_register_types (PeasObjectModule *module)
{
if (register_ggit ())
{
+ /* HACK: we load this type by name from the flatpak plugin, so make
+ * sure it exists.
+ */
+ g_type_ensure (IDE_TYPE_GIT_REMOTE_CALLBACKS);
+
peas_object_module_register_extension_type (module,
IDE_TYPE_VCS,
IDE_TYPE_GIT_VCS);
diff --git a/plugins/git/ide-git-remote-callbacks.c b/plugins/git/ide-git-remote-callbacks.c
index 6df1dc7..e611178 100644
--- a/plugins/git/ide-git-remote-callbacks.c
+++ b/plugins/git/ide-git-remote-callbacks.c
@@ -41,6 +41,7 @@ G_DEFINE_TYPE (IdeGitRemoteCallbacks, ide_git_remote_callbacks, GGIT_TYPE_REMOTE
enum {
PROP_0,
PROP_FRACTION,
+ PROP_PROGRESS,
LAST_PROP
};
@@ -202,6 +203,10 @@ ide_git_remote_callbacks_get_property (GObject *object,
g_value_set_double (value, ide_git_remote_callbacks_get_fraction (self));
break;
+ case PROP_PROGRESS:
+ g_value_set_object (value, ide_git_remote_callbacks_get_progress (self));
+ break;
+
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
@@ -227,6 +232,12 @@ ide_git_remote_callbacks_class_init (IdeGitRemoteCallbacksClass *klass)
1.0,
0.0,
(G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+ properties [PROP_PROGRESS] =
+ g_param_spec_object ("progress",
+ "Progress",
+ "An IdeProgress instance containing the operation progress.",
+ IDE_TYPE_PROGRESS,
+ (G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
g_object_class_install_properties (object_class, LAST_PROP, properties);
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]