|
Packit |
1e8aac |
/*
|
|
Packit |
1e8aac |
* Copyright (C) 2010 Marco Diego Aurélio Mesquita
|
|
Packit |
1e8aac |
*
|
|
Packit |
1e8aac |
* This program is free software; you can redistribute it and/or modify
|
|
Packit |
1e8aac |
* it under the terms of the GNU Lesser General Public License as
|
|
Packit |
1e8aac |
* published by the Free Software Foundation; either version 2 of the
|
|
Packit |
1e8aac |
* License, or (at your option) any later version.
|
|
Packit |
1e8aac |
*
|
|
Packit |
1e8aac |
* This program is distributed in the hope that it will be useful,
|
|
Packit |
1e8aac |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit |
1e8aac |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
Packit |
1e8aac |
* GNU General Public License for more details.
|
|
Packit |
1e8aac |
*
|
|
Packit |
1e8aac |
* You should have received a copy of the GNU Lesser General Public License
|
|
Packit |
1e8aac |
* along with this program; if not, write to the Free Software
|
|
Packit |
1e8aac |
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
Packit |
1e8aac |
*
|
|
Packit |
1e8aac |
* Authors:
|
|
Packit |
1e8aac |
* Marco Diego Aurélio Mesquita <marcodiegomesquita@gmail.com>
|
|
Packit |
1e8aac |
*/
|
|
Packit |
1e8aac |
|
|
Packit |
1e8aac |
#include <config.h>
|
|
Packit |
1e8aac |
|
|
Packit |
1e8aac |
/**
|
|
Packit |
1e8aac |
* SECTION:glade-preview
|
|
Packit |
1e8aac |
* @Short_Description: The glade preview launch/kill interface.
|
|
Packit |
1e8aac |
*
|
|
Packit |
1e8aac |
* This object owns all data that is needed to keep a preview. It stores
|
|
Packit |
1e8aac |
* the GIOChannel used for comunnication between glade and glade-previewer,
|
|
Packit |
1e8aac |
* the event source id for a watch (in the case a watch is used to monitor
|
|
Packit |
1e8aac |
* the communication channel), the previewed widget and the pid of the
|
|
Packit |
1e8aac |
* corresponding glade-previewer.
|
|
Packit |
1e8aac |
*
|
|
Packit |
1e8aac |
*/
|
|
Packit |
1e8aac |
|
|
Packit |
1e8aac |
|
|
Packit |
1e8aac |
#include <string.h>
|
|
Packit |
1e8aac |
#include <stdlib.h>
|
|
Packit |
1e8aac |
#include <glib.h>
|
|
Packit |
1e8aac |
#include <glib/gi18n-lib.h>
|
|
Packit |
1e8aac |
#include <glib/gstdio.h>
|
|
Packit |
1e8aac |
|
|
Packit |
1e8aac |
#include "glade.h"
|
|
Packit |
1e8aac |
#include "glade-preview.h"
|
|
Packit |
1e8aac |
#include "glade-project.h"
|
|
Packit |
1e8aac |
#include "glade-app.h"
|
|
Packit |
1e8aac |
|
|
Packit |
1e8aac |
#include "glade-preview-tokens.h"
|
|
Packit |
1e8aac |
|
|
Packit |
1e8aac |
#ifdef G_OS_WIN32
|
|
Packit |
1e8aac |
#define GLADE_PREVIEWER "glade-previewer.exe"
|
|
Packit |
1e8aac |
#else
|
|
Packit |
1e8aac |
#define GLADE_PREVIEWER "glade-previewer"
|
|
Packit |
1e8aac |
#endif
|
|
Packit |
1e8aac |
|
|
Packit |
1e8aac |
/* Private data for glade-preview */
|
|
Packit |
1e8aac |
struct _GladePreviewPrivate
|
|
Packit |
1e8aac |
{
|
|
Packit |
1e8aac |
GIOChannel *channel; /* Channel user for communication between glade and glade-previewer */
|
|
Packit |
1e8aac |
guint watch; /* Event source id used to monitor the channel */
|
|
Packit |
1e8aac |
GladeWidget *previewed_widget;
|
|
Packit |
1e8aac |
GPid pid; /* Pid of the corresponding glade-previewer process */
|
|
Packit |
1e8aac |
};
|
|
Packit |
1e8aac |
|
|
Packit |
1e8aac |
G_DEFINE_TYPE_WITH_PRIVATE (GladePreview, glade_preview, G_TYPE_OBJECT);
|
|
Packit |
1e8aac |
|
|
Packit |
1e8aac |
enum
|
|
Packit |
1e8aac |
{
|
|
Packit |
1e8aac |
PREVIEW_EXITS,
|
|
Packit |
1e8aac |
LAST_SIGNAL
|
|
Packit |
1e8aac |
};
|
|
Packit |
1e8aac |
|
|
Packit |
1e8aac |
static guint glade_preview_signals[LAST_SIGNAL] = { 0 };
|
|
Packit |
1e8aac |
|
|
Packit |
1e8aac |
/**
|
|
Packit |
1e8aac |
* glade_preview_kill
|
|
Packit |
1e8aac |
* @preview: a #GladePreview that will be killed.
|
|
Packit |
1e8aac |
*
|
|
Packit |
1e8aac |
* Uses the communication channel and protocol to send the "<quit>" token to the
|
|
Packit |
1e8aac |
* glade-previewer telling it to commit suicide.
|
|
Packit |
1e8aac |
*
|
|
Packit |
1e8aac |
*/
|
|
Packit |
1e8aac |
static void
|
|
Packit |
1e8aac |
glade_preview_kill (GladePreview *preview)
|
|
Packit |
1e8aac |
{
|
|
Packit |
1e8aac |
const gchar *quit = QUIT_TOKEN;
|
|
Packit |
1e8aac |
GIOChannel *channel;
|
|
Packit |
1e8aac |
GError *error = NULL;
|
|
Packit |
1e8aac |
gsize size;
|
|
Packit |
1e8aac |
|
|
Packit |
1e8aac |
channel = preview->priv->channel;
|
|
Packit |
1e8aac |
g_io_channel_write_chars (channel, quit, strlen (quit), &size, &error);
|
|
Packit |
1e8aac |
|
|
Packit |
1e8aac |
if (size != strlen (quit) && error != NULL)
|
|
Packit |
1e8aac |
{
|
|
Packit |
1e8aac |
g_warning ("Error passing quit signal trough pipe: %s", error->message);
|
|
Packit |
1e8aac |
g_error_free (error);
|
|
Packit |
1e8aac |
}
|
|
Packit |
1e8aac |
|
|
Packit |
1e8aac |
g_io_channel_flush (channel, &error);
|
|
Packit |
1e8aac |
if (error != NULL)
|
|
Packit |
1e8aac |
{
|
|
Packit |
1e8aac |
g_warning ("Error flushing channel: %s", error->message);
|
|
Packit |
1e8aac |
g_error_free (error);
|
|
Packit |
1e8aac |
}
|
|
Packit |
1e8aac |
|
|
Packit |
1e8aac |
g_io_channel_shutdown (channel, TRUE, &error);
|
|
Packit |
1e8aac |
if (error != NULL)
|
|
Packit |
1e8aac |
{
|
|
Packit |
1e8aac |
g_warning ("Error shutting down channel: %s", error->message);
|
|
Packit |
1e8aac |
g_error_free (error);
|
|
Packit |
1e8aac |
}
|
|
Packit |
1e8aac |
}
|
|
Packit |
1e8aac |
|
|
Packit |
1e8aac |
static void
|
|
Packit |
1e8aac |
glade_preview_dispose (GObject *gobject)
|
|
Packit |
1e8aac |
{
|
|
Packit |
1e8aac |
GladePreview *self = GLADE_PREVIEW (gobject);
|
|
Packit |
1e8aac |
|
|
Packit |
1e8aac |
if (self->priv->watch)
|
|
Packit |
1e8aac |
{
|
|
Packit |
1e8aac |
g_source_remove (self->priv->watch);
|
|
Packit |
1e8aac |
glade_preview_kill (self);
|
|
Packit |
1e8aac |
}
|
|
Packit |
1e8aac |
|
|
Packit |
1e8aac |
if (self->priv->channel)
|
|
Packit |
1e8aac |
{
|
|
Packit |
1e8aac |
g_io_channel_unref (self->priv->channel);
|
|
Packit |
1e8aac |
self->priv->channel = NULL;
|
|
Packit |
1e8aac |
}
|
|
Packit |
1e8aac |
|
|
Packit |
1e8aac |
G_OBJECT_CLASS (glade_preview_parent_class)->dispose (gobject);
|
|
Packit |
1e8aac |
}
|
|
Packit |
1e8aac |
|
|
Packit |
1e8aac |
/* We have to use finalize because of the signal that is sent in dispose */
|
|
Packit |
1e8aac |
static void
|
|
Packit |
1e8aac |
glade_preview_finalize (GObject *gobject)
|
|
Packit |
1e8aac |
{
|
|
Packit |
1e8aac |
G_OBJECT_CLASS (glade_preview_parent_class)->finalize (gobject);
|
|
Packit |
1e8aac |
}
|
|
Packit |
1e8aac |
|
|
Packit |
1e8aac |
static void
|
|
Packit |
1e8aac |
glade_preview_class_init (GladePreviewClass *klass)
|
|
Packit |
1e8aac |
{
|
|
Packit |
1e8aac |
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
|
Packit |
1e8aac |
|
|
Packit |
1e8aac |
gobject_class->dispose = glade_preview_dispose;
|
|
Packit |
1e8aac |
gobject_class->finalize = glade_preview_finalize;
|
|
Packit |
1e8aac |
|
|
Packit |
1e8aac |
/**
|
|
Packit |
1e8aac |
* GladePreview::exits:
|
|
Packit |
1e8aac |
* @gladepreview: the #GladePreview which received the signal.
|
|
Packit |
1e8aac |
* @gladeproject: the #GladeProject associated with the preview.
|
|
Packit |
1e8aac |
*
|
|
Packit |
1e8aac |
* Emitted when @preview exits.
|
|
Packit |
1e8aac |
*/
|
|
Packit |
1e8aac |
glade_preview_signals[PREVIEW_EXITS] =
|
|
Packit |
1e8aac |
g_signal_new ("exits",
|
|
Packit |
1e8aac |
G_TYPE_FROM_CLASS (gobject_class),
|
|
Packit |
1e8aac |
G_SIGNAL_RUN_FIRST,
|
|
Packit |
1e8aac |
0, NULL, NULL,
|
|
Packit |
1e8aac |
g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
|
|
Packit |
1e8aac |
}
|
|
Packit |
1e8aac |
|
|
Packit |
1e8aac |
static void
|
|
Packit |
1e8aac |
glade_preview_init (GladePreview *self)
|
|
Packit |
1e8aac |
{
|
|
Packit |
1e8aac |
GladePreviewPrivate *priv;
|
|
Packit |
1e8aac |
|
|
Packit |
1e8aac |
self->priv = priv = glade_preview_get_instance_private (self);
|
|
Packit |
1e8aac |
priv->channel = NULL;
|
|
Packit |
1e8aac |
}
|
|
Packit |
1e8aac |
|
|
Packit |
1e8aac |
static void
|
|
Packit |
1e8aac |
glade_preview_internal_watch (GPid pid, gint status, gpointer data)
|
|
Packit |
1e8aac |
{
|
|
Packit |
1e8aac |
GladePreview *preview = GLADE_PREVIEW (data);
|
|
Packit |
1e8aac |
|
|
Packit |
1e8aac |
preview->priv->watch = 0;
|
|
Packit |
1e8aac |
|
|
Packit |
1e8aac |
/* This means a preview exited. We'll now signal it */
|
|
Packit |
1e8aac |
g_signal_emit (preview, glade_preview_signals[PREVIEW_EXITS], 0);
|
|
Packit |
1e8aac |
}
|
|
Packit |
1e8aac |
|
|
Packit |
1e8aac |
/**
|
|
Packit |
1e8aac |
* glade_preview_launch:
|
|
Packit |
1e8aac |
* @widget: Pointer to a local instance of the widget that will be previewed.
|
|
Packit |
1e8aac |
* @buffer: Contents of an xml definition of the interface which will be previewed
|
|
Packit |
1e8aac |
*
|
|
Packit |
1e8aac |
* Creates a new #GladePreview and launches glade-previewer to preview it.
|
|
Packit |
1e8aac |
*
|
|
Packit |
1e8aac |
* Returns: a new #GladePreview or NULL if launch fails.
|
|
Packit |
1e8aac |
*
|
|
Packit |
1e8aac |
*/
|
|
Packit |
1e8aac |
GladePreview *
|
|
Packit |
1e8aac |
glade_preview_launch (GladeWidget *widget, const gchar *buffer)
|
|
Packit |
1e8aac |
{
|
|
Packit |
1e8aac |
GPid pid;
|
|
Packit |
1e8aac |
GError *error = NULL;
|
|
Packit |
1e8aac |
gchar *argv[10], *executable;
|
|
Packit |
1e8aac |
gint child_stdin;
|
|
Packit |
1e8aac |
gsize bytes_written;
|
|
Packit |
1e8aac |
GIOChannel *output;
|
|
Packit |
1e8aac |
GladePreview *preview = NULL;
|
|
Packit |
1e8aac |
const gchar *css_provider, *filename;
|
|
Packit |
1e8aac |
GladeProject *project;
|
|
Packit |
1e8aac |
gchar *name;
|
|
Packit |
1e8aac |
gint i;
|
|
Packit |
1e8aac |
|
|
Packit |
1e8aac |
g_return_val_if_fail (GLADE_IS_WIDGET (widget), NULL);
|
|
Packit |
1e8aac |
|
|
Packit |
1e8aac |
executable = g_find_program_in_path (GLADE_PREVIEWER);
|
|
Packit |
1e8aac |
|
|
Packit |
1e8aac |
project = glade_widget_get_project (widget);
|
|
Packit |
1e8aac |
filename = glade_project_get_path (project);
|
|
Packit |
1e8aac |
name = (filename) ? NULL : glade_project_get_name (project);
|
|
Packit |
1e8aac |
|
|
Packit |
1e8aac |
argv[0] = executable;
|
|
Packit |
1e8aac |
argv[1] = "--listen";
|
|
Packit |
1e8aac |
argv[2] = "--toplevel";
|
|
Packit |
1e8aac |
argv[3] = (gchar *) glade_widget_get_name (widget);
|
|
Packit |
1e8aac |
argv[4] = "--filename";
|
|
Packit |
1e8aac |
argv[5] = (filename) ? (gchar *) filename : name;
|
|
Packit |
1e8aac |
|
|
Packit |
1e8aac |
i = 5;
|
|
Packit |
1e8aac |
if (glade_project_get_template (project))
|
|
Packit |
1e8aac |
argv[++i] = "--template";
|
|
Packit |
1e8aac |
|
|
Packit |
1e8aac |
argv[++i] = NULL;
|
|
Packit |
1e8aac |
|
|
Packit |
1e8aac |
css_provider = glade_project_get_css_provider_path (glade_widget_get_project (widget));
|
|
Packit |
1e8aac |
if (css_provider)
|
|
Packit |
1e8aac |
{
|
|
Packit |
1e8aac |
argv[i] = "--css";
|
|
Packit |
1e8aac |
argv[++i] = (gchar *) css_provider;
|
|
Packit |
1e8aac |
argv[++i] = NULL;
|
|
Packit |
1e8aac |
}
|
|
Packit |
1e8aac |
|
|
Packit |
1e8aac |
if (g_spawn_async_with_pipes (NULL,
|
|
Packit |
1e8aac |
argv,
|
|
Packit |
1e8aac |
NULL, G_SPAWN_DO_NOT_REAP_CHILD, NULL, NULL,
|
|
Packit |
1e8aac |
&pid, &child_stdin, NULL, NULL,
|
|
Packit |
1e8aac |
&error) == FALSE)
|
|
Packit |
1e8aac |
{
|
|
Packit |
1e8aac |
g_warning (_("Error launching previewer: %s\n"), error->message);
|
|
Packit |
1e8aac |
glade_util_ui_message (glade_app_get_window (),
|
|
Packit |
1e8aac |
GLADE_UI_ERROR, NULL,
|
|
Packit |
1e8aac |
_("Failed to launch preview: %s.\n"),
|
|
Packit |
1e8aac |
error->message);
|
|
Packit |
1e8aac |
g_error_free (error);
|
|
Packit |
1e8aac |
g_free (executable);
|
|
Packit |
1e8aac |
g_free (name);
|
|
Packit |
1e8aac |
return NULL;
|
|
Packit |
1e8aac |
}
|
|
Packit |
1e8aac |
|
|
Packit |
1e8aac |
#ifdef G_OS_WIN32
|
|
Packit |
1e8aac |
output = g_io_channel_win32_new_fd (child_stdin);
|
|
Packit |
1e8aac |
#else
|
|
Packit |
1e8aac |
output = g_io_channel_unix_new (child_stdin);
|
|
Packit |
1e8aac |
#endif
|
|
Packit |
1e8aac |
|
|
Packit |
1e8aac |
g_io_channel_write_chars (output, buffer, strlen (buffer), &bytes_written,
|
|
Packit |
1e8aac |
&error);
|
|
Packit |
1e8aac |
|
|
Packit |
1e8aac |
if (bytes_written != strlen (buffer) && error != NULL)
|
|
Packit |
1e8aac |
{
|
|
Packit |
1e8aac |
g_warning ("Error passing UI trough pipe: %s", error->message);
|
|
Packit |
1e8aac |
g_error_free (error);
|
|
Packit |
1e8aac |
}
|
|
Packit |
1e8aac |
|
|
Packit |
1e8aac |
g_io_channel_flush (output, &error);
|
|
Packit |
1e8aac |
if (error != NULL)
|
|
Packit |
1e8aac |
{
|
|
Packit |
1e8aac |
g_warning ("Error flushing UI trough pipe: %s", error->message);
|
|
Packit |
1e8aac |
g_error_free (error);
|
|
Packit |
1e8aac |
}
|
|
Packit |
1e8aac |
|
|
Packit |
1e8aac |
/* Setting up preview data */
|
|
Packit |
1e8aac |
preview = g_object_new (GLADE_TYPE_PREVIEW, NULL);
|
|
Packit |
1e8aac |
preview->priv->channel = output;
|
|
Packit |
1e8aac |
preview->priv->previewed_widget = widget;
|
|
Packit |
1e8aac |
preview->priv->pid = pid;
|
|
Packit |
1e8aac |
|
|
Packit |
1e8aac |
preview->priv->watch =
|
|
Packit |
1e8aac |
g_child_watch_add (preview->priv->pid,
|
|
Packit |
1e8aac |
glade_preview_internal_watch,
|
|
Packit |
1e8aac |
preview);
|
|
Packit |
1e8aac |
|
|
Packit |
1e8aac |
g_free (executable);
|
|
Packit |
1e8aac |
g_free (name);
|
|
Packit |
1e8aac |
|
|
Packit |
1e8aac |
return preview;
|
|
Packit |
1e8aac |
}
|
|
Packit |
1e8aac |
|
|
Packit |
1e8aac |
void
|
|
Packit |
1e8aac |
glade_preview_update (GladePreview *preview, const gchar *buffer)
|
|
Packit |
1e8aac |
{
|
|
Packit |
1e8aac |
const gchar *update_token = UPDATE_TOKEN;
|
|
Packit |
1e8aac |
gchar *update;
|
|
Packit |
1e8aac |
GIOChannel *channel;
|
|
Packit |
1e8aac |
GError *error = NULL;
|
|
Packit |
1e8aac |
gsize size;
|
|
Packit |
1e8aac |
gsize bytes_written;
|
|
Packit |
1e8aac |
GladeWidget *gwidget;
|
|
Packit |
1e8aac |
|
|
Packit |
1e8aac |
g_return_if_fail (GLADE_IS_PREVIEW (preview));
|
|
Packit |
1e8aac |
g_return_if_fail (buffer && buffer[0]);
|
|
Packit |
1e8aac |
|
|
Packit |
1e8aac |
gwidget = glade_preview_get_widget (preview);
|
|
Packit |
1e8aac |
|
|
Packit |
1e8aac |
update = g_strdup_printf ("%s%s\n", update_token,
|
|
Packit |
1e8aac |
glade_widget_get_name (gwidget));
|
|
Packit |
1e8aac |
|
|
Packit |
1e8aac |
channel = preview->priv->channel;
|
|
Packit |
1e8aac |
g_io_channel_write_chars (channel, update, strlen (update), &size, &error);
|
|
Packit |
1e8aac |
|
|
Packit |
1e8aac |
if (size != strlen (update) && error != NULL)
|
|
Packit |
1e8aac |
{
|
|
Packit |
1e8aac |
g_warning ("Error passing quit signal trough pipe: %s", error->message);
|
|
Packit |
1e8aac |
g_error_free (error);
|
|
Packit |
1e8aac |
}
|
|
Packit |
1e8aac |
|
|
Packit |
1e8aac |
g_io_channel_flush (channel, &error);
|
|
Packit |
1e8aac |
if (error != NULL)
|
|
Packit |
1e8aac |
{
|
|
Packit |
1e8aac |
g_warning ("Error flushing channel: %s", error->message);
|
|
Packit |
1e8aac |
g_error_free (error);
|
|
Packit |
1e8aac |
}
|
|
Packit |
1e8aac |
|
|
Packit |
1e8aac |
/* We'll now send the interface: */
|
|
Packit |
1e8aac |
g_io_channel_write_chars (channel, buffer, strlen (buffer), &bytes_written,
|
|
Packit |
1e8aac |
&error);
|
|
Packit |
1e8aac |
|
|
Packit |
1e8aac |
if (bytes_written != strlen (buffer) && error != NULL)
|
|
Packit |
1e8aac |
{
|
|
Packit |
1e8aac |
g_warning ("Error passing UI trough pipe: %s", error->message);
|
|
Packit |
1e8aac |
g_error_free (error);
|
|
Packit |
1e8aac |
}
|
|
Packit |
1e8aac |
|
|
Packit |
1e8aac |
g_io_channel_flush (channel, &error);
|
|
Packit |
1e8aac |
if (error != NULL)
|
|
Packit |
1e8aac |
{
|
|
Packit |
1e8aac |
g_warning ("Error flushing UI trough pipe: %s", error->message);
|
|
Packit |
1e8aac |
g_error_free (error);
|
|
Packit |
1e8aac |
}
|
|
Packit |
1e8aac |
|
|
Packit |
1e8aac |
g_free (update);
|
|
Packit |
1e8aac |
}
|
|
Packit |
1e8aac |
|
|
Packit |
1e8aac |
GladeWidget *
|
|
Packit |
1e8aac |
glade_preview_get_widget (GladePreview *preview)
|
|
Packit |
1e8aac |
{
|
|
Packit |
1e8aac |
g_return_val_if_fail (GLADE_IS_PREVIEW (preview), NULL);
|
|
Packit |
1e8aac |
return preview->priv->previewed_widget;
|
|
Packit |
1e8aac |
}
|
|
Packit |
1e8aac |
|
|
Packit |
1e8aac |
GPid
|
|
Packit |
1e8aac |
glade_preview_get_pid (GladePreview *preview)
|
|
Packit |
1e8aac |
{
|
|
Packit |
1e8aac |
g_return_val_if_fail (GLADE_IS_PREVIEW (preview), 0);
|
|
Packit |
1e8aac |
return preview->priv->pid;
|
|
Packit |
1e8aac |
}
|