Skip to content

Instantly share code, notes, and snippets.

@kaushikgopal
Last active January 23, 2016 22:38
Show Gist options
  • Save kaushikgopal/5894b44320efc8c5cb18 to your computer and use it in GitHub Desktop.
Save kaushikgopal/5894b44320efc8c5cb18 to your computer and use it in GitHub Desktop.
Kaushik Gopal's Phoenix.Js window management script
// Generated by CoffeeScript 1.10.0
(function() {
var EMACS, FINDER, GRID_HEIGHT, GRID_WIDTH, ITERM, MARGIN_X, MARGIN_Y, TERMINAL, VIM, changeGridHeight, changeGridWidth, debug, focused, key_binding, keys, lastFrames, mash, moveWindowToNextScreen, moveWindowToPreviousScreen, snapAllToGrid, windowDownOneRow, windowGrowOneGridColumn, windowGrowOneGridRow, windowLeftOneColumn, windowRightOneColumn, windowShrinkOneGridColumn, windowShrinkOneGridRow, windowToFullHeight, windowUpOneRow, windows;
debug = function(o, label) {
if (label == null) {
label = "obj: ";
}
Phoenix.log(label);
return Phoenix.log(JSON.stringify(o));
};
MARGIN_X = 3;
MARGIN_Y = 3;
GRID_WIDTH = 20;
GRID_HEIGHT = 16;
_.mixin({
flatmap: function(list, iteratee, context) {
return _.flatten(_.map(list, iteratee, context));
}
});
focused = function() {
return Window.focusedWindow();
};
windows = function() {
return Window.visibleWindows();
};
Window.prototype.screenRect = function() {
return this.screen().visibleFrameInRectangle();
};
Window.prototype.fullGridFrame = function() {
return this.calculateGrid({
y: 0,
x: 0,
width: 1,
height: 1
});
};
snapAllToGrid = function() {
return _.map(visible(), function(win) {
return win.snapToGrid();
});
};
changeGridWidth = function(n) {
GRID_WIDTH = Math.max(1, GRID_WIDTH + n);
Phoenix.notify("grid is " + GRID_WIDTH + " tiles wide");
return snapAllToGrid();
};
changeGridHeight = function(n) {
GRID_HEIGHT = Math.max(1, GRID_HEIGHT + n);
Phoenix.notify("grid is " + GRID_HEIGHT + " tiles high");
return snapAllToGrid();
};
Window.prototype.getGrid = function() {
var frame, gridHeight, gridWidth;
frame = this.frame();
gridWidth = this.screenRect().width / GRID_WIDTH;
gridHeight = this.screenRect().height / GRID_HEIGHT;
return {
y: Math.round((frame.y - this.screenRect().y) / gridHeight),
x: Math.round((frame.x - this.screenRect().x) / gridWidth),
width: Math.max(1, Math.round(frame.width / gridWidth)),
height: Math.max(1, Math.round(frame.height / gridHeight))
};
};
Window.prototype.setGrid = function(grid, screen) {
var gridHeight, gridWidth;
gridWidth = this.screenRect().width / GRID_WIDTH;
gridHeight = this.screenRect().height / GRID_HEIGHT;
return this.setFrame({
y: ((grid.y * gridHeight) + this.screenRect().y) + MARGIN_Y,
x: ((grid.x * gridWidth) + this.screenRect().x) + MARGIN_X,
width: (grid.width * gridWidth) - (MARGIN_X * 2.0),
height: (grid.height * gridHeight) - (MARGIN_Y * 2.0)
});
};
Window.prototype.snapToGrid = function() {
if (this.isNormal()) {
return this.setGrid(this.getGrid(), this.screen());
}
};
Window.prototype.calculateGrid = function(arg) {
var height, width, x, y;
x = arg.x, y = arg.y, width = arg.width, height = arg.height;
return {
y: Math.round(y * this.screenRect().height) + MARGIN_Y + this.screenRect().y,
x: Math.round(x * this.screenRect().width) + MARGIN_X + this.screenRect().x,
width: Math.round(width * this.screenRect().width) - 2.0 * MARGIN_X,
height: Math.round(height * this.screenRect().height) - 2.0 * MARGIN_Y
};
};
Window.prototype.toGrid = function(arg) {
var height, rect, width, x, y;
x = arg.x, y = arg.y, width = arg.width, height = arg.height;
rect = this.calculateGrid({
x: x,
y: y,
width: width,
height: height
});
this.setFrame(rect);
return this;
};
Window.prototype.topRight = function() {
return {
x: this.frame().x + this.frame().width,
y: this.frame().y
};
};
Window.prototype.toLeft = function() {
return _.filter(this.windowsToWest(), function(win) {
return win.topLeft().x < this.topLeft().x - 10;
});
};
Window.prototype.toRight = function() {
return _.filter(this.windowsToEast(), function(win) {
return win.topRight().x > this.topRight().x + 10;
});
};
Window.prototype.info = function() {
var f;
f = this.frame();
return "[" + (this.app().processIdentifier()) + "] " + (this.app().name()) + " : " + (this.title()) + "\n{x:" + f.x + ", y:" + f.y + ", width:" + f.width + ", height:" + f.height + "}\n";
};
Window.sortByMostRecent = function(windows) {
var allVisible;
allVisible = visibleInOrder();
return _.sortBy(windows, function(win) {
return _.map(allVisible, function(w) {
return w.info();
}).indexOf(win.info());
});
};
lastFrames = {};
Window.prototype.toFullScreen = function() {
if (!_.isEqual(this.frame(), this.fullGridFrame())) {
this.rememberFrame();
return this.toGrid({
y: 0,
x: 0,
width: 1,
height: 1
});
} else if (lastFrames[this.uid()]) {
this.setFrame(lastFrames[this.uid()]);
return this.forgetFrame();
}
};
Window.prototype.uid = function() {
return (this.app().name()) + "::" + (this.title());
};
Window.prototype.rememberFrame = function() {
return lastFrames[this.uid()] = this.frame();
};
Window.prototype.forgetFrame = function() {
return delete lastFrames[this.uid()];
};
Window.prototype.toTopHalf = function() {
return this.toGrid({
x: 0,
y: 0,
width: 1,
height: 0.5
});
};
Window.prototype.toBottomHalf = function() {
return this.toGrid({
x: 0,
y: 0.5,
width: 1,
height: 0.5
});
};
Window.prototype.toLeftHalf = function() {
return this.toGrid({
x: 0,
y: 0,
width: 0.5,
height: 1
});
};
Window.prototype.toRightHalf = function() {
return this.toGrid({
x: 0.5,
y: 0,
width: 0.5,
height: 1
});
};
Window.prototype.toTopRight = function() {
return this.toGrid({
x: 0.5,
y: 0,
width: 0.5,
height: 0.5
});
};
Window.prototype.toBottomRight = function() {
return this.toGrid({
x: 0.5,
y: 0.5,
width: 0.5,
height: 0.5
});
};
Window.prototype.toTopLeft = function() {
return this.toGrid({
x: 0,
y: 0,
width: 0.5,
height: 0.5
});
};
Window.prototype.toBottomLeft = function() {
return this.toGrid({
x: 0,
y: 0.5,
width: 0.5,
height: 0.5
});
};
Window.prototype.pushLeft = function() {
return this.toGrid({
x: 0,
y: 0,
width: 2/3,
height: 1
});
};
Window.prototype.pushRight = function() {
return this.toGrid({
x: 2/3,
y: 0,
width: 1/3,
height: 1
});
};
Window.prototype.fillToScreenHeight = function() {
var fullFrame = this.calculateGrid({
y: 0,
x: 0,
width: 1,
height: 1
});
var newFrame = this.frame();
newFrame.y = 0;
newFrame.height = fullFrame.height;
Window.focusedWindow().setFrame(newFrame);
return this;
};
Window.prototype.tileWindowsForThisApp = function() {
var fullFrame = this.calculateGrid({
y: 0,
x: 0,
width: 1,
height: 1
});
var name = this.app().name();
var prevY = 0;
var prevX = 0;
var newFrame;
var currentAppWindows = _(Window.visibleWindows()).filter(function(window) {
if (window.app().name() == name) {
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.focus();
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;
};
});
return this;
};
moveWindowToNextScreen = function() {
return focused().setGrid(focused().getGrid(), focused().screen().nextScreen());
};
moveWindowToPreviousScreen = function() {
return focused().setGrid(focused().getGrid(), focused().screen().previousScreen());
};
windowLeftOneColumn = function() {
var frame;
frame = focused().getGrid();
frame.x = Math.max(frame.x - 1, 0);
return focused().setGrid(frame, focused().screen());
};
windowDownOneRow = function() {
var frame;
frame = focused().getGrid();
frame.y = Math.min(Math.floor(frame.y + 1), GRID_HEIGHT - 1);
return focused().setGrid(frame, focused().screen());
};
windowUpOneRow = function() {
var frame;
frame = focused().getGrid();
frame.y = Math.max(Math.floor(frame.y - 1), 0);
return focused().setGrid(frame, focused().screen());
};
windowRightOneColumn = function() {
var frame;
frame = focused().getGrid();
frame.x = Math.min(frame.x + 1, GRID_WIDTH - frame.width);
return focused().setGrid(frame, focused().screen());
};
windowGrowOneGridColumn = function() {
var frame;
frame = focused().getGrid();
frame.width = Math.min(frame.width + 1, GRID_WIDTH - frame.x);
return focused().setGrid(frame, focused().screen());
};
windowShrinkOneGridColumn = function() {
var frame;
frame = focused().getGrid();
frame.width = Math.max(frame.width - 1, 1);
return focused().setGrid(frame, focused().screen());
};
windowGrowOneGridRow = function() {
var frame;
frame = focused().getGrid();
frame.height = Math.min(frame.height + 1, GRID_HEIGHT);
return focused().setGrid(frame, focused().screen());
};
windowShrinkOneGridRow = function() {
var frame;
frame = focused().getGrid();
frame.height = Math.max(frame.height - 1, 1);
return focused().setGrid(frame, focused().screen());
};
windowToFullHeight = function() {
var frame;
frame = focused().getGrid();
frame.y = 0;
frame.height = GRID_HEIGHT;
return focused().setGrid(frame, focused().screen());
};
App.prototype.firstWindow = function() {
return this.visibleWindows()[0];
};
App.allWithName = function(name) {
return _.filter(App.runningApps(), function(app) {
return app.name() === name;
});
};
App.byName = function(name) {
var app;
app = _.first(App.allWithName(name));
app.show();
return app;
};
App.focusOrStart = function(name) {
var activeWindows, apps;
apps = App.allWithName(name);
if (_.isEmpty(apps)) {
Phoenix.notify("Starting " + name);
App.launch(name);
} else {
Phoenix.notify("Switching to " + name);
}
windows = _.flatmap(apps, function(x) {
return x.windows();
});
activeWindows = _.reject(windows, function(win) {
return win.isMinimized();
});
if (_.isEmpty(activeWindows)) {
App.launch(name);
}
return _.each(activeWindows, function(win) {
return win.focus();
});
};
keys = [];
key_binding = function(key, description, modifier, fn) {
return keys.push(Phoenix.bind(key, modifier, fn));
};
mash = 'cmd-alt-shift'.split('-');
key_binding('up', 'To Top Half', mash, function() {
return Window.focusedWindow().toTopHalf();
});
key_binding('down', 'To Bottom Half', mash, function() {
return Window.focusedWindow().toBottomHalf();
});
key_binding('left', 'To Left Half', mash, function() {
return Window.focusedWindow().toLeftHalf();
});
key_binding('right', 'To Right Half', mash, function() {
return Window.focusedWindow().toRightHalf();
});
key_binding('T', 'Top Left', mash, function() {
return Window.focusedWindow().toTopLeft();
});
key_binding('G', 'Bottom Left', mash, function() {
return Window.focusedWindow().toBottomLeft();
});
key_binding('Y', 'Top Right', mash, function() {
return Window.focusedWindow().toTopRight();
});
key_binding('H', 'Bottom Right', mash, function() {
return Window.focusedWindow().toBottomRight();
});
key_binding('[', 'Left Major', mash, function() {
return Window.focusedWindow().pushLeft();
});
key_binding(']', 'Right Minor', mash, function() {
return Window.focusedWindow().pushRight();
});
key_binding('space', 'Maximize Window', mash, function() {
return Window.focusedWindow().toFullScreen();
});
key_binding('W', 'Tile all windows for this app', mash, function() {
return Window.focusedWindow().tileWindowsForThisApp();
});
key_binding('U', 'Tile all windows for this app', mash, function() {
return Window.focusedWindow().fillToScreenHeight();
});
ITERM = "iTerm2";
VIM = "MacVim";
EMACS = "Emacs";
TERMINAL = "iTerm2";
FINDER = "Finder";
// key_binding('E', 'Launch Emacs', mash, function() {
// return App.focusOrStart(EMACS);
// });
key_binding('A', 'Launch Atom', mash, function() {
return App.focusOrStart("Atom");
});
// key_binding('V', 'Launch Vim', mash, function() {
// return App.focusOrStart(VIM);
// });
key_binding('I', 'Launch iTerm', mash, function() {
return App.focusOrStart("iTerm");
});
// key_binding('C', 'Launch Chrome', mash, function() {
// return App.focusOrStart(CHROME);
// });
key_binding('F', 'Launch Finder', mash, function() {
return App.focusOrStart(FINDER);
});
key_binding('P', 'Launch 1Password', mash, function() {
return App.focusOrStart("1Password");
});
key_binding('S', 'Launch Spotify', mash, function() {
return App.focusOrStart("Spotify");
});
// key_binding('N', 'To Next Screen', mash, function() {
// return moveWindowToNextScreen();
// });
//
// key_binding('P', 'To Previous Screen', mash, function() {
// return moveWindowToPreviousScreen();
// });
//
// key_binding('=', 'Increase Grid Columns', mash, function() {
// return changeGridWidth(+1);
// });
//
// key_binding('-', 'Reduce Grid Columns', mash, function() {
// return changeGridWidth(-1);
// });
//
// key_binding('[', 'Increase Grid Rows', mash, function() {
// return changeGridHeight(+1);
// });
//
// key_binding(']', 'Reduce Grid Rows', mash, function() {
// return changeGridHeight(-1);
// });
//
// key_binding(';', 'Snap focused to grid', mash, function() {
// return Window.focusedWindow().snapToGrid();
// });
//
// key_binding("'", 'Snap all to grid', mash, function() {
// return visible().map(function(win) {
// return win.snapToGrid();
// });
// });
//
// key_binding('H', 'Move Grid Left', mash, function() {
// return windowLeftOneColumn();
// });
//
// key_binding('J', 'Move Grid Down', mash, function() {
// return windowDownOneRow();
// });
//
// key_binding('K', 'Move Grid Up', mash, function() {
// return windowUpOneRow();
// });
//
// key_binding('L', 'Move Grid Right', mash, function() {
// return windowRightOneColumn();
// });
//
// key_binding('U', 'Window Full Height', mash, function() {
// return windowToFullHeight();
// });
//
// key_binding('I', 'Shrink by One Column', mash, function() {
// return windowShrinkOneGridColumn();
// });
//
// key_binding('O', 'Grow by One Column', mash, function() {
// return windowGrowOneGridColumn();
// });
//
// key_binding(',', 'Shrink by One Row', mash, function() {
// return windowShrinkOneGridRow();
// });
//
// key_binding('.', 'Grow by One Row', mash, function() {
// return windowGrowOneGridRow();
// });
Phoenix.notify("Loaded");
}).call(this);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment