mirror of
https://gitlab.gnome.org/GNOME/gtk.git
synced 2024-12-25 13:11:13 +00:00
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:
parent
2dc100fa76
commit
81af602dda
@ -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
|
||||
|
@ -1,6 +1,6 @@
|
||||
include $(top_srcdir)/Makefile.decl
|
||||
|
||||
SUBDIRS = input
|
||||
SUBDIRS = input other
|
||||
|
||||
if OS_UNIX
|
||||
SUBDIRS += printbackends
|
||||
|
1
modules/other/Makefile.am
Normal file
1
modules/other/Makefile.am
Normal file
@ -0,0 +1 @@
|
||||
SUBDIRS = parasite
|
52
modules/other/parasite/Makefile.am
Normal file
52
modules/other/parasite/Makefile.am
Normal 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
|
103
modules/other/parasite/button-path.c
Normal file
103
modules/other/parasite/button-path.c
Normal 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:
|
60
modules/other/parasite/button-path.h
Normal file
60
modules/other/parasite/button-path.h
Normal 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:
|
344
modules/other/parasite/classes-list.c
Normal file
344
modules/other/parasite/classes-list.c
Normal 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:
|
58
modules/other/parasite/classes-list.h
Normal file
58
modules/other/parasite/classes-list.h
Normal 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:
|
388
modules/other/parasite/css-editor.c
Normal file
388
modules/other/parasite/css-editor.c
Normal 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:
|
59
modules/other/parasite/css-editor.h
Normal file
59
modules/other/parasite/css-editor.h
Normal 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:
|
242
modules/other/parasite/inspect-button.c
Normal file
242
modules/other/parasite/inspect-button.c
Normal 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:
|
40
modules/other/parasite/module.c
Normal file
40
modules/other/parasite/module.c
Normal 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:
|
126
modules/other/parasite/object-hierarchy.c
Normal file
126
modules/other/parasite/object-hierarchy.c
Normal 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:
|
58
modules/other/parasite/object-hierarchy.h
Normal file
58
modules/other/parasite/object-hierarchy.h
Normal 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:
|
69
modules/other/parasite/parasite.h
Normal file
69
modules/other/parasite/parasite.h
Normal 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:
|
367
modules/other/parasite/prop-list.c
Normal file
367
modules/other/parasite/prop-list.c
Normal 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:
|
60
modules/other/parasite/prop-list.h
Normal file
60
modules/other/parasite/prop-list.h
Normal 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:
|
410
modules/other/parasite/property-cell-renderer.c
Normal file
410
modules/other/parasite/property-cell-renderer.c
Normal 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:
|
70
modules/other/parasite/property-cell-renderer.h
Normal file
70
modules/other/parasite/property-cell-renderer.h
Normal 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:
|
238
modules/other/parasite/python-hooks.c
Normal file
238
modules/other/parasite/python-hooks.c
Normal 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:
|
38
modules/other/parasite/python-hooks.h
Normal file
38
modules/other/parasite/python-hooks.h
Normal 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_
|
409
modules/other/parasite/python-shell.c
Normal file
409
modules/other/parasite/python-shell.c
Normal 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:
|
68
modules/other/parasite/python-shell.h
Normal file
68
modules/other/parasite/python-shell.h
Normal 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_
|
177
modules/other/parasite/themes.c
Normal file
177
modules/other/parasite/themes.c
Normal 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:
|
56
modules/other/parasite/themes.h
Normal file
56
modules/other/parasite/themes.h
Normal 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:
|
418
modules/other/parasite/widget-tree.c
Normal file
418
modules/other/parasite/widget-tree.c
Normal 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:
|
78
modules/other/parasite/widget-tree.h
Normal file
78
modules/other/parasite/widget-tree.h
Normal 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:
|
318
modules/other/parasite/window.c
Normal file
318
modules/other/parasite/window.c
Normal 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:
|
Loading…
Reference in New Issue
Block a user