[gnome-text-editor] app: allow opening local and remote stdin streams



commit 9e99ceff8b7c0c16a9bea02ebe89830b89cf55f0
Author: Christian Hergert <chergert redhat com>
Date:   Thu May 12 13:37:55 2022 -0700

    app: allow opening local and remote stdin streams
    
    This allows you to open a file using stdin with the standard - as the
    filename. If an existing gnome-text-editor process is running, that
    instance will be used to open the stdin stream.
    
    Fixes #368

 src/editor-application.c | 64 +++++++++++++++++++++++++++++++++++++++++--
 src/editor-session.c     | 71 ++++++++++++++++++++++++++++++++++++++++++++++++
 src/editor-session.h     |  3 ++
 3 files changed, 136 insertions(+), 2 deletions(-)
---
diff --git a/src/editor-application.c b/src/editor-application.c
index ae5e196..5d0131a 100644
--- a/src/editor-application.c
+++ b/src/editor-application.c
@@ -405,6 +405,25 @@ editor_application_startup (GApplication *application)
   gtk_window_set_default_icon_name (PACKAGE_ICON_NAME);
 }
 
+static gboolean
+load_stdin_stream_cb (gpointer user_data)
+{
+  EditorApplication *self = EDITOR_APPLICATION_DEFAULT;
+  EditorSession *session;
+  EditorWindow *window;
+  GInputStream *stream = user_data;
+
+  g_assert (EDITOR_IS_APPLICATION (self));
+  g_assert (G_IS_INPUT_STREAM (stream));
+
+  window = editor_application_get_current_window (self);
+  session = editor_application_get_session (self);
+  editor_session_open_stream (session, window, stream);
+  g_application_release (G_APPLICATION (self));
+
+  return G_SOURCE_REMOVE;
+}
+
 static int
 editor_application_command_line (GApplication            *app,
                                  GApplicationCommandLine *command_line)
@@ -412,6 +431,7 @@ editor_application_command_line (GApplication            *app,
   EditorApplication *self = (EditorApplication *)app;
   g_auto(GStrv) argv = NULL;
   g_autoptr(GPtrArray) files = NULL;
+  g_autoptr(GInputStream) stdin_stream = NULL;
   GVariantDict *options;
   gboolean new_window = FALSE;
   const char *hint = NULL;
@@ -430,8 +450,28 @@ editor_application_command_line (GApplication            *app,
   files = g_ptr_array_new_with_free_func (g_object_unref);
 
   for (int i = 1; i < argc; i++)
-    g_ptr_array_add (files,
-                     g_application_command_line_create_file_for_arg (command_line, argv[i]));
+    {
+      /* We want to read stdin into temporary file if we get '-' */
+      if (g_strcmp0 (argv[i], "-") == 0)
+        {
+          if (stdin_stream != NULL)
+            g_application_command_line_printerr (command_line,
+                                                 "%s\n",
+                                                 _("Standard input was requested multiple times. Ignoring 
request."));
+          else if (!(stdin_stream = g_application_command_line_get_stdin (command_line)))
+            g_application_command_line_printerr (command_line,
+                                                 "%s\n",
+                                                 _("Standard input is not supported on this platform. 
Ignoring request."));
+          continue;
+        }
+
+      /* Otherwise add the file to the list of files we need to open, taking
+       * into account the other directory a remote instance could be running
+       * from.
+       */
+      g_ptr_array_add (files,
+                       g_application_command_line_create_file_for_arg (command_line, argv[i]));
+    }
 
   /* Only accept --new-window if this is a remote instance, we already
    * create a window if we're in the same process.
@@ -449,6 +489,26 @@ editor_application_command_line (GApplication            *app,
   else
     g_application_activate (app);
 
+  /* We've activated but there is a strong chance that our state has not yet
+   * been restored because that requires reading from disk. Give a bit of a
+   * delay before we process the intput stream for our initial windows to be
+   * created and state restored.
+   *
+   * This is basically a hack, but to do anything else would require more state
+   * tracking in the session manager which is particularly difficult as the
+   * stdin could be coming from another process which has been passed to us
+   * over D-Bus.
+   */
+  if (stdin_stream != NULL)
+    {
+      g_application_hold (G_APPLICATION (self));
+      g_timeout_add_full (G_PRIORITY_DEFAULT,
+                          500 /* msec */,
+                          load_stdin_stream_cb,
+                          g_steal_pointer (&stdin_stream),
+                          g_object_unref);
+    }
+
   return EXIT_SUCCESS;
 }
 
diff --git a/src/editor-session.c b/src/editor-session.c
index 44d3bf2..e0cc706 100644
--- a/src/editor-session.c
+++ b/src/editor-session.c
@@ -2444,3 +2444,74 @@ _editor_session_clear_history (EditorSession *self)
         _editor_sidebar_model_remove_draft (self->recents, draft_id);
     }
 }
+
+static void
+editor_session_load_stream_cb (GObject      *object,
+                               GAsyncResult *result,
+                               gpointer      user_data)
+{
+  GtkSourceFileLoader *loader = (GtkSourceFileLoader *)object;
+  g_autoptr(EditorDocument) document = user_data;
+  g_autoptr(GError) error = NULL;
+
+  g_assert (GTK_SOURCE_IS_FILE_LOADER (loader));
+  g_assert (G_IS_ASYNC_RESULT (result));
+  g_assert (EDITOR_IS_DOCUMENT (document));
+
+  if (!gtk_source_file_loader_load_finish (loader, result, &error))
+    g_warning ("Failed to read input stream: %s", error->message);
+
+  gtk_text_buffer_set_modified (GTK_TEXT_BUFFER (document), TRUE);
+}
+
+static void
+load_stream_into_document (GInputStream   *stream,
+                           EditorDocument *document)
+{
+  g_autoptr(GtkSourceFileLoader) loader = NULL;
+  g_autoptr(GtkSourceFile) file = NULL;
+
+  g_assert (G_IS_INPUT_STREAM (stream));
+  g_assert (EDITOR_IS_DOCUMENT (document));
+
+  file = gtk_source_file_new ();
+  loader = gtk_source_file_loader_new_from_stream (GTK_SOURCE_BUFFER (document), file, stream);
+  gtk_source_file_loader_load_async (loader,
+                                     G_PRIORITY_DEFAULT,
+                                     NULL,
+                                     NULL, NULL, NULL,
+                                     editor_session_load_stream_cb,
+                                     g_object_ref (document));
+}
+
+void
+editor_session_open_stream (EditorSession *session,
+                            EditorWindow  *window,
+                            GInputStream  *stream)
+{
+  g_autoptr(EditorDocument) new_document = NULL;
+  EditorPage *old_page;
+  EditorPage *new_page;
+
+  g_return_if_fail (EDITOR_IS_SESSION (session));
+  g_return_if_fail (!window || EDITOR_IS_WINDOW (window));
+  g_return_if_fail (G_IS_INPUT_STREAM (stream));
+
+  if (window == NULL)
+    window = find_or_create_window (session);
+
+  /* If the window has a single empty page within it, just close that
+   * page and let our new page replace it.
+   */
+  if (editor_window_get_n_pages (window) == 1 &&
+      (old_page = editor_window_get_nth_page (window, 0)) &&
+      editor_page_get_can_discard (old_page))
+    _editor_window_remove_page (window, old_page);
+
+  new_document = editor_document_new_draft ();
+  new_page = editor_session_add_document (session, window, new_document);
+
+  load_stream_into_document (stream, new_document);
+  _editor_page_raise (new_page);
+  _editor_session_mark_dirty (session);
+}
diff --git a/src/editor-session.h b/src/editor-session.h
index 719f51f..e1a14b9 100644
--- a/src/editor-session.h
+++ b/src/editor-session.h
@@ -38,6 +38,9 @@ EditorPage   *editor_session_open                (EditorSession            *self
                                                   EditorWindow             *window,
                                                   GFile                    *file,
                                                   const GtkSourceEncoding  *encoding);
+void          editor_session_open_stream         (EditorSession            *session,
+                                                  EditorWindow             *window,
+                                                  GInputStream             *stream);
 void          editor_session_open_files          (EditorSession            *self,
                                                   GFile                   **files,
                                                   gint                      n_files,


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]