2

I'm writing a GNOME Shell extension in JavaScript that modifies all application windows.

As an exercise, I want to start off by getting the application name of just one open window and displaying it in the panel.

Right now, in Looking Glass, I can get all of the open windows by typing

>>> global.screen.get_active_workspace().list_windows()
r(0) = [object instance proxy GType:MetaWindowX11 ...], ...

and I can get the name of the first window in the list by typing

>>> Shell.WindowTracker.get_default().get_window_app(r(0)[0]).get_name()
r(1) = <name of application>

However, when I try to do this in my extension's extension.js file and then restart GNOME Shell, I can't get the name of the open window because the result of global.screen.get_active_workspace().list_windows() is undefined.

I thought that this might be happening because my extension was being executed before the windows were created, so I started looking into how to wait until a window is created before performing operations on windows.

This is where I've gotten really stuck.

In my extension's init() function, I am trying to add an event listener that runs my function update() when it receives the window-created signal.

The window-created signal is from the MetaDisplay object.

Here is what my code looks like so far:

let display = global.display;
display.connect('window-created', Lang.bind(this, this.update));

The code compiles without errors, but my function update() is not being called when new windows are created.

Does anyone know what is happening here? Is my syntax wrong? Should I be using a different signal?

Any help would be appreciated.

Full extension.js file

const St = imports.gi.St;
const Main = imports.ui.main;
const Lang = imports.lang;
const Shell = imports.gi.Shell;

let text, button;

function init() {
    button = new St.Bin({ style_class: 'panel-button', 
                          reactive: true, 
                          can_focus: true, 
                          x_fill: true, 
                          y_fill: false, 
                          track_hover: true });

    let display = global.display;
    display.connect('window-created', Lang.bind(this, this.update));
}

function update() {
    let window = global.screen.get_active_workspace().list_windows()[0];
    let name = Shell.WindowTracker.get_default().get_window_app(window).get_name();

    text = new St.Label({ text: name });
    button.set_child(text);
}

function enable() {
    Main.panel._rightBox.insert_child_at_index(button, 0);
}

function disable() {
    Main.panel._rightBox.remove_child(button);
}
  • If your code is fairly small, you could probably post it all. It's possible the problem is related to `this` usage, which is hard to tell from your snippet. Also have a look here where `global.screen` was recently deprecated: https://github.com/GNOME/gnome-shell/commit/47ea10b7c976abb1b9ab4f34da87abb1e36855fe#diff-6b6b2ef981951428e4f32fbe306acb60 – andy.holmes Sep 30 '18 at 01:45
  • I've just updated my question to include all of the code in my extension.js file. Also, thank you for the information about `global.screen`. – T. Andromedon Oct 01 '18 at 14:15

1 Answers1

0

I ended up figuring out how to solve my problem. The issues were in which signals I was listening for and where I was listening for them. After a lot of research, I also noticed that most extensions are object-oriented, so I changed my code to reflect that. Below is my new, working, object-oriented code.

const St = imports.gi.St;
const Main = imports.ui.main;
const Lang = imports.lang;
const Shell = imports.gi.Shell;

let button;

function MyApplication() {
    this._init();
}

MyApplication.prototype = {
    _init: function() {
        button = new St.Bin({ style_class: 'panel-button', 
                              reactive: true, 
                              can_focus: true, 
                              x_fill: true, 
                              y_fill: false, 
                              track_hover: true });
    },

    _update: function() {
        text = new St.Label({ text: Shell.WindowTracker.get_default().focus_app.get_name() });
        button.set_child(text);
    },

    enable: function() {
        Main.panel._rightBox.insert_child_at_index(button, 0);
        let callbackID = global.display.connect('notify::focus-window', Lang.bind(this, this._update));
    },

    disable: function() {
        Main.panel._rightBox.remove_child(button);
    }
};

function init() {
    return new MyApplication();
}