Search code examples
gnomegnome-shell-extensionsgjs

How do I check that a Gjs class has already been defined?


I am writing the preference view a GNOME shell extension and an facing issues when using the imports.lang function to write the application in an object oriented fashion.

const Gtk = imports.gi.Gtk
const Lang = imports.lang
Gtk.init(null)
const MyWindow = new Lang.Class({...})

Opening the preference window the first time works, but subsequent ones throw the following error: Error: Type name Gjs_MyWindow is already registered. Upon closing the window for the first time, I receive this error: TypeError: prefsModule.init is not a function.

The following more imperative code works:

const Gtk = imports.gi.Gtk
Gtk.init(null)
const window = new Gtk.Window({ type: Gtk.WindowType.TOPLEVEL })

Based on the errors thrown, my guess is that the class is being redefined. How can I avoid redefinition and receive the defined class otherwise? (Are there any docs I can refer to?)


Solution

  • Looks like the right answer is in this discussion.

    If you extend a GObject class (anything from St, Clutter, Gtk, etc.), you're registering a new GType, and that's not possible for extensions.

    ...

    Extensions are dynamic modules, and they can be loaded and unloaded - but that's not at all possible for GTypes.

    So, don't extend GTypes. Instead, use the "delegate pattern", which looks like that.

    const Class = new Lang.Class({
      Name: "Class",
    
      _init: function() {
        this.actor = new St.Button();
      }
    )};
    

    This being said, if you have a look at the extensions installed on your system and do something like grep -rn 'Extends: Gtk' /usr/share/gnome-shell/extensions/, you will see that some extensions still extend GTypes, and it doesn't cause any error. But you will notice that it's never done in the extension.js file...

    Don't ask for more details here, that's all I know as of today !