sbShutdownService.js
Go to the documentation of this file.
1 /*
2 //
3 // BEGIN SONGBIRD GPL
4 //
5 // This file is part of the Songbird web player.
6 //
7 // Copyright(c) 2005-2009 POTI, Inc.
8 // http://songbirdnest.com
9 //
10 // This file may be licensed under the terms of of the
11 // GNU General Public License Version 2 (the "GPL").
12 //
13 // Software distributed under the License is distributed
14 // on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either
15 // express or implied. See the GPL for the specific language
16 // governing rights and limitations.
17 //
18 // You should have received a copy of the GPL along with this
19 // program. If not, go to http://www.gnu.org/licenses/gpl.html
20 // or write to the Free Software Foundation, Inc.,
21 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
22 //
23 // END SONGBIRD GPL
24 //
25 */
26 
27 const Cc = Components.classes;
28 const Ci = Components.interfaces;
29 const Cu = Components.utils;
30 const Cr = Components.results;
31 
32 const SB_SHUTDOWNSERVICE_CLASSNAME = "sbShutdownService";
33 const SB_SHUTDOWNSERVICE_DESC = "Songbird Shutdown Service";
34 const SB_SHUTDOWNSERVICE_CONTRACTID = "@songbirdnest.com/shutdown-service;1";
35 const SB_SHUTDOWNSERVICE_CID = "{594137ED-DB4A-4530-8635-2573C018B4FB}";
36 
37 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
38 Cu.import("resource://app/jsmodules/WindowUtils.jsm");
39 Cu.import("resource://app/jsmodules/StringUtils.jsm");
40 
41 //------------------------------------------------------------------------------
42 // Songbird Shutdown Job Service
43 
44 var gTestListeners = [];
45 
47 {
48  var observerService = Cc["@mozilla.org/observer-service;1"]
49  .getService(Ci.nsIObserverService);
50  observerService.addObserver(this, "quit-application-requested", false);
51 }
52 
54 {
55  _mTasks: [],
56  _mTaskIndex: 0,
57  _mTotal: 0,
58  _mProgress: 0,
59  _mListeners: [],
60  _mShouldShutdown: true,
61  _mShutdownFlags: Ci.nsIAppStartup.eAttemptQuit,
62  _mStatus: Ci.sbIJobProgress.STATUS_RUNNING,
63 
64  // nsIObserver
65  observe: function(aSubject, aTopic, aData) {
66  if (aTopic == "quit-application-requested") {
67 
68  var observerService = Cc["@mozilla.org/observer-service;1"]
69  .getService(Ci.nsIObserverService);
70  // Only hault shutdown if there are tasks to be processed.
71  var listenerEnum =
72  observerService.enumerateObservers("songbird-shutdown");
73  while (listenerEnum.hasMoreElements()) {
74  try {
75  var curTask =
76  listenerEnum.getNext().QueryInterface(Ci.sbIShutdownJob);
77 
78  if (curTask.needsToRunTask) {
79  this._mTasks.push(curTask);
80  }
81  }
82  catch (e) {
83  Cu.reportError(e);
84  }
85  }
86 
87  if (this._mTasks.length > 0) {
88  // There are tasks to run, hault shutdown for now.
89  var stopShutdown = aSubject.QueryInterface(Ci.nsISupportsPRBool);
90  stopShutdown.data = true;
91 
92  // If the |aData| flag indicates that this is going to be a restart,
93  // append the restart flag for when we do shutdown.
94  if (aData == "restart") {
95  this._mShutdownFlags |= Ci.nsIAppStartup.eRestart;
96  }
97 
98  // If this notice was made by the unit test, don't shutdown once
99  // all the tasks have been processed.
100  if (aData && aData == "is-unit-test") {
101  this._mShouldShutdown = false;
102  }
103 
104  this._startProcessingTasks();
105  }
106  }
107  },
108 
109  // sbIJobProgressListener
110  onJobProgress: function(aJobProgress) {
111  this._notifyListeners();
112 
113  switch (aJobProgress.status) {
114  case Ci.sbIJobProgress.STATUS_FAILED:
115  // If the job failed - report the errors and continue on to the next
116  // shutdown task.
117  Cu.reportError("sbShutdownJobService - shutdown job failed!");
118 
119  case Ci.sbIJobProgress.STATUS_SUCCEEDED:
120  // Clean up ourselves on the current task.
121  var curTask = this._mTasks[this._mTaskIndex];
122  curTask.removeJobProgressListener(this);
123 
124  // Update the cumulative progress count
125  this._mProgress += this._mTasks[this._mTaskIndex].total;
126 
127  // Process the next task.
128  this._mTaskIndex++;
129  this._processNextTask();
130  break;
131  }
132  },
133 
134  // sbIJobProgress
135  get status() {
136  return this._mStatus;
137  },
138 
139  get blocked() {
140  return false;
141  },
142 
143  get statusText() {
144  var statusText = this._mTasks[this._mTaskIndex].statusText;
145  var remainingTasks = (this._mTasks.length - this._mTaskIndex) -1;
146 
147  if (statusText == "") {
148  // If the shutdown task does not provide a string, use a generic one.
149  statusText = SBString("shutdownservice.defaultstatustext");
150  }
151 
152  if (remainingTasks == 0) {
153  return statusText;
154  }
155  else {
156  return SBFormattedString("shutdownservice.statustext",
157  [statusText, remainingTasks]);
158  }
159  },
160 
161  get titleText() {
162  return SBString("shutdownservice.statustitle");
163  },
164 
165  get progress() {
166  return this._mProgress + this._mTasks[this._mTaskIndex].progress;
167  },
168 
169  get total() {
170  return this._mTotal;
171  },
172 
173  get errorCount() {
174  return 0;
175  },
176 
177  getErrorMessages: function() {
178  // Don't report any error messages for now.
179  return null;
180  },
181 
182  addJobProgressListener: function(aJobListener) {
183  this._mListeners.push(aJobListener);
184  },
185 
186  removeJobProgressListener: function(aJobListener) {
187  var listenerIndex = this._mListeners.indexOf(aJobListener);
188  if (listenerIndex > -1) {
189  this._mListeners.splice(listenerIndex, 1);
190  }
191  },
192 
193  // sbIJobCancelable
194  get canCancel() {
195  return true;
196  },
197 
198  cancel: function() {
199  this._doShutdown();
200  },
201 
202  _startProcessingTasks: function() {
203  // Calculate the total metric for the job progress interface.
204  for (var i = 0; i < this._mTasks.length; i++) {
205  this._mTotal += this._mTasks[i].total;
206  }
207 
208  // The only open window during the shutdown service should be the Songbird
209  // window. First, close down the main Songbird window.
210  var winMediator = Cc["@mozilla.org/appshell/window-mediator;1"]
211  .getService(Ci.nsIWindowMediator);
212  var songbirdWin = winMediator.getMostRecentWindow("Songbird:Main");
213  if (songbirdWin) {
214  songbirdWin.close();
215  }
216 
217  var args = Cc["@mozilla.org/array;1"].createInstance(Ci.nsIMutableArray);
218  args.appendElement(this, false);
219 
220  // Open the progress dialog using the hidden window since the shutdown
221  // progress dialog should be the only open Songbird window.
222  var appShellService = Cc["@mozilla.org/appshell/appShellService;1"]
223  .getService(Ci.nsIAppShellService);
224 
225  var parentWindow = appShellService.hiddenDOMWindow;
226  parentWindow.openDialog("chrome://songbird/content/xul/jobProgress.xul",
227  "job_progress_dialog",
228  "chrome,centerscreen",
229  args);
230 
231  this._processNextTask();
232  },
233 
234  _processNextTask: function() {
235  if (this._mTaskIndex < this._mTasks.length) {
236  this._notifyListeners();
237 
238  var nextTask = this._mTasks[this._mTaskIndex];
239  try {
240  nextTask.addJobProgressListener(this);
241  nextTask.startTask(this);
242  }
243  catch (e) {
244  Cu.reportError("Error processing shutdown task!");
245  this._mTaskIndex++;
246  this._processNextTask();
247  }
248  }
249  else {
250  this._doShutdown();
251  }
252  },
253 
254  _doShutdown: function() {
255  // Sleep for 100ms to allow the dialog to draw the complete progressbar
256  // and not close the dialog with a large chunk of "unfinished" progress.
257  this._mTaskIndex--; // make sure to show the last task
258  this._notifyListeners();
259  this._sleep(100);
260 
261  // Notify the listener (this will close the progress dialog)
262  this._mStatus = Ci.sbIJobProgress.STATUS_SUCCEEDED;
263  this._notifyListeners();
264 
265  // drop the references to the tasks
266  this._mTasks.splice(0);
267 
268  // Attempt to shutdown again.
269  if (this._mShouldShutdown) {
270  var appStartup = Cc["@mozilla.org/toolkit/app-startup;1"]
271  .getService(Ci.nsIAppStartup);
272  appStartup.quit(this._mShutdownFlags);
273  }
274  },
275 
276  _notifyListeners: function() {
277  // Clone the listeners, otherwise removing one in the middle can
278  // cause issues.
279  var listeners = [].concat(this._mListeners);
280  for (var i = 0; i < listeners.length; i++) {
281  try {
282  listeners[i].onJobProgress(this);
283  }
284  catch (e) {
285  Cu.reportError(e);
286  }
287  }
288  },
289 
290  _sleep: function(ms) {
291  var threadManager = Cc["@mozilla.org/thread-manager;1"]
292  .getService(Ci.nsIThreadManager);
293  var mainThread = threadManager.mainThread;
294  var then = new Date().getTime(), now = then;
295  for (; now - then < ms; now = new Date().getTime()) {
296  mainThread.processNextEvent(true);
297  }
298  },
299 
300  // XCOM Goo
303  classID: Components.ID(SB_SHUTDOWNSERVICE_CID),
305  QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver,
306  Ci.sbIJobProgressListener,
307  Ci.sbIJobProgress,
308  Ci.sbIJobCancelable])
309 };
310 
311 //------------------------------------------------------------------------------
312 // XPCOM Registration
313 
314 function NSGetModule(compMgr, fileSpec)
315 {
316  return XPCOMUtils.generateModule([sbShutdownJobService],
317  function(aCompMgr, aFileSpec, aLocation) {
318  XPCOMUtils.categoryManager.addCategoryEntry("app-startup",
320  "service," +
322  true,
323  true);
324  }
325  );
326 }
327 
var total
var args
Definition: alert.js:8
const SB_SHUTDOWNSERVICE_CONTRACTID
const Ci
static nsCOMPtr< nsIObserverService > observerService
Definition: UnityProxy.cpp:6
var gTestListeners
function SBFormattedString(aKey, aParams, aDefault, aStringBundle)
sbOSDControlService prototype className
function NSGetModule(compMgr, fileSpec)
sbDeviceFirmwareAutoCheckForUpdate prototype contractID
function sbShutdownJobService()
sbOSDControlService prototype QueryInterface
sbDeviceFirmwareAutoCheckForUpdate prototype classDescription
function SBString(aKey, aDefault, aStringBundle)
Definition: StringUtils.jsm:93
const Cr
const SB_SHUTDOWNSERVICE_DESC
const SB_SHUTDOWNSERVICE_CID
return null
Definition: FeedWriter.js:1143
const Cu
const SB_SHUTDOWNSERVICE_CLASSNAME
sbDeviceFirmwareAutoCheckForUpdate prototype classID
const Cc
function now()
_getSelectedPageStyle s i
_updateTextAndScrollDataForFrame aData
sbDeviceFirmwareAutoCheckForUpdate prototype observe