1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/browser/devtools/scratchpad/scratchpad-manager.jsm Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,174 @@ 1.4 +/* vim:set ts=2 sw=2 sts=2 et tw=80: 1.5 + * This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +"use strict"; 1.10 + 1.11 +this.EXPORTED_SYMBOLS = ["ScratchpadManager"]; 1.12 + 1.13 +const Cc = Components.classes; 1.14 +const Ci = Components.interfaces; 1.15 +const Cu = Components.utils; 1.16 + 1.17 +const SCRATCHPAD_WINDOW_URL = "chrome://browser/content/devtools/scratchpad.xul"; 1.18 +const SCRATCHPAD_WINDOW_FEATURES = "chrome,titlebar,toolbar,centerscreen,resizable,dialog=no"; 1.19 + 1.20 +Cu.import("resource://gre/modules/Services.jsm"); 1.21 + 1.22 +/** 1.23 + * The ScratchpadManager object opens new Scratchpad windows and manages the state 1.24 + * of open scratchpads for session restore. There's only one ScratchpadManager in 1.25 + * the life of the browser. 1.26 + */ 1.27 +this.ScratchpadManager = { 1.28 + 1.29 + _nextUid: 1, 1.30 + _scratchpads: [], 1.31 + 1.32 + /** 1.33 + * Get the saved states of open scratchpad windows. Called by 1.34 + * session restore. 1.35 + * 1.36 + * @return array 1.37 + * The array of scratchpad states. 1.38 + */ 1.39 + getSessionState: function SPM_getSessionState() 1.40 + { 1.41 + return this._scratchpads; 1.42 + }, 1.43 + 1.44 + /** 1.45 + * Restore scratchpad windows from the scratchpad session store file. 1.46 + * Called by session restore. 1.47 + * 1.48 + * @param function aSession 1.49 + * The session object with scratchpad states. 1.50 + * 1.51 + * @return array 1.52 + * The restored scratchpad windows. 1.53 + */ 1.54 + restoreSession: function SPM_restoreSession(aSession) 1.55 + { 1.56 + if (!Array.isArray(aSession)) { 1.57 + return []; 1.58 + } 1.59 + 1.60 + let wins = []; 1.61 + aSession.forEach(function(state) { 1.62 + let win = this.openScratchpad(state); 1.63 + wins.push(win); 1.64 + }, this); 1.65 + 1.66 + return wins; 1.67 + }, 1.68 + 1.69 + /** 1.70 + * Iterate through open scratchpad windows and save their states. 1.71 + */ 1.72 + saveOpenWindows: function SPM_saveOpenWindows() { 1.73 + this._scratchpads = []; 1.74 + 1.75 + function clone(src) { 1.76 + let dest = {}; 1.77 + 1.78 + for (let key in src) { 1.79 + if (src.hasOwnProperty(key)) { 1.80 + dest[key] = src[key]; 1.81 + } 1.82 + } 1.83 + 1.84 + return dest; 1.85 + } 1.86 + 1.87 + // We need to clone objects we get from Scratchpad instances 1.88 + // because such (cross-window) objects have a property 'parent' 1.89 + // that holds on to a ChromeWindow instance. This means that 1.90 + // such objects are not primitive-values-only anymore so they 1.91 + // can leak. 1.92 + 1.93 + let enumerator = Services.wm.getEnumerator("devtools:scratchpad"); 1.94 + while (enumerator.hasMoreElements()) { 1.95 + let win = enumerator.getNext(); 1.96 + if (!win.closed && win.Scratchpad.initialized) { 1.97 + this._scratchpads.push(clone(win.Scratchpad.getState())); 1.98 + } 1.99 + } 1.100 + }, 1.101 + 1.102 + /** 1.103 + * Open a new scratchpad window with an optional initial state. 1.104 + * 1.105 + * @param object aState 1.106 + * Optional. The initial state of the scratchpad, an object 1.107 + * with properties filename, text, and executionContext. 1.108 + * 1.109 + * @return nsIDomWindow 1.110 + * The opened scratchpad window. 1.111 + */ 1.112 + openScratchpad: function SPM_openScratchpad(aState) 1.113 + { 1.114 + let params = Cc["@mozilla.org/embedcomp/dialogparam;1"] 1.115 + .createInstance(Ci.nsIDialogParamBlock); 1.116 + 1.117 + params.SetNumberStrings(2); 1.118 + params.SetString(0, this.createUid()); 1.119 + 1.120 + if (aState) { 1.121 + if (typeof aState != 'object') { 1.122 + return; 1.123 + } 1.124 + 1.125 + params.SetString(1, JSON.stringify(aState)); 1.126 + } 1.127 + 1.128 + let win = Services.ww.openWindow(null, SCRATCHPAD_WINDOW_URL, "_blank", 1.129 + SCRATCHPAD_WINDOW_FEATURES, params); 1.130 + 1.131 + // Only add the shutdown observer if we've opened a scratchpad window. 1.132 + ShutdownObserver.init(); 1.133 + 1.134 + return win; 1.135 + }, 1.136 + 1.137 + /** 1.138 + * Create a unique ID for a new Scratchpad. 1.139 + */ 1.140 + createUid: function SPM_createUid() 1.141 + { 1.142 + return JSON.stringify(this._nextUid++); 1.143 + } 1.144 +}; 1.145 + 1.146 + 1.147 +/** 1.148 + * The ShutdownObserver listens for app shutdown and saves the current state 1.149 + * of the scratchpads for session restore. 1.150 + */ 1.151 +var ShutdownObserver = { 1.152 + _initialized: false, 1.153 + 1.154 + init: function SDO_init() 1.155 + { 1.156 + if (this._initialized) { 1.157 + return; 1.158 + } 1.159 + 1.160 + Services.obs.addObserver(this, "quit-application-granted", false); 1.161 + 1.162 + this._initialized = true; 1.163 + }, 1.164 + 1.165 + observe: function SDO_observe(aMessage, aTopic, aData) 1.166 + { 1.167 + if (aTopic == "quit-application-granted") { 1.168 + ScratchpadManager.saveOpenWindows(); 1.169 + this.uninit(); 1.170 + } 1.171 + }, 1.172 + 1.173 + uninit: function SDO_uninit() 1.174 + { 1.175 + Services.obs.removeObserver(this, "quit-application-granted"); 1.176 + } 1.177 +};