[glade] GladePreviewer: show handler information in infobar when a signal is emited. Added --print-handler o
- From: Juan Pablo Ugarte <jpu src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [glade] GladePreviewer: show handler information in infobar when a signal is emited. Added --print-handler o
- Date: Fri, 9 May 2014 17:34:01 +0000 (UTC)
commit 9d5780dc7797195e3c004cc5ec4c4b3b33d2118e
Author: Juan Pablo Ugarte <juanpablougarte gmail com>
Date: Fri May 9 14:28:32 2014 -0300
GladePreviewer: show handler information in infobar when a signal is emited.
Added --print-handler option (print handlers info on stdout)
gladeui/glade-preview-template.c | 25 ++++-
gladeui/glade-preview-template.h | 5 +-
gladeui/glade-preview-window.c | 240 +++++++++++++++++++++++++++++++++++++-
gladeui/glade-preview-window.h | 11 ++
gladeui/glade-previewer.c | 29 ++++-
5 files changed, 295 insertions(+), 15 deletions(-)
---
diff --git a/gladeui/glade-preview-template.c b/gladeui/glade-preview-template.c
index 1f9cdb8..b7d18a9 100644
--- a/gladeui/glade-preview-template.c
+++ b/gladeui/glade-preview-template.c
@@ -32,6 +32,9 @@ typedef struct
GTypeInfo info;
GString *template_string;
GBytes *template_data;
+
+ GtkBuilderConnectFunc connect_func;
+ gpointer connect_data;
gint count;
} TypeData;
@@ -61,8 +64,13 @@ static void
template_class_init (gpointer g_class, gpointer user_data)
{
TypeData *data = user_data;
+
gtk_widget_class_set_template (g_class, data->template_data);
- gtk_widget_class_set_connect_func (g_class, template_connect_function, NULL, NULL);
+
+ if (data->connect_func && data->connect_data)
+ gtk_widget_class_set_connect_func (g_class, data->connect_func, data->connect_data, NULL);
+ else
+ gtk_widget_class_set_connect_func (g_class, template_connect_function, NULL, NULL);
}
static GQuark type_data_quark = 0;
@@ -70,7 +78,9 @@ static GQuark type_data_quark = 0;
static GType
template_generate_type (const gchar *name,
const gchar *parent_name,
- GString *template_string)
+ GString *template_string,
+ GtkBuilderConnectFunc connect_func,
+ gpointer connect_data)
{
GType parent_type, retval;
gchar *real_name = NULL;
@@ -124,6 +134,8 @@ template_generate_type (const gchar *name,
data->info.instance_init = template_init;
data->info.class_data = data;
data->template_data = g_bytes_new_static (template_string->str, template_string->len);
+ data->connect_func = connect_func;
+ data->connect_data = connect_data;
retval = g_type_register_static (parent_type, real_name ? real_name : name, &data->info, 0);
@@ -237,7 +249,10 @@ passthrough (GMarkupParseContext *context,
}
GObject *
-glade_preview_template_object_new (const gchar *template_data, gsize len)
+glade_preview_template_object_new (const gchar *template_data,
+ gsize len,
+ GtkBuilderConnectFunc connect_func,
+ gpointer connect_data)
{
GMarkupParser parser = { start_element, end_element, text, passthrough};
ParseData state = { FALSE, NULL};
@@ -264,7 +279,9 @@ glade_preview_template_object_new (const gchar *template_data, gsize len)
{
GType template_type = template_generate_type (state.klass,
state.parent,
- state.xml);
+ state.xml,
+ connect_func,
+ connect_data);
if (template_type)
object = g_object_new (template_type, NULL);
else
diff --git a/gladeui/glade-preview-template.h b/gladeui/glade-preview-template.h
index 9c5fda9..14cd759 100644
--- a/gladeui/glade-preview-template.h
+++ b/gladeui/glade-preview-template.h
@@ -29,7 +29,10 @@
G_BEGIN_DECLS
GObject *
-glade_preview_template_object_new (const gchar *template_data, gsize len);
+glade_preview_template_object_new (const gchar *template_data,
+ gsize len,
+ GtkBuilderConnectFunc connect_func,
+ gpointer connect_data);
G_END_DECLS
diff --git a/gladeui/glade-preview-window.c b/gladeui/glade-preview-window.c
index cb2bfd6..651bc95 100644
--- a/gladeui/glade-preview-window.c
+++ b/gladeui/glade-preview-window.c
@@ -1,7 +1,7 @@
/*
* glade-preview-window.c
*
- * Copyright (C) 2013 Juan Pablo Ugarte
+ * Copyright (C) 2013-2014 Juan Pablo Ugarte
*
* Author: Juan Pablo Ugarte <juanpablougarte gmail com>
*
@@ -24,6 +24,7 @@
#include "glade-preview-window.h"
#include <glib/gi18n-lib.h>
+#include <glib/gprintf.h>
#include <cairo-pdf.h>
#include <cairo-svg.h>
#include <cairo-ps.h>
@@ -39,6 +40,7 @@ struct _GladePreviewWindowPrivate
GFileMonitor *css_monitor;
gchar *css_file;
gchar *extension;
+ gboolean print_handlers;
};
G_DEFINE_TYPE_WITH_PRIVATE (GladePreviewWindow, glade_preview_window, GTK_TYPE_WINDOW);
@@ -77,14 +79,25 @@ glade_preview_window_init (GladePreviewWindow *window)
}
static void
-glade_preview_window_finalize (GObject *object)
+glade_preview_window_dispose (GObject *object)
{
GladePreviewWindowPrivate *priv = GLADE_PREVIEW_WINDOW (object)->priv;
- g_free (priv->css_file);
+ priv->info = NULL;
g_clear_object (&priv->css_provider);
g_clear_object (&priv->css_monitor);
+ G_OBJECT_CLASS (glade_preview_window_parent_class)->dispose (object);
+}
+
+static void
+glade_preview_window_finalize (GObject *object)
+{
+ GladePreviewWindowPrivate *priv = GLADE_PREVIEW_WINDOW (object)->priv;
+
+ g_free (priv->css_file);
+ g_free (priv->extension);
+
G_OBJECT_CLASS (glade_preview_window_parent_class)->finalize (object);
}
@@ -158,6 +171,7 @@ glade_preview_window_class_init (GladePreviewWindowClass *klass)
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+ object_class->dispose = glade_preview_window_dispose;
object_class->finalize = glade_preview_window_finalize;
widget_class->realize = glade_preview_window_realize;
@@ -222,6 +236,9 @@ glade_preview_window_set_message (GladePreviewWindow *window,
g_return_if_fail (GLADE_IS_PREVIEW_WINDOW (window));
priv = window->priv;
+ if (!priv->info)
+ return;
+
gtk_info_bar_set_message_type (GTK_INFO_BAR (priv->info), type);
if (message)
@@ -551,3 +568,220 @@ glade_preview_window_slideshow_save (GladePreviewWindow *window,
else
g_warning ("Could not save slideshow to %s", filename);
}
+
+/**
+ * glade_preview_window_set_print_handlers:
+ * @window: A GladePreviewWindow
+ * @print: whether to print handlers or not
+ *
+ * Set whether to print handlers when they are activated or not.
+ * It only works if you use glade_preview_window_connect_function() as the
+ * connect funtion.
+ */
+void
+glade_preview_window_set_print_handlers (GladePreviewWindow *window,
+ gboolean print)
+{
+ g_return_if_fail (GLADE_IS_PREVIEW_WINDOW (window));
+ window->priv->print_handlers = print;
+}
+
+typedef struct
+{
+ gchar *handler_name;
+ GObject *connect_object;
+ GConnectFlags flags;
+} HandlerData;
+
+typedef struct
+{
+ GladePreviewWindow *window;
+ gint n_invocations;
+
+ GSignalQuery query;
+ GObject *object;
+ GList *handlers;
+} SignalData;
+
+static void
+handler_data_free (gpointer udata)
+{
+ HandlerData *hd = udata;
+ g_clear_object (&hd->connect_object);
+ g_free (hd->handler_name);
+ g_free (hd);
+}
+
+static void
+signal_data_free (gpointer udata, GClosure *closure)
+{
+ SignalData *data = udata;
+
+ g_list_free_full (data->handlers, handler_data_free);
+ data->handlers = NULL;
+
+ g_clear_object (&data->window);
+ g_clear_object (&data->object);
+
+ g_free (data);
+}
+
+static inline const gchar *
+object_get_name (GObject *object)
+{
+ if (GTK_IS_BUILDABLE (object))
+ return gtk_buildable_get_name (GTK_BUILDABLE (object));
+ else
+ return g_object_get_data (object, "gtk-builder-name");
+}
+
+static void
+glade_handler_append (GString *message,
+ GSignalQuery *query,
+ const gchar *object,
+ GList *handlers,
+ gboolean after)
+{
+ GList *l;
+
+ for (l = handlers; l; l = g_list_next (l))
+ {
+ HandlerData *hd = l->data;
+ gboolean handler_after = (hd->flags & G_CONNECT_AFTER);
+ gboolean swapped = (hd->flags & G_CONNECT_SWAPPED);
+ GObject *obj = hd->connect_object;
+ gint i;
+
+ if ((after && !handler_after) || (!after && handler_after))
+ continue;
+
+ g_string_append_printf (message, "\n\t-> %s%s %s (%s%s%s",
+ g_type_name (query->return_type),
+ g_type_is_a (query->return_type, G_TYPE_OBJECT) ? " *" : "",
+ hd->handler_name,
+ (swapped) ? ((obj) ? G_OBJECT_TYPE_NAME (obj) : "") : g_type_name
(query->itype),
+ (swapped) ? ((obj) ? " *" : "") : " *",
+ (swapped) ? ((obj) ? object_get_name (obj) : _("user_data")) : object);
+
+ for (i = 1; i < query->n_params; i++)
+ g_string_append_printf (message, ", %s%s",
+ g_type_name (query->param_types[i]),
+ g_type_is_a (query->param_types[i], G_TYPE_OBJECT) ? " *" : "");
+
+ g_string_append_printf (message, ", %s%s%s); ",
+ (swapped) ? g_type_name (query->itype) : ((obj) ? G_OBJECT_TYPE_NAME (obj) :
""),
+ (swapped) ? " *" : ((obj) ? " *" : ""),
+ (swapped) ? object : ((obj) ? object_get_name (obj) : _("user_data")));
+
+ if (swapped && after)
+ /* translators: GConnectFlags values */
+ g_string_append (message, _("Swapped | After"));
+ else if (swapped)
+ /* translators: GConnectFlags value */
+ g_string_append (message, _("Swapped"));
+ else if (after)
+ /* translators: GConnectFlags value */
+ g_string_append (message, _("After"));
+ }
+}
+
+static inline void
+glade_handler_method_append (GString *msg, GSignalQuery *q, const gchar *flags)
+{
+ g_string_append_printf (msg, "\n\t%sClass->%s(); %s", g_type_name (q->itype),
+ q->signal_name, flags);
+}
+
+static void
+on_handler_called (SignalData *data)
+{
+ GSignalQuery *query = &data->query;
+ GObject *object = data->object;
+ const gchar *object_name = object_get_name (object);
+ GString *message = g_string_new ("");
+
+ /* translators: this will be shown in glade previewer when a signal %s::%s is emited %d times */
+ g_string_append_printf (message, _("%s::%s emited %d time(s)"),
+ G_OBJECT_TYPE_NAME (object), query->signal_name,
+ ++data->n_invocations);
+
+ if (query->signal_flags & G_SIGNAL_RUN_FIRST)
+ glade_handler_method_append (message, query, _("Run First"));
+
+ glade_handler_append (message, query, object_name, data->handlers, FALSE);
+
+ if (query->signal_flags & G_SIGNAL_RUN_LAST)
+ glade_handler_method_append (message, query, _("Run Last"));
+
+ glade_handler_append (message, query, object_name, data->handlers, TRUE);
+
+ if (query->signal_flags & G_SIGNAL_RUN_CLEANUP)
+ glade_handler_method_append (message, query, _("Run Cleanup"));
+
+ glade_preview_window_set_message (data->window, GTK_MESSAGE_INFO, message->str);
+
+ if (data->window->priv->print_handlers)
+ g_printf ("\n%s\n", message->str);
+
+ g_string_free (message, TRUE);
+}
+
+/**
+ * glade_preview_window_connect_function:
+ * @builder:
+ * @object:
+ * @signal_name:
+ * @handler_name:
+ * @connect_object:
+ * @flags:
+ * @window: a #GladePreviewWindow
+ *
+ * Function that collects every signal handler in @builder and shows them
+ * in @window info bar when the callback is activated
+ */
+void
+glade_preview_window_connect_function (GtkBuilder *builder,
+ GObject *object,
+ const gchar *signal_name,
+ const gchar *handler_name,
+ GObject *connect_object,
+ GConnectFlags flags,
+ gpointer window)
+{
+ SignalData *data;
+ HandlerData *hd;
+ guint signal_id;
+ gchar *key;
+
+ g_return_if_fail (GLADE_IS_PREVIEW_WINDOW (window));
+
+ if (!(signal_id = g_signal_lookup (signal_name, G_OBJECT_TYPE (object))))
+ return;
+
+ key = g_strconcat ("glade-signal-data-", signal_name, NULL);
+ data = g_object_get_data (object, key);
+
+ if (!data)
+ {
+ data = g_new0 (SignalData, 1);
+
+ data->window = g_object_ref (window);
+ g_signal_query (signal_id, &data->query);
+ data->object = g_object_ref (object);
+
+ g_signal_connect_data (object, signal_name,
+ G_CALLBACK (on_handler_called),
+ data, signal_data_free, G_CONNECT_SWAPPED);
+
+ g_object_set_data (object, key, data);
+ }
+
+ hd = g_new0 (HandlerData, 1);
+ hd->handler_name = g_strdup (handler_name);
+ hd->connect_object = connect_object ? g_object_ref (connect_object) : NULL;
+ hd->flags = flags;
+
+ data->handlers = g_list_append (data->handlers, hd);
+
+ g_free (key);
+}
diff --git a/gladeui/glade-preview-window.h b/gladeui/glade-preview-window.h
index 0ff2bdc..56276e7 100644
--- a/gladeui/glade-preview-window.h
+++ b/gladeui/glade-preview-window.h
@@ -59,6 +59,9 @@ GtkWidget *glade_preview_window_new (void);
void glade_preview_window_set_widget (GladePreviewWindow *window,
GtkWidget *widget);
+void glade_preview_window_set_print_handlers (GladePreviewWindow *window,
+ gboolean print);
+
void glade_preview_window_set_message (GladePreviewWindow *window,
GtkMessageType type,
const gchar *message);
@@ -76,6 +79,14 @@ void glade_preview_window_screenshot (GladePreviewWindow *window,
void glade_preview_window_slideshow_save (GladePreviewWindow *window,
const gchar *filename);
+void glade_preview_window_connect_function (GtkBuilder *builder,
+ GObject *object,
+ const gchar *signal_name,
+ const gchar *handler_name,
+ GObject *connect_object,
+ GConnectFlags flags,
+ gpointer window);
+
G_END_DECLS
#endif /* _GLADE_PREVIEW_WINDOW_H_ */
diff --git a/gladeui/glade-previewer.c b/gladeui/glade-previewer.c
index dc26cf8..9f51057 100644
--- a/gladeui/glade-previewer.c
+++ b/gladeui/glade-previewer.c
@@ -96,7 +96,7 @@ static GObject *
get_toplevel_from_string (GladePreviewer *app, gchar *name, gchar *string, gsize size)
{
gchar *wd = NULL;
- GObject *retval;
+ GObject *retval = NULL;
/* We need to change the working directory so builder get a chance to load resources */
if (app->file_name)
@@ -110,7 +110,10 @@ get_toplevel_from_string (GladePreviewer *app, gchar *name, gchar *string, gsize
/* We use template flag as a hint since the user can turn on and off template
* while the preview is live.
*/
- retval = (app->is_template) ? glade_preview_template_object_new (string, size) : NULL;
+ if (app->is_template)
+ retval = glade_preview_template_object_new (string, size,
+ glade_preview_window_connect_function,
+ app->window);
if (!retval)
{
@@ -121,11 +124,18 @@ get_toplevel_from_string (GladePreviewer *app, gchar *name, gchar *string, gsize
app->is_template = FALSE;
if (gtk_builder_add_from_string (builder, string, size, &error))
- retval = get_toplevel (builder, name);
+ {
+ gtk_builder_connect_signals_full (builder,
+ glade_preview_window_connect_function,
+ app->window);
+ retval = get_toplevel (builder, name);
+ }
else
{
if (error->code == GTK_BUILDER_ERROR_UNHANDLED_TAG &&
- (retval = glade_preview_template_object_new (string, size)))
+ (retval = glade_preview_template_object_new (string, size, NULL, NULL)
+ glade_preview_window_connect_function,
+ app->window)))
{
/* At this point we know it is a template, so keep a hint for next time */
app->is_template = TRUE;
@@ -367,6 +377,7 @@ static gboolean listen = FALSE;
static gboolean version = FALSE;
static gboolean slideshow = FALSE;
static gboolean template = FALSE;
+static gboolean print_handler = FALSE;
static gchar *file_name = NULL;
static gchar *toplevel_name = NULL;
static gchar *css_file_name = NULL;
@@ -381,6 +392,7 @@ static GOptionEntry option_entries[] =
{"css", 0, 0, G_OPTION_ARG_FILENAME, &css_file_name, N_("CSS file to use"), NULL},
{"listen", 'l', 0, G_OPTION_ARG_NONE, &listen, N_("Listen standard input"), NULL},
{"slideshow", 0, 0, G_OPTION_ARG_NONE, &slideshow, N_("make a slideshow of every toplevel widget by
adding them in a GtkStack"), NULL},
+ {"print-handler", 0, 0, G_OPTION_ARG_NONE, &print_handler, N_("Print handlers signature on invocation"),
NULL},
{"version", 'v', 0, G_OPTION_ARG_NONE, &version, N_("Display previewer version"), NULL},
{NULL}
};
@@ -432,7 +444,12 @@ main (int argc, char **argv)
app = glade_previewer_new (file_name, toplevel_name);
gtk_widget_show (GTK_WIDGET (app->window));
-
+
+ app->is_template = template;
+
+ if (print_handler)
+ glade_preview_window_set_print_handlers (GLADE_PREVIEW_WINDOW (app->window), TRUE);
+
if (css_file_name)
glade_preview_window_set_css_file (app->window, css_file_name);
@@ -444,8 +461,6 @@ main (int argc, char **argv)
GIOChannel *input = g_io_channel_unix_new (fileno (stdin));
#endif
- app->is_template = template;
-
g_io_add_watch (input, G_IO_IN | G_IO_HUP, on_data_incoming, app);
gtk_main ();
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]