зеркало из https://github.com/mozilla/gecko-dev.git
Bug 661991 - close file pickers when the parent window closes. r=ehsan
This commit is contained in:
Родитель
3599d7bb0d
Коммит
bba2d20be5
|
@ -63,6 +63,10 @@
|
|||
PRUnichar *nsFilePicker::mLastUsedUnicodeDirectory;
|
||||
char nsFilePicker::mLastUsedDirectory[MAX_PATH+1] = { 0 };
|
||||
|
||||
static const PRUnichar kDialogPtrProp[] = L"DialogPtrProperty";
|
||||
static const DWORD kDialogTimerID = 9999;
|
||||
static const unsigned long kDialogTimerTimeout = 300;
|
||||
|
||||
#define MAX_EXTENSION_LENGTH 10
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -158,11 +162,44 @@ private:
|
|||
nsRefPtr<nsWindow> mWindow;
|
||||
};
|
||||
|
||||
// Manages a simple callback timer
|
||||
class AutoTimerCallbackCancel
|
||||
{
|
||||
public:
|
||||
AutoTimerCallbackCancel(nsFilePicker* aTarget,
|
||||
nsTimerCallbackFunc aCallbackFunc) {
|
||||
Init(aTarget, aCallbackFunc);
|
||||
}
|
||||
|
||||
~AutoTimerCallbackCancel() {
|
||||
if (mPickerCallbackTimer) {
|
||||
mPickerCallbackTimer->Cancel();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
void Init(nsFilePicker* aTarget,
|
||||
nsTimerCallbackFunc aCallbackFunc) {
|
||||
mPickerCallbackTimer = do_CreateInstance("@mozilla.org/timer;1");
|
||||
if (!mPickerCallbackTimer) {
|
||||
NS_WARNING("do_CreateInstance for timer failed??");
|
||||
return;
|
||||
}
|
||||
mPickerCallbackTimer->InitWithFuncCallback(aCallbackFunc,
|
||||
aTarget,
|
||||
kDialogTimerTimeout,
|
||||
nsITimer::TYPE_REPEATING_SLACK);
|
||||
}
|
||||
nsCOMPtr<nsITimer> mPickerCallbackTimer;
|
||||
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// nsIFilePicker
|
||||
|
||||
nsFilePicker::nsFilePicker() :
|
||||
mSelectedType(1)
|
||||
, mDlgWnd(NULL)
|
||||
#if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
|
||||
, mFDECookie(0)
|
||||
#endif
|
||||
|
@ -181,6 +218,7 @@ nsFilePicker::~nsFilePicker()
|
|||
|
||||
NS_IMPL_ISUPPORTS1(nsFilePicker, nsIFilePicker)
|
||||
|
||||
|
||||
#if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
|
||||
STDMETHODIMP nsFilePicker::QueryInterface(REFIID refiid, void** ppvResult)
|
||||
{
|
||||
|
@ -238,23 +276,54 @@ EnsureWindowVisible(HWND hwnd)
|
|||
|
||||
// Callback hook which will ensure that the window is visible. Currently
|
||||
// only in use on os <= XP.
|
||||
static UINT_PTR CALLBACK
|
||||
FilePickerHook(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
||||
UINT_PTR CALLBACK
|
||||
nsFilePicker::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));
|
||||
switch(msg) {
|
||||
case 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);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case MOZ_WM_ENSUREVISIBLE:
|
||||
EnsureWindowVisible(GetParent(hwnd));
|
||||
break;
|
||||
case WM_INITDIALOG:
|
||||
{
|
||||
OPENFILENAMEW* pofn = reinterpret_cast<OPENFILENAMEW*>(lParam);
|
||||
SetProp(hwnd, kDialogPtrProp, (HANDLE)pofn->lCustData);
|
||||
nsFilePicker* picker = reinterpret_cast<nsFilePicker*>(pofn->lCustData);
|
||||
if (picker) {
|
||||
picker->SetDialogHandle(hwnd);
|
||||
SetTimer(hwnd, kDialogTimerID, kDialogTimerTimeout, NULL);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case WM_TIMER:
|
||||
{
|
||||
// Check to see if our parent has been torn down, if so, we close too.
|
||||
if (wParam == kDialogTimerID) {
|
||||
nsFilePicker* picker =
|
||||
reinterpret_cast<nsFilePicker*>(GetProp(hwnd, kDialogPtrProp));
|
||||
if (picker && picker->ClosePickerIfNeeded(true)) {
|
||||
KillTimer(hwnd, kDialogTimerID);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -262,8 +331,11 @@ FilePickerHook(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
|||
|
||||
// Callback hook which will dynamically allocate a buffer large enough
|
||||
// for the file picker dialog. Currently only in use on os <= XP.
|
||||
static UINT_PTR CALLBACK
|
||||
MultiFilePickerHook(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
||||
UINT_PTR CALLBACK
|
||||
nsFilePicker::MultiFilePickerHook(HWND hwnd,
|
||||
UINT msg,
|
||||
WPARAM wParam,
|
||||
LPARAM lParam)
|
||||
{
|
||||
switch (msg) {
|
||||
case WM_INITDIALOG:
|
||||
|
@ -275,6 +347,15 @@ MultiFilePickerHook(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
|||
L"ComboBoxEx32", NULL );
|
||||
if(comboBox)
|
||||
SendMessage(comboBox, CB_LIMITTEXT, 0, 0);
|
||||
// Store our nsFilePicker ptr for future use
|
||||
OPENFILENAMEW* pofn = reinterpret_cast<OPENFILENAMEW*>(lParam);
|
||||
SetProp(hwnd, kDialogPtrProp, (HANDLE)pofn->lCustData);
|
||||
nsFilePicker* picker =
|
||||
reinterpret_cast<nsFilePicker*>(pofn->lCustData);
|
||||
if (picker) {
|
||||
picker->SetDialogHandle(hwnd);
|
||||
SetTimer(hwnd, kDialogTimerID, kDialogTimerTimeout, NULL);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case WM_NOTIFY:
|
||||
|
@ -327,6 +408,18 @@ MultiFilePickerHook(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
|||
}
|
||||
}
|
||||
break;
|
||||
case WM_TIMER:
|
||||
{
|
||||
// Check to see if our parent has been torn down, if so, we close too.
|
||||
if (wParam == kDialogTimerID) {
|
||||
nsFilePicker* picker =
|
||||
reinterpret_cast<nsFilePicker*>(GetProp(hwnd, kDialogPtrProp));
|
||||
if (picker && picker->ClosePickerIfNeeded(true)) {
|
||||
KillTimer(hwnd, kDialogTimerID);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return FilePickerHook(hwnd, msg, wParam, lParam);
|
||||
|
@ -374,6 +467,21 @@ nsFilePicker::OnShareViolation(IFileDialog *pfd,
|
|||
HRESULT
|
||||
nsFilePicker::OnTypeChange(IFileDialog *pfd)
|
||||
{
|
||||
// Failures here result in errors due to security concerns.
|
||||
nsRefPtr<IOleWindow> win;
|
||||
pfd->QueryInterface(IID_IOleWindow, getter_AddRefs(win));
|
||||
if (!win) {
|
||||
NS_ERROR("Could not retrieve the IOleWindow interface for IFileDialog.");
|
||||
return S_OK;
|
||||
}
|
||||
HWND hwnd = NULL;
|
||||
win->GetWindow(&hwnd);
|
||||
if (!hwnd) {
|
||||
NS_ERROR("Could not retrieve the HWND for IFileDialog.");
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
SetDialogHandle(hwnd);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
@ -387,6 +495,54 @@ nsFilePicker::OnOverwrite(IFileDialog *pfd,
|
|||
|
||||
#endif // MOZ_NTDDI_LONGHORN
|
||||
|
||||
/*
|
||||
* Close on parent close logic
|
||||
*/
|
||||
|
||||
bool
|
||||
nsFilePicker::ClosePickerIfNeeded(bool aIsXPDialog)
|
||||
{
|
||||
if (!mParentWidget || !mDlgWnd)
|
||||
return false;
|
||||
|
||||
nsWindow *win = static_cast<nsWindow *>(mParentWidget.get());
|
||||
// Note, the xp callbacks hand us an inner window, so we have to step up
|
||||
// one to get the actual dialog.
|
||||
HWND dlgWnd;
|
||||
if (aIsXPDialog)
|
||||
dlgWnd = GetParent(mDlgWnd);
|
||||
else
|
||||
dlgWnd = mDlgWnd;
|
||||
if (IsWindow(dlgWnd) && IsWindowVisible(dlgWnd) && win->DestroyCalled()) {
|
||||
PRUnichar className[64];
|
||||
// Make sure we have the right window
|
||||
if (GetClassNameW(dlgWnd, className, mozilla::ArrayLength(className)) &&
|
||||
!wcscmp(className, L"#32770") &&
|
||||
DestroyWindow(dlgWnd)) {
|
||||
mDlgWnd = NULL;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
nsFilePicker::PickerCallbackTimerFunc(nsITimer *aTimer, void *aCtx)
|
||||
{
|
||||
nsFilePicker* picker = (nsFilePicker*)aCtx;
|
||||
if (picker->ClosePickerIfNeeded(false)) {
|
||||
aTimer->Cancel();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsFilePicker::SetDialogHandle(HWND aWnd)
|
||||
{
|
||||
if (!aWnd || mDlgWnd)
|
||||
return;
|
||||
mDlgWnd = aWnd;
|
||||
}
|
||||
|
||||
/*
|
||||
* Folder picker invocation
|
||||
*/
|
||||
|
@ -412,6 +568,7 @@ nsFilePicker::ShowXPFolderPicker(const nsString& aInitialDir)
|
|||
browserInfo.ulFlags = BIF_USENEWUI | BIF_RETURNONLYFSDIRS;
|
||||
browserInfo.hwndOwner = adtw.get();
|
||||
browserInfo.iImage = nsnull;
|
||||
browserInfo.lParam = reinterpret_cast<LPARAM>(this);
|
||||
|
||||
if (!aInitialDir.IsEmpty()) {
|
||||
// the dialog is modal so that |initialDir.get()| will be valid in
|
||||
|
@ -536,6 +693,7 @@ nsFilePicker::ShowXPFilePicker(const nsString& aInitialDir)
|
|||
ofn.lpstrFile = fileBuffer;
|
||||
ofn.nMaxFile = FILE_BUFFER_SIZE;
|
||||
ofn.hwndOwner = adtw.get();
|
||||
ofn.lCustData = reinterpret_cast<LPARAM>(this);
|
||||
ofn.Flags = OFN_SHAREAWARE | OFN_LONGNAMES | OFN_OVERWRITEPROMPT |
|
||||
OFN_HIDEREADONLY | OFN_PATHMUSTEXIST | OFN_ENABLESIZING |
|
||||
OFN_EXPLORER;
|
||||
|
@ -797,15 +955,18 @@ nsFilePicker::ShowFilePicker(const nsString& aInitialDir)
|
|||
|
||||
// display
|
||||
|
||||
AutoDestroyTmpWindow adtw((HWND)(mParentWidget.get() ?
|
||||
mParentWidget->GetNativeData(NS_NATIVE_TMP_WINDOW) : NULL));
|
||||
{
|
||||
AutoDestroyTmpWindow adtw((HWND)(mParentWidget.get() ?
|
||||
mParentWidget->GetNativeData(NS_NATIVE_TMP_WINDOW) : NULL));
|
||||
AutoTimerCallbackCancel atcc(this, PickerCallbackTimerFunc);
|
||||
AutoWidgetPickerState awps(mParentWidget);
|
||||
|
||||
AutoWidgetPickerState awps(mParentWidget);
|
||||
if (FAILED(dialog->Show(adtw.get()))) {
|
||||
if (FAILED(dialog->Show(adtw.get()))) {
|
||||
dialog->Unadvise(mFDECookie);
|
||||
return false;
|
||||
}
|
||||
dialog->Unadvise(mFDECookie);
|
||||
return false;
|
||||
}
|
||||
dialog->Unadvise(mFDECookie);
|
||||
|
||||
// results
|
||||
|
||||
|
|
|
@ -57,6 +57,7 @@
|
|||
#endif
|
||||
|
||||
#include "nsILocalFile.h"
|
||||
#include "nsITimer.h"
|
||||
#include "nsISimpleEnumerator.h"
|
||||
#include "nsCOMArray.h"
|
||||
#include "nsAutoPtr.h"
|
||||
|
@ -134,6 +135,11 @@ protected:
|
|||
bool IsPrivacyModeEnabled();
|
||||
bool IsDefaultPathLink();
|
||||
bool IsDefaultPathHtml();
|
||||
void SetDialogHandle(HWND aWnd);
|
||||
bool ClosePickerIfNeeded(bool aIsXPDialog);
|
||||
static void PickerCallbackTimerFunc(nsITimer *aTimer, void *aPicker);
|
||||
static UINT_PTR CALLBACK MultiFilePickerHook(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
|
||||
static UINT_PTR CALLBACK FilePickerHook(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
|
||||
|
||||
nsCOMPtr<nsIWidget> mParentWidget;
|
||||
nsString mTitle;
|
||||
|
@ -148,7 +154,7 @@ protected:
|
|||
static char mLastUsedDirectory[];
|
||||
nsString mUnicodeFile;
|
||||
static PRUnichar *mLastUsedUnicodeDirectory;
|
||||
DWORD mFDECookie;
|
||||
HWND mDlgWnd;
|
||||
|
||||
#if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
|
||||
class ComDlgFilterSpec
|
||||
|
@ -161,11 +167,11 @@ protected:
|
|||
free(mSpecList);
|
||||
}
|
||||
|
||||
PRUint32 Length() {
|
||||
const PRUint32 Length() {
|
||||
return mLength;
|
||||
}
|
||||
|
||||
bool IsEmpty() {
|
||||
const bool IsEmpty() {
|
||||
return (mLength == 0);
|
||||
}
|
||||
|
||||
|
@ -180,7 +186,8 @@ protected:
|
|||
PRUint32 mLength;
|
||||
};
|
||||
|
||||
ComDlgFilterSpec mComFilterList;
|
||||
ComDlgFilterSpec mComFilterList;
|
||||
DWORD mFDECookie;
|
||||
#endif
|
||||
};
|
||||
|
||||
|
|
|
@ -310,6 +310,7 @@ public:
|
|||
void PickerOpen();
|
||||
void PickerClosed();
|
||||
|
||||
bool const DestroyCalled() { return mDestroyCalled; }
|
||||
protected:
|
||||
|
||||
// A magic number to identify the FAKETRACKPOINTSCROLLABLE window created
|
||||
|
|
Загрузка…
Ссылка в новой задаче