Bug 295540 - Multi-monitor: download save-as dialog remains on secondary monitor even if detached. r=jmathies
authorBrian R. Bondy <netzen@gmail.com>
Thu, 01 Sep 2011 10:01:45 -0400
changeset 76381 59c205c5d0adc4c1b2e6b0bc800594c3989a52fc
parent 76380 191f7bab5f5a01be721e48771a9e62ada0285d41
child 76382 6faef8a5901ccfee72d05bb7345d154ef83589aa
push id3
push userfelipc@gmail.com
push dateFri, 30 Sep 2011 20:09:13 +0000
reviewersjmathies
bugs295540
milestone9.0a1
Bug 295540 - Multi-monitor: download save-as dialog remains on secondary monitor even if detached. r=jmathies
widget/src/windows/nsFilePicker.cpp
widget/src/windows/nsWindowDefs.h
--- a/widget/src/windows/nsFilePicker.cpp
+++ b/widget/src/windows/nsFilePicker.cpp
@@ -93,36 +93,79 @@ int CALLBACK BrowseCallbackProc(HWND hwn
     if (filePath)
       ::SendMessageW(hwnd, BFFM_SETSELECTIONW,
                      TRUE /* true because lpData is a path string */,
                      lpData);
   }
   return 0;
 }
 
+static void EnsureWindowVisible(HWND hwnd) 
+{
+  // Obtain the monitor which has the largest area of intersection 
+  // with the window, or NULL if there is no intersection.
+  HMONITOR monitor = MonitorFromWindow(hwnd, MONITOR_DEFAULTTONULL);
+  if (!monitor) {
+    // The window is not visible, we should reposition it to the same place as its parent
+    HWND parentHwnd = GetParent(hwnd);
+    RECT parentRect;
+    GetWindowRect(parentHwnd, &parentRect);
+    BOOL b = SetWindowPos(hwnd, NULL, 
+                          parentRect.left, 
+                          parentRect.top, 0, 0, 
+                          SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOZORDER);
+  }
+}
+
+// Callback hook which will ensure that the window is visible
+static UINT_PTR CALLBACK FilePickerHook(HWND hwnd, UINT msg,
+                                        WPARAM wParam, LPARAM lParam) 
+{
+  if (msg == WM_NOTIFY) {
+    LPOFNOTIFYW lpofn = (LPOFNOTIFYW) lParam;
+    if (!lpofn || !lpofn->lpOFN) {
+      return 0;
+    }
+    
+    if (CDN_INITDONE == lpofn->hdr.code) {
+      // The Window will be automatically moved to the last position after
+      // CDN_INITDONE.  We post a message to ensure the window will be visible
+      // so it will be done after the automatic last position window move.
+      PostMessage(hwnd, MOZ_WM_ENSUREVISIBLE, 0, 0);
+    }
+  } else if (msg == MOZ_WM_ENSUREVISIBLE) {
+    EnsureWindowVisible(GetParent(hwnd));
+  }
+  return 0;
+}
+
+
 // Callback hook which will dynamically allocate a buffer large
 // enough for the file picker dialog.
-static UINT_PTR CALLBACK FilePickerHook(HWND hwnd, UINT msg,
-                                        WPARAM wParam, LPARAM lParam)
+static UINT_PTR CALLBACK MultiFilePickerHook(HWND hwnd, UINT msg,
+                                             WPARAM wParam, LPARAM lParam)
 {
   switch (msg) {
     case WM_INITDIALOG:
       {
         // Finds the child drop down of a File Picker dialog and sets the 
         // maximum amount of text it can hold when typed in manually.
         // A wParam of 0 mean 0x7FFFFFFE characters.
         HWND comboBox = FindWindowEx(GetParent(hwnd), NULL, 
                                      L"ComboBoxEx32", NULL );
         if(comboBox)
           SendMessage(comboBox, CB_LIMITTEXT, 0, 0);
       }
       break;
     case WM_NOTIFY:
       {
         LPOFNOTIFYW lpofn = (LPOFNOTIFYW) lParam;
+        if (!lpofn || !lpofn->lpOFN) {
+          return 0;
+        }
         // CDN_SELCHANGE is sent when the selection in the list box of the file
         // selection dialog changes
         if (lpofn->hdr.code == CDN_SELCHANGE) {
           HWND parentHWND = GetParent(hwnd);
 
           // Get the required size for the selected files buffer
           UINT newBufLength = 0; 
           int requiredBufLength = CommDlg_OpenSave_GetSpecW(parentHWND, 
@@ -158,17 +201,18 @@ static UINT_PTR CALLBACK FilePickerHook(
 
             lpofn->lpOFN->lpstrFile = filesBuffer;
             lpofn->lpOFN->nMaxFile  = newBufLength;
           }
         }
       }
       break;
   }
-  return 0;
+
+  return FilePickerHook(hwnd, msg, wParam, lParam);
 }
 
 NS_IMETHODIMP nsFilePicker::ShowW(PRInt16 *aReturnVal)
 {
   NS_ENSURE_ARG_POINTER(aReturnVal);
 
   // suppress blur events
   if (mParentWidget) {
@@ -241,17 +285,19 @@ NS_IMETHODIMP nsFilePicker::ShowW(PRInt1
     
     ofn.lpstrTitle   = (LPCWSTR)mTitle.get();
     ofn.lpstrFilter  = (LPCWSTR)filterBuffer.get();
     ofn.nFilterIndex = mSelectedType;
     ofn.hwndOwner    = (HWND) (mParentWidget.get() ? mParentWidget->GetNativeData(NS_NATIVE_TMP_WINDOW) : 0); 
     ofn.lpstrFile    = fileBuffer;
     ofn.nMaxFile     = FILE_BUFFER_SIZE;
     ofn.Flags = OFN_SHAREAWARE | OFN_LONGNAMES | OFN_OVERWRITEPROMPT |
-                OFN_HIDEREADONLY | OFN_PATHMUSTEXIST;
+                OFN_HIDEREADONLY | OFN_PATHMUSTEXIST | OFN_ENABLESIZING | 
+                OFN_EXPLORER | OFN_ENABLEHOOK;
+    ofn.lpfnHook = FilePickerHook;
 
     // Handle add to recent docs settings
     nsCOMPtr<nsIPrivateBrowsingService> pbs =
       do_GetService(NS_PRIVATE_BROWSING_SERVICE_CONTRACTID);
     PRBool privacyModeEnabled = PR_FALSE;
     if (pbs) {
       pbs->GetPrivateBrowsingEnabled(&privacyModeEnabled);
     }
@@ -300,26 +346,25 @@ NS_IMETHODIMP nsFilePicker::ShowW(PRInt1
     
     MOZ_SEH_TRY {
       if (mMode == modeOpen) {
         // FILE MUST EXIST!
         ofn.Flags |= OFN_FILEMUSTEXIST;
         result = ::GetOpenFileNameW(&ofn);
       }
       else if (mMode == modeOpenMultiple) {
-        ofn.Flags |= OFN_FILEMUSTEXIST | OFN_ALLOWMULTISELECT | 
-                     OFN_EXPLORER | OFN_ENABLEHOOK;
+        ofn.Flags |= OFN_FILEMUSTEXIST | OFN_ALLOWMULTISELECT;
 
         // The hook set here ensures that the buffer returned will always be
         // long enough to hold all selected files.  The hook may modify the
         // value of ofn.lpstrFile and deallocate the old buffer that it pointed
         // to (fileBuffer). The hook assumes that the passed in value is heap 
         // allocated and that the returned value should be freed by the caller.
         // If the hook changes the buffer, it will deallocate the old buffer.
-        ofn.lpfnHook = FilePickerHook;
+        ofn.lpfnHook = MultiFilePickerHook;
         fileBuffer.forget();
         result = ::GetOpenFileNameW(&ofn);
         fileBuffer = ofn.lpstrFile;
       }
       else if (mMode == modeSave) {
         ofn.Flags |= OFN_NOREADONLYRETURN;
 
         // Don't follow shortcuts when saving a shortcut, this can be used
--- a/widget/src/windows/nsWindowDefs.h
+++ b/widget/src/windows/nsWindowDefs.h
@@ -59,16 +59,19 @@
 // Used as a "tracer" event to probe event loop latency.
 #define MOZ_WM_TRACE                      (WM_APP+0x0301)
 // Our internal message for WM_MOUSEWHEEL, WM_MOUSEHWHEEL, WM_VSCROLL and
 // WM_HSCROLL
 #define MOZ_WM_MOUSEVWHEEL                (WM_APP+0x0310)
 #define MOZ_WM_MOUSEHWHEEL                (WM_APP+0x0311)
 #define MOZ_WM_VSCROLL                    (WM_APP+0x0312)
 #define MOZ_WM_HSCROLL                    (WM_APP+0x0313)
+// Internal message for ensuring the file picker is visible on multi monitor
+// systems, and when the screen resolution changes.
+#define MOZ_WM_ENSUREVISIBLE              (WM_APP + 14159)
 
 // GetWindowsVersion constants
 #define WIN2K_VERSION                     0x500
 #define WINXP_VERSION                     0x501
 #define WIN2K3_VERSION                    0x502
 #define VISTA_VERSION                     0x600
 #define WIN7_VERSION                      0x601