[gnome-builder: 29/139] libide-io: add libide-io static library
- From: Christian Hergert <chergert src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-builder: 29/139] libide-io: add libide-io static library
- Date: Thu, 10 Jan 2019 04:19:45 +0000 (UTC)
commit 251ebf53098a9257d22e04c8876beba721ffbfc2
Author: Christian Hergert <chergert redhat com>
Date: Wed Jan 9 15:41:56 2019 -0800
libide-io: add libide-io static library
This refactoring extracts various IO-based utilities into a new libide-io
library that other static libraries can build upon. PTY utilities have
been abstracted to be more generally useful in libide.
src/libide/io/ide-content-type.c | 117 +++++++
src/libide/io/ide-content-type.h | 31 ++
src/libide/{util/ide-glib.c => io/ide-gfile.c} | 389 +++++++--------------
src/libide/io/ide-gfile.h | 75 ++++
src/libide/{util => io}/ide-line-reader.c | 2 +-
src/libide/{util => io}/ide-line-reader.h | 4 +-
src/libide/io/ide-marked-content.c | 236 +++++++++++++
src/libide/io/ide-marked-content.h | 67 ++++
src/libide/{util/ide-posix.c => io/ide-path.c} | 79 +----
src/libide/{util/ide-posix.h => io/ide-path.h} | 24 +-
.../{storage => io}/ide-persistent-map-builder.c | 4 +-
.../{storage => io}/ide-persistent-map-builder.h | 5 +-
src/libide/{storage => io}/ide-persistent-map.c | 5 +-
src/libide/{storage => io}/ide-persistent-map.h | 5 +-
src/libide/io/ide-pkcon-transfer.c | 279 +++++++++++++++
src/libide/io/ide-pkcon-transfer.h | 39 +++
.../ptyintercept.c => io/ide-pty-intercept.c} | 249 +++++++------
src/libide/io/ide-pty-intercept.h | 108 ++++++
src/libide/io/libide-io.h | 42 +++
src/libide/io/meson.build | 69 ++++
src/libide/storage/meson.build | 14 -
src/libide/util/ide-glib.h | 124 -------
src/libide/util/ptyintercept.h | 97 -----
23 files changed, 1355 insertions(+), 709 deletions(-)
---
diff --git a/src/libide/io/ide-content-type.c b/src/libide/io/ide-content-type.c
new file mode 100644
index 000000000..df2a88dc7
--- /dev/null
+++ b/src/libide/io/ide-content-type.c
@@ -0,0 +1,117 @@
+/* ide-content-type.c
+ *
+ * Copyright 2018-2019 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/>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#define G_LOG_DOMAIN "ide-glib"
+
+#include "config.h"
+
+#include "ide-content-type.h"
+
+/**
+ * ide_g_content_type_get_symbolic_icon:
+ *
+ * This function is simmilar to g_content_type_get_symbolic_icon() except that
+ * it takes our bundled icons into account to ensure that they are taken at a
+ * higher priority than the fallbacks from the current icon theme such as
+ * Adwaita.
+ *
+ * Returns: (transfer full) (nullable): A #GIcon or %NULL
+ *
+ * Since: 3.32
+ */
+GIcon *
+ide_g_content_type_get_symbolic_icon (const gchar *content_type)
+{
+ static GHashTable *bundled;
+ g_autoptr(GIcon) icon = NULL;
+
+ g_return_val_if_fail (content_type != NULL, NULL);
+
+ if (g_once_init_enter (&bundled))
+ {
+ GHashTable *table = g_hash_table_new (g_str_hash, g_str_equal);
+
+ /*
+ * This needs to be updated when we add icons for specific mime-types
+ * because of how icon theme loading works (and it wanting to use
+ * Adwaita generic icons before our hicolor specific icons.
+ */
+
+#define ADD_ICON(t, n, v) g_hash_table_insert (t, (gpointer)n, v ? (gpointer)v : (gpointer)n)
+ ADD_ICON (table, "application-x-php-symbolic", NULL);
+ ADD_ICON (table, "text-css-symbolic", NULL);
+ ADD_ICON (table, "text-html-symbolic", NULL);
+ ADD_ICON (table, "text-markdown-symbolic", NULL);
+ ADD_ICON (table, "text-rust-symbolic", NULL);
+ ADD_ICON (table, "text-sql-symbolic", NULL);
+ ADD_ICON (table, "text-x-authors-symbolic", NULL);
+ ADD_ICON (table, "text-x-changelog-symbolic", NULL);
+ ADD_ICON (table, "text-x-chdr-symbolic", NULL);
+ ADD_ICON (table, "text-x-copying-symbolic", NULL);
+ ADD_ICON (table, "text-x-cpp-symbolic", NULL);
+ ADD_ICON (table, "text-x-csrc-symbolic", NULL);
+ ADD_ICON (table, "text-x-javascript-symbolic", NULL);
+ ADD_ICON (table, "text-x-python-symbolic", NULL);
+ ADD_ICON (table, "text-x-python3-symbolic", "text-x-python-symbolic");
+ ADD_ICON (table, "text-x-readme-symbolic", NULL);
+ ADD_ICON (table, "text-x-ruby-symbolic", NULL);
+ ADD_ICON (table, "text-x-script-symbolic", NULL);
+ ADD_ICON (table, "text-x-vala-symbolic", NULL);
+ ADD_ICON (table, "text-xml-symbolic", NULL);
+#undef ADD_ICON
+
+ g_once_init_leave (&bundled, table);
+ }
+
+ /*
+ * Basically just steal the name if we get something that is not generic,
+ * because that is the only way we can somewhat ensure that we don't use
+ * the Adwaita fallback for generic when what we want is the *exact* match
+ * from our hicolor/ bundle.
+ */
+
+ icon = g_content_type_get_symbolic_icon (content_type);
+
+ if (G_IS_THEMED_ICON (icon))
+ {
+ const gchar * const *names = g_themed_icon_get_names (G_THEMED_ICON (icon));
+
+ if (names != NULL)
+ {
+ gboolean fallback = FALSE;
+
+ for (guint i = 0; names[i] != NULL; i++)
+ {
+ const gchar *replace = g_hash_table_lookup (bundled, names[i]);
+
+ if (replace != NULL)
+ return g_icon_new_for_string (replace, NULL);
+
+ fallback |= (g_str_equal (names[i], "text-plain") ||
+ g_str_equal (names[i], "application-octet-stream"));
+ }
+
+ if (fallback)
+ return g_icon_new_for_string ("text-x-generic-symbolic", NULL);
+ }
+ }
+
+ return g_steal_pointer (&icon);
+}
diff --git a/src/libide/io/ide-content-type.h b/src/libide/io/ide-content-type.h
new file mode 100644
index 000000000..6304b69c1
--- /dev/null
+++ b/src/libide/io/ide-content-type.h
@@ -0,0 +1,31 @@
+/* ide-content-type.h
+ *
+ * Copyright 2018-2019 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/>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#pragma once
+
+#include <libide-core.h>
+
+G_BEGIN_DECLS
+
+IDE_AVAILABLE_IN_3_32
+GIcon *ide_g_content_type_get_symbolic_icon (const gchar *content_type);
+
+G_END_DECLS
+
diff --git a/src/libide/util/ide-glib.c b/src/libide/io/ide-gfile.c
similarity index 68%
rename from src/libide/util/ide-glib.c
rename to src/libide/io/ide-gfile.c
index 587fa527d..22148bc9c 100644
--- a/src/libide/util/ide-glib.c
+++ b/src/libide/io/ide-gfile.c
@@ -1,4 +1,4 @@
-/* ide-glib.c
+/* ide-gfile.c
*
* Copyright 2016-2019 Christian Hergert <chergert redhat com>
*
@@ -18,180 +18,159 @@
* SPDX-License-Identifier: GPL-3.0-or-later
*/
-#define G_LOG_DOMAIN "ide-glib"
-
-#include <string.h>
+#define G_LOG_DOMAIN "ide-gfile"
#include "config.h"
-#include "util/ide-flatpak.h"
-#include "util/ide-glib.h"
-#include "subprocess/ide-subprocess.h"
-#include "subprocess/ide-subprocess-launcher.h"
-#include "threading/ide-task.h"
-#include "vcs/ide-vcs.h"
+#include <libide-threading.h>
-typedef struct
-{
- GType type;
- GTask *task;
- union {
- gboolean v_bool;
- gint v_int;
- GError *v_error;
- struct {
- gpointer pointer;
- GDestroyNotify destroy;
- } v_ptr;
- } u;
-} TaskState;
-
-static gboolean
-do_return (gpointer user_data)
-{
- TaskState *state = user_data;
+#include "ide-gfile.h"
- switch (state->type)
- {
- case G_TYPE_INT:
- g_task_return_int (state->task, state->u.v_int);
- break;
-
- case G_TYPE_BOOLEAN:
- g_task_return_boolean (state->task, state->u.v_bool);
- break;
-
- case G_TYPE_POINTER:
- g_task_return_pointer (state->task, state->u.v_ptr.pointer, state->u.v_ptr.destroy);
- state->u.v_ptr.pointer = NULL;
- state->u.v_ptr.destroy = NULL;
- break;
-
- default:
- if (state->type == G_TYPE_ERROR)
- {
- g_task_return_error (state->task, g_steal_pointer (&state->u.v_error));
- break;
- }
+static GPtrArray *g_ignored;
+G_LOCK_DEFINE_STATIC (ignored);
- g_assert_not_reached ();
+static GPtrArray *
+get_ignored_locked (void)
+{
+ static const gchar *ignored_patterns[] = {
+ /* Ignore Gio temporary files */
+ ".goutputstream-*",
+ /* Ignore minified JS */
+ "*.min.js",
+ "*.min.js.*",
+ };
+
+ if (g_ignored == NULL)
+ {
+ g_ignored = g_ptr_array_new ();
+ for (guint i = 0; i < G_N_ELEMENTS (ignored_patterns); i++)
+ g_ptr_array_add (g_ignored, g_pattern_spec_new (ignored_patterns[i]));
}
- g_clear_object (&state->task);
- g_slice_free (TaskState, state);
-
- return G_SOURCE_REMOVE;
+ return g_ignored;
}
-static void
-task_state_attach (TaskState *state)
+/**
+ * ide_g_file_add_ignored_pattern:
+ * @pattern: a #GPatternSpec style glob pattern
+ *
+ * Adds a pattern that can be used to match ingored files. These are global
+ * to the application, so they should only include well-known ignored files
+ * such as those internal to a build system, or version control system, and
+ * similar.
+ *
+ * Since: 3.32
+ */
+void
+ide_g_file_add_ignored_pattern (const gchar *pattern)
{
- GMainContext *main_context;
- GSource *source;
-
- g_assert (state != NULL);
- g_assert (G_IS_TASK (state->task));
-
- main_context = g_task_get_context (state->task);
-
- source = g_timeout_source_new (0);
- g_source_set_callback (source, do_return, state, NULL);
- g_source_set_name (source, "[ide] ide_g_task_return_from_main");
- g_source_attach (source, main_context);
- g_source_unref (source);
+ G_LOCK (ignored);
+ g_ptr_array_add (get_ignored_locked (), g_pattern_spec_new (pattern));
+ G_UNLOCK (ignored);
}
/**
- * ide_g_task_return_boolean_from_main:
+ * ide_path_is_ignored:
+ * @path: the path to the file
+ *
+ * Checks if @path should be ignored using the global file
+ * ignores registered with Builder.
*
- * This is just like g_task_return_boolean() except that it enforces
- * that the current stack return to the main context before dispatching
- * the callback.
+ * Returns: %TRUE if @path should be ignored, otherwise %FALSE
*
* Since: 3.32
*/
-void
-ide_g_task_return_boolean_from_main (GTask *task,
- gboolean value)
+gboolean
+ide_path_is_ignored (const gchar *path)
{
- TaskState *state;
-
- g_return_if_fail (G_IS_TASK (task));
+ g_autofree gchar *name = NULL;
+ g_autofree gchar *reversed = NULL;
+ GPtrArray *ignored;
+ gsize len;
+ gboolean ret = FALSE;
- state = g_slice_new0 (TaskState);
- state->type = G_TYPE_BOOLEAN;
- state->task = g_object_ref (task);
- state->u.v_bool = !!value;
+ name = g_path_get_basename (path);
+ len = strlen (name);
+ reversed = g_utf8_strreverse (name, len);
- task_state_attach (state);
-}
+ /* Ignore empty files for whatever reason */
+ if (ide_str_empty0 (name))
+ return TRUE;
-void
-ide_g_task_return_int_from_main (GTask *task,
- gint value)
-{
- TaskState *state;
+ /* Ignore builtin backup files by GIO */
+ if (name[len - 1] == '~')
+ return TRUE;
- g_return_if_fail (G_IS_TASK (task));
+ G_LOCK (ignored);
- state = g_slice_new0 (TaskState);
- state->type = G_TYPE_INT;
- state->task = g_object_ref (task);
- state->u.v_int = value;
+ ignored = get_ignored_locked ();
- task_state_attach (state);
-}
-
-void
-ide_g_task_return_pointer_from_main (GTask *task,
- gpointer value,
- GDestroyNotify notify)
-{
- TaskState *state;
+ for (guint i = 0; i < ignored->len; i++)
+ {
+ GPatternSpec *pattern_spec = g_ptr_array_index (ignored, i);
- g_return_if_fail (G_IS_TASK (task));
+ if (g_pattern_match (pattern_spec, len, name, reversed))
+ {
+ ret = TRUE;
+ break;
+ }
+ }
- state = g_slice_new0 (TaskState);
- state->type = G_TYPE_POINTER;
- state->task = g_object_ref (task);
- state->u.v_ptr.pointer = value;
- state->u.v_ptr.destroy = notify;
+ G_UNLOCK (ignored);
- task_state_attach (state);
+ return ret;
}
/**
- * ide_g_task_return_error_from_main:
- * @task: a #GTask
- * @error: (transfer full): a #GError.
+ * ide_g_file_is_ignored:
+ * @file: a #GFile
*
- * Like g_task_return_error() but ensures we return to the main loop before
- * dispatching the result.
+ * Checks if @file should be ignored using the internal ignore rules. If you
+ * care about the version control system, see #IdeVcs and ide_vcs_is_ignored().
+ *
+ * Returns: %TRUE if @file should be ignored; otherwise %FALSE.
*
* Since: 3.32
*/
-void
-ide_g_task_return_error_from_main (GTask *task,
- GError *error)
+gboolean
+ide_g_file_is_ignored (GFile *file)
{
- TaskState *state;
+ g_autofree gchar *name = NULL;
+ g_autofree gchar *reversed = NULL;
+ GPtrArray *ignored;
+ gsize len;
+ gboolean ret = FALSE;
- g_return_if_fail (G_IS_TASK (task));
+ name = g_file_get_basename (file);
+ len = strlen (name);
+ reversed = g_utf8_strreverse (name, len);
- state = g_slice_new0 (TaskState);
- state->type = G_TYPE_ERROR;
- state->task = g_object_ref (task);
- state->u.v_error = error;
+ /* Ignore empty files for whatever reason */
+ if (ide_str_empty0 (name))
+ return TRUE;
- task_state_attach (state);
-}
+ /* Ignore builtin backup files by GIO */
+ if (name[len - 1] == '~')
+ return TRUE;
-const gchar *
-ide_gettext (const gchar *message)
-{
- if (message != NULL)
- return g_dgettext (GETTEXT_PACKAGE, message);
- return NULL;
+ G_LOCK (ignored);
+
+ ignored = get_ignored_locked ();
+
+ for (guint i = 0; i < ignored->len; i++)
+ {
+ GPatternSpec *pattern_spec = g_ptr_array_index (ignored, i);
+
+ if (g_pattern_match (pattern_spec, len, name, reversed))
+ {
+ ret = TRUE;
+ break;
+ }
+ }
+
+ G_UNLOCK (ignored);
+
+ return ret;
}
/**
@@ -386,6 +365,23 @@ ide_g_file_get_children_async (GFile *file,
ide_task_set_source_tag (task, ide_g_file_get_children_async);
ide_task_set_priority (task, io_priority);
ide_task_set_task_data (task, gc, get_children_free);
+
+#ifdef DEVELOPMENT_BUILD
+ /* Useful for testing slow interactions on project-tree and such */
+ if (g_getenv ("IDE_G_FILE_DELAY"))
+ {
+ gboolean
+ delayed_run (gpointer data)
+ {
+ g_autoptr(IdeTask) subtask = data;
+ ide_task_run_in_thread (subtask, ide_g_file_get_children_worker);
+ return G_SOURCE_REMOVE;
+ }
+ g_timeout_add_seconds (1, delayed_run, g_object_ref (task));
+ return;
+ }
+#endif
+
ide_task_run_in_thread (task, ide_g_file_get_children_worker);
}
@@ -491,7 +487,7 @@ populate_descendants_matching (GFile *file,
GFile *child = g_ptr_array_index (children, i);
/* Don't recurse into known bad directories */
- if (!ide_vcs_is_ignored (NULL, child, NULL))
+ if (!ide_g_file_is_ignored (child))
populate_descendants_matching (child, cancellable, results, spec, depth - 1);
}
}
@@ -693,124 +689,3 @@ ide_g_host_file_get_contents (const gchar *path,
return TRUE;
}
-
-gboolean
-ide_environ_parse (const gchar *pair,
- gchar **key,
- gchar **value)
-{
- const gchar *eq;
-
- g_return_val_if_fail (pair != NULL, FALSE);
-
- if (key != NULL)
- *key = NULL;
-
- if (value != NULL)
- *value = NULL;
-
- if ((eq = strchr (pair, '=')))
- {
- if (key != NULL)
- *key = g_strndup (pair, eq - pair);
-
- if (value != NULL)
- *value = g_strdup (eq + 1);
-
- return TRUE;
- }
-
- return FALSE;
-}
-
-/**
- * ide_g_content_type_get_symbolic_icon:
- *
- * This function is simmilar to g_content_type_get_symbolic_icon() except that
- * it takes our bundled icons into account to ensure that they are taken at a
- * higher priority than the fallbacks from the current icon theme such as
- * Adwaita.
- *
- * Returns: (transfer full) (nullable): A #GIcon or %NULL
- *
- * Since: 3.32
- */
-GIcon *
-ide_g_content_type_get_symbolic_icon (const gchar *content_type)
-{
- static GHashTable *bundled;
- g_autoptr(GIcon) icon = NULL;
-
- g_return_val_if_fail (content_type != NULL, NULL);
-
- if (g_once_init_enter (&bundled))
- {
- GHashTable *table = g_hash_table_new (g_str_hash, g_str_equal);
-
- /*
- * This needs to be updated when we add icons for specific mime-types
- * because of how icon theme loading works (and it wanting to use
- * Adwaita generic icons before our hicolor specific icons.
- */
-
-#define ADD_ICON(t, n, v) g_hash_table_insert (t, (gpointer)n, v ? (gpointer)v : (gpointer)n)
- ADD_ICON (table, "application-x-php-symbolic", NULL);
- ADD_ICON (table, "text-css-symbolic", NULL);
- ADD_ICON (table, "text-html-symbolic", NULL);
- ADD_ICON (table, "text-markdown-symbolic", NULL);
- ADD_ICON (table, "text-rust-symbolic", NULL);
- ADD_ICON (table, "text-sql-symbolic", NULL);
- ADD_ICON (table, "text-x-authors-symbolic", NULL);
- ADD_ICON (table, "text-x-changelog-symbolic", NULL);
- ADD_ICON (table, "text-x-chdr-symbolic", NULL);
- ADD_ICON (table, "text-x-copying-symbolic", NULL);
- ADD_ICON (table, "text-x-cpp-symbolic", NULL);
- ADD_ICON (table, "text-x-csrc-symbolic", NULL);
- ADD_ICON (table, "text-x-javascript-symbolic", NULL);
- ADD_ICON (table, "text-x-python-symbolic", NULL);
- ADD_ICON (table, "text-x-python3-symbolic", "text-x-python-symbolic");
- ADD_ICON (table, "text-x-readme-symbolic", NULL);
- ADD_ICON (table, "text-x-ruby-symbolic", NULL);
- ADD_ICON (table, "text-x-script-symbolic", NULL);
- ADD_ICON (table, "text-x-vala-symbolic", NULL);
- ADD_ICON (table, "text-xml-symbolic", NULL);
-#undef ADD_ICON
-
- g_once_init_leave (&bundled, table);
- }
-
- /*
- * Basically just steal the name if we get something that is not generic,
- * because that is the only way we can somewhat ensure that we don't use
- * the Adwaita fallback for generic when what we want is the *exact* match
- * from our hicolor/ bundle.
- */
-
- icon = g_content_type_get_symbolic_icon (content_type);
-
- if (G_IS_THEMED_ICON (icon))
- {
- const gchar * const *names = g_themed_icon_get_names (G_THEMED_ICON (icon));
-
- if (names != NULL)
- {
- gboolean fallback = FALSE;
-
- for (guint i = 0; names[i] != NULL; i++)
- {
- const gchar *replace = g_hash_table_lookup (bundled, names[i]);
-
- if (replace != NULL)
- return g_icon_new_for_string (replace, NULL);
-
- fallback |= (g_str_equal (names[i], "text-plain") ||
- g_str_equal (names[i], "application-octet-stream"));
- }
-
- if (fallback)
- return g_icon_new_for_string ("text-x-generic-symbolic", NULL);
- }
- }
-
- return g_steal_pointer (&icon);
-}
diff --git a/src/libide/io/ide-gfile.h b/src/libide/io/ide-gfile.h
new file mode 100644
index 000000000..250fec772
--- /dev/null
+++ b/src/libide/io/ide-gfile.h
@@ -0,0 +1,75 @@
+/* ide-gfile.h
+ *
+ * Copyright 2016-2019 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/>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#pragma once
+
+#if !defined (IDE_IO_INSIDE) && !defined (IDE_IO_COMPILATION)
+# error "Only <libide-io.h> can be included directly."
+#endif
+
+#include <libide-core.h>
+
+G_BEGIN_DECLS
+
+IDE_AVAILABLE_IN_3_32
+gboolean ide_path_is_ignored (const gchar *path);
+IDE_AVAILABLE_IN_3_32
+gboolean ide_g_file_is_ignored (GFile *file);
+IDE_AVAILABLE_IN_3_32
+void ide_g_file_add_ignored_pattern (const gchar *pattern);
+IDE_AVAILABLE_IN_3_32
+gchar *ide_g_file_get_uncanonical_relative_path (GFile *file,
+ GFile *other);
+IDE_AVAILABLE_IN_3_32
+void ide_g_file_find_with_depth_async (GFile *file,
+ const gchar *pattern,
+ guint max_depth,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+IDE_AVAILABLE_IN_3_32
+void ide_g_file_find_async (GFile *file,
+ const gchar *pattern,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+IDE_AVAILABLE_IN_3_32
+GPtrArray *ide_g_file_find_finish (GFile *file,
+ GAsyncResult *result,
+ GError **error);
+IDE_AVAILABLE_IN_3_32
+void ide_g_file_get_children_async (GFile *file,
+ const gchar *attributes,
+ GFileQueryInfoFlags flags,
+ gint io_priority,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+IDE_AVAILABLE_IN_3_32
+GPtrArray *ide_g_file_get_children_finish (GFile *file,
+ GAsyncResult *result,
+ GError **error);
+IDE_AVAILABLE_IN_3_32
+gboolean ide_g_host_file_get_contents (const gchar *path,
+ gchar **contents,
+ gsize *len,
+ GError **error);
+
+G_END_DECLS
diff --git a/src/libide/util/ide-line-reader.c b/src/libide/io/ide-line-reader.c
similarity index 98%
rename from src/libide/util/ide-line-reader.c
rename to src/libide/io/ide-line-reader.c
index 0ff7a6cd2..042531e79 100644
--- a/src/libide/util/ide-line-reader.c
+++ b/src/libide/io/ide-line-reader.c
@@ -24,7 +24,7 @@
#include <string.h>
-#include "util/ide-line-reader.h"
+#include "ide-line-reader.h"
void
ide_line_reader_init (IdeLineReader *reader,
diff --git a/src/libide/util/ide-line-reader.h b/src/libide/io/ide-line-reader.h
similarity index 96%
rename from src/libide/util/ide-line-reader.h
rename to src/libide/io/ide-line-reader.h
index 8c116531d..8e2a275fb 100644
--- a/src/libide/util/ide-line-reader.h
+++ b/src/libide/io/ide-line-reader.h
@@ -20,9 +20,7 @@
#pragma once
-#include <glib.h>
-
-#include "ide-version-macros.h"
+#include <libide-core.h>
G_BEGIN_DECLS
diff --git a/src/libide/io/ide-marked-content.c b/src/libide/io/ide-marked-content.c
new file mode 100644
index 000000000..19f5ebf15
--- /dev/null
+++ b/src/libide/io/ide-marked-content.c
@@ -0,0 +1,236 @@
+/* ide-marked-content.c
+ *
+ * Copyright 2018-2019 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/>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#define G_LOG_DOMAIN "ide-marked-content"
+
+#include "config.h"
+
+#include "ide-marked-content.h"
+
+#define IDE_MARKED_CONTENT_MAGIC 0x81124633
+
+struct _IdeMarkedContent
+{
+ guint magic;
+ IdeMarkedKind kind;
+ GBytes *data;
+ volatile gint ref_count;
+};
+
+G_DEFINE_BOXED_TYPE (IdeMarkedContent,
+ ide_marked_content,
+ ide_marked_content_ref,
+ ide_marked_content_unref)
+
+/**
+ * ide_marked_content_new:
+ * @content: a #GBytes containing the markup
+ * @kind: an #IdeMakredKind describing the markup kind
+ *
+ * Creates a new #IdeMarkedContent using the bytes provided.
+ *
+ * Returns: (transfer full): an #IdeMarkedContent
+ *
+ * Since: 3.32
+ */
+IdeMarkedContent *
+ide_marked_content_new (GBytes *content,
+ IdeMarkedKind kind)
+{
+ IdeMarkedContent *self;
+
+ g_return_val_if_fail (content != NULL, NULL);
+
+ self = g_slice_new0 (IdeMarkedContent);
+ self->magic = IDE_MARKED_CONTENT_MAGIC;
+ self->ref_count = 1;
+ self->data = g_bytes_ref (content);
+ self->kind = kind;
+
+ return self;
+}
+
+/**
+ * ide_marked_content_new_plaintext:
+ * @plaintext: (nullable): a string containing the plaintext
+ *
+ * Creates a new #IdeMarkedContent of type %IDE_MARKED_KIND_PLAINTEXT
+ * with the contents of @string.
+ *
+ * Returns: (transfer full): an #IdeMarkedContent
+ *
+ * Since: 3.32
+ */
+IdeMarkedContent *
+ide_marked_content_new_plaintext (const gchar *plaintext)
+{
+ if (plaintext == NULL)
+ plaintext = "";
+
+ return ide_marked_content_new_from_data (plaintext, -1, IDE_MARKED_KIND_PLAINTEXT);
+}
+
+/**
+ * ide_marked_content_new_from_data:
+ * @data: the data for the content
+ * @len: the length of the data, or -1 to strlen() @data
+ * @kind: the kind of markup
+ *
+ * Creates a new #IdeMarkedContent from the provided data.
+ *
+ * Returns: (transfer full): an #IdeMarkedContent
+ *
+ * Since: 3.32
+ */
+IdeMarkedContent *
+ide_marked_content_new_from_data (const gchar *data,
+ gssize len,
+ IdeMarkedKind kind)
+{
+ g_autoptr(GBytes) bytes = NULL;
+
+ if (len < 0)
+ len = strlen (data);
+
+ bytes = g_bytes_new (data, len);
+
+ return ide_marked_content_new (bytes, kind);
+}
+
+/**
+ * ide_marked_content_ref:
+ * @self: an #IdeMarkedContent
+ *
+ * Increments the reference count of @self by one.
+ *
+ * When a #IdeMarkedContent reaches a reference count of zero, by using
+ * ide_marked_content_unref(), it will be freed.
+ *
+ * Returns: (transfer full): @self with the reference count incremented
+ *
+ * Since: 3.32
+ */
+IdeMarkedContent *
+ide_marked_content_ref (IdeMarkedContent *self)
+{
+ g_return_val_if_fail (self != NULL, NULL);
+ g_return_val_if_fail (self->magic == IDE_MARKED_CONTENT_MAGIC, NULL);
+ g_return_val_if_fail (self->ref_count > 0, NULL);
+
+ g_atomic_int_inc (&self->ref_count);
+
+ return self;
+}
+
+/**
+ * ide_marked_content_unref:
+ * @self: an #IdeMarkedContent
+ *
+ * Decrements the reference count of @self by one.
+ *
+ * When the reference count of @self reaches zero, it will be freed.
+ *
+ * Since: 3.32
+ */
+void
+ide_marked_content_unref (IdeMarkedContent *self)
+{
+ g_return_if_fail (self != NULL);
+ g_return_if_fail (self->magic == IDE_MARKED_CONTENT_MAGIC);
+ g_return_if_fail (self->ref_count > 0);
+
+ if (g_atomic_int_dec_and_test (&self->ref_count))
+ {
+ self->magic = 0;
+ self->kind = 0;
+ g_clear_pointer (&self->data, g_bytes_unref);
+ g_slice_free (IdeMarkedContent, self);
+ }
+}
+
+/**
+ * ide_marked_content_get_kind:
+ * @self: an #IdeMarkedContent
+ *
+ * Gets the kind of markup that @self contains.
+ *
+ * This is used to display the content appropriately.
+ *
+ * Returns:
+ *
+ * Since: 3.32
+ */
+IdeMarkedKind
+ide_marked_content_get_kind (IdeMarkedContent *self)
+{
+ g_return_val_if_fail (self != NULL, 0);
+ g_return_val_if_fail (self->magic == IDE_MARKED_CONTENT_MAGIC, 0);
+ g_return_val_if_fail (self->ref_count > 0, 0);
+
+ return self->kind;
+}
+
+/**
+ * ide_marked_content_get_bytes:
+ *
+ * Gets the bytes for the marked content.
+ *
+ * Returns: (transfer none): a #GBytes
+ *
+ * Since: 3.32
+ */
+GBytes *
+ide_marked_content_get_bytes (IdeMarkedContent *self)
+{
+ g_return_val_if_fail (self != NULL, NULL);
+ g_return_val_if_fail (self->magic == IDE_MARKED_CONTENT_MAGIC, NULL);
+ g_return_val_if_fail (self->ref_count > 0, NULL);
+
+ return self->data;
+}
+
+/**
+ * ide_marked_content_as_string:
+ * @self: a #IdeMarkedContent
+ *
+ * Gets the contents of the marked content as a newly allcoated C string.
+ *
+ * Returns: (nullable): a newly allocated string or %NULL
+ *
+ * Since: 3.32
+ */
+gchar *
+ide_marked_content_as_string (IdeMarkedContent *self)
+{
+ g_return_val_if_fail (self != NULL, NULL);
+ g_return_val_if_fail (self->magic == IDE_MARKED_CONTENT_MAGIC, NULL);
+ g_return_val_if_fail (self->ref_count > 0, NULL);
+
+ if (self->data != NULL)
+ {
+ const gchar *buf;
+ gsize len;
+
+ if ((buf = g_bytes_get_data (self->data, &len)))
+ return g_strndup (buf, len);
+ }
+
+ return NULL;
+}
diff --git a/src/libide/io/ide-marked-content.h b/src/libide/io/ide-marked-content.h
new file mode 100644
index 000000000..0a5ecdba9
--- /dev/null
+++ b/src/libide/io/ide-marked-content.h
@@ -0,0 +1,67 @@
+/* ide-marked-content.h
+ *
+ * Copyright 2018-2019 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/>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#pragma once
+
+#if !defined (IDE_IO_INSIDE) && !defined (IDE_IO_COMPILATION)
+# error "Only <libide-io.h> can be included directly."
+#endif
+
+#include <libide-core.h>
+
+G_BEGIN_DECLS
+
+#define IDE_TYPE_MARKED_CONTENT (ide_marked_content_get_type())
+
+typedef struct _IdeMarkedContent IdeMarkedContent;
+
+typedef enum
+{
+ IDE_MARKED_KIND_PLAINTEXT = 0,
+ IDE_MARKED_KIND_MARKDOWN = 1,
+ IDE_MARKED_KIND_HTML = 2,
+ IDE_MARKED_KIND_PANGO = 3,
+} IdeMarkedKind;
+
+IDE_AVAILABLE_IN_3_32
+GType ide_marked_content_get_type (void);
+IDE_AVAILABLE_IN_3_32
+IdeMarkedContent *ide_marked_content_new (GBytes *content,
+ IdeMarkedKind kind);
+IDE_AVAILABLE_IN_3_32
+IdeMarkedContent *ide_marked_content_new_plaintext (const gchar *plaintext);
+IDE_AVAILABLE_IN_3_32
+IdeMarkedContent *ide_marked_content_new_from_data (const gchar *data,
+ gssize len,
+ IdeMarkedKind kind);
+IDE_AVAILABLE_IN_3_32
+GBytes *ide_marked_content_get_bytes (IdeMarkedContent *self);
+IDE_AVAILABLE_IN_3_32
+IdeMarkedKind ide_marked_content_get_kind (IdeMarkedContent *self);
+IDE_AVAILABLE_IN_3_32
+gchar *ide_marked_content_as_string (IdeMarkedContent *self);
+IDE_AVAILABLE_IN_3_32
+IdeMarkedContent *ide_marked_content_ref (IdeMarkedContent *self);
+IDE_AVAILABLE_IN_3_32
+void ide_marked_content_unref (IdeMarkedContent *self);
+
+G_DEFINE_AUTOPTR_CLEANUP_FUNC (IdeMarkedContent, ide_marked_content_unref)
+
+G_END_DECLS
diff --git a/src/libide/util/ide-posix.c b/src/libide/io/ide-path.c
similarity index 56%
rename from src/libide/util/ide-posix.c
rename to src/libide/io/ide-path.c
index 3e1cbcec5..51bd84211 100644
--- a/src/libide/util/ide-posix.c
+++ b/src/libide/io/ide-path.c
@@ -1,6 +1,6 @@
-/* ide-posix.c
+/* ide-path.c
*
- * Copyright 2016-2019 Christian Hergert <chergert redhat com>
+ * Copyright 2018-2019 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
@@ -23,83 +23,10 @@
#include "config.h"
#include <string.h>
-#include <sys/types.h>
-#include <sys/user.h>
-#include <sys/utsname.h>
#include <unistd.h>
#include <wordexp.h>
-#include "util/ide-posix.h"
-
-gchar *
-ide_create_host_triplet (const gchar *arch,
- const gchar *kernel,
- const gchar *system)
-{
- if (arch == NULL || kernel == NULL)
- return g_strdup (ide_get_system_type ());
- else if (system == NULL)
- return g_strdup_printf ("%s-%s", arch, kernel);
- else
- return g_strdup_printf ("%s-%s-%s", arch, kernel, system);
-}
-
-const gchar *
-ide_get_system_type (void)
-{
- static gchar *system_type;
- g_autofree gchar *os_lower = NULL;
- const gchar *machine = NULL;
- struct utsname u;
-
- if (system_type != NULL)
- return system_type;
-
- if (uname (&u) < 0)
- return g_strdup ("unknown");
-
- os_lower = g_utf8_strdown (u.sysname, -1);
-
- /* config.sub doesn't accept amd64-OS */
- machine = strcmp (u.machine, "amd64") ? u.machine : "x86_64";
-
- /*
- * TODO: Clearly we want to discover "gnu", but that should be just fine
- * for a default until we try to actually run on something non-gnu.
- * Which seems unlikely at the moment. If you run FreeBSD, you can
- * probably fix this for me :-) And while you're at it, make the
- * uname() call more portable.
- */
-
-#ifdef __GLIBC__
- system_type = g_strdup_printf ("%s-%s-%s", machine, os_lower, "gnu");
-#else
- system_type = g_strdup_printf ("%s-%s", machine, os_lower);
-#endif
-
- return system_type;
-}
-
-gchar *
-ide_get_system_arch (void)
-{
- struct utsname u;
- const char *machine;
-
- if (uname (&u) < 0)
- return g_strdup ("unknown");
-
- /* config.sub doesn't accept amd64-OS */
- machine = strcmp (u.machine, "amd64") ? u.machine : "x86_64";
-
- return g_strdup (machine);
-}
-
-gsize
-ide_get_system_page_size (void)
-{
- return sysconf (_SC_PAGE_SIZE);
-}
+#include "ide-path.h"
/**
* ide_path_expand:
diff --git a/src/libide/util/ide-posix.h b/src/libide/io/ide-path.h
similarity index 54%
rename from src/libide/util/ide-posix.h
rename to src/libide/io/ide-path.h
index f58793ed9..3144bc637 100644
--- a/src/libide/util/ide-posix.h
+++ b/src/libide/io/ide-path.h
@@ -1,6 +1,6 @@
-/* ide-posix.h
+/* ide-path.h
*
- * Copyright 2016-2019 Christian Hergert <chergert redhat com>
+ * Copyright 2018-2019 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
@@ -20,25 +20,17 @@
#pragma once
-#include <glib.h>
+#if !defined (IDE_IO_INSIDE) && !defined (IDE_IO_COMPILATION)
+# error "Only <libide-io.h> can be included directly."
+#endif
-#include "ide-version-macros.h"
+#include <libide-core.h>
G_BEGIN_DECLS
IDE_AVAILABLE_IN_3_32
-gchar *ide_get_system_arch (void);
+gchar *ide_path_collapse (const gchar *path);
IDE_AVAILABLE_IN_3_32
-const gchar *ide_get_system_type (void);
-IDE_AVAILABLE_IN_3_32
-gchar *ide_create_host_triplet (const gchar *arch,
- const gchar *kernel,
- const gchar *system);
-IDE_AVAILABLE_IN_3_32
-gsize ide_get_system_page_size (void) G_GNUC_CONST;
-IDE_AVAILABLE_IN_3_32
-gchar *ide_path_collapse (const gchar *path);
-IDE_AVAILABLE_IN_3_32
-gchar *ide_path_expand (const gchar *path);
+gchar *ide_path_expand (const gchar *path);
G_END_DECLS
diff --git a/src/libide/storage/ide-persistent-map-builder.c b/src/libide/io/ide-persistent-map-builder.c
similarity index 99%
rename from src/libide/storage/ide-persistent-map-builder.c
rename to src/libide/io/ide-persistent-map-builder.c
index d0c110439..7556d87f3 100644
--- a/src/libide/storage/ide-persistent-map-builder.c
+++ b/src/libide/io/ide-persistent-map-builder.c
@@ -23,10 +23,10 @@
#include "config.h"
+#include <libide-threading.h>
#include <string.h>
-#include "storage/ide-persistent-map-builder.h"
-#include "threading/ide-task.h"
+#include "ide-persistent-map-builder.h"
typedef struct
{
diff --git a/src/libide/storage/ide-persistent-map-builder.h b/src/libide/io/ide-persistent-map-builder.h
similarity index 97%
rename from src/libide/storage/ide-persistent-map-builder.h
rename to src/libide/io/ide-persistent-map-builder.h
index ecb4f0457..19bbb84e0 100644
--- a/src/libide/storage/ide-persistent-map-builder.h
+++ b/src/libide/io/ide-persistent-map-builder.h
@@ -1,6 +1,7 @@
/* ide-persistent-map-builder.h
*
* Copyright 2017 Anoop Chandu <anoopchandu96 gmail com>
+ * Copyright 2017-2019 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
@@ -20,9 +21,7 @@
#pragma once
-#include <gio/gio.h>
-
-#include "ide-version-macros.h"
+#include <libide-core.h>
G_BEGIN_DECLS
diff --git a/src/libide/storage/ide-persistent-map.c b/src/libide/io/ide-persistent-map.c
similarity index 99%
rename from src/libide/storage/ide-persistent-map.c
rename to src/libide/io/ide-persistent-map.c
index 099cf7a17..4bf7bb219 100644
--- a/src/libide/storage/ide-persistent-map.c
+++ b/src/libide/io/ide-persistent-map.c
@@ -23,8 +23,9 @@
#include "config.h"
-#include "storage/ide-persistent-map.h"
-#include "threading/ide-task.h"
+#include <libide-threading.h>
+
+#include "ide-persistent-map.h"
typedef struct
{
diff --git a/src/libide/storage/ide-persistent-map.h b/src/libide/io/ide-persistent-map.h
similarity index 96%
rename from src/libide/storage/ide-persistent-map.h
rename to src/libide/io/ide-persistent-map.h
index c88b7cc63..8589c9068 100644
--- a/src/libide/storage/ide-persistent-map.h
+++ b/src/libide/io/ide-persistent-map.h
@@ -1,6 +1,7 @@
/* ide-persistent-map.h
*
* Copyright 2017 Anoop Chandu <anoopchandu96 gmail com>
+ * Copyright 2017-2019 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
@@ -20,9 +21,7 @@
#pragma once
-#include <gio/gio.h>
-
-#include "ide-version-macros.h"
+#include <libide-core.h>
#define IDE_TYPE_PERSISTENT_MAP (ide_persistent_map_get_type ())
diff --git a/src/libide/io/ide-pkcon-transfer.c b/src/libide/io/ide-pkcon-transfer.c
new file mode 100644
index 000000000..76c819b17
--- /dev/null
+++ b/src/libide/io/ide-pkcon-transfer.c
@@ -0,0 +1,279 @@
+/* ide-pkcon-transfer.c
+ *
+ * Copyright 2017-2019 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/>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#define G_LOG_DOMAIN "ide-pkcon-transfer"
+
+#include "config.h"
+
+#include <glib/gi18n.h>
+#include <libide-threading.h>
+
+#include "ide-pkcon-transfer.h"
+
+struct _IdePkconTransfer
+{
+ IdeTransfer parent;
+ gchar **packages;
+ gchar *status;
+};
+
+enum {
+ PROP_0,
+ PROP_PACKAGES,
+ N_PROPS
+};
+
+G_DEFINE_TYPE (IdePkconTransfer, ide_pkcon_transfer, IDE_TYPE_TRANSFER)
+
+static GParamSpec *properties [N_PROPS];
+
+static void
+ide_pkcon_transfer_update_title (IdePkconTransfer *self)
+{
+ g_autofree gchar *title = NULL;
+ guint count;
+
+ g_assert (IDE_IS_PKCON_TRANSFER (self));
+
+ count = g_strv_length (self->packages);
+ title = g_strdup_printf (ngettext ("Installing %u package", "Installing %u packages", count), count);
+ ide_transfer_set_title (IDE_TRANSFER (self), title);
+}
+
+static void
+ide_pkcon_transfer_wait_check_cb (GObject *object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ IdeSubprocess *subprocess = (IdeSubprocess *)object;
+ g_autoptr(IdeTask) task = user_data;
+ g_autoptr(GError) error = NULL;
+
+ g_assert (IDE_IS_SUBPROCESS (subprocess));
+ g_assert (G_IS_ASYNC_RESULT (result));
+ g_assert (IDE_IS_TASK (task));
+
+ if (!ide_subprocess_wait_check_finish (subprocess, result, &error))
+ ide_task_return_error (task, g_steal_pointer (&error));
+ else
+ ide_task_return_boolean (task, TRUE);
+}
+
+static void
+ide_pkcon_transfer_read_line_cb (GObject *object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ GDataInputStream *stream = (GDataInputStream *)object;
+ g_autoptr(IdePkconTransfer) self = user_data;
+ g_autofree gchar *line = NULL;
+ g_auto(GStrv) parts = NULL;
+ gsize len;
+
+ g_assert (G_IS_DATA_INPUT_STREAM (stream));
+ g_assert (G_IS_ASYNC_RESULT (result));
+ g_assert (IDE_IS_PKCON_TRANSFER (self));
+
+ if (!(line = g_data_input_stream_read_line_finish_utf8 (stream, result, &len, NULL)))
+ return;
+
+ parts = g_strsplit (line, ":", 2);
+
+ if (parts[0]) g_strstrip (parts[0]);
+ if (parts[1]) g_strstrip (parts[1]);
+
+ if (g_strcmp0 (parts[0], "Status") == 0)
+ ide_transfer_set_status (IDE_TRANSFER (self), parts[1]);
+ else if (g_strcmp0 (parts[0], "Percentage") == 0 && parts[1])
+ ide_transfer_set_progress (IDE_TRANSFER (self), g_strtod (parts[1], NULL) / 100.0);
+
+ g_data_input_stream_read_line_async (stream,
+ G_PRIORITY_DEFAULT,
+ NULL,
+ ide_pkcon_transfer_read_line_cb,
+ g_object_ref (self));
+}
+
+static void
+ide_pkcon_transfer_execute_async (IdeTransfer *transfer,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ IdePkconTransfer *self = (IdePkconTransfer *)transfer;
+ g_autoptr(IdeSubprocessLauncher) launcher = NULL;
+ g_autoptr(IdeSubprocess) subprocess = NULL;
+ g_autoptr(GDataInputStream) data_stream = NULL;
+ g_autoptr(IdeTask) task = NULL;
+ g_autoptr(GError) error = NULL;
+ GInputStream *stdout_stream;
+
+ IDE_ENTRY;
+
+ g_assert (IDE_IS_TRANSFER (transfer));
+ g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
+
+ task = ide_task_new (self, cancellable, callback, user_data);
+ ide_task_set_source_tag (task, ide_pkcon_transfer_execute_async);
+
+ if (self->packages == NULL || !self->packages[0])
+ {
+ ide_task_return_boolean (task, TRUE);
+ IDE_EXIT;
+ }
+
+ launcher = ide_subprocess_launcher_new (G_SUBPROCESS_FLAGS_STDOUT_PIPE);
+ ide_subprocess_launcher_set_run_on_host (launcher, TRUE);
+ ide_subprocess_launcher_push_argv (launcher, "pkcon");
+ ide_subprocess_launcher_push_argv (launcher, "install");
+ ide_subprocess_launcher_push_argv (launcher, "-y");
+ ide_subprocess_launcher_push_argv (launcher, "-p");
+
+ for (guint i = 0; self->packages[i]; i++)
+ ide_subprocess_launcher_push_argv (launcher, self->packages[i]);
+
+ subprocess = ide_subprocess_launcher_spawn (launcher, cancellable, &error);
+
+ if (subprocess == NULL)
+ {
+ ide_task_return_error (task, g_steal_pointer (&error));
+ IDE_EXIT;
+ }
+
+ stdout_stream = ide_subprocess_get_stdout_pipe (subprocess);
+ data_stream = g_data_input_stream_new (stdout_stream);
+
+ g_data_input_stream_read_line_async (data_stream,
+ G_PRIORITY_DEFAULT,
+ cancellable,
+ ide_pkcon_transfer_read_line_cb,
+ g_object_ref (self));
+
+ ide_subprocess_wait_check_async (subprocess,
+ cancellable,
+ ide_pkcon_transfer_wait_check_cb,
+ g_steal_pointer (&task));
+
+ IDE_EXIT;
+}
+
+static gboolean
+ide_pkcon_transfer_execute_finish (IdeTransfer *transfer,
+ GAsyncResult *result,
+ GError **error)
+{
+ gboolean ret;
+
+ IDE_ENTRY;
+
+ g_assert (IDE_IS_TRANSFER (transfer));
+ g_assert (IDE_IS_TASK (result));
+
+ ret = ide_task_propagate_boolean (IDE_TASK (result), error);
+
+ IDE_RETURN (ret);
+}
+
+static void
+ide_pkcon_transfer_finalize (GObject *object)
+{
+ IdePkconTransfer *self = (IdePkconTransfer *)object;
+
+ g_clear_pointer (&self->packages, g_strfreev);
+ g_clear_pointer (&self->status, g_free);
+
+ G_OBJECT_CLASS (ide_pkcon_transfer_parent_class)->finalize (object);
+}
+
+static void
+ide_pkcon_transfer_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ IdePkconTransfer *self = IDE_PKCON_TRANSFER (object);
+
+ switch (prop_id)
+ {
+ case PROP_PACKAGES:
+ g_value_set_boxed (value, self->packages);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+}
+
+static void
+ide_pkcon_transfer_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ IdePkconTransfer *self = IDE_PKCON_TRANSFER (object);
+
+ switch (prop_id)
+ {
+ case PROP_PACKAGES:
+ self->packages = g_value_dup_boxed (value);
+ ide_pkcon_transfer_update_title (self);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+}
+
+static void
+ide_pkcon_transfer_class_init (IdePkconTransferClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ IdeTransferClass *transfer_class = IDE_TRANSFER_CLASS (klass);
+
+ object_class->finalize = ide_pkcon_transfer_finalize;
+ object_class->get_property = ide_pkcon_transfer_get_property;
+ object_class->set_property = ide_pkcon_transfer_set_property;
+
+ transfer_class->execute_async = ide_pkcon_transfer_execute_async;
+ transfer_class->execute_finish = ide_pkcon_transfer_execute_finish;
+
+ properties [PROP_PACKAGES] =
+ g_param_spec_boxed ("packages",
+ "Packages",
+ "The package names to be installed",
+ G_TYPE_STRV,
+ (G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_properties (object_class, N_PROPS, properties);
+}
+
+static void
+ide_pkcon_transfer_init (IdePkconTransfer *self)
+{
+ ide_transfer_set_icon_name (IDE_TRANSFER (self), "system-software-install-symbolic");
+}
+
+IdePkconTransfer *
+ide_pkcon_transfer_new (const gchar * const *packages)
+{
+ return g_object_new (IDE_TYPE_PKCON_TRANSFER,
+ "packages", packages,
+ NULL);
+}
diff --git a/src/libide/io/ide-pkcon-transfer.h b/src/libide/io/ide-pkcon-transfer.h
new file mode 100644
index 000000000..fe798e5ed
--- /dev/null
+++ b/src/libide/io/ide-pkcon-transfer.h
@@ -0,0 +1,39 @@
+/* ide-pkcon-transfer.h
+ *
+ * Copyright 2017-2019 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/>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#pragma once
+
+#if !defined (IDE_IO_INSIDE) && !defined (IDE_IO_COMPILATION)
+# error "Only <libide-io.h> can be included directly."
+#endif
+
+#include <libide-core.h>
+
+G_BEGIN_DECLS
+
+#define IDE_TYPE_PKCON_TRANSFER (ide_pkcon_transfer_get_type())
+
+IDE_AVAILABLE_IN_3_32
+G_DECLARE_FINAL_TYPE (IdePkconTransfer, ide_pkcon_transfer, IDE, PKCON_TRANSFER, IdeTransfer)
+
+IDE_AVAILABLE_IN_3_32
+IdePkconTransfer *ide_pkcon_transfer_new (const gchar * const *packages);
+
+G_END_DECLS
diff --git a/src/libide/util/ptyintercept.c b/src/libide/io/ide-pty-intercept.c
similarity index 66%
rename from src/libide/util/ptyintercept.c
rename to src/libide/io/ide-pty-intercept.c
index 868ce1d05..c498ce64f 100644
--- a/src/libide/util/ptyintercept.c
+++ b/src/libide/io/ide-pty-intercept.c
@@ -1,6 +1,6 @@
-/* ptyintercept.c
+/* ide-pty-intercept.c
*
- * Copyright 2018 Christian Hergert
+ * Copyright 2018-2019 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
@@ -35,7 +35,7 @@
#include <termios.h>
#include <unistd.h>
-#include "ptyintercept.h"
+#include "ide-pty-intercept.h"
/*
* We really don't need all that much. A PTY on Linux has a some amount of
@@ -49,18 +49,17 @@
#define MASTER_READ_PRIORITY G_PRIORITY_DEFAULT_IDLE
#define MASTER_WRITE_PRIORITY G_PRIORITY_HIGH
-
-static void _pty_intercept_side_close (pty_intercept_side_t *side);
-static gboolean _pty_intercept_in_cb (GIOChannel *channel,
- GIOCondition condition,
- gpointer user_data);
-static gboolean _pty_intercept_out_cb (GIOChannel *channel,
- GIOCondition condition,
- gpointer user_data);
-static void clear_source (guint *source_id);
+static void _ide_pty_intercept_side_close (IdePtyInterceptSide *side);
+static gboolean _ide_pty_intercept_in_cb (GIOChannel *channel,
+ GIOCondition condition,
+ gpointer user_data);
+static gboolean _ide_pty_intercept_out_cb (GIOChannel *channel,
+ GIOCondition condition,
+ gpointer user_data);
+static void clear_source (guint *source_id);
static gboolean
-_pty_intercept_set_raw (pty_fd_t fd)
+_ide_pty_intercept_set_raw (IdePtyFd fd)
{
struct termios t;
@@ -80,7 +79,7 @@ _pty_intercept_set_raw (pty_fd_t fd)
}
/**
- * pty_intercept_create_slave:
+ * ide_pty_intercept_create_slave:
* @master_fd: a pty master
* @blocking: use %FALSE to set O_NONBLOCK
*
@@ -90,15 +89,15 @@ _pty_intercept_set_raw (pty_fd_t fd)
* PTY slave.
*
* Returns: a FD for the slave PTY that should be closed with close().
- * Upon error, %PTY_FD_INVALID (-1) is returned.
+ * Upon error, %IDE_PTY_FD_INVALID (-1) is returned.
*
* Since: 3.32
*/
-pty_fd_t
-pty_intercept_create_slave (pty_fd_t master_fd,
- gboolean blocking)
+IdePtyFd
+ide_pty_intercept_create_slave (IdePtyFd master_fd,
+ gboolean blocking)
{
- g_auto(pty_fd_t) ret = PTY_FD_INVALID;
+ g_auto(IdePtyFd) ret = IDE_PTY_FD_INVALID;
gint extra = blocking ? 0 : O_NONBLOCK;
#if defined(HAVE_PTSNAME_R) || defined(__FreeBSD__)
char name[256];
@@ -109,50 +108,50 @@ pty_intercept_create_slave (pty_fd_t master_fd,
g_assert (master_fd != -1);
if (grantpt (master_fd) != 0)
- return PTY_FD_INVALID;
+ return IDE_PTY_FD_INVALID;
if (unlockpt (master_fd) != 0)
- return PTY_FD_INVALID;
+ return IDE_PTY_FD_INVALID;
#ifdef HAVE_PTSNAME_R
if (ptsname_r (master_fd, name, sizeof name - 1) != 0)
- return PTY_FD_INVALID;
+ return IDE_PTY_FD_INVALID;
name[sizeof name - 1] = '\0';
#elif defined(__FreeBSD__)
if (fdevname_r (master_fd, name + 5, sizeof name - 6) == NULL)
- return PTY_FD_INVALID;
+ return IDE_PTY_FD_INVALID;
memcpy (name, "/dev/", 5);
name[sizeof name - 1] = '\0';
#else
if (NULL == (name = ptsname (master_fd)))
- return PTY_FD_INVALID;
+ return IDE_PTY_FD_INVALID;
#endif
ret = open (name, O_RDWR | O_CLOEXEC | extra);
- if (ret == PTY_FD_INVALID && errno == EINVAL)
+ if (ret == IDE_PTY_FD_INVALID && errno == EINVAL)
{
gint flags;
ret = open (name, O_RDWR | O_CLOEXEC);
- if (ret == PTY_FD_INVALID && errno == EINVAL)
+ if (ret == IDE_PTY_FD_INVALID && errno == EINVAL)
ret = open (name, O_RDWR);
- if (ret == PTY_FD_INVALID)
- return PTY_FD_INVALID;
+ if (ret == IDE_PTY_FD_INVALID)
+ return IDE_PTY_FD_INVALID;
/* Add FD_CLOEXEC if O_CLOEXEC failed */
flags = fcntl (ret, F_GETFD, 0);
if ((flags & FD_CLOEXEC) == 0)
{
if (fcntl (ret, F_SETFD, flags | FD_CLOEXEC) < 0)
- return PTY_FD_INVALID;
+ return IDE_PTY_FD_INVALID;
}
if (!blocking)
{
if (!g_unix_set_fd_nonblocking (ret, TRUE, NULL))
- return PTY_FD_INVALID;
+ return IDE_PTY_FD_INVALID;
}
}
@@ -160,21 +159,21 @@ pty_intercept_create_slave (pty_fd_t master_fd,
}
/**
- * pty_intercept_create_master:
+ * ide_pty_intercept_create_master:
*
* Creates a new PTY master using posix_openpt(). Some fallbacks are
* provided for non-Linux systems where O_CLOEXEC and O_NONBLOCK may
* not be supported.
*
* Returns: a FD that should be closed with close() if successful.
- * Upon error, %PTY_FD_INVALID (-1) is returned.
+ * Upon error, %IDE_PTY_FD_INVALID (-1) is returned.
*
* Since: 3.32
*/
-pty_fd_t
-pty_intercept_create_master (void)
+IdePtyFd
+ide_pty_intercept_create_master (void)
{
- g_auto(pty_fd_t) master_fd = PTY_FD_INVALID;
+ g_auto(IdePtyFd) master_fd = IDE_PTY_FD_INVALID;
master_fd = posix_openpt (O_RDWR | O_NOCTTY | O_NONBLOCK | O_CLOEXEC);
@@ -182,28 +181,28 @@ pty_intercept_create_master (void)
/* Fallback for operating systems that don't support
* O_NONBLOCK and O_CLOEXEC when opening.
*/
- if (master_fd == PTY_FD_INVALID && errno == EINVAL)
+ if (master_fd == IDE_PTY_FD_INVALID && errno == EINVAL)
{
master_fd = posix_openpt (O_RDWR | O_NOCTTY | O_CLOEXEC);
- if (master_fd == PTY_FD_INVALID && errno == EINVAL)
+ if (master_fd == IDE_PTY_FD_INVALID && errno == EINVAL)
{
gint flags;
master_fd = posix_openpt (O_RDWR | O_NOCTTY);
if (master_fd == -1)
- return PTY_FD_INVALID;
+ return IDE_PTY_FD_INVALID;
flags = fcntl (master_fd, F_GETFD, 0);
if (flags < 0)
- return PTY_FD_INVALID;
+ return IDE_PTY_FD_INVALID;
if (fcntl (master_fd, F_SETFD, flags | FD_CLOEXEC) < 0)
- return PTY_FD_INVALID;
+ return IDE_PTY_FD_INVALID;
}
if (!g_unix_set_fd_nonblocking (master_fd, TRUE, NULL))
- return PTY_FD_INVALID;
+ return IDE_PTY_FD_INVALID;
}
#endif
@@ -220,7 +219,7 @@ clear_source (guint *source_id)
}
static void
-_pty_intercept_side_close (pty_intercept_side_t *side)
+_ide_pty_intercept_side_close (IdePtyInterceptSide *side)
{
g_assert (side != NULL);
@@ -231,12 +230,12 @@ _pty_intercept_side_close (pty_intercept_side_t *side)
}
static gboolean
-_pty_intercept_out_cb (GIOChannel *channel,
- GIOCondition condition,
- gpointer user_data)
+_ide_pty_intercept_out_cb (GIOChannel *channel,
+ GIOCondition condition,
+ gpointer user_data)
{
- pty_intercept_t *self = user_data;
- pty_intercept_side_t *us, *them;
+ IdePtyIntercept *self = user_data;
+ IdePtyInterceptSide *us, *them;
GIOStatus status;
const gchar *wrbuf;
gsize n_written = 0;
@@ -292,21 +291,21 @@ _pty_intercept_out_cb (GIOChannel *channel,
g_io_add_watch_full (them->channel,
them->read_prio,
G_IO_IN | G_IO_ERR | G_IO_HUP,
- _pty_intercept_in_cb,
+ _ide_pty_intercept_in_cb,
self, NULL);
return G_SOURCE_REMOVE;
close_and_cleanup:
- _pty_intercept_side_close (us);
- _pty_intercept_side_close (them);
+ _ide_pty_intercept_side_close (us);
+ _ide_pty_intercept_side_close (them);
return G_SOURCE_REMOVE;
}
/*
- * _pty_intercept_in_cb:
+ * _ide_pty_intercept_in_cb:
*
* This function is called when we have received a condition that specifies
* the channel has data to read. We read that data and then setup a watch
@@ -318,12 +317,12 @@ close_and_cleanup:
* The in watch is disabled until we have completed the write.
*/
static gboolean
-_pty_intercept_in_cb (GIOChannel *channel,
- GIOCondition condition,
- gpointer user_data)
+_ide_pty_intercept_in_cb (GIOChannel *channel,
+ GIOCondition condition,
+ gpointer user_data)
{
- pty_intercept_t *self = user_data;
- pty_intercept_side_t *us, *them;
+ IdePtyIntercept *self = user_data;
+ IdePtyInterceptSide *us, *them;
GIOStatus status = G_IO_STATUS_AGAIN;
gchar buf[4096];
gchar *wrbuf = buf;
@@ -331,7 +330,7 @@ _pty_intercept_in_cb (GIOChannel *channel,
g_assert (channel != NULL);
g_assert (condition & (G_IO_ERR | G_IO_HUP | G_IO_IN));
- g_assert (PTY_IS_INTERCEPT (self));
+ g_assert (IDE_IS_PTY_INTERCEPT (self));
if (channel == self->master.channel)
{
@@ -386,7 +385,7 @@ _pty_intercept_in_cb (GIOChannel *channel,
them->out_watch = g_io_add_watch_full (them->channel,
them->write_prio,
G_IO_OUT | G_IO_ERR | G_IO_HUP,
- _pty_intercept_out_cb,
+ _ide_pty_intercept_out_cb,
self, NULL);
us->in_watch = 0;
@@ -403,14 +402,14 @@ _pty_intercept_in_cb (GIOChannel *channel,
close_and_cleanup:
- _pty_intercept_side_close (us);
- _pty_intercept_side_close (them);
+ _ide_pty_intercept_side_close (us);
+ _ide_pty_intercept_side_close (them);
return G_SOURCE_REMOVE;
}
/**
- * pty_intercept_set_size:
+ * ide_pty_intercept_set_size:
*
* Proxies a winsize across to the inferior. If the PTY is the
* controlling PTY for the process, then SIGWINCH will be signaled
@@ -423,16 +422,16 @@ close_and_cleanup:
* Since: 3.32
*/
gboolean
-pty_intercept_set_size (pty_intercept_t *self,
- guint rows,
- guint columns)
+ide_pty_intercept_set_size (IdePtyIntercept *self,
+ guint rows,
+ guint columns)
{
- g_return_val_if_fail (PTY_IS_INTERCEPT (self), FALSE);
+ g_return_val_if_fail (IDE_IS_PTY_INTERCEPT (self), FALSE);
if (self->master.channel != NULL)
{
- pty_fd_t fd = g_io_channel_unix_get_fd (self->master.channel);
+ IdePtyFd fd = g_io_channel_unix_get_fd (self->master.channel);
struct winsize ws = {0};
ws.ws_col = columns;
@@ -444,13 +443,39 @@ pty_intercept_set_size (pty_intercept_t *self,
return FALSE;
}
+static guint
+_g_io_add_watch_full_with_context (GMainContext *main_context,
+ GIOChannel *channel,
+ gint priority,
+ GIOCondition condition,
+ GIOFunc func,
+ gpointer user_data,
+ GDestroyNotify notify)
+{
+ GSource *source;
+ guint id;
+
+ g_return_val_if_fail (channel != NULL, 0);
+
+ source = g_io_create_watch (channel, condition);
+
+ if (priority != G_PRIORITY_DEFAULT)
+ g_source_set_priority (source, priority);
+ g_source_set_callback (source, (GSourceFunc)func, user_data, notify);
+
+ id = g_source_attach (source, main_context);
+ g_source_unref (source);
+
+ return id;
+}
+
/**
- * pty_intercept_init:
- * @self: a location of memory to store a #pty_intercept_t
+ * ide_pty_intercept_init:
+ * @self: a location of memory to store a #IdePtyIntercept
* @fd: the PTY master fd, possibly from a #VtePty
* @main_context: (nullable): a #GMainContext or %NULL for thread-default
*
- * Creates a enw #pty_intercept_t using the PTY master fd @fd.
+ * Creates a enw #IdePtyIntercept using the PTY master fd @fd.
*
* A new PTY slave is created that will communicate with @fd.
* Additionally, a new PTY master is created that can communicate
@@ -462,33 +487,33 @@ pty_intercept_set_size (pty_intercept_t *self,
* Since: 3.32
*/
gboolean
-pty_intercept_init (pty_intercept_t *self,
- int fd,
- GMainContext *main_context)
+ide_pty_intercept_init (IdePtyIntercept *self,
+ int fd,
+ GMainContext *main_context)
{
- g_auto(pty_fd_t) slave_fd = PTY_FD_INVALID;
- g_auto(pty_fd_t) master_fd = PTY_FD_INVALID;
+ g_auto(IdePtyFd) slave_fd = IDE_PTY_FD_INVALID;
+ g_auto(IdePtyFd) master_fd = IDE_PTY_FD_INVALID;
struct winsize ws;
g_return_val_if_fail (self != NULL, FALSE);
g_return_val_if_fail (fd != -1, FALSE);
memset (self, 0, sizeof *self);
- self->magic = PTY_INTERCEPT_MAGIC;
+ self->magic = IDE_PTY_INTERCEPT_MAGIC;
- slave_fd = pty_intercept_create_slave (fd, FALSE);
- if (slave_fd == PTY_FD_INVALID)
+ slave_fd = ide_pty_intercept_create_slave (fd, FALSE);
+ if (slave_fd == IDE_PTY_FD_INVALID)
return FALSE;
/* Do not perform additional processing on the slave_fd created
* from the master we were provided. Otherwise, it will be happening
* twice instead of just once.
*/
- if (!_pty_intercept_set_raw (slave_fd))
+ if (!_ide_pty_intercept_set_raw (slave_fd))
return FALSE;
- master_fd = pty_intercept_create_master ();
- if (master_fd == PTY_FD_INVALID)
+ master_fd = ide_pty_intercept_create_master ();
+ if (master_fd == IDE_PTY_FD_INVALID)
return FALSE;
/* Copy the win size across */
@@ -516,28 +541,30 @@ pty_intercept_init (pty_intercept_t *self,
g_io_channel_set_buffer_size (self->slave.channel, CHANNEL_BUFFER_SIZE);
self->master.in_watch =
- g_io_add_watch_full (self->master.channel,
- self->master.read_prio,
- G_IO_IN | G_IO_ERR | G_IO_HUP,
- _pty_intercept_in_cb,
- self, NULL);
+ _g_io_add_watch_full_with_context (main_context,
+ self->master.channel,
+ self->master.read_prio,
+ G_IO_IN | G_IO_ERR | G_IO_HUP,
+ _ide_pty_intercept_in_cb,
+ self, NULL);
self->slave.in_watch =
- g_io_add_watch_full (self->slave.channel,
- self->slave.read_prio,
- G_IO_IN | G_IO_ERR | G_IO_HUP,
- _pty_intercept_in_cb,
- self, NULL);
+ _g_io_add_watch_full_with_context (main_context,
+ self->slave.channel,
+ self->slave.read_prio,
+ G_IO_IN | G_IO_ERR | G_IO_HUP,
+ _ide_pty_intercept_in_cb,
+ self, NULL);
return TRUE;
}
/**
- * pty_intercept_clear:
- * @self: a #pty_intercept_t
+ * ide_pty_intercept_clear:
+ * @self: a #IdePtyIntercept
*
- * Cleans up a #pty_intercept_t previously initialized with
- * pty_intercept_init().
+ * Cleans up a #IdePtyIntercept previously initialized with
+ * ide_pty_intercept_init().
*
* This diconnects any #GIOChannel that have been attached and
* releases any allocated memory.
@@ -547,9 +574,9 @@ pty_intercept_init (pty_intercept_t *self,
* Since: 3.32
*/
void
-pty_intercept_clear (pty_intercept_t *self)
+ide_pty_intercept_clear (IdePtyIntercept *self)
{
- g_return_if_fail (PTY_IS_INTERCEPT (self));
+ g_return_if_fail (IDE_IS_PTY_INTERCEPT (self));
clear_source (&self->slave.in_watch);
clear_source (&self->slave.out_watch);
@@ -565,30 +592,30 @@ pty_intercept_clear (pty_intercept_t *self)
}
/**
- * pty_intercept_get_fd:
- * @self: a #pty_intercept_t
+ * ide_pty_intercept_get_fd:
+ * @self: a #IdePtyIntercept
*
- * Gets a master PTY fd created by the #pty_intercept_t. This is suitable
+ * Gets a master PTY fd created by the #IdePtyIntercept. This is suitable
* to use to create a slave fd which can be passed to a child process.
*
* Returns: A FD of a PTY master if successful, otherwise -1.
*
* Since: 3.32
*/
-pty_fd_t
-pty_intercept_get_fd (pty_intercept_t *self)
+IdePtyFd
+ide_pty_intercept_get_fd (IdePtyIntercept *self)
{
- g_return_val_if_fail (PTY_IS_INTERCEPT (self), PTY_FD_INVALID);
- g_return_val_if_fail (self->master.channel != NULL, PTY_FD_INVALID);
+ g_return_val_if_fail (IDE_IS_PTY_INTERCEPT (self), IDE_PTY_FD_INVALID);
+ g_return_val_if_fail (self->master.channel != NULL, IDE_PTY_FD_INVALID);
return g_io_channel_unix_get_fd (self->master.channel);
}
/**
- * pty_intercept_set_callback:
- * @self: a pty_intercept_t
+ * ide_pty_intercept_set_callback:
+ * @self: a IdePtyIntercept
* @side: the side containing the data to watch
- * @callback: the callback to execute when data is received
+ * @callback: (scope notified): the callback to execute when data is received
* @user_data: closure data for @callback
*
* This sets the callback to execute every time data is received
@@ -599,12 +626,12 @@ pty_intercept_get_fd (pty_intercept_t *self)
* Since: 3.32
*/
void
-pty_intercept_set_callback (pty_intercept_t *self,
- pty_intercept_side_t *side,
- pty_intercept_callback_t callback,
- gpointer callback_data)
+ide_pty_intercept_set_callback (IdePtyIntercept *self,
+ IdePtyInterceptSide *side,
+ IdePtyInterceptCallback callback,
+ gpointer callback_data)
{
- g_return_if_fail (PTY_IS_INTERCEPT (self));
+ g_return_if_fail (IDE_IS_PTY_INTERCEPT (self));
g_return_if_fail (side == &self->master || side == &self->slave);
side->callback = callback;
diff --git a/src/libide/io/ide-pty-intercept.h b/src/libide/io/ide-pty-intercept.h
new file mode 100644
index 000000000..9d0c68bdd
--- /dev/null
+++ b/src/libide/io/ide-pty-intercept.h
@@ -0,0 +1,108 @@
+/* ide-pty-intercept.h
+ *
+ * Copyright 2018-2019 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/>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#pragma once
+
+#if !defined (IDE_IO_INSIDE) && !defined (IDE_IO_COMPILATION)
+# error "Only <libide-io.h> can be included directly."
+#endif
+
+#include <libide-core.h>
+#include <unistd.h>
+
+G_BEGIN_DECLS
+
+#define IDE_PTY_FD_INVALID (-1)
+#define IDE_PTY_INTERCEPT_MAGIC (0x81723647)
+#define IDE_IS_PTY_INTERCEPT(s) ((s) != NULL && (s)->magic == IDE_PTY_INTERCEPT_MAGIC)
+
+typedef int IdePtyFd;
+typedef struct _IdePtyIntercept IdePtyIntercept;
+typedef struct _IdePtyInterceptSide IdePtyInterceptSide;
+typedef void (*IdePtyInterceptCallback) (const IdePtyIntercept *intercept,
+ const IdePtyInterceptSide *side,
+ const guint8 *data,
+ gsize len,
+ gpointer user_data);
+
+struct _IdePtyInterceptSide
+{
+ GIOChannel *channel;
+ guint in_watch;
+ guint out_watch;
+ gint read_prio;
+ gint write_prio;
+ GBytes *out_bytes;
+ IdePtyInterceptCallback callback;
+ gpointer callback_data;
+};
+
+struct _IdePtyIntercept
+{
+ gsize magic;
+ IdePtyInterceptSide master;
+ IdePtyInterceptSide slave;
+};
+
+static inline IdePtyFd
+pty_fd_steal (IdePtyFd *fd)
+{
+ IdePtyFd ret = *fd;
+ *fd = -1;
+ return ret;
+}
+
+static void
+pty_fd_clear (IdePtyFd *fd)
+{
+ if (fd != NULL && *fd != -1)
+ {
+ int rfd = *fd;
+ *fd = -1;
+ close (rfd);
+ }
+}
+
+G_DEFINE_AUTO_CLEANUP_CLEAR_FUNC (IdePtyFd, pty_fd_clear)
+
+IDE_AVAILABLE_IN_3_32
+IdePtyFd ide_pty_intercept_create_master (void);
+IDE_AVAILABLE_IN_3_32
+IdePtyFd ide_pty_intercept_create_slave (IdePtyFd master_fd,
+ gboolean blocking);
+IDE_AVAILABLE_IN_3_32
+gboolean ide_pty_intercept_init (IdePtyIntercept *self,
+ IdePtyFd fd,
+ GMainContext *main_context);
+IDE_AVAILABLE_IN_3_32
+IdePtyFd ide_pty_intercept_get_fd (IdePtyIntercept *self);
+IDE_AVAILABLE_IN_3_32
+gboolean ide_pty_intercept_set_size (IdePtyIntercept *self,
+ guint rows,
+ guint columns);
+IDE_AVAILABLE_IN_3_32
+void ide_pty_intercept_clear (IdePtyIntercept *self);
+IDE_AVAILABLE_IN_3_32
+void ide_pty_intercept_set_callback (IdePtyIntercept *self,
+ IdePtyInterceptSide *side,
+ IdePtyInterceptCallback callback,
+ gpointer user_data);
+
+G_END_DECLS
diff --git a/src/libide/io/libide-io.h b/src/libide/io/libide-io.h
new file mode 100644
index 000000000..dce1b643e
--- /dev/null
+++ b/src/libide/io/libide-io.h
@@ -0,0 +1,42 @@
+/* ide-io.h
+ *
+ * Copyright 2018-2019 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/>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#pragma once
+
+#include <libide-core.h>
+#include <libide-threading.h>
+
+G_BEGIN_DECLS
+
+#define IDE_IO_INSIDE
+
+#include "ide-content-type.h"
+#include "ide-gfile.h"
+#include "ide-line-reader.h"
+#include "ide-marked-content.h"
+#include "ide-path.h"
+#include "ide-persistent-map-builder.h"
+#include "ide-persistent-map.h"
+#include "ide-pkcon-transfer.h"
+#include "ide-pty-intercept.h"
+
+#undef IDE_IO_INSIDE
+
+G_END_DECLS
diff --git a/src/libide/io/meson.build b/src/libide/io/meson.build
new file mode 100644
index 000000000..42ffb4b1d
--- /dev/null
+++ b/src/libide/io/meson.build
@@ -0,0 +1,69 @@
+libide_io_header_subdir = join_paths(libide_header_subdir, 'io')
+libide_include_directories += include_directories('.')
+
+#
+# Public API Headers
+#
+
+libide_io_public_headers = [
+ 'ide-content-type.h',
+ 'ide-gfile.h',
+ 'ide-line-reader.h',
+ 'ide-marked-content.h',
+ 'ide-path.h',
+ 'ide-persistent-map.h',
+ 'ide-persistent-map-builder.h',
+ 'ide-pkcon-transfer.h',
+ 'ide-pty-intercept.h',
+ 'libide-io.h',
+]
+
+install_headers(libide_io_public_headers, subdir: libide_io_header_subdir)
+
+#
+# Sources
+#
+
+libide_io_public_sources = [
+ 'ide-content-type.c',
+ 'ide-gfile.c',
+ 'ide-line-reader.c',
+ 'ide-marked-content.c',
+ 'ide-path.c',
+ 'ide-persistent-map.c',
+ 'ide-persistent-map-builder.c',
+ 'ide-pkcon-transfer.c',
+ 'ide-pty-intercept.c',
+]
+
+libide_io_sources = libide_io_public_sources
+
+#
+# Dependencies
+#
+
+libide_io_deps = [
+ libgio_dep,
+ libide_core_dep,
+ libide_threading_dep
+]
+
+#
+# Library Definitions
+#
+
+libide_io = static_library('ide-io-' + libide_api_version, libide_io_sources,
+ dependencies: libide_io_deps,
+ c_args: libide_args + release_args + ['-DIDE_IO_COMPILATION'],
+)
+
+libide_io_dep = declare_dependency(
+ dependencies: [ libgio_dep, libide_core_dep, libide_threading_dep ],
+ link_whole: libide_io,
+ include_directories: include_directories('.'),
+)
+
+gnome_builder_public_sources += files(libide_io_public_sources)
+gnome_builder_public_headers += files(libide_io_public_headers)
+gnome_builder_include_subdirs += libide_io_header_subdir
+gnome_builder_gir_extra_args += ['--c-include=libide-io.h', '-DIDE_IO_COMPILATION']
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]