Source code

Revision control

Other Tools

Line Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:expandtab:shiftwidth=2:tabstop=2:
 */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#ifndef nsIdleService_h__
#define nsIdleService_h__

#include "nsIIdleServiceInternal.h"
#include "nsCOMPtr.h"
#include "nsITimer.h"
#include "nsTArray.h"
#include "nsIObserver.h"
#include "nsIIdleService.h"
#include "nsCategoryCache.h"
#include "nsWeakReference.h"
#include "mozilla/TimeStamp.h"

/**
 * Class we can use to store an observer with its associated idle time
 * requirement and whether or not the observer thinks it's "idle".
 */
class IdleListener {
 public:
  nsCOMPtr<nsIObserver> observer;
  uint32_t reqIdleTime;
  bool isIdle;

  IdleListener(nsIObserver* obs, uint32_t reqIT, bool aIsIdle = false)
      : observer(obs), reqIdleTime(reqIT), isIdle(aIsIdle) {}
  ~IdleListener() {}
};

// This one will be declared later.
class nsIdleService;

/**
 * Class to handle the daily idle timer.
 */
class nsIdleServiceDaily : public nsIObserver, public nsSupportsWeakReference {
 public:
  NS_DECL_ISUPPORTS
  NS_DECL_NSIOBSERVER

  explicit nsIdleServiceDaily(nsIIdleService* aIdleService);

  /**
   * Initializes the daily idle observer.
   * Keep this separated from the constructor, since it could cause pointer
   * corruption due to AddRef/Release of "this".
   */
  void Init();

 private:
  virtual ~nsIdleServiceDaily();

  /**
   * StageIdleDaily is the interim call made when an idle-daily event is due.
   * However we don't want to fire idle-daily until the user is idle for this
   * session, so this sets up a short wait for an idle event which triggers
   * the actual idle-daily event.
   *
   * @param aHasBeenLongWait Pass true indicating nsIdleServiceDaily is having
   * trouble getting the idle-daily event fired. If true StageIdleDaily will
   * use a shorter idle wait time before firing idle-daily.
   */
  void StageIdleDaily(bool aHasBeenLongWait);

  /**
   * @note This is a normal pointer, part to avoid creating a cycle with the
   * idle service, part to avoid potential pointer corruption due to this class
   * being instantiated in the constructor of the service itself.
   */
  nsIIdleService* mIdleService;

  /**
   * Place to hold the timer used by this class to determine when a day has
   * passed, after that it will wait for idle time to be detected.
   */
  nsCOMPtr<nsITimer> mTimer;

  /**
   * Function that is called back once a day.
   */
  static void DailyCallback(nsITimer* aTimer, void* aClosure);

  /**
   * Cache of observers for the "idle-daily" category.
   */
  nsCategoryCache<nsIObserver> mCategoryObservers;

  /**
   * Boolean set to true when daily idle notifications should be disabled.
   */
  bool mShutdownInProgress;

  /**
   * Next time we expect an idle-daily timer to fire, in case timers aren't
   * very reliable on the platform. Value is in PR_Now microsecond units.
   */
  PRTime mExpectedTriggerTime;

  /**
   * Tracks which idle daily observer callback we ask for. There are two: a
   * regular long idle wait and a shorter wait if we've been waiting to fire
   * idle daily for an extended period. Set by StageIdleDaily.
   */
  int32_t mIdleDailyTriggerWait;
};

class nsIdleService : public nsIIdleServiceInternal {
 public:
  NS_DECL_ISUPPORTS
  NS_DECL_NSIIDLESERVICE
  NS_DECL_NSIIDLESERVICEINTERNAL

 protected:
  static already_AddRefed<nsIdleService> GetInstance();

  nsIdleService();
  virtual ~nsIdleService();

  /**
   * If there is a platform specific function to poll the system idel time
   * then that must be returned in this function, and the function MUST return
   * true, otherwise then the function should be left unimplemented or made
   * to return false (this can also be used for systems where it depends on
   * the configuration of the system if the idle time can be determined)
   *
   * @param aIdleTime
   *        The idle time in ms.
   *
   * @return true if the idle time could be polled, false otherwise.
   *
   * @note The time returned by this function can be different than the one
   *       returned by GetIdleTime, as that is corrected by any calls to
   *       ResetIdleTimeOut(), unless you overwrite that function too...
   */
  virtual bool PollIdleTime(uint32_t* aIdleTime);

  /**
   * Function that determines if we are in poll mode or not.
   *
   * @return true if polling is supported, false otherwise.
   */
  virtual bool UsePollMode();

 private:
  /**
   * Ensure that the timer is expiring at least at the given time
   *
   * The function might not restart the timer if there is one running currently
   *
   * @param aNextTimeout
   *        The last absolute time the timer should expire
   */
  void SetTimerExpiryIfBefore(mozilla::TimeStamp aNextTimeout);

  /**
   * Stores the next timeout time, 0 means timer not running
   */
  mozilla::TimeStamp mCurrentlySetToTimeoutAt;

  /**
   * mTimer holds the internal timer used by this class to detect when to poll
   * for idle time, when to check if idle timers should expire etc.
   */
  nsCOMPtr<nsITimer> mTimer;

  /**
   * Array of listeners that wants to be notified about idle time.
   */
  nsTArray<IdleListener> mArrayListeners;

  /**
   * Object keeping track of the daily idle thingy.
   */
  RefPtr<nsIdleServiceDaily> mDailyIdle;

  /**
   * Number of observers currently in idle mode.
   */
  uint32_t mIdleObserverCount;

  /**
   * Delta time from last non idle time to when the next observer should switch
   * to idle mode
   *
   * Time in seconds
   *
   * If this value is 0 it means there are no active observers
   */
  uint32_t mDeltaToNextIdleSwitchInS;

  /**
   * If true, the idle service is temporarily disabled, and all idle events
   * will be ignored.
   */
  bool mDisabled = false;

  /**
   * Absolute value for when the last user interaction took place.
   */
  mozilla::TimeStamp mLastUserInteraction;

  /**
   * Function that ensures the timer is running with at least the minimum time
   * needed.  It will kill the timer if there are no active observers.
   */
  void ReconfigureTimer(void);

  /**
   * Callback function that is called when the internal timer expires.
   *
   * This in turn calls the IdleTimerCallback that does the real processing
   */
  static void StaticIdleTimerCallback(nsITimer* aTimer, void* aClosure);

  /**
   * Function that handles when a timer has expired
   */
  void IdleTimerCallback(void);
};

#endif  // nsIdleService_h__