Skip to content

Commit

Permalink
adg: new API adg_object_clone()
Browse files Browse the repository at this point in the history
A helper method to clone a generic GObject instance. It traverses all
the readable/writable properties and duplicate them.

It will be helpful for customizing styles.
  • Loading branch information
ntd committed Mar 26, 2017
1 parent 43c8cc0 commit 2328cf6
Show file tree
Hide file tree
Showing 3 changed files with 89 additions and 0 deletions.
45 changes: 45 additions & 0 deletions src/adg/adg-utils.c
Original file line number Diff line number Diff line change
Expand Up @@ -460,6 +460,51 @@ adg_type_from_filename(const gchar *file)
return type;
}

/**
* adg_object_clone:
* @src: (transfer none): the source #GObject to clone
*
* A helper method that clones a generic #GObject instance. The implementation
* leverages the g_object_get_property() method on @src to get all the
* properties and uses g_object_newv() to create the destination clone.
*
* The code is not as sophisticated as one might expect, so apart from what
* described there is no other magic involved. It is internally used by ADG to
* clone #AdgStyle instances in adg_style_clone().
*
* Returns: (transfer full): the clone of @src.
*
* Since: 1.0
**/
GObject *
adg_object_clone(GObject *src)
{
GObject *dst;
GParameter *params;
GParamSpec **specs;
guint n, n_specs, n_params;

g_return_val_if_fail(G_IS_OBJECT(src), NULL);
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(&params[n_params].value, specs[n]->value_type);
g_object_get_property(src, specs[n]->name, &params[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;
}

/**
* adg_nop:
*
Expand Down
1 change: 1 addition & 0 deletions src/adg/adg-utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ gchar * adg_find_file (const gchar *file,
...);
gdouble adg_scale_factor (const gchar *scale);
cairo_surface_type_t adg_type_from_filename (const gchar *file);
GObject * adg_object_clone (GObject *src);
void adg_nop (void);
gdouble adg_round (gdouble value,
gint decimals);
Expand Down
43 changes: 43 additions & 0 deletions src/adg/tests/test-utils.c
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,48 @@ _adg_method_type_from_filename(void)
g_assert_cmpint(adg_type_from_filename("a.unknown"), ==, CAIRO_SURFACE_TYPE_XLIB);
}

static void
_adg_method_clone(void)
{
AdgCanvas *canvas, *clone;
AdgTitleBlock *title_block;

/* Sanity check */
g_assert_null(adg_object_clone(NULL));

canvas = adg_canvas_new();
title_block = adg_title_block_new();

adg_canvas_set_background_dress(canvas, ADG_DRESS_COLOR_ANNOTATION);
adg_canvas_set_title_block(canvas, title_block);
g_object_unref(title_block);
adg_canvas_set_margins(canvas, 1, 2, 3, 4);
adg_canvas_switch_frame(canvas, FALSE);

/* Check that the original canvas matches the expected states */
g_assert_cmpint(adg_canvas_get_background_dress(canvas), ==, ADG_DRESS_COLOR_ANNOTATION);
g_assert_true(adg_canvas_get_title_block(canvas) == title_block);
adg_assert_isapprox(adg_canvas_get_top_margin(canvas), 1);
adg_assert_isapprox(adg_canvas_get_right_margin(canvas), 2);
adg_assert_isapprox(adg_canvas_get_bottom_margin(canvas), 3);
adg_assert_isapprox(adg_canvas_get_left_margin(canvas), 4);
g_assert_false(adg_canvas_has_frame(canvas));

clone = ADG_CANVAS(adg_object_clone(G_OBJECT(canvas)));
g_object_unref(canvas);

/* Check the states on the clone are the same */
g_assert_cmpint(adg_canvas_get_background_dress(clone), ==, ADG_DRESS_COLOR_ANNOTATION);
g_assert_true(adg_canvas_get_title_block(clone) == title_block);
adg_assert_isapprox(adg_canvas_get_top_margin(clone), 1);
adg_assert_isapprox(adg_canvas_get_right_margin(clone), 2);
adg_assert_isapprox(adg_canvas_get_bottom_margin(clone), 3);
adg_assert_isapprox(adg_canvas_get_left_margin(clone), 4);
g_assert_false(adg_canvas_has_frame(clone));

g_object_unref(clone);
}

static void
_adg_method_nop(void)
{
Expand Down Expand Up @@ -176,6 +218,7 @@ main(int argc, char *argv[])
g_test_add_func("/adg/method/find-file", _adg_method_find_file);
g_test_add_func("/adg/method/scale-factor", _adg_method_scale_factor);
g_test_add_func("/adg/method/type-from-filename", _adg_method_type_from_filename);
g_test_add_func("/adg/method/clone", _adg_method_clone);
g_test_add_func("/adg/method/nop", _adg_method_nop);
g_test_add_func("/adg/method/round", _adg_method_round);
g_test_add_func("/adg/method/unescaped-strchr", _adg_method_unescaped_strchr);
Expand Down

0 comments on commit 2328cf6

Please sign in to comment.