В одной из программ на работе используется ряд самописных Gtk-виджетов для настройки фильтров изображения. Виджеты лежат в Box'е, добавляются, удаляются и настраиваются пользователем. У каждого типа виджетов свой набор настроек. Все настройки виджеты хранят в своих свойствах.
Чтобы сохранять после перезапуска программы список фильтров и их параметры, была идея сделать некий обобщенны код, не зависимый от конкретной задачи, который бы сохранял объекты Gobject в файлы (типы объектов и значения свойств) и потом воссоздавал последовательность объектов по этим файлам.
В качестве "proof of concept" был написан код, клонирующий объект Gobject. Функция g_object_clone возвращает копию объекта, переданного ей в качестве параметра src. Код основан на примере со StackOverflow. Обращаю внимание, что полноценно копируются только простые свойства, для boxed-типов копируется указатель с инкрементированием счетчика ссылок.
Код gobject_clone.c:
Чтобы сохранять после перезапуска программы список фильтров и их параметры, была идея сделать некий обобщенны код, не зависимый от конкретной задачи, который бы сохранял объекты Gobject в файлы (типы объектов и значения свойств) и потом воссоздавал последовательность объектов по этим файлам.
В качестве "proof of concept" был написан код, клонирующий объект Gobject. Функция g_object_clone возвращает копию объекта, переданного ей в качестве параметра src. Код основан на примере со StackOverflow. Обращаю внимание, что полноценно копируются только простые свойства, для boxed-типов копируется указатель с инкрементированием счетчика ссылок.
Код gobject_clone.c:
// gcc `pkg-config --libs --cflags glib-2.0 gobject-2.0` gobject_clone.c point.c -o gobject_clone #include <glib-object.h> #include "point.h" #include <stdio.h> #include <string.h> //< For strcmp.В качестве объектов в примере взят простенький класс Point с гитхаба за авторством Jacob Gelbman. Код point.h:// See http://stackoverflow.com/questions/3003655/is-there-a-good-way-to-copy-a-gtk-widget?answertab=votes#tab-top static GObject *g_object_clone(GObject *src) { GObject *dst; GParameter *params; GParamSpec **specs; guint n, n_specs, n_params; specs = g_object_class_list_properties(G_OBJECT_GET_CLASS(src), &n_specs); params = g_new0(GParameter, n_specs); n_params = 0; for (n = 0; n < n_specs; ++n) if((specs[n]->flags & G_PARAM_READWRITE) == G_PARAM_READWRITE) { params[n_params].name = g_intern_string(specs[n]->name); g_value_init(¶ms[n_params].value, specs[n]->value_type); g_object_get_property(src, specs[n]->name, ¶ms[n_params].value); ++n_params; } dst = g_object_newv(G_TYPE_FROM_INSTANCE(src), n_params, params); g_free(specs); g_free(params); return dst; } // Print, clear, print again. static void psp (Point *p) { g_print("OBJECT %p\n", p); g_print(" Before clearing:\n"); point_print(p); g_signal_emit_by_name(p, "clear"); g_print(" After clearing:\n"); point_print(p); g_print(" ...\n"); } int main(int argc, char **argv) { g_type_init(); GArray *array = g_array_new(FALSE, FALSE, sizeof(gint)); gint val1 = 33, val2 = 44; g_array_append_val(array, val1); g_array_append_val(array, val2); g_array_append_val(array, val1); GObject *p1 = g_object_new(TYPE_POINT, "x", 5, "y", 10, "a", array, NULL); GObject *p2 = g_object_clone(p1); //< Note: garray uses ref/unref for copy/free. psp(POINT(p1)); g_print("Appending value '%d' to array.\n", val2); g_print(" ...\n"); g_array_append_val(array, val2); psp(POINT(p2)); g_clear_object(&p1); g_clear_object(&p2); return 0; }
// https://github.com/zorgnax/gobject-examples/tree/master/02-point-inheritance #ifndef __POINT_H__ #define __POINT_H__ #include <glib.h> #include <glib-object.h>Код point.c:#define TYPE_POINT (point_get_type ()) #define POINT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TYPE_POINT, Point)) #define POINT_CLASS(cls) (G_TYPE_CHECK_CLASS_CAST ((cls), TYPE_POINT, PointClass)) #define IS_POINT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TYPE_POINT)) #define IS_POINT_CLASS(cls) (G_TYPE_CHECK_CLASS_TYPE ((cls), TYPE_POINT)) #define POINT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), TYPE_POINT, PointClass)) typedef struct _PointClass PointClass; typedef struct _Point Point; struct _PointClass { GObjectClass parent; void (*clear) (Point *self); }; struct _Point { GObject parent; gint x; gint y; GArray *array; }; GType point_get_type(void); void point_print(Point *self); #endif /*__POINT_H__*/
// https://github.com/zorgnax/gobject-examples/tree/master/02-point-inheritance #include <glib-object.h> #include "point.h"G_DEFINE_TYPE(Point, point, G_TYPE_OBJECT); enum { PROP_0, PROP_ARRAY, PROP_X, PROP_Y }; enum { CLEAR, LAST_SIGNAL }; static guint point_signals[LAST_SIGNAL] = {0}; void point_print (Point *self) { g_print(" x: %d, y: %d\n", self->x, self->y); g_print(" ar:"); if(self->array) { guint i; for(i = 0; i < self->array->len; i++) g_print(" %d", g_array_index(self->array, gint, i)); } else g_print("null"); g_print("\n"); } static void point_clear (Point *self) { g_object_set(self, "x", 0, "y", 0, "a", NULL, NULL); } static void point_get_property(GObject *obj, guint prop_id, GValue *value, GParamSpec *pspec) { Point *point = POINT(obj); switch (prop_id) { case PROP_ARRAY: g_value_set_boxed(value, point->array); break; case PROP_X: g_value_set_int(value, point->x); break; case PROP_Y: g_value_set_int(value, point->y); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, prop_id, pspec); break; } } static void point_set_property(GObject *obj, guint prop_id, const GValue *value, GParamSpec *pspec) { Point *point = POINT(obj); switch (prop_id) { case PROP_ARRAY: if(point->array) g_array_unref(point->array); point->array = g_value_dup_boxed(value); break; case PROP_X: point->x = g_value_get_int(value); break; case PROP_Y: point->y = g_value_get_int(value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, prop_id, pspec); break; } } static void point_finalize(GObject *point) { if(POINT(point)->array) g_array_unref(POINT(point)->array); G_OBJECT_CLASS(point_parent_class)->finalize(point); } static void point_class_init (PointClass *cls) { GObjectClass *g_object_class = G_OBJECT_CLASS(cls); GParamSpec *array_param; GParamSpec *x_param; GParamSpec *y_param; g_object_class->get_property = point_get_property; g_object_class->set_property = point_set_property; g_object_class->finalize = point_finalize; cls->clear = point_clear; array_param = g_param_spec_boxed( "a", "a", "some int array", G_TYPE_ARRAY, G_PARAM_READWRITE); x_param = g_param_spec_int( "x", "x", "x loc of point", INT_MIN, /* => */ INT_MAX, 0, G_PARAM_READWRITE); y_param = g_param_spec_int( "y", "y", "y loc of point", INT_MIN, /* => */ INT_MAX, 0, G_PARAM_READWRITE); g_object_class_install_property( g_object_class, PROP_ARRAY, array_param); g_object_class_install_property( g_object_class, PROP_X, x_param); g_object_class_install_property( g_object_class, PROP_Y, y_param); point_signals[CLEAR] = g_signal_new( "clear", /* signal_name */ TYPE_POINT, /* itype */ G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED, /* signal_flags */ G_STRUCT_OFFSET(PointClass, clear), /* class_offset */ NULL, /* accumulator */ NULL, /* accu_data */ g_cclosure_marshal_VOID__VOID, /* c_marshaller */ G_TYPE_NONE, /* return_type */ 0); /* n_params */ } static void point_init(Point *point) { point->array = NULL; }
0 коммент.:
Подписаться на:
Комментарии к сообщению (Atom)