Merge mozilla-central to autoland. a=merge CLOSED TREE

This commit is contained in:
shindli 2019-10-09 13:38:28 +03:00
commit 84419a8c10
16 changed files with 188 additions and 969 deletions

View File

@ -7,29 +7,13 @@ const { XPCOMUtils } = ChromeUtils.import(
);
XPCOMUtils.defineLazyModuleGetters(this, {
AppConstants: "resource://gre/modules/AppConstants.jsm",
BrowserWindowTracker: "resource:///modules/BrowserWindowTracker.jsm",
PlacesUtils: "resource://gre/modules/PlacesUtils.jsm",
PrivateBrowsingUtils: "resource://gre/modules/PrivateBrowsingUtils.jsm",
Services: "resource://gre/modules/Services.jsm",
UrlbarTokenizer: "resource:///modules/UrlbarTokenizer.jsm",
AppConstants: "resource://gre/modules/AppConstants.jsm",
PlacesUtils: "resource://gre/modules/PlacesUtils.jsm",
});
XPCOMUtils.defineLazyServiceGetter(
this,
"gTouchBarUpdater",
"@mozilla.org/widget/touchbarupdater;1",
"nsITouchBarUpdater"
);
// For accessing TouchBarHelper methods from static contexts in this file.
XPCOMUtils.defineLazyServiceGetter(
this,
"gTouchBarHelper",
"@mozilla.org/widget/touchbarhelper;1",
"nsITouchBarHelper"
);
/**
* Executes a XUL command on the top window. Called by the callbacks in each
* TouchBarInput.
@ -40,7 +24,8 @@ XPCOMUtils.defineLazyServiceGetter(
* Intended to be shorter and more readable than the XUL command.
*/
function execCommand(commandName, telemetryKey) {
let command = TouchBarHelper.window.document.getElementById(commandName);
let win = BrowserWindowTracker.getTopWindow();
let command = win.document.getElementById(commandName);
if (command) {
command.doCommand();
}
@ -67,15 +52,6 @@ function hexToInt(hexString) {
return isNaN(val) ? null : val;
}
const kInputTypes = {
BUTTON: "button",
LABEL: "label",
MAIN_BUTTON: "mainButton",
POPOVER: "popover",
SCROLLVIEW: "scrollView",
SCRUBBER: "scrubber",
};
/**
* An object containing all implemented TouchBarInput objects.
*/
@ -83,25 +59,25 @@ const kBuiltInInputs = {
Back: {
title: "back",
image: "chrome://browser/skin/back.svg",
type: kInputTypes.BUTTON,
type: "button",
callback: () => execCommand("Browser:Back", "Back"),
},
Forward: {
title: "forward",
image: "chrome://browser/skin/forward.svg",
type: kInputTypes.BUTTON,
type: "button",
callback: () => execCommand("Browser:Forward", "Forward"),
},
Reload: {
title: "reload",
image: "chrome://browser/skin/reload.svg",
type: kInputTypes.BUTTON,
type: "button",
callback: () => execCommand("Browser:Reload", "Reload"),
},
Home: {
title: "home",
image: "chrome://browser/skin/home.svg",
type: kInputTypes.BUTTON,
type: "button",
callback: () => {
let win = BrowserWindowTracker.getTopWindow();
win.BrowserHome();
@ -114,25 +90,25 @@ const kBuiltInInputs = {
Fullscreen: {
title: "fullscreen",
image: "chrome://browser/skin/fullscreen.svg",
type: kInputTypes.BUTTON,
type: "button",
callback: () => execCommand("View:FullScreen", "Fullscreen"),
},
Find: {
title: "find",
image: "chrome://browser/skin/search-glass.svg",
type: kInputTypes.BUTTON,
type: "button",
callback: () => execCommand("cmd_find", "Find"),
},
NewTab: {
title: "new-tab",
image: "chrome://browser/skin/add.svg",
type: kInputTypes.BUTTON,
type: "button",
callback: () => execCommand("cmd_newNavigatorTabNoEvent", "NewTab"),
},
Sidebar: {
title: "open-sidebar",
image: "chrome://browser/skin/sidebars.svg",
type: kInputTypes.BUTTON,
type: "button",
callback: () => {
let win = BrowserWindowTracker.getTopWindow();
win.SidebarUI.toggle();
@ -145,88 +121,31 @@ const kBuiltInInputs = {
AddBookmark: {
title: "add-bookmark",
image: "chrome://browser/skin/bookmark-hollow.svg",
type: kInputTypes.BUTTON,
type: "button",
callback: () => execCommand("Browser:AddBookmarkAs", "AddBookmark"),
},
ReaderView: {
title: "reader-view",
image: "chrome://browser/skin/readerMode.svg",
type: kInputTypes.BUTTON,
type: "button",
callback: () => execCommand("View:ReaderView", "ReaderView"),
disabled: true, // Updated when the page is found to be Reader View-able.
},
OpenLocation: {
title: "open-location",
image: "chrome://browser/skin/search-glass.svg",
type: kInputTypes.MAIN_BUTTON,
type: "mainButton",
callback: () => execCommand("Browser:OpenLocation", "OpenLocation"),
},
// This is a special-case `type: kInputTypes.SCRUBBER` element.
// This is a special-case `type: "scrubber"` element.
// Scrubbers are not yet generally implemented.
// See follow-up bug 1502539.
Share: {
title: "share",
type: "scrubber",
image: "chrome://browser/skin/share.svg",
type: kInputTypes.SCRUBBER,
callback: () => execCommand("cmd_share", "Share"),
},
SearchPopover: {
title: "search-popover",
image: "chrome://browser/skin/search-glass.svg",
type: kInputTypes.POPOVER,
children: {
SearchScrollViewLabel: {
title: "search-search-in",
type: kInputTypes.LABEL,
},
SearchScrollView: {
key: "search-scrollview",
type: kInputTypes.SCROLLVIEW,
children: {
Bookmarks: {
title: "search-bookmarks",
type: kInputTypes.BUTTON,
callback: () =>
gTouchBarHelper.insertRestrictionInUrlbar(
UrlbarTokenizer.RESTRICT.BOOKMARK
),
},
History: {
title: "search-history",
type: kInputTypes.BUTTON,
callback: () =>
gTouchBarHelper.insertRestrictionInUrlbar(
UrlbarTokenizer.RESTRICT.HISTORY
),
},
OpenTabs: {
title: "search-opentabs",
type: kInputTypes.BUTTON,
callback: () =>
gTouchBarHelper.insertRestrictionInUrlbar(
UrlbarTokenizer.RESTRICT.OPENPAGE
),
},
Tags: {
title: "search-tags",
type: kInputTypes.BUTTON,
callback: () =>
gTouchBarHelper.insertRestrictionInUrlbar(
UrlbarTokenizer.RESTRICT.TAG
),
},
Titles: {
title: "search-titles",
type: kInputTypes.BUTTON,
callback: () =>
gTouchBarHelper.insertRestrictionInUrlbar(
UrlbarTokenizer.RESTRICT.TITLE
),
},
},
},
},
},
};
const kHelperObservers = new Set([
@ -235,8 +154,6 @@ const kHelperObservers = new Set([
"touchbar-location-change",
"quit-application",
"intl:app-locales-changed",
"urlbar-focus",
"urlbar-blur",
]);
/**
@ -248,20 +165,16 @@ class TouchBarHelper {
for (let topic of kHelperObservers) {
Services.obs.addObserver(this, topic);
}
// We cache our search popover since otherwise it is frequently
// created/destroyed for the urlbar-focus/blur events.
this._searchPopover = this.getTouchBarInput("SearchPopover");
}
destructor() {
this._searchPopover = null;
for (let topic of kHelperObservers) {
Services.obs.removeObserver(this, topic);
}
}
get activeTitle() {
let tabbrowser = TouchBarHelper.window.ownerGlobal.gBrowser;
let tabbrowser = this.window.ownerGlobal.gBrowser;
let activeTitle;
if (tabbrowser) {
activeTitle = tabbrowser.selectedBrowser.contentTitle;
@ -288,25 +201,15 @@ class TouchBarHelper {
return layoutItems;
}
static get window() {
get window() {
return BrowserWindowTracker.getTopWindow();
}
get isUrlbarFocused() {
return TouchBarHelper.window.gURLBar.focused;
}
static get baseWindow() {
return TouchBarHelper.window.docShell.treeOwner.QueryInterface(
Ci.nsIBaseWindow
);
get bookmarkingUI() {
return this.window.BookmarkingUI;
}
getTouchBarInput(inputName) {
if (inputName == "SearchPopover" && this._searchPopover) {
return this._searchPopover;
}
// inputName might be undefined if an input's context() returns undefined.
if (!inputName || !kBuiltInInputs.hasOwnProperty(inputName)) {
return null;
@ -324,13 +227,8 @@ class TouchBarHelper {
let inputData = kBuiltInInputs[inputName];
let item = new TouchBarInput(inputData);
// Skip localization if there is already a cached localized title or if
// no title is needed.
if (
kBuiltInInputs[inputName].hasOwnProperty("localTitle") ||
!kBuiltInInputs[inputName].hasOwnProperty("title")
) {
// Skip localization if there is already a cached localized title.
if (kBuiltInInputs[inputName].hasOwnProperty("localTitle")) {
return item;
}
@ -338,11 +236,15 @@ class TouchBarHelper {
this._l10n.formatValue(item.key).then(result => {
item.title = result;
kBuiltInInputs[inputName].localTitle = result; // Cache result.
// Checking TouchBarHelper.window since this callback can fire after all windows are closed.
if (TouchBarHelper.window) {
gTouchBarUpdater.updateTouchBarInputs(TouchBarHelper.baseWindow, [
item,
]);
// Checking this.window since this callback can fire after all windows are closed.
if (this.window) {
let baseWindow = this.window.docShell.treeOwner.QueryInterface(
Ci.nsIBaseWindow
);
let updater = Cc["@mozilla.org/widget/touchbarupdater;1"].getService(
Ci.nsITouchBarUpdater
);
updater.updateTouchBarInputs(baseWindow, [item]);
}
});
@ -357,7 +259,7 @@ class TouchBarHelper {
* Additional keys to values in the kBuiltInInputs object in this file.
*/
_updateTouchBarInputs(...inputNames) {
if (!TouchBarHelper.window) {
if (!this.window) {
return;
}
@ -370,23 +272,13 @@ class TouchBarHelper {
inputs.push(input);
}
gTouchBarUpdater.updateTouchBarInputs(TouchBarHelper.baseWindow, inputs);
}
/**
* Inserts a restriction token into the Urlbar ahead of the current typed
* search term.
* @param {string} restrictionToken
* The restriction token to be inserted into the Urlbar. Preferably
* sourced from UrlbarTokenizer.RESTRICT.
*/
insertRestrictionInUrlbar(restrictionToken) {
let searchString = TouchBarHelper.window.gURLBar.lastSearchString.trimStart();
if (Object.values(UrlbarTokenizer.RESTRICT).includes(searchString[0])) {
searchString = searchString.substring(1).trimStart();
}
TouchBarHelper.window.gURLBar.search(`${restrictionToken} ${searchString}`);
let baseWindow = this.window.docShell.treeOwner.QueryInterface(
Ci.nsIBaseWindow
);
let updater = Cc["@mozilla.org/widget/touchbarupdater;1"].getService(
Ci.nsITouchBarUpdater
);
updater.updateTouchBarInputs(baseWindow, inputs);
}
observe(subject, topic, data) {
@ -396,10 +288,8 @@ class TouchBarHelper {
// ReaderView button is disabled on every location change since
// Reader View must determine if the new page can be Reader Viewed.
kBuiltInInputs.ReaderView.disabled = !data.startsWith("about:reader");
kBuiltInInputs.Back.disabled = !TouchBarHelper.window.gBrowser
.canGoBack;
kBuiltInInputs.Forward.disabled = !TouchBarHelper.window.gBrowser
.canGoForward;
kBuiltInInputs.Back.disabled = !this.window.gBrowser.canGoBack;
kBuiltInInputs.Forward.disabled = !this.window.gBrowser.canGoForward;
this._updateTouchBarInputs("ReaderView", "Back", "Forward");
break;
case "bookmark-icon-updated":
@ -414,29 +304,8 @@ class TouchBarHelper {
kBuiltInInputs.ReaderView.disabled = false;
this._updateTouchBarInputs("ReaderView");
break;
case "urlbar-focus":
if (!this._searchPopover) {
this._searchPopover = this.getTouchBarInput("SearchPopover");
}
gTouchBarUpdater.showPopover(
TouchBarHelper.baseWindow,
this._searchPopover,
true
);
break;
case "urlbar-blur":
if (!this._searchPopover) {
this._searchPopover = this.getTouchBarInput("SearchPopover");
}
gTouchBarUpdater.showPopover(
TouchBarHelper.baseWindow,
this._searchPopover,
false
);
break;
case "intl:app-locales-changed":
// On locale change, refresh all inputs after loading new localTitle.
this._searchPopover = null;
for (let input in kBuiltInInputs) {
delete input.localTitle;
}
@ -458,6 +327,7 @@ helperProto._l10n = new Localization(["browser/touchbar/touchbar.ftl"]);
/**
* A representation of a Touch Bar input.
* Uses async update() in lieu of a constructor to accomodate async l10n code.
* @param {object} input
* An object representing a Touch Bar Input.
* Contains listed properties.
@ -471,46 +341,21 @@ helperProto._l10n = new Localization(["browser/touchbar/touchbar.ftl"]);
* One of `button`, `mainButton`.
* @param {Function} input.callback
* A callback invoked when a touchbar item is touched.
* @param {string} [input.color]
* @param {string} input.color (optional)
* A string in hex format specifying the button's background color.
* If omitted, the default background color is used.
* @param {bool} [input.disabled]
* @param {bool} input.disabled (optional)
* If `true`, the Touch Bar input is greyed out and inoperable.
* @param {Array} [input.children]
* An array of input objects that will be displayed as children of
* this input. Available only for types KInputTypes.POPOVER and
* kInputTypes.SCROLLVIEW.
*/
class TouchBarInput {
constructor(input) {
this._key = input.key || input.title;
this._key = input.title;
this._title = input.hasOwnProperty("localTitle") ? input.localTitle : "";
this._image = input.image;
this._type = input.type;
this._callback = input.callback;
this._color = hexToInt(input.color);
this._disabled = input.hasOwnProperty("disabled") ? input.disabled : false;
if (input.children) {
this._children = [];
let toLocalize = [];
for (let childData of Object.values(input.children)) {
let initializedChild = new TouchBarInput(childData);
if (!initializedChild) {
continue;
}
// Children's types are prepended by the parent's type. This is so we
// can uniquely identify a child input from a standalone input with
// the same name. (e.g. a button called "back" in a popover would be a
// "popover-button.back" vs. a "button.back").
initializedChild.type = input.type + "-" + initializedChild.type;
this._children.push(initializedChild);
// Skip l10n for inputs without a title or those already localized.
if (childData.title && childData.title != "") {
toLocalize.push(initializedChild);
}
}
this._localizeChildren(toLocalize);
}
}
get key() {
@ -523,7 +368,7 @@ class TouchBarInput {
this._title = title;
}
get image() {
return this._image ? PlacesUtils.toURI(this._image) : null;
return PlacesUtils.toURI(this._image);
}
set image(image) {
this._image = image;
@ -556,35 +401,6 @@ class TouchBarInput {
set disabled(disabled) {
this._disabled = disabled;
}
get children() {
if (!this._children) {
return null;
}
let children = Cc["@mozilla.org/array;1"].createInstance(
Ci.nsIMutableArray
);
for (let child of this._children) {
children.appendElement(child);
}
return children;
}
/**
* Apply Fluent l10n to child inputs.
* @param {Array} children An array of initialized TouchBarInputs.
*/
async _localizeChildren(children) {
let titles = await helperProto._l10n.formatValues(
children.map(child => ({ id: child.key }))
);
// In the TouchBarInput constuctor, we filtered so children contains only
// those inputs with titles to be localized. We can be confident that the
// results in titles match up with the inputs to be localized.
children.forEach(function(child, index) {
child.title = titles[index];
});
gTouchBarUpdater.updateTouchBarInputs(TouchBarHelper.baseWindow, children);
}
}
const inputProto = TouchBarInput.prototype;

View File

@ -2,5 +2,4 @@
support-files =
readerModeArticle.html
[browser_touchbar_searchrestrictions.js]
[browser_touchbar_tests.js]
[browser_touchbar_tests.js]

View File

@ -1,129 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
const { XPCOMUtils } = ChromeUtils.import(
"resource://gre/modules/XPCOMUtils.jsm"
);
XPCOMUtils.defineLazyModuleGetters(this, {
UrlbarTokenizer: "resource:///modules/UrlbarTokenizer.jsm",
});
XPCOMUtils.defineLazyServiceGetter(
this,
"TouchBarHelper",
"@mozilla.org/widget/touchbarhelper;1",
"nsITouchBarHelper"
);
add_task(async function insertTokens() {
const tests = [
{
input: "",
token: UrlbarTokenizer.RESTRICT.HISTORY,
expected: "^ ",
},
{
input: "mozilla",
token: UrlbarTokenizer.RESTRICT.HISTORY,
expected: "^ mozilla",
},
{
input: "mozilla",
token: UrlbarTokenizer.RESTRICT.BOOKMARK,
expected: "* mozilla",
},
{
input: "mozilla",
token: UrlbarTokenizer.RESTRICT.TAG,
expected: "+ mozilla",
},
{
input: "mozilla",
token: UrlbarTokenizer.RESTRICT.OPENPAGE,
expected: "% mozilla",
},
{
input: "mozilla",
token: UrlbarTokenizer.RESTRICT.TITLE,
expected: "# mozilla",
},
];
let win = BrowserWindowTracker.getTopWindow();
for (let { input, token, expected } of tests) {
win.gURLBar.search(input);
TouchBarHelper.insertRestrictionInUrlbar(token);
Assert.equal(
win.gURLBar.value,
expected,
"The search restriction token should have been entered."
);
}
});
add_task(async function existingTokens() {
const tests = [
{
input: "* mozilla",
token: UrlbarTokenizer.RESTRICT.HISTORY,
expected: "^ mozilla",
},
{
input: "+ mozilla",
token: UrlbarTokenizer.RESTRICT.BOOKMARK,
expected: "* mozilla",
},
{
input: "( $ ^ mozilla",
token: UrlbarTokenizer.RESTRICT.TAG,
expected: "+ ( $ ^ mozilla",
},
{
input: "^*+%?#$ mozilla",
token: UrlbarTokenizer.RESTRICT.TAG,
expected: "+ *+%?#$ mozilla",
},
];
let win = BrowserWindowTracker.getTopWindow();
for (let { input, token, expected } of tests) {
win.gURLBar.search(input);
TouchBarHelper.insertRestrictionInUrlbar(token);
Assert.equal(
win.gURLBar.value,
expected,
"The search restriction token should have been replaced."
);
}
});
add_task(async function stripSpaces() {
const tests = [
{
input: " ^ mozilla",
token: UrlbarTokenizer.RESTRICT.HISTORY,
expected: "^ mozilla",
},
{
input: " + mozilla ",
token: UrlbarTokenizer.RESTRICT.BOOKMARK,
expected: "* mozilla ",
},
{
input: " moz illa ",
token: UrlbarTokenizer.RESTRICT.TAG,
expected: "+ moz illa ",
},
];
let win = BrowserWindowTracker.getTopWindow();
for (let { input, token, expected } of tests) {
win.gURLBar.search(input);
TouchBarHelper.insertRestrictionInUrlbar(token);
Assert.equal(
win.gURLBar.value,
expected,
"The search restriction token should have been entered " +
"with stripped whitespace."
);
}
});

View File

@ -983,14 +983,6 @@ class UrlbarInput {
return this._setValue(val, true);
}
get lastSearchString() {
return this._lastSearchString;
}
get openViewOnFocus() {
return this._openViewOnFocus;
}
get openViewOnFocusForCurrentTab() {
return (
this._openViewOnFocusAndSearchString ||
@ -1782,8 +1774,6 @@ class UrlbarInput {
if (this.getAttribute("pageproxystate") != "valid") {
this.window.UpdatePopupNotificationsVisibility();
}
Services.obs.notifyObservers(null, "urlbar-blur");
}
_on_click(event) {
@ -1824,8 +1814,6 @@ class UrlbarInput {
if (this.getAttribute("pageproxystate") != "valid") {
this.window.UpdatePopupNotificationsVisibility();
}
Services.obs.notifyObservers(null, "urlbar-focus");
}
_on_mouseover(event) {

View File

@ -18,17 +18,3 @@ open-location = Search or enter address
share = Share
close-window = Close Window
open-sidebar = Sidebars
# This string describes shortcuts for search.
search-popover = Search shortcuts
# Describes searches limited to a specific scope
# (e.g. searching only in history).
search-search-in = Search in:
## Various categories of shortcuts for search.
search-bookmarks = Bookmarks
search-history = History
search-opentabs = Open Tabs
search-tags = Tags
search-titles = Titles
##

View File

@ -74,7 +74,6 @@ def Libxul(name, output_category=None):
LDFLAGS += ['-Wl,-U,_OBJC_CLASS_$_NSSharingServicePickerTouchBarItem']
LDFLAGS += ['-Wl,-U,_OBJC_METACLASS_$_NSTouchBar']
LDFLAGS += ['-Wl,-U,_OBJC_CLASS_$_NSCustomTouchBarItem']
LDFLAGS += ['-Wl,-U,_OBJC_CLASS_$_NSPopoverTouchBarItem']
LDFLAGS += ['-lresolv']
if CONFIG['MOZ_DEBUG_SYMBOLS'] and CONFIG['CC_TYPE'] == 'clang-cl':

View File

@ -25,10 +25,10 @@ using namespace mozilla::dom;
NSString* mType;
NSColor* mColor;
BOOL mDisabled;
NSTouchBarItemIdentifier mNativeIdentifier;
nsCOMPtr<nsITouchBarInputCallback> mCallback;
RefPtr<Document> mDocument;
BOOL mIsIconPositionSet;
NSMutableArray<TouchBarInput*>* mChildren;
}
- (NSString*)key;
@ -42,7 +42,6 @@ using namespace mozilla::dom;
- (nsCOMPtr<nsITouchBarInputCallback>)callback;
- (RefPtr<Document>)document;
- (BOOL)isIconPositionSet;
- (NSMutableArray<TouchBarInput*>*)children;
- (void)setKey:(NSString*)aKey;
- (void)setTitle:(NSString*)aTitle;
- (void)setImageURI:(nsCOMPtr<nsIURI>)aImageURI;
@ -50,10 +49,10 @@ using namespace mozilla::dom;
- (void)setType:(NSString*)aType;
- (void)setColor:(NSColor*)aColor;
- (void)setDisabled:(BOOL)aDisabled;
- (void)setNativeIdentifier:(NSString*)aNativeIdentifier;
- (void)setCallback:(nsCOMPtr<nsITouchBarInputCallback>)aCallback;
- (void)setDocument:(RefPtr<Document>)aDocument;
- (void)setIconPositionSet:(BOOL)aIsIconPositionSet;
- (void)setChildren:(NSMutableArray<TouchBarInput*>*)aChildren;
- (id)initWithKey:(NSString*)aKey
title:(NSString*)aTitle
@ -62,22 +61,12 @@ using namespace mozilla::dom;
callback:(nsCOMPtr<nsITouchBarInputCallback>)aCallback
color:(uint32_t)aColor
disabled:(BOOL)aDisabled
document:(RefPtr<Document>)aDocument
children:(nsCOMPtr<nsIArray>)aChildren;
document:(RefPtr<Document>)aDocument;
- (TouchBarInput*)initWithXPCOM:(nsCOMPtr<nsITouchBarInput>)aInput;
- (void)releaseJSObjects;
- (void)dealloc;
/**
* We make this helper method static so that other classes can query a
* TouchBarInput's nativeIdentifier (e.g. nsTouchBarUpdater looking up a
* popover in mappedLayoutItems).
*/
+ (NSTouchBarItemIdentifier)nativeIdentifierWithType:(NSString*)aType withKey:(NSString*)aKey;
@end
/**
@ -103,26 +92,12 @@ using namespace mozilla::dom;
*/
@property(strong) NSMutableDictionary<NSTouchBarItemIdentifier, TouchBarInput*>* mappedLayoutItems;
/**
* Stores buttons displayed in a NSScrollView. They must be stored separately
* because they are generic NSButtons and not NSTouchBarItems. As such, they
* cannot be retrieved with [NSTouchBar itemForIdentifier].
*/
@property(strong) NSMutableDictionary<NSTouchBarItemIdentifier, NSButton*>* scrollViewButtons;
/**
* Returns an instance of nsTouchBar based on implementation details
* fetched from the frontend through nsTouchBarHelper.
*/
- (instancetype)init;
/**
* If aInputs is not nil, a nsTouchBar containing the inputs specified is
* initialized. Otherwise, a nsTouchBar is initialized containing a default set
* of inputs.
*/
- (instancetype)initWithInputs:(NSMutableArray<TouchBarInput*>*)aInputs;
- (void)dealloc;
/**
@ -137,45 +112,18 @@ using namespace mozilla::dom;
/**
* Updates an input on the Touch Bar by redirecting to one of the specific
* TouchBarItem types updaters.
* Returns true if the input was successfully updated.
*/
- (bool)updateItem:(TouchBarInput*)aInput;
/**
* Helper function for updateItem. Checks to see if a given input exists within
* any of this Touch Bar's popovers and updates it if it exists.
*/
- (bool)maybeUpdatePopoverChild:(TouchBarInput*)aInput;
/**
* Helper function for updateItem. Checks to see if a given input exists within
* any of this Touch Bar's scroll views and updates it if it exists.
*/
- (bool)maybeUpdateScrollViewChild:(TouchBarInput*)aInput;
/**
* Helper function for updateItem. Replaces an item in the
* self.mappedLayoutItems dictionary.
*/
- (void)replaceMappedLayoutItem:(TouchBarInput*)aItem;
- (void)updateItem:(TouchBarInput*)aInput;
/**
* Update or create various subclasses of TouchBarItem.
*/
- (void)updateButton:(NSButton*)aButton input:(TouchBarInput*)aInput;
- (void)updateMainButton:(NSButton*)aMainButton input:(TouchBarInput*)aInput;
- (void)updatePopover:(NSPopoverTouchBarItem*)aPopoverItem input:(TouchBarInput*)aInput;
- (void)updateScrollView:(NSCustomTouchBarItem*)aScrollViewItem input:(TouchBarInput*)aInput;
- (void)updateLabel:(NSTextField*)aLabel input:(TouchBarInput*)aInput;
- (NSTouchBarItem*)updateButton:(NSCustomTouchBarItem*)aButton input:(TouchBarInput*)aInput;
- (NSTouchBarItem*)updateMainButton:(NSCustomTouchBarItem*)aMainButton input:(TouchBarInput*)aInput;
- (NSTouchBarItem*)makeShareScrubberForIdentifier:(NSTouchBarItemIdentifier)aIdentifier;
/**
* If aShowing is true, aPopover is shown. Otherwise, it is hidden.
*/
- (void)showPopover:(TouchBarInput*)aPopover showing:(bool)aShowing;
/**
* Redirects button actions to the appropriate handler.
* Redirects button actions to the appropriate handler and handles telemetry.
*/
- (void)touchBarAction:(id)aSender;

View File

@ -12,108 +12,72 @@
@implementation nsTouchBar
static const NSTouchBarItemIdentifier BaseIdentifier = @"com.mozilla.firefox.touchbar";
static NSTouchBarItemIdentifier CustomButtonIdentifier = @"com.mozilla.firefox.touchbar.button";
static NSTouchBarItemIdentifier CustomMainButtonIdentifier =
@"com.mozilla.firefox.touchbar.mainbutton";
static NSTouchBarItemIdentifier ScrubberIdentifier = @"com.mozilla.firefox.touchbar.scrubber";
// Non-JS scrubber implemention for the Share Scrubber,
// since it is defined by an Apple API.
static NSTouchBarItemIdentifier ShareScrubberIdentifier =
[TouchBarInput nativeIdentifierWithType:@"scrubber" withKey:@"share"];
// The search popover needs to show/hide depending on if the Urlbar is focused
// when it is created. We keep track of its identifier to accomodate this
// special handling.
static NSTouchBarItemIdentifier SearchPopoverIdentifier =
[TouchBarInput nativeIdentifierWithType:@"popover" withKey:@"search-popover"];
[ScrubberIdentifier stringByAppendingPathExtension:@"share"];
// Used to tie action strings to buttons.
static char sIdentifierAssociationKey;
static const NSArray<NSString*>* kAllowedInputTypes = @[
@"button",
@"mainButton",
@"scrubber",
@"popover",
@"scrollView",
@"label",
];
// The default space between inputs, used where layout is not automatic.
static const uint32_t kInputSpacing = 8;
// The width of buttons in Apple's Share ScrollView. We use this in our
// ScrollViews to give them a native appearance.
static const uint32_t kScrollViewButtonWidth = 144;
static const uint32_t kInputIconSize = 16;
// The system default width for Touch Bar inputs is 128px. This is double.
#define MAIN_BUTTON_WIDTH 256
#pragma mark - NSTouchBarDelegate
- (instancetype)init {
return [self initWithInputs:nil];
}
- (instancetype)initWithInputs:(NSMutableArray<TouchBarInput*>*)aInputs {
if ((self = [super init])) {
mTouchBarHelper = do_GetService(NS_TOUCHBARHELPER_CID);
if (!mTouchBarHelper) {
NS_ERROR("Unable to create Touch Bar Helper.");
return nil;
}
self.delegate = self;
// This customization identifier is how users' custom layouts are saved by macOS.
// If this changes, all users' layouts would be reset to the default layout.
self.customizationIdentifier = @"com.mozilla.firefox.touchbar.defaultbar";
self.mappedLayoutItems = [NSMutableDictionary dictionary];
self.customizationAllowedItemIdentifiers = nil;
nsCOMPtr<nsIArray> allItems;
if (!aInputs) {
// This customization identifier is how users' custom layouts are saved by macOS.
// If this changes, all users' layouts would be reset to the default layout.
self.customizationIdentifier = [BaseIdentifier stringByAppendingPathExtension:@"defaultbar"];
nsCOMPtr<nsIArray> allItems;
nsresult rv = mTouchBarHelper->GetAllItems(getter_AddRefs(allItems));
if (NS_FAILED(rv) || !allItems) {
return nil;
}
uint32_t itemCount = 0;
allItems->GetLength(&itemCount);
// This is copied to self.customizationAllowedItemIdentifiers.
// Required since [self.mappedItems allKeys] does not preserve order.
// One slot is added for the spacer item.
NSMutableArray* orderedIdentifiers = [NSMutableArray arrayWithCapacity:itemCount + 1];
for (uint32_t i = 0; i < itemCount; ++i) {
nsCOMPtr<nsITouchBarInput> input = do_QueryElementAt(allItems, i);
if (!input) {
continue;
}
TouchBarInput* convertedInput = [[TouchBarInput alloc] initWithXPCOM:input];
// Add new input to dictionary for lookup of properties in delegate.
self.mappedLayoutItems[[convertedInput nativeIdentifier]] = convertedInput;
orderedIdentifiers[i] = [convertedInput nativeIdentifier];
}
[orderedIdentifiers addObject:@"NSTouchBarItemIdentifierFlexibleSpace"];
self.customizationAllowedItemIdentifiers = [orderedIdentifiers copy];
NSArray* defaultItemIdentifiers = @[
[TouchBarInput nativeIdentifierWithType:@"button" withKey:@"back"],
[TouchBarInput nativeIdentifierWithType:@"button" withKey:@"forward"],
[TouchBarInput nativeIdentifierWithType:@"button" withKey:@"reload"],
[TouchBarInput nativeIdentifierWithType:@"mainButton" withKey:@"open-location"],
[TouchBarInput nativeIdentifierWithType:@"button" withKey:@"new-tab"],
ShareScrubberIdentifier, SearchPopoverIdentifier
];
self.defaultItemIdentifiers = [defaultItemIdentifiers copy];
} else {
NSMutableArray* defaultItemIdentifiers = [NSMutableArray arrayWithCapacity:[aInputs count]];
for (TouchBarInput* input in aInputs) {
self.mappedLayoutItems[[input nativeIdentifier]] = input;
[defaultItemIdentifiers addObject:[input nativeIdentifier]];
}
self.defaultItemIdentifiers = [defaultItemIdentifiers copy];
nsresult rv = mTouchBarHelper->GetAllItems(getter_AddRefs(allItems));
if (NS_FAILED(rv) || !allItems) {
return nil;
}
uint32_t itemCount = 0;
allItems->GetLength(&itemCount);
// This is copied to self.customizationAllowedItemIdentifiers. Required since
// [self.mappedItems allKeys] does not preserve order.
// One slot is added for the spacer item.
NSMutableArray* orderedIdentifiers = [NSMutableArray arrayWithCapacity:itemCount + 1];
for (uint32_t i = 0; i < itemCount; ++i) {
nsCOMPtr<nsITouchBarInput> input = do_QueryElementAt(allItems, i);
if (!input) {
continue;
}
TouchBarInput* convertedInput = [[TouchBarInput alloc] initWithXPCOM:input];
// Add new input to dictionary for lookup of properties in delegate.
self.mappedLayoutItems[[convertedInput nativeIdentifier]] = convertedInput;
orderedIdentifiers[i] = [convertedInput nativeIdentifier];
}
[orderedIdentifiers addObject:@"NSTouchBarItemIdentifierFlexibleSpace"];
NSArray* defaultItemIdentifiers = @[
[CustomButtonIdentifier stringByAppendingPathExtension:@"back"],
[CustomButtonIdentifier stringByAppendingPathExtension:@"forward"],
[CustomButtonIdentifier stringByAppendingPathExtension:@"reload"],
[CustomMainButtonIdentifier stringByAppendingPathExtension:@"open-location"],
[CustomButtonIdentifier stringByAppendingPathExtension:@"new-tab"], ShareScrubberIdentifier
];
self.defaultItemIdentifiers = [defaultItemIdentifiers copy];
self.customizationAllowedItemIdentifiers = [orderedIdentifiers copy];
}
return self;
@ -122,25 +86,11 @@ static const uint32_t kInputIconSize = 16;
- (void)dealloc {
for (NSTouchBarItemIdentifier identifier in self.mappedLayoutItems) {
NSTouchBarItem* item = [self itemForIdentifier:identifier];
if (!item) {
continue;
}
if ([item isKindOfClass:[NSPopoverTouchBarItem class]]) {
[(NSPopoverTouchBarItem*)item setCollapsedRepresentation:nil];
[(NSPopoverTouchBarItem*)item setCollapsedRepresentationImage:nil];
[(nsTouchBar*)[(NSPopoverTouchBarItem*)item popoverTouchBar] release];
} else if ([[item view] isKindOfClass:[NSScrollView class]]) {
[[(NSScrollView*)[item view] documentView] release];
}
[[item view] release];
[item release];
}
[self.defaultItemIdentifiers release];
[self.customizationAllowedItemIdentifiers release];
[self.scrollViewButtons removeAllObjects];
[self.scrollViewButtons release];
[self.mappedLayoutItems removeAllObjects];
[self.mappedLayoutItems release];
[super dealloc];
@ -148,20 +98,7 @@ static const uint32_t kInputIconSize = 16;
- (NSTouchBarItem*)touchBar:(NSTouchBar*)aTouchBar
makeItemForIdentifier:(NSTouchBarItemIdentifier)aIdentifier {
TouchBarInput* input = self.mappedLayoutItems[aIdentifier];
if (!input) {
return nil;
}
// Checking to see if our new item is of an accepted type.
if (![kAllowedInputTypes
containsObject:[[[input type] componentsSeparatedByString:@"-"] lastObject]]) {
return nil;
}
if ([[input type] hasSuffix:@"scrubber"]) {
// We check the identifier rather than the type here as a special case.
if ([aIdentifier hasPrefix:ScrubberIdentifier]) {
if (![aIdentifier isEqualToString:ShareScrubberIdentifier]) {
// We're only supporting the Share scrubber for now.
return nil;
@ -169,253 +106,86 @@ static const uint32_t kInputIconSize = 16;
return [self makeShareScrubberForIdentifier:aIdentifier];
}
if ([[input type] hasSuffix:@"popover"]) {
NSPopoverTouchBarItem* newPopoverItem =
[[NSPopoverTouchBarItem alloc] initWithIdentifier:aIdentifier];
// We initialize popoverTouchBar here because we only allow setting this
// property on popover creation. Updating popoverTouchBar for every update
// of the popover item would be very expensive.
newPopoverItem.popoverTouchBar = [[nsTouchBar alloc] initWithInputs:[input children]];
[self updatePopover:newPopoverItem input:input];
return newPopoverItem;
}
// Our new item, which will be initialized depending on aIdentifier.
NSCustomTouchBarItem* newItem = [[NSCustomTouchBarItem alloc] initWithIdentifier:aIdentifier];
if ([[input type] hasSuffix:@"scrollView"]) {
[self updateScrollView:newItem input:input];
return newItem;
} else if ([[input type] hasSuffix:@"label"]) {
NSTextField* label = [NSTextField labelWithString:@""];
[self updateLabel:label input:input];
newItem.view = label;
return newItem;
}
// The cases of a button or main button require the same setup.
NSButton* button = [NSButton buttonWithTitle:@"" target:self action:@selector(touchBarAction:)];
newItem.view = button;
NSCustomTouchBarItem* item = [[NSCustomTouchBarItem alloc] initWithIdentifier:aIdentifier];
item.view = button;
if ([[input type] hasSuffix:@"button"] && ![[input type] hasPrefix:@"scrollView"]) {
[self updateButton:button input:input];
} else if ([[input type] hasSuffix:@"mainButton"]) {
[self updateMainButton:button input:input];
TouchBarInput* input = self.mappedLayoutItems[aIdentifier];
if ([aIdentifier hasPrefix:CustomButtonIdentifier]) {
return [self updateButton:item input:input];
} else if ([aIdentifier hasPrefix:CustomMainButtonIdentifier]) {
return [self updateMainButton:item input:input];
}
return newItem;
return nil;
}
- (bool)updateItem:(TouchBarInput*)aInput {
- (void)updateItem:(TouchBarInput*)aInput {
NSTouchBarItem* item = [self itemForIdentifier:[aInput nativeIdentifier]];
// If we can't immediately find item, there are three possibilities:
// * It is a button in a ScrollView, which can't be found with itemForIdentifier; or
// * It is contained within a popover; or
// * It simply does not exist.
// We check for each possibility here.
if (!item) {
if ([self maybeUpdateScrollViewChild:aInput]) {
[self replaceMappedLayoutItem:aInput];
return true;
}
if ([self maybeUpdatePopoverChild:aInput]) {
[self replaceMappedLayoutItem:aInput];
return true;
}
return false;
}
item.customizationLabel = [aInput title];
if ([[aInput type] hasSuffix:@"button"]) {
[self updateButton:(NSButton*)item.view input:aInput];
} else if ([[aInput type] hasSuffix:@"mainButton"]) {
[self updateMainButton:(NSButton*)item.view input:aInput];
} else if ([[aInput type] hasSuffix:@"scrollView"]) {
[self updateScrollView:(NSCustomTouchBarItem*)item input:aInput];
} else if ([[aInput type] hasSuffix:@"popover"]) {
[self updatePopover:(NSPopoverTouchBarItem*)item input:aInput];
} else if ([[aInput type] hasSuffix:@"label"]) {
[self updateLabel:(NSTextField*)item.view input:aInput];
}
[self replaceMappedLayoutItem:aInput];
return true;
}
- (bool)maybeUpdatePopoverChild:(TouchBarInput*)aInput {
for (NSTouchBarItemIdentifier identifier in self.mappedLayoutItems) {
TouchBarInput* potentialPopover = self.mappedLayoutItems[identifier];
if (![[potentialPopover type] hasSuffix:@"popover"]) {
continue;
}
NSTouchBarItem* popover = [self itemForIdentifier:[potentialPopover nativeIdentifier]];
if (popover) {
if ([(nsTouchBar*)[(NSPopoverTouchBarItem*)popover popoverTouchBar] updateItem:aInput]) {
return true;
}
}
}
return false;
}
- (bool)maybeUpdateScrollViewChild:(TouchBarInput*)aInput {
NSButton* scrollViewButton = self.scrollViewButtons[[aInput nativeIdentifier]];
if (scrollViewButton) {
// ScrollView buttons are similar to mainButtons except for their width.
[self updateMainButton:scrollViewButton input:aInput];
uint32_t buttonSize =
MAX(scrollViewButton.attributedTitle.size.width + kInputIconSize + kInputSpacing,
kScrollViewButtonWidth);
[[scrollViewButton widthAnchor] constraintGreaterThanOrEqualToConstant:buttonSize].active = YES;
}
// Updating the TouchBarInput* in the ScrollView's mChildren array.
for (NSTouchBarItemIdentifier identifier in self.mappedLayoutItems) {
TouchBarInput* potentialScrollView = self.mappedLayoutItems[identifier];
if (![[potentialScrollView type] hasSuffix:@"scrollView"]) {
continue;
}
for (uint32_t i = 0; i < [[potentialScrollView children] count]; ++i) {
TouchBarInput* child = [potentialScrollView children][i];
if (![[child nativeIdentifier] isEqualToString:[aInput nativeIdentifier]]) {
continue;
}
[[potentialScrollView children] replaceObjectAtIndex:i withObject:aInput];
[child release];
return true;
}
}
return false;
}
- (void)replaceMappedLayoutItem:(TouchBarInput*)aItem {
[self.mappedLayoutItems[[aItem nativeIdentifier]] release];
self.mappedLayoutItems[[aItem nativeIdentifier]] = aItem;
}
- (void)updateButton:(NSButton*)aButton input:(TouchBarInput*)aInput {
if (!aButton || !aInput) {
return;
}
if ([[aInput nativeIdentifier] hasPrefix:CustomButtonIdentifier]) {
[self updateButton:(NSCustomTouchBarItem*)item input:aInput];
} else if ([[aInput nativeIdentifier] hasPrefix:CustomMainButtonIdentifier]) {
[self updateMainButton:(NSCustomTouchBarItem*)item input:aInput];
}
aButton.title = [aInput title];
[self.mappedLayoutItems[[aInput nativeIdentifier]] release];
self.mappedLayoutItems[[aInput nativeIdentifier]] = aInput;
}
- (NSTouchBarItem*)updateButton:(NSCustomTouchBarItem*)aButton input:(TouchBarInput*)aInput {
NSButton* button = (NSButton*)aButton.view;
if (!button) {
return nil;
}
button.title = [aInput title];
if (![aInput isIconPositionSet]) {
[aButton setImagePosition:NSImageOnly];
[button setImagePosition:NSImageOnly];
[aInput setIconPositionSet:true];
}
if ([aInput imageURI]) {
RefPtr<nsTouchBarInputIcon> icon = [aInput icon];
if (!icon) {
icon = new nsTouchBarInputIcon([aInput document], aButton);
icon = new nsTouchBarInputIcon([aInput document], button);
[aInput setIcon:icon];
}
icon->SetupIcon([aInput imageURI]);
}
[aButton setEnabled:![aInput isDisabled]];
[button setEnabled:![aInput isDisabled]];
if ([aInput color]) {
aButton.bezelColor = [aInput color];
button.bezelColor = [aInput color];
}
objc_setAssociatedObject(aButton, &sIdentifierAssociationKey, [aInput nativeIdentifier],
objc_setAssociatedObject(button, &sIdentifierAssociationKey, [aInput nativeIdentifier],
OBJC_ASSOCIATION_RETAIN);
aButton.customizationLabel = [aInput title];
return aButton;
}
- (void)updateMainButton:(NSButton*)aMainButton input:(TouchBarInput*)aInput {
if (!aMainButton || !aInput) {
return;
}
- (NSTouchBarItem*)updateMainButton:(NSCustomTouchBarItem*)aMainButton
input:(TouchBarInput*)aInput {
NSButton* button = (NSButton*)aMainButton.view;
// If empty, string is still being localized. Display a blank input instead.
if ([[aInput title] isEqualToString:@""]) {
[aMainButton setImagePosition:NSNoImage];
[button setImagePosition:NSNoImage];
} else {
[aMainButton setImagePosition:NSImageLeft];
[button setImagePosition:NSImageLeft];
}
aMainButton.imageHugsTitle = YES;
button.imageHugsTitle = YES;
[aInput setIconPositionSet:true];
[self updateButton:aMainButton input:aInput];
[aMainButton.widthAnchor constraintGreaterThanOrEqualToConstant:MAIN_BUTTON_WIDTH].active = YES;
[aMainButton setContentHuggingPriority:1.0
forOrientation:NSLayoutConstraintOrientationHorizontal];
}
- (void)updatePopover:(NSPopoverTouchBarItem*)aPopoverItem input:(TouchBarInput*)aInput {
if (!aPopoverItem || !aInput) {
return;
}
aPopoverItem.showsCloseButton = YES;
if ([aInput imageURI]) {
RefPtr<nsTouchBarInputIcon> icon = [aInput icon];
if (!icon) {
icon = new nsTouchBarInputIcon([aInput document], nil, nil, aPopoverItem);
[aInput setIcon:icon];
}
icon->SetupIcon([aInput imageURI]);
} else if ([aInput title]) {
aPopoverItem.collapsedRepresentationLabel = [aInput title];
} else {
aPopoverItem.collapsedRepresentation = nil;
}
}
- (void)updateScrollView:(NSCustomTouchBarItem*)aScrollViewItem input:(TouchBarInput*)aInput {
if (!aScrollViewItem || ![aInput children]) {
return;
}
NSMutableDictionary* constraintViews = [NSMutableDictionary dictionary];
NSView* documentView = [[NSView alloc] initWithFrame:NSZeroRect];
NSString* layoutFormat = @"H:|-8-";
NSSize size = NSMakeSize(kInputSpacing, 30);
// Layout strings allow only alphanumeric characters. We will use this
// NSCharacterSet to strip illegal characters.
NSCharacterSet* charactersToRemove = [[NSCharacterSet alphanumericCharacterSet] invertedSet];
for (TouchBarInput* childInput in [aInput children]) {
if (![[childInput type] hasSuffix:@"button"]) {
continue;
}
NSButton* button = [NSButton buttonWithTitle:[childInput title]
target:self
action:@selector(touchBarAction:)];
// ScrollView buttons are similar to mainButtons except for their width.
[self updateMainButton:button input:childInput];
uint32_t buttonSize = MAX(button.attributedTitle.size.width + kInputIconSize + kInputSpacing,
kScrollViewButtonWidth);
[[button widthAnchor] constraintGreaterThanOrEqualToConstant:buttonSize].active = YES;
self.scrollViewButtons[[childInput nativeIdentifier]] = button;
button.translatesAutoresizingMaskIntoConstraints = NO;
[documentView addSubview:button];
NSString* layoutKey = [[[childInput nativeIdentifier]
componentsSeparatedByCharactersInSet:charactersToRemove] componentsJoinedByString:@""];
// Iteratively create our layout string.
layoutFormat =
[layoutFormat stringByAppendingString:[NSString stringWithFormat:@"[%@]-8-", layoutKey]];
[constraintViews setObject:button forKey:layoutKey];
size.width += kInputSpacing + buttonSize;
}
layoutFormat = [layoutFormat stringByAppendingString:[NSString stringWithFormat:@"|"]];
NSArray* hConstraints =
[NSLayoutConstraint constraintsWithVisualFormat:layoutFormat
options:NSLayoutFormatAlignAllCenterY
metrics:nil
views:constraintViews];
NSScrollView* scrollView =
[[NSScrollView alloc] initWithFrame:CGRectMake(0, 0, size.width, size.height)];
[documentView setFrame:NSMakeRect(0, 0, size.width, size.height)];
[NSLayoutConstraint activateConstraints:hConstraints];
scrollView.documentView = documentView;
aScrollViewItem.view = scrollView;
}
- (void)updateLabel:(NSTextField*)aLabel input:aInput {
if (!aLabel || ![aInput title]) {
return;
}
[aLabel setStringValue:[aInput title]];
aMainButton = (NSCustomTouchBarItem*)[self updateButton:aMainButton input:aInput];
[button.widthAnchor constraintGreaterThanOrEqualToConstant:MAIN_BUTTON_WIDTH].active = YES;
[button setContentHuggingPriority:1.0 forOrientation:NSLayoutConstraintOrientationHorizontal];
return aMainButton;
}
- (NSTouchBarItem*)makeShareScrubberForIdentifier:(NSTouchBarItemIdentifier)aIdentifier {
@ -440,22 +210,6 @@ static const uint32_t kInputIconSize = 16;
return servicesItem;
}
- (void)showPopover:(TouchBarInput*)aPopover showing:(bool)aShowing {
if (!aPopover) {
return;
}
NSPopoverTouchBarItem* popoverItem =
(NSPopoverTouchBarItem*)[self itemForIdentifier:[aPopover nativeIdentifier]];
if (!popoverItem) {
return;
}
if (aShowing) {
[popoverItem showPopover:self];
} else {
[popoverItem dismissPopover:self];
}
}
- (void)touchBarAction:(id)aSender {
NSTouchBarItemIdentifier identifier =
objc_getAssociatedObject(aSender, &sIdentifierAssociationKey);
@ -482,23 +236,13 @@ static const uint32_t kInputIconSize = 16;
for (NSTouchBarItemIdentifier identifier in self.mappedLayoutItems) {
TouchBarInput* input = self.mappedLayoutItems[identifier];
if (!input) {
continue;
RefPtr<nsTouchBarInputIcon> icon = [input icon];
if (icon) {
icon->ReleaseJSObjects();
}
// Childless popovers contain the default Touch Bar as its popoverTouchBar.
// We check for [input children] since the default Touch Bar contains a
// popover (search-popover), so this would infinitely loop if there was no check.
if ([[input type] hasSuffix:@"popover"] && [input children]) {
NSTouchBarItem* item = [self itemForIdentifier:identifier];
[(nsTouchBar*)[(NSPopoverTouchBarItem*)item popoverTouchBar] releaseJSObjects];
}
[input setCallback:nil];
[input setDocument:nil];
[input setImageURI:nil];
[input releaseJSObjects];
}
}
@ -575,7 +319,7 @@ static const uint32_t kInputIconSize = 16;
return mDisabled;
}
- (NSTouchBarItemIdentifier)nativeIdentifier {
return [TouchBarInput nativeIdentifierWithType:mType withKey:mKey];
return mNativeIdentifier;
}
- (nsCOMPtr<nsITouchBarInputCallback>)callback {
return mCallback;
@ -586,9 +330,6 @@ static const uint32_t kInputIconSize = 16;
- (BOOL)isIconPositionSet {
return mIsIconPositionSet;
}
- (NSMutableArray<TouchBarInput*>*)children {
return mChildren;
}
- (void)setKey:(NSString*)aKey {
[aKey retain];
[mKey release];
@ -625,6 +366,12 @@ static const uint32_t kInputIconSize = 16;
mDisabled = aDisabled;
}
- (void)setNativeIdentifier:(NSTouchBarItemIdentifier)aNativeIdentifier {
[aNativeIdentifier retain];
[mNativeIdentifier release];
mNativeIdentifier = aNativeIdentifier;
}
- (void)setCallback:(nsCOMPtr<nsITouchBarInputCallback>)aCallback {
mCallback = aCallback;
}
@ -641,16 +388,6 @@ static const uint32_t kInputIconSize = 16;
mIsIconPositionSet = aIsIconPositionSet;
}
- (void)setChildren:(NSMutableArray<TouchBarInput*>*)aChildren {
[aChildren retain];
for (TouchBarInput* child in mChildren) {
[child releaseJSObjects];
}
[mChildren removeAllObjects];
[mChildren release];
mChildren = aChildren;
}
- (id)initWithKey:(NSString*)aKey
title:(NSString*)aTitle
imageURI:(nsCOMPtr<nsIURI>)aImageURI
@ -658,8 +395,7 @@ static const uint32_t kInputIconSize = 16;
callback:(nsCOMPtr<nsITouchBarInputCallback>)aCallback
color:(uint32_t)aColor
disabled:(BOOL)aDisabled
document:(RefPtr<Document>)aDocument
children:(nsCOMPtr<nsIArray>)aChildren {
document:(RefPtr<Document>)aDocument {
if (self = [super init]) {
[self setKey:aKey];
[self setTitle:aTitle];
@ -668,28 +404,29 @@ static const uint32_t kInputIconSize = 16;
[self setCallback:aCallback];
[self setDocument:aDocument];
[self setIconPositionSet:false];
[self setDisabled:aDisabled];
if (aColor) {
[self setColor:[NSColor colorWithDisplayP3Red:((aColor >> 16) & 0xFF) / 255.0
green:((aColor >> 8) & 0xFF) / 255.0
blue:((aColor)&0xFF) / 255.0
alpha:1.0]];
}
if (aChildren) {
uint32_t itemCount = 0;
aChildren->GetLength(&itemCount);
NSMutableArray* orderedChildren = [NSMutableArray arrayWithCapacity:itemCount];
for (uint32_t i = 0; i < itemCount; ++i) {
nsCOMPtr<nsITouchBarInput> child = do_QueryElementAt(aChildren, i);
if (!child) {
continue;
}
TouchBarInput* convertedChild = [[TouchBarInput alloc] initWithXPCOM:child];
if (convertedChild) {
orderedChildren[i] = convertedChild;
}
}
[self setChildren:orderedChildren];
[self setDisabled:aDisabled];
NSTouchBarItemIdentifier TypeIdentifier = @"";
if ([aType isEqualToString:@"scrubber"]) {
TypeIdentifier = ScrubberIdentifier;
} else if ([aType isEqualToString:@"mainButton"]) {
TypeIdentifier = CustomMainButtonIdentifier;
} else {
TypeIdentifier = CustomButtonIdentifier;
}
if (!aKey) {
[self setNativeIdentifier:TypeIdentifier];
} else if ([aKey isEqualToString:@"share"]) {
[self setNativeIdentifier:[TypeIdentifier stringByAppendingPathExtension:aKey]];
} else {
[self setNativeIdentifier:[TypeIdentifier stringByAppendingPathExtension:aKey]];
}
}
@ -745,12 +482,6 @@ static const uint32_t kInputIconSize = 16;
return nil;
}
nsCOMPtr<nsIArray> children;
rv = aInput->GetChildren(getter_AddRefs(children));
if (NS_FAILED(rv)) {
return nil;
}
return [self initWithKey:nsCocoaUtils::ToNSString(keyStr)
title:nsCocoaUtils::ToNSString(titleStr)
imageURI:imageURI
@ -758,20 +489,7 @@ static const uint32_t kInputIconSize = 16;
callback:callback
color:colorInt
disabled:(BOOL)disabled
document:document
children:children];
}
- (void)releaseJSObjects {
if (mIcon) {
mIcon->ReleaseJSObjects();
}
mCallback = nil;
mImageURI = nil;
mDocument = nil;
for (TouchBarInput* child in mChildren) {
[child releaseJSObjects];
}
document:document];
}
- (void)dealloc {
@ -783,18 +501,8 @@ static const uint32_t kInputIconSize = 16;
[mTitle release];
[mType release];
[mColor release];
[mChildren removeAllObjects];
[mChildren release];
[mNativeIdentifier release];
[super dealloc];
}
+ (NSTouchBarItemIdentifier)nativeIdentifierWithType:(NSString*)aType withKey:(NSString*)aKey {
NSTouchBarItemIdentifier identifier;
identifier = [BaseIdentifier stringByAppendingPathExtension:aType];
if (aKey) {
identifier = [identifier stringByAppendingPathExtension:aKey];
}
return identifier;
}
@end

View File

@ -26,9 +26,9 @@ class imgRequestProxy;
class nsTouchBarInputIcon : public nsIconLoaderObserver {
public:
explicit nsTouchBarInputIcon(
RefPtr<Document> aDocument, NSButton* aButton,
NSSharingServicePickerTouchBarItem* aShareScrubber = nil,
NSPopoverTouchBarItem* aPopoverItem = nil);
RefPtr<Document> aDocument,
NSButton* aButton,
NSSharingServicePickerTouchBarItem* aShareScrubber = nil);
private:
virtual ~nsTouchBarInputIcon();
@ -59,8 +59,6 @@ class nsTouchBarInputIcon : public nsIconLoaderObserver {
// NSSharingServicePickerTouchBarItem does not expose an NSButton* on which we
// can set the `image` property.
NSSharingServicePickerTouchBarItem* mShareScrubber;
// We accept a popover only as a special case.
NSPopoverTouchBarItem* mPopoverItem;
// The icon loader object should never outlive its creating
// nsTouchBarInputIcon object.
RefPtr<nsIconLoaderService> mIconLoader;

View File

@ -22,14 +22,10 @@ using namespace mozilla;
static const uint32_t kIconSize = 16;
static const CGFloat kHiDPIScalingFactor = 2.0f;
nsTouchBarInputIcon::nsTouchBarInputIcon(RefPtr<Document> aDocument, NSButton* aButton,
NSSharingServicePickerTouchBarItem* aShareScrubber,
NSPopoverTouchBarItem* aPopoverItem)
: mDocument(aDocument),
mSetIcon(false),
mButton(aButton),
mShareScrubber(aShareScrubber),
mPopoverItem(aPopoverItem) {
nsTouchBarInputIcon::nsTouchBarInputIcon(RefPtr<Document> aDocument,
NSButton* aButton,
NSSharingServicePickerTouchBarItem* aShareScrubber)
: mDocument(aDocument), mSetIcon(false), mButton(aButton), mShareScrubber(aShareScrubber) {
MOZ_COUNT_CTOR(nsTouchBarInputIcon);
}
@ -49,14 +45,13 @@ void nsTouchBarInputIcon::Destroy() {
mButton = nil;
mShareScrubber = nil;
mPopoverItem = nil;
}
nsresult nsTouchBarInputIcon::SetupIcon(nsCOMPtr<nsIURI> aIconURI) {
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
// Still don't have one, then something is wrong, get out of here.
if (!(mButton || mShareScrubber || mPopoverItem)) {
if (!(mButton || mShareScrubber)) {
NS_ERROR("No Touch Bar button");
return NS_ERROR_FAILURE;
}
@ -75,7 +70,6 @@ nsresult nsTouchBarInputIcon::SetupIcon(nsCOMPtr<nsIURI> aIconURI) {
// Load placeholder icon.
[mButton setImage:mIconLoader->GetNativeIconImage()];
[mShareScrubber setButtonImage:mIconLoader->GetNativeIconImage()];
[mPopoverItem setCollapsedRepresentationImage:mIconLoader->GetNativeIconImage()];
}
nsresult rv = mIconLoader->LoadIcon(aIconURI);
@ -85,7 +79,6 @@ nsresult nsTouchBarInputIcon::SetupIcon(nsCOMPtr<nsIURI> aIconURI) {
// been set. Clear it.
[mButton setImage:nil];
[mShareScrubber setButtonImage:nil];
[mPopoverItem setCollapsedRepresentationImage:nil];
}
mSetIcon = true;
@ -102,7 +95,6 @@ nsresult nsTouchBarInputIcon::SetupIcon(nsCOMPtr<nsIURI> aIconURI) {
nsresult nsTouchBarInputIcon::OnComplete(NSImage* aImage) {
[mButton setImage:aImage];
[mShareScrubber setButtonImage:aImage];
[mPopoverItem setCollapsedRepresentationImage:aImage];
[aImage release];
return NS_OK;

View File

@ -19,10 +19,6 @@
blue:(CGFloat)blue
alpha:(CGFloat)alpha;
@end
@interface NSTextField (NewConstructors)
+ (NSTextField*)labelWithString:(NSString*)stringValue;
@end
#endif // !defined(MAC_OS_X_VERSION_10_12)
#if !defined(MAC_OS_X_VERSION_10_12_2) || MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_12_2
@ -32,8 +28,6 @@
typedef NSString* NSTouchBarItemIdentifier;
__attribute__((weak_import)) @interface NSTouchBarItem : NSObject
@property(readonly) NSView* view;
@property(strong) NSString* customizationLabel;
- (instancetype)initWithIdentifier:(NSTouchBarItemIdentifier)aIdentifier;
@end
@ -47,6 +41,7 @@ __attribute__((weak_import)) @interface NSSharingServicePickerTouchBarItem : NST
__attribute__((weak_import)) @interface NSCustomTouchBarItem : NSTouchBarItem
@property(strong) NSView* view;
@property(strong) NSString* customizationLabel;
@end
@protocol NSTouchBarDelegate
@ -61,16 +56,6 @@ __attribute__((weak_import)) @interface NSTouchBar : NSObject
- (NSTouchBarItem*)itemForIdentifier:(NSTouchBarItemIdentifier)aIdentifier;
@end
__attribute__((weak_import)) @interface NSPopoverTouchBarItem : NSTouchBarItem
@property(strong) NSView* collapsedRepresentation;
@property(strong) NSImage* collapsedRepresentationImage;
@property(strong) NSString* collapsedRepresentationLabel;
@property(strong) NSTouchBar* popoverTouchBar;
@property BOOL showsCloseButton;
- (void)showPopover:(id)sender;
- (void)dismissPopover:(id)sender;
@end
@interface NSButton (TouchBarButton)
@property(strong) NSColor* bezelColor;
@end

View File

@ -6,7 +6,6 @@
#define nsTouchBarUpdater_h_
#include "nsITouchBarUpdater.h"
#include "nsCocoaWindow.h"
class nsTouchBarUpdater : public nsITouchBarUpdater {
public:
@ -17,7 +16,6 @@ class nsTouchBarUpdater : public nsITouchBarUpdater {
protected:
virtual ~nsTouchBarUpdater() {}
BaseWindow* GetCocoaWindow(nsIBaseWindow* aWindow);
};
#endif // nsTouchBarUpdater_h_

View File

@ -9,6 +9,7 @@
#include "nsTouchBarUpdater.h"
#include "nsTouchBarNativeAPIDefines.h"
#include "nsCocoaWindow.h"
#include "nsIArray.h"
#include "nsIBaseWindow.h"
#include "nsIWidget.h"
@ -27,11 +28,12 @@ NS_IMPL_ISUPPORTS(nsTouchBarUpdater, nsITouchBarUpdater);
NS_IMETHODIMP
nsTouchBarUpdater::UpdateTouchBarInputs(nsIBaseWindow* aWindow,
const nsTArray<RefPtr<nsITouchBarInput>>& aInputs) {
if (!sTouchBarIsInitialized) {
return NS_OK;
nsCOMPtr<nsIWidget> widget = nullptr;
aWindow->GetMainWidget(getter_AddRefs(widget));
if (!widget) {
return NS_ERROR_FAILURE;
}
BaseWindow* cocoaWin = nsTouchBarUpdater::GetCocoaWindow(aWindow);
BaseWindow* cocoaWin = (BaseWindow*)widget->GetNativeData(NS_NATIVE_WINDOW);
if (!cocoaWin) {
return NS_ERROR_FAILURE;
}
@ -52,42 +54,6 @@ nsTouchBarUpdater::UpdateTouchBarInputs(nsIBaseWindow* aWindow,
return NS_OK;
}
NS_IMETHODIMP
nsTouchBarUpdater::ShowPopover(nsIBaseWindow* aWindow, nsITouchBarInput* aPopover, bool aShowing) {
if (!sTouchBarIsInitialized || !aPopover) {
return NS_OK;
}
BaseWindow* cocoaWin = nsTouchBarUpdater::GetCocoaWindow(aWindow);
if (!cocoaWin) {
return NS_ERROR_FAILURE;
}
if ([cocoaWin respondsToSelector:@selector(touchBar)]) {
// We don't need to completely reinitialize the popover. We only need its
// identifier to look it up in [nsTouchBar mappedLayoutItems].
nsAutoString keyStr;
nsresult rv = aPopover->GetKey(keyStr);
if (NS_FAILED(rv)) {
return NS_ERROR_FAILURE;
}
NSString* key = nsCocoaUtils::ToNSString(keyStr);
nsAutoString typeStr;
rv = aPopover->GetType(typeStr);
if (NS_FAILED(rv)) {
return NS_ERROR_FAILURE;
}
NSString* type = nsCocoaUtils::ToNSString(typeStr);
TouchBarInput* popoverItem = [[(nsTouchBar*)cocoaWin.touchBar mappedLayoutItems]
objectForKey:[TouchBarInput nativeIdentifierWithType:type withKey:key]];
[(nsTouchBar*)cocoaWin.touchBar showPopover:popoverItem showing:aShowing];
}
return NS_OK;
}
NS_IMETHODIMP
nsTouchBarUpdater::EnterCustomizeMode() {
[NSApp toggleTouchBarCustomizationPalette:(id)this];
@ -100,19 +66,6 @@ nsTouchBarUpdater::IsTouchBarInitialized(bool* aResult) {
return NS_OK;
}
BaseWindow* nsTouchBarUpdater::GetCocoaWindow(nsIBaseWindow* aWindow) {
nsCOMPtr<nsIWidget> widget = nullptr;
aWindow->GetMainWidget(getter_AddRefs(widget));
if (!widget) {
return nil;
}
BaseWindow* cocoaWin = (BaseWindow*)widget->GetNativeData(NS_NATIVE_WINDOW);
if (!cocoaWin) {
return nil;
}
return cocoaWin;
}
// NOTE: This method is for internal unit tests only.
NS_IMETHODIMP
nsTouchBarUpdater::SetTouchBarInitialized(bool aIsInitialized) {

View File

@ -22,11 +22,6 @@ interface nsITouchBarHelper : nsISupports
*/
readonly attribute AString activeTitle;
/**
* Return true if the Urlbar has focus.
*/
readonly attribute boolean isUrlbarFocused;
/**
* Returns all available Touch Bar Inputs in an nsIArray
* of nsITouchBarInput objects.
@ -38,10 +33,4 @@ interface nsITouchBarHelper : nsISupports
* Exposed for testing.
*/
nsITouchBarInput getTouchBarInput(in string aInputName);
/**
* Inserts a search restriction string in the Urlbar.
* Exposed for testing.
*/
void insertRestrictionInUrlbar(in string aToken);
};

View File

@ -65,10 +65,4 @@ interface nsITouchBarInput : nsISupports
* an imgLoader to load our SVG icons.
*/
readonly attribute Document document;
/**
* An array containing an input's children.
* Available for type = ("scrollView" || "popover").
*/
attribute nsIArray children;
};

View File

@ -34,9 +34,4 @@ interface nsITouchBarUpdater : nsISupports
* sets this value after a Touch Bar is initialized on compatible Macs.
*/
void setTouchBarInitialized(in boolean aIsInitialized);
/**
* If aShowing is true, aPopover is shown. Otherwise, it is hidden.
*/
void showPopover(in nsIBaseWindow aWindow, in nsITouchBarInput aPopover, in boolean aShowing);
};