145 lines
4.4 KiB
JavaScript
145 lines
4.4 KiB
JavaScript
|
// -*- mode: js2; indent-tabs-mode: nil; js2-basic-offset: 4 -*-
|
||
|
// Start apps on custom workspaces
|
||
|
/* exported init enable disable */
|
||
|
|
||
|
const { Shell } = imports.gi;
|
||
|
|
||
|
const ExtensionUtils = imports.misc.extensionUtils;
|
||
|
const Main = imports.ui.main;
|
||
|
|
||
|
class WindowMover {
|
||
|
constructor() {
|
||
|
this._settings = ExtensionUtils.getSettings();
|
||
|
this._appSystem = Shell.AppSystem.get_default();
|
||
|
this._appConfigs = new Map();
|
||
|
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(v => {
|
||
|
let [appId, num] = v.split(':');
|
||
|
this._appConfigs.set(appId, parseInt(num) - 1);
|
||
|
});
|
||
|
|
||
|
this._updateAppData();
|
||
|
}
|
||
|
|
||
|
_updateAppData() {
|
||
|
let ids = [...this._appConfigs.keys()];
|
||
|
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 && !this._appData.has(app)
|
||
|
);
|
||
|
addedApps.forEach(app => {
|
||
|
let data = {
|
||
|
windowsChangedId: app.connect('windows-changed',
|
||
|
this._appWindowsChanged.bind(this)),
|
||
|
moveWindowsId: 0,
|
||
|
windows: app.get_windows(),
|
||
|
};
|
||
|
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();
|
||
|
}
|
||
|
|
||
|
_moveWindow(window, workspaceNum) {
|
||
|
if (window.skip_taskbar)
|
||
|
return;
|
||
|
|
||
|
// ensure we have the required number of workspaces
|
||
|
let workspaceManager = global.workspace_manager;
|
||
|
for (let i = workspaceManager.n_workspaces; i <= workspaceNum; i++) {
|
||
|
window.change_workspace_by_index(i - 1, false);
|
||
|
workspaceManager.append_new_workspace(false, 0);
|
||
|
}
|
||
|
|
||
|
window.change_workspace_by_index(workspaceNum, false);
|
||
|
}
|
||
|
|
||
|
_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
|
||
|
));
|
||
|
|
||
|
let workspaceNum = this._appConfigs.get(app.id);
|
||
|
windows.filter(w => !data.windows.includes(w)).forEach(window => {
|
||
|
this._moveWindow(window, workspaceNum);
|
||
|
});
|
||
|
data.windows = windows;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
let prevCheckWorkspaces;
|
||
|
let winMover;
|
||
|
|
||
|
function init() {
|
||
|
ExtensionUtils.initTranslations();
|
||
|
}
|
||
|
|
||
|
function myCheckWorkspaces() {
|
||
|
let keepAliveWorkspaces = [];
|
||
|
let foundNonEmpty = false;
|
||
|
for (let i = this._workspaces.length - 1; i >= 0; i--) {
|
||
|
if (!foundNonEmpty)
|
||
|
foundNonEmpty = this._workspaces[i].list_windows().length > 0;
|
||
|
else if (!this._workspaces[i]._keepAliveId)
|
||
|
keepAliveWorkspaces.push(this._workspaces[i]);
|
||
|
}
|
||
|
|
||
|
// make sure the original method only removes empty workspaces at the end
|
||
|
keepAliveWorkspaces.forEach(ws => (ws._keepAliveId = 1));
|
||
|
prevCheckWorkspaces.call(this);
|
||
|
keepAliveWorkspaces.forEach(ws => delete ws._keepAliveId);
|
||
|
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
function enable() {
|
||
|
prevCheckWorkspaces = Main.wm._workspaceTracker._checkWorkspaces;
|
||
|
Main.wm._workspaceTracker._checkWorkspaces = myCheckWorkspaces;
|
||
|
|
||
|
winMover = new WindowMover();
|
||
|
}
|
||
|
|
||
|
function disable() {
|
||
|
Main.wm._workspaceTracker._checkWorkspaces = prevCheckWorkspaces;
|
||
|
winMover.destroy();
|
||
|
}
|