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"
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
{
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
);
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
) {
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
),
121 DevToolsConfirmInfoBarDelegate::~DevToolsConfirmInfoBarDelegate() {
122 if (!callback_
.is_null())
123 callback_
.Run(false);
126 string16
DevToolsConfirmInfoBarDelegate::GetMessageText() const {
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() {
142 bool DevToolsConfirmInfoBarDelegate::Cancel() {
143 callback_
.Run(false);
149 // DevToolsWindow::InspectedWebContentsObserver -------------------------------
151 class DevToolsWindow::InspectedWebContentsObserver
152 : public content::WebContentsObserver
{
154 explicit InspectedWebContentsObserver(content::WebContents
* web_contents
);
155 virtual ~InspectedWebContentsObserver();
157 content::WebContents
* web_contents() {
158 return WebContentsObserver::web_contents();
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
{
179 explicit FrontendWebContentsObserver(DevToolsWindow
* window
);
180 virtual ~FrontendWebContentsObserver();
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 -------------------------------------------------------------
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
;
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();
271 std::string
DevToolsWindow::GetDevToolsWindowPlacementPrefKey() {
272 return std::string(prefs::kBrowserWindowPlacement
) + "_" +
273 std::string(kDevToolsApp
);
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
,
302 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF
);
303 registry
->RegisterBooleanPref(
304 prefs::kDevToolsPortForwardingEnabled
,
306 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF
);
307 registry
->RegisterBooleanPref(
308 prefs::kDevToolsPortForwardingDefaultSet
,
310 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF
);
311 registry
->RegisterDictionaryPref(
312 prefs::kDevToolsPortForwardingConfig
,
313 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF
);
317 DevToolsWindow
* DevToolsWindow::GetDockedInstanceForInspectedTab(
318 content::WebContents
* inspected_web_contents
) {
319 if (!inspected_web_contents
||
320 !DevToolsAgentHost::HasFor(inspected_web_contents
->GetRenderViewHost()))
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
;
329 bool DevToolsWindow::IsDevToolsWindow(content::RenderViewHost
* window_rvh
) {
330 return AsDevToolsWindow(window_rvh
) != NULL
;
334 DevToolsWindow
* DevToolsWindow::OpenDevToolsWindowForWorker(
336 DevToolsAgentHost
* worker_agent
) {
337 DevToolsWindow
* window
= FindDevToolsWindow(worker_agent
);
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
);
349 DevToolsWindow
* DevToolsWindow::CreateDevToolsWindowForWorker(
351 return Create(profile
, GURL(), NULL
, DEVTOOLS_DOCK_SIDE_UNDOCKED
, true,
356 DevToolsWindow
* DevToolsWindow::OpenDevToolsWindow(
357 content::RenderViewHost
* inspected_rvh
) {
358 return ToggleDevToolsWindow(inspected_rvh
, true,
359 DEVTOOLS_TOGGLE_ACTION_SHOW
);
363 DevToolsWindow
* DevToolsWindow::ToggleDevToolsWindow(
365 DevToolsToggleAction action
) {
366 if (action
== DEVTOOLS_TOGGLE_ACTION_TOGGLE
&& browser
->is_devtools()) {
367 browser
->tab_strip_model()->CloseAllTabs();
371 return ToggleDevToolsWindow(
372 browser
->tab_strip_model()->GetActiveWebContents()->GetRenderViewHost(),
373 action
== DEVTOOLS_TOGGLE_ACTION_INSPECT
, action
);
377 void DevToolsWindow::OpenExternalFrontend(
379 const std::string
& frontend_url
,
380 content::DevToolsAgentHost
* agent_host
) {
381 DevToolsWindow
* window
= FindDevToolsWindow(agent_host
);
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
);
392 DevToolsWindow
* DevToolsWindow::ToggleDevToolsWindow(
393 content::RenderViewHost
* inspected_rvh
,
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
;
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());
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
)
418 else if (!window
->IsDocked() || do_open
)
419 window
->Show(action
);
421 window
->CloseWindow();
427 void DevToolsWindow::InspectElement(content::RenderViewHost
* inspected_rvh
,
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
);
439 int DevToolsWindow::GetMinimumWidth() {
440 const int kMinDevToolsWidth
= 150;
441 return kMinDevToolsWidth
;
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
;
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
) {
472 width_
= profile_
->GetPrefs()->
473 GetInteger(prefs::kDevToolsVSplitLocation
);
476 // By default, size devtools as 1/3 of the browser window.
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
485 width_
= std::min(container_width
- kMinContentsSize
, width_
);
489 int DevToolsWindow::GetHeight(int container_height
) {
491 height_
= profile_
->GetPrefs()->
492 GetInteger(prefs::kDevToolsHSplitLocation
);
495 // By default, size devtools as 1/3 of the browser window.
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_
);
507 void DevToolsWindow::SetWidth(int width
) {
509 profile_
->GetPrefs()->SetInteger(prefs::kDevToolsVSplitLocation
, width
);
512 void DevToolsWindow::SetHeight(int height
) {
514 profile_
->GetPrefs()->SetInteger(prefs::kDevToolsHSplitLocation
, height
);
517 void DevToolsWindow::Show(DevToolsToggleAction action
) {
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
);
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
);
548 CreateDevToolsBrowser();
550 if (should_show_window
) {
551 browser_
->window()->Show();
552 web_contents_
->GetView()->SetInitialFocus();
555 ScheduleAction(action
);
558 DevToolsWindow::DevToolsWindow(Profile
* profile
,
560 content::RenderViewHost
* inspected_rvh
,
561 DevToolsDockSide dock_side
)
564 dock_side_(dock_side
),
566 action_on_load_(DEVTOOLS_TOGGLE_ACTION_SHOW
),
569 dock_side_before_minimized_(dock_side
),
570 weak_factory_(this) {
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
);
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.
603 inspected_contents_observer_
.reset(new InspectedWebContentsObserver(
604 content::WebContents::FromRenderViewHost(inspected_rvh
)));
606 embedder_message_dispatcher_
.reset(
607 new DevToolsEmbedderMessageDispatcher(this));
611 DevToolsWindow
* DevToolsWindow::Create(
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
,
622 return new DevToolsWindow(profile
, url
, inspected_rvh
, dock_side
);
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"))
634 std::string
frontend_url(
635 base_url
.is_empty() ? chrome::kChromeUIDevToolsURL
: base_url
.spec());
636 ThemeService
* tp
= ThemeServiceFactory::GetForProfile(profile
);
638 std::string
url_string(
640 ((frontend_url
.find("?") == std::string::npos
) ? "?" : "&") +
641 "dockSide=" + SideToString(dock_side
) +
643 SkColorToRGBAString(tp
->GetColor(ThemeProperties::COLOR_TOOLBAR
)) +
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
);
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();
663 if (manager
->GetDevToolsAgentHostFor((*it
)->frontend_host_
.get()) ==
671 DevToolsWindow
* DevToolsWindow::AsDevToolsWindow(
672 content::RenderViewHost
* window_rvh
) {
673 if (g_instances
== NULL
)
675 DevToolsWindows
* instances
= &g_instances
.Get();
676 for (DevToolsWindows::iterator
it(instances
->begin()); it
!= instances
->end();
678 if ((*it
)->web_contents_
->GetRenderViewHost() == window_rvh
)
685 DevToolsDockSide
DevToolsWindow::GetDockSideFromPrefs(Profile
* profile
) {
686 std::string dock_side
=
687 profile
->GetPrefs()->GetString(prefs::kDevToolsDockSide
);
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
;
708 std::string
DevToolsWindow::SideToString(DevToolsDockSide 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
;
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();
745 DCHECK_EQ(chrome::NOTIFICATION_BROWSER_THEME_CHANGED
, type
);
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())
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
,
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
,
792 void DevToolsWindow::CloseContents(content::WebContents
* source
) {
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_
;
804 void DevToolsWindow::BeforeUnloadFired(content::WebContents
* tab
,
806 bool* proceed_to_fire_unload
) {
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
) {
819 BrowserWindow
* inspected_window
= GetInspectedBrowserWindow();
820 if (inspected_window
) {
821 return inspected_window
->PreHandleKeyboardEvent(event
,
822 is_keyboard_shortcut
);
828 void DevToolsWindow::HandleKeyboardEvent(
829 content::WebContents
* source
,
830 const content::NativeWebKeyboardEvent
& event
) {
832 if (event
.windowsKeyCode
== 0x08) {
833 // Do not navigate back in history on Windows (http://crbug.com/74156).
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
) {
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
, ¶ms
))) {
880 LOG(ERROR
) << "Invalid message was sent to embedder: " << message
;
885 dict
->GetInteger(kFrontendHostId
, &id
);
887 std::string error
= embedder_message_dispatcher_
->Dispatch(method
, params
);
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
) {
905 content::WebContents
* inspected_tab
= this->GetInspectedWebContents();
906 inspected_tab
->GetDelegate()->ActivateContents(inspected_tab
);
908 browser_
->window()->Activate();
912 void DevToolsWindow::CloseWindow() {
914 web_contents_
->GetRenderViewHost()->FirePageBeforeUnload(false);
917 void DevToolsWindow::SetWindowBounds(int x
, int y
, int width
, int height
) {
919 browser_
->window()->SetBounds(gfx::Rect(x
, y
, width
, height
));
922 void DevToolsWindow::MoveWindow(int x
, int y
) {
924 gfx::Rect bounds
= browser_
->window()->GetBounds();
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.
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_
));
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
;
967 case DEVTOOLS_DOCK_SIDE_RIGHT
:
968 pref_value
= kPrefRight
;
970 case DEVTOOLS_DOCK_SIDE_BOTTOM
:
971 pref_value
= kPrefBottom
;
973 case DEVTOOLS_DOCK_SIDE_MINIMIZED
:
974 // We don't persist minimized state.
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
);
991 chrome::HostDesktopType host_desktop_type
;
993 host_desktop_type
= browser_
->host_desktop_type();
995 // There should always be a browser when there are no inspected web
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
);
1013 void DevToolsWindow::SaveToFile(const std::string
& url
,
1014 const std::string
& content
,
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
);
1058 indexing_jobs_
[request_id
] =
1059 scoped_refptr
<DevToolsFileSystemIndexer::FileSystemIndexingJob
>(
1060 file_system_indexer_
->IndexPath(
1062 Bind(&DevToolsWindow::IndexingTotalWorkCalculated
,
1063 weak_factory_
.GetWeakPtr(),
1066 Bind(&DevToolsWindow::IndexingWorked
,
1067 weak_factory_
.GetWeakPtr(),
1070 Bind(&DevToolsWindow::IndexingDone
,
1071 weak_factory_
.GetWeakPtr(),
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())
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
>());
1094 file_system_indexer_
->SearchInPath(file_system_path
,
1096 Bind(&DevToolsWindow::SearchCompleted
,
1097 weak_factory_
.GetWeakPtr(),
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
,
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(
1136 const std::string
& file_system_path
,
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
,
1147 void DevToolsWindow::IndexingWorked(int request_id
,
1148 const std::string
& file_system_path
,
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(
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(
1189 InfoBarService::FromWebContents(GetInspectedWebContents()) :
1190 InfoBarService::FromWebContents(web_contents_
),
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(
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
,
1221 content::WebContents
* inspected_web_contents
= GetInspectedWebContents();
1222 if (!inspected_web_contents
)
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
) {
1237 BrowserWindow
* DevToolsWindow::GetInspectedBrowserWindow() {
1238 Browser
* browser
= NULL
;
1240 return FindInspectedBrowserAndTabIndex(&browser
, &tab
) ?
1241 browser
->window() : NULL
;
1244 bool DevToolsWindow::IsInspectedBrowserPopup() {
1245 Browser
* browser
= NULL
;
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
,
1255 base::FundamentalValue
docked(IsDocked());
1256 CallClientFunction("InspectorFrontendAPI.setAttachedWindow", &docked
, NULL
,
1260 void DevToolsWindow::ScheduleAction(DevToolsToggleAction action
) {
1261 action_on_load_
= action
;
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
);
1273 case DEVTOOLS_TOGGLE_ACTION_INSPECT
:
1274 CallClientFunction("InspectorFrontendAPI.enterInspectElementMode", NULL
,
1278 case DEVTOOLS_TOGGLE_ACTION_SHOW
:
1279 case DEVTOOLS_TOGGLE_ACTION_TOGGLE
:
1287 action_on_load_
= DEVTOOLS_TOGGLE_ACTION_SHOW
;
1290 void DevToolsWindow::UpdateTheme() {
1291 ThemeService
* tp
= ThemeServiceFactory::GetForProfile(profile_
);
1294 std::string
command("InspectorFrontendAPI.setToolbarColors(\"" +
1295 SkColorToRGBAString(tp
->GetColor(ThemeProperties::COLOR_TOOLBAR
)) +
1297 SkColorToRGBAString(tp
->GetColor(ThemeProperties::COLOR_BOOKMARK_TEXT
)) +
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
);
1315 Profile::FromBrowserContext(web_contents_
->GetBrowserContext());
1316 const ExtensionService
* extension_service
= extensions::ExtensionSystem::Get(
1317 profile
->GetOriginalProfile())->extension_service();
1318 if (!extension_service
)
1320 const ExtensionSet
* extensions
= extension_service
->extensions();
1323 for (ExtensionSet::const_iterator
extension(extensions
->begin());
1324 extension
!= extensions
->end(); ++extension
) {
1325 if (extensions::ManifestURL::GetDevToolsPage(extension
->get()).is_empty())
1327 DictionaryValue
* extension_info
= new DictionaryValue();
1328 extension_info
->Set(
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
,
1345 const Value
* arg3
) {
1349 base::JSONWriter::Write(arg1
, &json
);
1350 params
.append(json
);
1352 base::JSONWriter::Write(arg2
, &json
);
1353 params
.append(", " + json
);
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() {
1389 AddDevToolsExtensionsToClient();