Commit 5bbe3df2 authored by Christian Hergert's avatar Christian Hergert

pausable: add object helper for pausable operations

This gives us something we can let the context own to describe pausable
operations. We can then integrate it into the popover so that the user
has an escape hatch on expensive background operations.
parent 90308400
......@@ -25,6 +25,7 @@
#include "ide-debug.h"
#include "ide-global.h"
#include "ide-internal.h"
#include "ide-pausable.h"
#include "ide-service.h"
#include "buffers/ide-buffer-manager.h"
......@@ -72,6 +73,7 @@ struct _IdeContext
IdeDeviceManager *device_manager;
IdeDoap *doap;
IdeDocumentation *documentation;
GListStore *pausables;
GtkRecentManager *recent_manager;
IdeRunManager *run_manager;
IdeRuntimeManager *runtime_manager;
......@@ -499,11 +501,11 @@ ide_context_loaded (IdeContext *self)
static void
ide_context_dispose (GObject *object)
{
IdeContext *self = (IdeContext *)object;
IDE_ENTRY;
/*
* TODO: Shutdown services.
*/
g_list_store_remove_all (self->pausables);
G_OBJECT_CLASS (ide_context_parent_class)->dispose (object);
......@@ -518,6 +520,7 @@ ide_context_finalize (GObject *object)
IDE_ENTRY;
g_clear_object (&self->services);
g_clear_object (&self->pausables);
g_clear_pointer (&self->build_system_hint, g_free);
g_clear_pointer (&self->services_by_gtype, g_hash_table_unref);
......@@ -769,6 +772,8 @@ ide_context_init (IdeContext *self)
g_mutex_init (&self->unload_mutex);
self->pausables = g_list_store_new (IDE_TYPE_PAUSABLE);
self->recent_manager = g_object_ref (gtk_recent_manager_get_default ());
self->root_build_dir = g_build_filename (g_get_user_cache_dir (),
......@@ -2337,3 +2342,66 @@ ide_context_get_debug_manager (IdeContext *self)
return self->debug_manager;
}
/**
* ide_context_add_pausable:
* @self: an #IdeContext
* @pausable: an #IdePausable
*
* Adds a pausable which can be used to associate pausable actions with the
* context. Various UI in Builder may use this to present pausable actions to
* the user.
*
* Since: 3.26
*/
void
ide_context_add_pausable (IdeContext *self,
IdePausable *pausable)
{
g_return_if_fail (IDE_IS_CONTEXT (self));
g_return_if_fail (IDE_IS_PAUSABLE (pausable));
g_list_store_append (self->pausables, pausable);
}
/**
* ide_context_remove_pausable:
* @self: an #IdeContext
* @pausable: an #IdePausable
*
* Remove a previously registered #IdePausable.
*
* Since: 3.26
*/
void
ide_context_remove_pausable (IdeContext *self,
IdePausable *pausable)
{
guint n_items;
g_return_if_fail (IDE_IS_CONTEXT (self));
g_return_if_fail (IDE_IS_PAUSABLE (pausable));
n_items = g_list_model_get_n_items (G_LIST_MODEL (self->pausables));
for (guint i = 0; i < n_items; i++)
{
g_autoptr(IdePausable) item = NULL;
item = g_list_model_get_item (G_LIST_MODEL (self->pausables), i);
if (item == pausable)
{
g_list_store_remove (self->pausables, i);
break;
}
}
}
GListModel *
_ide_context_get_pausables (IdeContext *self)
{
g_return_val_if_fail (IDE_IS_CONTEXT (self), NULL);
return G_LIST_MODEL (self->pausables);
}
......@@ -76,6 +76,10 @@ void ide_context_restore_async (IdeContext
gboolean ide_context_restore_finish (IdeContext *self,
GAsyncResult *result,
GError **error);
void ide_context_add_pausable (IdeContext *self,
IdePausable *pausable);
void ide_context_remove_pausable (IdeContext *self,
IdePausable *pausable);
void ide_context_hold (IdeContext *self);
void ide_context_hold_for_object (IdeContext *self,
gpointer instance);
......
......@@ -41,6 +41,7 @@ void _ide_configuration_set_prebuild (IdeConfiguration
void _ide_configuration_set_postbuild (IdeConfiguration *self,
IdeBuildCommandQueue *postbuild);
gboolean _ide_context_is_restoring (IdeContext *self);
GListModel *_ide_context_get_pausables (IdeContext *self);
const gchar *_ide_file_get_content_type (IdeFile *self);
GtkSourceFile *_ide_file_set_content_type (IdeFile *self,
const gchar *content_type);
......
/* ide-pausable.c
*
* Copyright (C) 2017 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-pausable"
#include "ide-pausable.h"
struct _IdePausable
{
GObject parent_instance;
gchar *title;
gchar *subtitle;
guint paused : 1;
};
enum {
PROP_0,
PROP_TITLE,
PROP_SUBTITLE,
PROP_PAUSED,
N_PROPS
};
enum {
PAUSED,
UNPAUSED,
N_SIGNALS
};
G_DEFINE_TYPE (IdePausable, ide_pausable, G_TYPE_OBJECT)
static GParamSpec *properties [N_PROPS];
static guint signals [N_SIGNALS];
static void
ide_pausable_finalize (GObject *object)
{
IdePausable *self = (IdePausable *)object;
g_clear_pointer (&self->title, g_free);
g_clear_pointer (&self->subtitle, g_free);
G_OBJECT_CLASS (ide_pausable_parent_class)->finalize (object);
}
static void
ide_pausable_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
IdePausable *self = IDE_PAUSABLE (object);
switch (prop_id)
{
case PROP_TITLE:
g_value_set_string (value, self->title);
break;
case PROP_SUBTITLE:
g_value_set_string (value, self->subtitle);
break;
case PROP_PAUSED:
g_value_set_boolean (value, ide_pausable_get_paused (self));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
}
static void
ide_pausable_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
IdePausable *self = IDE_PAUSABLE (object);
switch (prop_id)
{
case PROP_TITLE:
ide_pausable_set_title (self, g_value_get_string (value));
break;
case PROP_SUBTITLE:
ide_pausable_set_subtitle (self, g_value_get_string (value));
break;
case PROP_PAUSED:
ide_pausable_set_paused (self, g_value_get_boolean (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
}
static void
ide_pausable_class_init (IdePausableClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->finalize = ide_pausable_finalize;
object_class->get_property = ide_pausable_get_property;
object_class->set_property = ide_pausable_set_property;
properties [PROP_PAUSED] =
g_param_spec_boolean ("paused", NULL, NULL, FALSE,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
properties [PROP_TITLE] =
g_param_spec_string ("title", NULL, NULL, NULL,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
properties [PROP_SUBTITLE] =
g_param_spec_string ("subtitle", NULL, NULL, NULL,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
g_object_class_install_properties (object_class, N_PROPS, properties);
signals [PAUSED] =
g_signal_new ("paused",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST,
0, NULL, NULL,
g_cclosure_marshal_VOID__VOID,
G_TYPE_NONE, 0);
signals [UNPAUSED] =
g_signal_new ("unpaused",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST,
0, NULL, NULL,
g_cclosure_marshal_VOID__VOID,
G_TYPE_NONE, 0);
}
static void
ide_pausable_init (IdePausable *self)
{
}
IdePausable *
ide_pausable_new (void)
{
return g_object_new (IDE_TYPE_PAUSABLE, NULL);
}
const gchar *
ide_pausable_get_title (IdePausable *self)
{
g_return_val_if_fail (IDE_IS_PAUSABLE (self), NULL);
return self->title;
}
void
ide_pausable_set_title (IdePausable *self,
const gchar *title)
{
if (g_strcmp0 (title, self->title) != 0)
{
g_free (self->title);
self->title = g_strdup (title);
g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_TITLE]);
}
}
const gchar *
ide_pausable_get_subtitle (IdePausable *self)
{
g_return_val_if_fail (IDE_IS_PAUSABLE (self), NULL);
return self->subtitle;
}
void
ide_pausable_set_subtitle (IdePausable *self,
const gchar *subtitle)
{
if (g_strcmp0 (subtitle, self->subtitle) != 0)
{
g_free (self->subtitle);
self->subtitle = g_strdup (subtitle);
g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_SUBTITLE]);
}
}
gboolean
ide_pausable_get_paused (IdePausable *self)
{
g_return_val_if_fail (IDE_IS_PAUSABLE (self), FALSE);
return self->paused;
}
void
ide_pausable_set_paused (IdePausable *self,
gboolean paused)
{
g_return_if_fail (IDE_IS_PAUSABLE (self));
paused = !!paused;
if (self->paused != paused)
{
self->paused = paused;
if (paused)
g_signal_emit (self, signals [PAUSED], 0);
else
g_signal_emit (self, signals [UNPAUSED], 0);
g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_PAUSED]);
}
}
void
ide_pausable_pause (IdePausable *self)
{
g_return_if_fail (IDE_IS_PAUSABLE (self));
ide_pausable_set_paused (self, TRUE);
}
void
ide_pausable_unpause (IdePausable *self)
{
g_return_if_fail (IDE_IS_PAUSABLE (self));
ide_pausable_set_paused (self, FALSE);
}
/* ide-pausable.h
*
* Copyright (C) 2017 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/>.
*/
#pragma once
#include <gio/gio.h>
G_BEGIN_DECLS
#define IDE_TYPE_PAUSABLE (ide_pausable_get_type())
G_DECLARE_FINAL_TYPE (IdePausable, ide_pausable, IDE, PAUSABLE, GObject)
IdePausable *ide_pausable_new (void);
gboolean ide_pausable_get_paused (IdePausable *self);
void ide_pausable_set_paused (IdePausable *self,
gboolean paused);
void ide_pausable_pause (IdePausable *self);
void ide_pausable_unpause (IdePausable *self);
const gchar *ide_pausable_get_title (IdePausable *self);
void ide_pausable_set_title (IdePausable *self,
const gchar *title);
const gchar *ide_pausable_get_subtitle (IdePausable *self);
void ide_pausable_set_subtitle (IdePausable *self,
const gchar *subtitle);
G_END_DECLS
......@@ -84,6 +84,8 @@ typedef struct _IdeIndenter IdeIndenter;
typedef struct _IdeObject IdeObject;
typedef struct _IdePausable IdePausable;
typedef struct _IdeProgress IdeProgress;
typedef struct _IdeProject IdeProject;
......
......@@ -33,6 +33,7 @@ G_BEGIN_DECLS
#include "ide-global.h"
#include "ide-macros.h"
#include "ide-object.h"
#include "ide-pausable.h"
#include "ide-service.h"
#include "ide-version.h"
......
......@@ -49,13 +49,14 @@ libide_enums = gnome.mkenums('ide-enums',
)
libide_public_headers = [
'ide.h',
'ide-context.h',
'ide-global.h',
'ide-macros.h',
'ide-object.h',
'ide-pausable.h',
'ide-service.h',
'ide-types.h',
'ide.h',
'application/ide-application-addin.h',
'application/ide-application-credits.h',
'application/ide-application-tool.h',
......@@ -271,6 +272,11 @@ libide_icons_resources = gnome.compile_resources('ide-icons-resources',
)
libide_public_sources = [
'ide.c',
'ide-context.c',
'ide-object.c',
'ide-pausable.c',
'ide-service.c',
'application/ide-application-addin.c',
'application/ide-application-tool.c',
'application/ide-application.c',
......@@ -344,10 +350,6 @@ libide_public_sources = [
'highlighting/ide-highlight-engine.c',
'highlighting/ide-highlight-index.c',
'highlighting/ide-highlighter.c',
'ide-context.c',
'ide-object.c',
'ide-service.c',
'ide.c',
'langserv/ide-langserv-client.c',
'langserv/ide-langserv-completion-provider.c',
'langserv/ide-langserv-diagnostic-provider.c',
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment