         _.include(@defaultDirection, directionComponent)
       )
 
-    # 𝒇 `_setState` is a simple setter that returns false if state doesn't change.
-    _setState: (state) ->
+    # 𝒇 `_setCurrentTrigger` is a simple setter that updates a trigger and makes
+    # it current, but only if it isn't already.
+    _setCurrentTrigger: ($trigger) ->
+      @_triggerChanged = not $trigger.is @_$currentTrigger
+      return no unless @_triggerChanged
+      @_inflateByTrigger $trigger
+      @_$currentTrigger = $trigger
+
+
+    # 𝒇 `_setState` is a simple setter that returns false if state doesn't
+    # change. It also handles minor tasks when switching to a new state.
+    _setState: (state, data...) ->
       return no if state is @_state
+      #- previous = @_state
       @_state = state
       @debugLog @_state
+      switch state
+        when 'asleep' then @afterHide.apply @, data
+        when 'awake' then @afterShow.apply @, data
+        when 'sleeping' then clearTimeout @_wakeCountdown
+        when 'waking'
+          clearTimeout @_sleepCountdown
+          @_triggerChanged = yes
 
     # 𝒇 `_setTip` aliases the conventional `$el` property to `$tip` for clarity.
     _setTip: ($tip) => @$tip = @$el = $tip


    # ### Appearance

    # 𝒇 `wakeByTrigger` is the main toggler and a `_state` updater. It takes an
    # `onWake` callback, which is usually to update position. The toggling and
    # main changes only happen if the delay is passed. It will return a bool for
    # success.
    wakeByTrigger: ($trigger, event, onWake) ->
      # - Store current trigger info.
      triggerChanged = not $trigger.is @_$currentTrigger
      if triggerChanged
        @_inflateByTrigger $trigger
        @_$currentTrigger = $trigger
      # - Go directly to the position updating if no toggling is needed.
      if @_state is 'awake'
        @_positionToTrigger $trigger, event
        @onShow triggerChanged, event
        if onWake? then onWake()
        @debugLog 'quick update'
        return yes
      if event? then @debugLog event.type
      # - Don't toggle if awake or waking, or if event isn't `truemouseenter`.
      return no if @_state in ['awake', 'waking']
      # - Get delay and initial duration.
      delay = @animations.show.delay
      duration = @animations.show.duration
      # - Our `wake` subroutine runs the timed-out logic, which includes the fade
      #   transition. The latter is also affected by `safeToggle`. The `onShow`
      #   and `afterShow` hook methods are also run.
      wake = =>
        @_positionToTrigger $trigger, event
        @onShow triggerChanged, event
        @$tip.stop().fadeIn duration, =>
          if triggerChanged
            onWake() if onWake?
          if @safeToggle is on then @$tip.siblings(@classNames.tip).fadeOut()
          @afterShow triggerChanged, event
          @_setState 'awake'
      # - Wake up depending on current state. If we are in the middle of
      #   sleeping, stop sleeping by updating `_sleepCountdown` and wake up
      #   sooner.
      if @_state is 'sleeping'
        @debugLog 'clear sleep'
        clearTimeout @_sleepCountdown
        duration = 0
        wake()
      # - Start the normal wakeup and update `_wakeCountdown`.
      else if event? and event.type is 'truemouseenter'
        triggerChanged = yes
        @_setState 'waking'
        @_wakeCountdown = setTimeout wake, delay
      yes

    # 𝒇 `sleepByTrigger` is a much simpler toggler compared to its counterpart
    # `wakeByTrigger`. It also updates `_state` and returns a bool for success.
    # As long as the tip isn't truly visible, or sleeping is redundant, it bails.
    sleepByTrigger: ($trigger) ->
      return no if @_state in ['asleep', 'sleeping']
      @_setState 'sleeping'
      clearTimeout @_wakeCountdown
      @_sleepCountdown = setTimeout =>
        @onHide()
        @$tip.stop().fadeOut @animations.hide.duration, =>
          @_setState 'asleep'
          @afterHide()
      , @animations.hide.delay
      yes

    # ### Content


      #   direction. Note that the direction data structure must be an array of
      #   `components`, and conventionally with top/bottom first.
      defaultDirection: ['bottom', 'right']
      # - `tipTemplate` should return interpolated html when given the
      #   additional container class list. Its context is the plugin instance.
      tipTemplate: (containerClass) ->
