widget/windows/WinMouseScrollHandler.h

Thu, 15 Jan 2015 15:59:08 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 15 Jan 2015 15:59:08 +0100
branch
TOR_BUG_9701
changeset 10
ac0c01689b40
permissions
-rw-r--r--

Implement a real Private Browsing Mode condition by changing the API/ABI;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

     1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     2 /* vim: set ts=2 et sw=2 tw=80: */
     3 /* This Source Code Form is subject to the terms of the Mozilla Public
     4  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
     5  * You can obtain one at http://mozilla.org/MPL/2.0/. */
     7 #ifndef mozilla_widget_WinMouseScrollHandler_h__
     8 #define mozilla_widget_WinMouseScrollHandler_h__
    10 #include "nscore.h"
    11 #include "nsDebug.h"
    12 #include "mozilla/Assertions.h"
    13 #include "mozilla/EventForwards.h"
    14 #include "mozilla/TimeStamp.h"
    15 #include <windows.h>
    17 class nsWindowBase;
    18 struct nsIntPoint;
    20 namespace mozilla {
    21 namespace widget {
    23 class ModifierKeyState;
    25 struct MSGResult;
    27 class MouseScrollHandler {
    28 public:
    29   static MouseScrollHandler* GetInstance();
    31   static void Initialize();
    32   static void Shutdown();
    34   static bool NeedsMessage(UINT aMsg);
    35   static bool ProcessMessage(nsWindowBase* aWidget,
    36                              UINT msg,
    37                              WPARAM wParam,
    38                              LPARAM lParam,
    39                              MSGResult& aResult);
    41   /**
    42    * See nsIWidget::SynthesizeNativeMouseScrollEvent() for the detail about
    43    * this method.
    44    */
    45   static nsresult SynthesizeNativeMouseScrollEvent(nsWindowBase* aWidget,
    46                                                    const nsIntPoint& aPoint,
    47                                                    uint32_t aNativeMessage,
    48                                                    int32_t aDelta,
    49                                                    uint32_t aModifierFlags,
    50                                                    uint32_t aAdditionalFlags);
    52   /**
    53    * IsWaitingInternalMessage() returns true if MouseScrollHandler posted
    54    * an internal message for a native mouse wheel message and has not
    55    * received it. Otherwise, false.
    56    */
    57   static bool IsWaitingInternalMessage()
    58   {
    59     return sInstance && sInstance->mIsWaitingInternalMessage;
    60   }
    62 private:
    63   MouseScrollHandler();
    64   ~MouseScrollHandler();
    66   bool mIsWaitingInternalMessage;
    68   static MouseScrollHandler* sInstance;
    70   /**
    71    * DispatchEvent() dispatches aEvent on aWidget.
    72    *
    73    * @return TRUE if the event was consumed.  Otherwise, FALSE.
    74    */
    75   static bool DispatchEvent(nsWindowBase* aWidget, WidgetGUIEvent& aEvent);
    77   /**
    78    * InitEvent() initializes the aEvent.  If aPoint is null, the result of
    79    * GetCurrentMessagePos() will be used.
    80    */
    81   static void InitEvent(nsWindowBase* aWidget,
    82                         WidgetGUIEvent& aEvent,
    83                         nsIntPoint* aPoint = nullptr);
    85   /**
    86    * GetModifierKeyState() returns current modifier key state.
    87    * Note that some devices need some hack for the modifier key state.
    88    * This method does it automatically.
    89    *
    90    * @param aMessage    Handling message.
    91    */
    92   static ModifierKeyState GetModifierKeyState(UINT aMessage);
    94   /**
    95    * MozGetMessagePos() returns the mouse cursor position when GetMessage()
    96    * was called last time.  However, if we're sending a native message,
    97    * this returns the specified cursor position by
    98    * SynthesizeNativeMouseScrollEvent().
    99    */
   100   static POINTS GetCurrentMessagePos();
   102   /**
   103    * ProcessNativeMouseWheelMessage() processes WM_MOUSEWHEEL and
   104    * WM_MOUSEHWHEEL.  Additionally, processes WM_VSCROLL and WM_HSCROLL if they
   105    * should be processed as mouse wheel message.
   106    * This method posts MOZ_WM_MOUSEVWHEEL, MOZ_WM_MOUSEHWHEEL,
   107    * MOZ_WM_VSCROLL or MOZ_WM_HSCROLL if we need to dispatch mouse scroll
   108    * events.  That avoids deadlock with plugin process.
   109    *
   110    * @param aWidget     A window which receives the message.
   111    * @param aMessage    WM_MOUSEWHEEL, WM_MOUSEHWHEEL, WM_VSCROLL or
   112    *                    WM_HSCROLL.
   113    * @param aWParam     The wParam value of the message.
   114    * @param aLParam     The lParam value of the message.
   115    */
   116   void ProcessNativeMouseWheelMessage(nsWindowBase* aWidget,
   117                                       UINT aMessage,
   118                                       WPARAM aWParam,
   119                                       LPARAM aLParam);
   121   /**
   122    * ProcessNativeScrollMessage() processes WM_VSCROLL and WM_HSCROLL.
   123    * This method just call ProcessMouseWheelMessage() if the message should be
   124    * processed as mouse wheel message.  Otherwise, dispatches a content
   125    * command event.
   126    *
   127    * @param aWidget     A window which receives the message.
   128    * @param aMessage    WM_VSCROLL or WM_HSCROLL.
   129    * @param aWParam     The wParam value of the message.
   130    * @param aLParam     The lParam value of the message.
   131    * @return            TRUE if the message is processed.  Otherwise, FALSE.
   132    */
   133   bool ProcessNativeScrollMessage(nsWindowBase* aWidget,
   134                                   UINT aMessage,
   135                                   WPARAM aWParam,
   136                                   LPARAM aLParam);
   138   /**
   139    * HandleMouseWheelMessage() processes MOZ_WM_MOUSEVWHEEL and
   140    * MOZ_WM_MOUSEHWHEEL which are posted when one of our windows received
   141    * WM_MOUSEWHEEL or WM_MOUSEHWHEEL for avoiding deadlock with OOPP.
   142    *
   143    * @param aWidget     A window which receives the wheel message.
   144    * @param aMessage    MOZ_WM_MOUSEWHEEL or MOZ_WM_MOUSEHWHEEL.
   145    * @param aWParam     The wParam value of the original message.
   146    * @param aLParam     The lParam value of the original message.
   147    */
   148   void HandleMouseWheelMessage(nsWindowBase* aWidget,
   149                                UINT aMessage,
   150                                WPARAM aWParam,
   151                                LPARAM aLParam);
   153   /**
   154    * HandleScrollMessageAsMouseWheelMessage() processes the MOZ_WM_VSCROLL and
   155    * MOZ_WM_HSCROLL which are posted when one of mouse windows received
   156    * WM_VSCROLL or WM_HSCROLL and user wants them to emulate mouse wheel
   157    * message's behavior.
   158    *
   159    * @param aWidget     A window which receives the scroll message.
   160    * @param aMessage    MOZ_WM_VSCROLL or MOZ_WM_HSCROLL.
   161    * @param aWParam     The wParam value of the original message.
   162    * @param aLParam     The lParam value of the original message.
   163    */
   164   void HandleScrollMessageAsMouseWheelMessage(nsWindowBase* aWidget,
   165                                               UINT aMessage,
   166                                               WPARAM aWParam,
   167                                               LPARAM aLParam);
   169   /**
   170    * ComputeMessagePos() computes the cursor position when the message was
   171    * added to the queue.
   172    *
   173    * @param aMessage    Handling message.
   174    * @param aWParam     Handling message's wParam.
   175    * @param aLParam     Handling message's lParam.
   176    * @return            Mouse cursor position when the message is added to
   177    *                    the queue or current cursor position if the result of
   178    *                    ::GetMessagePos() is broken.
   179    */
   180   POINT ComputeMessagePos(UINT aMessage,
   181                           WPARAM aWParam,
   182                           LPARAM aLParam);
   184   class EventInfo {
   185   public:
   186     /**
   187      * @param aWidget   An nsWindow which is handling the event.
   188      * @param aMessage  Must be WM_MOUSEWHEEL or WM_MOUSEHWHEEL.
   189      */
   190     EventInfo(nsWindowBase* aWidget, UINT aMessage, WPARAM aWParam, LPARAM aLParam);
   192     bool CanDispatchWheelEvent() const;
   194     int32_t GetNativeDelta() const { return mDelta; }
   195     HWND GetWindowHandle() const { return mWnd; }
   196     const TimeStamp& GetTimeStamp() const { return mTimeStamp; }
   197     bool IsVertical() const { return mIsVertical; }
   198     bool IsPositive() const { return (mDelta > 0); }
   199     bool IsPage() const { return mIsPage; }
   201     /**
   202      * @return          Number of lines or pages scrolled per WHEEL_DELTA.
   203      */
   204     int32_t GetScrollAmount() const;
   206   protected:
   207     EventInfo() :
   208       mIsVertical(false), mIsPage(false), mDelta(0), mWnd(nullptr)
   209     {
   210     }
   212     // TRUE if event is for vertical scroll.  Otherwise, FALSE.
   213     bool mIsVertical;
   214     // TRUE if event scrolls per page, otherwise, FALSE.
   215     bool mIsPage;
   216     // The native delta value.
   217     int32_t mDelta;
   218     // The window handle which is handling the event.
   219     HWND mWnd;
   220     // Timestamp of the event.
   221     TimeStamp mTimeStamp;
   222   };
   224   class LastEventInfo : public EventInfo {
   225   public:
   226     LastEventInfo() :
   227       EventInfo(), mAccumulatedDelta(0)
   228     {
   229     }
   231     /**
   232      * CanContinueTransaction() checks whether the new event can continue the
   233      * last transaction or not.  Note that if there is no transaction, this
   234      * returns true.
   235      */
   236     bool CanContinueTransaction(const EventInfo& aNewEvent);
   238     /**
   239      * ResetTransaction() resets the transaction, i.e., the instance forgets
   240      * the last event information.
   241      */
   242     void ResetTransaction();
   244     /**
   245      * RecordEvent() saves the information of new event.
   246      */
   247     void RecordEvent(const EventInfo& aEvent);
   249     /**
   250      * InitWheelEvent() initializes NS_WHEEL_WHEEL event and
   251      * recomputes the remaning detla for the event.
   252      * This must be called only once during handling a message and after
   253      * RecordEvent() is called.
   254      *
   255      * @param aWidget           A window which will dispatch the event.
   256      * @param aWheelEvent       An NS_WHEEL_WHEEL event, this will be
   257      *                          initialized.
   258      * @param aModKeyState      Current modifier key state.
   259      * @return                  TRUE if the event is ready to dispatch.
   260      *                          Otherwise, FALSE.
   261      */
   262     bool InitWheelEvent(nsWindowBase* aWidget,
   263                         WidgetWheelEvent& aWheelEvent,
   264                         const ModifierKeyState& aModKeyState);
   266   private:
   267     static int32_t RoundDelta(double aDelta);
   269     int32_t mAccumulatedDelta;
   270   };
   272   LastEventInfo mLastEventInfo;
   274   class SystemSettings {
   275   public:
   276     SystemSettings() : mInitialized(false) {}
   278     void Init();
   279     void MarkDirty();
   280     void NotifyUserPrefsMayOverrideSystemSettings();
   282     int32_t GetScrollAmount(bool aForVertical) const
   283     {
   284       MOZ_ASSERT(mInitialized, "SystemSettings must be initialized");
   285       return aForVertical ? mScrollLines : mScrollChars;
   286     }
   288     bool IsPageScroll(bool aForVertical) const
   289     {
   290       MOZ_ASSERT(mInitialized, "SystemSettings must be initialized");
   291       return aForVertical ? (mScrollLines == WHEEL_PAGESCROLL) :
   292                             (mScrollChars == WHEEL_PAGESCROLL);
   293     }
   295   private:
   296     bool mInitialized;
   297     int32_t mScrollLines;
   298     int32_t mScrollChars;
   299   };
   301   SystemSettings mSystemSettings;
   303   class UserPrefs {
   304   public:
   305     UserPrefs();
   306     ~UserPrefs();
   308     void MarkDirty();
   310     bool IsScrollMessageHandledAsWheelMessage()
   311     {
   312       Init();
   313       return mScrollMessageHandledAsWheelMessage;
   314     }
   316     int32_t GetOverriddenVerticalScrollAmout()
   317     {
   318       Init();
   319       return mOverriddenVerticalScrollAmount;
   320     }
   322     int32_t GetOverriddenHorizontalScrollAmout()
   323     {
   324       Init();
   325       return mOverriddenHorizontalScrollAmount;
   326     }
   328     int32_t GetMouseScrollTransactionTimeout()
   329     {
   330       Init();
   331       return mMouseScrollTransactionTimeout;
   332     }
   334   private:
   335     void Init();
   337     static void OnChange(const char* aPrefName, void* aClosure)
   338     {
   339       static_cast<UserPrefs*>(aClosure)->MarkDirty();
   340     }
   342     bool mInitialized;
   343     bool mScrollMessageHandledAsWheelMessage;
   344     int32_t mOverriddenVerticalScrollAmount;
   345     int32_t mOverriddenHorizontalScrollAmount;
   346     int32_t mMouseScrollTransactionTimeout;
   347   };
   349   UserPrefs mUserPrefs;
   351   class SynthesizingEvent {
   352   public:
   353     SynthesizingEvent() :
   354       mWnd(nullptr), mMessage(0), mWParam(0), mLParam(0),
   355       mStatus(NOT_SYNTHESIZING)
   356     {
   357     }
   359     ~SynthesizingEvent() {}
   361     static bool IsSynthesizing();
   363     nsresult Synthesize(const POINTS& aCursorPoint, HWND aWnd,
   364                         UINT aMessage, WPARAM aWParam, LPARAM aLParam,
   365                         const BYTE (&aKeyStates)[256]);
   367     void NativeMessageReceived(nsWindowBase* aWidget, UINT aMessage,
   368                                WPARAM aWParam, LPARAM aLParam);
   370     void NotifyNativeMessageHandlingFinished();
   371     void NotifyInternalMessageHandlingFinished();
   373     const POINTS& GetCursorPoint() const { return mCursorPoint; }
   375   private:
   376     POINTS mCursorPoint;
   377     HWND mWnd;
   378     UINT mMessage;
   379     WPARAM mWParam;
   380     LPARAM mLParam;
   381     BYTE mKeyState[256];
   382     BYTE mOriginalKeyState[256];
   384     enum Status {
   385       NOT_SYNTHESIZING,
   386       SENDING_MESSAGE,
   387       NATIVE_MESSAGE_RECEIVED,
   388       INTERNAL_MESSAGE_POSTED,
   389     };
   390     Status mStatus;
   392 #ifdef PR_LOGGING
   393     const char* GetStatusName()
   394     {
   395       switch (mStatus) {
   396         case NOT_SYNTHESIZING:
   397           return "NOT_SYNTHESIZING";
   398         case SENDING_MESSAGE:
   399           return "SENDING_MESSAGE";
   400         case NATIVE_MESSAGE_RECEIVED:
   401           return "NATIVE_MESSAGE_RECEIVED";
   402         case INTERNAL_MESSAGE_POSTED:
   403           return "INTERNAL_MESSAGE_POSTED";
   404         default:
   405           return "Unknown";
   406       }
   407     }
   408 #endif
   410     void Finish();
   411   }; // SynthesizingEvent
   413   SynthesizingEvent* mSynthesizingEvent;
   415 public:
   417   class Device {
   418   public:
   419     class Elantech {
   420     public:
   421       /**
   422        * GetDriverMajorVersion() returns the installed driver's major version.
   423        * If Elantech's driver was installed, returns 0.
   424        */
   425       static int32_t GetDriverMajorVersion();
   427       /**
   428        * IsHelperWindow() checks whether aWnd is a helper window of Elantech's
   429        * touchpad.  Returns TRUE if so.  Otherwise, FALSE.
   430        */
   431       static bool IsHelperWindow(HWND aWnd);
   433       /**
   434        * Key message handler for Elantech's hack.  Returns TRUE if the message
   435        * is consumed by this handler.  Otherwise, FALSE.
   436        */
   437       static bool HandleKeyMessage(nsWindowBase* aWidget,
   438                                    UINT aMsg,
   439                                    WPARAM aWParam);
   441       static void UpdateZoomUntil();
   442       static bool IsZooming();
   444       static void Init();
   446       static bool IsPinchHackNeeded() { return sUsePinchHack; }
   449     private:
   450       // Whether to enable the Elantech swipe gesture hack.
   451       static bool sUseSwipeHack;
   452       // Whether to enable the Elantech pinch-to-zoom gesture hack.
   453       static bool sUsePinchHack;
   454       static DWORD sZoomUntil;
   455     }; // class Elantech
   457     class TrackPoint {
   458     public:
   459       /**
   460        * IsDriverInstalled() returns TRUE if TrackPoint's driver is installed.
   461        * Otherwise, returns FALSE.
   462        */
   463       static bool IsDriverInstalled();
   464     }; // class TrackPoint
   466     class UltraNav {
   467     public:
   468       /**
   469        * IsObsoleteDriverInstalled() checks whether obsoleted UltraNav
   470        * is installed on the environment.
   471        * Returns TRUE if it was installed.  Otherwise, FALSE.
   472        */
   473       static bool IsObsoleteDriverInstalled();
   474     }; // class UltraNav
   476     class SetPoint {
   477     public:
   478       /**
   479        * SetPoint, Logitech's mouse driver, may report wrong cursor position
   480        * for WM_MOUSEHWHEEL message.  See comment in the implementation for
   481        * the detail.
   482        */
   483       static bool IsGetMessagePosResponseValid(UINT aMessage,
   484                                                WPARAM aWParam,
   485                                                LPARAM aLParam);
   486     private:
   487       static bool sMightBeUsing;
   488     };
   490     static void Init();
   492     static bool IsFakeScrollableWindowNeeded()
   493     {
   494       return sFakeScrollableWindowNeeded;
   495     }
   497   private:
   498     /**
   499      * Gets the bool value of aPrefName used to enable or disable an input
   500      * workaround (like the Trackpoint hack).  The pref can take values 0 (for
   501      * disabled), 1 (for enabled) or -1 (to automatically detect whether to
   502      * enable the workaround).
   503      *
   504      * @param aPrefName The name of the pref.
   505      * @param aValueIfAutomatic Whether the given input workaround should be
   506      *                          enabled by default.
   507      */
   508     static bool GetWorkaroundPref(const char* aPrefName,
   509                                   bool aValueIfAutomatic);
   511     static bool sFakeScrollableWindowNeeded;
   512   }; // class Device
   513 };
   515 } // namespace widget
   516 } // namespace mozilla
   518 #endif // mozilla_widget_WinMouseScrollHandler_h__

mercurial