Blame gladeui/glade-previewer.c

Packit 1e8aac
/*
Packit 1e8aac
 * glade-previewer.c
Packit 1e8aac
 *
Packit 1e8aac
 * Copyright (C) 2013-2016 Juan Pablo Ugarte
Packit 1e8aac
   *
Packit 1e8aac
 * Author: Juan Pablo Ugarte <juanpablougarte@gmail.com>
Packit 1e8aac
 *
Packit 1e8aac
 * This library is free software; you can redistribute it and/or modify it
Packit 1e8aac
 * under the terms of the GNU Lesser General Public License as
Packit 1e8aac
 * published by the Free Software Foundation; either version 2.1 of
Packit 1e8aac
 * the License, or (at your option) any later version.
Packit 1e8aac
   *
Packit 1e8aac
 * This library is distributed in the hope that it will be useful, but
Packit 1e8aac
 * WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 1e8aac
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 1e8aac
 * Lesser General Public License for more details.
Packit 1e8aac
 *
Packit 1e8aac
 * You should have received a copy of the GNU Lesser General Public 
Packit 1e8aac
 * License 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
 */
Packit 1e8aac
#include <config.h>
Packit 1e8aac
Packit 1e8aac
#include "glade-previewer.h"
Packit 1e8aac
#include <glib/gi18n-lib.h>
Packit 1e8aac
#include <glib/gprintf.h>
Packit 1e8aac
#include <cairo-pdf.h>
Packit 1e8aac
#include <cairo-svg.h>
Packit 1e8aac
#include <cairo-ps.h>
Packit 1e8aac
Packit 1e8aac
struct _GladePreviewerPrivate
Packit 1e8aac
{
Packit 1e8aac
  GtkWidget *widget;    /* Preview widget */
Packit 1e8aac
  GList     *objects;   /* SlideShow objects */
Packit 1e8aac
  GtkWidget *dialog;    /* Dialog to show messages */
Packit 1e8aac
  GtkWidget *textview;
Packit 1e8aac
Packit 1e8aac
  GtkCssProvider *css_provider;
Packit 1e8aac
  GFileMonitor *css_monitor;
Packit 1e8aac
  gchar *css_file;
Packit 1e8aac
  gchar *extension;
Packit 1e8aac
Packit 1e8aac
  gboolean print_handlers;
Packit 1e8aac
};
Packit 1e8aac
Packit 1e8aac
G_DEFINE_TYPE_WITH_PRIVATE (GladePreviewer, glade_previewer, G_TYPE_OBJECT);
Packit 1e8aac
Packit 1e8aac
static void
Packit 1e8aac
glade_previewer_init (GladePreviewer *preview)
Packit 1e8aac
{
Packit 1e8aac
  GladePreviewerPrivate *priv = glade_previewer_get_instance_private (preview);
Packit 1e8aac
Packit 1e8aac
  preview->priv = priv;
Packit 1e8aac
}
Packit 1e8aac
Packit 1e8aac
static void
Packit 1e8aac
glade_previewer_dispose (GObject *object)
Packit 1e8aac
{
Packit 1e8aac
  GladePreviewerPrivate *priv = GLADE_PREVIEWER (object)->priv;
Packit 1e8aac
Packit 1e8aac
  g_list_free (priv->objects);
Packit 1e8aac
  
Packit 1e8aac
  priv->objects = NULL;
Packit 1e8aac
  priv->dialog = NULL;
Packit 1e8aac
  g_clear_object (&priv->css_provider);
Packit 1e8aac
  g_clear_object (&priv->css_monitor);
Packit 1e8aac
Packit 1e8aac
  G_OBJECT_CLASS (glade_previewer_parent_class)->dispose (object);
Packit 1e8aac
}
Packit 1e8aac
Packit 1e8aac
static void
Packit 1e8aac
glade_previewer_finalize (GObject *object)
Packit 1e8aac
{
Packit 1e8aac
  GladePreviewerPrivate *priv = GLADE_PREVIEWER (object)->priv;
Packit 1e8aac
Packit 1e8aac
  g_free (priv->css_file);
Packit 1e8aac
  g_free (priv->extension);
Packit 1e8aac
Packit 1e8aac
  G_OBJECT_CLASS (glade_previewer_parent_class)->finalize (object);
Packit 1e8aac
}
Packit 1e8aac
Packit 1e8aac
static gboolean 
Packit 1e8aac
on_widget_key_press_event (GtkWidget      *widget,
Packit 1e8aac
                           GdkEventKey    *event,
Packit 1e8aac
                           GladePreviewer *preview)
Packit 1e8aac
{
Packit 1e8aac
  GladePreviewerPrivate *priv = preview->priv;
Packit 1e8aac
  GList *node = NULL;
Packit 1e8aac
  GtkStack *stack;
Packit 1e8aac
  gchar *extension;
Packit 1e8aac
Packit 1e8aac
  if (priv->objects)
Packit 1e8aac
    {
Packit 1e8aac
      stack = GTK_STACK (gtk_bin_get_child (GTK_BIN (priv->widget)));
Packit 1e8aac
      node = g_list_find (priv->objects, gtk_stack_get_visible_child (stack));
Packit 1e8aac
    }
Packit 1e8aac
Packit 1e8aac
  switch (event->keyval)
Packit 1e8aac
    {
Packit 1e8aac
      case GDK_KEY_Page_Up:
Packit 1e8aac
        if (node && node->prev)
Packit 1e8aac
          gtk_stack_set_visible_child  (stack, node->prev->data);
Packit 1e8aac
        return TRUE;
Packit 1e8aac
      break;
Packit 1e8aac
      case GDK_KEY_Page_Down:
Packit 1e8aac
        if (node && node->next)
Packit 1e8aac
          gtk_stack_set_visible_child  (stack, node->next->data);
Packit 1e8aac
        return TRUE;
Packit 1e8aac
      break;
Packit 1e8aac
      case GDK_KEY_F5:
Packit 1e8aac
        extension = "svg";
Packit 1e8aac
      break;
Packit 1e8aac
      case GDK_KEY_F6:
Packit 1e8aac
        extension = "ps";
Packit 1e8aac
      break;
Packit 1e8aac
      case GDK_KEY_F7:
Packit 1e8aac
        extension = "pdf";
Packit 1e8aac
      break;
Packit 1e8aac
      case GDK_KEY_F8:
Packit 1e8aac
        extension = priv->extension ? priv->extension : "png";
Packit 1e8aac
      break;
Packit 1e8aac
      case GDK_KEY_F11:
Packit 1e8aac
        if (gdk_window_get_state (gtk_widget_get_window (widget)) & GDK_WINDOW_STATE_FULLSCREEN)
Packit 1e8aac
          gtk_window_unfullscreen (GTK_WINDOW (widget));
Packit 1e8aac
        else
Packit 1e8aac
          gtk_window_fullscreen (GTK_WINDOW (widget));
Packit 1e8aac
Packit 1e8aac
        return TRUE;
Packit 1e8aac
      break;
Packit 1e8aac
      default:
Packit 1e8aac
        return FALSE;
Packit 1e8aac
      break;
Packit 1e8aac
    }
Packit 1e8aac
Packit 1e8aac
  if (extension)
Packit 1e8aac
    {
Packit 1e8aac
      gchar *tmp_file = g_strdup_printf ("glade-screenshot-XXXXXX.%s", extension); 
Packit 1e8aac
Packit 1e8aac
      g_mkstemp (tmp_file);
Packit 1e8aac
      glade_previewer_screenshot (preview, FALSE, tmp_file);
Packit 1e8aac
      g_free (tmp_file);
Packit 1e8aac
Packit 1e8aac
      return TRUE;
Packit 1e8aac
    }
Packit 1e8aac
Packit 1e8aac
  return FALSE;
Packit 1e8aac
}
Packit 1e8aac
Packit 1e8aac
static void
Packit 1e8aac
glade_previewer_class_init (GladePreviewerClass *klass)
Packit 1e8aac
{
Packit 1e8aac
  GObjectClass *object_class = G_OBJECT_CLASS (klass);
Packit 1e8aac
Packit 1e8aac
  object_class->dispose = glade_previewer_dispose;
Packit 1e8aac
  object_class->finalize = glade_previewer_finalize;
Packit 1e8aac
}
Packit 1e8aac
Packit 1e8aac
GObject *
Packit 1e8aac
glade_previewer_new (void)
Packit 1e8aac
{
Packit 1e8aac
  return g_object_new (GLADE_TYPE_PREVIEWER, NULL);
Packit 1e8aac
}
Packit 1e8aac
Packit 1e8aac
void
Packit 1e8aac
glade_previewer_present (GladePreviewer *preview)
Packit 1e8aac
{
Packit 1e8aac
  g_return_if_fail (GLADE_IS_PREVIEWER (preview));
Packit 1e8aac
  gtk_window_present (GTK_WINDOW (preview->priv->widget));
Packit 1e8aac
}
Packit 1e8aac
Packit 1e8aac
void
Packit 1e8aac
glade_previewer_set_widget (GladePreviewer *preview, GtkWidget *widget)
Packit 1e8aac
{
Packit 1e8aac
  GladePreviewerPrivate *priv;
Packit 1e8aac
  GtkWidget *sw;
Packit 1e8aac
Packit 1e8aac
  g_return_if_fail (GLADE_IS_PREVIEWER (preview));
Packit 1e8aac
  g_return_if_fail (GTK_IS_WIDGET (widget));
Packit 1e8aac
Packit 1e8aac
  priv = preview->priv;
Packit 1e8aac
Packit 1e8aac
  if (priv->widget)
Packit 1e8aac
    gtk_widget_destroy (priv->widget);
Packit 1e8aac
Packit 1e8aac
  if (!gtk_widget_is_toplevel (widget))
Packit 1e8aac
    {
Packit 1e8aac
      GtkWidget *window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
Packit 1e8aac
Packit 1e8aac
      gtk_container_add (GTK_CONTAINER (window), widget);
Packit 1e8aac
Packit 1e8aac
      priv->widget = window;
Packit 1e8aac
    }
Packit 1e8aac
  else
Packit 1e8aac
    {
Packit 1e8aac
      priv->widget = widget;
Packit 1e8aac
    }
Packit 1e8aac
Packit 1e8aac
  /* Create dialog to display messages */
Packit 1e8aac
  priv->dialog = gtk_window_new (GTK_WINDOW_TOPLEVEL);
Packit 1e8aac
  gtk_window_set_default_size (GTK_WINDOW (priv->dialog), 640, 320);
Packit 1e8aac
  gtk_window_set_title (GTK_WINDOW (priv->dialog), _("Glade Previewer log"));
Packit 1e8aac
  gtk_window_set_transient_for (GTK_WINDOW (priv->dialog), GTK_WINDOW (priv->widget));
Packit 1e8aac
Packit 1e8aac
  priv->textview = gtk_text_view_new ();
Packit 1e8aac
  gtk_widget_show (priv->textview);
Packit 1e8aac
Packit 1e8aac
  sw = gtk_scrolled_window_new (NULL, NULL);
Packit 1e8aac
  gtk_widget_show (sw);
Packit 1e8aac
Packit 1e8aac
  gtk_container_add (GTK_CONTAINER (sw), priv->textview);
Packit 1e8aac
  gtk_container_add (GTK_CONTAINER (priv->dialog), sw);
Packit 1e8aac
Packit 1e8aac
  /* Hide dialog on delete event */
Packit 1e8aac
  g_signal_connect (priv->dialog, "delete-event",
Packit 1e8aac
                    G_CALLBACK (gtk_widget_hide),
Packit 1e8aac
                    NULL);
Packit 1e8aac
Packit 1e8aac
  /* Quit on delete event */
Packit 1e8aac
  g_signal_connect (priv->widget, "delete-event",
Packit 1e8aac
                    G_CALLBACK (gtk_main_quit),
Packit 1e8aac
                    NULL);
Packit 1e8aac
Packit 1e8aac
  /* Make sure we get press events */
Packit 1e8aac
  gtk_widget_add_events (priv->widget, GDK_KEY_PRESS_MASK);
Packit 1e8aac
Packit 1e8aac
  /* Handle key presses for screenshot feature */
Packit 1e8aac
  g_signal_connect_object (priv->widget, "key-press-event",
Packit 1e8aac
                           G_CALLBACK (on_widget_key_press_event),
Packit 1e8aac
                           preview, 0);
Packit 1e8aac
}
Packit 1e8aac
Packit 1e8aac
void
Packit 1e8aac
glade_previewer_set_message (GladePreviewer *preview, 
Packit 1e8aac
                             GtkMessageType  type,
Packit 1e8aac
                             const gchar    *message)
Packit 1e8aac
{
Packit 1e8aac
  GladePreviewerPrivate *priv;
Packit 1e8aac
  GtkTextBuffer *buffer;
Packit 1e8aac
Packit 1e8aac
  g_return_if_fail (GLADE_IS_PREVIEWER (preview));
Packit 1e8aac
  priv = preview->priv;
Packit 1e8aac
Packit 1e8aac
  if (!priv->textview)
Packit 1e8aac
    return;
Packit 1e8aac
Packit 1e8aac
  buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->textview));
Packit 1e8aac
  
Packit 1e8aac
  if (message)
Packit 1e8aac
    {
Packit 1e8aac
      GtkTextIter iter;
Packit 1e8aac
Packit 1e8aac
      /* TODO: use message type to color text */
Packit 1e8aac
      gtk_text_buffer_get_start_iter (buffer, &iter);
Packit 1e8aac
      gtk_text_buffer_insert (buffer, &iter, "\n", -1);
Packit 1e8aac
Packit 1e8aac
      gtk_text_buffer_get_start_iter (buffer, &iter);
Packit 1e8aac
      gtk_text_buffer_insert (buffer, &iter, message, -1);
Packit 1e8aac
Packit 1e8aac
      gtk_window_present (GTK_WINDOW (priv->dialog));
Packit 1e8aac
    }
Packit 1e8aac
}
Packit 1e8aac
Packit 1e8aac
static void 
Packit 1e8aac
on_css_monitor_changed (GFileMonitor       *monitor,
Packit 1e8aac
                        GFile              *file,
Packit 1e8aac
                        GFile              *other_file,
Packit 1e8aac
                        GFileMonitorEvent   event_type,
Packit 1e8aac
                        GladePreviewer     *preview)
Packit 1e8aac
{
Packit 1e8aac
  GladePreviewerPrivate *priv = preview->priv;
Packit 1e8aac
  GError *error = NULL;
Packit 1e8aac
Packit 1e8aac
  gtk_css_provider_load_from_file (priv->css_provider, file, &error);
Packit 1e8aac
Packit 1e8aac
  if (error)
Packit 1e8aac
    {
Packit 1e8aac
      glade_previewer_set_message (preview, GTK_MESSAGE_WARNING, error->message);
Packit 1e8aac
      g_error_free (error);
Packit 1e8aac
    }
Packit 1e8aac
  else
Packit 1e8aac
    glade_previewer_set_message (preview, GTK_MESSAGE_OTHER, NULL);
Packit 1e8aac
}
Packit 1e8aac
Packit 1e8aac
void
Packit 1e8aac
glade_previewer_set_css_file (GladePreviewer *preview,
Packit 1e8aac
                            const gchar  *css_file)
Packit 1e8aac
{
Packit 1e8aac
  GladePreviewerPrivate *priv;
Packit 1e8aac
  GError *error = NULL;
Packit 1e8aac
  GFile *file;
Packit 1e8aac
Packit 1e8aac
  g_return_if_fail (GLADE_IS_PREVIEWER (preview));
Packit 1e8aac
  priv = preview->priv;
Packit 1e8aac
Packit 1e8aac
  g_free (priv->css_file);
Packit 1e8aac
  g_clear_object (&priv->css_monitor);
Packit 1e8aac
Packit 1e8aac
  priv->css_file = g_strdup (css_file);
Packit 1e8aac
  
Packit 1e8aac
  file = g_file_new_for_path (css_file);
Packit 1e8aac
  
Packit 1e8aac
  if (!priv->css_provider)
Packit 1e8aac
    {
Packit 1e8aac
      priv->css_provider = gtk_css_provider_new ();
Packit 1e8aac
      g_object_ref_sink (priv->css_provider);
Packit 1e8aac
Packit 1e8aac
      /* Set provider for default screen once */
Packit 1e8aac
      gtk_style_context_add_provider_for_screen (gdk_screen_get_default (),
Packit 1e8aac
                                                 GTK_STYLE_PROVIDER (priv->css_provider),
Packit 1e8aac
                                                 GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
Packit 1e8aac
    }
Packit 1e8aac
Packit 1e8aac
  priv->css_monitor = g_file_monitor_file (file, G_FILE_MONITOR_NONE, NULL, &error);
Packit 1e8aac
  if (error)
Packit 1e8aac
    {
Packit 1e8aac
      g_warning ("Cant monitor CSS file %s: %s", css_file, error->message);
Packit 1e8aac
      g_error_free (error);
Packit 1e8aac
    }
Packit 1e8aac
  else
Packit 1e8aac
    {
Packit 1e8aac
      g_object_ref_sink (priv->css_monitor);
Packit 1e8aac
      g_signal_connect (priv->css_monitor, "changed",
Packit 1e8aac
                        G_CALLBACK (on_css_monitor_changed), preview);
Packit 1e8aac
    }
Packit 1e8aac
Packit 1e8aac
  /* load CSS */
Packit 1e8aac
  gtk_css_provider_load_from_file (priv->css_provider, file, &error);
Packit 1e8aac
  if (error)
Packit 1e8aac
    {
Packit 1e8aac
      glade_previewer_set_message (preview, GTK_MESSAGE_INFO, error->message);
Packit 1e8aac
      g_message ("%s CSS parsing failed: %s", css_file, error->message);
Packit 1e8aac
      g_error_free (error);
Packit 1e8aac
    }
Packit 1e8aac
  
Packit 1e8aac
  g_object_unref (file);
Packit 1e8aac
}
Packit 1e8aac
Packit 1e8aac
void
Packit 1e8aac
glade_previewer_set_screenshot_extension (GladePreviewer *preview,
Packit 1e8aac
                                          const gchar    *extension)
Packit 1e8aac
{
Packit 1e8aac
  GladePreviewerPrivate *priv;
Packit 1e8aac
Packit 1e8aac
  g_return_if_fail (GLADE_IS_PREVIEWER (preview));
Packit 1e8aac
  priv = preview->priv;
Packit 1e8aac
Packit 1e8aac
  g_free (priv->extension);
Packit 1e8aac
  priv->extension = g_strdup (extension);
Packit 1e8aac
}
Packit 1e8aac
Packit 1e8aac
static gboolean
Packit 1e8aac
quit_when_idle (gpointer loop)
Packit 1e8aac
{
Packit 1e8aac
  g_main_loop_quit (loop);
Packit 1e8aac
Packit 1e8aac
  return G_SOURCE_REMOVE;
Packit 1e8aac
}
Packit 1e8aac
Packit 1e8aac
static void
Packit 1e8aac
check_for_draw (GdkEvent *event, gpointer loop)
Packit 1e8aac
{
Packit 1e8aac
  if (event->type == GDK_EXPOSE)
Packit 1e8aac
    {
Packit 1e8aac
      g_idle_add (quit_when_idle, loop);
Packit 1e8aac
      gdk_event_handler_set ((GdkEventFunc) gtk_main_do_event, NULL, NULL);
Packit 1e8aac
    }
Packit 1e8aac
Packit 1e8aac
  gtk_main_do_event (event);
Packit 1e8aac
}
Packit 1e8aac
Packit 1e8aac
/* Taken from Gtk sources gtk-reftest.c  */
Packit 1e8aac
static void
Packit 1e8aac
glade_previewer_wait_for_drawing (GdkWindow *window)
Packit 1e8aac
{
Packit 1e8aac
  GMainLoop *loop;
Packit 1e8aac
Packit 1e8aac
  loop = g_main_loop_new (NULL, FALSE);
Packit 1e8aac
  /* We wait until the widget is drawn for the first time.
Packit 1e8aac
   * We can not wait for a GtkWidget::draw event, because that might not
Packit 1e8aac
   * happen if the window is fully obscured by windowed child widgets.
Packit 1e8aac
   * Alternatively, we could wait for an expose event on widget's window.
Packit 1e8aac
   * Both of these are rather hairy, not sure what's best. */
Packit 1e8aac
  gdk_event_handler_set (check_for_draw, loop, NULL);
Packit 1e8aac
  g_main_loop_run (loop);
Packit 1e8aac
Packit 1e8aac
  /* give the WM/server some time to sync. They need it.
Packit 1e8aac
   * Also, do use popups instead of toplevls in your tests
Packit 1e8aac
   * whenever you can. */
Packit 1e8aac
  gdk_display_sync (gdk_window_get_display (window));
Packit 1e8aac
  g_timeout_add (500, quit_when_idle, loop);
Packit 1e8aac
  g_main_loop_run (loop);
Packit 1e8aac
}
Packit 1e8aac
Packit 1e8aac
static const gchar *
Packit 1e8aac
glade_previewer_get_extension (const gchar *filename)
Packit 1e8aac
{
Packit 1e8aac
  gchar *extension;
Packit 1e8aac
  
Packit 1e8aac
  g_return_val_if_fail (filename != NULL, NULL);
Packit 1e8aac
Packit 1e8aac
  extension = g_strrstr (filename,".");
Packit 1e8aac
Packit 1e8aac
  if (extension)
Packit 1e8aac
    extension++;
Packit 1e8aac
Packit 1e8aac
  if (!extension)
Packit 1e8aac
    {
Packit 1e8aac
      g_warning ("%s has no extension!", filename);
Packit 1e8aac
      return NULL;
Packit 1e8aac
    }
Packit 1e8aac
  return extension;
Packit 1e8aac
}
Packit 1e8aac
Packit 1e8aac
static void
Packit 1e8aac
glade_previewer_get_scale (GdkScreen *screen, gdouble *sx, gdouble *sy)
Packit 1e8aac
{
Packit 1e8aac
  if (sx)
Packit 1e8aac
    *sx = 72.0 / (gdk_screen_get_width (screen) / (gdk_screen_get_width_mm (screen) * 0.03937008));
Packit 1e8aac
Packit 1e8aac
  if (sy)
Packit 1e8aac
    *sy = 72.0 / (gdk_screen_get_height (screen) / (gdk_screen_get_height_mm (screen) * 0.03937008));
Packit 1e8aac
}
Packit 1e8aac
Packit 1e8aac
static cairo_surface_t *
Packit 1e8aac
glade_previewer_surface_from_file (const gchar *filename, gdouble w, gdouble h)
Packit 1e8aac
{
Packit 1e8aac
  cairo_surface_t *surface;
Packit 1e8aac
  const gchar *extension;
Packit 1e8aac
Packit 1e8aac
  extension = glade_previewer_get_extension (filename);
Packit 1e8aac
  
Packit 1e8aac
  if (extension == NULL)
Packit 1e8aac
    return NULL;
Packit 1e8aac
Packit 1e8aac
  if (g_strcmp0 (extension, "svg") == 0)
Packit 1e8aac
#if CAIRO_HAS_SVG_SURFACE
Packit 1e8aac
    surface = cairo_svg_surface_create (filename, w, h);
Packit 1e8aac
#else
Packit 1e8aac
    g_warning ("PDF not supported by the cairo version used");
Packit 1e8aac
#endif
Packit 1e8aac
  else if (g_strcmp0 (extension, "ps") == 0)
Packit 1e8aac
#if CAIRO_HAS_PS_SURFACE
Packit 1e8aac
    surface = cairo_ps_surface_create (filename, w, h);
Packit 1e8aac
#else
Packit 1e8aac
    g_warning ("PS not supported by the cairo version used");
Packit 1e8aac
#endif
Packit 1e8aac
  else if (g_strcmp0 (extension, "pdf") == 0)
Packit 1e8aac
#if CAIRO_HAS_PDF_SURFACE
Packit 1e8aac
    surface = cairo_pdf_surface_create (filename, w, h);
Packit 1e8aac
#else
Packit 1e8aac
    g_warning ("PDF not supported by the cairo version used");
Packit 1e8aac
#endif
Packit 1e8aac
  else
Packit 1e8aac
    return NULL;
Packit 1e8aac
Packit 1e8aac
  return surface;
Packit 1e8aac
}
Packit 1e8aac
Packit 1e8aac
/**
Packit 1e8aac
 * glade_previewer_screenshot:
Packit 1e8aac
 * @preview: A GladePreviewer
Packit 1e8aac
 * @wait: True if it should wait for widget to draw.
Packit 1e8aac
 * @filename:  a filename to save the image.
Packit 1e8aac
 * 
Packit 1e8aac
 * Takes a screenshot of the current widget @window is showing and save it to @filename
Packit 1e8aac
 * Supported extension are svg, ps, pdf and wahtever gdk-pixbuf supports 
Packit 1e8aac
 */
Packit 1e8aac
void
Packit 1e8aac
glade_previewer_screenshot (GladePreviewer *preview,
Packit 1e8aac
                            gboolean        wait,
Packit 1e8aac
                            const gchar    *filename)
Packit 1e8aac
{
Packit 1e8aac
  GladePreviewerPrivate *priv;
Packit 1e8aac
  cairo_surface_t *surface;
Packit 1e8aac
  GdkWindow *gdkwindow;
Packit 1e8aac
  GdkScreen *screen;
Packit 1e8aac
  gdouble sx, sy;
Packit 1e8aac
  gint w, h;
Packit 1e8aac
Packit 1e8aac
  g_return_if_fail (GLADE_IS_PREVIEWER (preview));
Packit 1e8aac
  g_return_if_fail (filename != NULL);
Packit 1e8aac
  priv = preview->priv;
Packit 1e8aac
Packit 1e8aac
  if (!priv->widget)
Packit 1e8aac
    return;
Packit 1e8aac
Packit 1e8aac
  gdkwindow = gtk_widget_get_window (priv->widget);
Packit 1e8aac
  screen = gdk_window_get_screen (gdkwindow);
Packit 1e8aac
Packit 1e8aac
  if (wait)
Packit 1e8aac
    glade_previewer_wait_for_drawing (gdkwindow);
Packit 1e8aac
Packit 1e8aac
  w = gtk_widget_get_allocated_width (priv->widget);
Packit 1e8aac
  h = gtk_widget_get_allocated_height (priv->widget);
Packit 1e8aac
  glade_previewer_get_scale (screen, &sx, &sy;;
Packit 1e8aac
    
Packit 1e8aac
  surface = glade_previewer_surface_from_file (filename, w*sx, h*sy);
Packit 1e8aac
Packit 1e8aac
  if (surface)
Packit 1e8aac
    {
Packit 1e8aac
      cairo_t *cr = cairo_create (surface);
Packit 1e8aac
      cairo_scale (cr, sx, sy);
Packit 1e8aac
      gtk_widget_draw (priv->widget, cr);
Packit 1e8aac
      cairo_destroy (cr);
Packit 1e8aac
      cairo_surface_destroy(surface);
Packit 1e8aac
    }
Packit 1e8aac
  else
Packit 1e8aac
    {
Packit 1e8aac
      GdkPixbuf *pix = gdk_pixbuf_get_from_window (gdkwindow, 0, 0, w, h);
Packit 1e8aac
      const gchar *ext = glade_previewer_get_extension (filename);
Packit 1e8aac
      GError *error = NULL;
Packit 1e8aac
      
Packit 1e8aac
      if (!gdk_pixbuf_save (pix, filename, ext ? ext : "png", &error, NULL))
Packit 1e8aac
        {
Packit 1e8aac
          g_warning ("Could not save screenshot to %s because %s", filename, error->message);
Packit 1e8aac
          g_error_free (error);
Packit 1e8aac
        }
Packit 1e8aac
Packit 1e8aac
      g_object_unref (pix);
Packit 1e8aac
    }
Packit 1e8aac
}
Packit 1e8aac
Packit 1e8aac
static gint
Packit 1e8aac
objects_cmp_func (gconstpointer a, gconstpointer b)
Packit 1e8aac
{
Packit 1e8aac
  const gchar *name_a, *name_b;
Packit 1e8aac
  name_a = gtk_buildable_get_name (GTK_BUILDABLE (a));
Packit 1e8aac
  name_b = gtk_buildable_get_name (GTK_BUILDABLE (b));
Packit 1e8aac
  return g_strcmp0 (name_a, name_b);
Packit 1e8aac
}
Packit 1e8aac
Packit 1e8aac
/**
Packit 1e8aac
 * glade_previewer_set_slideshow_widgets:
Packit 1e8aac
 * @preview: A GladePreviewer
Packit 1e8aac
 * @objects: GSlist of GObject
Packit 1e8aac
 * 
Packit 1e8aac
 * Add a list of objects to slideshow
Packit 1e8aac
 */
Packit 1e8aac
void
Packit 1e8aac
glade_previewer_set_slideshow_widgets (GladePreviewer *preview,
Packit 1e8aac
                                      GSList          *objects)
Packit 1e8aac
{
Packit 1e8aac
  GladePreviewerPrivate *priv;
Packit 1e8aac
  GtkStack *stack;
Packit 1e8aac
  GSList *l;
Packit 1e8aac
Packit 1e8aac
  g_return_if_fail (GLADE_IS_PREVIEWER (preview));
Packit 1e8aac
  priv = preview->priv;
Packit 1e8aac
Packit 1e8aac
  stack = GTK_STACK (gtk_stack_new ());
Packit 1e8aac
  gtk_stack_set_transition_type (stack, GTK_STACK_TRANSITION_TYPE_CROSSFADE);
Packit 1e8aac
Packit 1e8aac
  objects = g_slist_sort (g_slist_copy (objects), objects_cmp_func);
Packit 1e8aac
Packit 1e8aac
  for (l = objects; l; l = g_slist_next (l))
Packit 1e8aac
    {
Packit 1e8aac
       GObject *obj = l->data;
Packit 1e8aac
Packit 1e8aac
       if (!GTK_IS_WIDGET (obj) || gtk_widget_get_parent (GTK_WIDGET (obj)))
Packit 1e8aac
         continue;
Packit 1e8aac
Packit 1e8aac
       /* TODO: make sure we can add a toplevel inside a stack */
Packit 1e8aac
       if (GTK_IS_WINDOW (obj))
Packit 1e8aac
         continue;
Packit 1e8aac
Packit 1e8aac
       priv->objects = g_list_prepend (priv->objects, obj);
Packit 1e8aac
Packit 1e8aac
       gtk_stack_add_named (stack, GTK_WIDGET (obj),
Packit 1e8aac
                            gtk_buildable_get_name (GTK_BUILDABLE (obj)));
Packit 1e8aac
    }
Packit 1e8aac
Packit 1e8aac
  priv->objects = g_list_reverse (priv->objects); 
Packit 1e8aac
Packit 1e8aac
  glade_previewer_set_widget (preview, GTK_WIDGET (stack));
Packit 1e8aac
  gtk_widget_show (GTK_WIDGET (stack));
Packit 1e8aac
  
Packit 1e8aac
  g_slist_free (objects);
Packit 1e8aac
}
Packit 1e8aac
Packit 1e8aac
/**
Packit 1e8aac
 * glade_previewer_slideshow_save:
Packit 1e8aac
 * @preview: A GladePreviewer
Packit 1e8aac
 * @filename:  a filename to save the slideshow.
Packit 1e8aac
 * 
Packit 1e8aac
 * Takes a screenshot of every widget GtkStack children and save it to @filename
Packit 1e8aac
 * each in a different page
Packit 1e8aac
 */
Packit 1e8aac
void
Packit 1e8aac
glade_previewer_slideshow_save (GladePreviewer *preview,
Packit 1e8aac
                                const gchar    *filename)
Packit 1e8aac
{
Packit 1e8aac
  GladePreviewerPrivate *priv;
Packit 1e8aac
  cairo_surface_t *surface;
Packit 1e8aac
  GdkWindow *gdkwindow;
Packit 1e8aac
  GtkWidget *child;
Packit 1e8aac
  GtkStack *stack;
Packit 1e8aac
  gdouble sx, sy;
Packit 1e8aac
Packit 1e8aac
  g_return_if_fail (GLADE_IS_PREVIEWER (preview));
Packit 1e8aac
  g_return_if_fail (filename != NULL);
Packit 1e8aac
  priv = preview->priv;
Packit 1e8aac
Packit 1e8aac
  g_return_if_fail (GTK_IS_BIN (priv->widget));
Packit 1e8aac
Packit 1e8aac
  child = gtk_bin_get_child (GTK_BIN (priv->widget));
Packit 1e8aac
  g_return_if_fail (GTK_IS_STACK (child));
Packit 1e8aac
  stack = GTK_STACK (child);
Packit 1e8aac
Packit 1e8aac
  gtk_stack_set_transition_type (stack, GTK_STACK_TRANSITION_TYPE_NONE);
Packit 1e8aac
Packit 1e8aac
  gdkwindow = gtk_widget_get_window (priv->widget);
Packit 1e8aac
  glade_previewer_wait_for_drawing (gdkwindow);
Packit 1e8aac
  
Packit 1e8aac
  glade_previewer_get_scale (gtk_widget_get_screen (GTK_WIDGET (priv->widget)), &sx, &sy;; 
Packit 1e8aac
  surface = glade_previewer_surface_from_file (filename, 
Packit 1e8aac
                                             gtk_widget_get_allocated_width (GTK_WIDGET (stack))*sx,
Packit 1e8aac
                                             gtk_widget_get_allocated_height (GTK_WIDGET (stack))*sy);
Packit 1e8aac
Packit 1e8aac
  if (surface)
Packit 1e8aac
    {
Packit 1e8aac
      GList *l, *children = gtk_container_get_children (GTK_CONTAINER (stack));
Packit 1e8aac
      cairo_t *cr= cairo_create (surface);
Packit 1e8aac
Packit 1e8aac
      cairo_scale (cr, sx, sy);
Packit 1e8aac
Packit 1e8aac
      for (l = children; l; l = g_list_next (l))
Packit 1e8aac
        {
Packit 1e8aac
          GtkWidget *child = l->data;
Packit 1e8aac
          gtk_stack_set_visible_child (stack, child);
Packit 1e8aac
          glade_previewer_wait_for_drawing (gdkwindow);
Packit 1e8aac
          gtk_widget_draw (child, cr);
Packit 1e8aac
          cairo_show_page (cr);
Packit 1e8aac
        }
Packit 1e8aac
Packit 1e8aac
      if (children)
Packit 1e8aac
        gtk_stack_set_visible_child (stack, children->data);
Packit 1e8aac
Packit 1e8aac
      g_list_free (children);
Packit 1e8aac
      cairo_destroy (cr);
Packit 1e8aac
      cairo_surface_destroy(surface);
Packit 1e8aac
    }
Packit 1e8aac
  else
Packit 1e8aac
    g_warning ("Could not save slideshow to %s", filename);
Packit 1e8aac
}
Packit 1e8aac
Packit 1e8aac
/**
Packit 1e8aac
 * glade_previewer_set_print_handlers:
Packit 1e8aac
 * @preview: A GladePreviewer
Packit 1e8aac
 * @print: whether to print handlers or not
Packit 1e8aac
 * 
Packit 1e8aac
 * Set whether to print handlers when they are activated or not.
Packit 1e8aac
 * It only works if you use glade_previewer_connect_function() as the 
Packit 1e8aac
 * connect funtion.
Packit 1e8aac
 */
Packit 1e8aac
void
Packit 1e8aac
glade_previewer_set_print_handlers (GladePreviewer *preview,
Packit 1e8aac
                                    gboolean        print)
Packit 1e8aac
{
Packit 1e8aac
  g_return_if_fail (GLADE_IS_PREVIEWER (preview));
Packit 1e8aac
  preview->priv->print_handlers = print;
Packit 1e8aac
}
Packit 1e8aac
Packit 1e8aac
typedef struct
Packit 1e8aac
{
Packit 1e8aac
  gchar        *handler_name;
Packit 1e8aac
  GObject      *connect_object;
Packit 1e8aac
  GConnectFlags flags;
Packit 1e8aac
} HandlerData;
Packit 1e8aac
Packit 1e8aac
typedef struct
Packit 1e8aac
{
Packit 1e8aac
  GladePreviewer *window;
Packit 1e8aac
  gint          n_invocations;
Packit 1e8aac
Packit 1e8aac
  GSignalQuery  query;
Packit 1e8aac
  GObject      *object;
Packit 1e8aac
  GList        *handlers;
Packit 1e8aac
} SignalData;
Packit 1e8aac
Packit 1e8aac
static void
Packit 1e8aac
handler_data_free (gpointer udata)
Packit 1e8aac
{
Packit 1e8aac
  HandlerData *hd = udata;
Packit 1e8aac
  g_clear_object (&hd->connect_object);
Packit 1e8aac
  g_free (hd->handler_name);
Packit 1e8aac
  g_free (hd);
Packit 1e8aac
}
Packit 1e8aac
Packit 1e8aac
static void
Packit 1e8aac
signal_data_free (gpointer udata, GClosure *closure)
Packit 1e8aac
{
Packit 1e8aac
  SignalData *data = udata;
Packit 1e8aac
Packit 1e8aac
  g_list_free_full (data->handlers, handler_data_free);
Packit 1e8aac
  data->handlers = NULL;
Packit 1e8aac
Packit 1e8aac
  g_clear_object (&data->window);
Packit 1e8aac
  g_clear_object (&data->object);
Packit 1e8aac
Packit 1e8aac
  g_free (data);
Packit 1e8aac
}
Packit 1e8aac
Packit 1e8aac
static inline const gchar *
Packit 1e8aac
object_get_name (GObject *object)
Packit 1e8aac
{
Packit 1e8aac
  if (GTK_IS_BUILDABLE (object))
Packit 1e8aac
    return gtk_buildable_get_name (GTK_BUILDABLE (object));
Packit 1e8aac
  else
Packit 1e8aac
    return g_object_get_data (object, "gtk-builder-name");
Packit 1e8aac
}
Packit 1e8aac
Packit 1e8aac
static void
Packit 1e8aac
glade_handler_append (GString      *message,
Packit 1e8aac
                      GSignalQuery *query,
Packit 1e8aac
                      const gchar  *object,
Packit 1e8aac
                      GList        *handlers,
Packit 1e8aac
                      gboolean     after)
Packit 1e8aac
{
Packit 1e8aac
  GList *l;
Packit 1e8aac
Packit 1e8aac
  for (l = handlers; l; l = g_list_next (l))
Packit 1e8aac
    {
Packit 1e8aac
      HandlerData *hd = l->data;
Packit 1e8aac
      gboolean handler_after = (hd->flags & G_CONNECT_AFTER);
Packit 1e8aac
      gboolean swapped = (hd->flags & G_CONNECT_SWAPPED);
Packit 1e8aac
      GObject *obj = hd->connect_object;
Packit 1e8aac
      gint i;
Packit 1e8aac
Packit 1e8aac
      if ((after && !handler_after) || (!after && handler_after))
Packit 1e8aac
        continue;
Packit 1e8aac
Packit 1e8aac
      g_string_append_printf (message, "\n\t-> %s%s %s (%s%s%s",
Packit 1e8aac
                              g_type_name (query->return_type),
Packit 1e8aac
                              g_type_is_a (query->return_type, G_TYPE_OBJECT) ? " *" : "",
Packit 1e8aac
                              hd->handler_name,
Packit 1e8aac
                              (swapped) ? ((obj) ? G_OBJECT_TYPE_NAME (obj) : "") : g_type_name (query->itype),
Packit 1e8aac
                              (swapped) ? ((obj) ? " *" : "") : " *",
Packit 1e8aac
                              (swapped) ? ((obj) ? object_get_name (obj) : _("user_data")) : object);
Packit 1e8aac
Packit 1e8aac
      for (i = 1; i < query->n_params; i++)
Packit 1e8aac
        g_string_append_printf (message, ", %s%s", 
Packit 1e8aac
                                g_type_name (query->param_types[i]),
Packit 1e8aac
                                g_type_is_a (query->param_types[i], G_TYPE_OBJECT) ? " *" : "");
Packit 1e8aac
Packit 1e8aac
      g_string_append_printf (message, ", %s%s%s); ",
Packit 1e8aac
                              (swapped) ? g_type_name (query->itype) : ((obj) ? G_OBJECT_TYPE_NAME (obj) : ""),
Packit 1e8aac
                              (swapped) ? " *" : ((obj) ? " *" : ""),
Packit 1e8aac
                              (swapped) ? object : ((obj) ? object_get_name (obj) : _("user_data")));
Packit 1e8aac
Packit 1e8aac
      if (swapped && after)
Packit 1e8aac
        /* translators: GConnectFlags values */
Packit 1e8aac
        g_string_append (message, _("Swapped | After"));
Packit 1e8aac
      else if (swapped)
Packit 1e8aac
        /* translators: GConnectFlags value */
Packit 1e8aac
        g_string_append (message, _("Swapped"));
Packit 1e8aac
      else if (after)
Packit 1e8aac
        /* translators: GConnectFlags value */
Packit 1e8aac
        g_string_append (message, _("After"));
Packit 1e8aac
    }
Packit 1e8aac
}
Packit 1e8aac
Packit 1e8aac
static inline void
Packit 1e8aac
glade_handler_method_append (GString *msg, GSignalQuery *q, const gchar *flags)
Packit 1e8aac
{
Packit 1e8aac
  g_string_append_printf (msg, "\n\t%sClass->%s(); %s", g_type_name (q->itype),
Packit 1e8aac
                          q->signal_name, flags);
Packit 1e8aac
}
Packit 1e8aac
Packit 1e8aac
static void
Packit 1e8aac
on_handler_called (SignalData *data)
Packit 1e8aac
{
Packit 1e8aac
  GSignalQuery *query = &data->query;
Packit 1e8aac
  GObject *object = data->object;
Packit 1e8aac
  const gchar *object_name = object_get_name (object);
Packit 1e8aac
  GString *message = g_string_new ("");
Packit 1e8aac
Packit 1e8aac
  data->n_invocations++;
Packit 1e8aac
Packit 1e8aac
  if (data->n_invocations == 1)
Packit 1e8aac
    /* translators: this will be shown in glade previewer when a signal %s::%s is emited one time */
Packit 1e8aac
    g_string_append_printf (message, _("%s::%s emitted one time"),
Packit 1e8aac
                            G_OBJECT_TYPE_NAME (object), query->signal_name);
Packit 1e8aac
  else
Packit 1e8aac
    /* translators: this will be shown in glade previewer when a signal %s::%s is emited %d times */
Packit 1e8aac
    g_string_append_printf (message, _("%s::%s emitted %d times"),
Packit 1e8aac
                            G_OBJECT_TYPE_NAME (object), query->signal_name,
Packit 1e8aac
                            data->n_invocations);
Packit 1e8aac
Packit 1e8aac
  if (query->signal_flags & G_SIGNAL_RUN_FIRST)
Packit 1e8aac
    glade_handler_method_append (message, query, _("Run First"));
Packit 1e8aac
Packit 1e8aac
  glade_handler_append (message, query, object_name, data->handlers, FALSE);
Packit 1e8aac
Packit 1e8aac
  if (query->signal_flags & G_SIGNAL_RUN_LAST)
Packit 1e8aac
    glade_handler_method_append (message, query, _("Run Last"));
Packit 1e8aac
Packit 1e8aac
  glade_handler_append (message, query, object_name, data->handlers, TRUE);
Packit 1e8aac
Packit 1e8aac
  if (query->signal_flags & G_SIGNAL_RUN_CLEANUP)
Packit 1e8aac
    glade_handler_method_append (message, query, _("Run Cleanup"));
Packit 1e8aac
Packit 1e8aac
  glade_previewer_set_message (data->window, GTK_MESSAGE_INFO, message->str);
Packit 1e8aac
Packit 1e8aac
  if (data->window->priv->print_handlers)
Packit 1e8aac
    g_printf ("\n%s\n", message->str);
Packit 1e8aac
Packit 1e8aac
  g_string_free (message, TRUE);
Packit 1e8aac
}
Packit 1e8aac
Packit 1e8aac
/**
Packit 1e8aac
 * glade_previewer_connect_function:
Packit 1e8aac
 * @builder:
Packit 1e8aac
 * @object:
Packit 1e8aac
 * @signal_name:
Packit 1e8aac
 * @handler_name:
Packit 1e8aac
 * @connect_object:
Packit 1e8aac
 * @flags:
Packit 1e8aac
 * @window: a #GladePreviewer
Packit 1e8aac
 * 
Packit 1e8aac
 * Function that collects every signal handler in @builder and shows them
Packit 1e8aac
 * in @window info bar when the callback is activated
Packit 1e8aac
 */
Packit 1e8aac
void
Packit 1e8aac
glade_previewer_connect_function (GtkBuilder   *builder,
Packit 1e8aac
                                  GObject      *object,
Packit 1e8aac
                                  const gchar  *signal_name,
Packit 1e8aac
                                  const gchar  *handler_name,
Packit 1e8aac
                                  GObject      *connect_object,
Packit 1e8aac
                                  GConnectFlags flags,
Packit 1e8aac
                                  gpointer      window)
Packit 1e8aac
{
Packit 1e8aac
  SignalData *data;
Packit 1e8aac
  HandlerData *hd;
Packit 1e8aac
  guint signal_id;
Packit 1e8aac
  gchar *key;
Packit 1e8aac
Packit 1e8aac
  g_return_if_fail (GLADE_IS_PREVIEWER (window));
Packit 1e8aac
Packit 1e8aac
  if (!(signal_id = g_signal_lookup (signal_name, G_OBJECT_TYPE (object))))
Packit 1e8aac
    return;
Packit 1e8aac
Packit 1e8aac
  key = g_strconcat ("glade-signal-data-", signal_name, NULL);
Packit 1e8aac
  data = g_object_get_data (object, key);
Packit 1e8aac
Packit 1e8aac
  if (!data)
Packit 1e8aac
    {
Packit 1e8aac
      data = g_new0 (SignalData, 1);
Packit 1e8aac
Packit 1e8aac
      data->window = g_object_ref (window);
Packit 1e8aac
      g_signal_query (signal_id, &data->query);
Packit 1e8aac
      data->object = g_object_ref (object);
Packit 1e8aac
Packit 1e8aac
      g_signal_connect_data (object, signal_name,
Packit 1e8aac
                             G_CALLBACK (on_handler_called),
Packit 1e8aac
                             data, signal_data_free, G_CONNECT_SWAPPED);
Packit 1e8aac
Packit 1e8aac
      g_object_set_data (object, key, data);
Packit 1e8aac
    }
Packit 1e8aac
Packit 1e8aac
  hd = g_new0 (HandlerData, 1);
Packit 1e8aac
  hd->handler_name = g_strdup (handler_name);
Packit 1e8aac
  hd->connect_object = connect_object ? g_object_ref (connect_object) : NULL;
Packit 1e8aac
  hd->flags = flags;
Packit 1e8aac
Packit 1e8aac
  data->handlers = g_list_append (data->handlers, hd);
Packit 1e8aac
Packit 1e8aac
  g_free (key);
Packit 1e8aac
}