Skip to content

Instantly share code, notes, and snippets.

@ptomato
Created September 19, 2014 08:44
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ptomato/c4245c77d375022a43c5 to your computer and use it in GitHub Desktop.
Save ptomato/c4245c77d375022a43c5 to your computer and use it in GitHub Desktop.
Clone a GObject
const Gtk = imports.gi.Gtk;
const GObject = imports.gi.GObject;
const Gir = imports.gi.GIRepository;
// G_PARAM_READWRITE is not yet properly introspected
const READWRITE = GObject.ParamFlags.READABLE | GObject.ParamFlags.WRITABLE;
const dontCloneTheseProperties = [
['Gtk', 'Widget', 'parent'], // would try to add the new widget to the same parent
['Gtk', 'Widget', 'margin'], // sets all margin properties at once
['Gtk', 'Widget', 'expand'], // sets all expand properties at once
];
function ignoreInfoEqual(arg1, arg2) {
return arg1[0] === arg2[0] && arg1[1] === arg2[1] && arg1[2] === arg2[2];
}
function getWritablePropertyNamesForObjectInfo(info) {
let propertyNames = [];
let nProperties = Gir.object_info_get_n_properties(info);
for(let ix = 0; ix < nProperties; ix++) {
let propertyInfo = Gir.object_info_get_property(info, ix);
let flags = Gir.property_info_get_flags(propertyInfo);
if ((flags & READWRITE) == READWRITE) {
let name = propertyInfo.get_name();
let ignoreInfo = [info.get_namespace(), info.get_name(), name];
if (!dontCloneTheseProperties.some(ignoreInfoEqual.bind(null, ignoreInfo)))
propertyNames.push(name);
}
}
return propertyNames;
}
function clone(obj) {
// This seems like it ought to work, but segfaults:
// let typeClass = GObject.TypeClass.ref(obj.constructor.$gtype);
// let props = GObject.ObjectClass.prototype.list_properties.call(typeClass);
// let obj2 = new obj.constructor(props);
// return obj2;
let repository = Gir.Repository.get_default();
let baseInfo = repository.find_by_gtype(obj.constructor.$gtype);
let propertyNames = [];
for (let info = baseInfo; info !== null; info = Gir.object_info_get_parent(info)) {
propertyNames = propertyNames.concat(getWritablePropertyNamesForObjectInfo(info));
}
let constructProps = {};
propertyNames.forEach(function (name) {
constructProps[name] = obj[name];
});
return new obj.constructor(constructProps);
}
Gtk.init(null);
let win = new Gtk.Window();
let grid = new Gtk.Grid();
let button1 = new Gtk.Button({
label: 'I am a button!',
margin_left: 20,
tooltip_text: 'I am a tooltip!',
vexpand: true,
});
let button2 = clone(button1);
grid.add(button1);
grid.add(button2);
win.add(grid);
win.connect('destroy', Gtk.main_quit);
win.show_all();
Gtk.main();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment