1// Copyright (c) 2012 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#import "chrome/browser/ui/cocoa/applescript/window_applescript.h" 6 7#include "base/logging.h" 8#import "base/mac/scoped_nsobject.h" 9#include "base/memory/scoped_ptr.h" 10#include "base/time/time.h" 11#import "chrome/browser/app_controller_mac.h" 12#import "chrome/browser/chrome_browser_application_mac.h" 13#include "chrome/browser/profiles/profile.h" 14#include "chrome/browser/ui/browser.h" 15#include "chrome/browser/ui/browser_commands.h" 16#include "chrome/browser/ui/browser_finder.h" 17#include "chrome/browser/ui/browser_navigator.h" 18#include "chrome/browser/ui/browser_tabstrip.h" 19#include "chrome/browser/ui/browser_window.h" 20#include "chrome/browser/ui/cocoa/applescript/constants_applescript.h" 21#include "chrome/browser/ui/cocoa/applescript/error_applescript.h" 22#import "chrome/browser/ui/cocoa/applescript/tab_applescript.h" 23#include "chrome/browser/ui/host_desktop.h" 24#include "chrome/browser/ui/tab_contents/core_tab_helper.h" 25#include "chrome/browser/ui/tabs/tab_strip_model.h" 26#include "chrome/common/url_constants.h" 27#include "content/public/browser/web_contents.h" 28 29@interface WindowAppleScript(WindowAppleScriptPrivateMethods) 30// The NSWindow that corresponds to this window. 31- (NSWindow*)nativeHandle; 32@end 33 34@implementation WindowAppleScript 35 36- (id)init { 37 // Check which mode to open a new window. 38 NSScriptCommand* command = [NSScriptCommand currentCommand]; 39 NSString* mode = [[[command evaluatedArguments] 40 objectForKey:@"KeyDictionary"] objectForKey:@"mode"]; 41 AppController* appDelegate = [NSApp delegate]; 42 43 Profile* lastProfile = [appDelegate lastProfile]; 44 45 if (!lastProfile) { 46 AppleScript::SetError(AppleScript::errGetProfile); 47 return nil; 48 } 49 50 Profile* profile; 51 if ([mode isEqualToString:AppleScript::kIncognitoWindowMode]) { 52 profile = lastProfile->GetOffTheRecordProfile(); 53 } 54 else if ([mode isEqualToString:AppleScript::kNormalWindowMode] || !mode) { 55 profile = lastProfile; 56 } else { 57 // Mode cannot be anything else 58 AppleScript::SetError(AppleScript::errInvalidMode); 59 return nil; 60 } 61 // Set the mode to nil, to ensure that it is not set once more. 62 [[[command evaluatedArguments] objectForKey:@"KeyDictionary"] 63 setValue:nil forKey:@"mode"]; 64 return [self initWithProfile:profile]; 65} 66 67- (id)initWithProfile:(Profile*)aProfile { 68 if (!aProfile) { 69 [self release]; 70 return nil; 71 } 72 73 if ((self = [super init])) { 74 browser_ = new Browser( 75 Browser::CreateParams(aProfile, chrome::HOST_DESKTOP_TYPE_NATIVE)); 76 chrome::NewTab(browser_); 77 browser_->window()->Show(); 78 base::scoped_nsobject<NSNumber> numID( 79 [[NSNumber alloc] initWithInt:browser_->session_id().id()]); 80 [self setUniqueID:numID]; 81 } 82 return self; 83} 84 85- (id)initWithBrowser:(Browser*)aBrowser { 86 if (!aBrowser) { 87 [self release]; 88 return nil; 89 } 90 91 if ((self = [super init])) { 92 // It is safe to be weak, if a window goes away (eg user closing a window) 93 // the applescript runtime calls appleScriptWindows in 94 // BrowserCrApplication and this particular window is never returned. 95 browser_ = aBrowser; 96 base::scoped_nsobject<NSNumber> numID( 97 [[NSNumber alloc] initWithInt:browser_->session_id().id()]); 98 [self setUniqueID:numID]; 99 } 100 return self; 101} 102 103- (NSWindow*)nativeHandle { 104 // window() can be NULL during startup. 105 if (browser_->window()) 106 return browser_->window()->GetNativeWindow(); 107 return nil; 108} 109 110- (NSNumber*)activeTabIndex { 111 // Note: applescript is 1-based, that is lists begin with index 1. 112 int activeTabIndex = browser_->tab_strip_model()->active_index() + 1; 113 if (!activeTabIndex) { 114 return nil; 115 } 116 return [NSNumber numberWithInt:activeTabIndex]; 117} 118 119- (void)setActiveTabIndex:(NSNumber*)anActiveTabIndex { 120 // Note: applescript is 1-based, that is lists begin with index 1. 121 int atIndex = [anActiveTabIndex intValue] - 1; 122 if (atIndex >= 0 && atIndex < browser_->tab_strip_model()->count()) 123 browser_->tab_strip_model()->ActivateTabAt(atIndex, true); 124 else 125 AppleScript::SetError(AppleScript::errInvalidTabIndex); 126} 127 128- (NSString*)mode { 129 Profile* profile = browser_->profile(); 130 if (profile->IsOffTheRecord()) 131 return AppleScript::kIncognitoWindowMode; 132 return AppleScript::kNormalWindowMode; 133} 134 135- (void)setMode:(NSString*)theMode { 136 // cannot set mode after window is created. 137 if (theMode) { 138 AppleScript::SetError(AppleScript::errSetMode); 139 } 140} 141 142- (TabAppleScript*)activeTab { 143 TabAppleScript* currentTab = 144 [[[TabAppleScript alloc] initWithWebContents: 145 browser_->tab_strip_model()->GetActiveWebContents()] autorelease]; 146 [currentTab setContainer:self 147 property:AppleScript::kTabsProperty]; 148 return currentTab; 149} 150 151- (NSArray*)tabs { 152 TabStripModel* tabStrip = browser_->tab_strip_model(); 153 NSMutableArray* tabs = [NSMutableArray arrayWithCapacity:tabStrip->count()]; 154 155 for (int i = 0; i < tabStrip->count(); ++i) { 156 // Check to see if tab is closing. 157 content::WebContents* webContents = tabStrip->GetWebContentsAt(i); 158 if (webContents->IsBeingDestroyed()) { 159 continue; 160 } 161 162 base::scoped_nsobject<TabAppleScript> tab( 163 [[TabAppleScript alloc] initWithWebContents:webContents]); 164 [tab setContainer:self 165 property:AppleScript::kTabsProperty]; 166 [tabs addObject:tab]; 167 } 168 return tabs; 169} 170 171- (void)insertInTabs:(TabAppleScript*)aTab { 172 // This method gets called when a new tab is created so 173 // the container and property are set here. 174 [aTab setContainer:self 175 property:AppleScript::kTabsProperty]; 176 177 // Set how long it takes a tab to be created. 178 base::TimeTicks newTabStartTime = base::TimeTicks::Now(); 179 content::WebContents* contents = chrome::AddSelectedTabWithURL( 180 browser_, 181 GURL(chrome::kChromeUINewTabURL), 182 ui::PAGE_TRANSITION_TYPED); 183 CoreTabHelper* core_tab_helper = CoreTabHelper::FromWebContents(contents); 184 core_tab_helper->set_new_tab_start_time(newTabStartTime); 185 [aTab setWebContents:contents]; 186} 187 188- (void)insertInTabs:(TabAppleScript*)aTab atIndex:(int)index { 189 // This method gets called when a new tab is created so 190 // the container and property are set here. 191 [aTab setContainer:self 192 property:AppleScript::kTabsProperty]; 193 194 // Set how long it takes a tab to be created. 195 base::TimeTicks newTabStartTime = base::TimeTicks::Now(); 196 chrome::NavigateParams params(browser_, GURL(chrome::kChromeUINewTabURL), 197 ui::PAGE_TRANSITION_TYPED); 198 params.disposition = NEW_FOREGROUND_TAB; 199 params.tabstrip_index = index; 200 chrome::Navigate(¶ms); 201 CoreTabHelper* core_tab_helper = 202 CoreTabHelper::FromWebContents(params.target_contents); 203 core_tab_helper->set_new_tab_start_time(newTabStartTime); 204 205 [aTab setWebContents:params.target_contents]; 206} 207 208- (void)removeFromTabsAtIndex:(int)index { 209 if (index < 0 || index >= browser_->tab_strip_model()->count()) 210 return; 211 browser_->tab_strip_model()->CloseWebContentsAt( 212 index, TabStripModel::CLOSE_CREATE_HISTORICAL_TAB); 213} 214 215- (NSNumber*)orderedIndex { 216 return [NSNumber numberWithInt:[[self nativeHandle] orderedIndex]]; 217} 218 219- (void)setOrderedIndex:(NSNumber*)anIndex { 220 int index = [anIndex intValue] - 1; 221 if (index < 0 || index >= static_cast<int>(chrome::GetTotalBrowserCount())) { 222 AppleScript::SetError(AppleScript::errWrongIndex); 223 return; 224 } 225 [[self nativeHandle] setOrderedIndex:index]; 226} 227 228- (NSComparisonResult)windowComparator:(WindowAppleScript*)otherWindow { 229 int thisIndex = [[self orderedIndex] intValue]; 230 int otherIndex = [[otherWindow orderedIndex] intValue]; 231 if (thisIndex < otherIndex) 232 return NSOrderedAscending; 233 else if (thisIndex > otherIndex) 234 return NSOrderedDescending; 235 // Indexes can never be same. 236 NOTREACHED(); 237 return NSOrderedSame; 238} 239 240// Get and set values from the associated NSWindow. 241- (id)valueForUndefinedKey:(NSString*)key { 242 return [[self nativeHandle] valueForKey:key]; 243} 244 245- (void)setValue:(id)value forUndefinedKey:(NSString*)key { 246 [[self nativeHandle] setValue:(id)value forKey:key]; 247} 248 249- (void)handlesCloseScriptCommand:(NSCloseCommand*)command { 250 // window() can be NULL during startup. 251 if (browser_->window()) 252 browser_->window()->Close(); 253} 254 255- (NSNumber*)presenting { 256 BOOL presentingValue = NO; 257 if (browser_->window()) 258 presentingValue = browser_->window()->IsFullscreenWithoutChrome(); 259 return [NSNumber numberWithBool:presentingValue]; 260} 261 262- (void)handlesEnterPresentationMode:(NSScriptCommand*)command { 263 if (browser_->window()) { 264 browser_->window()->EnterFullscreen( 265 GURL(), FEB_TYPE_FULLSCREEN_EXIT_INSTRUCTION); 266 } 267} 268 269- (void)handlesExitPresentationMode:(NSScriptCommand*)command { 270 if (browser_->window()) 271 browser_->window()->ExitFullscreen(); 272} 273 274@end 275