feat: add session restore checkbox when quitting the browser

(cherry picked from commit 25890584ab485be765a2e4eff47e38f903a0ae24)
This commit is contained in:
Alex Kontos
2023-10-01 17:06:52 +01:00
parent c0f21b484c
commit 6d4862fcc8
9 changed files with 303 additions and 22 deletions

View File

@@ -11,7 +11,7 @@ ChromeUtils.defineESModuleGetters(lazy, {
}); });
ChromeUtils.defineLazyGetter(lazy, "gTabBrowserLocalization", function () { ChromeUtils.defineLazyGetter(lazy, "gTabBrowserLocalization", function () {
return new Localization(["browser/tabbrowser.ftl"], true); return new Localization(["browser/tabbrowser.ftl", "browser/waterfox.ftl"], true);
}); });
/** /**

View File

@@ -1532,6 +1532,18 @@ BrowserGlue.prototype = {
aQuitType = "quit"; aQuitType = "quit";
} }
let restoreSession;
let startupPref = Services.prefs.getIntPref("browser.startup.page");
// If we are set to anything other than restore session,
if (startupPref != 3) {
console.log("Value of: " + startupPref);
restoreSession = { value: false };
} else {
console.log("Value of: " + startupPref);
restoreSession = { value: true };
}
let win = lazy.BrowserWindowTracker.getTopWindow(); let win = lazy.BrowserWindowTracker.getTopWindow();
// Our prompt for quitting is most important, so replace others. // Our prompt for quitting is most important, so replace others.
@@ -1585,11 +1597,14 @@ BrowserGlue.prototype = {
checkboxLabelId = "tabbrowser-ask-close-tabs-checkbox"; checkboxLabelId = "tabbrowser-ask-close-tabs-checkbox";
} }
const [title, quitButtonLabel, checkboxLabel] = let checkboxLabelId2 = "tabbrowser-confirm-session-restore-checkbox";
const [title, quitButtonLabel, checkboxLabel, checkboxLabel2] =
win.gBrowser.tabLocalization.formatMessagesSync([ win.gBrowser.tabLocalization.formatMessagesSync([
titleId, titleId,
quitButtonLabelId, quitButtonLabelId,
checkboxLabelId, checkboxLabelId,
checkboxLabelId2,
]); ]);
// Only format the "close current tab" message if needed // Only format the "close current tab" message if needed
@@ -1621,7 +1636,7 @@ BrowserGlue.prototype = {
} }
// buttonPressed will be 0 for close all, 1 for cancel (don't close/quit), 2 for close current tab // buttonPressed will be 0 for close all, 1 for cancel (don't close/quit), 2 for close current tab
let buttonPressed = Services.prompt.confirmEx( let buttonPressed = Services.prompt.confirmEx2(
win, win,
title.value, title.value,
null, null,
@@ -1630,7 +1645,9 @@ BrowserGlue.prototype = {
null, null,
showCloseCurrentTabOption ? closeTabButtonLabel.value : null, showCloseCurrentTabOption ? closeTabButtonLabel.value : null,
checkboxLabel.value, checkboxLabel.value,
warnOnClose warnOnClose,
checkboxLabel2.value,
restoreSession
); );
// If the user has unticked the box, and has confirmed closing, stop showing // If the user has unticked the box, and has confirmed closing, stop showing
@@ -1648,6 +1665,18 @@ BrowserGlue.prototype = {
win.gBrowser.removeTab(win.gBrowser.selectedTab); win.gBrowser.removeTab(win.gBrowser.selectedTab);
} }
// If we are set to anything other than restore session,
// leave its value.
if (buttonPressed == 0) {
if (!restoreSession.value) {
if (startupPref === 3) {
Services.prefs.setIntPref("browser.startup.page", 1);
}
} else if (restoreSession.value) {
Services.prefs.setIntPref("browser.startup.page", 3);
}
}
this._quitSource = "unknown"; this._quitSource = "unknown";
aCancelQuit.data = buttonPressed != 0; aCancelQuit.data = buttonPressed != 0;

View File

@@ -117,7 +117,7 @@
}); });
ChromeUtils.defineLazyGetter(this, "tabLocalization", () => { ChromeUtils.defineLazyGetter(this, "tabLocalization", () => {
return new Localization( return new Localization(
["browser/tabbrowser.ftl", "branding/brand.ftl"], ["browser/tabbrowser.ftl", "branding/brand.ftl", "browser/waterfox.ftl"],
true true
); );
}); });
@@ -3806,36 +3806,65 @@
// default to true: if it were false, we wouldn't get this far // default to true: if it were false, we wouldn't get this far
var warnOnClose = { value: true }; var warnOnClose = { value: true };
let restoreSession;
let startupPref = Services.prefs.getIntPref("browser.startup.page");
// If we are set to anything other than restore session,
// leave its value.
if (startupPref != 3) {
restoreSession = { value: false };
} else {
restoreSession = { value: true };
}
// focus the window before prompting. // focus the window before prompting.
// this will raise any minimized window, which will // this will raise any minimized window, which will
// make it obvious which window the prompt is for and will // make it obvious which window the prompt is for and will
// solve the problem of windows "obscuring" the prompt. // solve the problem of windows "obscuring" the prompt.
// see bug #350299 for more details // see bug #350299 for more details
window.focus(); window.focus();
const [title, button, checkbox] = this.tabLocalization.formatValuesSync([ const [title, button, checkbox, checkboxLabel2] = this.tabLocalization.formatValuesSync([
{ {
id: "tabbrowser-confirm-close-tabs-title", id: "tabbrowser-confirm-close-tabs-title",
args: { tabCount: tabsToClose }, args: { tabCount: tabsToClose },
}, },
{ id: "tabbrowser-confirm-close-tabs-button" }, { id: "tabbrowser-confirm-close-tabs-button" },
{ id: "tabbrowser-ask-close-tabs-checkbox" }, { id: "tabbrowser-ask-close-tabs-checkbox" },
{ id: "tabbrowser-confirm-session-restore-checkbox" }
]); ]);
let flags = let flags =
ps.BUTTON_TITLE_IS_STRING * ps.BUTTON_POS_0 + ps.BUTTON_TITLE_IS_STRING * ps.BUTTON_POS_0 +
ps.BUTTON_TITLE_CANCEL * ps.BUTTON_POS_1; ps.BUTTON_TITLE_CANCEL * ps.BUTTON_POS_1;
let checkboxLabel = let checkboxLabel =
aCloseTabs == this.closingTabsEnum.ALL ? checkbox : null; aCloseTabs == this.closingTabsEnum.ALL ? checkbox : null;
var buttonPressed = ps.confirmEx( var buttonPressed;
window, if (Services.prefs.getBoolPref("browser.tabs.warnOnCloseOtherTabs")) {
title, buttonPressed = ps.confirmEx(
null, window,
flags, title,
button, null,
null, flags,
null, button,
checkboxLabel, null,
warnOnClose null,
); checkboxLabel,
warnOnClose
);
} else if (Services.prefs.getBoolPref("browser.tabs.warnOnClose")) {
buttonPressed = ps.confirmEx2(
window,
title,
null,
flags,
button,
null,
null,
checkboxLabel,
warnOnClose,
checkboxLabel2,
restoreSession
);
}
var reallyClose = buttonPressed == 0; var reallyClose = buttonPressed == 0;
@@ -3848,6 +3877,16 @@
Services.prefs.setBoolPref(pref, false); Services.prefs.setBoolPref(pref, false);
} }
if (buttonPressed == 0) {
if (!restoreSession.value) {
if (startupPref === 3) {
Services.prefs.setIntPref("browser.startup.page", 1);
}
} else if (restoreSession.value) {
Services.prefs.setIntPref("browser.startup.page", 3);
}
}
return reallyClose; return reallyClose;
} }

View File

@@ -90,6 +90,17 @@ interface nsIPrompt : nsISupports
in wstring checkMsg, in wstring checkMsg,
inout boolean checkValue); inout boolean checkValue);
int32_t confirmEx2(in wstring dialogTitle,
in wstring text,
in unsigned long buttonFlags,
in wstring button0Title,
in wstring button1Title,
in wstring button2Title,
in wstring checkMsg,
inout boolean checkValue,
in wstring checkMsg2,
inout boolean checkValue2);
boolean prompt(in wstring dialogTitle, boolean prompt(in wstring dialogTitle,
in wstring text, in wstring text,
inout wstring value, inout wstring value,

View File

@@ -95,6 +95,7 @@ function commonDialogOnLoad() {
infoTitle: document.getElementById("infoTitle"), infoTitle: document.getElementById("infoTitle"),
infoIcon: document.getElementById("infoIcon"), infoIcon: document.getElementById("infoIcon"),
checkbox: document.getElementById("checkbox"), checkbox: document.getElementById("checkbox"),
checkbox2: document.getElementById("checkbox2"),
checkboxContainer: document.getElementById("checkboxContainer"), checkboxContainer: document.getElementById("checkboxContainer"),
button3: dialog.getButton("extra2"), button3: dialog.getButton("extra2"),
button2: dialog.getButton("extra1"), button2: dialog.getButton("extra1"),
@@ -140,6 +141,9 @@ function commonDialogOnLoad() {
case "checkbox": case "checkbox":
Dialog.onCheckbox(); Dialog.onCheckbox();
break; break;
case "checkbox2":
Dialog.onCheckbox2();
break;
} }
}); });

View File

@@ -92,6 +92,7 @@
<div /> <div />
<!-- spacer --> <!-- spacer -->
<xul:checkbox id="checkbox" /> <xul:checkbox id="checkbox" />
<xul:checkbox id="checkbox2" />
</div> </div>
</div> </div>
</dialog> </dialog>

View File

@@ -78,6 +78,28 @@ export class CommonDialog {
this.iconClass = ["question-icon"]; this.iconClass = ["question-icon"];
this.soundID = Ci.nsISound.EVENT_CONFIRM_DIALOG_OPEN; this.soundID = Ci.nsISound.EVENT_CONFIRM_DIALOG_OPEN;
break; break;
case "confirmEx2":
var numButtons2 = 0;
if (this.args.button0Label) {
numButtons2++;
}
if (this.args.button1Label) {
numButtons2++;
}
if (this.args.button2Label) {
numButtons2++;
}
if (this.args.button3Label) {
numButtons2++;
}
if (numButtons2 == 0) {
throw new Error("A dialog with no buttons? Can not haz.");
}
this.numButtons = numButtons2;
this.hasInputField = false;
this.iconClass = ["question-icon"];
this.soundID = Ci.nsISound.EVENT_CONFIRM_DIALOG_OPEN;
break;
case "prompt": case "prompt":
this.numButtons = 2; this.numButtons = 2;
this.iconClass = ["question-icon"]; this.iconClass = ["question-icon"];
@@ -171,13 +193,35 @@ export class CommonDialog {
let infoBody = this.ui.infoBody; let infoBody = this.ui.infoBody;
infoBody.appendChild(infoBody.ownerDocument.createTextNode(croppedMessage)); infoBody.appendChild(infoBody.ownerDocument.createTextNode(croppedMessage));
// WATERFOX: Check if both labels are undefined before deciding to hide the container.
// This first checks if both labels are undefined before hiding the container.
// If not, it shows the container and then proceeds to render each checkbox if its corresponding label is defined.
let label = this.args.checkLabel; let label = this.args.checkLabel;
if (label) { let label2 = this.args.checkLabel2;
// Only show the checkbox if label has a value.
if (!label && !label2) {
// Hide everything if both labels undefined
this.ui.checkboxContainer.hidden = true;
} else {
// Show container
this.ui.checkboxContainer.hidden = false; this.ui.checkboxContainer.hidden = false;
this.ui.checkboxContainer.clientTop; // style flush to assure binding is attached this.ui.checkboxContainer.clientTop;
this.setLabelForNode(this.ui.checkbox, label);
this.ui.checkbox.checked = this.args.checked; if (label) {
this.setLabelForNode(this.ui.checkbox, label);
this.ui.checkbox.hidden = false;
this.ui.checkbox.checked = this.args.checked;
} else {
this.ui.checkbox.hidden = true;
}
if (label2) {
this.setLabelForNode(this.ui.checkbox2, label2);
this.ui.checkbox2.hidden = false;
this.ui.checkbox2.checked = this.args.checked2;
} else {
this.ui.checkbox2.hidden = true;
}
} }
// set the icon // set the icon
@@ -310,6 +354,10 @@ export class CommonDialog {
this.args.checked = this.ui.checkbox.checked; this.args.checked = this.ui.checkbox.checked;
} }
onCheckbox2() {
this.args.checked2 = this.ui.checkbox2.checked;
}
onButton0() { onButton0() {
this.args.promptActive = false; this.args.promptActive = false;
this.args.ok = true; this.args.ok = true;

View File

@@ -312,6 +312,34 @@ Prompter.prototype = {
); );
}, },
confirmEx2(
domWin,
title,
text,
flags,
button0,
button1,
button2,
checkLabel,
checkValue,
checkLabel2,
checkValue2
) {
let p = this.pickPrompter({ domWin });
return p.confirmEx2(
title,
text,
flags,
button0,
button1,
button2,
checkLabel,
checkValue,
checkLabel2,
checkValue2
);
},
/** /**
* Puts up a dialog with up to 3 buttons and an optional, labeled checkbox. * Puts up a dialog with up to 3 buttons and an optional, labeled checkbox.
* @param {BrowsingContext} browsingContext - The browsing context the * @param {BrowsingContext} browsingContext - The browsing context the
@@ -1524,6 +1552,66 @@ class ModalPrompter {
return args.buttonNumClicked; return args.buttonNumClicked;
} }
confirmEx2(
title,
text,
flags,
button0,
button1,
button2,
checkLabel,
checkValue,
checkLabel2,
checkValue2,
extraArgs = {}
) {
if (!title) {
title = InternalPromptUtils.getLocalizedString("Confirm");
}
let args = {
promptType: "confirmEx2",
title,
text,
checkLabel,
checked: this.async ? checkValue : checkValue.value,
checkLabel2,
checked2: this.async ? checkValue2 : checkValue2.value,
ok: false,
buttonNumClicked: 1,
...extraArgs,
};
let [label0, label1, label2, defaultButtonNum, isDelayEnabled] =
InternalPromptUtils.confirmExHelper(flags, button0, button1, button2);
args.defaultButtonNum = defaultButtonNum;
args.enableDelay = isDelayEnabled;
if (label0) {
args.button0Label = label0;
if (label1) {
args.button1Label = label1;
if (label2) {
args.button2Label = label2;
}
}
}
if (this.async) {
return this.openPromptAsync(args, result => ({
checked: !!result.checked,
checked2: !!result.checked2,
buttonNumClicked: result.buttonNumClicked,
}));
}
this.openPromptSync(args);
checkValue.value = args.checked;
checkValue2.value = args.checked2;
return args.buttonNumClicked;
}
nsIPrompt_prompt(title, text, value, checkLabel, checkValue) { nsIPrompt_prompt(title, text, value, checkLabel, checkValue) {
if (!title) { if (!title) {
title = InternalPromptUtils.getLocalizedString("Prompt"); title = InternalPromptUtils.getLocalizedString("Prompt");

View File

@@ -363,6 +363,67 @@ interface nsIPromptService : nsISupports
in wstring aButton2Title, in wstring aButton2Title,
in wstring aCheckMsg, in wstring aCheckMsg,
inout boolean aCheckState); inout boolean aCheckState);
/**
* Puts up a dialog with up to 3 buttons and an optional, labeled checkbox.
*
* @param aParent
* The parent window or null.
* @param aDialogTitle
* Text to appear in the title of the dialog.
* @param aText
* Text to appear in the body of the dialog.
* @param aButtonFlags
* A combination of Button Flags.
* @param aButton0Title
* Used when button 0 uses TITLE_IS_STRING
* @param aButton1Title
* Used when button 1 uses TITLE_IS_STRING
* @param aButton2Title
* Used when button 2 uses TITLE_IS_STRING
* @param aCheckMsg
* Text to appear with the checkbox. Null if no checkbox.
* @param aCheckState
* Contains the initial checked state of the checkbox when this method
* is called and the final checked state after this method returns.
* @param aCheckMsg2
* A second text to appear with the checkbox. Null if no checkbox.
* @param aCheckState2
* Contains the initial checked state of the checkbox when this method
* is called and the final checked state after this method returns.
*
* @return index of the button pressed.
*
* Buttons are numbered 0 - 2. The implementation can decide whether the
* sequence goes from right to left or left to right. Button 0 is the
* default button unless one of the Button Default Flags is specified.
*
* A button may use a predefined title, specified by one of the Button Title
* Flags values. Each title value can be multiplied by a position value to
* assign the title to a particular button. If BUTTON_TITLE_IS_STRING is
* used for a button, the string parameter for that button will be used. If
* the value for a button position is zero, the button will not be shown.
*
* In general, aButtonFlags is constructed per the following example:
*
* aButtonFlags = (BUTTON_POS_0) * (BUTTON_TITLE_AAA) +
* (BUTTON_POS_1) * (BUTTON_TITLE_BBB) +
* BUTTON_POS_1_DEFAULT;
*
* where "AAA" and "BBB" correspond to one of the button titles.
*/
int32_t confirmEx2(in mozIDOMWindowProxy aParent,
in wstring aDialogTitle,
in wstring aText,
in unsigned long aButtonFlags,
in wstring aButton0Title,
in wstring aButton1Title,
in wstring aButton2Title,
in wstring aCheckMsg,
inout boolean aCheckState,
in wstring aCheckMsg2,
inout boolean aCheckState2);
/** /**
* Like confirmEx, but with a BrowsingContext as parent. * Like confirmEx, but with a BrowsingContext as parent.
* *