/*global nativeRequire nwDispatcher windowManager*/ define(function(require, exports, module) { main.consumes = [ "c9", "Plugin", "menus", "settings", "ui", "upload", "commands", "dialog.question", "layout", "dialog.error", "util", "MenuItem", ]; main.provides = ["window.frame"]; return main; function main(options, imports, register) { var c9 = imports.c9; var ui = imports.ui; var menus = imports.menus; var Plugin = imports.Plugin; var settings = imports.settings; var commands = imports.commands; var util = imports.util; var layout = imports.layout; var question = imports["dialog.question"]; var error = imports["dialog.error"]; // Some require magic to get nw.gui var nw = nativeRequire("nw.gui"); // Ref to window var win = nw.Window.get(); var Menu = nw.Menu; var MenuItem = nw.MenuItem; var Tray = nw.Tray; var tray, nativeTitle, title, titlebar; /***** Initialization *****/ var plugin = new Plugin("Ajax.org", main.consumes); // var emit = plugin.getEmitter(); var loaded = false; function load() { if (loaded) return false; loaded = true; // Load native title setNativeTitle(); // When the UI is loaded, show the window c9.once("ready", function() { // Check Window Location validateWindowGeometry(); }, plugin); win.on("focusWindow", focusWindow); // Menu Items menus.addItemByPath("Cloud9/~", new ui.divider(), 2000000, plugin); menus.addItemByPath("Cloud9/Quit Cloud9", new ui.item({ selector: "closeAllWindowsQuit:", command: "exit" }), 2000100, plugin); menus.addItemByPath("Window/Developer Tools", new ui.item({ onclick: function() { win.showDevTools(); } }), 2000000, plugin); menus.addItemByPath("View/~", new ui.divider(), 800, plugin); var itemFullscreen = new ui.item({ isAvailable: function() { itemFullscreen.setAttribute("caption", win.isFullscreen ? "Leave Full Screen" : "Enter Full Screen"); return true; }, command: "toggleFullscreen" }); menus.addItemByPath("View/Enter Full Screen", itemFullscreen, 900, plugin); commands.addCommand({ name: "exit", bindKey: { mac: "Command-Q", win: "" }, exec: function() { windowManager.quit(); } }, plugin); commands.addCommand({ name: "closeWindow", bindKey: { mac: "", win: "Alt-F4" }, exec: function() { win.emit("close", "quit"); } }, plugin); commands.addCommand({ name: "fallback", bindKey: { mac: "Command-W", win: "Ctrl-F4" }, isAvailable: function() { return true; }, exec: function() { // Do nothing } }, plugin); commands.addCommand({ name: "toggleFullscreen", exec: function() { setTimeout(function() { win.isFullscreen ? win.leaveFullscreen() : win.enterFullscreen(); }, 100); } }, plugin); // Deal with closing win.on("askForQuit", function(quit) { var acceptQuit = quit ? windowManager.quitAll : saveAndQuit; // Fetch quit message, if any var message = window.onbeforeunload && window.onbeforeunload(); if (message) { question.show("Quit Cloud9?", "Are you sure you want to " + (quit ? "exit Cloud9?" : "close this window"), "Cloud9 will preserve your entire state. " + "Even unsaved files or changes will still " + "be available the next time you start cloud9.", function() { // yes settings.set("user/general/@confirmexit", !question.dontAsk); acceptQuit(); }, function() { // no settings.set("user/general/@confirmexit", !question.dontAsk); if (quit) windowManager.unquit(); }, { showDontAsk: true, yes: "Quit", no: "Cancel", }); // make sure nothing can cover this dialog question.once("show", function() { question.aml.setProperty("zindex", 30000000); }); focusWindow(); } else { acceptQuit(); } }); win.on("saveAndQuit", saveAndQuit); win.on("close", function(quit) { win.emit("askForQuit", quit); }); // saving can be slow for remote workspaces // so we hide window, Save All State and then quit function saveAndQuit() { win.hide(); // Prepare cloud9 for quitting c9.beforequit(); // Notify plugins that we're quitting c9.quit(); // Unregister the window windowManager.onClose(window.win.options.id); win.close(true); } // Settings settings.on("read", function() { settings.setDefaults("user/local", [ ["tray", "false"] ]); if (settings.getBool("user/local/@tray")) toggleTray(true); }, plugin); settings.on("user/local", function() { if (Boolean(tray) !== settings.getBool("user/local/@tray")) toggleTray(!tray); if (nativeTitle !== settings.getBool("user/local/@nativeTitle")) switchNativeTitle(!nativeTitle); }, plugin); // Preferences // prefs.add({ // "General" : { // position: 100, // "General" : { // "Show Tray Icon" : { // type: "checkbox", // path: "user/local/@tray", // position: 300 // } // // "Use Native Title Bar (requires restart)" : { // // type : "checkbox", // // path : "user/local/@nativeTitle", // // position : 300 // // } // } // } // }, plugin); // Window win.on("minimize", function() { win.isMinimized = true; settings.set("state/local/window/@minimized", true); }); win.on("restore", function() { win.isMinimized = false; settings.set("state/local/window/@minimized", false); }); win.on("maximize", function() { win.isMaximized = true; settings.set("state/local/window/@maximized", true); }); win.on("unmaximize", function() { win.isMaximized = false; settings.set("state/local/window/@maximized", false); }); var handler = storeWindowSettings.bind(null, false); win.on("move", handler); win.on("resize", handler); win.on("enter-fullscreen", handler); win.on("leave-fullscreen", handler); } /***** Methods *****/ var timer; function storeWindowSettings(force) { if (!force) { clearTimeout(timer); timer = setTimeout(storeWindowSettings.bind(null, true), 1000); return; } settings.set("state/local/window/@fullscreen", win.isFullscreen); win.emit("savePosition"); if (win.isFullscreen || win.isMaximized || win.isMinimized) return; settings.set("state/local/window/@position", win.x + ":" + win.y); settings.set("state/local/window/@size", win.width + ":" + win.height); } function toggleTray(to) { if (to) { // Create a tray icon tray = new Tray({ icon: 'favicon.ico' }); // Give it a menu var menu = new Menu(); menu.append(new MenuItem({ label: 'Visit c9.io', click: function() { window.open("http://c9.io"); } })); menu.append(new MenuItem({ label: 'Show Developer Tools', click: function() { win.showDevTools(); } })); tray.menu = menu; } else { // Remove the tray tray.remove(); tray = null; } } function switchNativeTitle(to) { } function setNativeTitle() { ui.insertCss(require("text!./local.less"), options.staticPrefix, plugin); var platform = process.platform; // c9.platform is remote os platform so we use process instead var titleHeight = platform == "win32" ? 27 : 23; var isMaximized = settings.get("state/local/window/@maximized"); error.top = titleHeight + 1; var div = document.body.appendChild(document.createElement("div")); div.className = "window-border"; // Move elements down to make room for the title bar layout.getElement("root").setAttribute("anchors", titleHeight + " 0 0 0"); document.querySelector(".c9-mbar-round").style.display = "none"; document.querySelector(".c9-mbar-logo").style.paddingTop = "0"; document.querySelector(".c9-menu-bar .c9-mbar-cont").style.paddingRight = "16px"; ui.setStyleRule(".right .panelsbar", "top", "-1px"); ui.setStyleRule(".right .panelsbar", "position", "absolute"); var logobar = layout.getElement("logobar"); if (!menus.minimized) logobar.setHeight(27); logobar.$ext.style.maxHeight = "27px"; titlebar = document.body.appendChild(document.createElement("div")); titlebar.className = "window-titlebar focus " + platform + (isMaximized ? " maximized" : ""); // Caption title = titlebar.appendChild(document.createElement("div")); title.className = "caption"; // Maximize var fullscreenbtn = titlebar.appendChild(document.createElement("div")); fullscreenbtn.className = "fullscreen"; fullscreenbtn.addEventListener("click", function() { win.enterFullscreen(); }); // Buttons var closebtn = titlebar.appendChild(document.createElement("div")); closebtn.className = "closebtn"; closebtn.addEventListener("click", function() { win.close(); }); var minbtn = titlebar.appendChild(document.createElement("div")); minbtn.className = "minbtn"; minbtn.addEventListener("click", function() { win.minimize(); }); var maxbtn = titlebar.appendChild(document.createElement("div")); maxbtn.className = "maxbtn"; maxbtn.addEventListener("click", function() { isMaximized && !apf.isMac ? win.unmaximize() : win.maximize(); }); win.on("blur", function() { titlebar.className = titlebar.className.replace(/ focus/g, ""); }); win.on("focus", function() { titlebar.className += " focus"; }); win.on("maximize", function() { titlebar.className += " maximized"; isMaximized = true; }); win.on("unmaximize", function() { titlebar.className = titlebar.className.replace(/ maximized/g, ""); isMaximized = false; }); var timer; var lastScreen = util.extend({}, screen); win.on("move", function(x, y) { clearTimeout(timer); timer = setTimeout(checkScreen, 500); }); // Temporary Hack - need resolution event setInterval(checkScreen, 2000); function checkScreen() { var s = lastScreen; lastScreen = util.extend({}, screen); if (!util.isEqual(s, lastScreen)) validateWindowGeometry(true); } win.on("leave-fullscreen", function() { layout.getElement("root").setAttribute("anchors", titleHeight + " 0 0 0"); titlebar.style.display = "block"; document.body.classList.remove("fullscreen"); }); var enterFullscreen = function() { layout.getElement("root").setAttribute("anchors", "0 0 0 0"); titlebar.style.display = "none"; document.body.classList.add("fullscreen"); }; win.on("enter-fullscreen", enterFullscreen); if (win.isFullscreen) enterFullscreen(); var menubar = document.querySelector(".c9-menu-bar"); menubar.style.backgroundPosition = "0 -4px"; menubar.style.webkitUserSelect = "none"; } function focusWindow() { // To support all platforms, we need to call both show and focus win.show(); win.focus(); } function validateWindowGeometry(fitInScreen) { if (settings.get("state/local/window/@maximized")) return; // Check if Window Position is In view var changedSize; var changedPos; var width = Math.max(400, win.width); var height = Math.max(300, win.height); if (width > screen.availWidth) { width = screen.availWidth; changedSize = true; } if (height > screen.availHeight) { height = screen.availHeight; changedSize = true; } var left = win.x; var top = win.y; var minLeft = screen.width - screen.availWidth; // Guestimate if (left < minLeft) { left = screen.availLeft; changedPos = true; } else if (left > screen.availWidth + screen.availLeft) { left = screen.availWidth + screen.availLeft - 100; changedPos = true; } if (top < screen.availTop) { top = screen.availTop; changedPos = true; } else if (top > screen.availHeight + screen.availTop) { top = screen.availHeight + screen.availTop - 100; changedPos = true; } else if (fitInScreen && height + top > screen.availTop + screen.availHeight) { top = screen.availTop; height = screen.availHeight; changedPos = true; changedSize = true; } if (changedPos) win.moveTo(left, top); if (changedSize) win.resizeTo(width, height); } function setTitle(str) { if (title) title.textContent = str; } /***** Lifecycle *****/ plugin.on("load", function() { load(); }); plugin.on("enable", function() { }); plugin.on("disable", function() { }); plugin.on("unload", function() { toggleTray(false); loaded = false; }); /***** Register and define API *****/ /** * Draws the file tree * @event afterfilesave Fires after a file is saved * @param {Object} e * node {XMLNode} description * oldpath {String} description **/ plugin.freezePublicAPI({ /** * */ focusWindow: focusWindow, setTitle: setTitle }); register(null, { "window.frame": plugin }); } });