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 #include "chrome/browser/devtools/devtools_window.h" 6 7 #include <algorithm> 8 9 #include "base/command_line.h" 10 #include "base/json/json_writer.h" 11 #include "base/lazy_instance.h" 12 #include "base/strings/string_number_conversions.h" 13 #include "base/strings/utf_string_conversions.h" 14 #include "base/values.h" 15 #include "chrome/browser/browser_process.h" 16 #include "chrome/browser/chrome_notification_types.h" 17 #include "chrome/browser/extensions/api/debugger/debugger_api.h" 18 #include "chrome/browser/extensions/extension_service.h" 19 #include "chrome/browser/extensions/extension_system.h" 20 #include "chrome/browser/file_select_helper.h" 21 #include "chrome/browser/infobars/confirm_infobar_delegate.h" 22 #include "chrome/browser/prefs/pref_service_syncable.h" 23 #include "chrome/browser/prefs/scoped_user_pref_update.h" 24 #include "chrome/browser/profiles/profile.h" 25 #include "chrome/browser/sessions/session_tab_helper.h" 26 #include "chrome/browser/themes/theme_properties.h" 27 #include "chrome/browser/themes/theme_service.h" 28 #include "chrome/browser/themes/theme_service_factory.h" 29 #include "chrome/browser/ui/browser.h" 30 #include "chrome/browser/ui/browser_dialogs.h" 31 #include "chrome/browser/ui/browser_iterator.h" 32 #include "chrome/browser/ui/browser_list.h" 33 #include "chrome/browser/ui/browser_window.h" 34 #include "chrome/browser/ui/host_desktop.h" 35 #include "chrome/browser/ui/prefs/prefs_tab_helper.h" 36 #include "chrome/browser/ui/tabs/tab_strip_model.h" 37 #include "chrome/browser/ui/webui/devtools_ui.h" 38 #include "chrome/common/chrome_switches.h" 39 #include "chrome/common/extensions/manifest_url_handler.h" 40 #include "chrome/common/pref_names.h" 41 #include "chrome/common/render_messages.h" 42 #include "chrome/common/url_constants.h" 43 #include "components/user_prefs/pref_registry_syncable.h" 44 #include "content/public/browser/browser_thread.h" 45 #include "content/public/browser/child_process_security_policy.h" 46 #include "content/public/browser/devtools_agent_host.h" 47 #include "content/public/browser/devtools_client_host.h" 48 #include "content/public/browser/devtools_manager.h" 49 #include "content/public/browser/favicon_status.h" 50 #include "content/public/browser/load_notification_details.h" 51 #include "content/public/browser/navigation_controller.h" 52 #include "content/public/browser/navigation_entry.h" 53 #include "content/public/browser/notification_source.h" 54 #include "content/public/browser/render_process_host.h" 55 #include "content/public/browser/render_view_host.h" 56 #include "content/public/browser/web_contents.h" 57 #include "content/public/browser/web_contents_observer.h" 58 #include "content/public/browser/web_contents_view.h" 59 #include "content/public/common/bindings_policy.h" 60 #include "content/public/common/content_client.h" 61 #include "content/public/common/page_transition_types.h" 62 #include "content/public/common/url_constants.h" 63 #include "grit/generated_resources.h" 64 #include "ui/base/l10n/l10n_util.h" 65 66 using content::DevToolsAgentHost; 67 68 69 // DevToolsConfirmInfoBarDelegate --------------------------------------------- 70 71 class DevToolsConfirmInfoBarDelegate : public ConfirmInfoBarDelegate { 72 public: 73 // If |infobar_service| is NULL, runs |callback| with a single argument with 74 // value "false". Otherwise, creates a dev tools confirm infobar and delegate 75 // and adds the inofbar to |infobar_service|. 76 static void Create(InfoBarService* infobar_service, 77 const DevToolsWindow::InfoBarCallback& callback, 78 const string16& message); 79 80 private: 81 DevToolsConfirmInfoBarDelegate( 82 InfoBarService* infobar_service, 83 const DevToolsWindow::InfoBarCallback& callback, 84 const string16& message); 85 virtual ~DevToolsConfirmInfoBarDelegate(); 86 87 virtual string16 GetMessageText() const OVERRIDE; 88 virtual string16 GetButtonLabel(InfoBarButton button) const OVERRIDE; 89 virtual bool Accept() OVERRIDE; 90 virtual bool Cancel() OVERRIDE; 91 92 DevToolsWindow::InfoBarCallback callback_; 93 const string16 message_; 94 95 DISALLOW_COPY_AND_ASSIGN(DevToolsConfirmInfoBarDelegate); 96 }; 97 98 void DevToolsConfirmInfoBarDelegate::Create( 99 InfoBarService* infobar_service, 100 const DevToolsWindow::InfoBarCallback& callback, 101 const string16& message) { 102 if (!infobar_service) { 103 callback.Run(false); 104 return; 105 } 106 107 infobar_service->AddInfoBar(scoped_ptr<InfoBarDelegate>( 108 new DevToolsConfirmInfoBarDelegate(infobar_service, callback, message))); 109 } 110 111 DevToolsConfirmInfoBarDelegate::DevToolsConfirmInfoBarDelegate( 112 InfoBarService* infobar_service, 113 const DevToolsWindow::InfoBarCallback& callback, 114 const string16& message) 115 : ConfirmInfoBarDelegate(infobar_service), 116 callback_(callback), 117 message_(message) { 118 } 119 120 DevToolsConfirmInfoBarDelegate::~DevToolsConfirmInfoBarDelegate() { 121 if (!callback_.is_null()) 122 callback_.Run(false); 123 } 124 125 string16 DevToolsConfirmInfoBarDelegate::GetMessageText() const { 126 return message_; 127 } 128 129 string16 DevToolsConfirmInfoBarDelegate::GetButtonLabel( 130 InfoBarButton button) const { 131 return l10n_util::GetStringUTF16((button == BUTTON_OK) ? 132 IDS_DEV_TOOLS_CONFIRM_ALLOW_BUTTON : IDS_DEV_TOOLS_CONFIRM_DENY_BUTTON); 133 } 134 135 bool DevToolsConfirmInfoBarDelegate::Accept() { 136 callback_.Run(true); 137 callback_.Reset(); 138 return true; 139 } 140 141 bool DevToolsConfirmInfoBarDelegate::Cancel() { 142 callback_.Run(false); 143 callback_.Reset(); 144 return true; 145 } 146 147 148 // DevToolsWindow::InspectedWebContentsObserver ------------------------------- 149 150 class DevToolsWindow::InspectedWebContentsObserver 151 : public content::WebContentsObserver { 152 public: 153 explicit InspectedWebContentsObserver(content::WebContents* web_contents); 154 virtual ~InspectedWebContentsObserver(); 155 156 content::WebContents* web_contents() { 157 return WebContentsObserver::web_contents(); 158 } 159 160 private: 161 DISALLOW_COPY_AND_ASSIGN(InspectedWebContentsObserver); 162 }; 163 164 DevToolsWindow::InspectedWebContentsObserver::InspectedWebContentsObserver( 165 content::WebContents* web_contents) 166 : WebContentsObserver(web_contents) { 167 } 168 169 DevToolsWindow::InspectedWebContentsObserver::~InspectedWebContentsObserver() { 170 } 171 172 173 // DevToolsWindow::FrontendWebContentsObserver -------------------------------- 174 175 class DevToolsWindow::FrontendWebContentsObserver 176 : public content::WebContentsObserver { 177 public: 178 explicit FrontendWebContentsObserver(content::WebContents* web_contents); 179 virtual ~FrontendWebContentsObserver(); 180 181 private: 182 // contents::WebContentsObserver: 183 virtual void AboutToNavigateRenderView( 184 content::RenderViewHost* render_view_host) OVERRIDE; 185 186 DISALLOW_COPY_AND_ASSIGN(FrontendWebContentsObserver); 187 }; 188 189 DevToolsWindow::FrontendWebContentsObserver::FrontendWebContentsObserver( 190 content::WebContents* web_contents) 191 : WebContentsObserver(web_contents) { 192 } 193 194 DevToolsWindow::FrontendWebContentsObserver::~FrontendWebContentsObserver() { 195 } 196 197 void DevToolsWindow::FrontendWebContentsObserver::AboutToNavigateRenderView( 198 content::RenderViewHost* render_view_host) { 199 content::DevToolsClientHost::SetupDevToolsFrontendClient(render_view_host); 200 } 201 202 203 // DevToolsWindow ------------------------------------------------------------- 204 205 namespace { 206 207 typedef std::vector<DevToolsWindow*> DevToolsWindows; 208 base::LazyInstance<DevToolsWindows>::Leaky g_instances = 209 LAZY_INSTANCE_INITIALIZER; 210 211 const char kPrefBottom[] = "dock_bottom"; 212 const char kPrefRight[] = "dock_right"; 213 const char kPrefUndocked[] = "undocked"; 214 215 const char kDockSideBottom[] = "bottom"; 216 const char kDockSideRight[] = "right"; 217 const char kDockSideUndocked[] = "undocked"; 218 const char kDockSideMinimized[] = "minimized"; 219 220 const int kMinContentsSize = 50; 221 222 std::string SkColorToRGBAString(SkColor color) { 223 // We avoid StringPrintf because it will use locale specific formatters for 224 // the double (e.g. ',' instead of '.' in German). 225 return "rgba(" + base::IntToString(SkColorGetR(color)) + "," + 226 base::IntToString(SkColorGetG(color)) + "," + 227 base::IntToString(SkColorGetB(color)) + "," + 228 base::DoubleToString(SkColorGetA(color) / 255.0) + ")"; 229 } 230 231 DictionaryValue* CreateFileSystemValue( 232 DevToolsFileHelper::FileSystem file_system) { 233 DictionaryValue* file_system_value = new DictionaryValue(); 234 file_system_value->SetString("fileSystemName", file_system.file_system_name); 235 file_system_value->SetString("rootURL", file_system.root_url); 236 file_system_value->SetString("fileSystemPath", file_system.file_system_path); 237 return file_system_value; 238 } 239 240 } // namespace 241 242 const char DevToolsWindow::kDevToolsApp[] = "DevToolsApp"; 243 244 DevToolsWindow::~DevToolsWindow() { 245 DevToolsWindows* instances = &g_instances.Get(); 246 DevToolsWindows::iterator it( 247 std::find(instances->begin(), instances->end(), this)); 248 DCHECK(it != instances->end()); 249 instances->erase(it); 250 251 for (IndexingJobsMap::const_iterator jobs_it(indexing_jobs_.begin()); 252 jobs_it != indexing_jobs_.end(); ++jobs_it) { 253 jobs_it->second->Stop(); 254 } 255 indexing_jobs_.clear(); 256 } 257 258 // static 259 std::string DevToolsWindow::GetDevToolsWindowPlacementPrefKey() { 260 return std::string(prefs::kBrowserWindowPlacement) + "_" + 261 std::string(kDevToolsApp); 262 } 263 264 // static 265 void DevToolsWindow::RegisterProfilePrefs( 266 user_prefs::PrefRegistrySyncable* registry) { 267 registry->RegisterBooleanPref( 268 prefs::kDevToolsOpenDocked, true, 269 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); 270 registry->RegisterStringPref( 271 prefs::kDevToolsDockSide, kDockSideBottom, 272 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); 273 registry->RegisterDictionaryPref( 274 prefs::kDevToolsEditedFiles, 275 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); 276 registry->RegisterDictionaryPref( 277 prefs::kDevToolsFileSystemPaths, 278 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); 279 registry->RegisterStringPref( 280 prefs::kDevToolsAdbKey, std::string(), 281 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); 282 283 registry->RegisterDictionaryPref( 284 GetDevToolsWindowPlacementPrefKey().c_str(), 285 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); 286 287 registry->RegisterBooleanPref( 288 prefs::kDevToolsPortForwardingEnabled, 289 false, 290 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); 291 registry->RegisterDictionaryPref( 292 prefs::kDevToolsPortForwardingConfig, 293 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); 294 } 295 296 // static 297 DevToolsWindow* DevToolsWindow::GetDockedInstanceForInspectedTab( 298 content::WebContents* inspected_web_contents) { 299 if (!inspected_web_contents || 300 !DevToolsAgentHost::HasFor(inspected_web_contents->GetRenderViewHost())) 301 return NULL; 302 scoped_refptr<DevToolsAgentHost> agent(DevToolsAgentHost::GetOrCreateFor( 303 inspected_web_contents->GetRenderViewHost())); 304 DevToolsWindow* window = FindDevToolsWindow(agent.get()); 305 return (window && window->IsDocked()) ? window : NULL; 306 } 307 308 // static 309 bool DevToolsWindow::IsDevToolsWindow(content::RenderViewHost* window_rvh) { 310 return AsDevToolsWindow(window_rvh) != NULL; 311 } 312 313 // static 314 DevToolsWindow* DevToolsWindow::OpenDevToolsWindowForWorker( 315 Profile* profile, 316 DevToolsAgentHost* worker_agent) { 317 DevToolsWindow* window = FindDevToolsWindow(worker_agent); 318 if (!window) { 319 window = DevToolsWindow::CreateDevToolsWindowForWorker(profile); 320 // Will disconnect the current client host if there is one. 321 content::DevToolsManager::GetInstance()->RegisterDevToolsClientHostFor( 322 worker_agent, window->frontend_host_.get()); 323 } 324 window->Show(DEVTOOLS_TOGGLE_ACTION_SHOW); 325 return window; 326 } 327 328 // static 329 DevToolsWindow* DevToolsWindow::CreateDevToolsWindowForWorker( 330 Profile* profile) { 331 return Create(profile, GURL(), NULL, DEVTOOLS_DOCK_SIDE_UNDOCKED, true); 332 } 333 334 // static 335 DevToolsWindow* DevToolsWindow::OpenDevToolsWindow( 336 content::RenderViewHost* inspected_rvh) { 337 return ToggleDevToolsWindow(inspected_rvh, true, 338 DEVTOOLS_TOGGLE_ACTION_SHOW); 339 } 340 341 // static 342 DevToolsWindow* DevToolsWindow::ToggleDevToolsWindow( 343 Browser* browser, 344 DevToolsToggleAction action) { 345 if (action == DEVTOOLS_TOGGLE_ACTION_TOGGLE && browser->is_devtools()) { 346 browser->tab_strip_model()->CloseAllTabs(); 347 return NULL; 348 } 349 350 return ToggleDevToolsWindow( 351 browser->tab_strip_model()->GetActiveWebContents()->GetRenderViewHost(), 352 action == DEVTOOLS_TOGGLE_ACTION_INSPECT, action); 353 } 354 355 // static 356 void DevToolsWindow::OpenExternalFrontend( 357 Profile* profile, 358 const std::string& frontend_url, 359 content::DevToolsAgentHost* agent_host) { 360 DevToolsWindow* window = FindDevToolsWindow(agent_host); 361 if (!window) { 362 window = Create(profile, DevToolsUI::GetProxyURL(frontend_url), NULL, 363 DEVTOOLS_DOCK_SIDE_UNDOCKED, false); 364 content::DevToolsManager::GetInstance()->RegisterDevToolsClientHostFor( 365 agent_host, window->frontend_host_.get()); 366 } 367 window->Show(DEVTOOLS_TOGGLE_ACTION_SHOW); 368 } 369 370 // static 371 DevToolsWindow* DevToolsWindow::ToggleDevToolsWindow( 372 content::RenderViewHost* inspected_rvh, 373 bool force_open, 374 DevToolsToggleAction action) { 375 scoped_refptr<DevToolsAgentHost> agent( 376 DevToolsAgentHost::GetOrCreateFor(inspected_rvh)); 377 content::DevToolsManager* manager = content::DevToolsManager::GetInstance(); 378 DevToolsWindow* window = FindDevToolsWindow(agent.get()); 379 bool do_open = force_open; 380 if (!window) { 381 Profile* profile = Profile::FromBrowserContext( 382 inspected_rvh->GetProcess()->GetBrowserContext()); 383 DevToolsDockSide dock_side = GetDockSideFromPrefs(profile); 384 window = Create(profile, GURL(), inspected_rvh, dock_side, false); 385 manager->RegisterDevToolsClientHostFor(agent.get(), 386 window->frontend_host_.get()); 387 do_open = true; 388 } 389 390 // Update toolbar to reflect DevTools changes. 391 window->UpdateBrowserToolbar(); 392 393 // If window is docked and visible, we hide it on toggle. If window is 394 // undocked, we show (activate) it. If window is minimized, we maximize it. 395 if (window->dock_side_ == DEVTOOLS_DOCK_SIDE_MINIMIZED) 396 window->Restore(); 397 else if (!window->IsDocked() || do_open) 398 window->Show(action); 399 else 400 window->CloseWindow(); 401 402 return window; 403 } 404 405 // static 406 void DevToolsWindow::InspectElement(content::RenderViewHost* inspected_rvh, 407 int x, 408 int y) { 409 scoped_refptr<DevToolsAgentHost> agent( 410 DevToolsAgentHost::GetOrCreateFor(inspected_rvh)); 411 agent->InspectElement(x, y); 412 // TODO(loislo): we should initiate DevTools window opening from within 413 // renderer. Otherwise, we still can hit a race condition here. 414 OpenDevToolsWindow(inspected_rvh); 415 } 416 417 // static 418 int DevToolsWindow::GetMinimumWidth() { 419 const int kMinDevToolsWidth = 150; 420 return kMinDevToolsWidth; 421 } 422 423 // static 424 int DevToolsWindow::GetMinimumHeight() { 425 // Minimal height of devtools pane or content pane when devtools are docked 426 // to the browser window. 427 const int kMinDevToolsHeight = 50; 428 return kMinDevToolsHeight; 429 } 430 431 // static 432 int DevToolsWindow::GetMinimizedHeight() { 433 const int kMinimizedDevToolsHeight = 24; 434 return kMinimizedDevToolsHeight; 435 } 436 437 void DevToolsWindow::InspectedContentsClosing() { 438 Hide(); 439 } 440 441 content::RenderViewHost* DevToolsWindow::GetRenderViewHost() { 442 return web_contents_->GetRenderViewHost(); 443 } 444 445 content::DevToolsClientHost* DevToolsWindow::GetDevToolsClientHostForTest() { 446 return frontend_host_.get(); 447 } 448 449 int DevToolsWindow::GetWidth(int container_width) { 450 if (width_ == -1) { 451 width_ = profile_->GetPrefs()-> 452 GetInteger(prefs::kDevToolsVSplitLocation); 453 } 454 455 // By default, size devtools as 1/3 of the browser window. 456 if (width_ == -1) 457 width_ = container_width / 3; 458 459 // Respect the minimum devtools width preset. 460 width_ = std::max(GetMinimumWidth(), width_); 461 462 // But it should never compromise the content window size unless the entire 463 // window is tiny. 464 width_ = std::min(container_width - kMinContentsSize, width_); 465 return width_; 466 } 467 468 int DevToolsWindow::GetHeight(int container_height) { 469 if (height_ == -1) { 470 height_ = profile_->GetPrefs()-> 471 GetInteger(prefs::kDevToolsHSplitLocation); 472 } 473 474 // By default, size devtools as 1/3 of the browser window. 475 if (height_ == -1) 476 height_ = container_height / 3; 477 478 // Respect the minimum devtools width preset. 479 height_ = std::max(GetMinimumHeight(), height_); 480 481 // But it should never compromise the content window size. 482 height_ = std::min(container_height - kMinContentsSize, height_); 483 return height_; 484 } 485 486 void DevToolsWindow::SetWidth(int width) { 487 width_ = width; 488 profile_->GetPrefs()->SetInteger(prefs::kDevToolsVSplitLocation, width); 489 } 490 491 void DevToolsWindow::SetHeight(int height) { 492 height_ = height; 493 profile_->GetPrefs()->SetInteger(prefs::kDevToolsHSplitLocation, height); 494 } 495 496 void DevToolsWindow::Show(DevToolsToggleAction action) { 497 if (IsDocked()) { 498 Browser* inspected_browser = NULL; 499 int inspected_tab_index = -1; 500 // Tell inspected browser to update splitter and switch to inspected panel. 501 if (!IsInspectedBrowserPopup() && 502 FindInspectedBrowserAndTabIndex(&inspected_browser, 503 &inspected_tab_index)) { 504 BrowserWindow* inspected_window = inspected_browser->window(); 505 web_contents_->SetDelegate(this); 506 inspected_window->UpdateDevTools(); 507 web_contents_->GetView()->SetInitialFocus(); 508 inspected_window->Show(); 509 TabStripModel* tab_strip_model = inspected_browser->tab_strip_model(); 510 tab_strip_model->ActivateTabAt(inspected_tab_index, true); 511 PrefsTabHelper::CreateForWebContents(web_contents_); 512 GetRenderViewHost()->SyncRendererPrefs(); 513 ScheduleAction(action); 514 return; 515 } 516 517 // Sometimes we don't know where to dock. Stay undocked. 518 dock_side_ = DEVTOOLS_DOCK_SIDE_UNDOCKED; 519 } 520 521 // Avoid consecutive window switching if the devtools window has been opened 522 // and the Inspect Element shortcut is pressed in the inspected tab. 523 bool should_show_window = 524 !browser_ || (action != DEVTOOLS_TOGGLE_ACTION_INSPECT); 525 526 if (!browser_) 527 CreateDevToolsBrowser(); 528 529 if (should_show_window) { 530 browser_->window()->Show(); 531 web_contents_->GetView()->SetInitialFocus(); 532 } 533 534 ScheduleAction(action); 535 } 536 537 DevToolsWindow::DevToolsWindow(Profile* profile, 538 const GURL& url, 539 content::RenderViewHost* inspected_rvh, 540 DevToolsDockSide dock_side) 541 : profile_(profile), 542 browser_(NULL), 543 dock_side_(dock_side), 544 is_loaded_(false), 545 action_on_load_(DEVTOOLS_TOGGLE_ACTION_SHOW), 546 weak_factory_(this), 547 width_(-1), 548 height_(-1), 549 dock_side_before_minimized_(dock_side) { 550 web_contents_ = 551 content::WebContents::Create(content::WebContents::CreateParams(profile)); 552 frontend_contents_observer_.reset( 553 new FrontendWebContentsObserver(web_contents_)); 554 555 web_contents_->GetController().LoadURL(url, content::Referrer(), 556 content::PAGE_TRANSITION_AUTO_TOPLEVEL, std::string()); 557 558 frontend_host_.reset(content::DevToolsClientHost::CreateDevToolsFrontendHost( 559 web_contents_, this)); 560 file_helper_.reset(new DevToolsFileHelper(web_contents_, profile)); 561 file_system_indexer_ = new DevToolsFileSystemIndexer(); 562 563 g_instances.Get().push_back(this); 564 565 // Wipe out page icon so that the default application icon is used. 566 content::NavigationEntry* entry = 567 web_contents_->GetController().GetActiveEntry(); 568 entry->GetFavicon().image = gfx::Image(); 569 entry->GetFavicon().valid = true; 570 571 // Register on-load actions. 572 content::Source<content::NavigationController> nav_controller_source( 573 &web_contents_->GetController()); 574 registrar_.Add(this, content::NOTIFICATION_LOAD_STOP, nav_controller_source); 575 registrar_.Add(this, chrome::NOTIFICATION_TAB_CLOSING, nav_controller_source); 576 registrar_.Add( 577 this, chrome::NOTIFICATION_BROWSER_THEME_CHANGED, 578 content::Source<ThemeService>( 579 ThemeServiceFactory::GetForProfile(profile_))); 580 581 // There is no inspected_rvh in case of shared workers. 582 if (inspected_rvh) 583 inspected_contents_observer_.reset(new InspectedWebContentsObserver( 584 content::WebContents::FromRenderViewHost(inspected_rvh))); 585 } 586 587 // static 588 DevToolsWindow* DevToolsWindow::Create( 589 Profile* profile, 590 const GURL& frontend_url, 591 content::RenderViewHost* inspected_rvh, 592 DevToolsDockSide dock_side, 593 bool shared_worker_frontend) { 594 // Create WebContents with devtools. 595 GURL url(GetDevToolsURL(profile, frontend_url, dock_side, 596 shared_worker_frontend)); 597 return new DevToolsWindow(profile, url, inspected_rvh, dock_side); 598 } 599 600 // static 601 GURL DevToolsWindow::GetDevToolsURL(Profile* profile, 602 const GURL& base_url, 603 DevToolsDockSide dock_side, 604 bool shared_worker_frontend) { 605 std::string frontend_url( 606 base_url.is_empty() ? chrome::kChromeUIDevToolsURL : base_url.spec()); 607 ThemeService* tp = ThemeServiceFactory::GetForProfile(profile); 608 DCHECK(tp); 609 std::string url_string( 610 frontend_url + 611 ((frontend_url.find("?") == std::string::npos) ? "?" : "&") + 612 "dockSide=" + SideToString(dock_side) + 613 "&toolbarColor=" + 614 SkColorToRGBAString(tp->GetColor(ThemeProperties::COLOR_TOOLBAR)) + 615 "&textColor=" + 616 SkColorToRGBAString(tp->GetColor(ThemeProperties::COLOR_BOOKMARK_TEXT))); 617 if (shared_worker_frontend) 618 url_string += "&isSharedWorker=true"; 619 if (CommandLine::ForCurrentProcess()->HasSwitch( 620 switches::kEnableDevToolsExperiments)) 621 url_string += "&experiments=true"; 622 return GURL(url_string); 623 } 624 625 // static 626 DevToolsWindow* DevToolsWindow::FindDevToolsWindow( 627 DevToolsAgentHost* agent_host) { 628 DevToolsWindows* instances = &g_instances.Get(); 629 content::DevToolsManager* manager = content::DevToolsManager::GetInstance(); 630 for (DevToolsWindows::iterator it(instances->begin()); it != instances->end(); 631 ++it) { 632 if (manager->GetDevToolsAgentHostFor((*it)->frontend_host_.get()) == 633 agent_host) 634 return *it; 635 } 636 return NULL; 637 } 638 639 // static 640 DevToolsWindow* DevToolsWindow::AsDevToolsWindow( 641 content::RenderViewHost* window_rvh) { 642 if (g_instances == NULL) 643 return NULL; 644 DevToolsWindows* instances = &g_instances.Get(); 645 for (DevToolsWindows::iterator it(instances->begin()); it != instances->end(); 646 ++it) { 647 if ((*it)->web_contents_->GetRenderViewHost() == window_rvh) 648 return *it; 649 } 650 return NULL; 651 } 652 653 // static 654 DevToolsDockSide DevToolsWindow::GetDockSideFromPrefs(Profile* profile) { 655 std::string dock_side = 656 profile->GetPrefs()->GetString(prefs::kDevToolsDockSide); 657 658 // Migrate prefs. 659 const char kOldPrefBottom[] = "bottom"; 660 const char kOldPrefRight[] = "right"; 661 if ((dock_side == kOldPrefBottom) || (dock_side == kOldPrefRight)) { 662 if (!profile->GetPrefs()->GetBoolean(prefs::kDevToolsOpenDocked)) 663 return DEVTOOLS_DOCK_SIDE_UNDOCKED; 664 return (dock_side == kOldPrefBottom) ? 665 DEVTOOLS_DOCK_SIDE_BOTTOM : DEVTOOLS_DOCK_SIDE_RIGHT; 666 } 667 668 if (dock_side == kPrefUndocked) 669 return DEVTOOLS_DOCK_SIDE_UNDOCKED; 670 if (dock_side == kPrefRight) 671 return DEVTOOLS_DOCK_SIDE_RIGHT; 672 // Default to docked to bottom. 673 return DEVTOOLS_DOCK_SIDE_BOTTOM; 674 } 675 676 // static 677 std::string DevToolsWindow::SideToString(DevToolsDockSide dock_side) { 678 switch (dock_side) { 679 case DEVTOOLS_DOCK_SIDE_UNDOCKED: return kDockSideUndocked; 680 case DEVTOOLS_DOCK_SIDE_RIGHT: return kDockSideRight; 681 case DEVTOOLS_DOCK_SIDE_BOTTOM: return kDockSideBottom; 682 case DEVTOOLS_DOCK_SIDE_MINIMIZED: return kDockSideMinimized; 683 default: return kDockSideUndocked; 684 } 685 } 686 687 // static 688 DevToolsDockSide DevToolsWindow::SideFromString( 689 const std::string& dock_side) { 690 if (dock_side == kDockSideRight) 691 return DEVTOOLS_DOCK_SIDE_RIGHT; 692 if (dock_side == kDockSideBottom) 693 return DEVTOOLS_DOCK_SIDE_BOTTOM; 694 return (dock_side == kDockSideMinimized) ? 695 DEVTOOLS_DOCK_SIDE_MINIMIZED : DEVTOOLS_DOCK_SIDE_UNDOCKED; 696 } 697 698 void DevToolsWindow::Observe(int type, 699 const content::NotificationSource& source, 700 const content::NotificationDetails& details) { 701 if (type == content::NOTIFICATION_LOAD_STOP) { 702 if (!is_loaded_) { 703 is_loaded_ = true; 704 UpdateTheme(); 705 DoAction(); 706 AddDevToolsExtensionsToClient(); 707 } 708 } else if (type == chrome::NOTIFICATION_TAB_CLOSING) { 709 if (content::Source<content::NavigationController>(source).ptr() == 710 &web_contents_->GetController()) { 711 // This happens when browser closes all of its tabs as a result 712 // of window.Close event. 713 // Notify manager that this DevToolsClientHost no longer exists and 714 // initiate self-destuct here. 715 content::DevToolsManager::GetInstance()->ClientHostClosing( 716 frontend_host_.get()); 717 UpdateBrowserToolbar(); 718 delete this; 719 } 720 } else { 721 DCHECK_EQ(chrome::NOTIFICATION_BROWSER_THEME_CHANGED, type); 722 UpdateTheme(); 723 } 724 } 725 726 content::WebContents* DevToolsWindow::OpenURLFromTab( 727 content::WebContents* source, 728 const content::OpenURLParams& params) { 729 if (!params.url.SchemeIs(chrome::kChromeDevToolsScheme)) { 730 content::WebContents* inspected_web_contents = GetInspectedWebContents(); 731 return inspected_web_contents ? 732 inspected_web_contents->OpenURL(params) : NULL; 733 } 734 735 content::DevToolsManager* manager = content::DevToolsManager::GetInstance(); 736 scoped_refptr<DevToolsAgentHost> agent_host( 737 manager->GetDevToolsAgentHostFor(frontend_host_.get())); 738 if (!agent_host.get()) 739 return NULL; 740 manager->ClientHostClosing(frontend_host_.get()); 741 manager->RegisterDevToolsClientHostFor(agent_host.get(), 742 frontend_host_.get()); 743 744 chrome::NavigateParams nav_params(profile_, params.url, params.transition); 745 FillNavigateParamsFromOpenURLParams(&nav_params, params); 746 nav_params.source_contents = source; 747 nav_params.tabstrip_add_types = TabStripModel::ADD_NONE; 748 nav_params.window_action = chrome::NavigateParams::SHOW_WINDOW; 749 nav_params.user_gesture = params.user_gesture; 750 chrome::Navigate(&nav_params); 751 return nav_params.target_contents; 752 } 753 754 void DevToolsWindow::AddNewContents(content::WebContents* source, 755 content::WebContents* new_contents, 756 WindowOpenDisposition disposition, 757 const gfx::Rect& initial_pos, 758 bool user_gesture, 759 bool* was_blocked) { 760 content::WebContents* inspected_web_contents = GetInspectedWebContents(); 761 if (inspected_web_contents) { 762 inspected_web_contents->GetDelegate()->AddNewContents( 763 source, new_contents, disposition, initial_pos, user_gesture, 764 was_blocked); 765 } 766 } 767 768 void DevToolsWindow::CloseContents(content::WebContents* source) { 769 } 770 771 bool DevToolsWindow::PreHandleKeyboardEvent( 772 content::WebContents* source, 773 const content::NativeWebKeyboardEvent& event, 774 bool* is_keyboard_shortcut) { 775 if (IsDocked()) { 776 BrowserWindow* inspected_window = GetInspectedBrowserWindow(); 777 if (inspected_window) { 778 return inspected_window->PreHandleKeyboardEvent(event, 779 is_keyboard_shortcut); 780 } 781 } 782 return false; 783 } 784 785 void DevToolsWindow::HandleKeyboardEvent( 786 content::WebContents* source, 787 const content::NativeWebKeyboardEvent& event) { 788 if (IsDocked()) { 789 if (event.windowsKeyCode == 0x08) { 790 // Do not navigate back in history on Windows (http://crbug.com/74156). 791 return; 792 } 793 BrowserWindow* inspected_window = GetInspectedBrowserWindow(); 794 if (inspected_window) 795 inspected_window->HandleKeyboardEvent(event); 796 } 797 } 798 799 content::JavaScriptDialogManager* DevToolsWindow::GetJavaScriptDialogManager() { 800 content::WebContents* inspected_web_contents = GetInspectedWebContents(); 801 return (inspected_web_contents && inspected_web_contents->GetDelegate()) ? 802 inspected_web_contents->GetDelegate()->GetJavaScriptDialogManager() : 803 content::WebContentsDelegate::GetJavaScriptDialogManager(); 804 } 805 806 content::ColorChooser* DevToolsWindow::OpenColorChooser( 807 content::WebContents* web_contents, 808 SkColor initial_color) { 809 return chrome::ShowColorChooser(web_contents, initial_color); 810 } 811 812 void DevToolsWindow::RunFileChooser(content::WebContents* web_contents, 813 const content::FileChooserParams& params) { 814 FileSelectHelper::RunFileChooser(web_contents, params); 815 } 816 817 void DevToolsWindow::WebContentsFocused(content::WebContents* contents) { 818 Browser* inspected_browser = NULL; 819 int inspected_tab_index = -1; 820 if (IsDocked() && FindInspectedBrowserAndTabIndex(&inspected_browser, 821 &inspected_tab_index)) 822 inspected_browser->window()->WebContentsFocused(contents); 823 } 824 825 void DevToolsWindow::ActivateWindow() { 826 if (IsDocked() && GetInspectedBrowserWindow()) 827 web_contents_->GetView()->Focus(); 828 else if (!IsDocked() && !browser_->window()->IsActive()) 829 browser_->window()->Activate(); 830 } 831 832 void DevToolsWindow::ChangeAttachedWindowHeight(unsigned height) { 833 NOTREACHED(); // TODO(dgozman): This is not used anymore, remove. 834 } 835 836 void DevToolsWindow::CloseWindow() { 837 DCHECK(IsDocked()); 838 content::DevToolsManager::GetInstance()->ClientHostClosing( 839 frontend_host_.get()); 840 Hide(); 841 } 842 843 void DevToolsWindow::MoveWindow(int x, int y) { 844 if (!IsDocked()) { 845 gfx::Rect bounds = browser_->window()->GetBounds(); 846 bounds.Offset(x, y); 847 browser_->window()->SetBounds(bounds); 848 } 849 } 850 851 void DevToolsWindow::SetDockSide(const std::string& side) { 852 DevToolsDockSide requested_side = SideFromString(side); 853 bool dock_requested = requested_side != DEVTOOLS_DOCK_SIDE_UNDOCKED; 854 bool is_docked = IsDocked(); 855 856 if (dock_requested && 857 (!GetInspectedWebContents() || !GetInspectedBrowserWindow() || 858 IsInspectedBrowserPopup())) { 859 // Cannot dock, avoid window flashing due to close-reopen cycle. 860 return; 861 } 862 863 if ((dock_side_ != DEVTOOLS_DOCK_SIDE_MINIMIZED) && 864 (requested_side == DEVTOOLS_DOCK_SIDE_MINIMIZED)) 865 dock_side_before_minimized_ = dock_side_; 866 867 dock_side_ = requested_side; 868 if (dock_requested && !is_docked) { 869 // Detach window from the external devtools browser. It will lead to 870 // the browser object's close and delete. Remove observer first. 871 TabStripModel* tab_strip_model = browser_->tab_strip_model(); 872 tab_strip_model->DetachWebContentsAt( 873 tab_strip_model->GetIndexOfWebContents(web_contents_)); 874 browser_ = NULL; 875 } else if (!dock_requested && is_docked) { 876 // Update inspected window to hide split and reset it. 877 BrowserWindow* inspected_window = GetInspectedBrowserWindow(); 878 if (inspected_window) 879 inspected_window->UpdateDevTools(); 880 } 881 882 if (dock_side_ != DEVTOOLS_DOCK_SIDE_MINIMIZED) { 883 std::string pref_value = kPrefBottom; 884 switch (dock_side_) { 885 case DEVTOOLS_DOCK_SIDE_UNDOCKED: 886 pref_value = kPrefUndocked; 887 break; 888 case DEVTOOLS_DOCK_SIDE_RIGHT: 889 pref_value = kPrefRight; 890 break; 891 case DEVTOOLS_DOCK_SIDE_BOTTOM: 892 pref_value = kPrefBottom; 893 break; 894 case DEVTOOLS_DOCK_SIDE_MINIMIZED: 895 // We don't persist minimized state. 896 break; 897 } 898 profile_->GetPrefs()->SetString(prefs::kDevToolsDockSide, pref_value); 899 } 900 901 Show(DEVTOOLS_TOGGLE_ACTION_SHOW); 902 } 903 904 void DevToolsWindow::OpenInNewTab(const std::string& url) { 905 content::OpenURLParams params( 906 GURL(url), content::Referrer(), NEW_FOREGROUND_TAB, 907 content::PAGE_TRANSITION_LINK, false); 908 content::WebContents* inspected_web_contents = GetInspectedWebContents(); 909 if (inspected_web_contents) { 910 inspected_web_contents->OpenURL(params); 911 } else { 912 chrome::HostDesktopType host_desktop_type; 913 if (browser_) { 914 host_desktop_type = browser_->host_desktop_type(); 915 } else { 916 // There should always be a browser when there are no inspected web 917 // contents. 918 NOTREACHED(); 919 host_desktop_type = chrome::GetActiveDesktop(); 920 } 921 922 const BrowserList* browser_list = 923 BrowserList::GetInstance(host_desktop_type); 924 for (BrowserList::const_iterator it = browser_list->begin(); 925 it != browser_list->end(); ++it) { 926 if ((*it)->type() == Browser::TYPE_TABBED) { 927 (*it)->OpenURL(params); 928 break; 929 } 930 } 931 } 932 } 933 934 void DevToolsWindow::SaveToFile(const std::string& url, 935 const std::string& content, 936 bool save_as) { 937 file_helper_->Save(url, content, save_as, 938 base::Bind(&DevToolsWindow::FileSavedAs, 939 weak_factory_.GetWeakPtr(), url)); 940 } 941 942 void DevToolsWindow::AppendToFile(const std::string& url, 943 const std::string& content) { 944 file_helper_->Append(url, content, 945 base::Bind(&DevToolsWindow::AppendedTo, 946 weak_factory_.GetWeakPtr(), url)); 947 } 948 949 void DevToolsWindow::RequestFileSystems() { 950 CHECK(web_contents_->GetURL().SchemeIs(chrome::kChromeDevToolsScheme)); 951 file_helper_->RequestFileSystems(base::Bind( 952 &DevToolsWindow::FileSystemsLoaded, weak_factory_.GetWeakPtr())); 953 } 954 955 void DevToolsWindow::AddFileSystem() { 956 CHECK(web_contents_->GetURL().SchemeIs(chrome::kChromeDevToolsScheme)); 957 file_helper_->AddFileSystem( 958 base::Bind(&DevToolsWindow::FileSystemAdded, weak_factory_.GetWeakPtr()), 959 base::Bind(&DevToolsWindow::ShowDevToolsConfirmInfoBar, 960 weak_factory_.GetWeakPtr())); 961 } 962 963 void DevToolsWindow::RemoveFileSystem(const std::string& file_system_path) { 964 CHECK(web_contents_->GetURL().SchemeIs(chrome::kChromeDevToolsScheme)); 965 file_helper_->RemoveFileSystem(file_system_path); 966 StringValue file_system_path_value(file_system_path); 967 CallClientFunction("InspectorFrontendAPI.fileSystemRemoved", 968 &file_system_path_value, NULL, NULL); 969 } 970 971 void DevToolsWindow::IndexPath(int request_id, 972 const std::string& file_system_path) { 973 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); 974 CHECK(web_contents_->GetURL().SchemeIs(chrome::kChromeDevToolsScheme)); 975 if (!file_helper_->IsFileSystemAdded(file_system_path)) { 976 IndexingDone(request_id, file_system_path); 977 return; 978 } 979 indexing_jobs_[request_id] = 980 scoped_refptr<DevToolsFileSystemIndexer::FileSystemIndexingJob>( 981 file_system_indexer_->IndexPath( 982 file_system_path, 983 Bind(&DevToolsWindow::IndexingTotalWorkCalculated, 984 weak_factory_.GetWeakPtr(), 985 request_id, 986 file_system_path), 987 Bind(&DevToolsWindow::IndexingWorked, 988 weak_factory_.GetWeakPtr(), 989 request_id, 990 file_system_path), 991 Bind(&DevToolsWindow::IndexingDone, 992 weak_factory_.GetWeakPtr(), 993 request_id, 994 file_system_path))); 995 } 996 997 void DevToolsWindow::StopIndexing(int request_id) { 998 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); 999 IndexingJobsMap::iterator it = indexing_jobs_.find(request_id); 1000 if (it == indexing_jobs_.end()) 1001 return; 1002 it->second->Stop(); 1003 indexing_jobs_.erase(it); 1004 } 1005 1006 void DevToolsWindow::SearchInPath(int request_id, 1007 const std::string& file_system_path, 1008 const std::string& query) { 1009 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); 1010 CHECK(web_contents_->GetURL().SchemeIs(chrome::kChromeDevToolsScheme)); 1011 if (!file_helper_->IsFileSystemAdded(file_system_path)) { 1012 SearchCompleted(request_id, file_system_path, std::vector<std::string>()); 1013 return; 1014 } 1015 file_system_indexer_->SearchInPath(file_system_path, 1016 query, 1017 Bind(&DevToolsWindow::SearchCompleted, 1018 weak_factory_.GetWeakPtr(), 1019 request_id, 1020 file_system_path)); 1021 } 1022 1023 void DevToolsWindow::FileSavedAs(const std::string& url) { 1024 StringValue url_value(url); 1025 CallClientFunction("InspectorFrontendAPI.savedURL", &url_value, NULL, NULL); 1026 } 1027 1028 void DevToolsWindow::AppendedTo(const std::string& url) { 1029 StringValue url_value(url); 1030 CallClientFunction("InspectorFrontendAPI.appendedToURL", &url_value, NULL, 1031 NULL); 1032 } 1033 1034 void DevToolsWindow::FileSystemsLoaded( 1035 const std::vector<DevToolsFileHelper::FileSystem>& file_systems) { 1036 ListValue file_systems_value; 1037 for (size_t i = 0; i < file_systems.size(); ++i) 1038 file_systems_value.Append(CreateFileSystemValue(file_systems[i])); 1039 CallClientFunction("InspectorFrontendAPI.fileSystemsLoaded", 1040 &file_systems_value, NULL, NULL); 1041 } 1042 1043 void DevToolsWindow::FileSystemAdded( 1044 const DevToolsFileHelper::FileSystem& file_system) { 1045 StringValue error_string_value((std::string())); 1046 DictionaryValue* file_system_value = NULL; 1047 if (!file_system.file_system_path.empty()) 1048 file_system_value = CreateFileSystemValue(file_system); 1049 CallClientFunction("InspectorFrontendAPI.fileSystemAdded", 1050 &error_string_value, file_system_value, NULL); 1051 if (file_system_value) 1052 delete file_system_value; 1053 } 1054 1055 void DevToolsWindow::IndexingTotalWorkCalculated( 1056 int request_id, 1057 const std::string& file_system_path, 1058 int total_work) { 1059 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); 1060 base::FundamentalValue request_id_value(request_id); 1061 StringValue file_system_path_value(file_system_path); 1062 base::FundamentalValue total_work_value(total_work); 1063 CallClientFunction("InspectorFrontendAPI.indexingTotalWorkCalculated", 1064 &request_id_value, &file_system_path_value, 1065 &total_work_value); 1066 } 1067 1068 void DevToolsWindow::IndexingWorked(int request_id, 1069 const std::string& file_system_path, 1070 int worked) { 1071 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); 1072 base::FundamentalValue request_id_value(request_id); 1073 StringValue file_system_path_value(file_system_path); 1074 base::FundamentalValue worked_value(worked); 1075 CallClientFunction("InspectorFrontendAPI.indexingWorked", &request_id_value, 1076 &file_system_path_value, &worked_value); 1077 } 1078 1079 void DevToolsWindow::IndexingDone(int request_id, 1080 const std::string& file_system_path) { 1081 indexing_jobs_.erase(request_id); 1082 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); 1083 base::FundamentalValue request_id_value(request_id); 1084 StringValue file_system_path_value(file_system_path); 1085 CallClientFunction("InspectorFrontendAPI.indexingDone", &request_id_value, 1086 &file_system_path_value, NULL); 1087 } 1088 1089 void DevToolsWindow::SearchCompleted( 1090 int request_id, 1091 const std::string& file_system_path, 1092 const std::vector<std::string>& file_paths) { 1093 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); 1094 ListValue file_paths_value; 1095 for (std::vector<std::string>::const_iterator it(file_paths.begin()); 1096 it != file_paths.end(); ++it) { 1097 file_paths_value.AppendString(*it); 1098 } 1099 base::FundamentalValue request_id_value(request_id); 1100 StringValue file_system_path_value(file_system_path); 1101 CallClientFunction("InspectorFrontendAPI.searchCompleted", &request_id_value, 1102 &file_system_path_value, &file_paths_value); 1103 } 1104 1105 void DevToolsWindow::ShowDevToolsConfirmInfoBar( 1106 const string16& message, 1107 const InfoBarCallback& callback) { 1108 DevToolsConfirmInfoBarDelegate::Create( 1109 IsDocked() ? 1110 InfoBarService::FromWebContents(GetInspectedWebContents()) : 1111 InfoBarService::FromWebContents(web_contents_), 1112 callback, message); 1113 } 1114 1115 void DevToolsWindow::CreateDevToolsBrowser() { 1116 std::string wp_key = GetDevToolsWindowPlacementPrefKey(); 1117 PrefService* prefs = profile_->GetPrefs(); 1118 const DictionaryValue* wp_pref = prefs->GetDictionary(wp_key.c_str()); 1119 if (!wp_pref || wp_pref->empty()) { 1120 DictionaryPrefUpdate update(prefs, wp_key.c_str()); 1121 DictionaryValue* defaults = update.Get(); 1122 defaults->SetInteger("left", 100); 1123 defaults->SetInteger("top", 100); 1124 defaults->SetInteger("right", 740); 1125 defaults->SetInteger("bottom", 740); 1126 defaults->SetBoolean("maximized", false); 1127 defaults->SetBoolean("always_on_top", false); 1128 } 1129 1130 browser_ = new Browser(Browser::CreateParams::CreateForDevTools( 1131 profile_, 1132 chrome::GetHostDesktopTypeForNativeView( 1133 web_contents_->GetView()->GetNativeView()))); 1134 browser_->tab_strip_model()->AddWebContents( 1135 web_contents_, -1, content::PAGE_TRANSITION_AUTO_TOPLEVEL, 1136 TabStripModel::ADD_ACTIVE); 1137 GetRenderViewHost()->SyncRendererPrefs(); 1138 } 1139 1140 bool DevToolsWindow::FindInspectedBrowserAndTabIndex(Browser** browser, 1141 int* tab) { 1142 content::WebContents* inspected_web_contents = GetInspectedWebContents(); 1143 if (!inspected_web_contents) 1144 return false; 1145 1146 for (chrome::BrowserIterator it; !it.done(); it.Next()) { 1147 int tab_index = it->tab_strip_model()->GetIndexOfWebContents( 1148 inspected_web_contents); 1149 if (tab_index != TabStripModel::kNoTab) { 1150 *browser = *it; 1151 *tab = tab_index; 1152 return true; 1153 } 1154 } 1155 return false; 1156 } 1157 1158 BrowserWindow* DevToolsWindow::GetInspectedBrowserWindow() { 1159 Browser* browser = NULL; 1160 int tab; 1161 return FindInspectedBrowserAndTabIndex(&browser, &tab) ? 1162 browser->window() : NULL; 1163 } 1164 1165 bool DevToolsWindow::IsInspectedBrowserPopup() { 1166 Browser* browser = NULL; 1167 int tab; 1168 return FindInspectedBrowserAndTabIndex(&browser, &tab) && 1169 browser->is_type_popup(); 1170 } 1171 1172 void DevToolsWindow::UpdateFrontendDockSide() { 1173 base::StringValue dock_side(SideToString(dock_side_)); 1174 CallClientFunction("InspectorFrontendAPI.setDockSide", &dock_side, NULL, 1175 NULL); 1176 base::FundamentalValue docked(IsDocked()); 1177 CallClientFunction("InspectorFrontendAPI.setAttachedWindow", &docked, NULL, 1178 NULL); 1179 } 1180 1181 void DevToolsWindow::Hide() { 1182 if (IsDocked()) { 1183 // Update dev tools to reflect removed dev tools window. 1184 BrowserWindow* inspected_window = GetInspectedBrowserWindow(); 1185 if (inspected_window) 1186 inspected_window->UpdateDevTools(); 1187 // In case of docked web_contents_, we own it so delete here. 1188 delete web_contents_; 1189 1190 delete this; 1191 } else { 1192 // First, initiate self-destruct to free all the registrars. 1193 // Then close all tabs. Browser will take care of deleting web_contents_ 1194 // for us. 1195 Browser* browser = browser_; 1196 delete this; 1197 browser->tab_strip_model()->CloseAllTabs(); 1198 } 1199 } 1200 1201 void DevToolsWindow::ScheduleAction(DevToolsToggleAction action) { 1202 action_on_load_ = action; 1203 if (is_loaded_) 1204 DoAction(); 1205 } 1206 1207 void DevToolsWindow::DoAction() { 1208 UpdateFrontendDockSide(); 1209 switch (action_on_load_) { 1210 case DEVTOOLS_TOGGLE_ACTION_SHOW_CONSOLE: 1211 CallClientFunction("InspectorFrontendAPI.showConsole", NULL, NULL, NULL); 1212 break; 1213 1214 case DEVTOOLS_TOGGLE_ACTION_INSPECT: 1215 CallClientFunction("InspectorFrontendAPI.enterInspectElementMode", NULL, 1216 NULL, NULL); 1217 break; 1218 1219 case DEVTOOLS_TOGGLE_ACTION_SHOW: 1220 case DEVTOOLS_TOGGLE_ACTION_TOGGLE: 1221 // Do nothing. 1222 break; 1223 1224 default: 1225 NOTREACHED(); 1226 break; 1227 } 1228 action_on_load_ = DEVTOOLS_TOGGLE_ACTION_SHOW; 1229 } 1230 1231 void DevToolsWindow::UpdateTheme() { 1232 ThemeService* tp = ThemeServiceFactory::GetForProfile(profile_); 1233 DCHECK(tp); 1234 1235 std::string command("InspectorFrontendAPI.setToolbarColors(\"" + 1236 SkColorToRGBAString(tp->GetColor(ThemeProperties::COLOR_TOOLBAR)) + 1237 "\", \"" + 1238 SkColorToRGBAString(tp->GetColor(ThemeProperties::COLOR_BOOKMARK_TEXT)) + 1239 "\")"); 1240 web_contents_->GetRenderViewHost()->ExecuteJavascriptInWebFrame( 1241 string16(), ASCIIToUTF16(command)); 1242 } 1243 1244 void DevToolsWindow::AddDevToolsExtensionsToClient() { 1245 content::WebContents* inspected_web_contents = GetInspectedWebContents(); 1246 if (inspected_web_contents) { 1247 SessionTabHelper* session_tab_helper = 1248 SessionTabHelper::FromWebContents(inspected_web_contents); 1249 if (session_tab_helper) { 1250 base::FundamentalValue tabId(session_tab_helper->session_id().id()); 1251 CallClientFunction("WebInspector.setInspectedTabId", &tabId, NULL, NULL); 1252 } 1253 } 1254 1255 Profile* profile = 1256 Profile::FromBrowserContext(web_contents_->GetBrowserContext()); 1257 const ExtensionService* extension_service = extensions::ExtensionSystem::Get( 1258 profile->GetOriginalProfile())->extension_service(); 1259 if (!extension_service) 1260 return; 1261 const ExtensionSet* extensions = extension_service->extensions(); 1262 1263 ListValue results; 1264 for (ExtensionSet::const_iterator extension(extensions->begin()); 1265 extension != extensions->end(); ++extension) { 1266 if (extensions::ManifestURL::GetDevToolsPage(extension->get()).is_empty()) 1267 continue; 1268 DictionaryValue* extension_info = new DictionaryValue(); 1269 extension_info->Set( 1270 "startPage", 1271 new StringValue( 1272 extensions::ManifestURL::GetDevToolsPage(extension->get()).spec())); 1273 extension_info->Set("name", new StringValue((*extension)->name())); 1274 extension_info->Set( 1275 "exposeExperimentalAPIs", 1276 new base::FundamentalValue((*extension)->HasAPIPermission( 1277 extensions::APIPermission::kExperimental))); 1278 results.Append(extension_info); 1279 } 1280 CallClientFunction("WebInspector.addExtensions", &results, NULL, NULL); 1281 } 1282 1283 void DevToolsWindow::CallClientFunction(const std::string& function_name, 1284 const Value* arg1, 1285 const Value* arg2, 1286 const Value* arg3) { 1287 std::string params; 1288 if (arg1) { 1289 std::string json; 1290 base::JSONWriter::Write(arg1, &json); 1291 params.append(json); 1292 if (arg2) { 1293 base::JSONWriter::Write(arg2, &json); 1294 params.append(", " + json); 1295 if (arg3) { 1296 base::JSONWriter::Write(arg3, &json); 1297 params.append(", " + json); 1298 } 1299 } 1300 } 1301 string16 javascript = ASCIIToUTF16(function_name + "(" + params + ");"); 1302 web_contents_->GetRenderViewHost()-> 1303 ExecuteJavascriptInWebFrame(string16(), javascript); 1304 } 1305 1306 void DevToolsWindow::UpdateBrowserToolbar() { 1307 content::WebContents* inspected_web_contents = GetInspectedWebContents(); 1308 if (!inspected_web_contents) 1309 return; 1310 BrowserWindow* inspected_window = GetInspectedBrowserWindow(); 1311 if (inspected_window) 1312 inspected_window->UpdateToolbar(inspected_web_contents, false); 1313 } 1314 1315 bool DevToolsWindow::IsDocked() { 1316 return dock_side_ != DEVTOOLS_DOCK_SIDE_UNDOCKED; 1317 } 1318 1319 void DevToolsWindow::Restore() { 1320 if (dock_side_ == DEVTOOLS_DOCK_SIDE_MINIMIZED) 1321 SetDockSide(SideToString(dock_side_before_minimized_)); 1322 } 1323 1324 content::WebContents* DevToolsWindow::GetInspectedWebContents() { 1325 return inspected_contents_observer_ ? 1326 inspected_contents_observer_->web_contents() : NULL; 1327 } 1328