// -*- mode: js2; indent-tabs-mode: nil; js2-basic-offset: 4 -*-
/* exported init */
const { Shell } = imports.gi;
const ExtensionUtils = imports.misc.extensionUtils;
class WindowMover {
constructor() {
this._settings = ExtensionUtils.getSettings();
this._appSystem = Shell.AppSystem.get_default();
this._appConfigs = new Set();
this._appData = new Map();
this._appsChangedId = this._appSystem.connect(
'installed-changed', this._updateAppData.bind(this));
this._settings.connect('changed', this._updateAppConfigs.bind(this));
this._updateAppConfigs();
}
_updateAppConfigs() {
this._appConfigs.clear();
this._settings.get_strv('application-list').forEach(appId => {
this._appConfigs.add(appId);
});
this._updateAppData();
}
_updateAppData() {
let ids = [...this._appConfigs.values()];
let removedApps = [...this._appData.keys()].filter(
a => !ids.includes(a.id)
);
removedApps.forEach(app => {
app.disconnect(this._appData.get(app).windowsChangedId);
this._appData.delete(app);
});
let addedApps = ids.map(id => this._appSystem.lookup_app(id)).filter(
app => app != null && !this._appData.has(app)
);
addedApps.forEach(app => {
let data = {
windows: app.get_windows(),
windowsChangedId: app.connect(
'windows-changed', this._appWindowsChanged.bind(this))
};
this._appData.set(app, data);
});
}
destroy() {
if (this._appsChangedId) {
this._appSystem.disconnect(this._appsChangedId);
this._appsChangedId = 0;
}
if (this._settings) {
this._settings.run_dispose();
this._settings = null;
}
this._appConfigs.clear();
this._updateAppData();
}
_appWindowsChanged(app) {
let data = this._appData.get(app);
let windows = app.get_windows();
// If get_compositor_private() returns non-NULL on a removed windows,
// the window still exists and is just moved to a different workspace
// or something; assume it'll be added back immediately, so keep it
// to avoid moving it again
windows.push(...data.windows.filter(
w => !windows.includes(w) && w.get_compositor_private() != null
));
windows.filter(w => !data.windows.includes(w)).forEach(window => {
let leader = data.windows.find(w => w.get_pid() == window.get_pid());
if (leader)
window.change_workspace(leader.get_workspace());
});
data.windows = windows;
}
}
class Extension {
constructor() {
this._winMover = null;
}
enable() {
this._winMover = new WindowMover();
}
disable() {
this._winMover.destroy();
this._winMover = null;
}
}
function init() {
ExtensionUtils.initTranslations();
return new Extension();
}