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