Skip to content

Instantly share code, notes, and snippets.

@edinella
Forked from kaushikgopal/.phoenix.1.js
Last active August 29, 2015 14:20
Show Gist options
  • Save edinella/9c7acb41d411717d8b04 to your computer and use it in GitHub Desktop.
Save edinella/9c7acb41d411717d8b04 to your computer and use it in GitHub Desktop.
// Forked from kaushikgopal/.phoenix.js
// Released under MIT license - http://opensource.org/licenses/MIT
var BROWSER;
var EDITOR;
var FINDER;
var GRID_HEIGHT;
var GRID_WIDTH;
var MARGIN_X;
var MARGIN_Y;
var MUSIC;
var TERMINAL;
var VIDEO;
var changeGridHeight;
var changeGridWidth;
var debug;
var forApp;
var key_binding;
var lastFrames;
var layouts;
var mash;
var moveWindowLeftOneColumn;
var moveWindowRightOneColumn;
var moveWindowToNextScreen;
var moveWindowToPreviousScreen;
var snapAllToGrid;
var switchLayout;
var transposeWindows;
var windowDownOneRow;
var windowGrowOneGridColumn;
var windowGrowOneGridRow;
var windowShrinkOneGridColumn;
var windowShrinkOneGridRow;
var windowToFullHeight;
var windowUpOneRow;
var tileWindowsForThisApp;
debug = function(message) {
return api.alert(message, 10);
};
MARGIN_X = 3;
MARGIN_Y = 3;
GRID_WIDTH = 2;
GRID_HEIGHT = 2;
EDITOR = 'Atom';
BROWSER = 'Chrome';
TERMINAL = 'Terminal';
FINDER = 'Finder';
MUSIC = 'Spotify';
VIDEO = 'Quicktime Player';
layouts = {
'Editor and Browser': {
0: {app: BROWSER, whereTo: 'toRightHalf'},
1: {app: EDITOR, whereTo: 'toLeftHalf'}
},
'Editor and Terminal': {
0: {app: TERMINAL, whereTo: 'toRightHalf'},
1: {app: EDITOR, whereTo: 'toLeftHalf'}
},
'Terminal and Browser': {
0: {app: TERMINAL, whereTo: 'toLeftHalf'},
1: {app: BROWSER, whereTo: 'toRightHalf'}
},
'Finder and Terminal': {
0: {app: TERMINAL, whereTo: 'toRightHalf'},
1: {app: FINDER, whereTo: 'toLeftHalf'}
},
'Finder and Browser': {
0: {app: BROWSER, whereTo: 'toRightHalf'},
1: {app: FINDER, whereTo: 'toLeftHalf'}
}
};
snapAllToGrid = function() {
Window.visibleWindows().map(function(win) {
win.snapToGrid();
});
};
changeGridWidth = function(by_) {
GRID_WIDTH = Math.max(1, GRID_WIDTH + by_);
api.alert('grid is now ' + GRID_WIDTH + ' tiles wide', 1);
snapAllToGrid();
};
changeGridHeight = function(by_) {
GRID_HEIGHT = Math.max(1, GRID_HEIGHT + by_);
api.alert('grid is now ' + GRID_HEIGHT + ' tiles high', 1);
snapAllToGrid();
};
Window.prototype.getGrid = function() {
var winFrame = this.frame();
var screenRect = this.screen().frameWithoutDockOrMenu();
var thirdScreenWidth = screenRect.width / GRID_WIDTH;
var halfScreenHeight = screenRect.height / GRID_HEIGHT;
return {
x: Math.round((winFrame.x - screenRect.x) / thirdScreenWidth),
y: Math.round((winFrame.y - screenRect.y) / halfScreenHeight),
width: Math.max(1, Math.round(winFrame.width / thirdScreenWidth)),
height: Math.max(1, Math.round(winFrame.height / halfScreenHeight))
};
};
Window.prototype.setGrid = function(grid, screen) {
var screenRect = screen.frameWithoutDockOrMenu();
var thirdScreenWidth = screenRect.width / GRID_WIDTH;
var halfScreenHeight = screenRect.height / GRID_HEIGHT;
var newFrame = {
x: (grid.x * thirdScreenWidth) + screenRect.x,
y: (grid.y * halfScreenHeight) + screenRect.y,
width: grid.width * thirdScreenWidth,
height: grid.height * halfScreenHeight
};
newFrame.x += MARGIN_X;
newFrame.y += MARGIN_Y;
newFrame.width -= MARGIN_X * 2.0;
newFrame.height -= MARGIN_Y * 2.0;
return this.setFrame(newFrame);
};
Window.prototype.snapToGrid = function() {
if (this.isNormalWindow()) {
return this.setGrid(this.getGrid(), this.screen());
}
};
Window.prototype.calculateGrid = function(x, y, width, height) {
var screen;
screen = this.screen().frameWithoutDockOrMenu();
return {
x: Math.round(x * screen.width) + MARGIN_X + screen.x,
y: Math.round(y * screen.height) + MARGIN_Y + screen.y,
width: Math.round(width * screen.width) - 2.0 * MARGIN_X,
height: Math.round(height * screen.height) - 2.0 * MARGIN_Y
};
};
Window.prototype.toGrid = function(x, y, width, height) {
var rect = this.calculateGrid(x, y, width, height);
this.setFrame(rect);
return this;
};
Window.prototype.topRight = function() {
var f = this.frame();
return {
x: f.x + f.width,
y: f.y
};
};
Window.prototype.toLeft = function() {
var p = this.topLeft();
return _.chain(this.windowsToWest()).filter(function(win) {
return win.topLeft().x < p.x - 10;
}).value();
};
Window.prototype.toRight = function() {
var p = this.topRight();
return _.chain(this.windowsToEast()).filter(function(win) {
return win.topRight().x > p.x + 10;
}).value();
};
Window.prototype.info = function() {
var f = this.frame();
return [
'[', this.app().pid, '] ', this.app().title(), ' : ', this.title(), '\n',
'{x:', f.x, ', y:', f.y, ', width:', f.width, ', height:', f.height, '}\n',
].join('');
};
Window.sortByMostRecent = function(windows) {
var allVisible = Window.visibleWindowsMostRecentFirst();
return _.chain(windows).sortBy(function(win) {
return _.map(allVisible, function(w) {
return w.info();
}).indexOf(win.info());
}).value();
};
lastFrames = {};
Window.prototype.toFullScreen = function() {
var fullFrame = this.calculateGrid(0, 0, 1, 1);
if (!_.isEqual(this.frame(), fullFrame)) {
this.rememberFrame();
return this.toGrid(0, 0, 1, 1);
} else if (lastFrames[this]) {
this.setFrame(lastFrames[this]);
return this.forgetFrame();
}
};
Window.prototype.rememberFrame = function() {
return (lastFrames[this] = this.frame());
};
Window.prototype.forgetFrame = function() {
return delete lastFrames[this];
};
Window.prototype.toTopHalf = function() {
return this.toGrid(0, 0, 1, 0.5);
};
Window.prototype.toBottomHalf = function() {
return this.toGrid(0, 0.5, 1, 0.5);
};
Window.prototype.toLeftHalf = function() {
return this.toGrid(0, 0, 0.5, 1);
};
Window.prototype.toRightHalf = function() {
return this.toGrid(0.5, 0, 0.5, 1);
};
Window.prototype.toTopRight = function() {
return this.toGrid(0.5, 0, 0.5, 0.5);
};
Window.prototype.toBottomRight = function() {
return this.toGrid(0.5, 0.5, 0.5, 0.5);
};
Window.prototype.toTopLeft = function() {
return this.toGrid(0, 0, 0.5, 0.5);
};
Window.prototype.toBottomLeft = function() {
return this.toGrid(0, 0.5, 0.5, 0.5);
};
moveWindowToNextScreen = function() {
var win = Window.focusedWindow();
return win.setGrid(win.getGrid(), win.screen().nextScreen());
};
moveWindowToPreviousScreen = function() {
var win = Window.focusedWindow();
return win.setGrid(win.getGrid(), win.screen().previousScreen());
};
moveWindowLeftOneColumn = function() {
var win = Window.focusedWindow();
var frame = win.getGrid();
frame.x = Math.max(frame.x - 1, 0);
return win.setGrid(frame, win.screen());
};
moveWindowRightOneColumn = function() {
var win = Window.focusedWindow();
var frame = win.getGrid();
frame.x = Math.min(frame.x + 1, GRID_WIDTH - frame.width);
return win.setGrid(frame, win.screen());
};
windowGrowOneGridColumn = function() {
var win = Window.focusedWindow();
var frame = win.getGrid();
frame.width = Math.min(frame.width + 1, GRID_WIDTH - frame.x);
return win.setGrid(frame, win.screen());
};
windowShrinkOneGridColumn = function() {
var win = Window.focusedWindow();
var frame = win.getGrid();
frame.width = Math.max(frame.width - 1, 1);
return win.setGrid(frame, win.screen());
};
windowGrowOneGridRow = function() {
var win = Window.focusedWindow();
var frame = win.getGrid();
frame.height = Math.min(frame.height + 1, GRID_HEIGHT);
return win.setGrid(frame, win.screen());
};
windowShrinkOneGridRow = function() {
var win = Window.focusedWindow();
var frame = win.getGrid();
frame.height = Math.max(frame.height - 1, 1);
return win.setGrid(frame, win.screen());
};
windowDownOneRow = function() {
var win = Window.focusedWindow();
var frame = win.getGrid();
frame.y = Math.min(Math.floor(frame.y + 1), GRID_HEIGHT - 1);
return win.setGrid(frame, win.screen());
};
windowUpOneRow = function() {
var win = Window.focusedWindow();
var frame = win.getGrid();
frame.y = Math.max(Math.floor(frame.y - 1), 0);
return win.setGrid(frame, win.screen());
};
windowToFullHeight = function() {
var win = Window.focusedWindow();
var frame = win.getGrid();
frame.y = 0;
frame.height = GRID_HEIGHT;
return win.setGrid(frame, win.screen());
};
transposeWindows = function(swapFrame, switchFocus) {
if (swapFrame === null) {
swapFrame = true;
}
if (switchFocus === null) {
switchFocus = true;
}
var win = Window.focusedWindow();
var left = win.toRight();
var right = win.toLeft();
var targets = left.length > 0 ? left : right.length > 0 ? right : void 0;
var hasWinToTranspose = (targets ? targets.length : void 0) > 0;
if (!hasWinToTranspose) {
api.alert('Can\'t see any windows to transpose');
return;
}
target = Window.sortByMostRecent(targets)[0];
var tFrame = target.frame();
var wFrame = win.frame();
if (swapFrame) {
win.setFrame(tFrame);
target.setFrame(wFrame);
} else {
target.topLeft({
x: wFrame.x,
y: wFrame.y
});
win.topLeft({
x: tFrame.x,
y: tFrame.y
});
}
if (switchFocus) {
return target.focusWindow();
}
};
Window.prototype.tileWindowsForThisApp = function() {
var fullFrame = this.calculateGrid(0, 0, 1, 1);
var title = this.app().title();
var prevY = 0;
var prevX = 0;
var newFrame;
var currentAppWindows = _(Window.visibleWindows()).filter(function(window) {
if (window.app().title() == title) {
return true;
}
});
currentAppWindows.reverse();
_.each(currentAppWindows, function(window) {
newFrame = {
x: prevX,
y: prevY,
width: 0.8 * fullFrame.width,
height: 0.8 * fullFrame.height
};
window.setFrame(newFrame);
window.focusWindow();
prevY = prevY + 100;
prevX = prevX + 50;
if (prevY + 0.8 * fullFrame.height >= fullFrame.height) {
prevY = 0;
}
if (prevX + 0.8 * fullFrame.width >= fullFrame.width) {
prevX = 0;
}
});
};
App.prototype.firstWindow = function() {
return this.visibleWindows()[0];
};
App.byTitle = function(title) {
var apps = this.runningApps();
var i = 0;
while (i < apps.length) {
var app = apps[i];
if (app.title() === title) {
app.show();
return app;
}
i++;
}
};
App.allWithTitle = function(title) {
return _(this.runningApps()).filter(function(app) {
if (app.title() === title) {
return true;
}
});
};
App.focusOrStart = function(title) {
var apps = App.allWithTitle(title);
if (_.isEmpty(apps)) {
api.alert('Attempting to start ' + title);
api.launch(title);
return;
}
var windows = _.chain(apps).map(function(x) {
return x.allWindows();
}).flatten().value();
var activeWindows = _(windows).reject(function(win) {
return win.isWindowMinimized();
});
if (_.isEmpty(activeWindows)) {
api.launch(title);
}
activeWindows.forEach(function(win) {
win.focusWindow();
});
};
forApp = function(title, fn) {
var app;
app = App.byTitle(title);
if (app) {
return _.each(app.visibleWindows(), fn);
}
};
switchLayout = function(name) {
return _.each(layouts[name], function(config) {
var app;
App.focusOrStart(config.app);
app = App.byTitle(config.app);
return app.firstWindow()[config.whereTo]();
});
};
// KEY BINDINGS
kBind = function(key, modifier, fn) {
return api.bind(key, modifier, fn);
};
mash = 'cmd+alt+ctrl'.split('+');
kBind('space', mash, function() {
return Window.focusedWindow().toFullScreen();
});
kBind('up', mash, function() {
return Window.focusedWindow().toTopHalf();
});
kBind('down', mash, function() {
return Window.focusedWindow().toBottomHalf();
});
kBind('left', mash, function() {
return Window.focusedWindow().toLeftHalf();
});
kBind('right', mash, function() {
return Window.focusedWindow().toRightHalf();
});
kBind('\\', mash, function() {
return moveWindowToNextScreen();
});
kBind('P', mash, function() {
return moveWindowToPreviousScreen();
});
kBind('Y', mash, function() {
return transposeWindows(true, true);
});
kBind('Q', mash, function() {
return Window.focusedWindow().toTopLeft();
});
kBind('A', mash, function() {
return Window.focusedWindow().toBottomLeft();
});
kBind('W', mash, function() {
return Window.focusedWindow().toTopRight();
});
kBind('S', mash, function() {
return Window.focusedWindow().toBottomRight();
});
kBind('R', mash, function() {
return Window.focusedWindow().focusWindowUp();
});
kBind('D', mash, function() {
return Window.focusedWindow().focusWindowLeft();
});
kBind('F', mash, function() {
return Window.focusedWindow().focusWindowRight();
});
kBind('C', mash, function() {
return Window.focusedWindow().focusWindowDown();
});
kBind('O', mash, function() {
return changeGridHeight(+1);
});
kBind('I', mash, function() {
return changeGridHeight(-1);
});
kBind('K', mash, function() {
return changeGridWidth(+1);
});
kBind('L', mash, function() {
return changeGridWidth(-1);
});
kBind('=', mash, function() {
return windowShrinkOneGridRow();
});
kBind('-', mash, function() {
return windowGrowOneGridRow();
});
kBind(']', mash, function() {
return windowShrinkOneGridColumn();
});
kBind('[', mash, function() {
return windowGrowOneGridColumn();
});
kBind(';', mash, function() {
return Window.focusedWindow().snapToGrid();
});
kBind('\'', mash, function() {
return Window.visibleWindows().map(function(win) {return win.snapToGrid();});
});
kBind('T', mash, function() {
return Window.focusedWindow().tileWindowsForThisApp();
});
kBind('U', mash, function() {
return windowToFullHeight();
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment