browser/modules/WindowsJumpLists.jsm

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/browser/modules/WindowsJumpLists.jsm	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,581 @@
     1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     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 +Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
    1.10 +Components.utils.import("resource://gre/modules/Services.jsm");
    1.11 +
    1.12 +/**
    1.13 + * Constants
    1.14 + */
    1.15 +
    1.16 +const Cc = Components.classes;
    1.17 +const Ci = Components.interfaces;
    1.18 +
    1.19 +// Stop updating jumplists after some idle time.
    1.20 +const IDLE_TIMEOUT_SECONDS = 5 * 60;
    1.21 +
    1.22 +// Prefs
    1.23 +const PREF_TASKBAR_BRANCH    = "browser.taskbar.lists.";
    1.24 +const PREF_TASKBAR_ENABLED   = "enabled";
    1.25 +const PREF_TASKBAR_ITEMCOUNT = "maxListItemCount";
    1.26 +const PREF_TASKBAR_FREQUENT  = "frequent.enabled";
    1.27 +const PREF_TASKBAR_RECENT    = "recent.enabled";
    1.28 +const PREF_TASKBAR_TASKS     = "tasks.enabled";
    1.29 +const PREF_TASKBAR_REFRESH   = "refreshInSeconds";
    1.30 +
    1.31 +// Hash keys for pendingStatements.
    1.32 +const LIST_TYPE = {
    1.33 +  FREQUENT: 0
    1.34 +, RECENT: 1
    1.35 +}
    1.36 +
    1.37 +/**
    1.38 + * Exports
    1.39 + */
    1.40 +
    1.41 +this.EXPORTED_SYMBOLS = [
    1.42 +  "WinTaskbarJumpList",
    1.43 +];
    1.44 +
    1.45 +/**
    1.46 + * Smart getters
    1.47 + */
    1.48 +
    1.49 +XPCOMUtils.defineLazyGetter(this, "_prefs", function() {
    1.50 +  return Services.prefs.getBranch(PREF_TASKBAR_BRANCH);
    1.51 +});
    1.52 +
    1.53 +XPCOMUtils.defineLazyGetter(this, "_stringBundle", function() {
    1.54 +  return Services.strings
    1.55 +                 .createBundle("chrome://browser/locale/taskbar.properties");
    1.56 +});
    1.57 +
    1.58 +XPCOMUtils.defineLazyGetter(this, "PlacesUtils", function() {
    1.59 +  Components.utils.import("resource://gre/modules/PlacesUtils.jsm");
    1.60 +  return PlacesUtils;
    1.61 +});
    1.62 +
    1.63 +XPCOMUtils.defineLazyGetter(this, "NetUtil", function() {
    1.64 +  Components.utils.import("resource://gre/modules/NetUtil.jsm");
    1.65 +  return NetUtil;
    1.66 +});
    1.67 +
    1.68 +XPCOMUtils.defineLazyServiceGetter(this, "_idle",
    1.69 +                                   "@mozilla.org/widget/idleservice;1",
    1.70 +                                   "nsIIdleService");
    1.71 +
    1.72 +XPCOMUtils.defineLazyServiceGetter(this, "_taskbarService",
    1.73 +                                   "@mozilla.org/windows-taskbar;1",
    1.74 +                                   "nsIWinTaskbar");
    1.75 +
    1.76 +XPCOMUtils.defineLazyServiceGetter(this, "_winShellService",
    1.77 +                                   "@mozilla.org/browser/shell-service;1",
    1.78 +                                   "nsIWindowsShellService");
    1.79 +
    1.80 +XPCOMUtils.defineLazyModuleGetter(this, "PrivateBrowsingUtils",
    1.81 +  "resource://gre/modules/PrivateBrowsingUtils.jsm");
    1.82 +
    1.83 +/**
    1.84 + * Global functions
    1.85 + */
    1.86 +
    1.87 +function _getString(name) {
    1.88 +  return _stringBundle.GetStringFromName(name);
    1.89 +}
    1.90 +
    1.91 +/////////////////////////////////////////////////////////////////////////////
    1.92 +// Task list configuration data object.
    1.93 +
    1.94 +var tasksCfg = [
    1.95 +  /**
    1.96 +   * Task configuration options: title, description, args, iconIndex, open, close.
    1.97 +   *
    1.98 +   * title       - Task title displayed in the list. (strings in the table are temp fillers.)
    1.99 +   * description - Tooltip description on the list item.
   1.100 +   * args        - Command line args to invoke the task.
   1.101 +   * iconIndex   - Optional win icon index into the main application for the
   1.102 +   *               list item.
   1.103 +   * open        - Boolean indicates if the command should be visible after the browser opens.
   1.104 +   * close       - Boolean indicates if the command should be visible after the browser closes.
   1.105 +   */
   1.106 +  // Open new tab
   1.107 +  {
   1.108 +    get title()       _getString("taskbar.tasks.newTab.label"),
   1.109 +    get description() _getString("taskbar.tasks.newTab.description"),
   1.110 +    args:             "-new-tab about:blank",
   1.111 +    iconIndex:        3, // New window icon
   1.112 +    open:             true,
   1.113 +    close:            true, // The jump list already has an app launch icon, but
   1.114 +                            // we don't always update the list on shutdown.
   1.115 +                            // Thus true for consistency.
   1.116 +  },
   1.117 +
   1.118 +  // Open new window
   1.119 +  {
   1.120 +    get title()       _getString("taskbar.tasks.newWindow.label"),
   1.121 +    get description() _getString("taskbar.tasks.newWindow.description"),
   1.122 +    args:             "-browser",
   1.123 +    iconIndex:        2, // New tab icon
   1.124 +    open:             true,
   1.125 +    close:            true, // No point, but we don't always update the list on
   1.126 +                            // shutdown. Thus true for consistency.
   1.127 +  },
   1.128 +
   1.129 +  // Open new private window
   1.130 +  {
   1.131 +    get title()       _getString("taskbar.tasks.newPrivateWindow.label"),
   1.132 +    get description() _getString("taskbar.tasks.newPrivateWindow.description"),
   1.133 +    args:             "-private-window",
   1.134 +    iconIndex:        4, // Private browsing mode icon
   1.135 +    open:             true,
   1.136 +    close:            true, // No point, but we don't always update the list on
   1.137 +                            // shutdown. Thus true for consistency.
   1.138 +  },
   1.139 +];
   1.140 +
   1.141 +/////////////////////////////////////////////////////////////////////////////
   1.142 +// Implementation
   1.143 +
   1.144 +this.WinTaskbarJumpList =
   1.145 +{
   1.146 +  _builder: null,
   1.147 +  _tasks: null,
   1.148 +  _shuttingDown: false,
   1.149 +
   1.150 +  /**
   1.151 +   * Startup, shutdown, and update
   1.152 +   */ 
   1.153 +
   1.154 +  startup: function WTBJL_startup() {
   1.155 +    // exit if this isn't win7 or higher.
   1.156 +    if (!this._initTaskbar())
   1.157 +      return;
   1.158 +
   1.159 +    // Win shell shortcut maintenance. If we've gone through an update,
   1.160 +    // this will update any pinned taskbar shortcuts. Not specific to
   1.161 +    // jump lists, but this was a convienent place to call it. 
   1.162 +    try {
   1.163 +      // dev builds may not have helper.exe, ignore failures.
   1.164 +      this._shortcutMaintenance();
   1.165 +    } catch (ex) {
   1.166 +    }
   1.167 +
   1.168 +    // Store our task list config data
   1.169 +    this._tasks = tasksCfg;
   1.170 +
   1.171 +    // retrieve taskbar related prefs.
   1.172 +    this._refreshPrefs();
   1.173 +
   1.174 +    // observer for private browsing and our prefs branch
   1.175 +    this._initObs();
   1.176 +
   1.177 +    // jump list refresh timer
   1.178 +    this._updateTimer();
   1.179 +  },
   1.180 +
   1.181 +  update: function WTBJL_update() {
   1.182 +    // are we disabled via prefs? don't do anything!
   1.183 +    if (!this._enabled)
   1.184 +      return;
   1.185 +
   1.186 +    // do what we came here to do, update the taskbar jumplist
   1.187 +    this._buildList();
   1.188 +  },
   1.189 +
   1.190 +  _shutdown: function WTBJL__shutdown() {
   1.191 +    this._shuttingDown = true;
   1.192 +
   1.193 +    // Correctly handle a clear history on shutdown.  If there are no
   1.194 +    // entries be sure to empty all history lists.  Luckily Places caches
   1.195 +    // this value, so it's a pretty fast call.
   1.196 +    if (!PlacesUtils.history.hasHistoryEntries) {
   1.197 +      this.update();
   1.198 +    }
   1.199 +
   1.200 +    this._free();
   1.201 +  },
   1.202 +
   1.203 +  _shortcutMaintenance: function WTBJL__maintenace() {
   1.204 +    _winShellService.shortcutMaintenance();
   1.205 +  },
   1.206 +
   1.207 +  /**
   1.208 +   * List building
   1.209 +   *
   1.210 +   * @note Async builders must add their mozIStoragePendingStatement to
   1.211 +   *       _pendingStatements object, using a different LIST_TYPE entry for
   1.212 +   *       each statement. Once finished they must remove it and call
   1.213 +   *       commitBuild().  When there will be no more _pendingStatements,
   1.214 +   *       commitBuild() will commit for real.
   1.215 +   */
   1.216 +
   1.217 +  _pendingStatements: {},
   1.218 +  _hasPendingStatements: function WTBJL__hasPendingStatements() {
   1.219 +    return Object.keys(this._pendingStatements).length > 0;
   1.220 +  },
   1.221 +
   1.222 +  _buildList: function WTBJL__buildList() {
   1.223 +    if (this._hasPendingStatements()) {
   1.224 +      // We were requested to update the list while another update was in
   1.225 +      // progress, this could happen at shutdown, idle or privatebrowsing.
   1.226 +      // Abort the current list building.
   1.227 +      for (let listType in this._pendingStatements) {
   1.228 +        this._pendingStatements[listType].cancel();
   1.229 +        delete this._pendingStatements[listType];
   1.230 +      }
   1.231 +      this._builder.abortListBuild();
   1.232 +    }
   1.233 +
   1.234 +    // anything to build?
   1.235 +    if (!this._showFrequent && !this._showRecent && !this._showTasks) {
   1.236 +      // don't leave the last list hanging on the taskbar.
   1.237 +      this._deleteActiveJumpList();
   1.238 +      return;
   1.239 +    }
   1.240 +
   1.241 +    if (!this._startBuild())
   1.242 +      return;
   1.243 +
   1.244 +    if (this._showTasks)
   1.245 +      this._buildTasks();
   1.246 +
   1.247 +    // Space for frequent items takes priority over recent.
   1.248 +    if (this._showFrequent)
   1.249 +      this._buildFrequent();
   1.250 +
   1.251 +    if (this._showRecent)
   1.252 +      this._buildRecent();
   1.253 +
   1.254 +    this._commitBuild();
   1.255 +  },
   1.256 +
   1.257 +  /**
   1.258 +   * Taskbar api wrappers
   1.259 +   */ 
   1.260 +
   1.261 +  _startBuild: function WTBJL__startBuild() {
   1.262 +    var removedItems = Cc["@mozilla.org/array;1"].
   1.263 +                       createInstance(Ci.nsIMutableArray);
   1.264 +    this._builder.abortListBuild();
   1.265 +    if (this._builder.initListBuild(removedItems)) { 
   1.266 +      // Prior to building, delete removed items from history.
   1.267 +      this._clearHistory(removedItems);
   1.268 +      return true;
   1.269 +    }
   1.270 +    return false;
   1.271 +  },
   1.272 +
   1.273 +  _commitBuild: function WTBJL__commitBuild() {
   1.274 +    if (!this._hasPendingStatements() && !this._builder.commitListBuild()) {
   1.275 +      this._builder.abortListBuild();
   1.276 +    }
   1.277 +  },
   1.278 +
   1.279 +  _buildTasks: function WTBJL__buildTasks() {
   1.280 +    var items = Cc["@mozilla.org/array;1"].
   1.281 +                createInstance(Ci.nsIMutableArray);
   1.282 +    this._tasks.forEach(function (task) {
   1.283 +      if ((this._shuttingDown && !task.close) || (!this._shuttingDown && !task.open))
   1.284 +        return;
   1.285 +      var item = this._getHandlerAppItem(task.title, task.description,
   1.286 +                                         task.args, task.iconIndex, null);
   1.287 +      items.appendElement(item, false);
   1.288 +    }, this);
   1.289 +    
   1.290 +    if (items.length > 0)
   1.291 +      this._builder.addListToBuild(this._builder.JUMPLIST_CATEGORY_TASKS, items);
   1.292 +  },
   1.293 +
   1.294 +  _buildCustom: function WTBJL__buildCustom(title, items) {
   1.295 +    if (items.length > 0)
   1.296 +      this._builder.addListToBuild(this._builder.JUMPLIST_CATEGORY_CUSTOMLIST, items, title);
   1.297 +  },
   1.298 +
   1.299 +  _buildFrequent: function WTBJL__buildFrequent() {
   1.300 +    // If history is empty, just bail out.
   1.301 +    if (!PlacesUtils.history.hasHistoryEntries) {
   1.302 +      return;
   1.303 +    }
   1.304 +
   1.305 +    // Windows supports default frequent and recent lists,
   1.306 +    // but those depend on internal windows visit tracking
   1.307 +    // which we don't populate. So we build our own custom
   1.308 +    // frequent and recent lists using our nav history data.
   1.309 +
   1.310 +    var items = Cc["@mozilla.org/array;1"].
   1.311 +                createInstance(Ci.nsIMutableArray);
   1.312 +    // track frequent items so that we don't add them to
   1.313 +    // the recent list.
   1.314 +    this._frequentHashList = [];
   1.315 +
   1.316 +    this._pendingStatements[LIST_TYPE.FREQUENT] = this._getHistoryResults(
   1.317 +      Ci.nsINavHistoryQueryOptions.SORT_BY_VISITCOUNT_DESCENDING,
   1.318 +      this._maxItemCount,
   1.319 +      function (aResult) {
   1.320 +        if (!aResult) {
   1.321 +          delete this._pendingStatements[LIST_TYPE.FREQUENT];
   1.322 +          // The are no more results, build the list.
   1.323 +          this._buildCustom(_getString("taskbar.frequent.label"), items);
   1.324 +          this._commitBuild();
   1.325 +          return;
   1.326 +        }
   1.327 +
   1.328 +        let title = aResult.title || aResult.uri;
   1.329 +        let faviconPageUri = Services.io.newURI(aResult.uri, null, null);
   1.330 +        let shortcut = this._getHandlerAppItem(title, title, aResult.uri, 1, 
   1.331 +                                               faviconPageUri);
   1.332 +        items.appendElement(shortcut, false);
   1.333 +        this._frequentHashList.push(aResult.uri);
   1.334 +      },
   1.335 +      this
   1.336 +    );
   1.337 +  },
   1.338 +
   1.339 +  _buildRecent: function WTBJL__buildRecent() {
   1.340 +    // If history is empty, just bail out.
   1.341 +    if (!PlacesUtils.history.hasHistoryEntries) {
   1.342 +      return;
   1.343 +    }
   1.344 +
   1.345 +    var items = Cc["@mozilla.org/array;1"].
   1.346 +                createInstance(Ci.nsIMutableArray);
   1.347 +    // Frequent items will be skipped, so we select a double amount of
   1.348 +    // entries and stop fetching results at _maxItemCount.
   1.349 +    var count = 0;
   1.350 +
   1.351 +    this._pendingStatements[LIST_TYPE.RECENT] = this._getHistoryResults(
   1.352 +      Ci.nsINavHistoryQueryOptions.SORT_BY_DATE_DESCENDING,
   1.353 +      this._maxItemCount * 2,
   1.354 +      function (aResult) {
   1.355 +        if (!aResult) {
   1.356 +          // The are no more results, build the list.
   1.357 +          this._buildCustom(_getString("taskbar.recent.label"), items);
   1.358 +          delete this._pendingStatements[LIST_TYPE.RECENT];
   1.359 +          this._commitBuild();
   1.360 +          return;
   1.361 +        }
   1.362 +
   1.363 +        if (count >= this._maxItemCount) {
   1.364 +          return;
   1.365 +        }
   1.366 +
   1.367 +        // Do not add items to recent that have already been added to frequent.
   1.368 +        if (this._frequentHashList &&
   1.369 +            this._frequentHashList.indexOf(aResult.uri) != -1) {
   1.370 +          return;
   1.371 +        }
   1.372 +
   1.373 +        let title = aResult.title || aResult.uri;
   1.374 +        let faviconPageUri = Services.io.newURI(aResult.uri, null, null);
   1.375 +        let shortcut = this._getHandlerAppItem(title, title, aResult.uri, 1,
   1.376 +                                               faviconPageUri);
   1.377 +        items.appendElement(shortcut, false);
   1.378 +        count++;
   1.379 +      },
   1.380 +      this
   1.381 +    );
   1.382 +  },
   1.383 +
   1.384 +  _deleteActiveJumpList: function WTBJL__deleteAJL() {
   1.385 +    this._builder.deleteActiveList();
   1.386 +  },
   1.387 +
   1.388 +  /**
   1.389 +   * Jump list item creation helpers
   1.390 +   */
   1.391 +
   1.392 +  _getHandlerAppItem: function WTBJL__getHandlerAppItem(name, description, 
   1.393 +                                                        args, iconIndex, 
   1.394 +                                                        faviconPageUri) {
   1.395 +    var file = Services.dirsvc.get("XREExeF", Ci.nsILocalFile);
   1.396 +
   1.397 +    var handlerApp = Cc["@mozilla.org/uriloader/local-handler-app;1"].
   1.398 +                     createInstance(Ci.nsILocalHandlerApp);
   1.399 +    handlerApp.executable = file;
   1.400 +    // handlers default to the leaf name if a name is not specified
   1.401 +    if (name && name.length != 0)
   1.402 +      handlerApp.name = name;
   1.403 +    handlerApp.detailedDescription = description;
   1.404 +    handlerApp.appendParameter(args);
   1.405 +
   1.406 +    var item = Cc["@mozilla.org/windows-jumplistshortcut;1"].
   1.407 +               createInstance(Ci.nsIJumpListShortcut);
   1.408 +    item.app = handlerApp;
   1.409 +    item.iconIndex = iconIndex;
   1.410 +    item.faviconPageUri = faviconPageUri;
   1.411 +    return item;
   1.412 +  },
   1.413 +
   1.414 +  _getSeparatorItem: function WTBJL__getSeparatorItem() {
   1.415 +    var item = Cc["@mozilla.org/windows-jumplistseparator;1"].
   1.416 +               createInstance(Ci.nsIJumpListSeparator);
   1.417 +    return item;
   1.418 +  },
   1.419 +
   1.420 +  /**
   1.421 +   * Nav history helpers
   1.422 +   */
   1.423 +
   1.424 +  _getHistoryResults:
   1.425 +  function WTBLJL__getHistoryResults(aSortingMode, aLimit, aCallback, aScope) {
   1.426 +    var options = PlacesUtils.history.getNewQueryOptions();
   1.427 +    options.maxResults = aLimit;
   1.428 +    options.sortingMode = aSortingMode;
   1.429 +    var query = PlacesUtils.history.getNewQuery();
   1.430 +
   1.431 +    // Return the pending statement to the caller, to allow cancelation.
   1.432 +    return PlacesUtils.history.QueryInterface(Ci.nsPIPlacesDatabase)
   1.433 +                              .asyncExecuteLegacyQueries([query], 1, options, {
   1.434 +      handleResult: function (aResultSet) {
   1.435 +        for (let row; (row = aResultSet.getNextRow());) {
   1.436 +          try {
   1.437 +            aCallback.call(aScope,
   1.438 +                           { uri: row.getResultByIndex(1)
   1.439 +                           , title: row.getResultByIndex(2)
   1.440 +                           });
   1.441 +          } catch (e) {}
   1.442 +        }
   1.443 +      },
   1.444 +      handleError: function (aError) {
   1.445 +        Components.utils.reportError(
   1.446 +          "Async execution error (" + aError.result + "): " + aError.message);
   1.447 +      },
   1.448 +      handleCompletion: function (aReason) {
   1.449 +        aCallback.call(WinTaskbarJumpList, null);
   1.450 +      },
   1.451 +    });
   1.452 +  },
   1.453 +
   1.454 +  _clearHistory: function WTBJL__clearHistory(items) {
   1.455 +    if (!items)
   1.456 +      return;
   1.457 +    var URIsToRemove = [];
   1.458 +    var e = items.enumerate();
   1.459 +    while (e.hasMoreElements()) {
   1.460 +      let oldItem = e.getNext().QueryInterface(Ci.nsIJumpListShortcut);
   1.461 +      if (oldItem) {
   1.462 +        try { // in case we get a bad uri
   1.463 +          let uriSpec = oldItem.app.getParameter(0);
   1.464 +          URIsToRemove.push(NetUtil.newURI(uriSpec));
   1.465 +        } catch (err) { }
   1.466 +      }
   1.467 +    }
   1.468 +    if (URIsToRemove.length > 0) {
   1.469 +      PlacesUtils.bhistory.removePages(URIsToRemove, URIsToRemove.length, true);
   1.470 +    }
   1.471 +  },
   1.472 +
   1.473 +  /**
   1.474 +   * Prefs utilities
   1.475 +   */ 
   1.476 +
   1.477 +  _refreshPrefs: function WTBJL__refreshPrefs() {
   1.478 +    this._enabled = _prefs.getBoolPref(PREF_TASKBAR_ENABLED);
   1.479 +    this._showFrequent = _prefs.getBoolPref(PREF_TASKBAR_FREQUENT);
   1.480 +    this._showRecent = _prefs.getBoolPref(PREF_TASKBAR_RECENT);
   1.481 +    this._showTasks = _prefs.getBoolPref(PREF_TASKBAR_TASKS);
   1.482 +    this._maxItemCount = _prefs.getIntPref(PREF_TASKBAR_ITEMCOUNT);
   1.483 +  },
   1.484 +
   1.485 +  /**
   1.486 +   * Init and shutdown utilities
   1.487 +   */ 
   1.488 +
   1.489 +  _initTaskbar: function WTBJL__initTaskbar() {
   1.490 +    this._builder = _taskbarService.createJumpListBuilder();
   1.491 +    if (!this._builder || !this._builder.available)
   1.492 +      return false;
   1.493 +
   1.494 +    return true;
   1.495 +  },
   1.496 +
   1.497 +  _initObs: function WTBJL__initObs() {
   1.498 +    // If the browser is closed while in private browsing mode, the "exit"
   1.499 +    // notification is fired on quit-application-granted.
   1.500 +    // History cleanup can happen at profile-change-teardown.
   1.501 +    Services.obs.addObserver(this, "profile-before-change", false);
   1.502 +    Services.obs.addObserver(this, "browser:purge-session-history", false);
   1.503 +    _prefs.addObserver("", this, false);
   1.504 +  },
   1.505 + 
   1.506 +  _freeObs: function WTBJL__freeObs() {
   1.507 +    Services.obs.removeObserver(this, "profile-before-change");
   1.508 +    Services.obs.removeObserver(this, "browser:purge-session-history");
   1.509 +    _prefs.removeObserver("", this);
   1.510 +  },
   1.511 +
   1.512 +  _updateTimer: function WTBJL__updateTimer() {
   1.513 +    if (this._enabled && !this._shuttingDown && !this._timer) {
   1.514 +      this._timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
   1.515 +      this._timer.initWithCallback(this,
   1.516 +                                   _prefs.getIntPref(PREF_TASKBAR_REFRESH)*1000,
   1.517 +                                   this._timer.TYPE_REPEATING_SLACK);
   1.518 +    }
   1.519 +    else if ((!this._enabled || this._shuttingDown) && this._timer) {
   1.520 +      this._timer.cancel();
   1.521 +      delete this._timer;
   1.522 +    }
   1.523 +  },
   1.524 +
   1.525 +  _hasIdleObserver: false,
   1.526 +  _updateIdleObserver: function WTBJL__updateIdleObserver() {
   1.527 +    if (this._enabled && !this._shuttingDown && !this._hasIdleObserver) {
   1.528 +      _idle.addIdleObserver(this, IDLE_TIMEOUT_SECONDS);
   1.529 +      this._hasIdleObserver = true;
   1.530 +    }
   1.531 +    else if ((!this._enabled || this._shuttingDown) && this._hasIdleObserver) {
   1.532 +      _idle.removeIdleObserver(this, IDLE_TIMEOUT_SECONDS);
   1.533 +      this._hasIdleObserver = false;
   1.534 +    }
   1.535 +  },
   1.536 +
   1.537 +  _free: function WTBJL__free() {
   1.538 +    this._freeObs();
   1.539 +    this._updateTimer();
   1.540 +    this._updateIdleObserver();
   1.541 +    delete this._builder;
   1.542 +  },
   1.543 +
   1.544 +  /**
   1.545 +   * Notification handlers
   1.546 +   */
   1.547 +
   1.548 +  notify: function WTBJL_notify(aTimer) {
   1.549 +    // Add idle observer on the first notification so it doesn't hit startup.
   1.550 +    this._updateIdleObserver();
   1.551 +    this.update();
   1.552 +  },
   1.553 +
   1.554 +  observe: function WTBJL_observe(aSubject, aTopic, aData) {
   1.555 +    switch (aTopic) {
   1.556 +      case "nsPref:changed":
   1.557 +        if (this._enabled == true && !_prefs.getBoolPref(PREF_TASKBAR_ENABLED))
   1.558 +          this._deleteActiveJumpList();
   1.559 +        this._refreshPrefs();
   1.560 +        this._updateTimer();
   1.561 +        this._updateIdleObserver();
   1.562 +        this.update();
   1.563 +      break;
   1.564 +
   1.565 +      case "profile-before-change":
   1.566 +        this._shutdown();
   1.567 +      break;
   1.568 +
   1.569 +      case "browser:purge-session-history":
   1.570 +        this.update();
   1.571 +      break;
   1.572 +      case "idle":
   1.573 +        if (this._timer) {
   1.574 +          this._timer.cancel();
   1.575 +          delete this._timer;
   1.576 +        }
   1.577 +      break;
   1.578 +
   1.579 +      case "active":
   1.580 +        this._updateTimer();
   1.581 +      break;
   1.582 +    }
   1.583 +  },
   1.584 +};

mercurial