classes, interfaces and properties in Javascript/gjs

Thought I’d share some more Javascript snippets with you zany kids.

Firstly, how to implement an interface (specifically a GInterface), for example an Mx.ItemFactory:

const ButtonFactory = new Lang.Class({
  Name: 'ButtonFactory',
  Extends: GObject.Object,
  Implements: [ Mx.ItemFactory ],
 
  _init : function (callback)
  {
    this.parent();
    this._callback = callback;
  },
 
  vfunc_create : function ()
  {
    let button = new Button();
    button.connect('clicked', Lang.bind(this, function ()
      {
        this._callback(button);
      }));
 
    return button;
  },
});

The important thing to notice is the vfunc_ that gets prepended to any calls you’re overriding from the library. Also be aware of your terminating commas, semicolons and braces.1

Of course, we want to bind extra attributes into the classes built by our factory (I’m not sure why Mx.ItemFactorys don’t just pass a row so that we can do whatever we like in the factory). Anyway, classes are easy in Javascript so we can just extend Mx.Button to include a property we can bind:

const Button = new Lang.Class({
  Name: 'Button',
  Extends: Mx.Button,
  Properties: {
    'id': GObject.ParamSpec.string('id', '', '',
        GObject.ParamFlags.READABLE | GObject.ParamFlags.WRITABLE,
        ''),
  },
 
  _init : function (params)
  {
    this.parent(params);
    this._id = '';
  },
 
  get id ()
  {
    return this._id;
  },
 
  set id (val)
  {
    this._id = val;
  },
});

Again be aware of missing commas.

For more examples take a look at testGObjectClass.js. You should also know that much of this requires a recent gjs, so it’ll be available in GNOME 3.4, but not 3.2.

If you’re interested, here’s the code that uses this factory:

let factory = new ButtonFactory(Lang.bind(this, function (button)
  {
    ...
  }));
 
let view = new Mx.ListView({
    'model': model,
    'factory': factory,
  });
 
view.add_attribute('label', 0);
view.add_attribute('id', 1);

Thanks to Jasper St. Pierre for the help.

  1. Obviously the entire class system here is a hack, which is what makes it so reminiscent of Perl. []

lilypond scales generator

I picked up my saxophone for the first time in a while last night and went along to a big band rehearsal. Very quickly discovered that I’ve forgotten most of my scales and that I need to do some practice.

Realised I didn’t feel like writing eight scales out in nine keys, and there had to be a better way, so I played around for a bit with lilypond and then hacked together a bit of Python to help generate my scales.

Anyway, I thought this was pretty neat, and possibly useful to others, so I’ve shoved it on github.

Gtk.ListStores and Clutter.ListModels in Javascript/gjs

It’s surprisingly hard to find this, and the generated documentation is actually misleaingly wrong1, so here’s how to create ListStores and ListModels in Javascript with gjs.

let store = new Gtk.ListStore();
store.set_column_types([GObject.TYPE_STRING, GObject.TYPE_INT]);
store.insert_with_valuesv(-1, [ 0, 1 ], [ "test", 42 ]);
let model = Clutter.ListModel.newv(
    [ GObject.TYPE_STRING, GObject.TYPE_STRING ],
    [ 'Column Name 1', 'Column Name 2' ]);
model.appendv([ 0, 1 ], [ "String 1", "String 2" ]);

The first array is the column numbers you wish to assign, the second array is the values for those columns.

Fundamental GTypes are available as GObject.TYPE_*. You can specify non-basic types using the class, e.g. Clutter.Text.

There are other variations possible, but this should provide the basics required to figure out the rest.2

  1. The n_columns parameter is a lie, and will be inferred by gjs from the array size. []
  2. You’re welcome. []

wireless issues with rtl8192ce and Thinkpad X220

I rebooted the other day, which got me a new kernel (3.2.91), and now it seems my wireless (rtl8192ce) has become really flaky and unstable. At first I thought it was the router playing up, but everything else in the house works fine (everything else in the house is made by Apple it seems).

Typically it fails to associate until you reboot the router (which is why I thought it might be the router) or occasionally the laptop. When it is connected performance is occasionally crappy. I’m totally out of my depth debugging this. I poked around a bit but found nothing meaningful.

Help appreciated!

  1. I think I was running 3.2.1 before, which got uninstalled. Fedora helpfully left 3.2.6 and 3.2.7, neither of which I think I ever booted into. []

libpeas

Seriously impressed with libpeas.

I think about my previous work adding plugins to things (some of them involved Bonobo) and I think how much easier it would have been if this technology was around back then.

It was very simple to put together some plugin GObject interfaces, annotate and add introspection for them, and then write some Javascript plugins that implement the interface. It looks like C on the C side, and Javascript on the Javascript side. No weird IDLs or custom file formats or generated bindings, just regular gobject-introspection.

Here’s an example of what I mean (needs to be run from the src/ dir, cause I was lazy about paths).