forked from mirrors/gecko-dev
Bug 1563349 - Part 4 - Support NSPopoverTouchBarItem. r=spohl
Differential Revision: https://phabricator.services.mozilla.com/D47621 --HG-- extra : moz-landing-system : lando
This commit is contained in:
parent
dc2a166e28
commit
525bd39f48
9 changed files with 205 additions and 20 deletions
|
|
@ -74,6 +74,7 @@ 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':
|
||||
|
|
|
|||
|
|
@ -130,18 +130,37 @@ 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.
|
||||
*/
|
||||
- (void)updateItem:(TouchBarInput*)aInput;
|
||||
- (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. Replaces an item in the
|
||||
* self.mappedLayoutItems dictionary.
|
||||
*/
|
||||
- (void)replaceMappedLayoutItem:(TouchBarInput*)aItem;
|
||||
|
||||
/**
|
||||
* 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;
|
||||
- (NSTouchBarItem*)makeShareScrubberForIdentifier:(NSTouchBarItemIdentifier)aIdentifier;
|
||||
|
||||
/**
|
||||
* Redirects button actions to the appropriate handler and handles telemetry.
|
||||
* 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.
|
||||
*/
|
||||
- (void)touchBarAction:(id)aSender;
|
||||
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ static const NSArray<NSString*>* kAllowedInputTypes = @[
|
|||
@"button",
|
||||
@"mainButton",
|
||||
@"scrubber",
|
||||
@"popover",
|
||||
];
|
||||
|
||||
// The system default width for Touch Bar inputs is 128px. This is double.
|
||||
|
|
@ -106,6 +107,15 @@ static const NSArray<NSString*>* kAllowedInputTypes = @[
|
|||
- (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];
|
||||
}
|
||||
|
||||
[item release];
|
||||
}
|
||||
|
||||
|
|
@ -139,6 +149,17 @@ static const NSArray<NSString*>* kAllowedInputTypes = @[
|
|||
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];
|
||||
|
||||
|
|
@ -154,10 +175,14 @@ static const NSArray<NSString*>* kAllowedInputTypes = @[
|
|||
return newItem;
|
||||
}
|
||||
|
||||
- (void)updateItem:(TouchBarInput*)aInput {
|
||||
- (bool)updateItem:(TouchBarInput*)aInput {
|
||||
NSTouchBarItem* item = [self itemForIdentifier:[aInput nativeIdentifier]];
|
||||
if (!item) {
|
||||
return;
|
||||
if ([self maybeUpdatePopoverChild:aInput]) {
|
||||
[self replaceMappedLayoutItem:aInput];
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if ([[aInput type] hasSuffix:@"button"]) {
|
||||
|
|
@ -166,10 +191,34 @@ static const NSArray<NSString*>* kAllowedInputTypes = @[
|
|||
} else if ([[aInput type] hasSuffix:@"mainButton"]) {
|
||||
[(NSCustomTouchBarItem*)item setCustomizationLabel:[aInput title]];
|
||||
[self updateMainButton:(NSButton*)item.view input:aInput];
|
||||
} else if ([[aInput type] hasSuffix:@"popover"]) {
|
||||
[(NSPopoverTouchBarItem*)item setCustomizationLabel:[aInput title]];
|
||||
[self updatePopover:(NSPopoverTouchBarItem*)item input:aInput];
|
||||
}
|
||||
|
||||
[self.mappedLayoutItems[[aInput nativeIdentifier]] release];
|
||||
self.mappedLayoutItems[[aInput nativeIdentifier]] = 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;
|
||||
}
|
||||
|
||||
- (void)replaceMappedLayoutItem:(TouchBarInput*)aItem {
|
||||
[self.mappedLayoutItems[[aItem nativeIdentifier]] release];
|
||||
self.mappedLayoutItems[[aItem nativeIdentifier]] = aItem;
|
||||
}
|
||||
|
||||
- (void)updateButton:(NSButton*)aButton input:(TouchBarInput*)aInput {
|
||||
|
|
@ -220,6 +269,25 @@ static const NSArray<NSString*>* kAllowedInputTypes = @[
|
|||
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;
|
||||
}
|
||||
}
|
||||
|
||||
- (NSTouchBarItem*)makeShareScrubberForIdentifier:(NSTouchBarItemIdentifier)aIdentifier {
|
||||
TouchBarInput* input = self.mappedLayoutItems[aIdentifier];
|
||||
// System-default share menu
|
||||
|
|
@ -242,6 +310,22 @@ static const NSArray<NSString*>* kAllowedInputTypes = @[
|
|||
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);
|
||||
|
|
@ -271,6 +355,12 @@ static const NSArray<NSString*>* kAllowedInputTypes = @[
|
|||
if (!input) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ([[input type] hasSuffix:@"popover"]) {
|
||||
NSTouchBarItem* item = [self itemForIdentifier:identifier];
|
||||
[(nsTouchBar*)[(NSPopoverTouchBarItem*)item popoverTouchBar] releaseJSObjects];
|
||||
}
|
||||
|
||||
[input setCallback:nil];
|
||||
[input setDocument:nil];
|
||||
[input setImageURI:nil];
|
||||
|
|
|
|||
|
|
@ -26,9 +26,9 @@ class imgRequestProxy;
|
|||
class nsTouchBarInputIcon : public nsIconLoaderObserver {
|
||||
public:
|
||||
explicit nsTouchBarInputIcon(
|
||||
RefPtr<Document> aDocument,
|
||||
NSButton* aButton,
|
||||
NSSharingServicePickerTouchBarItem* aShareScrubber = nil);
|
||||
RefPtr<Document> aDocument, NSButton* aButton,
|
||||
NSSharingServicePickerTouchBarItem* aShareScrubber = nil,
|
||||
NSPopoverTouchBarItem* aPopoverItem = nil);
|
||||
|
||||
private:
|
||||
virtual ~nsTouchBarInputIcon();
|
||||
|
|
@ -59,6 +59,8 @@ 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;
|
||||
|
|
|
|||
|
|
@ -22,10 +22,14 @@ using namespace mozilla;
|
|||
static const uint32_t kIconSize = 16;
|
||||
static const CGFloat kHiDPIScalingFactor = 2.0f;
|
||||
|
||||
nsTouchBarInputIcon::nsTouchBarInputIcon(RefPtr<Document> aDocument,
|
||||
NSButton* aButton,
|
||||
NSSharingServicePickerTouchBarItem* aShareScrubber)
|
||||
: mDocument(aDocument), mSetIcon(false), mButton(aButton), mShareScrubber(aShareScrubber) {
|
||||
nsTouchBarInputIcon::nsTouchBarInputIcon(RefPtr<Document> aDocument, NSButton* aButton,
|
||||
NSSharingServicePickerTouchBarItem* aShareScrubber,
|
||||
NSPopoverTouchBarItem* aPopoverItem)
|
||||
: mDocument(aDocument),
|
||||
mSetIcon(false),
|
||||
mButton(aButton),
|
||||
mShareScrubber(aShareScrubber),
|
||||
mPopoverItem(aPopoverItem) {
|
||||
MOZ_COUNT_CTOR(nsTouchBarInputIcon);
|
||||
}
|
||||
|
||||
|
|
@ -45,13 +49,14 @@ 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)) {
|
||||
if (!(mButton || mShareScrubber || mPopoverItem)) {
|
||||
NS_ERROR("No Touch Bar button");
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
|
@ -70,6 +75,7 @@ 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);
|
||||
|
|
@ -79,6 +85,7 @@ nsresult nsTouchBarInputIcon::SetupIcon(nsCOMPtr<nsIURI> aIconURI) {
|
|||
// been set. Clear it.
|
||||
[mButton setImage:nil];
|
||||
[mShareScrubber setButtonImage:nil];
|
||||
[mPopoverItem setCollapsedRepresentationImage:nil];
|
||||
}
|
||||
|
||||
mSetIcon = true;
|
||||
|
|
@ -95,6 +102,7 @@ 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;
|
||||
|
|
|
|||
|
|
@ -58,6 +58,17 @@ __attribute__((weak_import)) @interface NSTouchBar : NSObject
|
|||
- (NSTouchBarItem*)itemForIdentifier:(NSTouchBarItemIdentifier)aIdentifier;
|
||||
@end
|
||||
|
||||
__attribute__((weak_import)) @interface NSPopoverTouchBarItem : NSTouchBarItem
|
||||
@property(strong) NSString* customizationLabel;
|
||||
@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
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
#define nsTouchBarUpdater_h_
|
||||
|
||||
#include "nsITouchBarUpdater.h"
|
||||
#include "nsCocoaWindow.h"
|
||||
|
||||
class nsTouchBarUpdater : public nsITouchBarUpdater {
|
||||
public:
|
||||
|
|
@ -16,6 +17,7 @@ class nsTouchBarUpdater : public nsITouchBarUpdater {
|
|||
|
||||
protected:
|
||||
virtual ~nsTouchBarUpdater() {}
|
||||
BaseWindow* GetCocoaWindow(nsIBaseWindow* aWindow);
|
||||
};
|
||||
|
||||
#endif // nsTouchBarUpdater_h_
|
||||
|
|
|
|||
|
|
@ -9,7 +9,6 @@
|
|||
#include "nsTouchBarUpdater.h"
|
||||
#include "nsTouchBarNativeAPIDefines.h"
|
||||
|
||||
#include "nsCocoaWindow.h"
|
||||
#include "nsIArray.h"
|
||||
#include "nsIBaseWindow.h"
|
||||
#include "nsIWidget.h"
|
||||
|
|
@ -28,12 +27,11 @@ NS_IMPL_ISUPPORTS(nsTouchBarUpdater, nsITouchBarUpdater);
|
|||
NS_IMETHODIMP
|
||||
nsTouchBarUpdater::UpdateTouchBarInputs(nsIBaseWindow* aWindow,
|
||||
const nsTArray<RefPtr<nsITouchBarInput>>& aInputs) {
|
||||
nsCOMPtr<nsIWidget> widget = nullptr;
|
||||
aWindow->GetMainWidget(getter_AddRefs(widget));
|
||||
if (!widget) {
|
||||
return NS_ERROR_FAILURE;
|
||||
if (!sTouchBarIsInitialized) {
|
||||
return NS_OK;
|
||||
}
|
||||
BaseWindow* cocoaWin = (BaseWindow*)widget->GetNativeData(NS_NATIVE_WINDOW);
|
||||
|
||||
BaseWindow* cocoaWin = nsTouchBarUpdater::GetCocoaWindow(aWindow);
|
||||
if (!cocoaWin) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
|
@ -54,6 +52,42 @@ 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];
|
||||
|
|
@ -66,6 +100,19 @@ 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) {
|
||||
|
|
|
|||
|
|
@ -34,4 +34,9 @@ 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);
|
||||
};
|
||||
|
|
|
|||
Loading…
Reference in a new issue