blob: 8b3dcd3298c6491f5d04c97beb2f872e66957279 [file] [log] [blame]
// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#import "chrome/browser/ui/cocoa/media_picker/desktop_media_picker_controller.h"
#include <utility>
#include "base/bind.h"
#include "base/command_line.h"
#import "base/mac/bundle_locations.h"
#include "base/strings/sys_string_conversions.h"
#include "base/task/post_task.h"
#include "chrome/browser/media/webrtc/desktop_media_list.h"
#include "chrome/browser/ui/browser_finder.h"
#include "chrome/browser/ui/browser_window.h"
#import "chrome/browser/ui/cocoa/key_equivalent_constants.h"
#import "chrome/browser/ui/cocoa/media_picker/desktop_media_picker_item.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/grit/chromium_strings.h"
#include "chrome/grit/generated_resources.h"
#include "components/strings/grit/components_strings.h"
#include "content/public/browser/browser_task_traits.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/web_contents.h"
#include "content/public/browser/web_contents_delegate.h"
#import "third_party/google_toolbox_for_mac/src/AppKit/GTMUILocalizerAndLayoutTweaker.h"
#import "ui/base/cocoa/flipped_view.h"
#import "ui/base/cocoa/window_size_constants.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/gfx/image/image_skia_util_mac.h"
using content::DesktopMediaID;
namespace {
const CGFloat kDesktopMediaPickerInitialContentWidth = 620;
const CGFloat kDesktopMediaPickerMinimumContentWidth = 500;
const CGFloat kDesktopMediaPickerMinimumContentHeight = 390;
const CGFloat kDesktopMediaPickerThumbnailWidth = 150;
const CGFloat kDesktopMediaPickerThumbnailHeight = 150;
const CGFloat kDesktopMediaPickerSingleScreenWidth = 300;
const CGFloat kDesktopMediaPickerSingleScreenHeight = 300;
const CGFloat kDesktopMediaPickerMultipleScreenWidth = 220;
const CGFloat kDesktopMediaPickerMultipleScreenHeight = 220;
const CGFloat kDesktopMediaPickerFramePadding = 20;
const CGFloat kDesktopMediaPickerControlSpacing = 10;
const CGFloat kDesktopMediaPickerExcessButtonPadding = 6;
const CGFloat kDesktopMediaPickerRowHeight = 20;
const CGFloat kDesktopMediaPickerRowWidth = 500;
const CGFloat kDesktopMediaPickerIconWidth = 20;
const CGFloat kDesktopMediaPickerPaddedWidth =
kDesktopMediaPickerInitialContentWidth -
(kDesktopMediaPickerFramePadding * 2);
const CGFloat kDesktopMediaPickerFontSize = 13;
NSString* const kDesktopMediaPickerIconId = @"icon";
NSString* const kDesktopMediaPickerTitleId = @"title";
} // namespace
@interface DesktopMediaPickerController ()
// Populate the window with controls and views.
- (void)initializeContentsWithParams:(const DesktopMediaPicker::Params&)params;
// Add |NSSegmentControl| for source type switch.
- (void)createTypeButtonAtOrigin:(NSPoint)origin;
// Add |IKImageBrowerView| for screen and window source view.
// Add |NSTableView| for tab source view.
- (void)createSourceViewsAtOrigin:(NSPoint)origin;
// Add check box for audio sharing.
- (void)createAudioCheckboxAtOrigin:(NSPoint)origin;
// Create the share and cancel button.
- (void)createActionButtonsAtOrigin:(NSPoint)origin;
// Create a |NSTextField| with label traits given |width|. Frame height is
// automatically adjusted to fit.
- (NSTextField*)createTextFieldWithText:(NSString*)text
frameWidth:(CGFloat)width;
// Create a button with |title|, with size adjusted to fit.
- (NSButton*)createButtonWithTitle:(NSString*)title;
- (IKImageBrowserView*)createImageBrowserWithSize:(NSSize)size;
// Report result by invoking |doneCallback_|. The callback is invoked only on
// the first call to |reportResult:|. Subsequent calls will be no-ops.
- (void)reportResult:(DesktopMediaID)sourceID;
// Action handlers.
- (void)sharePressed:(id)sender;
- (void)cancelPressed:(id)sender;
// Helper functions to get source type, or get data entities based on source
// type.
- (DesktopMediaID::Type)selectedSourceType;
- (DesktopMediaID::Type)sourceTypeForBrowser:(id)browser;
- (id)browserViewForType:(DesktopMediaID::Type)sourceType;
- (NSMutableArray*)itemSetForType:(DesktopMediaID::Type)sourceType;
- (NSInteger)selectedIndexForType:(DesktopMediaID::Type)sourceType;
- (void)setTabBrowserIndex:(NSInteger)index;
@end
@implementation DesktopMediaPickerController
- (id)initWithSourceLists:
(std::vector<std::unique_ptr<DesktopMediaList>>)sourceLists
callback:(const DesktopMediaPicker::DoneCallback&)callback
params:(const DesktopMediaPicker::Params&)params {
const NSUInteger kStyleMask =
NSTitledWindowMask | NSClosableWindowMask | NSResizableWindowMask;
base::scoped_nsobject<NSWindow> window(
[[NSWindow alloc] initWithContentRect:ui::kWindowSizeDeterminedLater
styleMask:kStyleMask
backing:NSBackingStoreBuffered
defer:NO]);
if ((self = [super initWithWindow:window])) {
NSWindow* parent = params.parent.GetNativeNSWindow();
[parent addChildWindow:window ordered:NSWindowAbove];
[window setDelegate:self];
sourceLists_ = std::move(sourceLists);
for (auto& sourceList : sourceLists_) {
switch (sourceList->GetMediaListType()) {
case DesktopMediaID::TYPE_NONE:
NOTREACHED();
break;
case DesktopMediaID::TYPE_SCREEN:
screenItems_.reset([[NSMutableArray alloc] init]);
break;
case DesktopMediaID::TYPE_WINDOW:
sourceList->SetViewDialogWindowId(DesktopMediaID(
DesktopMediaID::TYPE_WINDOW, [window windowNumber]));
windowItems_.reset([[NSMutableArray alloc] init]);
break;
case DesktopMediaID::TYPE_WEB_CONTENTS:
tabItems_.reset([[NSMutableArray alloc] init]);
break;
}
}
[self initializeContentsWithParams:params];
doneCallback_ = callback;
bridge_.reset(new DesktopMediaPickerBridge(self));
}
return self;
}
- (void)dealloc {
[shareButton_ setTarget:nil];
[cancelButton_ setTarget:nil];
[screenBrowser_ setDelegate:nil];
[screenBrowser_ setDataSource:nil];
[windowBrowser_ setDelegate:nil];
[windowBrowser_ setDataSource:nil];
[tabBrowser_ setDataSource:nil];
[tabBrowser_ setDelegate:nil];
[[self window] close];
[super dealloc];
}
- (void)initializeContentsWithParams:(const DesktopMediaPicker::Params&)params {
// Use flipped coordinates to facilitate manual layout.
base::scoped_nsobject<FlippedView> content(
[[FlippedView alloc] initWithFrame:NSZeroRect]);
[[self window] setContentView:content];
NSPoint origin = NSMakePoint(kDesktopMediaPickerFramePadding,
kDesktopMediaPickerFramePadding);
// Set the dialog's title.
NSString* titleText = l10n_util::GetNSString(IDS_DESKTOP_MEDIA_PICKER_TITLE);
[[self window] setTitle:titleText];
// Set the dialog's description.
NSString* descriptionText;
if (params.app_name == params.target_name) {
descriptionText =
l10n_util::GetNSStringF(IDS_DESKTOP_MEDIA_PICKER_TEXT, params.app_name);
} else {
descriptionText =
l10n_util::GetNSStringF(IDS_DESKTOP_MEDIA_PICKER_TEXT_DELEGATED,
params.app_name, params.target_name);
}
NSTextField* description =
[self createTextFieldWithText:descriptionText
frameWidth:kDesktopMediaPickerPaddedWidth];
[description setFrameOrigin:origin];
[content addSubview:description];
origin.y += NSHeight([description frame]) + kDesktopMediaPickerControlSpacing;
[self createTypeButtonAtOrigin:origin];
origin.y +=
NSHeight([sourceTypeControl_ frame]) + kDesktopMediaPickerControlSpacing;
[self createSourceViewsAtOrigin:origin];
origin.y +=
NSHeight([imageBrowserScroll_ frame]) + kDesktopMediaPickerControlSpacing;
if (params.request_audio) {
[self createAudioCheckboxAtOrigin:origin];
origin.y += NSHeight([audioShareCheckbox_ frame]) +
kDesktopMediaPickerControlSpacing;
if (params.approve_audio_by_default) {
[audioShareCheckbox_ setState:NSOnState];
} else {
[audioShareCheckbox_ setState:NSOffState];
}
}
[self createActionButtonsAtOrigin:origin];
origin.y += kDesktopMediaPickerFramePadding +
(NSHeight([cancelButton_ frame]) -
kDesktopMediaPickerExcessButtonPadding);
// Resize window to fit.
[content setAutoresizesSubviews:NO];
[[self window]
setContentSize:NSMakeSize(kDesktopMediaPickerInitialContentWidth,
origin.y)];
[[self window]
setContentMinSize:NSMakeSize(kDesktopMediaPickerMinimumContentWidth,
kDesktopMediaPickerMinimumContentHeight)];
[content setAutoresizesSubviews:YES];
// Initialize the type selection at the first segment.
[sourceTypeControl_ setSelected:YES forSegment:0];
[self typeButtonPressed:sourceTypeControl_];
[[self window]
makeFirstResponder:[self browserViewForType:[self selectedSourceType]]];
}
- (void)createTypeButtonAtOrigin:(NSPoint)origin {
// Create segmented button.
sourceTypeControl_.reset(
[[NSSegmentedControl alloc] initWithFrame:NSZeroRect]);
NSInteger segmentCount = sourceLists_.size();
[sourceTypeControl_ setSegmentCount:segmentCount];
NSInteger segmentIndex = 0;
for (auto& sourceList : sourceLists_) {
switch (sourceList->GetMediaListType()) {
case DesktopMediaID::TYPE_NONE:
NOTREACHED();
break;
case DesktopMediaID::TYPE_SCREEN:
[sourceTypeControl_
setLabel:l10n_util::GetNSString(
IDS_DESKTOP_MEDIA_PICKER_SOURCE_TYPE_SCREEN)
forSegment:segmentIndex];
[[sourceTypeControl_ cell] setTag:DesktopMediaID::TYPE_SCREEN
forSegment:segmentIndex];
break;
case DesktopMediaID::TYPE_WINDOW:
[sourceTypeControl_
setLabel:l10n_util::GetNSString(
IDS_DESKTOP_MEDIA_PICKER_SOURCE_TYPE_WINDOW)
forSegment:segmentIndex];
[[sourceTypeControl_ cell] setTag:DesktopMediaID::TYPE_WINDOW
forSegment:segmentIndex];
break;
case DesktopMediaID::TYPE_WEB_CONTENTS:
[sourceTypeControl_
setLabel:l10n_util::GetNSString(
IDS_DESKTOP_MEDIA_PICKER_SOURCE_TYPE_TAB)
forSegment:segmentIndex];
[[sourceTypeControl_ cell] setTag:DesktopMediaID::TYPE_WEB_CONTENTS
forSegment:segmentIndex];
break;
}
++segmentIndex;
}
[sourceTypeControl_ setTarget:self];
[sourceTypeControl_ setAction:@selector(typeButtonPressed:)];
[[sourceTypeControl_ cell] setTrackingMode:NSSegmentSwitchTrackingSelectOne];
[[[self window] contentView] addSubview:sourceTypeControl_];
[sourceTypeControl_ sizeToFit];
[sourceTypeControl_ setAutoresizingMask:NSViewMaxXMargin | NSViewMinXMargin];
CGFloat controlWidth = NSWidth([sourceTypeControl_ frame]);
CGFloat controlHeight = NSHeight([sourceTypeControl_ frame]);
NSRect centerFrame =
NSMakeRect((kDesktopMediaPickerInitialContentWidth - controlWidth) / 2,
origin.y, controlWidth, controlHeight);
[sourceTypeControl_ setFrame:NSIntegralRect(centerFrame)];
}
- (void)createSourceViewsAtOrigin:(NSPoint)origin {
for (auto& sourceList : sourceLists_) {
switch (sourceList->GetMediaListType()) {
case DesktopMediaID::TYPE_NONE: {
NOTREACHED();
break;
}
case DesktopMediaID::TYPE_SCREEN: {
const bool is_single = sourceList->GetSourceCount() <= 1;
const CGFloat width = is_single
? kDesktopMediaPickerSingleScreenWidth
: kDesktopMediaPickerMultipleScreenWidth;
const CGFloat height = is_single
? kDesktopMediaPickerSingleScreenHeight
: kDesktopMediaPickerMultipleScreenHeight;
screenBrowser_.reset([[self
createImageBrowserWithSize:NSMakeSize(width, height)] retain]);
break;
}
case DesktopMediaID::TYPE_WINDOW: {
windowBrowser_.reset([[self
createImageBrowserWithSize:NSMakeSize(
kDesktopMediaPickerThumbnailWidth,
kDesktopMediaPickerThumbnailHeight)]
retain]);
break;
}
case DesktopMediaID::TYPE_WEB_CONTENTS: {
tabBrowser_.reset([[NSTableView alloc] initWithFrame:NSZeroRect]);
[tabBrowser_ setDelegate:self];
[tabBrowser_ setDataSource:self];
[tabBrowser_ setAllowsMultipleSelection:NO];
[tabBrowser_ setRowHeight:kDesktopMediaPickerRowHeight];
[tabBrowser_ setDoubleAction:@selector(sharePressed:)];
base::scoped_nsobject<NSTableColumn> iconColumn([[NSTableColumn alloc]
initWithIdentifier:kDesktopMediaPickerIconId]);
[iconColumn setEditable:NO];
[iconColumn setWidth:kDesktopMediaPickerIconWidth];
[tabBrowser_ addTableColumn:iconColumn];
base::scoped_nsobject<NSTableColumn> titleColumn([[NSTableColumn alloc]
initWithIdentifier:kDesktopMediaPickerTitleId]);
[titleColumn setEditable:NO];
[titleColumn setWidth:kDesktopMediaPickerRowWidth];
[tabBrowser_ addTableColumn:titleColumn];
[tabBrowser_ setHeaderView:nil];
break;
}
}
}
// Create a scroll view to host the image browsers.
NSRect imageBrowserScrollFrame =
NSMakeRect(origin.x, origin.y, kDesktopMediaPickerPaddedWidth, 350);
imageBrowserScroll_.reset(
[[NSScrollView alloc] initWithFrame:imageBrowserScrollFrame]);
[imageBrowserScroll_ setHasVerticalScroller:YES];
[imageBrowserScroll_ setBorderType:NSBezelBorder];
[imageBrowserScroll_
setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
[[[self window] contentView] addSubview:imageBrowserScroll_];
}
- (void)createAudioCheckboxAtOrigin:(NSPoint)origin {
audioShareCheckbox_.reset([[NSButton alloc] initWithFrame:NSZeroRect]);
[audioShareCheckbox_ setFrameOrigin:origin];
[audioShareCheckbox_ setAutoresizingMask:NSViewMaxXMargin | NSViewMinYMargin];
[audioShareCheckbox_ setButtonType:NSSwitchButton];
[audioShareCheckbox_
setTitle:l10n_util::GetNSString(IDS_DESKTOP_MEDIA_PICKER_AUDIO_SHARE)];
[audioShareCheckbox_ sizeToFit];
[[[self window] contentView] addSubview:audioShareCheckbox_];
}
- (void)createActionButtonsAtOrigin:(NSPoint)origin {
FlippedView* content = [[self window] contentView];
// Create the share button.
shareButton_ =
[self createButtonWithTitle:l10n_util::GetNSString(
IDS_DESKTOP_MEDIA_PICKER_SHARE)];
origin.x =
kDesktopMediaPickerInitialContentWidth - kDesktopMediaPickerFramePadding -
(NSWidth([shareButton_ frame]) - kDesktopMediaPickerExcessButtonPadding);
[shareButton_ setEnabled:NO];
[shareButton_ setFrameOrigin:origin];
[shareButton_ setAutoresizingMask:NSViewMinXMargin | NSViewMinYMargin];
[shareButton_ setTarget:self];
[shareButton_ setKeyEquivalent:kKeyEquivalentEscape];
[shareButton_ setAction:@selector(sharePressed:)];
[content addSubview:shareButton_];
// Create the cancel button.
cancelButton_ =
[self createButtonWithTitle:l10n_util::GetNSString(IDS_CANCEL)];
origin.x -= kDesktopMediaPickerControlSpacing +
(NSWidth([cancelButton_ frame]) -
(kDesktopMediaPickerExcessButtonPadding * 2));
[cancelButton_ setFrameOrigin:origin];
[cancelButton_ setAutoresizingMask:NSViewMinXMargin | NSViewMinYMargin];
[cancelButton_ setTarget:self];
[cancelButton_ setKeyEquivalent:kKeyEquivalentReturn];
[cancelButton_ setAction:@selector(cancelPressed:)];
[content addSubview:cancelButton_];
}
- (NSTextField*)createTextFieldWithText:(NSString*)text
frameWidth:(CGFloat)width {
NSRect frame = NSMakeRect(0, 0, width, 1);
base::scoped_nsobject<NSTextField> textField(
[[NSTextField alloc] initWithFrame:frame]);
[textField setEditable:NO];
[textField setSelectable:YES];
[textField setDrawsBackground:NO];
[textField setBezeled:NO];
[textField setStringValue:text];
[textField setFont:[NSFont systemFontOfSize:kDesktopMediaPickerFontSize]];
[textField setAutoresizingMask:NSViewWidthSizable];
[GTMUILocalizerAndLayoutTweaker sizeToFitFixedWidthTextField:textField];
return textField.autorelease();
}
- (NSButton*)createButtonWithTitle:(NSString*)title {
base::scoped_nsobject<NSButton> button(
[[NSButton alloc] initWithFrame:NSZeroRect]);
[button setButtonType:NSMomentaryPushInButton];
[button setBezelStyle:NSRoundedBezelStyle];
[button setTitle:title];
[GTMUILocalizerAndLayoutTweaker sizeToFitView:button];
return button.autorelease();
}
- (IKImageBrowserView*)createImageBrowserWithSize:(NSSize)size {
NSUInteger cellStyle = IKCellsStyleShadowed | IKCellsStyleTitled;
base::scoped_nsobject<IKImageBrowserView> browser(
[[IKImageBrowserView alloc] initWithFrame:NSZeroRect]);
[browser setDelegate:self];
[browser setDataSource:self];
[browser setCellsStyleMask:cellStyle];
[browser setCellSize:size];
[browser setAllowsMultipleSelection:NO];
return browser.autorelease();
}
#pragma mark Event Actions
- (void)showWindow:(id)sender {
// Signal the source lists to start sending thumbnails. |bridge_| is used as
// the observer, and will forward notifications to this object.
for (auto& sourceList : sourceLists_) {
switch (sourceList->GetMediaListType()) {
case DesktopMediaID::TYPE_NONE: {
NOTREACHED();
break;
}
case DesktopMediaID::TYPE_SCREEN: {
sourceList->SetThumbnailSize(
gfx::Size(kDesktopMediaPickerSingleScreenWidth,
kDesktopMediaPickerSingleScreenHeight));
sourceList->StartUpdating(bridge_.get());
break;
}
case DesktopMediaID::TYPE_WINDOW: {
sourceList->SetThumbnailSize(
gfx::Size(kDesktopMediaPickerThumbnailWidth,
kDesktopMediaPickerThumbnailHeight));
sourceList->StartUpdating(bridge_.get());
break;
}
case DesktopMediaID::TYPE_WEB_CONTENTS: {
sourceList->SetThumbnailSize(gfx::Size(kDesktopMediaPickerIconWidth,
kDesktopMediaPickerRowHeight));
sourceList->StartUpdating(bridge_.get());
break;
}
}
}
[self.window center];
[super showWindow:sender];
}
- (void)reportResult:(DesktopMediaID)sourceID {
if (doneCallback_.is_null()) {
return;
}
sourceID.audio_share = ![audioShareCheckbox_ isHidden] &&
[audioShareCheckbox_ state] == NSOnState;
// If the media source is an tab, activate it.
if (sourceID.type == DesktopMediaID::TYPE_WEB_CONTENTS) {
content::WebContents* tab = content::WebContents::FromRenderFrameHost(
content::RenderFrameHost::FromID(
sourceID.web_contents_id.render_process_id,
sourceID.web_contents_id.main_render_frame_id));
if (tab) {
tab->GetDelegate()->ActivateContents(tab);
Browser* browser = chrome::FindBrowserWithWebContents(tab);
if (browser && browser->window())
browser->window()->Activate();
}
}
// Notify the |callback_| asynchronously because it may release the
// controller.
base::PostTaskWithTraits(FROM_HERE, {content::BrowserThread::UI},
base::Bind(doneCallback_, sourceID));
doneCallback_.Reset();
}
- (void)sharePressed:(id)sender {
DesktopMediaID::Type selectedType = [self selectedSourceType];
NSMutableArray* items = [self itemSetForType:selectedType];
NSInteger selectedIndex = [self selectedIndexForType:selectedType];
DesktopMediaPickerItem* item = [items objectAtIndex:selectedIndex];
[self reportResult:[item sourceID]];
[self close];
}
- (void)cancelPressed:(id)sender {
[self reportResult:DesktopMediaID()];
[self close];
}
- (void)typeButtonPressed:(id)sender {
DesktopMediaID::Type selectedType = [self selectedSourceType];
id browser = [self browserViewForType:selectedType];
[audioShareCheckbox_
setHidden:selectedType != DesktopMediaID::TYPE_WEB_CONTENTS];
[imageBrowserScroll_ setDocumentView:browser];
if (selectedType == DesktopMediaID::TYPE_WEB_CONTENTS) {
NSInteger selectedIndex = [self selectedIndexForType:selectedType];
[tabBrowser_ reloadData];
[self setTabBrowserIndex:selectedIndex];
} else {
[browser reloadData];
[self imageBrowserSelectionDidChange:browser];
}
}
#pragma mark Data Retrieve Helper
- (DesktopMediaID::Type)selectedSourceType {
NSInteger segment = [sourceTypeControl_ selectedSegment];
return static_cast<DesktopMediaID::Type>(
[[sourceTypeControl_ cell] tagForSegment:segment]);
}
- (DesktopMediaID::Type)sourceTypeForBrowser:(id)browser {
if (browser == screenBrowser_.get())
return DesktopMediaID::TYPE_SCREEN;
if (browser == windowBrowser_.get())
return DesktopMediaID::TYPE_WINDOW;
return DesktopMediaID::TYPE_WEB_CONTENTS;
}
- (id)browserViewForType:(DesktopMediaID::Type)sourceType {
switch (sourceType) {
case DesktopMediaID::TYPE_SCREEN:
return screenBrowser_;
case DesktopMediaID::TYPE_WINDOW:
return windowBrowser_;
case DesktopMediaID::TYPE_WEB_CONTENTS:
return tabBrowser_;
case DesktopMediaID::TYPE_NONE:
NOTREACHED();
return nil;
}
}
- (NSMutableArray*)itemSetForType:(DesktopMediaID::Type)sourceType {
switch (sourceType) {
case DesktopMediaID::TYPE_SCREEN:
return screenItems_;
case DesktopMediaID::TYPE_WINDOW:
return windowItems_;
case DesktopMediaID::TYPE_WEB_CONTENTS:
return tabItems_;
case DesktopMediaID::TYPE_NONE:
NOTREACHED();
return nil;
}
}
- (NSInteger)selectedIndexForType:(DesktopMediaID::Type)sourceType {
NSIndexSet* indexes = nil;
switch (sourceType) {
case DesktopMediaID::TYPE_SCREEN:
indexes = [screenBrowser_ selectionIndexes];
break;
case DesktopMediaID::TYPE_WINDOW:
indexes = [windowBrowser_ selectionIndexes];
break;
case DesktopMediaID::TYPE_WEB_CONTENTS:
indexes = [tabBrowser_ selectedRowIndexes];
break;
case DesktopMediaID::TYPE_NONE:
NOTREACHED();
}
if ([indexes count] == 0)
return -1;
return [indexes firstIndex];
}
- (void)setTabBrowserIndex:(NSInteger)index {
NSIndexSet* indexes;
if (index < 0)
indexes = [NSIndexSet indexSet];
else
indexes = [NSIndexSet indexSetWithIndex:index];
[tabBrowser_ selectRowIndexes:indexes byExtendingSelection:NO];
// Enable or disable the OK button based on whether we have a selection.
[shareButton_ setEnabled:(index >= 0)];
}
#pragma mark NSWindowDelegate
- (void)windowWillClose:(NSNotification*)notification {
// Report the result if it hasn't been reported yet. |reportResult:| ensures
// that the result is only reported once.
[self reportResult:DesktopMediaID()];
// Remove self from the parent.
NSWindow* window = [self window];
[[window parentWindow] removeChildWindow:window];
}
#pragma mark IKImageBrowserDataSource
- (NSUInteger)numberOfItemsInImageBrowser:(IKImageBrowserView*)browser {
DesktopMediaID::Type sourceType = [self sourceTypeForBrowser:browser];
NSMutableArray* items = [self itemSetForType:sourceType];
return [items count];
}
- (id)imageBrowser:(IKImageBrowserView*)browser itemAtIndex:(NSUInteger)index {
DesktopMediaID::Type sourceType = [self sourceTypeForBrowser:browser];
NSMutableArray* items = [self itemSetForType:sourceType];
DesktopMediaPickerItem* item = [items objectAtIndex:index];
// For screen source, if there is only one source, we can omit the label
// "Entire Screen", because it is redundant with tab label "Your Entire
// Screen".
[item setTitleHidden:browser == screenBrowser_ && [items count] == 1];
return item;
}
#pragma mark IKImageBrowserDelegate
- (void)imageBrowser:(IKImageBrowserView*)browser
cellWasDoubleClickedAtIndex:(NSUInteger)index {
DesktopMediaPickerItem* item;
if (browser == screenBrowser_)
item = [screenItems_ objectAtIndex:index];
else
item = [windowItems_ objectAtIndex:index];
[self reportResult:[item sourceID]];
[self close];
}
- (void)imageBrowserSelectionDidChange:(IKImageBrowserView*)browser {
DesktopMediaID::Type selectedType = [self selectedSourceType];
NSInteger selectedIndex = [self selectedIndexForType:selectedType];
// Enable or disable the OK button based on whether we have a selection.
[shareButton_ setEnabled:(selectedIndex >= 0)];
}
#pragma mark NSTableViewDataSource
- (NSInteger)numberOfRowsInTableView:(NSTableView*)table {
return [tabItems_ count];
}
#pragma mark NSTableViewDelegate
- (NSView*)tableView:(NSTableView*)table
viewForTableColumn:(NSTableColumn*)column
row:(NSInteger)rowIndex {
if ([[column identifier] isEqualToString:kDesktopMediaPickerIconId]) {
NSImage* image = [[tabItems_ objectAtIndex:rowIndex] imageRepresentation];
base::scoped_nsobject<NSImageView> iconView(
[[table makeViewWithIdentifier:kDesktopMediaPickerIconId owner:self]
retain]);
if (!iconView) {
iconView.reset([[NSImageView alloc]
initWithFrame:NSMakeRect(0, 0, kDesktopMediaPickerIconWidth,
kDesktopMediaPickerRowWidth)]);
[iconView setIdentifier:kDesktopMediaPickerIconId];
}
[iconView setImage:image];
return iconView.autorelease();
}
NSString* string = [[tabItems_ objectAtIndex:rowIndex] imageTitle];
base::scoped_nsobject<NSTextField> titleView(
[[table makeViewWithIdentifier:kDesktopMediaPickerTitleId owner:self]
retain]);
if (!titleView) {
titleView.reset(
[[self createTextFieldWithText:string
frameWidth:kDesktopMediaPickerMinimumContentWidth]
retain]);
[titleView setIdentifier:kDesktopMediaPickerTitleId];
} else {
[titleView setStringValue:string];
}
return titleView.autorelease();
}
- (void)tableViewSelectionDidChange:(NSNotification*)notification {
NSIndexSet* indexes = [tabBrowser_ selectedRowIndexes];
// Enable or disable the OK button based on whether we have a selection.
[shareButton_ setEnabled:([indexes count] > 0)];
}
#pragma mark DesktopMediaPickerObserver
- (void)sourceAddedForList:(DesktopMediaList*)list atIndex:(int)index {
DesktopMediaID::Type sourceType = list->GetMediaListType();
NSMutableArray* items = [self itemSetForType:sourceType];
id browser = [self browserViewForType:sourceType];
NSInteger selectedIndex = [self selectedIndexForType:sourceType];
if (selectedIndex >= index)
++selectedIndex;
const DesktopMediaList::Source& source = list->GetSource(index);
NSString* imageTitle = base::SysUTF16ToNSString(source.name);
base::scoped_nsobject<DesktopMediaPickerItem> item(
[[DesktopMediaPickerItem alloc] initWithSourceId:source.id
imageUID:++lastImageUID_
imageTitle:imageTitle]);
[items insertObject:item atIndex:index];
[browser reloadData];
if (sourceType == DesktopMediaID::TYPE_WEB_CONTENTS) {
// Memorizing selection.
[self setTabBrowserIndex:selectedIndex];
} else if (sourceType == DesktopMediaID::TYPE_SCREEN) {
if ([items count] == 2) {
// Switch to multiple sources mode.
[browser setCellSize:NSMakeSize(kDesktopMediaPickerMultipleScreenWidth,
kDesktopMediaPickerMultipleScreenHeight)];
}
}
NSString* autoselectSource = base::SysUTF8ToNSString(
base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
switches::kAutoSelectDesktopCaptureSource));
if ([autoselectSource isEqualToString:imageTitle]) {
[self reportResult:[item sourceID]];
[self close];
}
}
- (void)sourceRemovedForList:(DesktopMediaList*)list atIndex:(int)index {
DesktopMediaID::Type sourceType = list->GetMediaListType();
NSMutableArray* items = [self itemSetForType:sourceType];
id browser = [self browserViewForType:sourceType];
if (sourceType == DesktopMediaID::TYPE_WEB_CONTENTS) {
NSInteger selectedIndex = [self selectedIndexForType:sourceType];
if (selectedIndex > index)
--selectedIndex;
else if (selectedIndex == index)
selectedIndex = -1;
[tabItems_ removeObjectAtIndex:index];
[tabBrowser_ reloadData];
[self setTabBrowserIndex:selectedIndex];
return;
}
if ([[browser selectionIndexes] containsIndex:index]) {
// Selected item was removed. Clear selection.
[browser setSelectionIndexes:[NSIndexSet indexSet] byExtendingSelection:NO];
}
[items removeObjectAtIndex:index];
if (sourceType == DesktopMediaID::TYPE_SCREEN && [items count] == 1)
[browser setCellSize:NSMakeSize(kDesktopMediaPickerSingleScreenWidth,
kDesktopMediaPickerSingleScreenHeight)];
[browser reloadData];
}
- (void)sourceMovedForList:(DesktopMediaList*)list
from:(int)oldIndex
to:(int)newIndex {
DesktopMediaID::Type sourceType = list->GetMediaListType();
NSMutableArray* items = [self itemSetForType:sourceType];
id browser = [self browserViewForType:sourceType];
NSInteger selectedIndex = [self selectedIndexForType:sourceType];
if (selectedIndex > oldIndex && selectedIndex <= newIndex)
--selectedIndex;
else if (selectedIndex < oldIndex && selectedIndex >= newIndex)
++selectedIndex;
else if (selectedIndex == oldIndex)
selectedIndex = newIndex;
base::scoped_nsobject<DesktopMediaPickerItem> item(
[[items objectAtIndex:oldIndex] retain]);
[items removeObjectAtIndex:oldIndex];
[items insertObject:item atIndex:newIndex];
[browser reloadData];
if (sourceType == DesktopMediaID::TYPE_WEB_CONTENTS)
[self setTabBrowserIndex:selectedIndex];
}
- (void)sourceNameChangedForList:(DesktopMediaList*)list atIndex:(int)index {
DesktopMediaID::Type sourceType = list->GetMediaListType();
NSMutableArray* items = [self itemSetForType:sourceType];
id browser = [self browserViewForType:sourceType];
NSInteger selectedIndex = [self selectedIndexForType:sourceType];
DesktopMediaPickerItem* item = [items objectAtIndex:index];
const DesktopMediaList::Source& source = list->GetSource(index);
[item setImageTitle:base::SysUTF16ToNSString(source.name)];
[browser reloadData];
if (sourceType == DesktopMediaID::TYPE_WEB_CONTENTS)
[self setTabBrowserIndex:selectedIndex];
}
- (void)sourceThumbnailChangedForList:(DesktopMediaList*)list
atIndex:(int)index {
DesktopMediaID::Type sourceType = list->GetMediaListType();
NSMutableArray* items = [self itemSetForType:sourceType];
id browser = [self browserViewForType:sourceType];
NSInteger selectedIndex = [self selectedIndexForType:sourceType];
const DesktopMediaList::Source& source = list->GetSource(index);
NSImage* image = gfx::NSImageFromImageSkia(source.thumbnail);
DesktopMediaPickerItem* item = [items objectAtIndex:index];
[item setImageRepresentation:image];
[browser reloadData];
if (sourceType == DesktopMediaID::TYPE_WEB_CONTENTS)
[self setTabBrowserIndex:selectedIndex];
}
@end // @interface DesktopMediaPickerController