Skip to content

Instantly share code, notes, and snippets.

@reusee
Created December 12, 2019 05:59
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save reusee/c8dbba4d2172352870a8e0349fd1b2f1 to your computer and use it in GitHub Desktop.
Save reusee/c8dbba4d2172352870a8e0349fd1b2f1 to your computer and use it in GitHub Desktop.
personal gnome shell extension
'use strict'
const { Meta, Shell, GLib } = imports.gi;
const Main = imports.ui.main;
const ExtensionUtils = imports.misc.extensionUtils;
const Me = ExtensionUtils.getCurrentExtension();
const Util = imports.misc.util;
class Extension {
constructor() {
}
enable() {
log(`enable ${Me.metadata.name}`);
// key bindings
const bindings = [
// windows management
{
accelerator: '<super>k',
// focus next
fn: () => {
this.switchWindow((windows, i) => {
i = i + 1
if (i >= windows.length) {
i = 0
}
return i
})
},
},
{
accelerator: '<super>j',
// focus prev
fn: () => {
this.switchWindow((windows, i) => {
i = i - 1
if (i < 0) {
i = windows.length - 1
}
return i
})
},
},
{
accelerator: '<super>z',
fn: () => {
// close
global.display.focus_window.delete(global.display.get_current_time());
},
},
{
accelerator: '<super>a',
fn: () => {
// minimize
global.display.focus_window.minimize();
},
},
// programs
{
accelerator: '<super>Return',
fn: () => {
// terminal emulator
Util.spawn(['/home/reus/bin/terminal']);
},
},
{
accelerator: '<super>i',
fn: () => {
// open or switch to browser
this.switchWindow((windows, i) => {
for (const idx in windows) {
if (windows[idx].get_wm_class() == 'Vivaldi-stable') {
return idx
}
}
Util.spawn(['vivaldi-stable']);
return -1
})
},
},
]
const actions = {};
global.display.connect(
'accelerator-activated',
function(display, action, deviceID, timestamp) {
const fn = actions[action];
if (fn) {
fn()
}
},
)
for (const binding of bindings) {
const action = global.display.grab_accelerator(binding.accelerator, 0);
if (action != Meta.KeyBindingAction.NONE) {
let name = Meta.external_binding_name_for_action(action);
Main.wm.allowKeybinding(name, Shell.ActionMode.ALL);
actions[action] = binding.fn;
}
}
// windows signals
global.display.connect_after('window-created', (display, win) => {
win.connect_after('focus', () => {
// unmaximize
win.unmaximize(Meta.MaximizeFlags.HORIZONTAL | Meta.MaximizeFlags.VERTICAL);
})
})
global.display.connect_after('notify::focus-window', (display, win) => {
const focus = display.focus_window;
if (focus) {
this.relayout(focus.get_workspace());
}
})
// mutter shadow
const shadow_factory = Meta.ShadowFactory.get_default()
shadow_factory.set_params('normal', true, new Meta.ShadowParams({
'radius': 50,
'opacity': 255,
}))
log(`enable ${Me.metadata.name} done`);
}
relayout(workspace) {
const rect = workspace.get_work_area_all_monitors();
const default_height = rect.height
const default_width = default_height / 3 * 4
const padding = rect.width - default_width
let windows = workspace.list_windows()
.filter(win => {
return !win.is_hidden()
&& win.get_window_type() == Meta.WindowType.NORMAL
&& win.get_transient_for() == null
})
const focus = global.display.focus_window;
let focus_top = focus
const transient_for = focus_top.get_transient_for()
if (transient_for) {
focus_top = transient_for
}
const focus_index = windows.indexOf(focus_top);
if (focus_index >= 0) {
windows = windows.slice(focus_index + 1)
.concat(windows.slice(0, focus_index + 1))
}
for (const i in windows) {
const width = default_width;
const height = default_height;
const x = windows.length == 1 ?
rect.x + padding
: rect.x + padding / (windows.length - 1) * i
const y = rect.y
windows[i].move_resize_frame(false, x, y, width, height);
windows[i].raise()
}
focus.raise()
}
switchWindow(getIndex) {
const workspace = global.workspace_manager.get_active_workspace();
let windows = workspace.list_windows();
windows = windows.filter(win => !win.is_hidden());
const focus = global.display.focus_window;
let i = windows.indexOf(focus);
const idx = getIndex(windows, i);
if (idx >= 0 && idx != i) {
windows[idx].activate(global.display.get_current_time());
}
}
disable() {
log(`disable ${Me.metadata.name}`);
}
}
function init() {
log(`init ${Me.metadata.name}`);
return new Extension();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment