def on_timer(self, evt):
    """
    Keep watching the mouse displacement via timer
    Needed since EVT_MOVE doesn't happen once the mouse gets outside the
    frame
    """
    ctrl_is_down = wx.GetKeyState(wx.WXK_CONTROL)
    shift_is_down = wx.GetKeyState(wx.WXK_SHIFT)
    ms = wx.GetMouseState()
    new_pos = None

    # New initialization when keys pressed change
    if self._key_state != (ctrl_is_down, shift_is_down):
      self._key_state = (ctrl_is_down, shift_is_down)

      # Keep state at click
      self._click_ms_x, self._click_ms_y = ms.x, ms.y
      self._click_frame_x, self._click_frame_y = self.pos
      self._click_frame_width, self._click_frame_height = self.size
      self._click_opacity = self.opacity

      # Avoids refresh when there's no move (stores last mouse state)
      self._last_ms = ms.x, ms.y

      # Quadrant at click (need to know how to resize)
      width, height = self.size
      self._quad_signal_x = 1 if (self._click_ms_x -
                                  self._click_frame_x) / width > .5 else -1
      self._quad_signal_y = 1 if (self._click_ms_y -
                                  self._click_frame_y) / height > .5 else -1

    # "Polling watcher" for mouse left button while it's kept down
    if (wx.__version__ >= "3" and ms.leftIsDown) or \
       (wx.__version__ <  "3" and ms.leftDown):
      if self._last_ms != (ms.x, ms.y): # Moved?
        self._last_ms = (ms.x, ms.y)
        delta_x = ms.x - self._click_ms_x
        delta_y = ms.y - self._click_ms_y

        # Change transparency / opacity
        if shift_is_down:
          self.opacity = max(MIN_OPACITY,
                             min(MAX_OPACITY, self._click_opacity - delta_y)
                            )

        # Resize
        if ctrl_is_down:
          # New size
          new_w = max(MIN_WIDTH, self._click_frame_width +
                                 2 * delta_x * self._quad_signal_x
                     )
          new_h = max(MIN_HEIGHT, self._click_frame_height +
                                  2 * delta_y * self._quad_signal_y
                     )
          self.size = new_w, new_h

          # Center should be kept
          center_x = self._click_frame_x + self._click_frame_width / 2
          center_y = self._click_frame_y + self._click_frame_height / 2
          new_pos = (center_x - new_w / 2,
                     center_y - new_h / 2)

        # Move the window
        if not (ctrl_is_down or shift_is_down):
          new_pos = (self._click_frame_x + delta_x,
                     self._click_frame_y + delta_y)

      if new_pos is not None:
        self.pos = new_pos

      # Since left button is kept down, there should be another one shot
      # timer event again, without creating many timers like wx.CallLater
      self._timer.Start(MOUSE_TIMER_WATCH, True)