Initial import

This is a copy of https://github.com/chipx86/gtkparasite.git
with minimal edits to make it build.
This commit is contained in:
Matthias Clasen 2014-05-02 21:48:33 -04:00
parent 2dc100fa76
commit 81af602dda
28 changed files with 4310 additions and 1 deletions

View File

@ -1898,6 +1898,8 @@ modules/printbackends/lpr/Makefile
modules/printbackends/file/Makefile
modules/printbackends/papi/Makefile
modules/printbackends/test/Makefile
modules/other/Makefile
modules/other/parasite/Makefile
])
AC_OUTPUT

View File

@ -1,6 +1,6 @@
include $(top_srcdir)/Makefile.decl
SUBDIRS = input
SUBDIRS = input other
if OS_UNIX
SUBDIRS += printbackends

View File

@ -0,0 +1 @@
SUBDIRS = parasite

View File

@ -0,0 +1,52 @@
moduledir = $(libdir)/gtk-3.0/modules
module_LTLIBRARIES = libgtkparasite.la
libgtkparasite_la_SOURCES = \
inspect-button.c \
module.c \
parasite.h \
prop-list.h \
prop-list.c \
property-cell-renderer.c \
property-cell-renderer.h \
python-hooks.c \
python-hooks.h \
python-shell.c \
python-shell.h \
widget-tree.h \
widget-tree.c \
window.c \
button-path.h \
button-path.c \
classes-list.h \
classes-list.c \
css-editor.h \
css-editor.c \
object-hierarchy.h \
object-hierarchy.c \
themes.h \
themes.c
libgtkparasite_la_CPPFLAGS = \
-I$(top_srcdir) \
-I$(top_srcdir)/gtk \
-I$(top_builddir)/gtk \
-I$(top_srcdir)/gdk \
-I$(top_builddir)/gdk \
-DGTK_DATADIR=\"$(datadir)\" \
-DGTK_COMPILATION \
$(GTK_DEP_CFLAGS) \
$(GTK_DEBUG_FLAGS)
if PLATFORM_WIN32
no_undefined = -no-undefined
endif
libgtkparasite_la_LDFLAGS = -avoid-version -module $(no_undefined)
libgtkparasite_la_LIBADD = \
$(top_builddir)/gtk/libgtk-3.la \
$(GTK_DEP_LIBS)
-include $(top_srcdir)/git.mk

View File

@ -0,0 +1,103 @@
/*
* Copyright (c) 2013 Intel Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "button-path.h"
struct _ParasiteButtonPathPrivate
{
GtkWidget *sw;
GtkWidget *button_box;
};
G_DEFINE_TYPE_WITH_PRIVATE (ParasiteButtonPath, parasite_buttonpath, GTK_TYPE_BOX)
static void
parasite_buttonpath_init (ParasiteButtonPath *bp)
{
GtkWidget *label;
bp->priv = parasite_buttonpath_get_instance_private (bp);
g_object_set (bp,
"orientation", GTK_ORIENTATION_HORIZONTAL,
NULL);
bp->priv->sw = g_object_new (GTK_TYPE_SCROLLED_WINDOW,
"hscrollbar-policy", GTK_POLICY_AUTOMATIC,
"vscrollbar-policy", GTK_POLICY_NEVER,
"hexpand", TRUE,
NULL);
gtk_container_add (GTK_CONTAINER (bp), bp->priv->sw);
bp->priv->button_box = g_object_new (GTK_TYPE_BOX,
"orientation", GTK_ORIENTATION_HORIZONTAL,
"hexpand", TRUE,
"margin", 6,
NULL);
gtk_style_context_add_class (gtk_widget_get_style_context (bp->priv->button_box), "linked");
gtk_container_add (GTK_CONTAINER (bp->priv->sw), bp->priv->button_box);
label = g_object_new (GTK_TYPE_LABEL,
"label", "Choose a widget through the inspector",
"xalign", 0.5,
"hexpand", TRUE,
NULL);
gtk_container_add (GTK_CONTAINER (bp->priv->button_box), label);
}
static void
parasite_buttonpath_class_init(ParasiteButtonPathClass *klass)
{
}
GtkWidget *
parasite_buttonpath_new ()
{
return GTK_WIDGET (g_object_new (PARASITE_TYPE_BUTTONPATH, NULL));
}
void
parasite_buttonpath_set_widget(ParasiteButtonPath *bp,
GtkWidget *widget)
{
char *path, **words;
int i;
GtkWidget *b;
GtkContainer *box = GTK_CONTAINER (bp->priv->button_box);
gtk_container_foreach (box, (GtkCallback)gtk_widget_destroy, NULL);
path = gtk_widget_path_to_string (gtk_widget_get_path (widget));
words = g_strsplit (path, " ", 0);
for (i = 0; i < g_strv_length (words); i++)
{
b = gtk_button_new_with_label (words[i]);
gtk_widget_show (b);
gtk_container_add (box, b);
}
g_strfreev (words);
g_free (path);
}
// vim: set et sw=4 ts=4:

View File

@ -0,0 +1,60 @@
/*
* Copyright (c) 2013 Intel Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef _GTKPARASITE_BUTTONPATH_H_
#define _GTKPARASITE_BUTTONPATH_H_
#include <gtk/gtk.h>
#define PARASITE_TYPE_BUTTONPATH (parasite_buttonpath_get_type())
#define PARASITE_BUTTONPATH(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), PARASITE_TYPE_BUTTONPATH, ParasiteButtonPath))
#define PARASITE_BUTTONPATH_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), PARASITE_TYPE_BUTTONPATH, ParasiteButtonPathClass))
#define PARASITE_IS_BUTTONPATH(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), PARASITE_TYPE_BUTTONPATH))
#define PARASITE_IS_BUTTONPATH_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), PARASITE_TYPE_BUTTONPATH))
#define PARASITE_BUTTONPATH_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), PARASITE_TYPE_BUTTONPATH, ParasiteButtonPathClass))
typedef struct _ParasiteButtonPathPrivate ParasiteButtonPathPrivate;
typedef struct _ParasiteButtonPath {
GtkBox parent;
ParasiteButtonPathPrivate *priv;
} ParasiteButtonPath;
typedef struct _ParasiteButtonPathClass {
GtkBoxClass parent;
} ParasiteButtonPathClass;
G_BEGIN_DECLS
GType parasite_buttonpath_get_type ();
GtkWidget *parasite_buttonpath_new ();
void parasite_buttonpath_set_widget (ParasiteButtonPath *bp,
GtkWidget *widget);
G_END_DECLS
#endif // _GTKPARASITE_BUTTONPATH_H_
// vim: set et sw=4 ts=4:

View File

@ -0,0 +1,344 @@
/*
* Copyright (c) 2013 Intel Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "classes-list.h"
#include "parasite.h"
enum
{
COLUMN_ENABLED,
COLUMN_NAME,
COLUMN_USER,
NUM_COLUMNS
};
typedef struct
{
gboolean enabled;
gboolean user;
} ParasiteClassesListByContext;
struct _ParasiteClassesListPrivate
{
GtkWidget *toolbar;
GtkWidget *view;
GtkListStore *model;
GHashTable *contexts;
GtkStyleContext *current_context;
};
G_DEFINE_TYPE_WITH_PRIVATE (ParasiteClassesList, parasite_classeslist, GTK_TYPE_BOX)
static void
enabled_toggled (GtkCellRendererToggle *renderer, gchar *path, ParasiteClassesList *cl)
{
GtkTreeIter iter;
gboolean enabled;
GHashTable *context;
ParasiteClassesListByContext *c;
gchar *name;
if (!gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (cl->priv->model), &iter, path))
{
g_warning ("Parasite: Couldn't find the css class path for %s.", path);
return;
}
gtk_tree_model_get (GTK_TREE_MODEL (cl->priv->model), &iter,
COLUMN_ENABLED, &enabled,
COLUMN_NAME, &name,
-1);
enabled = !enabled;
gtk_list_store_set (cl->priv->model, &iter,
COLUMN_ENABLED, enabled,
-1);
context = g_hash_table_lookup (cl->priv->contexts, cl->priv->current_context);
if (context)
{
c = g_hash_table_lookup (context, name);
if (c)
{
c->enabled = enabled;
if (enabled)
{
gtk_style_context_add_class (cl->priv->current_context, name);
}
else
{
gtk_style_context_remove_class (cl->priv->current_context, name);
}
}
else
{
g_warning ("Parasite: Couldn't find the css class %s in the class hash table.", name);
}
}
else
{
g_warning ("Parasite: Couldn't find the hash table for the style context for css class %s.", name);
}
}
static void
add_clicked (GtkButton *button, ParasiteClassesList *cl)
{
GtkWidget *dialog, *content_area, *entry;
dialog = gtk_dialog_new_with_buttons ("New class",
GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (cl))),
GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
"_OK", GTK_RESPONSE_OK,
"Cancel", GTK_RESPONSE_CANCEL,
NULL);
gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK);
entry = g_object_new (GTK_TYPE_ENTRY,
"visible", TRUE,
"margin", 5,
"placeholder-text", "Class name",
"activates-default", TRUE,
NULL);
content_area = gtk_dialog_get_content_area (GTK_DIALOG (dialog));
gtk_container_add (GTK_CONTAINER (content_area), entry);
if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK)
{
const gchar *name = gtk_entry_get_text (GTK_ENTRY (entry));
GHashTable *context = g_hash_table_lookup (cl->priv->contexts, cl->priv->current_context);
if (*name && !g_hash_table_contains (context, name))
{
GtkTreeIter tree_iter;
gtk_style_context_add_class (cl->priv->current_context, name);
ParasiteClassesListByContext *c = g_new0 (ParasiteClassesListByContext, 1);
c->enabled = TRUE;
c->user = TRUE;
g_hash_table_insert (context, (gpointer)g_strdup (name), c);
gtk_list_store_append (cl->priv->model, &tree_iter);
gtk_list_store_set (cl->priv->model, &tree_iter,
COLUMN_ENABLED, TRUE,
COLUMN_NAME, name,
COLUMN_USER, TRUE,
-1);
}
}
gtk_widget_destroy (dialog);
}
static void
read_classes_from_style_context (ParasiteClassesList *cl)
{
GList *l, *classes;
ParasiteClassesListByContext *c;
GtkTreeIter tree_iter;
GHashTable *hash_context;
hash_context = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
classes = gtk_style_context_list_classes (cl->priv->current_context);
for (l = classes; l; l = l->next)
{
c = g_new0 (ParasiteClassesListByContext, 1);
c->enabled = TRUE;
g_hash_table_insert (hash_context, g_strdup (l->data), c);
gtk_list_store_append (cl->priv->model, &tree_iter);
gtk_list_store_set (cl->priv->model, &tree_iter,
COLUMN_ENABLED, TRUE,
COLUMN_NAME, l->data,
COLUMN_USER, FALSE,
-1);
}
g_list_free (classes);
g_hash_table_replace (cl->priv->contexts, cl->priv->current_context, hash_context);
}
static void
restore_defaults_clicked (GtkButton *button, ParasiteClassesList *cl)
{
GHashTableIter hash_iter;
gchar *name;
ParasiteClassesListByContext *c;
GHashTable *hash_context = g_hash_table_lookup (cl->priv->contexts, cl->priv->current_context);
g_hash_table_iter_init (&hash_iter, hash_context);
while (g_hash_table_iter_next (&hash_iter, (gpointer *)&name, (gpointer *)&c))
{
if (c->user)
{
gtk_style_context_remove_class (cl->priv->current_context, name);
}
else if (!c->enabled)
{
gtk_style_context_add_class (cl->priv->current_context, name);
}
}
gtk_list_store_clear (cl->priv->model);
read_classes_from_style_context (cl);
}
static void
create_toolbar (ParasiteClassesList *cl)
{
GtkWidget *button;
cl->priv->toolbar = g_object_new (GTK_TYPE_TOOLBAR,
"icon-size", GTK_ICON_SIZE_SMALL_TOOLBAR,
"sensitive", FALSE,
NULL);
gtk_container_add (GTK_CONTAINER (cl), cl->priv->toolbar);
button = g_object_new (GTK_TYPE_TOOL_BUTTON,
"icon-name", "add",
"tooltip-text", "Add a class",
NULL);
g_signal_connect (button, "clicked", G_CALLBACK (add_clicked), cl);
gtk_container_add (GTK_CONTAINER (cl->priv->toolbar), button);
button = g_object_new (GTK_TYPE_TOOL_BUTTON,
"icon-name", "revert",
"tooltip-text", "Restore defaults for this widget",
NULL);
g_signal_connect (button, "clicked", G_CALLBACK (restore_defaults_clicked), cl);
gtk_container_add (GTK_CONTAINER (cl->priv->toolbar), button);
}
static void
draw_name_column (GtkTreeViewColumn *column,
GtkCellRenderer *renderer,
GtkTreeModel *model,
GtkTreeIter *iter,
ParasiteClassesList *cl)
{
gboolean user;
gtk_tree_model_get (model, iter, COLUMN_USER, &user, -1);
if (user)
{
g_object_set (renderer, "style", PANGO_STYLE_ITALIC, NULL);
}
else
{
g_object_set (renderer, "style", PANGO_STYLE_NORMAL, NULL);
}
}
static void
parasite_classeslist_init (ParasiteClassesList *cl)
{
GtkCellRenderer *renderer;
GtkTreeViewColumn *column;
GtkWidget *sw;
g_object_set (cl, "orientation", GTK_ORIENTATION_VERTICAL, NULL);
cl->priv = parasite_classeslist_get_instance_private (cl);
create_toolbar (cl);
sw = g_object_new (GTK_TYPE_SCROLLED_WINDOW,
"expand", TRUE,
NULL);
gtk_container_add (GTK_CONTAINER (cl), sw);
cl->priv->contexts = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, (GDestroyNotify)g_hash_table_destroy);
cl->priv->model = gtk_list_store_new (NUM_COLUMNS,
G_TYPE_BOOLEAN, // COLUMN_ENABLED
G_TYPE_STRING, // COLUMN_NAME
G_TYPE_BOOLEAN); // COLUMN_USER
cl->priv->view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (cl->priv->model));
gtk_container_add (GTK_CONTAINER (sw), cl->priv->view);
renderer = gtk_cell_renderer_toggle_new ();
g_signal_connect (renderer, "toggled", G_CALLBACK (enabled_toggled), cl);
column = gtk_tree_view_column_new_with_attributes ("", renderer,
"active", COLUMN_ENABLED,
NULL);
gtk_tree_view_append_column (GTK_TREE_VIEW (cl->priv->view), column);
renderer = gtk_cell_renderer_text_new ();
g_object_set (renderer, "scale", TREE_TEXT_SCALE, NULL);
column = gtk_tree_view_column_new_with_attributes ("Name", renderer,
"text", COLUMN_NAME,
NULL);
gtk_tree_view_column_set_cell_data_func (column, renderer, (GtkTreeCellDataFunc)draw_name_column, cl, NULL);
gtk_tree_view_append_column (GTK_TREE_VIEW (cl->priv->view), column);
}
void
parasite_classeslist_set_widget (ParasiteClassesList *cl,
GtkWidget *widget)
{
GtkStyleContext *widget_context;
GHashTable *hash_context;
GtkTreeIter tree_iter;
ParasiteClassesListByContext *c;
gtk_list_store_clear (cl->priv->model);
gtk_widget_set_sensitive (GTK_WIDGET (cl), TRUE);
widget_context = gtk_widget_get_style_context (widget);
cl->priv->current_context = widget_context;
gtk_widget_set_sensitive (cl->priv->toolbar, TRUE);
hash_context = g_hash_table_lookup (cl->priv->contexts, widget_context);
if (hash_context)
{
GHashTableIter hash_iter;
gchar *name;
g_hash_table_iter_init (&hash_iter, hash_context);
while (g_hash_table_iter_next (&hash_iter, (gpointer *)&name, (gpointer *)&c))
{
gtk_list_store_append (cl->priv->model, &tree_iter);
gtk_list_store_set (cl->priv->model, &tree_iter,
COLUMN_ENABLED, c->enabled,
COLUMN_NAME, name,
COLUMN_USER, c->user,
-1);
}
}
else
{
read_classes_from_style_context (cl);
}
}
static void
parasite_classeslist_class_init (ParasiteClassesListClass *klass)
{
}
GtkWidget *
parasite_classeslist_new ()
{
return GTK_WIDGET (g_object_new (PARASITE_TYPE_CLASSESLIST, NULL));
}
// vim: set et sw=4 ts=4:

View File

@ -0,0 +1,58 @@
/*
* Copyright (c) 2013 Intel Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef _GTKPARASITE_CLASSESLIST_H_
#define _GTKPARASITE_CLASSESLIST_H_
#include <gtk/gtk.h>
#define PARASITE_TYPE_CLASSESLIST (parasite_classeslist_get_type())
#define PARASITE_CLASSESLIST(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), PARASITE_TYPE_CLASSESLIST, ParasiteClassesList))
#define PARASITE_CLASSESLIST_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), PARASITE_TYPE_CLASSESLIST, ParasiteClassesListClass))
#define PARASITE_IS_CLASSESLIST(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), PARASITE_TYPE_CLASSESLIST))
#define PARASITE_IS_CLASSESLIST_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), PARASITE_TYPE_CLASSESLIST))
#define PARASITE_CLASSESLIST_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), PARASITE_TYPE_CLASSESLIST, ParasiteClassesListClass))
typedef struct _ParasiteClassesListPrivate ParasiteClassesListPrivate;
typedef struct _ParasiteClassesList {
GtkBox parent;
ParasiteClassesListPrivate *priv;
} ParasiteClassesList;
typedef struct _ParasiteClassesListClass {
GtkBoxClass parent;
} ParasiteClassesListClass;
G_BEGIN_DECLS
GType parasite_classeslist_get_type ();
GtkWidget *parasite_classeslist_new ();
void parasite_classeslist_set_widget (ParasiteClassesList* classeslist,
GtkWidget *widget);
G_END_DECLS
#endif // _GTKPARASITE_CLASSESLIST_H_
// vim: set et sw=4 ts=4:

View File

@ -0,0 +1,388 @@
/*
* Copyright (c) 2013 Intel Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "css-editor.h"
#include "parasite.h"
#define PARASITE_CSSEDITOR_TEXT "parasite-csseditor-text"
#define PARASITE_CSSEDITOR_PROVIDER "parasite-csseditor-provider"
enum
{
COLUMN_ENABLED,
COLUMN_NAME,
COLUMN_USER,
NUM_COLUMNS
};
enum
{
PROP_0,
PROP_GLOBAL
};
typedef struct
{
gboolean enabled;
gboolean user;
} ParasiteCssEditorByContext;
struct _ParasiteCssEditorPrivate
{
GtkWidget *toolbar;
GtkTextBuffer *text;
GtkCssProvider *provider;
gboolean global;
GtkStyleContext *selected_context;
GtkToggleToolButton *disable_button;
};
G_DEFINE_TYPE_WITH_PRIVATE (ParasiteCssEditor, parasite_csseditor, GTK_TYPE_BOX)
static const gchar *initial_text_global =
"/*\n"
"You can type here any CSS rule recognized by GTK+.\n"
"You can temporarily disable this custom CSS by clicking on the \"Pause\" button above.\n\n"
"Changes are applied instantly and globally, for the whole application.\n"
"*/\n\n";
static const gchar *initial_text_widget =
"/*\n"
"You can type here any CSS rule recognized by GTK+.\n"
"You can temporarily disable this custom CSS by clicking on the \"Pause\" button above.\n\n"
"Changes are applied instantly, only for this selected widget.\n"
"*/\n\n";
static void
disable_toggled (GtkToggleToolButton *button, ParasiteCssEditor *editor)
{
if (gtk_toggle_tool_button_get_active (button))
{
if (editor->priv->global)
{
gtk_style_context_remove_provider_for_screen (gdk_screen_get_default (),
GTK_STYLE_PROVIDER (editor->priv->provider));
}
else if (editor->priv->selected_context)
{
gtk_style_context_remove_provider (editor->priv->selected_context,
GTK_STYLE_PROVIDER (g_object_get_data (G_OBJECT (editor->priv->selected_context), PARASITE_CSSEDITOR_PROVIDER)));
}
}
else
{
if (editor->priv->global)
{
gtk_style_context_add_provider_for_screen (gdk_screen_get_default (),
GTK_STYLE_PROVIDER (editor->priv->provider),
GTK_STYLE_PROVIDER_PRIORITY_USER);
}
else if (editor->priv->selected_context)
{
gtk_style_context_add_provider (editor->priv->selected_context,
GTK_STYLE_PROVIDER (g_object_get_data (G_OBJECT (editor->priv->selected_context), PARASITE_CSSEDITOR_PROVIDER)),
G_MAXUINT);
}
}
}
static void
create_toolbar (ParasiteCssEditor *editor)
{
editor->priv->toolbar = g_object_new (GTK_TYPE_TOOLBAR,
"icon-size", GTK_ICON_SIZE_SMALL_TOOLBAR,
NULL);
gtk_container_add (GTK_CONTAINER (editor), editor->priv->toolbar);
editor->priv->disable_button = g_object_new (GTK_TYPE_TOGGLE_TOOL_BUTTON,
"icon-name", "media-playback-pause",
"tooltip-text", "Disable this custom css",
NULL);
g_signal_connect (editor->priv->disable_button,
"toggled",
G_CALLBACK (disable_toggled),
editor);
gtk_container_add (GTK_CONTAINER (editor->priv->toolbar),
GTK_WIDGET (editor->priv->disable_button));
}
static void
apply_system_font (GtkWidget *widget)
{
GSettings *s = g_settings_new ("org.gnome.desktop.interface");
gchar *font_name = g_settings_get_string (s, "monospace-font-name");
PangoFontDescription *font_desc = pango_font_description_from_string (font_name);
gtk_widget_override_font (widget, font_desc);
pango_font_description_free (font_desc);
g_free (font_name);
g_object_unref (s);
}
static gchar *
get_current_text (GtkTextBuffer *buffer)
{
GtkTextIter start, end;
gtk_text_buffer_get_start_iter (buffer, &start);
gtk_text_buffer_get_end_iter (buffer, &end);
gtk_text_buffer_remove_all_tags (buffer, &start, &end);
return gtk_text_buffer_get_text (buffer, &start, &end, FALSE);
}
static void
text_changed (GtkTextBuffer *buffer, ParasiteCssEditor *editor)
{
GtkCssProvider *provider;
char *text;
if (editor->priv->global)
provider = editor->priv->provider;
else if (editor->priv->selected_context)
provider = g_object_get_data (G_OBJECT (editor->priv->selected_context), PARASITE_CSSEDITOR_PROVIDER);
else
return;
text = get_current_text (buffer);
gtk_css_provider_load_from_data (provider, text, -1, NULL);
g_free (text);
gtk_style_context_reset_widgets (gdk_screen_get_default ());
}
static void
show_parsing_error (GtkCssProvider *provider,
GtkCssSection *section,
const GError *error,
ParasiteCssEditor *editor)
{
GtkTextIter start, end;
const char *tag_name;
GtkTextBuffer *buffer = GTK_TEXT_BUFFER (editor->priv->text);
gtk_text_buffer_get_iter_at_line_index (buffer,
&start,
gtk_css_section_get_start_line (section),
gtk_css_section_get_start_position (section));
gtk_text_buffer_get_iter_at_line_index (buffer,
&end,
gtk_css_section_get_end_line (section),
gtk_css_section_get_end_position (section));
if (g_error_matches (error, GTK_CSS_PROVIDER_ERROR, GTK_CSS_PROVIDER_ERROR_DEPRECATED))
tag_name = "warning";
else
tag_name = "error";
gtk_text_buffer_apply_tag_by_name (buffer, tag_name, &start, &end);
}
static void
create_text_widget (ParasiteCssEditor *editor)
{
GtkWidget *sw, *view;
editor->priv->text = gtk_text_buffer_new (NULL);
if (editor->priv->global)
gtk_text_buffer_set_text (GTK_TEXT_BUFFER (editor->priv->text), initial_text_global, -1);
else
gtk_text_buffer_set_text (GTK_TEXT_BUFFER (editor->priv->text), initial_text_widget, -1);
g_signal_connect (editor->priv->text, "changed", G_CALLBACK (text_changed), editor);
gtk_text_buffer_create_tag (GTK_TEXT_BUFFER (editor->priv->text),
"warning",
"underline", PANGO_UNDERLINE_SINGLE,
NULL);
gtk_text_buffer_create_tag (GTK_TEXT_BUFFER (editor->priv->text),
"error",
"underline", PANGO_UNDERLINE_ERROR,
NULL);
sw = g_object_new (GTK_TYPE_SCROLLED_WINDOW,
"expand", TRUE,
NULL);
gtk_container_add (GTK_CONTAINER (editor), sw);
view = g_object_new (GTK_TYPE_TEXT_VIEW,
"buffer", editor->priv->text,
"wrap-mode", GTK_WRAP_WORD,
NULL);
apply_system_font (view);
gtk_container_add (GTK_CONTAINER (sw), view);
}
static void
create_provider (ParasiteCssEditor *editor)
{
GtkCssProvider *provider = gtk_css_provider_new ();
if (editor->priv->global)
{
editor->priv->provider = provider;
gtk_style_context_add_provider_for_screen (gdk_screen_get_default (),
GTK_STYLE_PROVIDER (editor->priv->provider),
GTK_STYLE_PROVIDER_PRIORITY_USER);
}
else if (editor->priv->selected_context)
{
gtk_style_context_add_provider (editor->priv->selected_context,
GTK_STYLE_PROVIDER (provider),
G_MAXUINT);
g_object_set_data (G_OBJECT (editor->priv->selected_context),
PARASITE_CSSEDITOR_PROVIDER,
provider);
}
g_signal_connect (provider,
"parsing-error",
G_CALLBACK (show_parsing_error),
editor);
}
static void
parasite_csseditor_init (ParasiteCssEditor *editor)
{
editor->priv = parasite_csseditor_get_instance_private (editor);
}
static void
constructed (GObject *object)
{
ParasiteCssEditor *editor = PARASITE_CSSEDITOR (object);
g_object_set (editor,
"orientation", GTK_ORIENTATION_VERTICAL,
"sensitive", editor->priv->global,
NULL);
create_toolbar (editor);
create_provider (editor);
create_text_widget (editor);
}
static void
get_property (GObject *object,
guint param_id,
GValue *value,
GParamSpec *pspec)
{
ParasiteCssEditor *editor = PARASITE_CSSEDITOR (object);
switch (param_id)
{
case PROP_GLOBAL:
g_value_set_boolean (value, editor->priv->global);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, param_id, pspec);
break;
}
}
static void
set_property (GObject *object,
guint param_id,
const GValue *value,
GParamSpec *pspec)
{
ParasiteCssEditor *editor = PARASITE_CSSEDITOR (object);
switch (param_id)
{
case PROP_GLOBAL:
editor->priv->global = g_value_get_boolean (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, param_id, pspec);
break;
}
}
static void
parasite_csseditor_class_init (ParasiteCssEditorClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->get_property = get_property;
object_class->set_property = set_property;
object_class->constructed = constructed;
g_object_class_install_property (object_class,
PROP_GLOBAL,
g_param_spec_boolean ("global",
"Global",
"Whether this editor changes the whole application or just the selected widget",
TRUE,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
}
GtkWidget *
parasite_csseditor_new (gboolean global)
{
return GTK_WIDGET (g_object_new (PARASITE_TYPE_CSSEDITOR,
"global", global,
NULL));
}
void
parasite_csseditor_set_widget (ParasiteCssEditor *editor, GtkWidget *widget)
{
gchar *text;
GtkCssProvider *provider;
g_return_if_fail (PARASITE_IS_CSSEDITOR (editor));
g_return_if_fail (!editor->priv->global);
gtk_widget_set_sensitive (GTK_WIDGET (editor), TRUE);
if (editor->priv->selected_context)
{
text = get_current_text (GTK_TEXT_BUFFER (editor->priv->text));
g_object_set_data_full (G_OBJECT (editor->priv->selected_context),
PARASITE_CSSEDITOR_TEXT,
text,
g_free);
}
editor->priv->selected_context = gtk_widget_get_style_context (widget);
provider = g_object_get_data (G_OBJECT (editor->priv->selected_context), PARASITE_CSSEDITOR_PROVIDER);
if (!provider)
{
create_provider (editor);
}
text = g_object_get_data (G_OBJECT (editor->priv->selected_context), PARASITE_CSSEDITOR_TEXT);
if (text)
gtk_text_buffer_set_text (GTK_TEXT_BUFFER (editor->priv->text), text, -1);
else
gtk_text_buffer_set_text (GTK_TEXT_BUFFER (editor->priv->text), initial_text_widget, -1);
disable_toggled (editor->priv->disable_button, editor);
}
// vim: set et sw=4 ts=4:

View File

@ -0,0 +1,59 @@
/*
* Copyright (c) 2013 Intel Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef _GTKPARASITE_CSSEDITOR_H_
#define _GTKPARASITE_CSSEDITOR_H_
#include <gtk/gtk.h>
#define PARASITE_TYPE_CSSEDITOR (parasite_csseditor_get_type())
#define PARASITE_CSSEDITOR(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), PARASITE_TYPE_CSSEDITOR, ParasiteCssEditor))
#define PARASITE_CSSEDITOR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), PARASITE_TYPE_CSSEDITOR, ParasiteCssEditorClass))
#define PARASITE_IS_CSSEDITOR(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), PARASITE_TYPE_CSSEDITOR))
#define PARASITE_IS_CSSEDITOR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), PARASITE_TYPE_CSSEDITOR))
#define PARASITE_CSSEDITOR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), PARASITE_TYPE_CSSEDITOR, ParasiteCssEditorClass))
typedef struct _ParasiteCssEditorPrivate ParasiteCssEditorPrivate;
typedef struct _ParasiteCssEditor {
GtkBox parent;
ParasiteCssEditorPrivate *priv;
} ParasiteCssEditor;
typedef struct _ParasiteCssEditorClass {
GtkBoxClass parent;
} ParasiteCssEditorClass;
G_BEGIN_DECLS
GType parasite_csseditor_get_type ();
GtkWidget *parasite_csseditor_new (gboolean global);
void parasite_csseditor_set_widget (ParasiteCssEditor *editor,
GtkWidget *widget);
G_END_DECLS
#endif // _GTKPARASITE_CSSEDITOR_H_
// vim: set et sw=4 ts=4:

View File

@ -0,0 +1,242 @@
/*
* Copyright (c) 2008-2009 Christian Hammond
* Copyright (c) 2008-2009 David Trowbridge
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "parasite.h"
#include "widget-tree.h"
static void
on_inspect_widget(GtkWidget *grab_window,
GdkEventButton *event,
ParasiteWindow *parasite)
{
gdk_device_ungrab (gtk_get_current_event_device (), event->time);
gtk_widget_hide(parasite->highlight_window);
if (parasite->selected_window != NULL)
{
GtkWidget *toplevel = NULL;
GtkWidget *widget = NULL;
gdk_window_get_user_data(
gdk_window_get_toplevel(parasite->selected_window),
(gpointer*)&toplevel);
gdk_window_get_user_data (parasite->selected_window, (gpointer*)&widget);
if (toplevel)
{
parasite_widget_tree_scan (PARASITE_WIDGET_TREE (parasite->widget_tree),
toplevel);
}
if (widget)
{
parasite_widget_tree_select_object (PARASITE_WIDGET_TREE (parasite->widget_tree),
G_OBJECT (widget));
}
}
}
static void
on_highlight_window_show (GtkWidget *window, ParasiteWindow *parasite)
{
if (gtk_widget_is_composited (parasite->window))
{
gtk_widget_set_opacity (parasite->highlight_window, 0.2);
}
else
{
/*
* TODO: Do something different when there's no compositing manager.
* Draw a border or something.
*/
}
}
static void
ensure_highlight_window (ParasiteWindow *parasite)
{
GdkRGBA color;
if (parasite->highlight_window != NULL)
return;
color.red = 0;
color.green = 0;
color.blue = 65535;
color.alpha = 1;
parasite->highlight_window = gtk_window_new (GTK_WINDOW_POPUP);
gtk_widget_override_background_color (parasite->highlight_window,
GTK_STATE_NORMAL,
&color);
g_signal_connect (parasite->highlight_window, "show", G_CALLBACK (on_highlight_window_show), parasite);
}
static void
on_highlight_widget(GtkWidget *grab_window,
GdkEventMotion *event,
ParasiteWindow *parasite)
{
GdkWindow *selected_window;
gint x, y, width, height;
ensure_highlight_window (parasite);
gtk_widget_hide (parasite->highlight_window);
selected_window = gdk_device_get_window_at_position (gtk_get_current_event_device (),
NULL,
NULL);
if (selected_window == NULL)
{
/* This window isn't in-process. Ignore it. */
parasite->selected_window = NULL;
return;
}
if (gdk_window_get_toplevel(selected_window) == gtk_widget_get_window(parasite->window))
{
/* Don't hilight things in the parasite window */
parasite->selected_window = NULL;
return;
}
parasite->selected_window = selected_window;
gdk_window_get_origin (selected_window, &x, &y);
width = gdk_window_get_width (selected_window);
height = gdk_window_get_height (selected_window);
gtk_window_move (GTK_WINDOW (parasite->highlight_window), x, y);
gtk_window_resize (GTK_WINDOW (parasite->highlight_window), width, height);
gtk_widget_show (parasite->highlight_window);
}
static void
on_inspect_button_release (GtkWidget *button,
GdkEventButton *event,
ParasiteWindow *parasite)
{
GdkCursor *cursor;
GdkEventMask events;
events = GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK;
if (parasite->grab_window == NULL)
{
parasite->grab_window = gtk_window_new (GTK_WINDOW_POPUP);
gtk_widget_show(parasite->grab_window);
gtk_window_resize (GTK_WINDOW (parasite->grab_window), 1, 1);
gtk_window_move (GTK_WINDOW (parasite->grab_window), -100, -100);
gtk_widget_add_events (parasite->grab_window, events);
g_signal_connect (parasite->grab_window, "button_release_event", G_CALLBACK (on_inspect_widget), parasite);
g_signal_connect (parasite->grab_window, "motion_notify_event", G_CALLBACK(on_highlight_widget), parasite);
}
cursor = gdk_cursor_new_for_display (gtk_widget_get_display (button), GDK_CROSSHAIR);
gdk_device_grab (gtk_get_current_event_device (),
gtk_widget_get_window (parasite->grab_window),
GDK_OWNERSHIP_WINDOW,
FALSE,
events,
cursor,
event->time);
g_object_unref (cursor);
}
GtkWidget *
gtkparasite_inspect_button_new(ParasiteWindow *parasite)
{
GtkWidget *button;
button = gtk_button_new_from_icon_name ("find", GTK_ICON_SIZE_BUTTON);
gtk_widget_set_tooltip_text (button, "Inspect");
g_signal_connect(G_OBJECT(button), "button_release_event",
G_CALLBACK(on_inspect_button_release), parasite);
return button;
}
static gboolean
on_flash_timeout(ParasiteWindow *parasite)
{
parasite->flash_count++;
if (parasite->flash_count == 8)
{
parasite->flash_cnx = 0;
return FALSE;
}
if (parasite->flash_count % 2 == 0)
{
if (gtk_widget_get_visible(parasite->highlight_window))
gtk_widget_hide(parasite->highlight_window);
else
gtk_widget_show(parasite->highlight_window);
}
return TRUE;
}
void
gtkparasite_flash_widget(ParasiteWindow *parasite, GtkWidget *widget)
{
gint x, y, width, height;
GdkWindow *parent_window;
if (!gtk_widget_get_visible(widget) || !gtk_widget_get_mapped(widget))
return;
ensure_highlight_window(parasite);
parent_window = gtk_widget_get_parent_window(widget);
if (parent_window != NULL) {
GtkAllocation alloc;
gtk_widget_get_allocation(widget, &alloc);
gdk_window_get_origin(parent_window, &x, &y);
x += alloc.x;
y += alloc.y;
width = alloc.width;
height = alloc.height;
gtk_window_move(GTK_WINDOW(parasite->highlight_window), x, y);
gtk_window_resize(GTK_WINDOW(parasite->highlight_window), width, height);
gtk_widget_show(parasite->highlight_window);
if (parasite->flash_cnx != 0)
g_source_remove(parasite->flash_cnx);
parasite->flash_count = 0;
parasite->flash_cnx = g_timeout_add(150, (GSourceFunc)on_flash_timeout,
parasite);
}
}
// vim: set et sw=4 ts=4:

View File

@ -0,0 +1,40 @@
/*
* Copyright (c) 2008-2009 Christian Hammond
* Copyright (c) 2008-2009 David Trowbridge
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include <glib.h>
#include "config.h"
#include "parasite.h"
#include "python-hooks.h"
void
gtk_module_init(gint *argc, gchar ***argv)
{
#ifdef ENABLE_PYTHON
parasite_python_init();
#endif
gtkparasite_window_create();
}
// vim: set et sw=4 ts=4:

View File

@ -0,0 +1,126 @@
/*
* Copyright (c) 2013 Intel Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "object-hierarchy.h"
#include "parasite.h"
enum
{
COLUMN_OBJECT_NAME,
NUM_COLUMNS
};
struct _ParasiteObjectHierarchyPrivate
{
GtkTreeStore *model;
GtkTreeView *tree;
};
G_DEFINE_TYPE_WITH_PRIVATE (ParasiteObjectHierarchy, parasite_objecthierarchy, GTK_TYPE_BOX)
static void
parasite_objecthierarchy_init (ParasiteObjectHierarchy *oh)
{
oh->priv = parasite_objecthierarchy_get_instance_private (oh);
}
static void
constructed (GObject *object)
{
ParasiteObjectHierarchy *oh = PARASITE_OBJECTHIERARCHY (object);
GtkWidget *sw;
GtkCellRenderer *renderer;
GtkTreeViewColumn *column;
g_object_set (object,
"orientation", GTK_ORIENTATION_VERTICAL,
NULL);
sw = g_object_new (GTK_TYPE_SCROLLED_WINDOW,
"expand", TRUE,
NULL);
gtk_container_add (GTK_CONTAINER (object), sw);
oh->priv->model = gtk_tree_store_new (NUM_COLUMNS,
G_TYPE_STRING); // COLUMN_OBJECT_NAME
oh->priv->tree = GTK_TREE_VIEW (gtk_tree_view_new_with_model (GTK_TREE_MODEL (oh->priv->model)));
gtk_container_add (GTK_CONTAINER (sw), GTK_WIDGET (oh->priv->tree));
renderer = gtk_cell_renderer_text_new ();
g_object_set (renderer, "scale", TREE_TEXT_SCALE, NULL);
column = gtk_tree_view_column_new_with_attributes ("Object Hierarchy", renderer,
"text", COLUMN_OBJECT_NAME,
NULL);
gtk_tree_view_append_column (GTK_TREE_VIEW (oh->priv->tree), column);
}
static void
parasite_objecthierarchy_class_init (ParasiteObjectHierarchyClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->constructed = constructed;
}
GtkWidget *
parasite_objecthierarchy_new (void)
{
return GTK_WIDGET (g_object_new (PARASITE_TYPE_OBJECTHIERARCHY,
NULL));
}
void
parasite_objecthierarchy_set_object (ParasiteObjectHierarchy *oh, GObject *object)
{
GObjectClass *klass = G_OBJECT_GET_CLASS (object);
const gchar *class_name;
GtkTreeIter iter, parent;
GSList *list = NULL, *l;
gtk_tree_store_clear (oh->priv->model);
do
{
class_name = G_OBJECT_CLASS_NAME (klass);
list = g_slist_append (list, (gpointer)class_name);
}
while ((klass = g_type_class_peek_parent (klass))) ;
list = g_slist_reverse (list);
for (l = list; l; l = l->next)
{
gtk_tree_store_append (oh->priv->model, &iter, l == list ? NULL : &parent);
gtk_tree_store_set (oh->priv->model, &iter,
COLUMN_OBJECT_NAME, l->data,
-1);
parent = iter;
}
g_slist_free (list);
gtk_tree_view_expand_all (oh->priv->tree);
gtk_tree_selection_select_iter (gtk_tree_view_get_selection (oh->priv->tree),
&iter);
}
// vim: set et sw=4 ts=4:

View File

@ -0,0 +1,58 @@
/*
* Copyright (c) 2013 Intel Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef _GTKPARASITE_OBJECTHIERARCHY_H_
#define _GTKPARASITE_OBJECTHIERARCHY_H_
#include <gtk/gtk.h>
#define PARASITE_TYPE_OBJECTHIERARCHY (parasite_objecthierarchy_get_type())
#define PARASITE_OBJECTHIERARCHY(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), PARASITE_TYPE_OBJECTHIERARCHY, ParasiteObjectHierarchy))
#define PARASITE_OBJECTHIERARCHY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), PARASITE_TYPE_OBJECTHIERARCHY, ParasiteObjectHierarchyClass))
#define PARASITE_IS_OBJECTHIERARCHY(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), PARASITE_TYPE_OBJECTHIERARCHY))
#define PARASITE_IS_OBJECTHIERARCHY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), PARASITE_TYPE_OBJECTHIERARCHY))
#define PARASITE_OBJECTHIERARCHY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), PARASITE_TYPE_OBJECTHIERARCHY, ParasiteObjectHierarchyClass))
typedef struct _ParasiteObjectHierarchyPrivate ParasiteObjectHierarchyPrivate;
typedef struct _ParasiteObjectHierarchy {
GtkBox parent;
ParasiteObjectHierarchyPrivate *priv;
} ParasiteObjectHierarchy;
typedef struct _ParasiteObjectHierarchyClass {
GtkBoxClass parent;
} ParasiteObjectHierarchyClass;
G_BEGIN_DECLS
GType parasite_objecthierarchy_get_type (void);
GtkWidget *parasite_objecthierarchy_new (void);
void parasite_objecthierarchy_set_object (ParasiteObjectHierarchy *editor,
GObject *object);
G_END_DECLS
#endif // _GTKPARASITE_OBJECTHIERARCHY_H_
// vim: set et sw=4 ts=4:

View File

@ -0,0 +1,69 @@
/*
* Copyright (c) 2008-2009 Christian Hammond
* Copyright (c) 2008-2009 David Trowbridge
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef _GTKPARASITE_H_
#define _GTKPARASITE_H_
#include <gtk/gtk.h>
#define TREE_TEXT_SCALE 0.8
#define TREE_CHECKBOX_SIZE (gint)(0.8 * 13)
typedef struct
{
GtkWidget *window;
GtkWidget *widget_tree;
GtkWidget *prop_list;
GtkWidget *python_shell;
GtkWidget *button_path;
GtkWidget *classes_list;
GtkWidget *widget_css_editor;
GtkWidget *oh;
GtkWidget *grab_window;
GtkWidget *highlight_window;
GtkWidget *widget_popup;
GdkWindow *selected_window;
gboolean edit_mode_enabled;
int flash_count;
int flash_cnx;
} ParasiteWindow;
void gtkparasite_window_create();
void gtkparasite_flash_widget(ParasiteWindow *parasite, GtkWidget *widget);
GtkWidget *gtkparasite_inspect_button_new(ParasiteWindow *parasite);
#endif // _GTKPARASITE_H_
// vim: set et sw=4 ts=4:

View File

@ -0,0 +1,367 @@
/*
* Copyright (c) 2008-2009 Christian Hammond
* Copyright (c) 2008-2009 David Trowbridge
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "parasite.h"
#include "prop-list.h"
#include "property-cell-renderer.h"
enum
{
COLUMN_NAME,
COLUMN_VALUE,
COLUMN_DEFINED_AT,
COLUMN_OBJECT,
COLUMN_TOOLTIP,
COLUMN_RO,
NUM_COLUMNS
};
enum
{
PROP_0,
PROP_WIDGET_TREE
};
struct _ParasitePropListPrivate
{
GObject *object;
GtkListStore *model;
GHashTable *prop_iters;
GList *signal_cnxs;
GtkWidget *widget_tree;
GtkTreeViewColumn *property_column;
};
G_DEFINE_TYPE_WITH_PRIVATE (ParasitePropList, parasite_proplist, GTK_TYPE_TREE_VIEW)
static void
parasite_proplist_init (ParasitePropList *pl)
{
pl->priv = parasite_proplist_get_instance_private (pl);
}
static gboolean
query_tooltip_cb (GtkWidget *widget,
gint x,
gint y,
gboolean keyboard_tip,
GtkTooltip *tooltip,
ParasitePropList *pl)
{
GtkTreeIter iter;
GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
GtkTreeModel *model = gtk_tree_view_get_model (tree_view);
GtkTreePath *path = NULL;
gchar *tooltip_text;
if (!gtk_tree_view_get_tooltip_context (tree_view,
&x,
&y,
keyboard_tip,
&model,
&path,
&iter))
return FALSE;
gtk_tree_model_get (model, &iter, COLUMN_TOOLTIP, &tooltip_text, -1);
gtk_tooltip_set_text (tooltip, tooltip_text);
gtk_tree_view_set_tooltip_cell (tree_view,
tooltip,
path,
pl->priv->property_column,
NULL);
gtk_tree_path_free (path);
g_free (tooltip_text);
return TRUE;
}
static void
draw_columns (GtkTreeViewColumn *column,
GtkCellRenderer *renderer,
GtkTreeModel *model,
GtkTreeIter *iter,
ParasitePropList *pl)
{
gboolean ro;
gtk_tree_model_get (model, iter, COLUMN_RO, &ro, -1);
if (ro)
{
g_object_set (renderer, "foreground", "#a7aba7", NULL);
}
else
{
g_object_set (renderer, "foreground-set", FALSE, NULL);
}
}
static void
constructed (GObject *object)
{
ParasitePropList *pl = PARASITE_PROPLIST (object);
GtkCellRenderer *renderer;
GtkTreeViewColumn *column;
pl->priv->prop_iters = g_hash_table_new_full (g_str_hash,
g_str_equal,
NULL,
(GDestroyNotify) gtk_tree_iter_free);
pl->priv->model = gtk_list_store_new(NUM_COLUMNS,
G_TYPE_STRING, // COLUMN_NAME
G_TYPE_STRING, // COLUMN_VALUE
G_TYPE_STRING, // COLUMN_DEFINED_AT
G_TYPE_OBJECT, // COLUMN_OBJECT
G_TYPE_STRING, // COLUMN_TOOLTIP
G_TYPE_BOOLEAN);// COLUMN_RO
gtk_tree_view_set_model (GTK_TREE_VIEW (pl),
GTK_TREE_MODEL (pl->priv->model));
renderer = gtk_cell_renderer_text_new();
g_object_set (renderer, "scale", TREE_TEXT_SCALE, NULL);
pl->priv->property_column = gtk_tree_view_column_new_with_attributes ("Property",
renderer,
"text", COLUMN_NAME,
NULL);
gtk_tree_view_append_column (GTK_TREE_VIEW (pl), pl->priv->property_column);
g_object_set (pl->priv->property_column,
"resizable", TRUE,
"sort-order", GTK_SORT_ASCENDING,
"sort-column-id", COLUMN_NAME,
NULL);
gtk_tree_view_column_set_cell_data_func (pl->priv->property_column,
renderer,
(GtkTreeCellDataFunc) draw_columns,
pl,
NULL);
renderer = parasite_property_cell_renderer_new ();
g_object_set_data (G_OBJECT (renderer), "parasite-widget-tree", pl->priv->widget_tree);
g_object_set (renderer,
"scale", TREE_TEXT_SCALE,
"editable", TRUE,
NULL);
column = gtk_tree_view_column_new_with_attributes ("Value", renderer,
"text", COLUMN_VALUE,
"object", COLUMN_OBJECT,
"name", COLUMN_NAME,
NULL);
gtk_tree_view_append_column (GTK_TREE_VIEW (pl), column);
gtk_tree_view_column_set_resizable (column, TRUE);
gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (pl->priv->model),
COLUMN_NAME,
GTK_SORT_ASCENDING);
gtk_tree_view_column_set_cell_data_func (column,
renderer,
(GtkTreeCellDataFunc) draw_columns,
pl,
NULL);
renderer = gtk_cell_renderer_text_new ();
g_object_set (renderer, "scale", TREE_TEXT_SCALE, NULL);
column = gtk_tree_view_column_new_with_attributes ("Defined at",
renderer,
"text", COLUMN_DEFINED_AT,
NULL);
gtk_tree_view_append_column (GTK_TREE_VIEW (pl), column);
gtk_tree_view_column_set_cell_data_func (column,
renderer,
(GtkTreeCellDataFunc) draw_columns,
pl,
NULL);
g_object_set (object, "has-tooltip", TRUE, NULL);
g_signal_connect (object, "query-tooltip", G_CALLBACK (query_tooltip_cb), pl);
}
static void
get_property (GObject *object,
guint param_id,
GValue *value,
GParamSpec *pspec)
{
ParasitePropList *pl = PARASITE_PROPLIST (object);
switch (param_id)
{
case PROP_WIDGET_TREE:
g_value_take_object (value, pl->priv->widget_tree);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
break;
}
}
static void
set_property (GObject *object,
guint param_id,
const GValue *value,
GParamSpec *pspec)
{
ParasitePropList *pl = PARASITE_PROPLIST (object);
switch (param_id)
{
case PROP_WIDGET_TREE:
pl->priv->widget_tree = g_value_get_object (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
break;
}
}
static void
parasite_proplist_class_init (ParasitePropListClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS(klass);
object_class->get_property = get_property;
object_class->set_property = set_property;
object_class->constructed = constructed;
g_object_class_install_property (object_class,
PROP_WIDGET_TREE,
g_param_spec_object ("widget-tree",
"Widget Tree",
"Widget tree",
GTK_TYPE_WIDGET,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
}
static void
parasite_prop_list_update_prop (ParasitePropList *pl,
GtkTreeIter *iter,
GParamSpec *prop)
{
GValue gvalue = {0};
char *value;
g_value_init(&gvalue, prop->value_type);
g_object_get_property (pl->priv->object, prop->name, &gvalue);
if (G_VALUE_HOLDS_ENUM (&gvalue))
{
GEnumClass *enum_class = G_PARAM_SPEC_ENUM(prop)->enum_class;
GEnumValue *enum_value = g_enum_get_value(enum_class, g_value_get_enum(&gvalue));
value = g_strdup (enum_value->value_name);
}
else
{
value = g_strdup_value_contents(&gvalue);
}
gtk_list_store_set (pl->priv->model, iter,
COLUMN_NAME, prop->name,
COLUMN_VALUE, value,
COLUMN_DEFINED_AT, g_type_name (prop->owner_type),
COLUMN_OBJECT, pl->priv->object,
COLUMN_TOOLTIP, g_param_spec_get_blurb (prop),
COLUMN_RO, !(prop->flags & G_PARAM_WRITABLE),
-1);
g_free (value);
g_value_unset (&gvalue);
}
static void
parasite_proplist_prop_changed_cb (GObject *pspec,
GParamSpec *prop,
ParasitePropList *pl)
{
GtkTreeIter *iter = g_hash_table_lookup(pl->priv->prop_iters, prop->name);
if (iter != NULL)
parasite_prop_list_update_prop (pl, iter, prop);
}
GtkWidget *
parasite_proplist_new (GtkWidget *widget_tree)
{
return g_object_new (PARASITE_TYPE_PROPLIST,
"widget-tree", widget_tree,
NULL);
}
void
parasite_proplist_set_object (ParasitePropList* pl, GObject *object)
{
GtkTreeIter iter;
GParamSpec **props;
guint num_properties;
guint i;
GList *l;
pl->priv->object = object;
for (l = pl->priv->signal_cnxs; l != NULL; l = l->next)
{
gulong id = GPOINTER_TO_UINT (l->data);
if (g_signal_handler_is_connected (object, id))
g_signal_handler_disconnect (object, id);
}
g_list_free (pl->priv->signal_cnxs);
pl->priv->signal_cnxs = NULL;
g_hash_table_remove_all (pl->priv->prop_iters);
gtk_list_store_clear (pl->priv->model);
props = g_object_class_list_properties (G_OBJECT_GET_CLASS (object), &num_properties);
for (i = 0; i < num_properties; i++)
{
GParamSpec *prop = props[i];
char *signal_name;
if (! (prop->flags & G_PARAM_READABLE))
continue;
gtk_list_store_append (pl->priv->model, &iter);
parasite_prop_list_update_prop (pl, &iter, prop);
g_hash_table_insert (pl->priv->prop_iters, (gpointer) prop->name, gtk_tree_iter_copy (&iter));
/* Listen for updates */
signal_name = g_strdup_printf ("notify::%s", prop->name);
pl->priv->signal_cnxs =
g_list_prepend (pl->priv->signal_cnxs, GINT_TO_POINTER(
g_signal_connect(object, signal_name,
G_CALLBACK (parasite_proplist_prop_changed_cb),
pl)));
g_free (signal_name);
}
}
// vim: set et sw=4 ts=4:

View File

@ -0,0 +1,60 @@
/*
* Copyright (c) 2008-2009 Christian Hammond
* Copyright (c) 2008-2009 David Trowbridge
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef _GTKPARASITE_PROPLIST_H_
#define _GTKPARASITE_PROPLIST_H_
#include <gtk/gtk.h>
#define PARASITE_TYPE_PROPLIST (parasite_proplist_get_type())
#define PARASITE_PROPLIST(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), PARASITE_TYPE_PROPLIST, ParasitePropList))
#define PARASITE_PROPLIST_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), PARASITE_TYPE_PROPLIST, ParasitePropListClass))
#define PARASITE_IS_PROPLIST(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), PARASITE_TYPE_PROPLIST))
#define PARASITE_IS_PROPLIST_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), PARASITE_TYPE_PROPLIST))
#define PARASITE_PROPLIST_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), PARASITE_TYPE_PROPLIST, ParasitePropListClass))
typedef struct _ParasitePropListPrivate ParasitePropListPrivate;
typedef struct _ParasitePropList {
GtkTreeView parent;
ParasitePropListPrivate *priv;
} ParasitePropList;
typedef struct _ParasitePropListClass {
GtkTreeViewClass parent;
} ParasitePropListClass;
G_BEGIN_DECLS
GType parasite_proplist_get_type (void);
GtkWidget *parasite_proplist_new (GtkWidget *widget_tree);
void parasite_proplist_set_object (ParasitePropList *proplist,
GObject *object);
G_END_DECLS
#endif // _GTKPARASITE_PROPLIST_H_
// vim: set et sw=4 ts=4:

View File

@ -0,0 +1,410 @@
/*
* Copyright (c) 2008-2009 Christian Hammond
* Copyright (c) 2008-2009 David Trowbridge
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "parasite.h"
#include "property-cell-renderer.h"
#include "widget-tree.h"
struct _ParasitePropertyCellRendererPrivate
{
GObject *object;
char *name;
};
enum
{
PROP_0,
PROP_OBJECT,
PROP_NAME
};
G_DEFINE_TYPE_WITH_PRIVATE (ParasitePropertyCellRenderer, parasite_property_cell_renderer, GTK_TYPE_CELL_RENDERER_TEXT);
static void
parasite_property_cell_renderer_init(ParasitePropertyCellRenderer *renderer)
{
renderer->priv = parasite_property_cell_renderer_get_instance_private (renderer);
}
static void
get_property (GObject *object,
guint param_id,
GValue *value,
GParamSpec *pspec)
{
ParasitePropertyCellRenderer *r = PARASITE_PROPERTY_CELL_RENDERER (object);
switch (param_id)
{
case PROP_OBJECT:
g_value_set_object(value, r->priv->object);
break;
case PROP_NAME:
g_value_set_string(value, r->priv->name);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, param_id, pspec);
break;
}
}
static void
set_property (GObject *object,
guint param_id,
const GValue *value,
GParamSpec *pspec)
{
ParasitePropertyCellRenderer *r = PARASITE_PROPERTY_CELL_RENDERER (object);
switch (param_id)
{
case PROP_OBJECT:
r->priv->object = g_value_get_object (value);
break;
case PROP_NAME:
g_free (r->priv->name);
r->priv->name = g_value_dup_string (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, param_id, pspec);
break;
}
}
static void
stop_editing(GtkCellEditable *editable, GtkCellRenderer *renderer)
{
GObject *object;
const char *name;
GValue gvalue = {0};
GParamSpec *prop;
object = g_object_get_data(G_OBJECT(editable), "_prop_object");
name = g_object_get_data(G_OBJECT(editable), "_prop_name");
prop = g_object_class_find_property(G_OBJECT_GET_CLASS(object), name);
g_value_init(&gvalue, prop->value_type);
if (GTK_IS_ENTRY(editable))
{
gboolean canceled;
g_object_get(editable, "editing_canceled", &canceled, NULL);
gtk_cell_renderer_stop_editing(renderer, canceled);
if (canceled)
return;
if (GTK_IS_SPIN_BUTTON(editable))
{
double value =
g_ascii_strtod(gtk_entry_get_text(GTK_ENTRY(editable)), NULL);
if (G_IS_PARAM_SPEC_INT(prop))
g_value_set_int(&gvalue, (gint)value);
else if G_IS_PARAM_SPEC_UINT(prop)
g_value_set_uint(&gvalue, (guint)value);
else if G_IS_PARAM_SPEC_INT64(prop)
g_value_set_int64(&gvalue, (gint64)value);
else if G_IS_PARAM_SPEC_UINT64(prop)
g_value_set_uint64(&gvalue, (guint64)value);
else if G_IS_PARAM_SPEC_LONG(prop)
g_value_set_long(&gvalue, (glong)value);
else if G_IS_PARAM_SPEC_ULONG(prop)
g_value_set_ulong(&gvalue, (gulong)value);
else if G_IS_PARAM_SPEC_DOUBLE(prop)
g_value_set_double(&gvalue, (gdouble)value);
else
return;
}
else
{
g_value_set_string(&gvalue,
gtk_entry_get_text(GTK_ENTRY(editable)));
}
}
else if (GTK_IS_COMBO_BOX(editable))
{
// We have no way of getting the canceled state for a GtkComboBox.
gtk_cell_renderer_stop_editing(renderer, FALSE);
if (G_IS_PARAM_SPEC_BOOLEAN(prop))
{
g_value_set_boolean(&gvalue,
gtk_combo_box_get_active(GTK_COMBO_BOX(editable)) == 1);
}
else if (G_IS_PARAM_SPEC_ENUM(prop))
{
char *enum_name = gtk_combo_box_text_get_active_text (GTK_COMBO_BOX_TEXT (editable));
GEnumClass *enum_class;
GEnumValue *enum_value;
if (enum_name == NULL)
return;
enum_class = G_PARAM_SPEC_ENUM(prop)->enum_class;
enum_value = g_enum_get_value_by_name(enum_class, enum_name);
g_value_set_enum(&gvalue, enum_value->value);
g_free(enum_name);
}
}
g_object_set_property(object, name, &gvalue);
g_value_unset(&gvalue);
}
static GtkCellEditable *
start_editing (GtkCellRenderer *renderer,
GdkEvent *event,
GtkWidget *widget,
const gchar *path,
const GdkRectangle *background_area,
const GdkRectangle *cell_area,
GtkCellRendererState flags)
{
PangoFontDescription *font_desc;
GtkCellEditable *editable = NULL;
GObject *object;
const char *name;
GValue gvalue = {0};
GParamSpec *prop;
g_object_get(renderer,
"object", &object,
"name", &name,
NULL);
prop = g_object_class_find_property(G_OBJECT_GET_CLASS(object), name);
g_value_init(&gvalue, prop->value_type);
g_object_get_property(object, name, &gvalue);
if (G_VALUE_HOLDS_OBJECT (&gvalue))
{
ParasiteWidgetTree *widget_tree = g_object_get_data (G_OBJECT (renderer), "parasite-widget-tree");
GObject *prop_object = g_value_get_object (&gvalue);
GtkTreeIter iter;
if (prop_object)
{
/* First check if the value is already in the tree (happens with 'parent' for instance) */
if (parasite_widget_tree_find_object (widget_tree, prop_object, &iter))
{
parasite_widget_tree_select_object (widget_tree, prop_object);
}
else if (parasite_widget_tree_find_object (widget_tree, object, &iter))
{
parasite_widget_tree_append_object (widget_tree, prop_object, &iter);
parasite_widget_tree_select_object (widget_tree, prop_object);
}
else
{
g_warning ("Parasite: couldn't find the widget in the tree");
}
}
g_value_unset (&gvalue);
return NULL;
}
else
{
if (!(prop->flags & G_PARAM_WRITABLE))
return NULL;
if (G_VALUE_HOLDS_ENUM(&gvalue) || G_VALUE_HOLDS_BOOLEAN(&gvalue))
{
GtkWidget *combobox = gtk_combo_box_text_new ();
gtk_widget_show(combobox);
g_object_set(G_OBJECT(combobox), "has-frame", FALSE, NULL);
GList *renderers;
if (G_VALUE_HOLDS_BOOLEAN(&gvalue))
{
gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (combobox), "FALSE");
gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (combobox), "TRUE");
gtk_combo_box_set_active(GTK_COMBO_BOX (combobox), g_value_get_boolean (&gvalue) ? 1 : 0);
}
else if (G_VALUE_HOLDS_ENUM(&gvalue))
{
gint value = g_value_get_enum(&gvalue);
GEnumClass *enum_class = G_PARAM_SPEC_ENUM(prop)->enum_class;
guint i;
for (i = 0; i < enum_class->n_values; i++)
{
GEnumValue *enum_value = &enum_class->values[i];
gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (combobox),
enum_value->value_name);
if (enum_value->value == value)
gtk_combo_box_set_active(GTK_COMBO_BOX(combobox), i);
}
}
renderers = gtk_cell_layout_get_cells(GTK_CELL_LAYOUT(combobox));
g_object_set(G_OBJECT(renderers->data), "scale", TREE_TEXT_SCALE, NULL);
g_list_free(renderers);
editable = GTK_CELL_EDITABLE(combobox);
}
else if (G_VALUE_HOLDS_STRING(&gvalue))
{
GtkWidget *entry = gtk_entry_new();
gtk_widget_show(entry);
gtk_entry_set_text(GTK_ENTRY(entry), g_value_get_string(&gvalue));
editable = GTK_CELL_EDITABLE(entry);
}
else if (G_VALUE_HOLDS_INT(&gvalue) ||
G_VALUE_HOLDS_UINT(&gvalue) ||
G_VALUE_HOLDS_INT64(&gvalue) ||
G_VALUE_HOLDS_UINT64(&gvalue) ||
G_VALUE_HOLDS_LONG(&gvalue) ||
G_VALUE_HOLDS_ULONG(&gvalue) ||
G_VALUE_HOLDS_DOUBLE(&gvalue))
{
double min, max, value;
GtkWidget *spinbutton;
guint digits = 0;
if (G_VALUE_HOLDS_INT(&gvalue))
{
GParamSpecInt *paramspec = G_PARAM_SPEC_INT(prop);
min = paramspec->minimum;
max = paramspec->maximum;
value = g_value_get_int(&gvalue);
}
else if (G_VALUE_HOLDS_UINT(&gvalue))
{
GParamSpecUInt *paramspec = G_PARAM_SPEC_UINT(prop);
min = paramspec->minimum;
max = paramspec->maximum;
value = g_value_get_uint(&gvalue);
}
else if (G_VALUE_HOLDS_INT64(&gvalue))
{
GParamSpecInt64 *paramspec = G_PARAM_SPEC_INT64(prop);
min = paramspec->minimum;
max = paramspec->maximum;
value = g_value_get_int64(&gvalue);
}
else if (G_VALUE_HOLDS_UINT64(&gvalue))
{
GParamSpecUInt64 *paramspec = G_PARAM_SPEC_UINT64(prop);
min = paramspec->minimum;
max = paramspec->maximum;
value = g_value_get_uint64(&gvalue);
}
else if (G_VALUE_HOLDS_LONG(&gvalue))
{
GParamSpecLong *paramspec = G_PARAM_SPEC_LONG(prop);
min = paramspec->minimum;
max = paramspec->maximum;
value = g_value_get_long(&gvalue);
}
else if (G_VALUE_HOLDS_ULONG(&gvalue))
{
GParamSpecULong *paramspec = G_PARAM_SPEC_ULONG(prop);
min = paramspec->minimum;
max = paramspec->maximum;
value = g_value_get_ulong(&gvalue);
}
else if (G_VALUE_HOLDS_DOUBLE(&gvalue))
{
GParamSpecDouble *paramspec = G_PARAM_SPEC_DOUBLE(prop);
min = paramspec->minimum;
max = paramspec->maximum;
value = g_value_get_double(&gvalue);
digits = 2;
}
else
{
// Shouldn't really be able to happen.
return NULL;
}
spinbutton = gtk_spin_button_new_with_range(min, max, 1);
gtk_widget_show(spinbutton);
gtk_spin_button_set_value(GTK_SPIN_BUTTON(spinbutton), value);
gtk_spin_button_set_digits(GTK_SPIN_BUTTON(spinbutton), digits);
editable = GTK_CELL_EDITABLE(spinbutton);
}
}
g_value_unset(&gvalue);
if (!editable)
return NULL;
font_desc = pango_font_description_new();
pango_font_description_set_size(font_desc, 8 * PANGO_SCALE);
gtk_widget_override_font (GTK_WIDGET (editable), font_desc);
pango_font_description_free(font_desc);
g_signal_connect(editable, "editing_done", G_CALLBACK (stop_editing), renderer);
g_object_set_data_full (G_OBJECT (editable), "_prop_name", g_strdup (name), g_free);
g_object_set_data (G_OBJECT (editable), "_prop_object", object);
return editable;
}
static void
parasite_property_cell_renderer_class_init (ParasitePropertyCellRendererClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GtkCellRendererClass *cell_class = GTK_CELL_RENDERER_CLASS (klass);
object_class->get_property = get_property;
object_class->set_property = set_property;
cell_class->start_editing = start_editing;
g_object_class_install_property(object_class,
PROP_OBJECT,
g_param_spec_object ("object",
"Object",
"The object owning the property",
G_TYPE_OBJECT,
G_PARAM_READWRITE));
g_object_class_install_property(object_class,
PROP_NAME,
g_param_spec_string ("name",
"Name",
"The property name",
NULL,
G_PARAM_READWRITE));
}
GtkCellRenderer *
parasite_property_cell_renderer_new(void)
{
return g_object_new(PARASITE_TYPE_PROPERTY_CELL_RENDERER, NULL);
}
// vim: set et ts=4:

View File

@ -0,0 +1,70 @@
/*
* Copyright (c) 2008-2009 Christian Hammond
* Copyright (c) 2008-2009 David Trowbridge
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef _GTKPARASITE_PROPERTY_CELL_RENDERER_H_
#define _GTKPARASITE_PROPERTY_CELL_RENDERER_H_
#include <gtk/gtk.h>
#define PARASITE_TYPE_PROPERTY_CELL_RENDERER (parasite_property_cell_renderer_get_type())
#define PARASITE_PROPERTY_CELL_RENDERER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), PARASITE_TYPE_PROPERTY_CELL_RENDERER, ParasitePropertyCellRenderer))
#define PARASITE_PROPERTY_CELL_RENDERER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), PARASITE_TYPE_PROPERTY_CELL_RENDERER, ParasitePropertyCellRendererClass))
#define PARASITE_IS_PROPERTY_CELL_RENDERER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), PARASITE_TYPE_PROPERTY_CELL_RENDERER))
#define PARASITE_IS_PROPERTY_CELL_RENDERER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), PARASITE_TYPE_PROPERTY_CELL_RENDERER))
#define PARASITE_PROPERTY_CELL_RENDERER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), PARASITE_TYPE_PROPERTY_CELL_RENDERER, ParasitePropertyCellRendererClass))
typedef struct _ParasitePropertyCellRendererPrivate ParasitePropertyCellRendererPrivate;
typedef struct
{
GtkCellRendererText parent;
ParasitePropertyCellRendererPrivate *priv;
} ParasitePropertyCellRenderer;
typedef struct
{
GtkCellRendererTextClass parent;
// Padding for future expansion
void (*reserved0)(void);
void (*reserved1)(void);
void (*reserved2)(void);
void (*reserved3)(void);
} ParasitePropertyCellRendererClass;
G_BEGIN_DECLS
GType parasite_property_cell_renderer_get_type();
GtkCellRenderer *parasite_property_cell_renderer_new();
G_END_DECLS
#endif // _GTKPARASITE_PROPERTY_CELL_RENDERER_H_
// vim: set et sw=4 ts=4:

View File

@ -0,0 +1,238 @@
/*
* Copyright (c) 2008-2009 Christian Hammond
* Copyright (c) 2008-2009 David Trowbridge
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include <dlfcn.h>
#include "config.h"
#include <signal.h>
#ifdef ENABLE_PYTHON
# include <Python.h>
# include <pygobject.h>
#endif
#include "python-hooks.h"
static gboolean python_enabled = FALSE;
#ifdef ENABLE_PYTHON
static GString *captured_stdout = NULL;
static GString *captured_stderr = NULL;
static PyObject *
capture_stdout(PyObject *self, PyObject *args)
{
char *str = NULL;
if (!PyArg_ParseTuple(args, "s", &str))
return NULL;
g_string_append(captured_stdout, str);
Py_INCREF(Py_None);
return Py_None;
}
static PyObject *
capture_stderr(PyObject *self, PyObject *args)
{
char *str = NULL;
if (!PyArg_ParseTuple(args, "s", &str))
return NULL;
g_string_append(captured_stderr, str);
Py_INCREF(Py_None);
return Py_None;
}
static PyObject *
wrap_gobj(PyObject *self, PyObject *args)
{
void *addr;
GObject *obj;
if (!PyArg_ParseTuple(args, "l", &addr))
return NULL;
if (!G_IS_OBJECT(addr))
return NULL; // XXX
obj = G_OBJECT(addr);
if (!obj)
return NULL; // XXX
return pygobject_new(obj);
}
static PyMethodDef parasite_python_methods[] = {
{"capture_stdout", capture_stdout, METH_VARARGS, "Captures stdout"},
{"capture_stderr", capture_stderr, METH_VARARGS, "Captures stderr"},
{"gobj", wrap_gobj, METH_VARARGS, "Wraps a C GObject"},
{NULL, NULL, 0, NULL}
};
static gboolean
is_blacklisted(void)
{
const char *prgname = g_get_prgname();
return (!strcmp(prgname, "gimp"));
}
#endif // ENABLE_PYTHON
void
parasite_python_init(void)
{
#ifdef ENABLE_PYTHON
int res;
struct sigaction old_sigint;
if (is_blacklisted())
return;
/* This prevents errors such as "undefined symbol: PyExc_ImportError" */
if (!dlopen(PYTHON_SHARED_LIB, RTLD_NOW | RTLD_GLOBAL))
{
g_error("%s\n", dlerror());
return;
}
captured_stdout = g_string_new("");
captured_stderr = g_string_new("");
/* Back up and later restore SIGINT so Python doesn't steal it from us. */
res = sigaction(SIGINT, NULL, &old_sigint);
if (!Py_IsInitialized())
Py_Initialize();
res = sigaction(SIGINT, &old_sigint, NULL);
Py_InitModule("parasite", parasite_python_methods);
PyRun_SimpleString(
"import parasite\n"
"import sys\n"
"\n"
"class StdoutCatcher:\n"
" def write(self, str):\n"
" parasite.capture_stdout(str)\n"
"\n"
"class StderrCatcher:\n"
" def write(self, str):\n"
" parasite.capture_stderr(str)\n"
"\n"
);
if (!pygobject_init(-1, -1, -1))
{
fprintf(stderr, "Error initializing pygobject support.\n");
PyErr_Print();
return;
}
char *argv[] = { "", NULL };
PySys_SetArgv(0, argv);
if (!PyImport_ImportModule("gi._gobject"))
{
PyErr_SetString(PyExc_ImportError, "could not import gi.gobject");
return;
}
if (!PyImport_ImportModule("gi.repository"))
{
PyErr_SetString(PyExc_ImportError, "could not import gi.repository");
return;
}
if (!PyImport_ImportModule("gi.repository.Gtk"))
{
PyErr_SetString(PyExc_ImportError, "could not import gtk");
return;
}
python_enabled = TRUE;
#endif // ENABLE_PYTHON
}
void
parasite_python_run(const char *command,
ParasitePythonLogger stdout_logger,
ParasitePythonLogger stderr_logger,
gpointer user_data)
{
#ifdef ENABLE_PYTHON
PyGILState_STATE gstate;
PyObject *module;
PyObject *dict;
PyObject *obj;
gstate = PyGILState_Ensure();
module = PyImport_AddModule("__main__");
dict = PyModule_GetDict(module);
PyRun_SimpleString("old_stdout = sys.stdout\n"
"old_stderr = sys.stderr\n"
"sys.stdout = StdoutCatcher()\n"
"sys.stderr = StderrCatcher()\n");
obj = PyRun_String(command, Py_single_input, dict, dict);
PyRun_SimpleString("sys.stdout = old_stdout\n"
"sys.stderr = old_stderr\n");
if (stdout_logger != NULL)
stdout_logger(captured_stdout->str, user_data);
if (stderr_logger != NULL)
stderr_logger(captured_stderr->str, user_data);
// Print any returned object
if (obj != NULL && obj != Py_None) {
PyObject *repr = PyObject_Repr(obj);
if (repr != NULL) {
char *string = PyString_AsString(repr);
stdout_logger(string, user_data);
stdout_logger("\n", user_data);
}
Py_XDECREF(repr);
}
Py_XDECREF(obj);
PyGILState_Release(gstate);
g_string_erase(captured_stdout, 0, -1);
g_string_erase(captured_stderr, 0, -1);
#endif // ENABLE_PYTHON
}
gboolean
parasite_python_is_enabled(void)
{
return python_enabled;
}
// vim: set et sw=4 ts=4:

View File

@ -0,0 +1,38 @@
/*
* Copyright (c) 2008-2009 Christian Hammond
* Copyright (c) 2008-2009 David Trowbridge
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef _GTKPARASITE_PYTHON_MODULE_H_
#define _GTKPARASITE_PYTHON_MODULE_H_
#include <glib.h>
typedef void (*ParasitePythonLogger)(const char *text, gpointer user_data);
void parasite_python_init(void);
void parasite_python_run(const char *command,
ParasitePythonLogger stdout_logger,
ParasitePythonLogger stderr_logger,
gpointer user_data);
gboolean parasite_python_is_enabled(void);
#endif // _GTKPARASITE_PYTHON_MODULE_H_

View File

@ -0,0 +1,409 @@
/*
* Copyright (c) 2008-2009 Christian Hammond
* Copyright (c) 2008-2009 David Trowbridge
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include <gdk/gdkkeysyms.h>
#include <string.h>
#include "python-hooks.h"
#include "python-shell.h"
#define MAX_HISTORY_LENGTH 20
struct _ParasitePythonShellPrivate
{
GtkWidget *textview;
GtkTextMark *scroll_mark;
GtkTextMark *line_start_mark;
GQueue *history;
GList *cur_history_item;
GString *pending_command;
gboolean in_block;
};
G_DEFINE_TYPE_WITH_PRIVATE (ParasitePythonShell, parasite_python_shell, GTK_TYPE_BOX);
/* Widget functions */
static void parasite_python_shell_finalize (GObject *obj);
/* Python integration */
static void parasite_python_shell_write_prompt(GtkWidget *python_shell);
static char *parasite_python_shell_get_input(GtkWidget *python_shell);
/* Callbacks */
static gboolean parasite_python_shell_key_press_cb(GtkWidget *textview,
GdkEventKey *event,
GtkWidget *python_shell);
static void
parasite_python_shell_class_init(ParasitePythonShellClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS(klass);
object_class->finalize = parasite_python_shell_finalize;
}
static void
parasite_python_shell_init (ParasitePythonShell *python_shell)
{
GtkWidget *swin;
GtkTextBuffer *buffer;
GtkTextIter iter;
PangoFontDescription *font_desc;
python_shell->priv = parasite_python_shell_get_instance_private (python_shell);
python_shell->priv->history = g_queue_new();
gtk_box_set_spacing(GTK_BOX(python_shell), 6);
swin = gtk_scrolled_window_new(NULL, NULL);
gtk_widget_show(swin);
gtk_box_pack_start(GTK_BOX(python_shell), swin, TRUE, TRUE, 0);
gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(swin),
GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(swin),
GTK_SHADOW_IN);
python_shell->priv->textview = gtk_text_view_new();
gtk_widget_show(python_shell->priv->textview);
gtk_container_add(GTK_CONTAINER(swin), python_shell->priv->textview);
gtk_text_view_set_cursor_visible(GTK_TEXT_VIEW(python_shell->priv->textview), TRUE);
gtk_text_view_set_pixels_above_lines(GTK_TEXT_VIEW(python_shell->priv->textview), 3);
gtk_text_view_set_left_margin(GTK_TEXT_VIEW(python_shell->priv->textview), 3);
gtk_text_view_set_right_margin(GTK_TEXT_VIEW(python_shell->priv->textview), 3);
g_signal_connect(python_shell->priv->textview, "key_press_event",
G_CALLBACK(parasite_python_shell_key_press_cb),
python_shell);
/* Make the textview monospaced */
font_desc = pango_font_description_from_string("monospace");
pango_font_description_set_size(font_desc, 8 * PANGO_SCALE);
gtk_widget_override_font(python_shell->priv->textview, font_desc);
pango_font_description_free(font_desc);
/* Create the end-of-buffer mark */
buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(python_shell->priv->textview));
gtk_text_buffer_get_end_iter(buffer, &iter);
python_shell->priv->scroll_mark = gtk_text_buffer_create_mark(buffer, "scroll_mark",
&iter, FALSE);
/* Create the beginning-of-line mark */
python_shell->priv->line_start_mark = gtk_text_buffer_create_mark(buffer,
"line_start_mark",
&iter, TRUE);
/* Register some tags */
gtk_text_buffer_create_tag(buffer, "stdout", NULL);
gtk_text_buffer_create_tag(buffer, "stderr",
"foreground", "red",
"paragraph-background", "#FFFFE0",
NULL);
gtk_text_buffer_create_tag(buffer, "prompt",
"foreground", "blue",
NULL);
parasite_python_shell_write_prompt(GTK_WIDGET(python_shell));
}
static void
parasite_python_shell_finalize(GObject *python_shell)
{
ParasitePythonShellPrivate *priv = PARASITE_PYTHON_SHELL(python_shell)->priv;
g_queue_free(priv->history);
}
static void
parasite_python_shell_log_stdout(const char *text, gpointer python_shell)
{
parasite_python_shell_append_text(PARASITE_PYTHON_SHELL(python_shell),
text, "stdout");
}
static void
parasite_python_shell_log_stderr(const char *text, gpointer python_shell)
{
parasite_python_shell_append_text(PARASITE_PYTHON_SHELL(python_shell),
text, "stderr");
}
static void
parasite_python_shell_write_prompt(GtkWidget *python_shell)
{
ParasitePythonShellPrivate *priv = PARASITE_PYTHON_SHELL(python_shell)->priv;
GtkTextBuffer *buffer =
gtk_text_view_get_buffer(GTK_TEXT_VIEW(priv->textview));
GtkTextIter iter;
const char *prompt = (priv->pending_command == NULL ? ">>> " : "... ");
parasite_python_shell_append_text(PARASITE_PYTHON_SHELL(python_shell),
prompt, "prompt");
gtk_text_buffer_get_end_iter(buffer, &iter);
gtk_text_buffer_move_mark(buffer, priv->line_start_mark, &iter);
}
static void
parasite_python_shell_process_line(GtkWidget *python_shell)
{
ParasitePythonShellPrivate *priv = PARASITE_PYTHON_SHELL(python_shell)->priv;
char *command = parasite_python_shell_get_input(python_shell);
char last_char;
parasite_python_shell_append_text(PARASITE_PYTHON_SHELL(python_shell),
"\n", NULL);
if (*command != '\0')
{
/* Save this command in the history. */
g_queue_push_head(priv->history, command);
priv->cur_history_item = NULL;
if (g_queue_get_length(priv->history) > MAX_HISTORY_LENGTH)
g_free(g_queue_pop_tail(priv->history));
}
last_char = command[MAX(0, strlen(command) - 1)];
if (last_char == ':' || last_char == '\\' ||
(priv->in_block && g_ascii_isspace(command[0])))
{
printf("in block.. %c, %d, %d\n",
last_char, priv->in_block,
g_ascii_isspace(command[0]));
/* This is a multi-line expression */
if (priv->pending_command == NULL)
priv->pending_command = g_string_new(command);
else
g_string_append(priv->pending_command, command);
g_string_append_c(priv->pending_command, '\n');
if (last_char == ':')
priv->in_block = TRUE;
}
else
{
if (priv->pending_command != NULL)
{
g_string_append(priv->pending_command, command);
g_string_append_c(priv->pending_command, '\n');
/* We're not actually leaking this. It's in the history. */
command = g_string_free(priv->pending_command, FALSE);
}
parasite_python_run(command,
parasite_python_shell_log_stdout,
parasite_python_shell_log_stderr,
python_shell);
if (priv->pending_command != NULL)
{
/* Now do the cleanup. */
g_free(command);
priv->pending_command = NULL;
priv->in_block = FALSE;
}
}
parasite_python_shell_write_prompt(python_shell);
}
static void
parasite_python_shell_replace_input(GtkWidget *python_shell,
const char *text)
{
ParasitePythonShellPrivate *priv = PARASITE_PYTHON_SHELL(python_shell)->priv;
GtkTextBuffer *buffer =
gtk_text_view_get_buffer(GTK_TEXT_VIEW(priv->textview));
GtkTextIter start_iter;
GtkTextIter end_iter;
gtk_text_buffer_get_iter_at_mark(buffer, &start_iter,
priv->line_start_mark);
gtk_text_buffer_get_end_iter(buffer, &end_iter);
gtk_text_buffer_delete(buffer, &start_iter, &end_iter);
gtk_text_buffer_insert(buffer, &end_iter, text, -1);
}
static char *
parasite_python_shell_get_input(GtkWidget *python_shell)
{
ParasitePythonShellPrivate *priv = PARASITE_PYTHON_SHELL(python_shell)->priv;
GtkTextBuffer *buffer =
gtk_text_view_get_buffer(GTK_TEXT_VIEW(priv->textview));
GtkTextIter start_iter;
GtkTextIter end_iter;
gtk_text_buffer_get_iter_at_mark(buffer, &start_iter,
priv->line_start_mark);
gtk_text_buffer_get_end_iter(buffer, &end_iter);
return gtk_text_buffer_get_text(buffer, &start_iter, &end_iter, FALSE);
}
static const char *
parasite_python_shell_get_history_back(GtkWidget *python_shell)
{
ParasitePythonShellPrivate *priv = PARASITE_PYTHON_SHELL(python_shell)->priv;
if (priv->cur_history_item == NULL)
{
priv->cur_history_item = g_queue_peek_head_link(priv->history);
if (priv->cur_history_item == NULL)
return "";
}
else if (priv->cur_history_item->next != NULL)
priv->cur_history_item = priv->cur_history_item->next;
return (const char *)priv->cur_history_item->data;
}
static const char *
parasite_python_shell_get_history_forward(GtkWidget *python_shell)
{
ParasitePythonShellPrivate *priv = PARASITE_PYTHON_SHELL(python_shell)->priv;
if (priv->cur_history_item == NULL || priv->cur_history_item->prev == NULL)
{
priv->cur_history_item = NULL;
return "";
}
priv->cur_history_item = priv->cur_history_item->prev;
return (const char *)priv->cur_history_item->data;
}
static gboolean
parasite_python_shell_key_press_cb(GtkWidget *textview,
GdkEventKey *event,
GtkWidget *python_shell)
{
if (event->keyval == GDK_KEY_Return)
{
parasite_python_shell_process_line(python_shell);
return TRUE;
}
else if (event->keyval == GDK_KEY_Up)
{
parasite_python_shell_replace_input(python_shell,
parasite_python_shell_get_history_back(python_shell));
return TRUE;
}
else if (event->keyval == GDK_KEY_Down)
{
parasite_python_shell_replace_input(python_shell,
parasite_python_shell_get_history_forward(python_shell));
return TRUE;
}
else if (event->string != NULL)
{
ParasitePythonShellPrivate *priv = PARASITE_PYTHON_SHELL(python_shell)->priv;
GtkTextBuffer *buffer =
gtk_text_view_get_buffer(GTK_TEXT_VIEW(priv->textview));
GtkTextMark *insert_mark = gtk_text_buffer_get_insert(buffer);
GtkTextMark *selection_mark =
gtk_text_buffer_get_selection_bound(buffer);
GtkTextIter insert_iter;
GtkTextIter selection_iter;
GtkTextIter start_iter;
gint cmp_start_insert;
gint cmp_start_select;
gint cmp_insert_select;
gtk_text_buffer_get_iter_at_mark(buffer, &start_iter,
priv->line_start_mark);
gtk_text_buffer_get_iter_at_mark(buffer, &insert_iter, insert_mark);
gtk_text_buffer_get_iter_at_mark(buffer, &selection_iter,
selection_mark);
cmp_start_insert = gtk_text_iter_compare(&start_iter, &insert_iter);
cmp_start_select = gtk_text_iter_compare(&start_iter, &selection_iter);
cmp_insert_select = gtk_text_iter_compare(&insert_iter,
&selection_iter);
if (cmp_start_insert == 0 && cmp_start_select == 0 &&
(event->keyval == GDK_KEY_BackSpace ||
event->keyval == GDK_KEY_Left))
{
return TRUE;
}
if (cmp_start_insert <= 0 && cmp_start_select <= 0)
{
return FALSE;
}
else if (cmp_start_insert > 0 && cmp_start_select > 0)
{
gtk_text_buffer_place_cursor(buffer, &start_iter);
}
else if (cmp_insert_select < 0)
{
gtk_text_buffer_move_mark(buffer, insert_mark, &start_iter);
}
else if (cmp_insert_select > 0)
{
gtk_text_buffer_move_mark(buffer, selection_mark, &start_iter);
}
}
return FALSE;
}
GtkWidget *
parasite_python_shell_new(void)
{
return g_object_new(PARASITE_TYPE_PYTHON_SHELL, NULL);
}
void
parasite_python_shell_append_text(ParasitePythonShell *python_shell,
const char *str,
const char *tag)
{
ParasitePythonShellPrivate *priv = python_shell->priv;
GtkTextIter end;
GtkTextBuffer *buffer =
gtk_text_view_get_buffer(GTK_TEXT_VIEW(priv->textview));
GtkTextMark *mark = gtk_text_buffer_get_insert(buffer);
gtk_text_buffer_get_end_iter(buffer, &end);
gtk_text_buffer_move_mark(buffer, mark, &end);
gtk_text_buffer_insert_with_tags_by_name(buffer, &end, str, -1, tag, NULL);
gtk_text_view_scroll_to_mark(GTK_TEXT_VIEW(priv->textview), mark,
0, TRUE, 0, 1);
}
void
parasite_python_shell_focus(ParasitePythonShell *python_shell)
{
gtk_widget_grab_focus (python_shell->priv->textview);
}
// vim: set et ts=4:

View File

@ -0,0 +1,68 @@
/*
* Copyright (c) 2008-2009 Christian Hammond
* Copyright (c) 2008-2009 David Trowbridge
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef _PARASITE_PYTHON_SHELL_H_
#define _PARASITE_PYTHON_SHELL_H_
typedef struct _ParasitePythonShell ParasitePythonShell;
typedef struct _ParasitePythonShellClass ParasitePythonShellClass;
typedef struct _ParasitePythonShellPrivate ParasitePythonShellPrivate;
#include <gtk/gtk.h>
#define PARASITE_TYPE_PYTHON_SHELL (parasite_python_shell_get_type())
#define PARASITE_PYTHON_SHELL(obj) \
(G_TYPE_CHECK_INSTANCE_CAST((obj), PARASITE_TYPE_PYTHON_SHELL, ParasitePythonShell))
#define PARASITE_PYTHON_SHELL_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST((klass), PARASITE_TYPE_PYTHON_SHELL, ParasitePythonShellClass))
#define PARASITE_IS_PYTHON_SHELL(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE((obj), PARASITE_TYPE_PYTHON_SHELL))
#define PARASITE_IS_PYTHON_SHELL_CLASS(klass) \
(G_TYPE_CHECK_CLASS_TYPE((klass), PARASITE_TYPE_PYTHON_SHELL))
#define PARASITE_PYTHON_SHELL_GET_CLASS(obj) \
(G_TYPE_INSTANCE_GET_CLASS ((obj), PARASITE_TYPE_PYTHON_SHELL, ParasitePythonShellClass))
struct _ParasitePythonShell
{
GtkBox parent_object;
ParasitePythonShellPrivate *priv;
};
struct _ParasitePythonShellClass
{
GtkBoxClass parent_class;
};
G_BEGIN_DECLS
GType parasite_python_shell_get_type(void);
GtkWidget *parasite_python_shell_new(void);
void parasite_python_shell_append_text(ParasitePythonShell *python_shell,
const char *str,
const char *tag);
void parasite_python_shell_focus(ParasitePythonShell *python_shell);
G_END_DECLS
#endif // _PARASITE_PYTHON_SHELL_H_

View File

@ -0,0 +1,177 @@
/*
* Copyright (c) 2013 Intel Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "themes.h"
struct _ParasiteThemesPrivate
{
int dummy;
};
G_DEFINE_TYPE_WITH_PRIVATE (ParasiteThemes, parasite_themes, GTK_TYPE_LIST_BOX)
static void
parasite_themes_init (ParasiteThemes *pt)
{
pt->priv = parasite_themes_get_instance_private (pt);
}
static GtkWidget *
create_dark (ParasiteThemes *pt)
{
GtkWidget *b, *l, *s;
b = g_object_new (GTK_TYPE_BOX,
"orientation", GTK_ORIENTATION_HORIZONTAL,
"margin", 10,
NULL);
l = g_object_new (GTK_TYPE_LABEL,
"label", "Use dark variant",
"hexpand", TRUE,
"xalign", 0.0,
NULL);
gtk_container_add (GTK_CONTAINER (b), l);
s = gtk_switch_new ();
g_object_bind_property (s, "active",
gtk_settings_get_default (), "gtk-application-prefer-dark-theme",
G_BINDING_BIDIRECTIONAL);
gtk_container_add (GTK_CONTAINER (b), s);
return b;
}
static void
fill_gtk (const char *path, GHashTable *t)
{
const gchar *dir_entry;
GDir *dir = g_dir_open (path, 0, NULL);
if (!dir)
return;
while ((dir_entry = g_dir_read_name (dir)))
{
char *filename = g_build_filename (path, dir_entry, "gtk-3.0", NULL);
if (g_file_test (filename, G_FILE_TEST_IS_DIR)
&& !g_hash_table_contains (t, dir_entry))
g_hash_table_add (t, g_strdup (dir_entry));
g_free (filename);
}
}
static void
gtk_changed (GtkComboBox *c, ParasiteThemes *pt)
{
char *theme = gtk_combo_box_text_get_active_text (GTK_COMBO_BOX_TEXT (c));
g_object_set (gtk_settings_get_default (),
"gtk-theme-name", theme,
NULL);
g_free (theme);
}
static GtkWidget *
create_gtk (ParasiteThemes *pt)
{
GtkWidget *b, *l, *c;
GHashTable *t;
char *theme, *default_theme, *path;
GHashTableIter iter;
int i, pos;
GSettings *settings;
b = g_object_new (GTK_TYPE_BOX,
"orientation", GTK_ORIENTATION_HORIZONTAL,
"margin", 10,
NULL);
l = g_object_new (GTK_TYPE_LABEL,
"label", "GTK+ Theme",
"hexpand", TRUE,
"xalign", 0.0,
NULL);
gtk_container_add (GTK_CONTAINER (b), l);
t = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
fill_gtk (GTK_DATADIR "/themes", t);
path = g_build_filename (g_get_user_data_dir (), "themes", NULL);
fill_gtk (path, t);
g_free (path);
c = gtk_combo_box_text_new ();
gtk_container_add (GTK_CONTAINER (b), c);
settings = g_settings_new ("org.gnome.desktop.interface");
default_theme = g_settings_get_string (settings, "gtk-theme");
g_object_unref (settings);
g_hash_table_iter_init (&iter, t);
pos = i = 0;
while (g_hash_table_iter_next (&iter, (gpointer *)&theme, NULL))
{
gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (c), theme);
if (g_strcmp0 (theme, default_theme) == 0)
pos = i;
i++;
}
g_hash_table_destroy (t);
gtk_combo_box_set_active (GTK_COMBO_BOX (c), pos);
g_signal_connect (c, "changed", G_CALLBACK (gtk_changed), pt);
return b;
}
static void
constructed (GObject *object)
{
ParasiteThemes *pt = PARASITE_THEMES (object);
GtkContainer *box = GTK_CONTAINER (object);
g_object_set (object,
"selection-mode", GTK_SELECTION_NONE,
NULL);
gtk_container_add (box, create_dark (pt));
gtk_container_add (box, create_gtk (pt));
}
static void
parasite_themes_class_init (ParasiteThemesClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->constructed = constructed;
}
GtkWidget *
parasite_themes_new (void)
{
return GTK_WIDGET (g_object_new (PARASITE_TYPE_THEMES, NULL));
}
// vim: set et sw=4 ts=4:

View File

@ -0,0 +1,56 @@
/*
* Copyright (c) 2013 Intel Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef _GTKPARASITE_THEMES_H_
#define _GTKPARASITE_THEMES_H_
#include <gtk/gtk.h>
#define PARASITE_TYPE_THEMES (parasite_themes_get_type())
#define PARASITE_THEMES(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), PARASITE_TYPE_THEMES, ParasiteThemes))
#define PARASITE_THEMES_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), PARASITE_TYPE_THEMES, ParasiteThemesClass))
#define PARASITE_IS_THEMES(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), PARASITE_TYPE_THEMES))
#define PARASITE_IS_THEMES_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), PARASITE_TYPE_THEMES))
#define PARASITE_THEMES_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), PARASITE_TYPE_THEMES, ParasiteThemesClass))
typedef struct _ParasiteThemesPrivate ParasiteThemesPrivate;
typedef struct _ParasiteThemes {
GtkListBox parent;
ParasiteThemesPrivate *priv;
} ParasiteThemes;
typedef struct _ParasiteThemesClass {
GtkListBoxClass parent;
} ParasiteThemesClass;
G_BEGIN_DECLS
GType parasite_themes_get_type (void);
GtkWidget *parasite_themes_new (void);
G_END_DECLS
#endif // _GTKPARASITE_THEMES_H_
// vim: set et sw=4 ts=4:

View File

@ -0,0 +1,418 @@
/*
* Copyright (c) 2008-2009 Christian Hammond
* Copyright (c) 2008-2009 David Trowbridge
* Copyright (c) 2013 Intel Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "parasite.h"
#include "prop-list.h"
#include "widget-tree.h"
#include <string.h>
enum
{
OBJECT,
OBJECT_TYPE,
OBJECT_NAME,
WIDGET_REALIZED,
WIDGET_VISIBLE,
WIDGET_MAPPED,
OBJECT_ADDRESS,
SENSITIVE,
NUM_COLUMNS
};
enum
{
WIDGET_CHANGED,
LAST_SIGNAL
};
struct _ParasiteWidgetTreePrivate
{
GtkTreeStore *model;
GHashTable *iters;
};
static guint widget_tree_signals[LAST_SIGNAL] = { 0 };
G_DEFINE_TYPE_WITH_PRIVATE (ParasiteWidgetTree, parasite_widget_tree, GTK_TYPE_TREE_VIEW)
static void
parasite_widget_tree_on_widget_selected(GtkTreeSelection *selection,
ParasiteWidgetTree *widget_tree)
{
g_signal_emit(widget_tree, widget_tree_signals[WIDGET_CHANGED], 0);
}
static void
parasite_widget_tree_init (ParasiteWidgetTree *widget_tree)
{
GtkCellRenderer *renderer;
GtkTreeViewColumn *column;
GtkTreeSelection *selection;
widget_tree->priv = parasite_widget_tree_get_instance_private (widget_tree);
widget_tree->priv->iters = g_hash_table_new_full (g_direct_hash,
g_direct_equal,
NULL,
(GDestroyNotify) gtk_tree_iter_free);
widget_tree->priv->model = gtk_tree_store_new(
NUM_COLUMNS,
G_TYPE_POINTER, // OBJECT
G_TYPE_STRING, // OBJECT_TYPE
G_TYPE_STRING, // OBJECT_NAME
G_TYPE_BOOLEAN, // WIDGET_REALIZED
G_TYPE_BOOLEAN, // WIDGET_VISIBLE
G_TYPE_BOOLEAN, // WIDGET_MAPPED
G_TYPE_STRING, // OBJECT_ADDRESS
G_TYPE_BOOLEAN);// SENSITIVE
gtk_tree_view_set_model(GTK_TREE_VIEW(widget_tree),
GTK_TREE_MODEL(widget_tree->priv->model));
gtk_tree_view_set_enable_search(GTK_TREE_VIEW(widget_tree), TRUE);
gtk_tree_view_set_search_column(GTK_TREE_VIEW(widget_tree), OBJECT_NAME);
selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(widget_tree));
g_signal_connect(G_OBJECT(selection), "changed",
G_CALLBACK(parasite_widget_tree_on_widget_selected),
widget_tree);
// Widget column
renderer = gtk_cell_renderer_text_new();
g_object_set(G_OBJECT(renderer), "scale", TREE_TEXT_SCALE, NULL);
column = gtk_tree_view_column_new_with_attributes("Widget", renderer,
"text", OBJECT_TYPE,
"sensitive", SENSITIVE,
NULL);
gtk_tree_view_append_column(GTK_TREE_VIEW(widget_tree), column);
gtk_tree_view_column_set_resizable(column, TRUE);
// Name column
renderer = gtk_cell_renderer_text_new();
g_object_set(G_OBJECT(renderer), "scale", TREE_TEXT_SCALE, NULL);
column = gtk_tree_view_column_new_with_attributes("Name", renderer,
"text", OBJECT_NAME,
"sensitive", SENSITIVE,
NULL);
gtk_tree_view_append_column(GTK_TREE_VIEW(widget_tree), column);
gtk_tree_view_column_set_resizable(column, TRUE);
// Realized column
renderer = gtk_cell_renderer_toggle_new();
g_object_set(G_OBJECT(renderer),
"activatable", TRUE,
"indicator-size", TREE_CHECKBOX_SIZE,
NULL);
column = gtk_tree_view_column_new_with_attributes("Realized",
renderer,
"active", WIDGET_REALIZED,
NULL);
gtk_tree_view_append_column(GTK_TREE_VIEW(widget_tree), column);
// Mapped column
renderer = gtk_cell_renderer_toggle_new();
g_object_set(G_OBJECT(renderer),
"activatable", TRUE,
"indicator-size", TREE_CHECKBOX_SIZE,
NULL);
column = gtk_tree_view_column_new_with_attributes("Mapped",
renderer,
"active", WIDGET_MAPPED,
NULL);
gtk_tree_view_append_column(GTK_TREE_VIEW(widget_tree), column);
// Visible column
renderer = gtk_cell_renderer_toggle_new();
g_object_set(G_OBJECT(renderer),
"activatable", TRUE,
"indicator-size", TREE_CHECKBOX_SIZE,
NULL);
column = gtk_tree_view_column_new_with_attributes("Visible",
renderer,
"active", WIDGET_VISIBLE,
NULL);
gtk_tree_view_append_column(GTK_TREE_VIEW(widget_tree), column);
// Poinder Address column
renderer = gtk_cell_renderer_text_new();
g_object_set(G_OBJECT(renderer),
"scale", TREE_TEXT_SCALE,
"family", "monospace",
NULL);
column = gtk_tree_view_column_new_with_attributes("Pointer Address",
renderer,
"text", OBJECT_ADDRESS,
"sensitive", SENSITIVE,
NULL);
gtk_tree_view_append_column(GTK_TREE_VIEW(widget_tree), column);
gtk_tree_view_column_set_resizable(column, TRUE);
parasite_widget_tree_append_object (widget_tree, G_OBJECT (gtk_settings_get_default ()), NULL);
}
static void
parasite_widget_tree_class_init(ParasiteWidgetTreeClass *klass)
{
klass->widget_changed = NULL;
widget_tree_signals[WIDGET_CHANGED] =
g_signal_new("widget-changed",
G_OBJECT_CLASS_TYPE(klass),
G_SIGNAL_RUN_FIRST | G_SIGNAL_NO_RECURSE,
G_STRUCT_OFFSET(ParasiteWidgetTreeClass, widget_changed),
NULL, NULL,
g_cclosure_marshal_VOID__VOID,
G_TYPE_NONE, 0);
}
GtkWidget *
parasite_widget_tree_new ()
{
return g_object_new (PARASITE_TYPE_WIDGET_TREE, NULL);
}
GObject *
parasite_widget_tree_get_selected_object (ParasiteWidgetTree *widget_tree)
{
GtkTreeIter iter;
GtkTreeSelection *sel;
GtkTreeModel *model;
sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (widget_tree));
if (gtk_tree_selection_get_selected (sel, &model, &iter))
{
GObject *object;
gtk_tree_model_get (model, &iter,
OBJECT, &object,
-1);
return object;
}
return NULL;
}
static void
on_container_forall(GtkWidget *widget, gpointer data)
{
GList **list = (GList **)data;
*list = g_list_append(*list, widget);
}
void
parasite_widget_tree_append_object (ParasiteWidgetTree *widget_tree,
GObject *object,
GtkTreeIter *parent_iter)
{
GtkTreeIter iter;
const char *class_name = G_OBJECT_CLASS_NAME (G_OBJECT_GET_CLASS (object));
const char *name = NULL;
char *address;
gboolean realized;
gboolean mapped;
gboolean visible;
gboolean is_widget;
GList *l;
realized = mapped = visible = FALSE;
is_widget = GTK_IS_WIDGET (object);
if (is_widget)
{
GtkWidget *widget = GTK_WIDGET (object);
name = gtk_widget_get_name (GTK_WIDGET (object));
realized = gtk_widget_get_realized (widget);
mapped = gtk_widget_get_mapped (widget);
visible = gtk_widget_get_visible (widget);
}
if (name == NULL || g_strcmp0 (name, class_name) == 0)
{
if (GTK_IS_LABEL (object))
{
name = gtk_label_get_text (GTK_LABEL (object));
}
else if (GTK_IS_BUTTON (object))
{
name = gtk_button_get_label (GTK_BUTTON (object));
}
else if (GTK_IS_WINDOW (object))
{
name = gtk_window_get_title (GTK_WINDOW (object));
}
else
{
name = "";
}
}
address = g_strdup_printf ("%p", object);
gtk_tree_store_append (widget_tree->priv->model, &iter, parent_iter);
gtk_tree_store_set (widget_tree->priv->model, &iter,
OBJECT, object,
OBJECT_TYPE, class_name,
OBJECT_NAME, name,
WIDGET_REALIZED, realized,
WIDGET_MAPPED, mapped,
WIDGET_VISIBLE, visible,
OBJECT_ADDRESS, address,
SENSITIVE, !is_widget || (realized && mapped && visible),
-1);
g_hash_table_insert (widget_tree->priv->iters, object, gtk_tree_iter_copy (&iter));
g_free(address);
if (GTK_IS_CONTAINER (object))
{
GList* children = NULL;
/* Pick up all children, including those that are internal. */
gtk_container_forall (GTK_CONTAINER (object),
on_container_forall, &children);
for (l = children; l != NULL; l = l->next)
{
parasite_widget_tree_append_object (widget_tree, l->data, &iter);
}
g_list_free(children);
}
}
void
parasite_widget_tree_scan (ParasiteWidgetTree *widget_tree,
GtkWidget *window)
{
gtk_tree_store_clear (widget_tree->priv->model);
g_hash_table_remove_all (widget_tree->priv->iters);
parasite_widget_tree_append_object (widget_tree, G_OBJECT (gtk_settings_get_default ()), NULL);
parasite_widget_tree_append_object (widget_tree, G_OBJECT (window), NULL);
gtk_tree_view_columns_autosize (GTK_TREE_VIEW (widget_tree));
}
/*
static GList *
get_parents(GtkWidget *widget,
GList *parents)
{
GtkWidget *parent = gtk_widget_get_parent(widget);
parents = g_list_prepend(parents, widget);
if (parent != NULL)
return get_parents(parent, parents);
return parents;
}
gboolean
parasite_widget_tree_find_widget (ParasiteWidgetTree *widget_tree,
GtkWidget *widget,
GtkTreeIter *iter)
{
GList *parents = get_parents (widget, NULL);
GList *l;
GtkTreeIter inner_iter, parent_iter = {0};
gboolean found = FALSE;
gboolean in_root = TRUE;
for (l = parents; l != NULL; l = l->next)
{
GtkWidget *cur_widget = GTK_WIDGET (l->data);
gboolean valid;
found = FALSE;
for (valid = gtk_tree_model_iter_children (widget_tree->priv->model,
&inner_iter,
in_root ? NULL : &parent_iter);
valid;
valid = gtk_tree_model_iter_next (widget_tree->priv->model, &inner_iter))
{
GtkWidget *iter_widget;
gtk_tree_model_get (widget_tree->priv->model,
&inner_iter,
WIDGET, &iter_widget,
-1);
if (iter_widget == cur_widget)
{
parent_iter = inner_iter;
in_root = FALSE;
found = TRUE;
break;
}
}
}
g_list_free(parents);
*iter = inner_iter;
return found;
}
*/
gboolean
parasite_widget_tree_find_object (ParasiteWidgetTree *widget_tree,
GObject *object,
GtkTreeIter *iter)
{
GtkTreeIter *internal_iter = g_hash_table_lookup (widget_tree->priv->iters, object);
if (internal_iter)
{
*iter = *internal_iter;
return TRUE;
}
return FALSE;
}
void
parasite_widget_tree_select_object (ParasiteWidgetTree *widget_tree,
GObject *object)
{
GtkTreeIter iter;
if (parasite_widget_tree_find_object (widget_tree, object, &iter))
{
GtkTreePath *path = gtk_tree_model_get_path (GTK_TREE_MODEL (widget_tree->priv->model), &iter);
gtk_tree_view_expand_to_path(GTK_TREE_VIEW(widget_tree), path);
gtk_tree_selection_select_iter(
gtk_tree_view_get_selection(GTK_TREE_VIEW(widget_tree)),
&iter);
gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW (widget_tree), path, NULL, FALSE, 0, 0);
}
}
// vim: set et sw=4 ts=4:

View File

@ -0,0 +1,78 @@
/*
* Copyright (c) 2008-2009 Christian Hammond
* Copyright (c) 2008-2009 David Trowbridge
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef _GTKPARASITE_WIDGET_TREE_H_
#define _GTKPARASITE_WIDGET_TREE_H_
#include <gtk/gtk.h>
#define PARASITE_TYPE_WIDGET_TREE (parasite_widget_tree_get_type())
#define PARASITE_WIDGET_TREE(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), PARASITE_TYPE_WIDGET_TREE, ParasiteWidgetTree))
#define PARASITE_WIDGET_TREE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), PARASITE_TYPE_WIDGET_TREE, ParasiteWidgetTreeClass))
#define PARASITE_IS_WIDGET_TREE(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), PARASITE_TYPE_WIDGET_TREE))
#define PARASITE_IS_WIDGET_TREE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), PARASITE_TYPE_WIDGET_TREE))
#define PARASITE_WIDGET_TREE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), PARASITE_TYPE_WIDGET_TREE, ParasiteWidgetTreeClass))
typedef struct _ParasiteWidgetTreePrivate ParasiteWidgetTreePrivate;
typedef struct _ParasiteWidgetTree {
GtkTreeView parent;
// Private
ParasiteWidgetTreePrivate *priv;
} ParasiteWidgetTree;
typedef struct _ParasiteWidgetTreeClass {
GtkTreeViewClass parent;
void (*widget_changed)(ParasiteWidgetTree *tree);
} ParasiteWidgetTreeClass;
G_BEGIN_DECLS
GType parasite_widget_tree_get_type (void);
GtkWidget *parasite_widget_tree_new (void);
GObject *parasite_widget_tree_get_selected_object (ParasiteWidgetTree *widget_tree);
void parasite_widget_tree_scan (ParasiteWidgetTree *widget_tree,
GtkWidget *window);
void parasite_widget_tree_select_object (ParasiteWidgetTree *widget_tree,
GObject *object);
void parasite_widget_tree_append_object (ParasiteWidgetTree *widget_tree,
GObject *object,
GtkTreeIter *parent_iter);
gboolean parasite_widget_tree_find_object (ParasiteWidgetTree *widget_tree,
GObject *object,
GtkTreeIter *iter);
G_END_DECLS
#endif // _GTKPARASITE_WIDGETTREE_H_
// vim: set et sw=4 ts=4:

View File

@ -0,0 +1,318 @@
/*
* Copyright (c) 2008-2009 Christian Hammond
* Copyright (c) 2008-2009 David Trowbridge
* Copyright (c) 2013 Intel Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include <stdlib.h>
#include "parasite.h"
#include "prop-list.h"
#include "classes-list.h"
#include "css-editor.h"
#include "object-hierarchy.h"
#include "widget-tree.h"
#include "python-hooks.h"
#include "python-shell.h"
#include "button-path.h"
#include "themes.h"
static void
on_widget_tree_selection_changed (ParasiteWidgetTree *widget_tree,
ParasiteWindow *parasite)
{
GObject *selected = parasite_widget_tree_get_selected_object (widget_tree);
if (selected != NULL)
{
parasite_proplist_set_object (PARASITE_PROPLIST (parasite->prop_list),
selected);
parasite_objecthierarchy_set_object (PARASITE_OBJECTHIERARCHY (parasite->oh),
selected);
if (GTK_IS_WIDGET (selected))
{
GtkWidget *widget = GTK_WIDGET (selected);
gtkparasite_flash_widget(parasite, widget);
parasite_buttonpath_set_widget (PARASITE_BUTTONPATH (parasite->button_path), widget);
parasite_classeslist_set_widget (PARASITE_CLASSESLIST (parasite->classes_list), widget);
parasite_csseditor_set_widget (PARASITE_CSSEDITOR (parasite->widget_css_editor), widget);
}
else
{
gtk_widget_set_sensitive (parasite->classes_list, FALSE);
gtk_widget_set_sensitive (parasite->widget_css_editor, FALSE);
}
}
}
static gboolean
on_widget_tree_button_press(ParasiteWidgetTree *widget_tree,
GdkEventButton *event,
ParasiteWindow *parasite)
{
if (event->button == 3)
{
gtk_menu_popup(GTK_MENU(parasite->widget_popup), NULL, NULL,
NULL, NULL, event->button, event->time);
}
return FALSE;
}
static void
on_send_widget_to_shell_activate(GtkWidget *menuitem,
ParasiteWindow *parasite)
{
char *str;
GObject *object;
object = parasite_widget_tree_get_selected_object (PARASITE_WIDGET_TREE (parasite->widget_tree));
if (!object)
return;
str = g_strdup_printf ("parasite.gobj(%p)", object);
parasite_python_shell_append_text (PARASITE_PYTHON_SHELL (parasite->python_shell),
str,
NULL);
g_free(str);
parasite_python_shell_focus (PARASITE_PYTHON_SHELL (parasite->python_shell));
}
static GtkWidget *
create_widget_list_pane(ParasiteWindow *parasite)
{
GtkWidget *swin;
swin = g_object_new (GTK_TYPE_SCROLLED_WINDOW,
"hscrollbar-policy", GTK_POLICY_AUTOMATIC,
"vscrollbar-policy", GTK_POLICY_ALWAYS,
"shadow-type", GTK_SHADOW_IN,
"width-request", 250,
"expand", TRUE,
NULL);
parasite->widget_tree = parasite_widget_tree_new();
gtk_container_add(GTK_CONTAINER(swin), parasite->widget_tree);
g_signal_connect(G_OBJECT(parasite->widget_tree),
"widget-changed",
G_CALLBACK(on_widget_tree_selection_changed),
parasite);
if (parasite_python_is_enabled())
{
g_signal_connect(G_OBJECT(parasite->widget_tree),
"button-press-event",
G_CALLBACK(on_widget_tree_button_press),
parasite);
}
return swin;
}
static GtkWidget *
create_prop_list_pane(ParasiteWindow *parasite)
{
GtkWidget *swin;
swin = g_object_new (GTK_TYPE_SCROLLED_WINDOW,
"hscrollbar-policy", GTK_POLICY_AUTOMATIC,
"vscrollbar-policy", GTK_POLICY_ALWAYS,
"shadow-type", GTK_SHADOW_IN,
"width-request", 250,
NULL);
parasite->prop_list = parasite_proplist_new (parasite->widget_tree);
gtk_container_add(GTK_CONTAINER(swin), parasite->prop_list);
return swin;
}
static void
on_show_graphic_updates_toggled(GtkWidget *toggle_button,
ParasiteWindow *parasite)
{
gdk_window_set_debug_updates(
gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(toggle_button)));
}
static GtkWidget *
create_toolbar (ParasiteWindow *window) {
GtkWidget *button;
GtkWidget *box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
GtkStyleContext *context = gtk_widget_get_style_context (box);
GtkWidget *image;
gtk_style_context_add_class (context, "linked");
button = gtkparasite_inspect_button_new (window);
gtk_container_add (GTK_CONTAINER (box), button);
button = gtk_toggle_button_new ();
image = gtk_image_new_from_icon_name ("view-refresh", GTK_ICON_SIZE_BUTTON);
gtk_button_set_image (GTK_BUTTON (button), image);
gtk_widget_set_tooltip_text (button, "Show Graphic Updates");
gtk_container_add (GTK_CONTAINER (box), button);
g_signal_connect (button,
"toggled",
G_CALLBACK (on_show_graphic_updates_toggled),
window);
gtk_widget_show_all (box);
return box;
}
static void
delete_window (GtkWidget *widget) {
GApplication *app = g_application_get_default ();
gtk_widget_hide (widget);
if (app)
g_application_quit (app);
else
exit (0);
}
void
gtkparasite_window_create()
{
ParasiteWindow *window;
GtkWidget *vpaned, *hpaned;
GtkWidget *header;
GtkWidget *box;
GtkWidget *nb;
char *title;
window = g_new0(ParasiteWindow, 1);
/*
* Create the top-level window.
*/
window->window = g_object_new (GTK_TYPE_WINDOW,
"default-height", 500,
"default-width", 1000,
NULL);
g_signal_connect (window->window,
"delete-event",
G_CALLBACK (delete_window),
NULL);
title = g_strdup_printf("Parasite - %s", g_get_application_name());
gtk_window_set_title (GTK_WINDOW (window->window), title);
header = gtk_header_bar_new ();
gtk_header_bar_set_title (GTK_HEADER_BAR (header), title);
gtk_header_bar_set_show_close_button (GTK_HEADER_BAR (header), TRUE);
gtk_window_set_titlebar (GTK_WINDOW (window->window), header);
gtk_header_bar_pack_start (GTK_HEADER_BAR (header), create_toolbar (window));
g_free(title);
nb = g_object_new (GTK_TYPE_NOTEBOOK,
"show-border", FALSE,
"margin-left", 6,
"margin-right", 6,
"margin-bottom", 6,
NULL);
gtk_container_add (GTK_CONTAINER (window->window), nb);
box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
gtk_notebook_append_page (GTK_NOTEBOOK (nb),
box,
gtk_label_new ("Widget Tree"));
gtk_notebook_append_page (GTK_NOTEBOOK (nb),
parasite_themes_new (),
gtk_label_new ("Themes"));
gtk_notebook_append_page (GTK_NOTEBOOK (nb),
parasite_csseditor_new (TRUE),
gtk_label_new ("Custom CSS"));
window->button_path = parasite_buttonpath_new ();
gtk_container_add (GTK_CONTAINER (box), window->button_path);
hpaned = gtk_paned_new (GTK_ORIENTATION_HORIZONTAL);
gtk_container_add (GTK_CONTAINER (box), hpaned);
vpaned = gtk_paned_new (GTK_ORIENTATION_VERTICAL);
gtk_paned_pack1 (GTK_PANED (hpaned), vpaned, TRUE, FALSE);
gtk_paned_pack1 (GTK_PANED (vpaned), create_widget_list_pane (window), TRUE, FALSE);
nb = g_object_new (GTK_TYPE_NOTEBOOK,
"enable-popup", TRUE,
"show-border", FALSE,
NULL);
gtk_notebook_append_page (GTK_NOTEBOOK (nb),
create_prop_list_pane (window),
gtk_label_new ("GObject Properties"));
window->oh = parasite_objecthierarchy_new ();
gtk_notebook_append_page (GTK_NOTEBOOK (nb),
window->oh,
gtk_label_new ("Hierarchy"));
window->classes_list = parasite_classeslist_new ();
gtk_notebook_append_page (GTK_NOTEBOOK (nb),
window->classes_list,
gtk_label_new ("CSS Classes"));
window->widget_css_editor = parasite_csseditor_new (FALSE);
gtk_notebook_append_page (GTK_NOTEBOOK (nb),
window->widget_css_editor,
gtk_label_new ("Custom CSS"));
gtk_paned_pack2 (GTK_PANED (hpaned), nb, FALSE, FALSE);
if (parasite_python_is_enabled())
{
GtkWidget *menuitem;
window->python_shell = parasite_python_shell_new();
gtk_paned_pack2(GTK_PANED(vpaned), window->python_shell, FALSE, FALSE);
/*
* XXX Eventually we'll want to put more in here besides the menu
* item we define below. At that point, we'll need to make this
* more generic.
*/
window->widget_popup = gtk_menu_new();
gtk_widget_show(window->widget_popup);
menuitem = gtk_menu_item_new_with_label("Send Widget to Shell");
gtk_widget_show(menuitem);
gtk_menu_shell_append(GTK_MENU_SHELL(window->widget_popup), menuitem);
g_signal_connect(G_OBJECT(menuitem), "activate",
G_CALLBACK(on_send_widget_to_shell_activate), window);
}
gtk_widget_show_all (window->window);
}
// vim: set et sw=4 ts=4: