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.
5 #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/string_util.h"
15 #include "base/strings/utf_string_conversions.h"
16 #include "base/values.h"
17 #include "chrome/browser/browser_process.h"
18 #include "chrome/browser/chrome_notification_types.h"
19 #include "chrome/browser/extensions/api/debugger/debugger_api.h"
20 #include "chrome/browser/extensions/extension_service.h"
21 #include "chrome/browser/extensions/extension_system.h"
22 #include "chrome/browser/extensions/extension_web_contents_observer.h"
23 #include "chrome/browser/file_select_helper.h"
24 #include "chrome/browser/infobars/confirm_infobar_delegate.h"
25 #include "chrome/browser/infobars/infobar.h"
26 #include "chrome/browser/prefs/pref_service_syncable.h"
27 #include "chrome/browser/profiles/profile.h"
28 #include "chrome/browser/sessions/session_tab_helper.h"
29 #include "chrome/browser/themes/theme_properties.h"
30 #include "chrome/browser/themes/theme_service.h"
31 #include "chrome/browser/themes/theme_service_factory.h"
32 #include "chrome/browser/ui/browser.h"
33 #include "chrome/browser/ui/browser_dialogs.h"
34 #include "chrome/browser/ui/browser_iterator.h"
35 #include "chrome/browser/ui/browser_list.h"
36 #include "chrome/browser/ui/browser_window.h"
37 #include "chrome/browser/ui/host_desktop.h"
38 #include "chrome/browser/ui/prefs/prefs_tab_helper.h"
39 #include "chrome/browser/ui/tabs/tab_strip_model.h"
40 #include "chrome/browser/ui/webui/devtools_ui.h"
41 #include "chrome/common/chrome_switches.h"
42 #include "chrome/common/extensions/manifest_url_handler.h"
43 #include "chrome/common/pref_names.h"
44 #include "chrome/common/render_messages.h"
45 #include "chrome/common/url_constants.h"
46 #include "components/user_prefs/pref_registry_syncable.h"
47 #include "content/public/browser/browser_thread.h"
48 #include "content/public/browser/child_process_security_policy.h"
49 #include "content/public/browser/devtools_agent_host.h"
50 #include "content/public/browser/devtools_client_host.h"
51 #include "content/public/browser/devtools_manager.h"
52 #include "content/public/browser/favicon_status.h"
53 #include "content/public/browser/load_notification_details.h"
54 #include "content/public/browser/navigation_controller.h"
55 #include "content/public/browser/navigation_entry.h"
56 #include "content/public/browser/notification_source.h"
57 #include "content/public/browser/render_process_host.h"
58 #include "content/public/browser/render_view_host.h"
59 #include "content/public/browser/user_metrics.h"
60 #include "content/public/browser/web_contents.h"
61 #include "content/public/browser/web_contents_observer.h"
62 #include "content/public/browser/web_contents_view.h"
63 #include "content/public/common/bindings_policy.h"
64 #include "content/public/common/content_client.h"
65 #include "content/public/common/page_transition_types.h"
66 #include "content/public/common/url_constants.h"
67 #include "extensions/common/extension_set.h"
68 #include "grit/generated_resources.h"
69 #include "ui/base/l10n/l10n_util.h"
71 using base::DictionaryValue
;
72 using content::BrowserThread
;
73 using content::DevToolsAgentHost
;
76 // DevToolsConfirmInfoBarDelegate ---------------------------------------------
78 class DevToolsConfirmInfoBarDelegate
: public ConfirmInfoBarDelegate
{
80 // If |infobar_service| is NULL, runs |callback| with a single argument with
81 // value "false". Otherwise, creates a dev tools confirm infobar and delegate
82 // and adds the inofbar to |infobar_service|.
83 static void Create(InfoBarService
* infobar_service
,
84 const DevToolsWindow::InfoBarCallback
& callback
,
85 const base::string16
& message
);
88 DevToolsConfirmInfoBarDelegate(
89 const DevToolsWindow::InfoBarCallback
& callback
,
90 const base::string16
& message
);
91 virtual ~DevToolsConfirmInfoBarDelegate();
93 virtual base::string16
GetMessageText() const OVERRIDE
;
94 virtual base::string16
GetButtonLabel(InfoBarButton button
) const OVERRIDE
;
95 virtual bool Accept() OVERRIDE
;
96 virtual bool Cancel() OVERRIDE
;
98 DevToolsWindow::InfoBarCallback callback_
;
99 const base::string16 message_
;
101 DISALLOW_COPY_AND_ASSIGN(DevToolsConfirmInfoBarDelegate
);
104 void DevToolsConfirmInfoBarDelegate::Create(
105 InfoBarService
* infobar_service
,
106 const DevToolsWindow::InfoBarCallback
& callback
,
107 const base::string16
& message
) {
108 if (!infobar_service
) {
113 infobar_service
->AddInfoBar(ConfirmInfoBarDelegate::CreateInfoBar(
114 scoped_ptr
<ConfirmInfoBarDelegate
>(
115 new DevToolsConfirmInfoBarDelegate(callback
, message
))));
118 DevToolsConfirmInfoBarDelegate::DevToolsConfirmInfoBarDelegate(
119 const DevToolsWindow::InfoBarCallback
& callback
,
120 const base::string16
& message
)
121 : ConfirmInfoBarDelegate(),
126 DevToolsConfirmInfoBarDelegate::~DevToolsConfirmInfoBarDelegate() {
127 if (!callback_
.is_null())
128 callback_
.Run(false);
131 base::string16
DevToolsConfirmInfoBarDelegate::GetMessageText() const {
135 base::string16
DevToolsConfirmInfoBarDelegate::GetButtonLabel(
136 InfoBarButton button
) const {
137 return l10n_util::GetStringUTF16((button
== BUTTON_OK
) ?
138 IDS_DEV_TOOLS_CONFIRM_ALLOW_BUTTON
: IDS_DEV_TOOLS_CONFIRM_DENY_BUTTON
);
141 bool DevToolsConfirmInfoBarDelegate::Accept() {
147 bool DevToolsConfirmInfoBarDelegate::Cancel() {
148 callback_
.Run(false);
154 // DevToolsWindow::InspectedWebContentsObserver -------------------------------
156 class DevToolsWindow::InspectedWebContentsObserver
157 : public content::WebContentsObserver
{
159 explicit InspectedWebContentsObserver(content::WebContents
* web_contents
);
160 virtual ~InspectedWebContentsObserver();
162 content::WebContents
* web_contents() {
163 return WebContentsObserver::web_contents();
167 DISALLOW_COPY_AND_ASSIGN(InspectedWebContentsObserver
);
170 DevToolsWindow::InspectedWebContentsObserver::InspectedWebContentsObserver(
171 content::WebContents
* web_contents
)
172 : WebContentsObserver(web_contents
) {
175 DevToolsWindow::InspectedWebContentsObserver::~InspectedWebContentsObserver() {
179 // DevToolsWindow::FrontendWebContentsObserver --------------------------------
181 class DevToolsWindow::FrontendWebContentsObserver
182 : public content::WebContentsObserver
{
184 explicit FrontendWebContentsObserver(DevToolsWindow
* window
);
185 virtual ~FrontendWebContentsObserver();
188 // contents::WebContentsObserver:
189 virtual void AboutToNavigateRenderView(
190 content::RenderViewHost
* render_view_host
) OVERRIDE
;
191 virtual void DocumentOnLoadCompletedInMainFrame(int32 page_id
) OVERRIDE
;
192 virtual void WebContentsDestroyed(content::WebContents
*) OVERRIDE
;
194 DevToolsWindow
* devtools_window_
;
195 DISALLOW_COPY_AND_ASSIGN(FrontendWebContentsObserver
);
198 DevToolsWindow::FrontendWebContentsObserver::FrontendWebContentsObserver(
199 DevToolsWindow
* devtools_window
)
200 : WebContentsObserver(devtools_window
->web_contents()),
201 devtools_window_(devtools_window
) {
204 void DevToolsWindow::FrontendWebContentsObserver::WebContentsDestroyed(
205 content::WebContents
* contents
) {
206 delete devtools_window_
;
209 DevToolsWindow::FrontendWebContentsObserver::~FrontendWebContentsObserver() {
212 void DevToolsWindow::FrontendWebContentsObserver::AboutToNavigateRenderView(
213 content::RenderViewHost
* render_view_host
) {
214 content::DevToolsClientHost::SetupDevToolsFrontendClient(render_view_host
);
217 void DevToolsWindow::FrontendWebContentsObserver::
218 DocumentOnLoadCompletedInMainFrame(int32 page_id
) {
219 devtools_window_
->DocumentOnLoadCompletedInMainFrame();
222 // DevToolsWindow -------------------------------------------------------------
226 typedef std::vector
<DevToolsWindow
*> DevToolsWindows
;
227 base::LazyInstance
<DevToolsWindows
>::Leaky g_instances
=
228 LAZY_INSTANCE_INITIALIZER
;
230 // TODO(dgozman): remove after switching to SetIsDocked.
231 const char kDockSideUndocked
[] = "undocked";
233 static const char kFrontendHostId
[] = "id";
234 static const char kFrontendHostMethod
[] = "method";
235 static const char kFrontendHostParams
[] = "params";
237 std::string
SkColorToRGBAString(SkColor color
) {
238 // We avoid StringPrintf because it will use locale specific formatters for
239 // the double (e.g. ',' instead of '.' in German).
240 return "rgba(" + base::IntToString(SkColorGetR(color
)) + "," +
241 base::IntToString(SkColorGetG(color
)) + "," +
242 base::IntToString(SkColorGetB(color
)) + "," +
243 base::DoubleToString(SkColorGetA(color
) / 255.0) + ")";
246 base::DictionaryValue
* CreateFileSystemValue(
247 DevToolsFileHelper::FileSystem file_system
) {
248 base::DictionaryValue
* file_system_value
= new base::DictionaryValue();
249 file_system_value
->SetString("fileSystemName", file_system
.file_system_name
);
250 file_system_value
->SetString("rootURL", file_system
.root_url
);
251 file_system_value
->SetString("fileSystemPath", file_system
.file_system_path
);
252 return file_system_value
;
257 const char DevToolsWindow::kDevToolsApp
[] = "DevToolsApp";
259 DevToolsWindow::~DevToolsWindow() {
260 content::DevToolsManager::GetInstance()->ClientHostClosing(
261 frontend_host_
.get());
262 UpdateBrowserToolbar();
264 DevToolsWindows
* instances
= &g_instances
.Get();
265 DevToolsWindows::iterator
it(
266 std::find(instances
->begin(), instances
->end(), this));
267 DCHECK(it
!= instances
->end());
268 instances
->erase(it
);
270 for (IndexingJobsMap::const_iterator
jobs_it(indexing_jobs_
.begin());
271 jobs_it
!= indexing_jobs_
.end(); ++jobs_it
) {
272 jobs_it
->second
->Stop();
274 indexing_jobs_
.clear();
278 std::string
DevToolsWindow::GetDevToolsWindowPlacementPrefKey() {
279 return std::string(prefs::kBrowserWindowPlacement
) + "_" +
280 std::string(kDevToolsApp
);
284 void DevToolsWindow::RegisterProfilePrefs(
285 user_prefs::PrefRegistrySyncable
* registry
) {
286 registry
->RegisterDictionaryPref(
287 prefs::kDevToolsEditedFiles
,
288 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF
);
289 registry
->RegisterDictionaryPref(
290 prefs::kDevToolsFileSystemPaths
,
291 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF
);
292 registry
->RegisterStringPref(
293 prefs::kDevToolsAdbKey
, std::string(),
294 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF
);
296 registry
->RegisterDictionaryPref(
297 GetDevToolsWindowPlacementPrefKey().c_str(),
298 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF
);
300 registry
->RegisterBooleanPref(
301 prefs::kDevToolsDiscoverUsbDevicesEnabled
,
303 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF
);
304 registry
->RegisterBooleanPref(
305 prefs::kDevToolsPortForwardingEnabled
,
307 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF
);
308 registry
->RegisterBooleanPref(
309 prefs::kDevToolsPortForwardingDefaultSet
,
311 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF
);
312 registry
->RegisterDictionaryPref(
313 prefs::kDevToolsPortForwardingConfig
,
314 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF
);
318 DevToolsWindow
* DevToolsWindow::GetDockedInstanceForInspectedTab(
319 content::WebContents
* inspected_web_contents
) {
320 DevToolsWindow
* window
= GetInstanceForInspectedRenderViewHost(
321 inspected_web_contents
->GetRenderViewHost());
324 // Not yet loaded window is treated as docked, but we should not present it
325 // until we decided on docking.
326 bool is_docked_set
= window
->load_state_
== kLoadCompleted
||
327 window
->load_state_
== kIsDockedSet
;
328 return window
->is_docked_
&& is_docked_set
? window
: NULL
;
332 DevToolsWindow
* DevToolsWindow::GetInstanceForInspectedRenderViewHost(
333 content::RenderViewHost
* inspected_rvh
) {
334 if (!inspected_rvh
|| !DevToolsAgentHost::HasFor(inspected_rvh
))
337 scoped_refptr
<DevToolsAgentHost
> agent(DevToolsAgentHost::GetOrCreateFor(
339 return FindDevToolsWindow(agent
.get());
343 bool DevToolsWindow::IsDevToolsWindow(content::RenderViewHost
* window_rvh
) {
344 return AsDevToolsWindow(window_rvh
) != NULL
;
348 DevToolsWindow
* DevToolsWindow::OpenDevToolsWindowForWorker(
350 DevToolsAgentHost
* worker_agent
) {
351 DevToolsWindow
* window
= FindDevToolsWindow(worker_agent
);
353 window
= DevToolsWindow::CreateDevToolsWindowForWorker(profile
);
354 // Will disconnect the current client host if there is one.
355 content::DevToolsManager::GetInstance()->RegisterDevToolsClientHostFor(
356 worker_agent
, window
->frontend_host_
.get());
358 window
->ScheduleShow(DevToolsToggleAction::Show());
363 DevToolsWindow
* DevToolsWindow::CreateDevToolsWindowForWorker(
365 content::RecordAction(base::UserMetricsAction("DevTools_InspectWorker"));
366 return Create(profile
, GURL(), NULL
, true, false, false);
370 DevToolsWindow
* DevToolsWindow::OpenDevToolsWindow(
371 content::RenderViewHost
* inspected_rvh
) {
372 return ToggleDevToolsWindow(
373 inspected_rvh
, true, DevToolsToggleAction::Show());
377 DevToolsWindow
* DevToolsWindow::OpenDevToolsWindow(
378 content::RenderViewHost
* inspected_rvh
,
379 const DevToolsToggleAction
& action
) {
380 return ToggleDevToolsWindow(
381 inspected_rvh
, true, action
);
385 DevToolsWindow
* DevToolsWindow::OpenDevToolsWindowForTest(
386 content::RenderViewHost
* inspected_rvh
,
388 DevToolsWindow
* window
= OpenDevToolsWindow(inspected_rvh
);
389 window
->SetIsDockedAndShowImmediatelyForTest(is_docked
);
394 DevToolsWindow
* DevToolsWindow::OpenDevToolsWindowForTest(
397 return OpenDevToolsWindowForTest(
398 browser
->tab_strip_model()->GetActiveWebContents()->GetRenderViewHost(),
403 DevToolsWindow
* DevToolsWindow::ToggleDevToolsWindow(
405 const DevToolsToggleAction
& action
) {
406 if (action
.type() == DevToolsToggleAction::kToggle
&&
407 browser
->is_devtools()) {
408 browser
->tab_strip_model()->CloseAllTabs();
412 return ToggleDevToolsWindow(
413 browser
->tab_strip_model()->GetActiveWebContents()->GetRenderViewHost(),
414 action
.type() == DevToolsToggleAction::kInspect
, action
);
418 void DevToolsWindow::OpenExternalFrontend(
420 const std::string
& frontend_url
,
421 content::DevToolsAgentHost
* agent_host
) {
422 DevToolsWindow
* window
= FindDevToolsWindow(agent_host
);
424 window
= Create(profile
, DevToolsUI::GetProxyURL(frontend_url
), NULL
,
426 content::DevToolsManager::GetInstance()->RegisterDevToolsClientHostFor(
427 agent_host
, window
->frontend_host_
.get());
429 window
->ScheduleShow(DevToolsToggleAction::Show());
433 DevToolsWindow
* DevToolsWindow::ToggleDevToolsWindow(
434 content::RenderViewHost
* inspected_rvh
,
436 const DevToolsToggleAction
& action
) {
437 scoped_refptr
<DevToolsAgentHost
> agent(
438 DevToolsAgentHost::GetOrCreateFor(inspected_rvh
));
439 content::DevToolsManager
* manager
= content::DevToolsManager::GetInstance();
440 DevToolsWindow
* window
= FindDevToolsWindow(agent
.get());
441 bool do_open
= force_open
;
443 Profile
* profile
= Profile::FromBrowserContext(
444 inspected_rvh
->GetProcess()->GetBrowserContext());
445 content::RecordAction(
446 base::UserMetricsAction("DevTools_InspectRenderer"));
447 window
= Create(profile
, GURL(), inspected_rvh
, false, false, true);
448 manager
->RegisterDevToolsClientHostFor(agent
.get(),
449 window
->frontend_host_
.get());
453 // Update toolbar to reflect DevTools changes.
454 window
->UpdateBrowserToolbar();
456 // If window is docked and visible, we hide it on toggle. If window is
457 // undocked, we show (activate) it.
458 if (!window
->is_docked_
|| do_open
)
459 window
->ScheduleShow(action
);
461 window
->CloseWindow();
467 void DevToolsWindow::InspectElement(content::RenderViewHost
* inspected_rvh
,
470 scoped_refptr
<DevToolsAgentHost
> agent(
471 DevToolsAgentHost::GetOrCreateFor(inspected_rvh
));
472 agent
->InspectElement(x
, y
);
473 // TODO(loislo): we should initiate DevTools window opening from within
474 // renderer. Otherwise, we still can hit a race condition here.
475 OpenDevToolsWindow(inspected_rvh
);
479 int DevToolsWindow::GetMinimizedHeight() {
480 const int kMinimizedDevToolsHeight
= 24;
481 return kMinimizedDevToolsHeight
;
484 void DevToolsWindow::InspectedContentsClosing() {
485 intercepted_page_beforeunload_
= false;
486 // This will prevent any activity after frontend is loaded.
487 action_on_load_
= DevToolsToggleAction::NoOp();
488 web_contents_
->GetRenderViewHost()->ClosePage();
491 content::RenderViewHost
* DevToolsWindow::GetRenderViewHost() {
492 return web_contents_
->GetRenderViewHost();
495 gfx::Insets
DevToolsWindow::GetContentsInsets() const {
496 return contents_insets_
;
499 gfx::Size
DevToolsWindow::GetMinimumSize() const {
500 const gfx::Size kMinDevToolsSize
= gfx::Size(200, 100);
501 return kMinDevToolsSize
;
504 void DevToolsWindow::ScheduleShow(const DevToolsToggleAction
& action
) {
505 if (load_state_
== kLoadCompleted
) {
510 // Action will be done only after load completed.
511 action_on_load_
= action
;
514 // No harm to show always-undocked window right away.
516 Show(DevToolsToggleAction::Show());
520 void DevToolsWindow::Show(const DevToolsToggleAction
& action
) {
521 if (action
.type() == DevToolsToggleAction::kNoOp
)
526 Browser
* inspected_browser
= NULL
;
527 int inspected_tab_index
= -1;
528 FindInspectedBrowserAndTabIndex(GetInspectedWebContents(),
530 &inspected_tab_index
);
531 DCHECK(inspected_browser
);
532 DCHECK(inspected_tab_index
!= -1);
534 // Tell inspected browser to update splitter and switch to inspected panel.
535 BrowserWindow
* inspected_window
= inspected_browser
->window();
536 web_contents_
->SetDelegate(this);
537 inspected_window
->UpdateDevTools();
538 web_contents_
->GetView()->SetInitialFocus();
539 inspected_window
->Show();
541 TabStripModel
* tab_strip_model
= inspected_browser
->tab_strip_model();
542 tab_strip_model
->ActivateTabAt(inspected_tab_index
, true);
543 PrefsTabHelper::CreateForWebContents(web_contents_
);
544 GetRenderViewHost()->SyncRendererPrefs();
550 // Avoid consecutive window switching if the devtools window has been opened
551 // and the Inspect Element shortcut is pressed in the inspected tab.
552 bool should_show_window
=
553 !browser_
|| (action
.type() != DevToolsToggleAction::kInspect
);
556 CreateDevToolsBrowser();
558 if (should_show_window
) {
559 browser_
->window()->Show();
560 web_contents_
->GetView()->SetInitialFocus();
567 bool DevToolsWindow::HandleBeforeUnload(content::WebContents
* frontend_contents
,
568 bool proceed
, bool* proceed_to_fire_unload
) {
569 DevToolsWindow
* window
= AsDevToolsWindow(
570 frontend_contents
->GetRenderViewHost());
573 if (!window
->intercepted_page_beforeunload_
)
575 window
->BeforeUnloadFired(frontend_contents
, proceed
,
576 proceed_to_fire_unload
);
581 bool DevToolsWindow::InterceptPageBeforeUnload(content::WebContents
* contents
) {
582 DevToolsWindow
* window
=
583 DevToolsWindow::GetInstanceForInspectedRenderViewHost(
584 contents
->GetRenderViewHost());
585 if (!window
|| window
->intercepted_page_beforeunload_
)
588 // Not yet loaded frontend will not handle beforeunload.
589 if (window
->load_state_
!= kLoadCompleted
)
592 window
->intercepted_page_beforeunload_
= true;
593 // Handle case of devtools inspecting another devtools instance by passing
594 // the call up to the inspecting devtools instance.
595 if (!DevToolsWindow::InterceptPageBeforeUnload(window
->web_contents())) {
596 window
->web_contents()->GetRenderViewHost()->FirePageBeforeUnload(false);
602 bool DevToolsWindow::NeedsToInterceptBeforeUnload(
603 content::WebContents
* contents
) {
604 DevToolsWindow
* window
=
605 DevToolsWindow::GetInstanceForInspectedRenderViewHost(
606 contents
->GetRenderViewHost());
607 return window
&& !window
->intercepted_page_beforeunload_
;
611 bool DevToolsWindow::HasFiredBeforeUnloadEventForDevToolsBrowser(
613 DCHECK(browser
->is_devtools());
614 // When FastUnloadController is used, devtools frontend will be detached
615 // from the browser window at this point which means we've already fired
617 if (browser
->tab_strip_model()->empty())
619 content::WebContents
* contents
=
620 browser
->tab_strip_model()->GetWebContentsAt(0);
621 DevToolsWindow
* window
= AsDevToolsWindow(contents
->GetRenderViewHost());
624 return window
->intercepted_page_beforeunload_
;
628 void DevToolsWindow::OnPageCloseCanceled(content::WebContents
* contents
) {
629 DevToolsWindow
*window
=
630 DevToolsWindow::GetInstanceForInspectedRenderViewHost(
631 contents
->GetRenderViewHost());
634 window
->intercepted_page_beforeunload_
= false;
635 // Propagate to devtools opened on devtools if any.
636 DevToolsWindow::OnPageCloseCanceled(window
->web_contents());
639 DevToolsWindow::DevToolsWindow(Profile
* profile
,
641 content::RenderViewHost
* inspected_rvh
,
647 // This initialization allows external front-end to work without changes.
648 // We don't wait for docking call, but instead immediately show undocked.
649 // Passing "dockSide=undocked" parameter ensures proper UI.
650 load_state_(can_dock
? kNotLoaded
: kIsDockedSet
),
651 action_on_load_(DevToolsToggleAction::NoOp()),
652 ignore_set_is_docked_for_test_(false),
653 intercepted_page_beforeunload_(false),
654 weak_factory_(this) {
656 content::WebContents::Create(content::WebContents::CreateParams(profile
));
657 frontend_contents_observer_
.reset(new FrontendWebContentsObserver(this));
659 // Set up delegate, so we get fully-functional window immediately.
660 // It will not appear in UI though until |load_state_ == kLoadCompleted|.
661 web_contents_
->SetDelegate(this);
663 web_contents_
->GetController().LoadURL(url
, content::Referrer(),
664 content::PAGE_TRANSITION_AUTO_TOPLEVEL
, std::string());
666 frontend_host_
.reset(content::DevToolsClientHost::CreateDevToolsFrontendHost(
667 web_contents_
, this));
668 file_helper_
.reset(new DevToolsFileHelper(web_contents_
, profile
));
669 file_system_indexer_
= new DevToolsFileSystemIndexer();
670 extensions::ExtensionWebContentsObserver::CreateForWebContents(web_contents_
);
672 g_instances
.Get().push_back(this);
674 // Wipe out page icon so that the default application icon is used.
675 content::NavigationEntry
* entry
=
676 web_contents_
->GetController().GetActiveEntry();
677 entry
->GetFavicon().image
= gfx::Image();
678 entry
->GetFavicon().valid
= true;
680 // Register on-load actions.
682 this, chrome::NOTIFICATION_BROWSER_THEME_CHANGED
,
683 content::Source
<ThemeService
>(
684 ThemeServiceFactory::GetForProfile(profile_
)));
686 // There is no inspected_rvh in case of shared workers.
688 inspected_contents_observer_
.reset(new InspectedWebContentsObserver(
689 content::WebContents::FromRenderViewHost(inspected_rvh
)));
691 embedder_message_dispatcher_
.reset(
692 new DevToolsEmbedderMessageDispatcher(this));
696 DevToolsWindow
* DevToolsWindow::Create(
698 const GURL
& frontend_url
,
699 content::RenderViewHost
* inspected_rvh
,
700 bool shared_worker_frontend
,
701 bool external_frontend
,
704 // Check for a place to dock.
705 Browser
* browser
= NULL
;
707 content::WebContents
* inspected_web_contents
=
708 content::WebContents::FromRenderViewHost(inspected_rvh
);
709 if (!FindInspectedBrowserAndTabIndex(inspected_web_contents
,
711 browser
->is_type_popup()) {
716 // Create WebContents with devtools.
717 GURL
url(GetDevToolsURL(profile
, frontend_url
,
718 shared_worker_frontend
,
721 return new DevToolsWindow(profile
, url
, inspected_rvh
, can_dock
);
725 GURL
DevToolsWindow::GetDevToolsURL(Profile
* profile
,
726 const GURL
& base_url
,
727 bool shared_worker_frontend
,
728 bool external_frontend
,
730 if (base_url
.SchemeIs("data"))
733 std::string
frontend_url(
734 base_url
.is_empty() ? chrome::kChromeUIDevToolsURL
: base_url
.spec());
735 ThemeService
* tp
= ThemeServiceFactory::GetForProfile(profile
);
737 std::string
url_string(
739 ((frontend_url
.find("?") == std::string::npos
) ? "?" : "&") +
740 "dockSide=undocked" + // TODO(dgozman): remove this support in M38.
742 SkColorToRGBAString(tp
->GetColor(ThemeProperties::COLOR_TOOLBAR
)) +
744 SkColorToRGBAString(tp
->GetColor(ThemeProperties::COLOR_BOOKMARK_TEXT
)));
745 if (shared_worker_frontend
)
746 url_string
+= "&isSharedWorker=true";
747 if (external_frontend
)
748 url_string
+= "&remoteFrontend=true";
750 url_string
+= "&can_dock=true";
751 if (CommandLine::ForCurrentProcess()->HasSwitch(
752 switches::kEnableDevToolsExperiments
))
753 url_string
+= "&experiments=true";
754 url_string
+= "&updateAppcache";
755 return GURL(url_string
);
759 DevToolsWindow
* DevToolsWindow::FindDevToolsWindow(
760 DevToolsAgentHost
* agent_host
) {
761 DevToolsWindows
* instances
= &g_instances
.Get();
762 content::DevToolsManager
* manager
= content::DevToolsManager::GetInstance();
763 for (DevToolsWindows::iterator
it(instances
->begin()); it
!= instances
->end();
765 if (manager
->GetDevToolsAgentHostFor((*it
)->frontend_host_
.get()) ==
773 DevToolsWindow
* DevToolsWindow::AsDevToolsWindow(
774 content::RenderViewHost
* window_rvh
) {
775 if (g_instances
== NULL
)
777 DevToolsWindows
* instances
= &g_instances
.Get();
778 for (DevToolsWindows::iterator
it(instances
->begin()); it
!= instances
->end();
780 if ((*it
)->web_contents_
->GetRenderViewHost() == window_rvh
)
786 // TODO(dgozman): remove after switch to SetIsDocked.
788 bool DevToolsWindow::IsDockedFromString(const std::string
& dock_side
) {
789 return dock_side
!= kDockSideUndocked
;
792 void DevToolsWindow::Observe(int type
,
793 const content::NotificationSource
& source
,
794 const content::NotificationDetails
& details
) {
795 DCHECK_EQ(chrome::NOTIFICATION_BROWSER_THEME_CHANGED
, type
);
799 content::WebContents
* DevToolsWindow::OpenURLFromTab(
800 content::WebContents
* source
,
801 const content::OpenURLParams
& params
) {
802 if (!params
.url
.SchemeIs(chrome::kChromeDevToolsScheme
)) {
803 content::WebContents
* inspected_web_contents
= GetInspectedWebContents();
804 return inspected_web_contents
?
805 inspected_web_contents
->OpenURL(params
) : NULL
;
808 content::DevToolsManager
* manager
= content::DevToolsManager::GetInstance();
809 scoped_refptr
<DevToolsAgentHost
> agent_host(
810 manager
->GetDevToolsAgentHostFor(frontend_host_
.get()));
811 if (!agent_host
.get())
813 manager
->ClientHostClosing(frontend_host_
.get());
814 manager
->RegisterDevToolsClientHostFor(agent_host
.get(),
815 frontend_host_
.get());
817 chrome::NavigateParams
nav_params(profile_
, params
.url
, params
.transition
);
818 FillNavigateParamsFromOpenURLParams(&nav_params
, params
);
819 nav_params
.source_contents
= source
;
820 nav_params
.tabstrip_add_types
= TabStripModel::ADD_NONE
;
821 nav_params
.window_action
= chrome::NavigateParams::SHOW_WINDOW
;
822 nav_params
.user_gesture
= params
.user_gesture
;
823 chrome::Navigate(&nav_params
);
824 return nav_params
.target_contents
;
827 void DevToolsWindow::AddNewContents(content::WebContents
* source
,
828 content::WebContents
* new_contents
,
829 WindowOpenDisposition disposition
,
830 const gfx::Rect
& initial_pos
,
833 content::WebContents
* inspected_web_contents
= GetInspectedWebContents();
834 if (inspected_web_contents
) {
835 inspected_web_contents
->GetDelegate()->AddNewContents(
836 source
, new_contents
, disposition
, initial_pos
, user_gesture
,
841 void DevToolsWindow::CloseContents(content::WebContents
* source
) {
843 // This will prevent any activity after frontend is loaded.
844 action_on_load_
= DevToolsToggleAction::NoOp();
845 // Update dev tools to reflect removed dev tools window.
846 BrowserWindow
* inspected_window
= GetInspectedBrowserWindow();
847 if (inspected_window
)
848 inspected_window
->UpdateDevTools();
849 // In case of docked web_contents_, we own it so delete here.
850 // Embedding DevTools window will be deleted as a result of
851 // WebContentsDestroyed callback.
852 delete web_contents_
;
855 void DevToolsWindow::BeforeUnloadFired(content::WebContents
* tab
,
857 bool* proceed_to_fire_unload
) {
858 if (!intercepted_page_beforeunload_
) {
859 // Docked devtools window closed directly.
861 content::DevToolsManager::GetInstance()->ClientHostClosing(
862 frontend_host_
.get());
864 *proceed_to_fire_unload
= proceed
;
866 // Inspected page is attempting to close.
867 content::WebContents
* inspected_web_contents
= GetInspectedWebContents();
869 inspected_web_contents
->GetRenderViewHost()->FirePageBeforeUnload(false);
872 inspected_web_contents
->GetDelegate()->BeforeUnloadFired(
873 inspected_web_contents
, false, &should_proceed
);
874 DCHECK(!should_proceed
);
876 *proceed_to_fire_unload
= false;
880 bool DevToolsWindow::PreHandleKeyboardEvent(
881 content::WebContents
* source
,
882 const content::NativeWebKeyboardEvent
& event
,
883 bool* is_keyboard_shortcut
) {
885 BrowserWindow
* inspected_window
= GetInspectedBrowserWindow();
886 if (inspected_window
) {
887 return inspected_window
->PreHandleKeyboardEvent(event
,
888 is_keyboard_shortcut
);
894 void DevToolsWindow::HandleKeyboardEvent(
895 content::WebContents
* source
,
896 const content::NativeWebKeyboardEvent
& event
) {
898 if (event
.windowsKeyCode
== 0x08) {
899 // Do not navigate back in history on Windows (http://crbug.com/74156).
902 BrowserWindow
* inspected_window
= GetInspectedBrowserWindow();
903 if (inspected_window
)
904 inspected_window
->HandleKeyboardEvent(event
);
908 content::JavaScriptDialogManager
* DevToolsWindow::GetJavaScriptDialogManager() {
909 content::WebContents
* inspected_web_contents
= GetInspectedWebContents();
910 return (inspected_web_contents
&& inspected_web_contents
->GetDelegate()) ?
911 inspected_web_contents
->GetDelegate()->GetJavaScriptDialogManager() :
912 content::WebContentsDelegate::GetJavaScriptDialogManager();
915 content::ColorChooser
* DevToolsWindow::OpenColorChooser(
916 content::WebContents
* web_contents
,
917 SkColor initial_color
,
918 const std::vector
<content::ColorSuggestion
>& suggestions
) {
919 return chrome::ShowColorChooser(web_contents
, initial_color
);
922 void DevToolsWindow::RunFileChooser(content::WebContents
* web_contents
,
923 const content::FileChooserParams
& params
) {
924 FileSelectHelper::RunFileChooser(web_contents
, params
);
927 void DevToolsWindow::WebContentsFocused(content::WebContents
* contents
) {
928 Browser
* inspected_browser
= NULL
;
929 int inspected_tab_index
= -1;
930 if (is_docked_
&& FindInspectedBrowserAndTabIndex(GetInspectedWebContents(),
932 &inspected_tab_index
))
933 inspected_browser
->window()->WebContentsFocused(contents
);
936 void DevToolsWindow::DispatchOnEmbedder(const std::string
& message
) {
938 base::ListValue empty_params
;
939 base::ListValue
* params
= &empty_params
;
941 base::DictionaryValue
* dict
= NULL
;
942 scoped_ptr
<base::Value
> parsed_message(base::JSONReader::Read(message
));
943 if (!parsed_message
||
944 !parsed_message
->GetAsDictionary(&dict
) ||
945 !dict
->GetString(kFrontendHostMethod
, &method
) ||
946 (dict
->HasKey(kFrontendHostParams
) &&
947 !dict
->GetList(kFrontendHostParams
, ¶ms
))) {
948 LOG(ERROR
) << "Invalid message was sent to embedder: " << message
;
953 dict
->GetInteger(kFrontendHostId
, &id
);
955 std::string error
= embedder_message_dispatcher_
->Dispatch(method
, params
);
957 scoped_ptr
<base::Value
> id_value(base::Value::CreateIntegerValue(id
));
958 scoped_ptr
<base::Value
> error_value(base::Value::CreateStringValue(error
));
959 CallClientFunction("InspectorFrontendAPI.embedderMessageAck",
960 id_value
.get(), error_value
.get(), NULL
);
964 void DevToolsWindow::ActivateWindow() {
965 if (is_docked_
&& GetInspectedBrowserWindow())
966 web_contents_
->GetView()->Focus();
967 else if (!is_docked_
&& !browser_
->window()->IsActive())
968 browser_
->window()->Activate();
971 void DevToolsWindow::ActivateContents(content::WebContents
* contents
) {
973 content::WebContents
* inspected_tab
= this->GetInspectedWebContents();
974 inspected_tab
->GetDelegate()->ActivateContents(inspected_tab
);
976 browser_
->window()->Activate();
980 void DevToolsWindow::CloseWindow() {
982 // This will prevent any activity after frontend is loaded.
983 action_on_load_
= DevToolsToggleAction::NoOp();
984 web_contents_
->GetRenderViewHost()->FirePageBeforeUnload(false);
987 void DevToolsWindow::SetContentsInsets(
988 int top
, int left
, int bottom
, int right
) {
989 if (contents_insets_
.top() == top
&&
990 contents_insets_
.left() == left
&&
991 contents_insets_
.bottom() == bottom
&&
992 contents_insets_
.right() == right
) {
996 contents_insets_
= gfx::Insets(top
, left
, bottom
, right
);
998 // Update inspected window.
999 BrowserWindow
* inspected_window
= GetInspectedBrowserWindow();
1000 if (inspected_window
)
1001 inspected_window
->UpdateDevTools();
1005 void DevToolsWindow::MoveWindow(int x
, int y
) {
1007 gfx::Rect bounds
= browser_
->window()->GetBounds();
1008 bounds
.Offset(x
, y
);
1009 browser_
->window()->SetBounds(bounds
);
1013 void DevToolsWindow::SetIsDockedAndShowImmediatelyForTest(bool is_docked
) {
1014 DCHECK(!is_docked
|| can_dock_
);
1015 if (load_state_
== kLoadCompleted
) {
1016 SetIsDocked(is_docked
);
1018 is_docked_
= is_docked
;
1019 load_state_
= load_state_
== kNotLoaded
? kIsDockedSet
: kLoadCompleted
;
1020 // Note that action_on_load_ will be performed after the load is actually
1021 // completed. For now, just show the window.
1022 Show(DevToolsToggleAction::Show());
1023 if (load_state_
== kLoadCompleted
)
1026 ignore_set_is_docked_for_test_
= true;
1029 void DevToolsWindow::SetDockSide(const std::string
& side
) {
1030 // TODO(dgozman): remove this method after frontend switches to SetIsDocked.
1031 SetIsDocked(IsDockedFromString(side
));
1034 void DevToolsWindow::SetIsDocked(bool dock_requested
) {
1035 if (ignore_set_is_docked_for_test_
)
1038 DCHECK(can_dock_
|| !dock_requested
);
1040 dock_requested
= false;
1042 bool was_docked
= is_docked_
;
1043 is_docked_
= dock_requested
;
1045 if (load_state_
!= kLoadCompleted
) {
1046 // This is a first time call we waited for to initialize.
1047 load_state_
= load_state_
== kNotLoaded
? kIsDockedSet
: kLoadCompleted
;
1048 if (load_state_
== kLoadCompleted
)
1053 if (dock_requested
== was_docked
)
1056 if (dock_requested
&& !was_docked
) {
1057 // Detach window from the external devtools browser. It will lead to
1058 // the browser object's close and delete. Remove observer first.
1059 TabStripModel
* tab_strip_model
= browser_
->tab_strip_model();
1060 tab_strip_model
->DetachWebContentsAt(
1061 tab_strip_model
->GetIndexOfWebContents(web_contents_
));
1063 } else if (!dock_requested
&& was_docked
) {
1064 // Update inspected window to hide split and reset it.
1065 BrowserWindow
* inspected_window
= GetInspectedBrowserWindow();
1066 if (inspected_window
)
1067 inspected_window
->UpdateDevTools();
1070 Show(DevToolsToggleAction::Show());
1073 void DevToolsWindow::OpenInNewTab(const std::string
& url
) {
1074 content::OpenURLParams
params(
1075 GURL(url
), content::Referrer(), NEW_FOREGROUND_TAB
,
1076 content::PAGE_TRANSITION_LINK
, false);
1077 content::WebContents
* inspected_web_contents
= GetInspectedWebContents();
1078 if (inspected_web_contents
) {
1079 inspected_web_contents
->OpenURL(params
);
1081 chrome::HostDesktopType host_desktop_type
;
1083 host_desktop_type
= browser_
->host_desktop_type();
1085 // There should always be a browser when there are no inspected web
1088 host_desktop_type
= chrome::GetActiveDesktop();
1091 const BrowserList
* browser_list
=
1092 BrowserList::GetInstance(host_desktop_type
);
1093 for (BrowserList::const_iterator it
= browser_list
->begin();
1094 it
!= browser_list
->end(); ++it
) {
1095 if ((*it
)->type() == Browser::TYPE_TABBED
) {
1096 (*it
)->OpenURL(params
);
1103 void DevToolsWindow::SaveToFile(const std::string
& url
,
1104 const std::string
& content
,
1106 file_helper_
->Save(url
, content
, save_as
,
1107 base::Bind(&DevToolsWindow::FileSavedAs
,
1108 weak_factory_
.GetWeakPtr(), url
),
1109 base::Bind(&DevToolsWindow::CanceledFileSaveAs
,
1110 weak_factory_
.GetWeakPtr(), url
));
1113 void DevToolsWindow::AppendToFile(const std::string
& url
,
1114 const std::string
& content
) {
1115 file_helper_
->Append(url
, content
,
1116 base::Bind(&DevToolsWindow::AppendedTo
,
1117 weak_factory_
.GetWeakPtr(), url
));
1120 void DevToolsWindow::RequestFileSystems() {
1121 CHECK(web_contents_
->GetURL().SchemeIs(chrome::kChromeDevToolsScheme
));
1122 file_helper_
->RequestFileSystems(base::Bind(
1123 &DevToolsWindow::FileSystemsLoaded
, weak_factory_
.GetWeakPtr()));
1126 void DevToolsWindow::AddFileSystem() {
1127 CHECK(web_contents_
->GetURL().SchemeIs(chrome::kChromeDevToolsScheme
));
1128 file_helper_
->AddFileSystem(
1129 base::Bind(&DevToolsWindow::FileSystemAdded
, weak_factory_
.GetWeakPtr()),
1130 base::Bind(&DevToolsWindow::ShowDevToolsConfirmInfoBar
,
1131 weak_factory_
.GetWeakPtr()));
1134 void DevToolsWindow::RemoveFileSystem(const std::string
& file_system_path
) {
1135 CHECK(web_contents_
->GetURL().SchemeIs(chrome::kChromeDevToolsScheme
));
1136 file_helper_
->RemoveFileSystem(file_system_path
);
1137 base::StringValue
file_system_path_value(file_system_path
);
1138 CallClientFunction("InspectorFrontendAPI.fileSystemRemoved",
1139 &file_system_path_value
, NULL
, NULL
);
1142 void DevToolsWindow::UpgradeDraggedFileSystemPermissions(
1143 const std::string
& file_system_url
) {
1144 CHECK(web_contents_
->GetURL().SchemeIs(chrome::kChromeDevToolsScheme
));
1145 file_helper_
->UpgradeDraggedFileSystemPermissions(
1147 base::Bind(&DevToolsWindow::FileSystemAdded
, weak_factory_
.GetWeakPtr()),
1148 base::Bind(&DevToolsWindow::ShowDevToolsConfirmInfoBar
,
1149 weak_factory_
.GetWeakPtr()));
1152 void DevToolsWindow::IndexPath(int request_id
,
1153 const std::string
& file_system_path
) {
1154 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
1155 CHECK(web_contents_
->GetURL().SchemeIs(chrome::kChromeDevToolsScheme
));
1156 if (!file_helper_
->IsFileSystemAdded(file_system_path
)) {
1157 IndexingDone(request_id
, file_system_path
);
1160 indexing_jobs_
[request_id
] =
1161 scoped_refptr
<DevToolsFileSystemIndexer::FileSystemIndexingJob
>(
1162 file_system_indexer_
->IndexPath(
1164 Bind(&DevToolsWindow::IndexingTotalWorkCalculated
,
1165 weak_factory_
.GetWeakPtr(),
1168 Bind(&DevToolsWindow::IndexingWorked
,
1169 weak_factory_
.GetWeakPtr(),
1172 Bind(&DevToolsWindow::IndexingDone
,
1173 weak_factory_
.GetWeakPtr(),
1175 file_system_path
)));
1178 void DevToolsWindow::StopIndexing(int request_id
) {
1179 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
1180 IndexingJobsMap::iterator it
= indexing_jobs_
.find(request_id
);
1181 if (it
== indexing_jobs_
.end())
1184 indexing_jobs_
.erase(it
);
1187 void DevToolsWindow::SearchInPath(int request_id
,
1188 const std::string
& file_system_path
,
1189 const std::string
& query
) {
1190 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
1191 CHECK(web_contents_
->GetURL().SchemeIs(chrome::kChromeDevToolsScheme
));
1192 if (!file_helper_
->IsFileSystemAdded(file_system_path
)) {
1193 SearchCompleted(request_id
, file_system_path
, std::vector
<std::string
>());
1196 file_system_indexer_
->SearchInPath(file_system_path
,
1198 Bind(&DevToolsWindow::SearchCompleted
,
1199 weak_factory_
.GetWeakPtr(),
1204 void DevToolsWindow::FileSavedAs(const std::string
& url
) {
1205 base::StringValue
url_value(url
);
1206 CallClientFunction("InspectorFrontendAPI.savedURL", &url_value
, NULL
, NULL
);
1209 void DevToolsWindow::CanceledFileSaveAs(const std::string
& url
) {
1210 base::StringValue
url_value(url
);
1211 CallClientFunction("InspectorFrontendAPI.canceledSaveURL",
1212 &url_value
, NULL
, NULL
);
1215 void DevToolsWindow::AppendedTo(const std::string
& url
) {
1216 base::StringValue
url_value(url
);
1217 CallClientFunction("InspectorFrontendAPI.appendedToURL", &url_value
, NULL
,
1221 void DevToolsWindow::FileSystemsLoaded(
1222 const std::vector
<DevToolsFileHelper::FileSystem
>& file_systems
) {
1223 base::ListValue file_systems_value
;
1224 for (size_t i
= 0; i
< file_systems
.size(); ++i
)
1225 file_systems_value
.Append(CreateFileSystemValue(file_systems
[i
]));
1226 CallClientFunction("InspectorFrontendAPI.fileSystemsLoaded",
1227 &file_systems_value
, NULL
, NULL
);
1230 void DevToolsWindow::FileSystemAdded(
1231 const DevToolsFileHelper::FileSystem
& file_system
) {
1232 scoped_ptr
<base::StringValue
> error_string_value(
1233 new base::StringValue(std::string()));
1234 scoped_ptr
<base::DictionaryValue
> file_system_value
;
1235 if (!file_system
.file_system_path
.empty())
1236 file_system_value
.reset(CreateFileSystemValue(file_system
));
1237 CallClientFunction("InspectorFrontendAPI.fileSystemAdded",
1238 error_string_value
.get(), file_system_value
.get(), NULL
);
1241 void DevToolsWindow::IndexingTotalWorkCalculated(
1243 const std::string
& file_system_path
,
1245 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
1246 base::FundamentalValue
request_id_value(request_id
);
1247 base::StringValue
file_system_path_value(file_system_path
);
1248 base::FundamentalValue
total_work_value(total_work
);
1249 CallClientFunction("InspectorFrontendAPI.indexingTotalWorkCalculated",
1250 &request_id_value
, &file_system_path_value
,
1254 void DevToolsWindow::IndexingWorked(int request_id
,
1255 const std::string
& file_system_path
,
1257 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
1258 base::FundamentalValue
request_id_value(request_id
);
1259 base::StringValue
file_system_path_value(file_system_path
);
1260 base::FundamentalValue
worked_value(worked
);
1261 CallClientFunction("InspectorFrontendAPI.indexingWorked", &request_id_value
,
1262 &file_system_path_value
, &worked_value
);
1265 void DevToolsWindow::IndexingDone(int request_id
,
1266 const std::string
& file_system_path
) {
1267 indexing_jobs_
.erase(request_id
);
1268 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
1269 base::FundamentalValue
request_id_value(request_id
);
1270 base::StringValue
file_system_path_value(file_system_path
);
1271 CallClientFunction("InspectorFrontendAPI.indexingDone", &request_id_value
,
1272 &file_system_path_value
, NULL
);
1275 void DevToolsWindow::SearchCompleted(
1277 const std::string
& file_system_path
,
1278 const std::vector
<std::string
>& file_paths
) {
1279 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
1280 base::ListValue file_paths_value
;
1281 for (std::vector
<std::string
>::const_iterator
it(file_paths
.begin());
1282 it
!= file_paths
.end(); ++it
) {
1283 file_paths_value
.AppendString(*it
);
1285 base::FundamentalValue
request_id_value(request_id
);
1286 base::StringValue
file_system_path_value(file_system_path
);
1287 CallClientFunction("InspectorFrontendAPI.searchCompleted", &request_id_value
,
1288 &file_system_path_value
, &file_paths_value
);
1291 void DevToolsWindow::ShowDevToolsConfirmInfoBar(
1292 const base::string16
& message
,
1293 const InfoBarCallback
& callback
) {
1294 DevToolsConfirmInfoBarDelegate::Create(
1296 InfoBarService::FromWebContents(GetInspectedWebContents()) :
1297 InfoBarService::FromWebContents(web_contents_
),
1301 void DevToolsWindow::CreateDevToolsBrowser() {
1302 std::string wp_key
= GetDevToolsWindowPlacementPrefKey();
1303 PrefService
* prefs
= profile_
->GetPrefs();
1304 const base::DictionaryValue
* wp_pref
= prefs
->GetDictionary(wp_key
.c_str());
1305 if (!wp_pref
|| wp_pref
->empty()) {
1306 DictionaryPrefUpdate
update(prefs
, wp_key
.c_str());
1307 base::DictionaryValue
* defaults
= update
.Get();
1308 defaults
->SetInteger("left", 100);
1309 defaults
->SetInteger("top", 100);
1310 defaults
->SetInteger("right", 740);
1311 defaults
->SetInteger("bottom", 740);
1312 defaults
->SetBoolean("maximized", false);
1313 defaults
->SetBoolean("always_on_top", false);
1316 browser_
= new Browser(Browser::CreateParams::CreateForDevTools(
1318 chrome::GetHostDesktopTypeForNativeView(
1319 web_contents_
->GetView()->GetNativeView())));
1320 browser_
->tab_strip_model()->AddWebContents(
1321 web_contents_
, -1, content::PAGE_TRANSITION_AUTO_TOPLEVEL
,
1322 TabStripModel::ADD_ACTIVE
);
1323 GetRenderViewHost()->SyncRendererPrefs();
1327 bool DevToolsWindow::FindInspectedBrowserAndTabIndex(
1328 content::WebContents
* inspected_web_contents
, Browser
** browser
, int* tab
) {
1329 if (!inspected_web_contents
)
1332 for (chrome::BrowserIterator it
; !it
.done(); it
.Next()) {
1333 int tab_index
= it
->tab_strip_model()->GetIndexOfWebContents(
1334 inspected_web_contents
);
1335 if (tab_index
!= TabStripModel::kNoTab
) {
1344 BrowserWindow
* DevToolsWindow::GetInspectedBrowserWindow() {
1345 Browser
* browser
= NULL
;
1347 return FindInspectedBrowserAndTabIndex(GetInspectedWebContents(),
1349 browser
->window() : NULL
;
1352 void DevToolsWindow::DoAction(const DevToolsToggleAction
& action
) {
1353 switch (action
.type()) {
1354 case DevToolsToggleAction::kShowConsole
:
1355 CallClientFunction("InspectorFrontendAPI.showConsole", NULL
, NULL
, NULL
);
1358 case DevToolsToggleAction::kInspect
:
1359 CallClientFunction("InspectorFrontendAPI.enterInspectElementMode", NULL
,
1363 case DevToolsToggleAction::kShow
:
1364 case DevToolsToggleAction::kToggle
:
1368 case DevToolsToggleAction::kReveal
: {
1369 const DevToolsToggleAction::RevealParams
* params
=
1372 base::StringValue
url_value(params
->url
);
1373 base::FundamentalValue
line_value(static_cast<int>(params
->line_number
));
1374 base::FundamentalValue
column_value(
1375 static_cast<int>(params
->column_number
));
1376 CallClientFunction("InspectorFrontendAPI.revealSourceLine",
1388 void DevToolsWindow::UpdateTheme() {
1389 ThemeService
* tp
= ThemeServiceFactory::GetForProfile(profile_
);
1392 std::string
command("InspectorFrontendAPI.setToolbarColors(\"" +
1393 SkColorToRGBAString(tp
->GetColor(ThemeProperties::COLOR_TOOLBAR
)) +
1395 SkColorToRGBAString(tp
->GetColor(ThemeProperties::COLOR_BOOKMARK_TEXT
)) +
1397 web_contents_
->GetRenderViewHost()->ExecuteJavascriptInWebFrame(
1398 base::string16(), base::ASCIIToUTF16(command
));
1401 void DevToolsWindow::AddDevToolsExtensionsToClient() {
1402 content::WebContents
* inspected_web_contents
= GetInspectedWebContents();
1403 if (inspected_web_contents
) {
1404 SessionTabHelper
* session_tab_helper
=
1405 SessionTabHelper::FromWebContents(inspected_web_contents
);
1406 if (session_tab_helper
) {
1407 base::FundamentalValue
tabId(session_tab_helper
->session_id().id());
1408 CallClientFunction("WebInspector.setInspectedTabId", &tabId
, NULL
, NULL
);
1413 Profile::FromBrowserContext(web_contents_
->GetBrowserContext());
1414 const ExtensionService
* extension_service
= extensions::ExtensionSystem::Get(
1415 profile
->GetOriginalProfile())->extension_service();
1416 if (!extension_service
)
1418 const extensions::ExtensionSet
* extensions
= extension_service
->extensions();
1420 base::ListValue results
;
1421 for (extensions::ExtensionSet::const_iterator
extension(extensions
->begin());
1422 extension
!= extensions
->end(); ++extension
) {
1423 if (extensions::ManifestURL::GetDevToolsPage(extension
->get()).is_empty())
1425 base::DictionaryValue
* extension_info
= new base::DictionaryValue();
1426 extension_info
->Set(
1428 new base::StringValue(
1429 extensions::ManifestURL::GetDevToolsPage(extension
->get()).spec()));
1430 extension_info
->Set("name", new base::StringValue((*extension
)->name()));
1431 extension_info
->Set(
1432 "exposeExperimentalAPIs",
1433 new base::FundamentalValue((*extension
)->HasAPIPermission(
1434 extensions::APIPermission::kExperimental
)));
1435 results
.Append(extension_info
);
1437 CallClientFunction("WebInspector.addExtensions", &results
, NULL
, NULL
);
1440 void DevToolsWindow::CallClientFunction(const std::string
& function_name
,
1441 const base::Value
* arg1
,
1442 const base::Value
* arg2
,
1443 const base::Value
* arg3
) {
1447 base::JSONWriter::Write(arg1
, &json
);
1448 params
.append(json
);
1450 base::JSONWriter::Write(arg2
, &json
);
1451 params
.append(", " + json
);
1453 base::JSONWriter::Write(arg3
, &json
);
1454 params
.append(", " + json
);
1458 base::string16 javascript
=
1459 base::ASCIIToUTF16(function_name
+ "(" + params
+ ");");
1460 web_contents_
->GetRenderViewHost()->ExecuteJavascriptInWebFrame(
1461 base::string16(), javascript
);
1464 void DevToolsWindow::UpdateBrowserToolbar() {
1465 BrowserWindow
* inspected_window
= GetInspectedBrowserWindow();
1466 if (inspected_window
)
1467 inspected_window
->UpdateToolbar(NULL
);
1470 content::WebContents
* DevToolsWindow::GetInspectedWebContents() {
1471 return inspected_contents_observer_
?
1472 inspected_contents_observer_
->web_contents() : NULL
;
1475 void DevToolsWindow::DocumentOnLoadCompletedInMainFrame() {
1476 load_state_
= load_state_
== kNotLoaded
? kOnLoadFired
: kLoadCompleted
;
1477 if (load_state_
== kLoadCompleted
)
1481 void DevToolsWindow::LoadCompleted() {
1482 Show(action_on_load_
);
1483 action_on_load_
= DevToolsToggleAction::NoOp();
1485 AddDevToolsExtensionsToClient();