mirror of
https://github.com/gosticks/PaperWM.git
synced 2026-02-07 01:12:45 +00:00
217 lines
6.5 KiB
JavaScript
217 lines
6.5 KiB
JavaScript
// polyfill workspace_manager that was introduced in 3.30 (must happen before modules are imported)
|
|
if (!global.workspace_manager) {
|
|
global.workspace_manager = global.screen;
|
|
}
|
|
|
|
/**
|
|
The currently used modules
|
|
- tiling is the main module, responsible for tiling and workspaces
|
|
|
|
- navigator is used to initiate a discrete navigation.
|
|
Focus is only switched when the navigation is done.
|
|
|
|
- keybindings is a utility wrapper around mutters keybinding facilities.
|
|
|
|
- scratch is used to manage floating windows, or scratch windows.
|
|
|
|
- liveAltTab is a simple altTab implementiation with live previews.
|
|
|
|
- stackoverlay is somewhat kludgy. It makes clicking on the left or right
|
|
edge of the screen always activate the partially (or sometimes wholly)
|
|
concealed window at the edges.
|
|
|
|
- app creates new windows based on the current application. It's possible
|
|
to create custom new window handlers.
|
|
|
|
- kludges is used for monkey patching gnome shell behavior which simply
|
|
doesn't fit paperwm.
|
|
|
|
- topbar adds the workspace name to the topbar and styles it.
|
|
|
|
- gestures is responsible for 3-finger swiping (only works in wayland).
|
|
*/
|
|
var modules = [
|
|
'tiling', 'navigator', 'keybindings', 'scratch', 'liveAltTab', 'utils',
|
|
'stackoverlay', 'app', 'kludges', 'topbar', 'settings','gestures'
|
|
];
|
|
|
|
/**
|
|
Tell the modules to run init, enable or disable
|
|
*/
|
|
function run(method) {
|
|
for (let name of modules) {
|
|
// Bail if there's an error in our own modules
|
|
if (!safeCall(name, method))
|
|
return false;
|
|
}
|
|
|
|
if (hasUserConfigFile()) {
|
|
safeCall('user', method);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
function safeCall(name, method) {
|
|
try {
|
|
print("#paperwm", `${method} ${name}`);
|
|
let module = Extension.imports[name];
|
|
module && module[method] && module[method].call(module, errorNotification);
|
|
return true;
|
|
} catch(e) {
|
|
print("#paperwm", `${name} failed ${method}`);
|
|
print(`JS ERROR: ${e}\n${e.stack}`);
|
|
errorNotification(
|
|
"PaperWM",
|
|
`Error occured in ${name} @${method}:\n\n${e.message}`,
|
|
e.stack);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
var SESSIONID = ""+(new Date().getTime());
|
|
|
|
/**
|
|
* The extension sometimes go through multiple init -> enable -> disable
|
|
* cycles. So we need to keep track of whether we're initialized..
|
|
*/
|
|
var initRun;
|
|
var enabled = false;
|
|
|
|
var Extension, convenience;
|
|
function init() {
|
|
SESSIONID += "#";
|
|
log(`#paperwm init: ${SESSIONID}`);
|
|
|
|
// var Gio = imports.gi.Gio;
|
|
// let extfile = Gio.file_new_for_path( Extension.imports.extension.__file__);
|
|
Extension = imports.misc.extensionUtils.getCurrentExtension();
|
|
convenience = Extension.imports.convenience;
|
|
|
|
if(initRun) {
|
|
log(`#startup Reinitialized against our will! Skip adding bindings again to not cause trouble.`);
|
|
return;
|
|
}
|
|
|
|
initUserConfig();
|
|
|
|
if (run('init'))
|
|
initRun = true;
|
|
}
|
|
|
|
function enable() {
|
|
log(`#paperwm enable ${SESSIONID}`);
|
|
if (enabled) {
|
|
log('enable called without calling disable');
|
|
return;
|
|
}
|
|
|
|
if (run('enable'))
|
|
enabled = true;
|
|
}
|
|
|
|
function disable() {
|
|
log(`#paperwm disable ${SESSIONID}`);
|
|
if (!enabled) {
|
|
log('disable called without calling enable');
|
|
return;
|
|
}
|
|
|
|
if (run('disable'))
|
|
enabled = false;
|
|
}
|
|
|
|
|
|
var Gio = imports.gi.Gio;
|
|
var GLib = imports.gi.GLib;
|
|
var Main = imports.ui.main;
|
|
|
|
function getConfigDir() {
|
|
return Gio.file_new_for_path(GLib.get_user_config_dir() + '/paperwm');
|
|
}
|
|
|
|
function hasUserConfigFile() {
|
|
return getConfigDir().get_child("user.js").query_exists(null);
|
|
}
|
|
|
|
function installConfig() {
|
|
print("#rc", "Installing config");
|
|
const configDir = getConfigDir();
|
|
configDir.make_directory_with_parents(null);
|
|
|
|
// We copy metadata.json to the config directory so gnome-shell-mode
|
|
// know which extension the files belong to (ideally we'd symlink, but
|
|
// that trips up the importer: Extension.imports.<complete> in
|
|
// gnome-shell-mode crashes gnome-shell..)
|
|
const metadata = Extension.dir.get_child("metadata.json");
|
|
metadata.copy(configDir.get_child("metadata.json"), Gio.FileCopyFlags.NONE, null, null);
|
|
|
|
// Copy the user.js template to the config directory
|
|
const user = Extension.dir.get_child("examples/user.js");
|
|
user.copy(configDir.get_child("user.js"), Gio.FileCopyFlags.NONE, null, null);
|
|
|
|
const settings = convenience.getSettings();
|
|
settings.set_boolean("has-installed-config-template", true);
|
|
}
|
|
|
|
function initUserConfig() {
|
|
const paperSettings = convenience.getSettings();
|
|
|
|
if (!paperSettings.get_boolean("has-installed-config-template")
|
|
&& !hasUserConfigFile())
|
|
{
|
|
try {
|
|
installConfig();
|
|
|
|
const configDir = getConfigDir().get_path();
|
|
const notification = notify("PaperWM", `Installed user configuration in ${configDir}`);
|
|
notification.connect('activated', () => {
|
|
imports.misc.util.spawn(["nautilus", configDir]);
|
|
notification.destroy();
|
|
});
|
|
} catch(e) {
|
|
errorNotification("PaperWM",
|
|
`Failed to install user config: ${e.message}`, e.stack);
|
|
print("#rc", "Install failed", e.message);
|
|
}
|
|
|
|
}
|
|
|
|
if (hasUserConfigFile()) {
|
|
Extension.imports.searchPath.push(getConfigDir().get_path());
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Our own version of imports.ui.main.notify allowing more control over the
|
|
* notification
|
|
*/
|
|
function notify(msg, details, params) {
|
|
const MessageTray = imports.ui.messageTray;
|
|
let source = new MessageTray.SystemNotificationSource();
|
|
// note-to-self: the source is automatically destroyed when all its
|
|
// notifications are removed.
|
|
Main.messageTray.add(source);
|
|
let notification = new MessageTray.Notification(source, msg, details, params);
|
|
notification.setResident(true); // Usually more annoying that the notification disappear than not
|
|
source.notify(notification);
|
|
return notification;
|
|
}
|
|
|
|
function spawnPager(content) {
|
|
const quoted = GLib.shell_quote(content);
|
|
imports.misc.util.spawn(["sh", "-c", `echo -En ${quoted} | gedit --new-window -`]);
|
|
}
|
|
|
|
/**
|
|
* Show an notification opening a the full message in dedicated window upon
|
|
* activation
|
|
*/
|
|
function errorNotification(title, message, fullMessage) {
|
|
const notification = notify(title, message);
|
|
notification.connect('activated', () => {
|
|
spawnPager([title, message, "", fullMessage].join("\n"));
|
|
notification.destroy();
|
|
});
|
|
}
|