Bug 594977 - Part 3: rejigger the Trackpoint hack for older versions of the Synaptics drivers r=roc a=blocker
authorCameron McCormack <cam@mcc.id.au>
Tue, 28 Dec 2010 23:16:43 +1300
changeset 59750 77143138cfba4416b020ef00fedf6326740a82dd
parent 59749 39db16b78175009a9a6e425ed1686b9d072bd99b
child 59751 0e609f37f4bc364f2606fcfe01ea9906bce4399d
push id1
push usershaver@mozilla.com
push dateTue, 04 Jan 2011 17:58:04 +0000
reviewersroc, blocker
bugs594977
milestone2.0b9pre
Bug 594977 - Part 3: rejigger the Trackpoint hack for older versions of the Synaptics drivers r=roc a=blocker
widget/src/windows/nsWindow.cpp
widget/src/windows/nsWindow.h
--- a/widget/src/windows/nsWindow.cpp
+++ b/widget/src/windows/nsWindow.cpp
@@ -620,22 +620,60 @@ nsWindow::Create(nsIWidget *aParent,
     DWORD dwAttribute = TRUE;    
     nsUXThemeData::dwmSetWindowAttributePtr(mWnd, DWMWA_NONCLIENT_RTL_LAYOUT, &dwAttribute, sizeof dwAttribute);
   }
 #endif
 
   if (mWindowType != eWindowType_plugin &&
       mWindowType != eWindowType_invisible &&
       UseTrackPointHack()) {
-    // Ugly Thinkpad Driver Hack (Bug 507222)
-    // We create an invisible scrollbar to trick the 
-    // Trackpoint driver into sending us scrolling messages
-    ::CreateWindowW(L"SCROLLBAR", L"FAKETRACKPOINTSCROLLBAR", 
-                    WS_CHILD | WS_VISIBLE, 0,0,0,0, mWnd, NULL,
-                    nsToolkit::mDllInstance, NULL);
+    // Ugly Thinkpad Driver Hack (Bugs 507222 and 594977)
+    //
+    // We create two zero-sized windows as descendants of the top-level window,
+    // like so:
+    //
+    //   Top-level window (MozillaWindowClass)
+    //     FAKETRACKPOINTSCROLLCONTAINER (MozillaWindowClass)
+    //       FAKETRACKPOINTSCROLLABLE (MozillaWindowClass)
+    //
+    // We need to have the middle window, otherwise the Trackpoint driver
+    // will fail to deliver scroll messages.  WM_MOUSEWHEEL messages are
+    // sent to the FAKETRACKPOINTSCROLLABLE, which then propagate up the
+    // window hierarchy until they are handled by nsWindow::WindowProc.
+    // WM_HSCROLL messages are also sent to the FAKETRACKPOINTSCROLLABLE,
+    // but these do not propagate automatically, so we have the window
+    // procedure pretend that they were dispatched to the top-level window
+    // instead.
+    //
+    // The FAKETRACKPOINTSCROLLABLE needs to have the specific window styles it
+    // is given below so that it catches the Trackpoint driver's heuristics.
+    HWND scrollContainerWnd = ::CreateWindowW
+      (className.get(), L"FAKETRACKPOINTSCROLLCONTAINER",
+       WS_CHILD | WS_VISIBLE,
+       0, 0, 0, 0, mWnd, NULL, nsToolkit::mDllInstance, NULL);
+    HWND scrollableWnd = ::CreateWindowW
+      (className.get(), L"FAKETRACKPOINTSCROLLABLE",
+       WS_CHILD | WS_VISIBLE | WS_VSCROLL | WS_TABSTOP | 0x30,
+       0, 0, 0, 0, scrollContainerWnd, NULL, nsToolkit::mDllInstance, NULL);
+
+    // Give the FAKETRACKPOINTSCROLLABLE window a specific ID so that
+    // WindowProcInternal can distinguish it from the top-level window
+    // easily.
+    ::SetWindowLongPtrW(scrollableWnd, GWLP_ID, eFakeTrackPointScrollableID);
+
+    // Make FAKETRACKPOINTSCROLLABLE use nsWindow::WindowProc, and store the
+    // old window procedure in its "user data".
+    WNDPROC oldWndProc;
+    if (mUnicodeWidget)
+      oldWndProc = (WNDPROC)::SetWindowLongPtrW(scrollableWnd, GWLP_WNDPROC,
+                                                (LONG_PTR)nsWindow::WindowProc);
+    else
+      oldWndProc = (WNDPROC)::SetWindowLongPtrA(scrollableWnd, GWLP_WNDPROC,
+                                                (LONG_PTR)nsWindow::WindowProc);
+    ::SetWindowLongPtrW(scrollableWnd, GWLP_USERDATA, (LONG_PTR)oldWndProc);
   }
 
   // call the event callback to notify about creation
 
   DispatchStandardEvent(NS_CREATE);
   SubclassWindow(TRUE);
 
   if (sTrimOnMinimize == 2 && mWindowType == eWindowType_invisible) {
@@ -4417,16 +4455,28 @@ LRESULT CALLBACK nsWindow::WindowProc(HW
 }
 
 LRESULT CALLBACK nsWindow::WindowProcInternal(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
 {
   NS_TIME_FUNCTION_MIN_FMT(5.0, "%s (line %d) (hWnd: %p, msg: %p, wParam: %p, lParam: %p",
                            MOZ_FUNCTION_NAME, __LINE__, hWnd, msg,
                            wParam, lParam);
 
+  if (::GetWindowLongPtrW(hWnd, GWLP_ID) == eFakeTrackPointScrollableID) {
+    // This message was sent to the FAKETRACKPOINTSCROLLABLE.
+    if (msg == WM_HSCROLL) {
+      // Route WM_HSCROLL messages to the main window.
+      hWnd = ::GetParent(::GetParent(hWnd));
+    } else {
+      // Handle all other messages with its original window procedure.
+      WNDPROC prevWindowProc = (WNDPROC)::GetWindowLongPtr(hWnd, GWLP_USERDATA);
+      return ::CallWindowProcW(prevWindowProc, hWnd, msg, wParam, lParam);
+    }
+  }
+
   // Get the window which caused the event and ask it to process the message
   nsWindow *someWindow = GetNSWindowPtr(hWnd);
 
 #ifdef MOZ_IPC
   if (someWindow)
     someWindow->IPCWindowProcHandler(msg, wParam, lParam);
 #endif
 
@@ -8615,23 +8665,23 @@ HasRegistryKey(HKEY aRoot, LPCWSTR aName
   return PR_TRUE;
 }
 
 static PRBool
 IsObsoleteSynapticsDriver()
 {
   HKEY key;
   LONG result = ::RegOpenKeyExW(HKEY_LOCAL_MACHINE,
-      L"Software\\Synaptics\\SynTP\\Install\\DriverVersion", 0, KEY_READ, &key);
+      L"Software\\Synaptics\\SynTP\\Install", 0, KEY_READ, &key);
   if (result != ERROR_SUCCESS)
     return PR_FALSE;
   DWORD type;
   PRUnichar buf[40];
   DWORD buflen = sizeof(buf);
-  result = ::RegQueryValueExW(key, NULL, NULL, &type, (BYTE*)buf, &buflen);
+  result = ::RegQueryValueExW(key, L"DriverVersion", NULL, &type, (BYTE*)buf, &buflen);
   ::RegCloseKey(key);
   if (result != ERROR_SUCCESS || type != REG_SZ)
     return PR_FALSE;
   buf[NS_ARRAY_LENGTH(buf) - 1] = 0;
 
   int majorVersion = wcstol(buf, NULL, 10);
   return majorVersion < 15;
 }
--- a/widget/src/windows/nsWindow.h
+++ b/widget/src/windows/nsWindow.h
@@ -282,16 +282,20 @@ public:
     return preview.forget();
   }
   void SetTaskbarPreview(nsITaskbarWindowPreview *preview) { mTaskbarPreview = do_GetWeakReference(preview); }
 #endif
 
   NS_IMETHOD              ReparentNativeWidget(nsIWidget* aNewParent);
 protected:
 
+  // A magic number to identify the FAKETRACKPOINTSCROLLABLE window created
+  // when the trackpoint hack is enabled.
+  enum { eFakeTrackPointScrollableID = 0x46545053 };
+
   /**
    * Callbacks
    */
   static LRESULT CALLBACK WindowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
   static LRESULT CALLBACK WindowProcInternal(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
 
   static BOOL CALLBACK    BroadcastMsgToChildren(HWND aWnd, LPARAM aMsg);
   static BOOL CALLBACK    BroadcastMsg(HWND aTopWindow, LPARAM aMsg);