[gedit/dbus: 3/5] Implement loading document from stdin
- From: Jesse van den Kieboom <jessevdk src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gedit/dbus: 3/5] Implement loading document from stdin
- Date: Wed, 5 May 2010 21:24:08 +0000 (UTC)
commit 8ecf21b3454b99751e8c5dd6401b962accc46f69
Author: Jesse van den Kieboom <jesse vandenkieboom epfl ch>
Date: Wed May 5 23:21:28 2010 +0200
Implement loading document from stdin
gedit/Makefile.am | 5 +
gedit/gedit-dbus.c | 605 +++++++++++++++++++++++++++++++++++++++--
gedit/gedit-document-loader.c | 18 ++
gedit/gedit-fifo.c | 347 +++++++++++++++++++++++
gedit/gedit-fifo.h | 58 ++++
gedit/gedit-utils.c | 15 +
gedit/gedit-utils.h | 2 +
gedit/gedit.c | 23 +-
8 files changed, 1029 insertions(+), 44 deletions(-)
---
diff --git a/gedit/Makefile.am b/gedit/Makefile.am
index 838e03e..bfc9693 100644
--- a/gedit/Makefile.am
+++ b/gedit/Makefile.am
@@ -216,6 +216,11 @@ if !ENABLE_GVFS_METADATA
libgedit_la_SOURCES += gedit-metadata-manager.c
endif
+if !PLATFORM_WIN32
+libgedit_la_SOURCES += gedit-fifo.c
+NOINST_H_FILES += gedit-fifo.h
+endif
+
gedit-enum-types.h: gedit-enum-types.h.template $(INST_H_FILES) $(GLIB_MKENUMS)
$(AM_V_GEN) (cd $(srcdir) && $(GLIB_MKENUMS) --template gedit-enum-types.h.template $(INST_H_FILES)) > $@
diff --git a/gedit/gedit-dbus.c b/gedit/gedit-dbus.c
index 3b63391..6e0d8e4 100644
--- a/gedit/gedit-dbus.c
+++ b/gedit/gedit-dbus.c
@@ -35,6 +35,13 @@
#include <gdk/gdkx.h>
#endif
+#ifdef G_OS_UNIX
+#include <gio/gunixinputstream.h>
+#include <gio/gunixconnection.h>
+#include <unistd.h>
+#include "gedit-fifo.h"
+#endif
+
typedef struct _WaitData WaitData;
typedef void (*WaitHandlerFunc)(GObject *object, WaitData *data);
@@ -51,6 +58,19 @@ struct _WaitData
#define GEDIT_DBUS_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE((object), GEDIT_TYPE_DBUS, GeditDBusPrivate))
+typedef struct
+{
+ GeditDBus *dbus;
+ GCancellable *cancellable;
+
+ GeditWindow *window;
+ const GeditEncoding *encoding;
+ gint line_position;
+ gint column_position;
+ gboolean jump_to;
+ WaitData *wait_data;
+} AsyncData;
+
struct _GeditDBusPrivate
{
GeditDBusResult result;
@@ -58,13 +78,79 @@ struct _GeditDBusPrivate
guint wait_id;
guint next_wait_id;
+
+ GeditFifo *stdin_fifo;
+ GInputStream *stdin_in_stream;
+ GOutputStream *stdin_out_stream;
+ GCancellable *stdin_cancellable;
};
G_DEFINE_TYPE (GeditDBus, gedit_dbus, G_TYPE_OBJECT)
static void
+async_window_destroyed (AsyncData *async,
+ GObject *where_the_object_was)
+{
+ g_cancellable_cancel (async->cancellable);
+ async->window = NULL;
+}
+
+static void
+async_data_free (AsyncData *async)
+{
+ g_object_unref (async->cancellable);
+
+ if (async->window)
+ {
+ g_object_weak_unref (G_OBJECT (async->window),
+ (GWeakNotify)async_window_destroyed,
+ async);
+ }
+
+ g_slice_free (AsyncData, async);
+}
+
+static AsyncData *
+async_data_new (GeditDBus *dbus)
+{
+ AsyncData *async;
+
+ async = g_slice_new0 (AsyncData);
+
+ async->dbus = dbus;
+ async->cancellable = g_cancellable_new ();
+
+ dbus->priv->stdin_cancellable = g_object_ref (async->cancellable);
+
+ return async;
+}
+
+static void
gedit_dbus_finalize (GObject *object)
{
+ GeditDBus *dbus = GEDIT_DBUS (object);
+
+ if (dbus->priv->stdin_cancellable)
+ {
+ g_cancellable_cancel (dbus->priv->stdin_cancellable);
+ g_object_unref (dbus->priv->stdin_cancellable);
+ }
+
+ if (dbus->priv->stdin_fifo)
+ {
+ g_object_unref (dbus->priv->stdin_fifo);
+ }
+
+ if (dbus->priv->stdin_out_stream)
+ {
+ g_object_unref (dbus->priv->stdin_out_stream);
+ }
+
+ if (dbus->priv->stdin_in_stream)
+ {
+ g_object_unref (dbus->priv->stdin_in_stream);
+ }
+
G_OBJECT_CLASS (gedit_dbus_parent_class)->finalize (object);
}
@@ -197,7 +283,7 @@ get_display_arguments (GeditDBus *dbus,
}
static GVariant *
-compose_open_parameters (GeditDBus *dbus, GeditCommandLine *command_line)
+compose_open_parameters (GeditDBus *dbus)
{
GVariantBuilder file_list;
GSList *files;
@@ -208,6 +294,10 @@ compose_open_parameters (GeditDBus *dbus, GeditCommandLine *command_line)
gint viewport_x;
gint viewport_y;
GVariant *ret;
+ GeditCommandLine *command_line;
+ gchar *stdin_path;
+
+ command_line = gedit_command_line_get_default ();
g_variant_builder_init (&file_list, G_VARIANT_TYPE ("as"));
@@ -228,7 +318,18 @@ compose_open_parameters (GeditDBus *dbus, GeditCommandLine *command_line)
&viewport_x,
&viewport_y);
- ret = g_variant_new ("(assiibbbusiiii)",
+ if (dbus->priv->stdin_fifo)
+ {
+ GFile *file = gedit_fifo_get_file (dbus->priv->stdin_fifo);
+ stdin_path = g_file_get_path (file);
+ g_object_unref (file);
+ }
+ else
+ {
+ stdin_path = g_strdup ("");
+ }
+
+ ret = g_variant_new ("(assiibbbusiiiis)",
&file_list,
encoding ? gedit_encoding_get_charset (encoding) : "",
gedit_command_line_get_line_position (command_line),
@@ -241,23 +342,29 @@ compose_open_parameters (GeditDBus *dbus, GeditCommandLine *command_line)
screen_number,
workspace,
viewport_x,
- viewport_y);
+ viewport_y,
+ stdin_path);
+ g_free (stdin_path);
return ret;
}
static void
-slave_open_ready_cb (GDBusProxy *proxy,
- GAsyncResult *result,
- GeditDBus *dbus)
+slave_open_ready_cb (GDBusConnection *connection,
+ GAsyncResult *result,
+ GeditDBus *dbus)
{
- GVariant *ret;
+ GDBusMessage *ret;
GError *error = NULL;
GeditCommandLine *command_line;
- ret = g_dbus_proxy_invoke_method_finish (proxy, result, &error);
+ ret = g_dbus_connection_send_message_with_reply_finish (connection,
+ result,
+ &error);
command_line = gedit_command_line_get_default ();
+ /* TODO: start proxying stdin if needed */
+
if (ret == NULL)
{
g_warning ("Failed to call gedit service: %s", error->message);
@@ -268,7 +375,10 @@ slave_open_ready_cb (GDBusProxy *proxy,
}
else
{
- g_variant_get (ret, "(u)", &dbus->priv->wait_id);
+ g_variant_get (g_dbus_message_get_body (ret),
+ "(u)",
+ &dbus->priv->wait_id);
+
dbus->priv->result = GEDIT_DBUS_RESULT_SUCCESS;
if (!gedit_command_line_get_wait (command_line))
@@ -298,6 +408,153 @@ on_open_proxy_signal (GDBusProxy *proxy,
}
}
+#ifdef G_OS_UNIX
+static void
+stdin_write_finish (GOutputStream *stream,
+ GAsyncResult *result,
+ AsyncData *async)
+{
+ GError *error = NULL;
+ gssize written;
+ GeditDBusPrivate *priv;
+
+ if (g_cancellable_is_cancelled (async->cancellable))
+ {
+ async_data_free (async);
+ return;
+ }
+
+ written = g_output_stream_splice_finish (stream, result, &error);
+ priv = async->dbus->priv;
+
+ g_object_unref (priv->stdin_out_stream);
+ g_object_unref (priv->stdin_in_stream);
+
+ priv->stdin_out_stream = NULL;
+ priv->stdin_in_stream = NULL;
+
+ if (written == -1)
+ {
+ g_warning ("Failed to write stdin: %s", error->message);
+ g_error_free (error);
+ }
+
+ async_data_free (async);
+
+ g_object_unref (priv->stdin_fifo);
+ priv->stdin_fifo = NULL;
+
+ g_object_unref (priv->stdin_cancellable);
+ priv->stdin_cancellable = NULL;
+}
+
+static void
+stdin_pipe_ready_to_write (GeditFifo *fifo,
+ GAsyncResult *result,
+ AsyncData *async)
+{
+ GeditDBusPrivate *priv;
+ GOutputStream *stream;
+ GError *error = NULL;
+
+ if (g_cancellable_is_cancelled (async->cancellable))
+ {
+ async_data_free (async);
+ return;
+ }
+
+ stream = gedit_fifo_open_write_finish (fifo, result, &error);
+
+ if (stream == NULL)
+ {
+ g_warning ("Could not open fifo for writing: %s", error->message);
+ g_error_free (error);
+
+ /* Can't do that then */
+ async_data_free (async);
+ return;
+ }
+
+ priv = async->dbus->priv;
+
+ priv->stdin_out_stream = stream;
+ priv->stdin_in_stream = g_unix_input_stream_new (STDIN_FILENO, TRUE);
+
+ g_output_stream_splice_async (priv->stdin_out_stream,
+ priv->stdin_in_stream,
+ G_OUTPUT_STREAM_SPLICE_CLOSE_SOURCE |
+ G_OUTPUT_STREAM_SPLICE_CLOSE_TARGET,
+ G_PRIORITY_DEFAULT,
+ async->cancellable,
+ (GAsyncReadyCallback)stdin_write_finish,
+ async);
+}
+
+static void
+open_command_add_stdin_pipe (GeditDBus *dbus)
+{
+ AsyncData *async;
+
+ dbus->priv->stdin_fifo = gedit_fifo_new (NULL);
+
+ if (!dbus->priv->stdin_fifo)
+ {
+ g_warning ("Failed to create fifo for standard in");
+ return;
+ }
+
+ async = async_data_new (dbus);
+
+ gedit_fifo_open_write_async (dbus->priv->stdin_fifo,
+ G_PRIORITY_DEFAULT,
+ async->cancellable,
+ (GAsyncReadyCallback)stdin_pipe_ready_to_write,
+ async);
+}
+#endif
+
+static void
+open_command_add_stdin (GeditDBus *dbus,
+ GDBusConnection *connection,
+ GDBusMessage *message)
+{
+#ifdef G_OS_UNIX
+ GUnixFDList *fdlist;
+ GError *error = NULL;
+ gint ret;
+
+ if (!gedit_utils_can_read_from_stdin ())
+ {
+ return;
+ }
+
+ if (!(g_dbus_connection_get_capabilities (connection) &
+ G_DBUS_CAPABILITY_FLAGS_UNIX_FD_PASSING))
+ {
+ /* Fallback with named pipe */
+ open_command_add_stdin_pipe (dbus);
+ return;
+ }
+
+ fdlist = g_unix_fd_list_new ();
+ ret = g_unix_fd_list_append (fdlist, STDIN_FILENO, &error);
+
+ if (ret == -1)
+ {
+ g_warning ("Could not read from standard in: %s", error->message);
+ g_error_free (error);
+ }
+ else
+ {
+ /* Here we can close STDIN because it's dupped */
+ close (STDIN_FILENO);
+ }
+
+ g_dbus_message_set_unix_fd_list (message, fdlist);
+ g_object_unref (fdlist);
+#endif
+}
+
static void
command_line_proxy_appeared (GDBusConnection *connection,
const gchar *name,
@@ -306,6 +563,7 @@ command_line_proxy_appeared (GDBusConnection *connection,
GeditDBus *dbus)
{
GeditCommandLine *command_line;
+ GDBusMessage *message;
command_line = gedit_command_line_get_default ();
@@ -317,14 +575,23 @@ command_line_proxy_appeared (GDBusConnection *connection,
dbus);
}
- g_dbus_proxy_invoke_method (proxy,
- "Open",
- compose_open_parameters (dbus, command_line),
- G_DBUS_INVOKE_METHOD_FLAGS_NONE,
- -1,
- NULL,
- (GAsyncReadyCallback)slave_open_ready_cb,
- dbus);
+ message = g_dbus_message_new_method_call (g_dbus_proxy_get_unique_bus_name (proxy),
+ "/org/gnome/gedit",
+ "org.gnome.gedit.CommandLine",
+ "Open");
+
+ open_command_add_stdin (dbus, connection, message);
+ g_dbus_message_set_body (message, compose_open_parameters (dbus));
+
+ g_dbus_connection_send_message_with_reply (g_dbus_proxy_get_connection (proxy),
+ message,
+ -1,
+ NULL,
+ NULL,
+ (GAsyncReadyCallback)slave_open_ready_cb,
+ dbus);
+
+ g_object_unref (message);
}
static void
@@ -632,6 +899,233 @@ install_wait_handler (GeditDBus *dbus,
g_object_weak_ref (object, (GWeakNotify)unref_wait_handler, data);
}
+#ifdef G_OS_UNIX
+static GeditTab *
+tab_from_stream (GeditWindow *window,
+ GInputStream *stream,
+ const GeditEncoding *encoding,
+ gint line_position,
+ gint column_position,
+ gboolean jump_to)
+{
+ GList *documents;
+ GeditDocument *doc = NULL;
+ GeditTab *tab = NULL;
+
+ documents = gedit_window_get_documents (window);
+
+ if (documents)
+ {
+ doc = GEDIT_DOCUMENT (documents->data);
+ tab = gedit_tab_get_from_document (doc);
+ }
+
+ if (documents && !documents->next &&
+ gedit_document_is_untouched (doc) &&
+ gedit_tab_get_state (tab) == GEDIT_TAB_STATE_NORMAL)
+ {
+ /* open right in that document */
+ GeditDocument *doc = GEDIT_DOCUMENT (documents->data);
+
+ tab = gedit_tab_get_from_document (doc);
+
+ _gedit_tab_load_stream (tab,
+ stream,
+ encoding,
+ line_position,
+ column_position);
+ }
+ else
+ {
+ tab = gedit_window_create_tab_from_stream (window,
+ stream,
+ encoding,
+ line_position,
+ column_position,
+ jump_to);
+ }
+
+ g_list_free (documents);
+ return tab;
+}
+#endif
+
+static GSList *
+create_tabs_for_fds (GeditDBus *dbus,
+ GDBusMethodInvocation *invocation,
+ GeditWindow *window,
+ const GeditEncoding *encoding,
+ gint line_position,
+ gint column_position,
+ gboolean jump_to)
+{
+#ifdef G_OS_UNIX
+ GDBusMessage *message;
+ GDBusConnection *connection;
+ GUnixFDList *fdlist;
+ GSList *ret = NULL;
+ gint num;
+ gint i;
+
+ connection = g_dbus_method_invocation_get_connection (invocation);
+
+ if (!(g_dbus_connection_get_capabilities (connection) &
+ G_DBUS_CAPABILITY_FLAGS_UNIX_FD_PASSING))
+ {
+ return NULL;
+ }
+
+ message = g_dbus_method_invocation_get_message (invocation);
+ fdlist = g_dbus_message_get_unix_fd_list (message);
+
+ if (!fdlist)
+ {
+ return NULL;
+ }
+
+ num = g_unix_fd_list_get_length (fdlist);
+
+ for (i = 0; i < num; ++i)
+ {
+ gint fd;
+ GError *error = NULL;
+
+ fd = g_unix_fd_list_get (fdlist, i, &error);
+
+ if (fd == -1)
+ {
+ g_warning ("Could not open stream for service: %s", error->message);
+ g_error_free (error);
+ error = NULL;
+ }
+ else
+ {
+ GeditTab *tab;
+ GInputStream *stream;
+
+ /* fd is dupped, so we close it when the stream closes */
+ stream = g_unix_input_stream_new (fd, TRUE);
+
+ tab = tab_from_stream (window,
+ stream,
+ encoding,
+ line_position,
+ column_position,
+ jump_to);
+
+ g_object_unref (stream);
+
+ if (tab)
+ {
+ ret = g_slist_prepend (ret, tab);
+ jump_to = FALSE;
+ }
+ }
+ }
+
+ return g_slist_reverse (ret);
+#else
+ return NULL;
+#endif
+}
+
+#ifdef G_OS_UNIX
+static void
+stdin_pipe_ready_to_read (GeditFifo *fifo,
+ GAsyncResult *result,
+ AsyncData *async)
+{
+ GInputStream *stream;
+ GError *error = NULL;
+ GeditTab *tab;
+
+ if (g_cancellable_is_cancelled (async->cancellable))
+ {
+ async_data_free (async);
+ return;
+ }
+
+ stream = gedit_fifo_open_read_finish (fifo, result, &error);
+
+ if (!stream)
+ {
+ g_warning ("Opening stdin pipe error: %s", error->message);
+
+ g_error_free (error);
+
+ g_object_unref (async->dbus->priv->stdin_cancellable);
+ async->dbus->priv->stdin_cancellable = NULL;
+
+ g_object_unref (fifo);
+ async->dbus->priv->stdin_fifo = NULL;
+
+ async_data_free (async);
+ return;
+ }
+
+ tab = tab_from_stream (async->window,
+ stream,
+ async->encoding,
+ async->line_position,
+ async->column_position,
+ async->jump_to);
+
+ g_object_unref (stream);
+
+ if (async->wait_data)
+ {
+ install_wait_handler (async->dbus,
+ async->wait_data,
+ G_OBJECT (tab),
+ wait_handler_dbus);
+ }
+}
+#endif
+
+static void
+create_tab_for_pipe (GeditDBus *dbus,
+ const gchar *pipe,
+ GeditWindow *window,
+ const GeditEncoding *encoding,
+ gint line_position,
+ gint column_position,
+ gboolean jump_to,
+ WaitData *wait_data)
+{
+#ifdef G_OS_UNIX
+ /* We'll do this async */
+ GFile *file;
+ AsyncData *async;
+
+ file = g_file_new_for_path (pipe);
+ dbus->priv->stdin_fifo = gedit_fifo_new (file);
+ g_object_unref (file);
+
+ if (dbus->priv->stdin_fifo == NULL)
+ {
+ return;
+ }
+
+ async = async_data_new (dbus);
+ async->window = window;
+ async->encoding = encoding;
+ async->line_position = line_position;
+ async->column_position = column_position;
+ async->jump_to = jump_to;
+ async->wait_data = wait_data;
+
+ g_object_weak_ref (G_OBJECT (window),
+ (GWeakNotify)async_window_destroyed,
+ async);
+
+ gedit_fifo_open_read_async (dbus->priv->stdin_fifo,
+ G_PRIORITY_DEFAULT,
+ async->cancellable,
+ (GAsyncReadyCallback)stdin_pipe_ready_to_read,
+ async);
+#endif
+}
+
static void
dbus_handle_open (GeditDBus *dbus,
GVariant *parameters,
@@ -656,9 +1150,12 @@ dbus_handle_open (GeditDBus *dbus,
GSList *loaded_documents = NULL;
gboolean empty_window;
WaitData *data;
+ GSList *item;
+ GSList *tabs;
+ gchar *stdin_pipe;
g_variant_get (parameters,
- "(assiibbbusiiii)",
+ "(assiibbbusiiiis)",
&file_list,
&charset_encoding,
&line_position,
@@ -671,7 +1168,8 @@ dbus_handle_open (GeditDBus *dbus,
&screen_number,
&workspace,
&viewport_x,
- &viewport_y);
+ &viewport_y,
+ &stdin_pipe);
locations = variant_iter_list_to_locations (file_list);
g_variant_iter_free (file_list);
@@ -702,20 +1200,46 @@ dbus_handle_open (GeditDBus *dbus,
column_position);
}
- if (new_document)
- {
- GeditTab *tab;
- tab = gedit_window_create_tab (window, TRUE);
+ g_slist_free (locations);
+
+ tabs = create_tabs_for_fds (dbus,
+ invocation,
+ window,
+ encoding,
+ line_position,
+ column_position,
+ loaded_documents == NULL);
- loaded_documents = g_slist_append (loaded_documents, gedit_tab_get_document (tab));
+ for (item = tabs; item; item = g_slist_next (item))
+ {
+ loaded_documents = g_slist_append (loaded_documents, gedit_tab_get_document (item->data));
}
- set_interaction_time_and_present (window, startup_time);
+ g_slist_free (tabs);
- g_slist_free (locations);
+ set_interaction_time_and_present (window, startup_time);
if (!wait)
{
+ if (stdin_pipe && *stdin_pipe)
+ {
+ create_tab_for_pipe (dbus,
+ stdin_pipe,
+ window,
+ encoding,
+ line_position,
+ column_position,
+ loaded_documents == NULL && !new_document,
+ NULL);
+ }
+
+ g_free (stdin_pipe);
+
+ if (new_document)
+ {
+ gedit_window_create_tab (window, loaded_documents == NULL);
+ }
+
g_slist_free (loaded_documents);
g_dbus_method_invocation_return_value (invocation,
g_variant_new ("(u)", 0));
@@ -729,8 +1253,30 @@ dbus_handle_open (GeditDBus *dbus,
data->close_window = empty_window;
data->wait_id = ++dbus->priv->next_wait_id;
- if (loaded_documents == NULL)
+ if (stdin_pipe && *stdin_pipe)
+ {
+ create_tab_for_pipe (dbus,
+ stdin_pipe,
+ window,
+ encoding,
+ line_position,
+ column_position,
+ loaded_documents == NULL && !new_document,
+ data);
+ }
+
+ if (new_document)
{
+ GeditTab *tab;
+ tab = gedit_window_create_tab (window, loaded_documents == NULL);
+
+ loaded_documents = g_slist_append (loaded_documents,
+ gedit_tab_get_document (tab));
+ }
+
+ if (loaded_documents == NULL && !(stdin_pipe && *stdin_pipe))
+ {
+ /* Add wait handler on the window */
install_wait_handler (dbus,
data,
G_OBJECT (window),
@@ -750,6 +1296,8 @@ dbus_handle_open (GeditDBus *dbus,
}
}
+ g_free (stdin_pipe);
+
g_slist_free (loaded_documents);
g_dbus_method_invocation_return_value (invocation, g_variant_new ("(u)", data->wait_id));
}
@@ -792,6 +1340,7 @@ static const GDBusArgInfo in_args[] = {
{"workspace" , "i"},
{"viewport_x" , "i"},
{"viewport_y" , "i"},
+ {"stdin_pipe" , "s"}
};
static const GDBusArgInfo out_args[] = {
@@ -799,7 +1348,7 @@ static const GDBusArgInfo out_args[] = {
};
static const GDBusMethodInfo command_line_methods[] = {
- {"Open", "assiibbbusiiii", 13, in_args, "u", 1, out_args}
+ {"Open", "assiibbbusiiiis", 14, in_args, "u", 1, out_args}
};
static const GDBusArgInfo signal_args[] = {
diff --git a/gedit/gedit-document-loader.c b/gedit/gedit-document-loader.c
index a1dd214..2de4c63 100644
--- a/gedit/gedit-document-loader.c
+++ b/gedit/gedit-document-loader.c
@@ -567,6 +567,24 @@ async_read_cb (GInputStream *stream,
return;
}
+ /* When reading just from the stream, try to do content-type
+ detection based on data */
+ if (loader->priv->location == NULL && loader->priv->info == NULL)
+ {
+ gchar *guessed;
+
+ loader->priv->info = g_file_info_new ();
+
+ guessed = g_content_type_guess (NULL,
+ (guchar *)loader->priv->buffer,
+ async->read,
+ NULL);
+
+ g_file_info_set_attribute_string (loader->priv->info,
+ G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE,
+ guessed);
+ }
+
/* Bump the size. */
loader->priv->bytes_read += async->read;
diff --git a/gedit/gedit-fifo.c b/gedit/gedit-fifo.c
new file mode 100644
index 0000000..79afaf5
--- /dev/null
+++ b/gedit/gedit-fifo.c
@@ -0,0 +1,347 @@
+#include "gedit-fifo.h"
+#include <stdio.h>
+#include <gio/gunixinputstream.h>
+#include <gio/gunixoutputstream.h>
+#include <errno.h>
+#include <string.h>
+
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include <glib.h>
+#include <glib/gstdio.h>
+
+#define GEDIT_FIFO_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE((object), GEDIT_TYPE_FIFO, GeditFifoPrivate))
+
+/* Properties */
+enum
+{
+ PROP_0,
+ PROP_FILE
+};
+
+struct _GeditFifoPrivate
+{
+ GFile *file;
+ gint open_mode;
+};
+
+static void gedit_fifo_initable_iface_init (gpointer giface, gpointer iface_data);
+
+G_DEFINE_TYPE_WITH_CODE (GeditFifo,
+ gedit_fifo,
+ G_TYPE_OBJECT,
+ G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE, gedit_fifo_initable_iface_init))
+
+static gboolean
+gedit_fifo_initable_init (GInitable *initable,
+ GCancellable *cancellable,
+ GError **error)
+{
+ g_return_val_if_fail (GEDIT_IS_FIFO (initable), FALSE);
+
+ if (cancellable && g_cancellable_set_error_if_cancelled (cancellable, error))
+ {
+ return FALSE;
+ }
+
+ return GEDIT_FIFO (initable)->priv->file != NULL;
+}
+
+static void
+gedit_fifo_initable_iface_init (gpointer giface, gpointer iface_data)
+{
+ GInitableIface *iface = giface;
+
+ iface->init = gedit_fifo_initable_init;
+}
+
+static void
+gedit_fifo_finalize (GObject *object)
+{
+ GeditFifo *self = GEDIT_FIFO (object);
+
+ if (self->priv->file)
+ {
+ g_object_unref (self->priv->file);
+ }
+
+ G_OBJECT_CLASS (gedit_fifo_parent_class)->finalize (object);
+}
+
+static void
+gedit_fifo_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
+{
+ GeditFifo *self = GEDIT_FIFO (object);
+
+ switch (prop_id)
+ {
+ case PROP_FILE:
+ self->priv->file = g_value_dup_object (value);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gedit_fifo_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
+{
+ GeditFifo *self = GEDIT_FIFO (object);
+
+ switch (prop_id)
+ {
+ case PROP_FILE:
+ g_value_set_object (value, self->priv->file);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+init_fifo (GeditFifo *fifo)
+{
+ gchar tmp[] = "gedit-fifo.XXXXXX";
+ gint fd;
+
+ fd = g_mkstemp (tmp);
+
+ if (fd == -1)
+ {
+ g_warning ("Could not generate temporary name for fifo: %s",
+ strerror (errno));
+ return;
+ }
+
+ close (fd);
+
+ if (g_unlink (tmp) == -1)
+ {
+ return;
+ }
+
+ if (mkfifo (tmp, 0600) == -1)
+ {
+ g_warning ("Could not create named pipe for standard in: %s",
+ strerror (errno));
+ return;
+ }
+
+ fifo->priv->file = g_file_new_for_path (tmp);
+}
+
+static void
+gedit_fifo_constructed (GObject *object)
+{
+ GeditFifo *self = GEDIT_FIFO (object);
+
+ if (!self->priv->file)
+ {
+ init_fifo (self);
+ }
+ else if (!g_file_query_exists (self->priv->file, NULL))
+ {
+ g_object_unref (self->priv->file);
+ self->priv->file = NULL;
+ }
+}
+
+static void
+gedit_fifo_class_init (GeditFifoClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->finalize = gedit_fifo_finalize;
+
+ object_class->set_property = gedit_fifo_set_property;
+ object_class->get_property = gedit_fifo_get_property;
+
+ object_class->constructed = gedit_fifo_constructed;
+
+ g_object_class_install_property (object_class, PROP_FILE,
+ g_param_spec_object ("file",
+ "FILE",
+ "The fifo file",
+ G_TYPE_FILE,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_STATIC_STRINGS));
+
+ g_type_class_add_private (object_class, sizeof(GeditFifoPrivate));
+}
+
+static void
+gedit_fifo_init (GeditFifo *self)
+{
+ self->priv = GEDIT_FIFO_GET_PRIVATE (self);
+}
+
+GeditFifo *
+gedit_fifo_new (GFile *file)
+{
+ return g_initable_new (GEDIT_TYPE_FIFO, NULL, NULL, "file", file, NULL);
+}
+
+static void
+fifo_open_in_thread (GSimpleAsyncResult *res,
+ GObject *object,
+ GCancellable *cancellable)
+{
+ GError *error = NULL;
+ gchar *path;
+ gint fd;
+ GeditFifo *fifo;
+ gpointer stream;
+
+ if (cancellable && g_cancellable_set_error_if_cancelled (cancellable, &error))
+ {
+ g_simple_async_result_set_from_error (res, error);
+ g_error_free (error);
+ return;
+ }
+
+ fifo = GEDIT_FIFO (object);
+ path = g_file_get_path (fifo->priv->file);
+ fd = g_open (path, fifo->priv->open_mode, 0);
+ g_free (path);
+
+ if (cancellable && g_cancellable_set_error_if_cancelled (cancellable, &error))
+ {
+ if (fd != -1)
+ {
+ close (fd);
+ }
+
+ g_simple_async_result_set_from_error (res, error);
+ g_error_free (error);
+ return;
+ }
+
+ if (fd == -1)
+ {
+ g_simple_async_result_set_error (res,
+ G_IO_ERROR,
+ g_io_error_from_errno (errno),
+ "%s",
+ strerror (errno));
+ return;
+ }
+
+ if (fifo->priv->open_mode & O_WRONLY)
+ {
+ stream = g_unix_output_stream_new (fd, TRUE);
+ }
+ else
+ {
+ stream = g_unix_input_stream_new (fd, TRUE);
+ }
+
+ g_simple_async_result_set_op_res_gpointer (res,
+ stream,
+ (GDestroyNotify)g_object_unref);
+}
+
+static void
+async_open (GeditFifo *fifo,
+ gint mode,
+ gint io_priority,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GSimpleAsyncResult *ret;
+
+ fifo->priv->open_mode = mode;
+
+ ret = g_simple_async_result_new (G_OBJECT (fifo),
+ callback,
+ user_data,
+ fifo_open_in_thread);
+
+ g_simple_async_result_run_in_thread (ret,
+ fifo_open_in_thread,
+ io_priority,
+ cancellable);
+}
+
+GInputStream *
+gedit_fifo_open_read_finish (GeditFifo *fifo,
+ GAsyncResult *result,
+ GError **error)
+{
+ GSimpleAsyncResult *simple;
+
+ g_return_val_if_fail (GEDIT_IS_FIFO (fifo), NULL);
+ g_return_val_if_fail (g_simple_async_result_is_valid (result,
+ G_OBJECT (fifo),
+ fifo_open_in_thread),
+ NULL);
+
+ simple = G_SIMPLE_ASYNC_RESULT (result);
+
+ if (g_simple_async_result_propagate_error (simple, error))
+ {
+ return NULL;
+ }
+
+ return G_INPUT_STREAM (g_object_ref (g_simple_async_result_get_op_res_gpointer (simple)));
+}
+
+GOutputStream *
+gedit_fifo_open_write_finish (GeditFifo *fifo,
+ GAsyncResult *result,
+ GError **error)
+{
+ GSimpleAsyncResult *simple;
+
+ g_return_val_if_fail (GEDIT_IS_FIFO (fifo), NULL);
+ g_return_val_if_fail (g_simple_async_result_is_valid (result,
+ G_OBJECT (fifo),
+ fifo_open_in_thread),
+ NULL);
+
+ simple = G_SIMPLE_ASYNC_RESULT (result);
+
+ if (g_simple_async_result_propagate_error (simple, error))
+ {
+ return NULL;
+ }
+
+ return G_OUTPUT_STREAM (g_simple_async_result_get_op_res_gpointer (simple));
+}
+
+void
+gedit_fifo_open_read_async (GeditFifo *fifo,
+ gint io_priority,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ g_return_if_fail (GEDIT_IS_FIFO (fifo));
+
+ async_open (fifo, O_RDONLY, io_priority, cancellable, callback, user_data);
+}
+
+void
+gedit_fifo_open_write_async (GeditFifo *fifo,
+ gint io_priority,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ g_return_if_fail (GEDIT_IS_FIFO (fifo));
+
+ async_open (fifo, O_WRONLY, io_priority, cancellable, callback, user_data);
+}
+
+GFile *
+gedit_fifo_get_file (GeditFifo *fifo)
+{
+ g_return_val_if_fail (GEDIT_IS_FIFO (fifo), NULL);
+ return g_file_dup (fifo->priv->file);
+}
diff --git a/gedit/gedit-fifo.h b/gedit/gedit-fifo.h
new file mode 100644
index 0000000..c59ddb4
--- /dev/null
+++ b/gedit/gedit-fifo.h
@@ -0,0 +1,58 @@
+#ifndef __GEDIT_FIFO_H__
+#define __GEDIT_FIFO_H__
+
+#include <glib-object.h>
+#include <gio/gio.h>
+
+G_BEGIN_DECLS
+
+#define GEDIT_TYPE_FIFO (gedit_fifo_get_type ())
+#define GEDIT_FIFO(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GEDIT_TYPE_FIFO, GeditFifo))
+#define GEDIT_FIFO_CONST(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GEDIT_TYPE_FIFO, GeditFifo const))
+#define GEDIT_FIFO_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GEDIT_TYPE_FIFO, GeditFifoClass))
+#define GEDIT_IS_FIFO(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GEDIT_TYPE_FIFO))
+#define GEDIT_IS_FIFO_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GEDIT_TYPE_FIFO))
+#define GEDIT_FIFO_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GEDIT_TYPE_FIFO, GeditFifoClass))
+
+typedef struct _GeditFifo GeditFifo;
+typedef struct _GeditFifoClass GeditFifoClass;
+typedef struct _GeditFifoPrivate GeditFifoPrivate;
+
+struct _GeditFifo {
+ GObject parent;
+
+ GeditFifoPrivate *priv;
+};
+
+struct _GeditFifoClass {
+ GObjectClass parent_class;
+};
+
+GType gedit_fifo_get_type (void) G_GNUC_CONST;
+
+GeditFifo *gedit_fifo_new (GFile *file);
+GFile *gedit_fifo_get_file (GeditFifo *fifo);
+
+void gedit_fifo_open_read_async (GeditFifo *fifo,
+ gint io_priority,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+
+void gedit_fifo_open_write_async (GeditFifo *fifo,
+ gint io_priority,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+
+GOutputStream *gedit_fifo_open_write_finish (GeditFifo *fifo,
+ GAsyncResult *result,
+ GError **error);
+
+GInputStream *gedit_fifo_open_read_finish (GeditFifo *fifo,
+ GAsyncResult *result,
+ GError **error);
+
+G_END_DECLS
+
+#endif /* __GEDIT_FIFO_H__ */
diff --git a/gedit/gedit-utils.c b/gedit/gedit-utils.c
index 4f76e75..071e137 100644
--- a/gedit/gedit-utils.c
+++ b/gedit/gedit-utils.c
@@ -59,6 +59,10 @@
#include <X11/Xatom.h>
#endif
+#ifdef G_OS_UNIX
+#include <unistd.h>
+#endif
+
#include "gseal-gtk-compat.h"
#define STDIN_DELAY_MICROSECONDS 100000
@@ -1525,4 +1529,15 @@ gedit_utils_decode_uri (const gchar *uri,
return TRUE;
}
+
+gboolean
+gedit_utils_can_read_from_stdin (void)
+{
+#ifdef G_OS_UNIX
+ return !isatty (STDIN_FILENO);
+#else
+ return FALSE;
+#endif
+}
+
/* ex:ts=8:noet: */
diff --git a/gedit/gedit-utils.h b/gedit/gedit-utils.h
index 80d24a2..8c8c6d4 100644
--- a/gedit/gedit-utils.h
+++ b/gedit/gedit-utils.h
@@ -154,6 +154,8 @@ gboolean gedit_utils_decode_uri (const gchar *uri,
/* Turns data from a drop into a list of well formatted uris */
gchar **gedit_utils_drop_get_uris (GtkSelectionData *selection_data);
+gboolean gedit_utils_can_read_from_stdin (void);
+
G_END_DECLS
#endif /* __GEDIT_UTILS_H__ */
diff --git a/gedit/gedit.c b/gedit/gedit.c
index cf55c2f..c6d5c64 100644
--- a/gedit/gedit.c
+++ b/gedit/gedit.c
@@ -59,27 +59,21 @@
#endif
#ifdef G_OS_UNIX
-#include <unistd.h>
#include <gio/gunixinputstream.h>
+#include <unistd.h>
#endif
-#ifdef G_OS_UNIX
-static gboolean
+static void
gedit_main_load_from_stdin (GeditWindow *window,
gboolean jump_to)
{
+#ifdef G_OS_UNIX
GInputStream *stream;
const GeditEncoding *encoding;
gint line_position;
gint column_position;
GeditCommandLine *command_line;
- /* Only if it's not a tty */
- if (isatty (STDIN_FILENO))
- {
- return FALSE;
- }
-
command_line = gedit_command_line_get_default ();
encoding = gedit_command_line_get_encoding (command_line);
@@ -96,10 +90,8 @@ gedit_main_load_from_stdin (GeditWindow *window,
column_position,
jump_to);
g_object_unref (stream);
-
- return TRUE;
-}
#endif
+}
static void
gedit_main_window (void)
@@ -140,13 +132,11 @@ gedit_main_window (void)
g_slist_free (loaded);
}
-#ifdef G_OS_UNIX
- /* We can only do this on unix systems */
- if (gedit_main_load_from_stdin (window, !doc_created))
+ if (gedit_utils_can_read_from_stdin ())
{
+ gedit_main_load_from_stdin (window, !doc_created);
doc_created = TRUE;
}
-#endif
if (!doc_created || gedit_command_line_get_new_document (command_line))
{
@@ -203,6 +193,7 @@ gedit_main (gboolean service)
/* Cleanup */
g_object_unref (engine);
+ g_object_unref (app);
#ifndef ENABLE_GVFS_METADATA
gedit_metadata_manager_shutdown ();
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]