Bug 253950 - When the profile is locked, startup UI should be less confusing (not the profile manager) r=ben+darin

This commit is contained in:
bsmedberg%covad.net 2005-03-15 20:01:12 +00:00
Родитель e525d43d1b
Коммит c266bbcbdd
14 изменённых файлов: 228 добавлений и 37 удалений

Просмотреть файл

@ -136,7 +136,7 @@ nsProfileDirServiceProvider::SetProfileDir(nsIFile* aProfileDir)
dirToLock = do_QueryInterface(mNonSharedProfileDir);
else
dirToLock = do_QueryInterface(mProfileDir);
rv = mProfileDirLock->Lock(dirToLock);
rv = mProfileDirLock->Lock(dirToLock, nsnull);
if (NS_FAILED(rv))
return rv;
#endif

Просмотреть файл

@ -390,7 +390,8 @@ PR_BEGIN_MACRO \
}
#endif /* XP_UNIX */
nsresult nsProfileLock::Lock(nsILocalFile* aFile)
nsresult nsProfileLock::Lock(nsILocalFile* aProfileDir,
nsIProfileUnlocker* *aUnlocker)
{
#if defined (XP_MACOSX)
NS_NAMED_LITERAL_STRING(LOCKFILE_NAME, ".parentlock");
@ -403,17 +404,20 @@ nsresult nsProfileLock::Lock(nsILocalFile* aFile)
#endif
nsresult rv;
if (aUnlocker)
*aUnlocker = nsnull;
NS_ENSURE_STATE(!mHaveLock);
PRBool isDir;
rv = aFile->IsDirectory(&isDir);
rv = aProfileDir->IsDirectory(&isDir);
if (NS_FAILED(rv))
return rv;
if (!isDir)
return NS_ERROR_FILE_NOT_DIRECTORY;
nsCOMPtr<nsILocalFile> lockFile;
rv = aFile->Clone((nsIFile **)((void **)getter_AddRefs(lockFile)));
rv = aProfileDir->Clone((nsIFile **)((void **)getter_AddRefs(lockFile)));
if (NS_FAILED(rv))
return rv;
@ -491,8 +495,10 @@ nsresult nsProfileLock::Lock(nsILocalFile* aFile)
OPEN_ALWAYS,
FILE_FLAG_DELETE_ON_CLOSE,
nsnull);
if (mLockFileHandle == INVALID_HANDLE_VALUE)
if (mLockFileHandle == INVALID_HANDLE_VALUE) {
// XXXbsmedberg: provide a profile-unlocker here!
return NS_ERROR_FILE_ACCESS_DENIED;
}
#elif defined(XP_OS2)
nsCAutoString filePath;
rv = lockFile->GetNativePath(filePath);
@ -535,7 +541,7 @@ nsresult nsProfileLock::Lock(nsILocalFile* aFile)
}
#elif defined(XP_UNIX)
nsCOMPtr<nsIFile> oldLockFile;
rv = aFile->Clone(getter_AddRefs(oldLockFile));
rv = aProfileDir->Clone(getter_AddRefs(oldLockFile));
if (NS_SUCCEEDED(rv))
{
rv = oldLockFile->Append(OLD_LOCKFILE_NAME);

Просмотреть файл

@ -42,6 +42,8 @@
#include "nsILocalFile.h"
class nsIProfileUnlocker;
#if defined (XP_WIN)
#include <windows.h>
#endif
@ -69,7 +71,16 @@ public:
nsProfileLock& operator=(nsProfileLock& rhs);
nsresult Lock(nsILocalFile* aFile);
/**
* Attempt to lock a profile directory.
*
* @param aProfileDir [in] The profile directory to lock.
* @param aUnlocker [out] Optional. This is only returned when locking
* fails with NS_ERROR_FILE_ACCESS_DENIED, and may not
* be returned at all.
* @throws NS_ERROR_FILE_ACCESS_DENIED if the profile is locked.
*/
nsresult Lock(nsILocalFile* aProfileDir, nsIProfileUnlocker* *aUnlocker);
nsresult Unlock();
private:

Просмотреть файл

@ -53,6 +53,7 @@ XPIDLSRCS = \
nsIProfileInternal.idl \
nsIProfileStartupListener.idl \
nsISessionRoaming.idl \
nsIProfileUnlocker.idl \
$(NULL)
ifeq ($(OS_ARCH),WINNT)

Просмотреть файл

@ -0,0 +1,54 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Mozilla XULRunner.
*
* The Initial Developer of the Original Code is
* Benjamin Smedberg <benjamin@smedbergs.us>
*
* Portions created by the Initial Developer are Copyright (C) 2005
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "nsISupports.idl"
[scriptable, uuid(08923af1-e7a3-4fae-ba02-128502193994)]
interface nsIProfileUnlocker : nsISupports
{
const unsigned long ATTEMPT_QUIT = 0;
const unsigned long FORCE_QUIT = 1;
/**
* Try to unlock the specified profile by attempting or forcing the
* process that currently holds the lock to quit.
*
* @param aSeverity either ATTEMPT_QUIT or FORCE_QUIT
* @throws NS_ERROR_FAILURE if unlocking failed.
*/
void unlock(in unsigned long aSeverity);
};

Просмотреть файл

@ -506,11 +506,11 @@ nsProfile::LoadDefaultProfileDir(nsCString & profileURLStr, PRBool canInteract)
// If the profile is locked, we need the UI
nsCOMPtr<nsILocalFile> localFile(do_QueryInterface(curProfileDir));
nsProfileLock tempLock;
rv = tempLock.Lock(localFile);
rv = tempLock.Lock(localFile, nsnull);
if (NS_FAILED(rv))
profileURLStr = PROFILE_MANAGER_URL;
#endif
}
}
}
else
profileURLStr = PROFILE_SELECTION_URL;

Просмотреть файл

@ -1,12 +1,15 @@
# LOCALIZATION NOTE: Do not translate <html:br/>
restartTitle=Restart %S
restartMessage=%S is already running, but is not responding. To open a new window, you must restart %S.
profileTooltip=Profile: '%S' - Path: '%S'
pleaseSelectTitle=Select Profile
pleaseSelect=Please select a profile to begin %S, or create a new profile.
profileLockedTitle=Profile In Use
profileLocked=%S cannot use the profile "%S" because it is in use.\n\nPlease choose another profile or create a new one.
profileLocked2=%S cannot use the profile "%S" because it is in use.\n\nTo continue, close the running instance of %S or choose a different profile.
renameProfileTitle=Rename Profile
renameProfilePrompt=Rename the profile "%S" to:

Просмотреть файл

@ -247,7 +247,7 @@ function onFinish()
}
else {
// Use the newly created Profile.
var profileLock = profile.lock();
var profileLock = profile.lock(null);
var dialogParams = window.arguments[0].QueryInterface(I.nsIDialogParamBlock);
dialogParams.objects.insertElementAt(profileLock, 0, false);

Просмотреть файл

@ -117,12 +117,12 @@ function acceptDialog()
var profileLock;
try {
profileLock = selectedProfile.profile.lock();
profileLock = selectedProfile.profile.lock({ value: null });
}
catch (e) {
var lockedTitle = gProfileManagerBundle.getString("profileLockedTitle");
var locked =
gProfileManagerBundle.getFormattedString("profileLocked", [appName, selectedProfile.profile.name]);
gProfileManagerBundle.getFormattedString("profileLocked2", [appName, selectedProfile.profile.name, appName]);
gPromptService.alert(window, lockedTitle, locked);
return false;

Просмотреть файл

@ -39,6 +39,7 @@
interface nsILocalFile;
interface nsIToolkitProfile;
interface nsIProfileUnlocker;
/**
* Hold on to a profile lock. Once you release the last reference to this
@ -52,12 +53,29 @@ interface nsIProfileLock : nsISupports
void unlock();
};
[scriptable, uuid(87cea5c2-b9ed-44f9-8984-e75bc9f7134a)]
/**
* A interface representing a profile.
* @note THIS INTERFACE SHOULD BE IMPLEMENTED BY THE TOOLKIT CODE ONLY! DON'T
* EVEN THINK ABOUT IMPLEMENTING THIS IN JAVASCRIPT!
*/
[scriptable, uuid(0008686a-ee99-4a27-8f1b-190596f535b1)]
interface nsIToolkitProfile : nsISupports
{
readonly attribute nsILocalFile rootDir;
attribute AUTF8String name;
void remove(in boolean removeFiles);
nsIProfileLock lock();
/**
* Lock this profile using platform-specific locking methods.
*
* @param lockFile If locking fails, this may return a lockFile object
* which can be used in platform-specific ways to
* determine which process has the file locked. Null
* may be passed.
* @return An interface which holds a profile lock as long as you reference
* it.
* @throws NS_ERROR_FILE_ACCESS_DENIED if the profile was already locked.
*/
nsIProfileLock lock(out nsIProfileUnlocker aUnlocker);
};

Просмотреть файл

@ -81,10 +81,11 @@ public:
nsCOMPtr<nsToolkitProfile> mNext;
nsToolkitProfile *mPrev;
~nsToolkitProfile() { }
private:
nsToolkitProfile(const nsACString& aName, nsILocalFile* aFile,
nsToolkitProfile* aPrev);
~nsToolkitProfile() { }
friend class nsToolkitProfileLock;
@ -99,14 +100,13 @@ public:
NS_DECL_ISUPPORTS
NS_DECL_NSIPROFILELOCK
nsresult Init(nsToolkitProfile* aProfile);
nsresult Init(nsILocalFile* aDirectory);
nsresult Init(nsToolkitProfile* aProfile, nsIProfileUnlocker* *aUnlocker);
nsresult Init(nsILocalFile* aDirectory, nsIProfileUnlocker* *aUnlocker);
nsToolkitProfileLock() { }
private:
~nsToolkitProfileLock();
private:
nsCOMPtr<nsToolkitProfile> mProfile;
nsCOMPtr<nsILocalFile> mDirectory;
@ -242,7 +242,7 @@ nsToolkitProfile::Remove(PRBool removeFiles)
}
NS_IMETHODIMP
nsToolkitProfile::Lock(nsIProfileLock* *aResult)
nsToolkitProfile::Lock(nsIProfileUnlocker* *aUnlocker, nsIProfileLock* *aResult)
{
if (mLock) {
NS_ADDREF(*aResult = mLock);
@ -252,7 +252,7 @@ nsToolkitProfile::Lock(nsIProfileLock* *aResult)
nsCOMPtr<nsToolkitProfileLock> lock = new nsToolkitProfileLock();
if (!lock) return NS_ERROR_OUT_OF_MEMORY;
nsresult rv = lock->Init(this);
nsresult rv = lock->Init(this, aUnlocker);
if (NS_FAILED(rv)) return rv;
NS_ADDREF(*aResult = lock);
@ -262,10 +262,10 @@ nsToolkitProfile::Lock(nsIProfileLock* *aResult)
NS_IMPL_ISUPPORTS1(nsToolkitProfileLock, nsIProfileLock)
nsresult
nsToolkitProfileLock::Init(nsToolkitProfile* aProfile)
nsToolkitProfileLock::Init(nsToolkitProfile* aProfile, nsIProfileUnlocker* *aUnlocker)
{
nsresult rv;
rv = Init(aProfile->mFile);
rv = Init(aProfile->mFile, aUnlocker);
if (NS_SUCCEEDED(rv))
mProfile = aProfile;
@ -273,11 +273,11 @@ nsToolkitProfileLock::Init(nsToolkitProfile* aProfile)
}
nsresult
nsToolkitProfileLock::Init(nsILocalFile* aDirectory)
nsToolkitProfileLock::Init(nsILocalFile* aDirectory, nsIProfileUnlocker* *aUnlocker)
{
nsresult rv;
rv = mLock.Lock(aDirectory);
rv = mLock.Lock(aDirectory, aUnlocker);
if (NS_SUCCEEDED(rv))
mDirectory = aDirectory;
@ -523,16 +523,17 @@ NS_IMETHODIMP
nsToolkitProfileService::LockProfilePath(nsILocalFile* aDirectory,
nsIProfileLock* *aResult)
{
return NS_LockProfilePath(aDirectory, aResult);
return NS_LockProfilePath(aDirectory, nsnull, aResult);
}
nsresult
NS_LockProfilePath(nsILocalFile* aPath, nsIProfileLock* *aResult)
NS_LockProfilePath(nsILocalFile* aPath, nsIProfileUnlocker* *aUnlocker,
nsIProfileLock* *aResult)
{
nsCOMPtr<nsToolkitProfileLock> lock = new nsToolkitProfileLock();
if (!lock) return NS_ERROR_OUT_OF_MEMORY;
nsresult rv = lock->Init(aPath);
nsresult rv = lock->Init(aPath, aUnlocker);
if (NS_FAILED(rv)) return rv;
NS_ADDREF(*aResult = lock);

Просмотреть файл

@ -59,6 +59,7 @@ REQUIRES = \
embedcomponents \
extensions \
gfx \
intl \
js \
necko \
pref \

Просмотреть файл

@ -74,7 +74,10 @@
#include "nsIObserverService.h"
#include "nsINativeAppSupport.h"
#include "nsIProcess.h"
#include "nsIProfileUnlocker.h"
#include "nsIPromptService.h"
#include "nsIServiceManager.h"
#include "nsIStringBundle.h"
#include "nsISupportsPrimitives.h"
#include "nsITimelineService.h"
#include "nsIToolkitChromeRegistry.h"
@ -90,6 +93,7 @@
#include "nsCOMPtr.h"
#include "nsDirectoryServiceDefs.h"
#include "nsDirectoryServiceUtils.h"
#include "nsEmbedCID.h"
#include "nsNetUtil.h"
#include "nsXPCOM.h"
#include "nsXPIDLString.h"
@ -1082,7 +1086,78 @@ static nsresult LaunchChild(nsINativeAppSupport* aNative)
return NS_ERROR_LAUNCHED_CHILD_PROCESS;
}
static const char kProfileManagerURL[] = "chrome://mozapps/content/profile/profileSelection.xul";
static const char kProfileProperties[] =
"chrome://mozapps/locale/profile/profileSelection.properties";
static nsresult
ProfileLockedDialog(nsILocalFile* aProfileDir, nsIProfileUnlocker* aUnlocker,
nsINativeAppSupport* aNative, nsIProfileLock* *aResult)
{
nsresult rv;
ScopedXPCOMStartup xpcom;
rv = xpcom.Initialize();
NS_ENSURE_SUCCESS(rv, rv);
rv = xpcom.DoAutoreg();
rv |= xpcom.InitEventQueue();
rv |= xpcom.SetWindowCreator(aNative);
NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
{ //extra scoping is needed so we release these components before xpcom shutdown
nsCOMPtr<nsIStringBundleService> sbs
(do_GetService(NS_STRINGBUNDLE_CONTRACTID));
NS_ENSURE_TRUE(sbs, NS_ERROR_FAILURE);
nsCOMPtr<nsIStringBundle> sb;
sbs->CreateBundle(kProfileProperties, getter_AddRefs(sb));
NS_ENSURE_TRUE(sbs, NS_ERROR_FAILURE);
NS_ConvertUTF8toUTF16 appName(gAppData->appName);
const PRUnichar* params[] = {appName.get(), appName.get()};
nsXPIDLString killMessage;
sb->FormatStringFromName(NS_LITERAL_STRING("restartMessage").get(),
params, 2, getter_Copies(killMessage));
nsXPIDLString killTitle;
sb->FormatStringFromName(NS_LITERAL_STRING("restartTitle").get(),
params, 1, getter_Copies(killTitle));
if (!killMessage || !killTitle)
return NS_ERROR_FAILURE;
nsCOMPtr<nsIPromptService> ps
(do_GetService(NS_PROMPTSERVICE_CONTRACTID));
NS_ENSURE_TRUE(ps, NS_ERROR_FAILURE);
PRUint32 flags = nsIPromptService::BUTTON_TITLE_OK * nsIPromptService::BUTTON_POS_0;
if (aUnlocker) {
flags =
nsIPromptService::BUTTON_TITLE_CANCEL * nsIPromptService::BUTTON_POS_0 +
nsIPromptService::BUTTON_TITLE_IS_STRING * nsIPromptService::BUTTON_POS_1 +
nsIPromptService::BUTTON_POS_1_DEFAULT;
}
PRInt32 button;
rv = ps->ConfirmEx(nsnull, killTitle, killMessage, flags,
killTitle, nsnull, nsnull, nsnull, nsnull, &button);
NS_ENSURE_SUCCESS(rv, rv);
if (button == 1 && aUnlocker) {
rv = aUnlocker->Unlock(nsIProfileUnlocker::FORCE_QUIT);
if (NS_FAILED(rv)) return rv;
return NS_LockProfilePath(aProfileDir, nsnull, aResult);
}
return NS_ERROR_ABORT;
}
}
static const char kProfileManagerURL[] =
"chrome://mozapps/content/profile/profileSelection.xul";
static nsresult
ShowProfileManager(nsIToolkitProfileService* aProfileSvc,
@ -1225,7 +1300,7 @@ SelectProfile(nsIProfileLock* *aResult, nsINativeAppSupport* aNative,
getter_AddRefs(lf));
NS_ENSURE_SUCCESS(rv, rv);
return NS_LockProfilePath(lf, aResult);
return NS_LockProfilePath(lf, nsnull, aResult);
}
if (CheckArg("migration"))
@ -1241,7 +1316,13 @@ SelectProfile(nsIProfileLock* *aResult, nsINativeAppSupport* aNative,
rv = NS_GetFileFromPath(arg, getter_AddRefs(lf));
NS_ENSURE_SUCCESS(rv, rv);
return NS_LockProfilePath(lf, aResult);
nsCOMPtr<nsIProfileUnlocker> unlocker;
rv = NS_LockProfilePath(lf, getter_AddRefs(unlocker), aResult);
if (NS_SUCCEEDED(rv))
return rv;
return ProfileLockedDialog(lf, unlocker, aNative, aResult);
}
nsCOMPtr<nsIToolkitProfileService> profileSvc;
@ -1309,9 +1390,16 @@ SelectProfile(nsIProfileLock* *aResult, nsINativeAppSupport* aNative,
rv = profileSvc->GetProfileByName(nsDependentCString(arg),
getter_AddRefs(profile));
if (NS_SUCCEEDED(rv)) {
rv = profile->Lock(aResult);
nsCOMPtr<nsIProfileUnlocker> unlocker;
rv = profile->Lock(nsnull, aResult);
if (NS_SUCCEEDED(rv))
return NS_OK;
nsCOMPtr<nsILocalFile> profileDir;
rv = profile->GetRootDir(getter_AddRefs(profileDir));
NS_ENSURE_SUCCESS(rv, rv);
return ProfileLockedDialog(profileDir, unlocker, aNative, aResult);
}
return ShowProfileManager(profileSvc, aNative);
@ -1321,7 +1409,6 @@ SelectProfile(nsIProfileLock* *aResult, nsINativeAppSupport* aNative,
return ShowProfileManager(profileSvc, aNative);
}
if (!count) {
gDoMigration = PR_TRUE;
@ -1332,7 +1419,7 @@ SelectProfile(nsIProfileLock* *aResult, nsINativeAppSupport* aNative,
getter_AddRefs(profile));
if (NS_SUCCEEDED(rv)) {
profileSvc->Flush();
rv = profile->Lock(aResult);
rv = profile->Lock(nsnull, aResult);
if (NS_SUCCEEDED(rv))
return NS_OK;
}
@ -1347,9 +1434,16 @@ SelectProfile(nsIProfileLock* *aResult, nsINativeAppSupport* aNative,
// GetSelectedProfile will auto-select the only profile if there's just one
profileSvc->GetSelectedProfile(getter_AddRefs(profile));
if (profile) {
rv = profile->Lock(aResult);
nsCOMPtr<nsIProfileUnlocker> unlocker;
rv = profile->Lock(getter_AddRefs(unlocker), aResult);
if (NS_SUCCEEDED(rv))
return NS_OK;
nsCOMPtr<nsILocalFile> profileDir;
rv = profile->GetRootDir(getter_AddRefs(profileDir));
NS_ENSURE_SUCCESS(rv, rv);
return ProfileLockedDialog(profileDir, unlocker, aNative, aResult);
}
}

Просмотреть файл

@ -65,6 +65,7 @@ class nsXREDirProvider;
class nsIToolkitProfileService;
class nsILocalFile;
class nsIProfileLock;
class nsIProfileUnlocker;
extern nsXREDirProvider* gDirServiceProvider;
extern const nsXREAppData* gAppData;
@ -90,7 +91,8 @@ NS_HIDDEN_(nsresult)
NS_GetFileFromPath(const char *aPath, nsILocalFile* *aResult);
NS_HIDDEN_(nsresult)
NS_LockProfilePath(nsILocalFile* aPath, nsIProfileLock* *aResult);
NS_LockProfilePath(nsILocalFile* aPath, nsIProfileUnlocker* *aUnlocker,
nsIProfileLock* *aResult);
#define NS_NATIVEAPPSUPPORT_CONTRACTID "@mozilla.org/toolkit/native-app-support;1"