Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(144)

Side by Side Diff: chrome/browser/debugger/devtools_window.cc

Issue 11630004: DevTools: rename debugger/ to devtools/, move DevTools files into content/renderer/devtools. (Closed) Base URL: http://git.chromium.org/chromium/src.git@master
Patch Set: For landing Created 8 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include <algorithm>
6
7 #include "base/command_line.h"
8 #include "base/json/json_writer.h"
9 #include "base/lazy_instance.h"
10 #include "base/string_number_conversions.h"
11 #include "base/stringprintf.h"
12 #include "base/utf_string_conversions.h"
13 #include "base/values.h"
14 #include "chrome/browser/browser_process.h"
15 #include "chrome/browser/debugger/devtools_window.h"
16 #include "chrome/browser/extensions/api/debugger/debugger_api.h"
17 #include "chrome/browser/extensions/extension_service.h"
18 #include "chrome/browser/extensions/extension_system.h"
19 #include "chrome/browser/file_select_helper.h"
20 #include "chrome/browser/prefs/pref_service.h"
21 #include "chrome/browser/prefs/scoped_user_pref_update.h"
22 #include "chrome/browser/profiles/profile.h"
23 #include "chrome/browser/sessions/session_tab_helper.h"
24 #include "chrome/browser/themes/theme_service.h"
25 #include "chrome/browser/themes/theme_service_factory.h"
26 #include "chrome/browser/ui/browser.h"
27 #include "chrome/browser/ui/browser_list.h"
28 #include "chrome/browser/ui/browser_list_impl.h"
29 #include "chrome/browser/ui/browser_window.h"
30 #include "chrome/browser/ui/tabs/tab_strip_model.h"
31 #include "chrome/common/chrome_notification_types.h"
32 #include "chrome/common/chrome_switches.h"
33 #include "chrome/common/pref_names.h"
34 #include "chrome/common/render_messages.h"
35 #include "chrome/common/url_constants.h"
36 #include "content/public/browser/content_browser_client.h"
37 #include "content/public/browser/devtools_agent_host_registry.h"
38 #include "content/public/browser/devtools_manager.h"
39 #include "content/public/browser/favicon_status.h"
40 #include "content/public/browser/load_notification_details.h"
41 #include "content/public/browser/navigation_controller.h"
42 #include "content/public/browser/navigation_entry.h"
43 #include "content/public/browser/notification_source.h"
44 #include "content/public/browser/render_process_host.h"
45 #include "content/public/browser/render_view_host.h"
46 #include "content/public/browser/web_contents.h"
47 #include "content/public/browser/web_contents_view.h"
48 #include "content/public/common/bindings_policy.h"
49 #include "content/public/common/page_transition_types.h"
50 #include "grit/generated_resources.h"
51
52 typedef std::vector<DevToolsWindow*> DevToolsWindowList;
53 namespace {
54 base::LazyInstance<DevToolsWindowList>::Leaky
55 g_instances = LAZY_INSTANCE_INITIALIZER;
56 } // namespace
57
58 using content::DevToolsAgentHost;
59 using content::DevToolsAgentHostRegistry;
60 using content::DevToolsClientHost;
61 using content::DevToolsManager;
62 using content::FileChooserParams;
63 using content::NativeWebKeyboardEvent;
64 using content::NavigationController;
65 using content::NavigationEntry;
66 using content::OpenURLParams;
67 using content::RenderViewHost;
68 using content::WebContents;
69
70 const char DevToolsWindow::kDevToolsApp[] = "DevToolsApp";
71
72 const char kOldPrefBottom[] = "bottom";
73 const char kOldPrefRight[] = "right";
74
75 const char kPrefBottom[] = "dock_bottom";
76 const char kPrefRight[] = "dock_right";
77 const char kPrefUndocked[] = "undocked";
78
79 const char kDockSideBottom[] = "bottom";
80 const char kDockSideRight[] = "right";
81 const char kDockSideUndocked[] = "undocked";
82
83 // Minimal height of devtools pane or content pane when devtools are docked
84 // to the browser window.
85 const int kMinDevToolsHeight = 50;
86 const int kMinDevToolsWidth = 150;
87 const int kMinContentsSize = 50;
88
89 // static
90 void DevToolsWindow::RegisterUserPrefs(PrefService* prefs) {
91 prefs->RegisterBooleanPref(prefs::kDevToolsOpenDocked,
92 true,
93 PrefService::UNSYNCABLE_PREF);
94 prefs->RegisterStringPref(prefs::kDevToolsDockSide,
95 kDockSideBottom,
96 PrefService::UNSYNCABLE_PREF);
97 prefs->RegisterDictionaryPref(prefs::kDevToolsEditedFiles,
98 PrefService::UNSYNCABLE_PREF);
99 }
100
101 // static
102 DevToolsWindow* DevToolsWindow::GetDockedInstanceForInspectedTab(
103 WebContents* inspected_web_contents) {
104 if (!inspected_web_contents)
105 return NULL;
106
107 if (!DevToolsAgentHostRegistry::HasDevToolsAgentHost(
108 inspected_web_contents->GetRenderViewHost()))
109 return NULL;
110 DevToolsAgentHost* agent = DevToolsAgentHostRegistry::GetDevToolsAgentHost(
111 inspected_web_contents->GetRenderViewHost());
112 DevToolsManager* manager = DevToolsManager::GetInstance();
113 DevToolsClientHost* client_host = manager->GetDevToolsClientHostFor(agent);
114 DevToolsWindow* window = AsDevToolsWindow(client_host);
115 return window && window->IsDocked() ? window : NULL;
116 }
117
118 // static
119 bool DevToolsWindow::IsDevToolsWindow(RenderViewHost* window_rvh) {
120 return AsDevToolsWindow(window_rvh) != NULL;
121 }
122
123 // static
124 DevToolsWindow* DevToolsWindow::OpenDevToolsWindowForWorker(
125 Profile* profile,
126 DevToolsAgentHost* worker_agent) {
127 DevToolsWindow* window;
128 DevToolsClientHost* client = content::DevToolsManager::GetInstance()->
129 GetDevToolsClientHostFor(worker_agent);
130 if (client) {
131 window = AsDevToolsWindow(client);
132 if (!window)
133 return NULL;
134 } else {
135 window = DevToolsWindow::CreateDevToolsWindowForWorker(profile);
136 DevToolsManager::GetInstance()->RegisterDevToolsClientHostFor(
137 worker_agent,
138 window->frontend_host_);
139 }
140 window->Show(DEVTOOLS_TOGGLE_ACTION_SHOW);
141 return window;
142 }
143
144 // static
145 DevToolsWindow* DevToolsWindow::CreateDevToolsWindowForWorker(
146 Profile* profile) {
147 return Create(profile, NULL, DEVTOOLS_DOCK_SIDE_UNDOCKED, true);
148 }
149
150 // static
151 DevToolsWindow* DevToolsWindow::OpenDevToolsWindow(
152 RenderViewHost* inspected_rvh) {
153 return ToggleDevToolsWindow(inspected_rvh, true,
154 DEVTOOLS_TOGGLE_ACTION_SHOW);
155 }
156
157 // static
158 DevToolsWindow* DevToolsWindow::ToggleDevToolsWindow(
159 Browser* browser,
160 DevToolsToggleAction action) {
161 if (action == DEVTOOLS_TOGGLE_ACTION_TOGGLE && browser->is_devtools()) {
162 browser->tab_strip_model()->CloseAllTabs();
163 return NULL;
164 }
165 RenderViewHost* inspected_rvh =
166 browser->tab_strip_model()->GetActiveWebContents()->GetRenderViewHost();
167
168 return ToggleDevToolsWindow(inspected_rvh,
169 action == DEVTOOLS_TOGGLE_ACTION_INSPECT,
170 action);
171 }
172
173 void DevToolsWindow::InspectElement(RenderViewHost* inspected_rvh,
174 int x,
175 int y) {
176 DevToolsAgentHost* agent = DevToolsAgentHostRegistry::GetDevToolsAgentHost(
177 inspected_rvh);
178 DevToolsManager::GetInstance()->InspectElement(agent, x, y);
179 // TODO(loislo): we should initiate DevTools window opening from within
180 // renderer. Otherwise, we still can hit a race condition here.
181 OpenDevToolsWindow(inspected_rvh);
182 }
183
184
185 DevToolsWindow* DevToolsWindow::Create(
186 Profile* profile,
187 RenderViewHost* inspected_rvh,
188 DevToolsDockSide dock_side,
189 bool shared_worker_frontend) {
190 // Create WebContents with devtools.
191 WebContents* web_contents =
192 WebContents::Create(WebContents::CreateParams(profile));
193 web_contents->GetRenderViewHost()->AllowBindings(
194 content::BINDINGS_POLICY_WEB_UI);
195 web_contents->GetController().LoadURL(
196 GetDevToolsUrl(profile, dock_side, shared_worker_frontend),
197 content::Referrer(),
198 content::PAGE_TRANSITION_AUTO_TOPLEVEL,
199 std::string());
200 return new DevToolsWindow(web_contents, profile, inspected_rvh, dock_side);
201 }
202
203 DevToolsWindow::DevToolsWindow(WebContents* web_contents,
204 Profile* profile,
205 RenderViewHost* inspected_rvh,
206 DevToolsDockSide dock_side)
207 : profile_(profile),
208 inspected_web_contents_(NULL),
209 web_contents_(web_contents),
210 browser_(NULL),
211 dock_side_(dock_side),
212 is_loaded_(false),
213 action_on_load_(DEVTOOLS_TOGGLE_ACTION_SHOW),
214 width_(-1),
215 height_(-1) {
216 frontend_host_ = DevToolsClientHost::CreateDevToolsFrontendHost(web_contents,
217 this);
218 file_helper_.reset(new DevToolsFileHelper(profile, this));
219
220 g_instances.Get().push_back(this);
221 // Wipe out page icon so that the default application icon is used.
222 NavigationEntry* entry = web_contents->GetController().GetActiveEntry();
223 entry->GetFavicon().image = gfx::Image();
224 entry->GetFavicon().valid = true;
225
226 // Register on-load actions.
227 registrar_.Add(
228 this,
229 content::NOTIFICATION_LOAD_STOP,
230 content::Source<NavigationController>(&web_contents->GetController()));
231 registrar_.Add(
232 this,
233 chrome::NOTIFICATION_TAB_CLOSING,
234 content::Source<NavigationController>(&web_contents->GetController()));
235 registrar_.Add(
236 this,
237 chrome::NOTIFICATION_BROWSER_THEME_CHANGED,
238 content::Source<ThemeService>(
239 ThemeServiceFactory::GetForProfile(profile_)));
240 // There is no inspected_rvh in case of shared workers.
241 if (inspected_rvh)
242 inspected_web_contents_ = WebContents::FromRenderViewHost(inspected_rvh);
243 }
244
245 DevToolsWindow::~DevToolsWindow() {
246 DevToolsWindowList& instances = g_instances.Get();
247 DevToolsWindowList::iterator it = std::find(instances.begin(),
248 instances.end(),
249 this);
250 DCHECK(it != instances.end());
251 instances.erase(it);
252 }
253
254 void DevToolsWindow::InspectedContentsClosing() {
255 if (IsDocked()) {
256 // Update dev tools to reflect removed dev tools window.
257 BrowserWindow* inspected_window = GetInspectedBrowserWindow();
258 if (inspected_window)
259 inspected_window->UpdateDevTools();
260 // In case of docked web_contents_, we own it so delete here.
261 delete web_contents_;
262
263 delete this;
264 } else {
265 // First, initiate self-destruct to free all the registrars.
266 // Then close all tabs. Browser will take care of deleting web_contents_
267 // for us.
268 Browser* browser = browser_;
269 delete this;
270 browser->tab_strip_model()->CloseAllTabs();
271 }
272 }
273
274 void DevToolsWindow::ContentsReplaced(WebContents* new_contents) {
275 inspected_web_contents_ = new_contents;
276 }
277
278 void DevToolsWindow::Show(DevToolsToggleAction action) {
279 if (IsDocked()) {
280 Browser* inspected_browser;
281 int inspected_tab_index;
282 // Tell inspected browser to update splitter and switch to inspected panel.
283 if (!IsInspectedBrowserPopupOrPanel() &&
284 FindInspectedBrowserAndTabIndex(&inspected_browser,
285 &inspected_tab_index)) {
286 BrowserWindow* inspected_window = inspected_browser->window();
287 web_contents_->SetDelegate(this);
288 inspected_window->UpdateDevTools();
289 web_contents_->GetView()->SetInitialFocus();
290 inspected_window->Show();
291 TabStripModel* tab_strip_model = inspected_browser->tab_strip_model();
292 tab_strip_model->ActivateTabAt(inspected_tab_index, true);
293 ScheduleAction(action);
294 return;
295 } else {
296 // Sometimes we don't know where to dock. Stay undocked.
297 dock_side_ = DEVTOOLS_DOCK_SIDE_UNDOCKED;
298 }
299 }
300
301 // Avoid consecutive window switching if the devtools window has been opened
302 // and the Inspect Element shortcut is pressed in the inspected tab.
303 bool should_show_window =
304 !browser_ || action != DEVTOOLS_TOGGLE_ACTION_INSPECT;
305
306 if (!browser_)
307 CreateDevToolsBrowser();
308
309 if (should_show_window) {
310 browser_->window()->Show();
311 web_contents_->GetView()->SetInitialFocus();
312 }
313
314 ScheduleAction(action);
315 }
316
317 int DevToolsWindow::GetWidth(int container_width) {
318 if (width_ == -1) {
319 width_ = profile_->GetPrefs()->
320 GetInteger(prefs::kDevToolsVSplitLocation);
321 }
322
323 // By default, size devtools as 1/3 of the browser window.
324 if (width_ == -1)
325 width_ = container_width / 3;
326
327 // Respect the minimum devtools width preset.
328 width_ = std::max(kMinDevToolsWidth, width_);
329
330 // But it should never compromise the content window size unless the entire
331 // window is tiny.
332 width_ = std::min(container_width - kMinContentsSize, width_);
333 if (width_ < (kMinContentsSize / 2))
334 width_ = container_width / 3;
335 return width_;
336 }
337
338 int DevToolsWindow::GetHeight(int container_height) {
339 if (height_ == -1) {
340 height_ = profile_->GetPrefs()->
341 GetInteger(prefs::kDevToolsHSplitLocation);
342 }
343
344 // By default, size devtools as 1/3 of the browser window.
345 if (height_ == -1)
346 height_ = container_height / 3;
347
348 // Respect the minimum devtools width preset.
349 height_ = std::max(kMinDevToolsHeight, height_);
350
351 // But it should never compromise the content window size.
352 height_ = std::min(container_height - kMinContentsSize, height_);
353 if (height_ < (kMinContentsSize / 2))
354 height_ = container_height / 3;
355 return height_;
356 }
357
358 void DevToolsWindow::SetWidth(int width) {
359 width_ = width;
360 profile_->GetPrefs()->SetInteger(prefs::kDevToolsVSplitLocation, width);
361 }
362
363 void DevToolsWindow::SetHeight(int height) {
364 height_ = height;
365 profile_->GetPrefs()->SetInteger(prefs::kDevToolsHSplitLocation, height);
366 }
367
368 RenderViewHost* DevToolsWindow::GetRenderViewHost() {
369 return web_contents_->GetRenderViewHost();
370 }
371
372 void DevToolsWindow::CreateDevToolsBrowser() {
373 // TODO(pfeldman): Make browser's getter for this key static.
374 std::string wp_key;
375 wp_key.append(prefs::kBrowserWindowPlacement);
376 wp_key.append("_");
377 wp_key.append(kDevToolsApp);
378
379 PrefService* prefs = profile_->GetPrefs();
380 if (!prefs->FindPreference(wp_key.c_str())) {
381 prefs->RegisterDictionaryPref(wp_key.c_str(), PrefService::UNSYNCABLE_PREF);
382 }
383
384 const DictionaryValue* wp_pref = prefs->GetDictionary(wp_key.c_str());
385 if (!wp_pref || wp_pref->empty()) {
386 DictionaryPrefUpdate update(prefs, wp_key.c_str());
387 DictionaryValue* defaults = update.Get();
388 defaults->SetInteger("left", 100);
389 defaults->SetInteger("top", 100);
390 defaults->SetInteger("right", 740);
391 defaults->SetInteger("bottom", 740);
392 defaults->SetBoolean("maximized", false);
393 defaults->SetBoolean("always_on_top", false);
394 }
395
396 browser_ = new Browser(Browser::CreateParams::CreateForDevTools(profile_));
397 browser_->tab_strip_model()->AddWebContents(
398 web_contents_, -1, content::PAGE_TRANSITION_AUTO_TOPLEVEL,
399 TabStripModel::ADD_ACTIVE);
400 }
401
402 bool DevToolsWindow::FindInspectedBrowserAndTabIndex(Browser** browser,
403 int* tab) {
404 if (!inspected_web_contents_)
405 return false;
406
407 bool found = FindInspectedBrowserAndTabIndexFromBrowserList(
408 chrome::BrowserListImpl::GetInstance(chrome::HOST_DESKTOP_TYPE_NATIVE),
409 browser,
410 tab);
411 // On Windows 8 we can have the desktop environment and the ASH environment
412 // active concurrently. If we fail to find the inspected web contents in the
413 // native browser list, then we should look in the ASH browser list.
414 #if defined(OS_WIN) && defined(USE_AURA)
415 if (!found) {
416 found = FindInspectedBrowserAndTabIndexFromBrowserList(
417 chrome::BrowserListImpl::GetInstance(chrome::HOST_DESKTOP_TYPE_ASH),
418 browser,
419 tab);
420 }
421 #endif
422 return found;
423 }
424
425 bool DevToolsWindow::FindInspectedBrowserAndTabIndexFromBrowserList(
426 chrome::BrowserListImpl* browser_list,
427 Browser** browser,
428 int* tab) {
429 if (!inspected_web_contents_)
430 return false;
431
432 for (chrome::BrowserListImpl::const_iterator it = browser_list->begin();
433 it != browser_list->end(); ++it) {
434 int tab_index = (*it)->tab_strip_model()->GetIndexOfWebContents(
435 inspected_web_contents_);
436 if (tab_index != TabStripModel::kNoTab) {
437 *browser = *it;
438 *tab = tab_index;
439 return true;
440 }
441 }
442 return false;
443 }
444
445 BrowserWindow* DevToolsWindow::GetInspectedBrowserWindow() {
446 Browser* browser = NULL;
447 int tab;
448 return FindInspectedBrowserAndTabIndex(&browser, &tab) ?
449 browser->window() : NULL;
450 }
451
452 bool DevToolsWindow::IsInspectedBrowserPopupOrPanel() {
453 Browser* browser = NULL;
454 int tab;
455 if (!FindInspectedBrowserAndTabIndex(&browser, &tab))
456 return false;
457
458 return browser->is_type_popup() || browser->is_type_panel();
459 }
460
461 void DevToolsWindow::UpdateFrontendDockSide() {
462 base::StringValue dock_side(SideToString(dock_side_));
463 CallClientFunction("InspectorFrontendAPI.setDockSide", &dock_side);
464 base::FundamentalValue docked(IsDocked());
465 CallClientFunction("InspectorFrontendAPI.setAttachedWindow", &docked);
466 }
467
468
469 void DevToolsWindow::AddDevToolsExtensionsToClient() {
470 if (inspected_web_contents_) {
471 SessionTabHelper* session_tab_helper =
472 SessionTabHelper::FromWebContents(inspected_web_contents_);
473 if (session_tab_helper) {
474 base::FundamentalValue tabId(session_tab_helper->session_id().id());
475 CallClientFunction("WebInspector.setInspectedTabId", &tabId);
476 }
477 }
478 ListValue results;
479 Profile* profile =
480 Profile::FromBrowserContext(web_contents_->GetBrowserContext());
481 const ExtensionService* extension_service = extensions::ExtensionSystem::Get(
482 profile->GetOriginalProfile())->extension_service();
483 if (!extension_service)
484 return;
485
486 const ExtensionSet* extensions = extension_service->extensions();
487
488 for (ExtensionSet::const_iterator extension = extensions->begin();
489 extension != extensions->end(); ++extension) {
490 if ((*extension)->devtools_url().is_empty())
491 continue;
492 DictionaryValue* extension_info = new DictionaryValue();
493 extension_info->Set("startPage",
494 new StringValue((*extension)->devtools_url().spec()));
495 extension_info->Set("name", new StringValue((*extension)->name()));
496 bool allow_experimental = (*extension)->HasAPIPermission(
497 extensions::APIPermission::kExperimental);
498 extension_info->Set("exposeExperimentalAPIs",
499 new base::FundamentalValue(allow_experimental));
500 results.Append(extension_info);
501 }
502 CallClientFunction("WebInspector.addExtensions", &results);
503 }
504
505 WebContents* DevToolsWindow::OpenURLFromTab(WebContents* source,
506 const OpenURLParams& params) {
507 if (inspected_web_contents_)
508 return inspected_web_contents_->OpenURL(params);
509 return NULL;
510 }
511
512 void DevToolsWindow::CallClientFunction(const std::string& function_name,
513 const Value* arg) {
514 std::string json;
515 if (arg)
516 base::JSONWriter::Write(arg, &json);
517
518 string16 javascript =
519 ASCIIToUTF16(function_name + "(" + json + ");");
520 web_contents_->GetRenderViewHost()->
521 ExecuteJavascriptInWebFrame(string16(), javascript);
522 }
523
524 void DevToolsWindow::Observe(int type,
525 const content::NotificationSource& source,
526 const content::NotificationDetails& details) {
527 if (type == content::NOTIFICATION_LOAD_STOP && !is_loaded_) {
528 is_loaded_ = true;
529 UpdateTheme();
530 DoAction();
531 AddDevToolsExtensionsToClient();
532 } else if (type == chrome::NOTIFICATION_TAB_CLOSING) {
533 if (content::Source<NavigationController>(source).ptr() ==
534 &web_contents_->GetController()) {
535 // This happens when browser closes all of its tabs as a result
536 // of window.Close event.
537 // Notify manager that this DevToolsClientHost no longer exists and
538 // initiate self-destuct here.
539 DevToolsManager::GetInstance()->ClientHostClosing(frontend_host_);
540 UpdateBrowserToolbar();
541 delete this;
542 }
543 } else if (type == chrome::NOTIFICATION_BROWSER_THEME_CHANGED) {
544 UpdateTheme();
545 }
546 }
547
548 void DevToolsWindow::ScheduleAction(DevToolsToggleAction action) {
549 action_on_load_ = action;
550 if (is_loaded_)
551 DoAction();
552 }
553
554 void DevToolsWindow::DoAction() {
555 UpdateFrontendDockSide();
556 switch (action_on_load_) {
557 case DEVTOOLS_TOGGLE_ACTION_SHOW_CONSOLE:
558 CallClientFunction("InspectorFrontendAPI.showConsole", NULL);
559 break;
560 case DEVTOOLS_TOGGLE_ACTION_INSPECT:
561 CallClientFunction("InspectorFrontendAPI.enterInspectElementMode", NULL);
562 case DEVTOOLS_TOGGLE_ACTION_SHOW:
563 case DEVTOOLS_TOGGLE_ACTION_TOGGLE:
564 // Do nothing.
565 break;
566 default:
567 NOTREACHED();
568 }
569 action_on_load_ = DEVTOOLS_TOGGLE_ACTION_SHOW;
570 }
571
572 std::string SkColorToRGBAString(SkColor color) {
573 // We convert the alpha using DoubleToString because StringPrintf will use
574 // locale specific formatters (e.g., use , instead of . in German).
575 return StringPrintf("rgba(%d,%d,%d,%s)", SkColorGetR(color),
576 SkColorGetG(color), SkColorGetB(color),
577 base::DoubleToString(SkColorGetA(color) / 255.0).c_str());
578 }
579
580 // static
581 GURL DevToolsWindow::GetDevToolsUrl(Profile* profile,
582 DevToolsDockSide dock_side,
583 bool shared_worker_frontend) {
584 ThemeService* tp = ThemeServiceFactory::GetForProfile(profile);
585 CHECK(tp);
586
587 SkColor color_toolbar =
588 tp->GetColor(ThemeService::COLOR_TOOLBAR);
589 SkColor color_tab_text =
590 tp->GetColor(ThemeService::COLOR_BOOKMARK_TEXT);
591
592 const CommandLine& command_line = *CommandLine::ForCurrentProcess();
593 bool experiments_enabled =
594 command_line.HasSwitch(switches::kEnableDevToolsExperiments);
595
596 std::string url_string = StringPrintf("%sdevtools.html?"
597 "dockSide=%s&toolbarColor=%s&textColor=%s%s%s",
598 chrome::kChromeUIDevToolsURL,
599 SideToString(dock_side).c_str(),
600 SkColorToRGBAString(color_toolbar).c_str(),
601 SkColorToRGBAString(color_tab_text).c_str(),
602 shared_worker_frontend ? "&isSharedWorker=true" : "",
603 experiments_enabled ? "&experiments=true" : "");
604 return GURL(url_string);
605 }
606
607 void DevToolsWindow::UpdateTheme() {
608 ThemeService* tp = ThemeServiceFactory::GetForProfile(profile_);
609 CHECK(tp);
610
611 SkColor color_toolbar =
612 tp->GetColor(ThemeService::COLOR_TOOLBAR);
613 SkColor color_tab_text =
614 tp->GetColor(ThemeService::COLOR_BOOKMARK_TEXT);
615 std::string command = StringPrintf(
616 "InspectorFrontendAPI.setToolbarColors(\"%s\", \"%s\")",
617 SkColorToRGBAString(color_toolbar).c_str(),
618 SkColorToRGBAString(color_tab_text).c_str());
619 web_contents_->GetRenderViewHost()->
620 ExecuteJavascriptInWebFrame(string16(), UTF8ToUTF16(command));
621 }
622
623 void DevToolsWindow::AddNewContents(WebContents* source,
624 WebContents* new_contents,
625 WindowOpenDisposition disposition,
626 const gfx::Rect& initial_pos,
627 bool user_gesture,
628 bool* was_blocked) {
629 if (inspected_web_contents_) {
630 inspected_web_contents_->GetDelegate()->AddNewContents(
631 source, new_contents, disposition, initial_pos, user_gesture,
632 was_blocked);
633 }
634 }
635
636 bool DevToolsWindow::PreHandleKeyboardEvent(
637 WebContents* source,
638 const NativeWebKeyboardEvent& event, bool* is_keyboard_shortcut) {
639 if (IsDocked()) {
640 BrowserWindow* inspected_window = GetInspectedBrowserWindow();
641 if (inspected_window)
642 return inspected_window->PreHandleKeyboardEvent(
643 event, is_keyboard_shortcut);
644 }
645 return false;
646 }
647
648 void DevToolsWindow::HandleKeyboardEvent(WebContents* source,
649 const NativeWebKeyboardEvent& event) {
650 if (IsDocked()) {
651 if (event.windowsKeyCode == 0x08) {
652 // Do not navigate back in history on Windows (http://crbug.com/74156).
653 return;
654 }
655 BrowserWindow* inspected_window = GetInspectedBrowserWindow();
656 if (inspected_window)
657 inspected_window->HandleKeyboardEvent(event);
658 }
659 }
660
661 // static
662 DevToolsWindow* DevToolsWindow::ToggleDevToolsWindow(
663 RenderViewHost* inspected_rvh,
664 bool force_open,
665 DevToolsToggleAction action) {
666 DevToolsAgentHost* agent = DevToolsAgentHostRegistry::GetDevToolsAgentHost(
667 inspected_rvh);
668 DevToolsManager* manager = DevToolsManager::GetInstance();
669 DevToolsClientHost* host = manager->GetDevToolsClientHostFor(agent);
670 DevToolsWindow* window = AsDevToolsWindow(host);
671 if (host && !window) {
672 // Break remote debugging / extension debugging session.
673 host->ReplacedWithAnotherClient();
674 manager->UnregisterDevToolsClientHostFor(agent);
675 }
676
677 bool do_open = force_open;
678 if (!window) {
679 Profile* profile = Profile::FromBrowserContext(
680 inspected_rvh->GetProcess()->GetBrowserContext());
681 DevToolsDockSide dock_side = GetDockSideFromPrefs(profile);
682 window = Create(profile, inspected_rvh, dock_side, false);
683 manager->RegisterDevToolsClientHostFor(agent, window->frontend_host_);
684 do_open = true;
685 }
686
687 // Update toolbar to reflect DevTools changes.
688 window->UpdateBrowserToolbar();
689
690 // If window is docked and visible, we hide it on toggle. If window is
691 // undocked, we show (activate) it.
692 if (!window->IsDocked() || do_open)
693 window->Show(action);
694 else
695 manager->UnregisterDevToolsClientHostFor(agent);
696
697 return window;
698 }
699
700 // static
701 DevToolsWindow* DevToolsWindow::AsDevToolsWindow(
702 DevToolsClientHost* client_host) {
703 if (!client_host || g_instances == NULL)
704 return NULL;
705 DevToolsWindowList& instances = g_instances.Get();
706 for (DevToolsWindowList::iterator it = instances.begin();
707 it != instances.end(); ++it) {
708 if ((*it)->frontend_host_ == client_host)
709 return *it;
710 }
711 return NULL;
712 }
713
714 // static
715 DevToolsWindow* DevToolsWindow::AsDevToolsWindow(RenderViewHost* window_rvh) {
716 if (g_instances == NULL)
717 return NULL;
718 DevToolsWindowList& instances = g_instances.Get();
719 for (DevToolsWindowList::iterator it = instances.begin();
720 it != instances.end(); ++it) {
721 if ((*it)->web_contents_->GetRenderViewHost() == window_rvh)
722 return *it;
723 }
724 return NULL;
725 }
726
727 void DevToolsWindow::ActivateWindow() {
728 if (!IsDocked()) {
729 if (!browser_->window()->IsActive()) {
730 browser_->window()->Activate();
731 }
732 } else {
733 BrowserWindow* inspected_window = GetInspectedBrowserWindow();
734 if (inspected_window)
735 web_contents_->GetView()->Focus();
736 }
737 }
738
739 void DevToolsWindow::CloseWindow() {
740 DCHECK(IsDocked());
741 DevToolsManager::GetInstance()->ClientHostClosing(frontend_host_);
742 InspectedContentsClosing();
743 }
744
745 void DevToolsWindow::MoveWindow(int x, int y) {
746 if (!IsDocked()) {
747 gfx::Rect bounds = browser_->window()->GetBounds();
748 bounds.Offset(x, y);
749 browser_->window()->SetBounds(bounds);
750 }
751 }
752
753 void DevToolsWindow::SetDockSide(const std::string& side) {
754 DevToolsDockSide requested_side = SideFromString(side);
755 bool dock_requested = requested_side != DEVTOOLS_DOCK_SIDE_UNDOCKED;
756 bool is_docked = IsDocked();
757
758 if (dock_requested && (!inspected_web_contents_ ||
759 !GetInspectedBrowserWindow() || IsInspectedBrowserPopupOrPanel())) {
760 // Cannot dock, avoid window flashing due to close-reopen cycle.
761 return;
762 }
763
764 dock_side_ = requested_side;
765 if (dock_requested) {
766 if (!is_docked) {
767 // Detach window from the external devtools browser. It will lead to
768 // the browser object's close and delete. Remove observer first.
769 TabStripModel* tab_strip_model = browser_->tab_strip_model();
770 tab_strip_model->DetachWebContentsAt(
771 tab_strip_model->GetIndexOfWebContents(web_contents_));
772 browser_ = NULL;
773 }
774 } else if (is_docked) {
775 // Update inspected window to hide split and reset it.
776 BrowserWindow* inspected_window = GetInspectedBrowserWindow();
777 if (inspected_window)
778 inspected_window->UpdateDevTools();
779 }
780
781 std::string pref_value = kPrefBottom;
782 switch (dock_side_) {
783 case DEVTOOLS_DOCK_SIDE_UNDOCKED:
784 pref_value = kPrefUndocked;
785 break;
786 case DEVTOOLS_DOCK_SIDE_RIGHT:
787 pref_value = kPrefRight;
788 break;
789 case DEVTOOLS_DOCK_SIDE_BOTTOM:
790 pref_value = kPrefBottom;
791 break;
792 }
793 profile_->GetPrefs()->SetString(prefs::kDevToolsDockSide, pref_value);
794
795 Show(DEVTOOLS_TOGGLE_ACTION_SHOW);
796 }
797
798 void DevToolsWindow::OpenInNewTab(const std::string& url) {
799 OpenURLParams params(GURL(url),
800 content::Referrer(),
801 NEW_FOREGROUND_TAB,
802 content::PAGE_TRANSITION_LINK,
803 false /* is_renderer_initiated */);
804 if (inspected_web_contents_) {
805 inspected_web_contents_->OpenURL(params);
806 } else {
807 for (BrowserList::const_iterator it = BrowserList::begin();
808 it != BrowserList::end(); ++it) {
809 if ((*it)->type() == Browser::TYPE_TABBED) {
810 (*it)->OpenURL(params);
811 break;
812 }
813 }
814 }
815 }
816
817 void DevToolsWindow::SaveToFile(const std::string& url,
818 const std::string& content,
819 bool save_as) {
820 file_helper_->Save(url, content, save_as);
821 }
822
823 void DevToolsWindow::AppendToFile(const std::string& url,
824 const std::string& content) {
825 file_helper_->Append(url, content);
826 }
827
828 void DevToolsWindow::FileSavedAs(const std::string& url) {
829 StringValue url_value(url);
830 CallClientFunction("InspectorFrontendAPI.savedURL", &url_value);
831 }
832
833 void DevToolsWindow::AppendedTo(const std::string& url) {
834 StringValue url_value(url);
835 CallClientFunction("InspectorFrontendAPI.appendedToURL", &url_value);
836 }
837
838 content::JavaScriptDialogCreator* DevToolsWindow::GetJavaScriptDialogCreator() {
839 if (inspected_web_contents_ && inspected_web_contents_->GetDelegate()) {
840 return inspected_web_contents_->GetDelegate()->
841 GetJavaScriptDialogCreator();
842 }
843 return content::WebContentsDelegate::GetJavaScriptDialogCreator();
844 }
845
846 void DevToolsWindow::RunFileChooser(WebContents* web_contents,
847 const FileChooserParams& params) {
848 FileSelectHelper::RunFileChooser(web_contents, params);
849 }
850
851 void DevToolsWindow::WebContentsFocused(WebContents* contents) {
852 Browser* inspected_browser = NULL;
853 int inspected_tab_index = -1;
854
855 if (IsDocked() && FindInspectedBrowserAndTabIndex(&inspected_browser,
856 &inspected_tab_index)) {
857 inspected_browser->window()->WebContentsFocused(contents);
858 }
859 }
860
861 void DevToolsWindow::UpdateBrowserToolbar() {
862 if (!inspected_web_contents_)
863 return;
864 BrowserWindow* inspected_window = GetInspectedBrowserWindow();
865 if (inspected_window)
866 inspected_window->UpdateToolbar(inspected_web_contents_, false);
867 }
868
869 bool DevToolsWindow::IsDocked() {
870 return dock_side_ != DEVTOOLS_DOCK_SIDE_UNDOCKED;
871 }
872
873 // static
874 DevToolsDockSide DevToolsWindow::GetDockSideFromPrefs(Profile* profile) {
875 std::string dock_side =
876 profile->GetPrefs()->GetString(prefs::kDevToolsDockSide);
877
878 // Migrate prefs
879 if (dock_side == kOldPrefBottom || dock_side == kOldPrefRight) {
880 bool docked = profile->GetPrefs()->GetBoolean(prefs::kDevToolsOpenDocked);
881 if (dock_side == kOldPrefBottom)
882 return docked ? DEVTOOLS_DOCK_SIDE_BOTTOM : DEVTOOLS_DOCK_SIDE_UNDOCKED;
883 else
884 return docked ? DEVTOOLS_DOCK_SIDE_RIGHT : DEVTOOLS_DOCK_SIDE_UNDOCKED;
885 }
886
887 if (dock_side == kPrefUndocked)
888 return DEVTOOLS_DOCK_SIDE_UNDOCKED;
889 else if (dock_side == kPrefRight)
890 return DEVTOOLS_DOCK_SIDE_RIGHT;
891 // Default to docked to bottom
892 return DEVTOOLS_DOCK_SIDE_BOTTOM;
893 }
894
895 // static
896 std::string DevToolsWindow::SideToString(DevToolsDockSide dock_side) {
897 std::string dock_side_string;
898 switch (dock_side) {
899 case DEVTOOLS_DOCK_SIDE_UNDOCKED: return kDockSideUndocked;
900 case DEVTOOLS_DOCK_SIDE_RIGHT: return kDockSideRight;
901 case DEVTOOLS_DOCK_SIDE_BOTTOM: return kDockSideBottom;
902 }
903 return kDockSideUndocked;
904 }
905
906 // static
907 DevToolsDockSide DevToolsWindow::SideFromString(
908 const std::string& dock_side) {
909 if (dock_side == kDockSideRight)
910 return DEVTOOLS_DOCK_SIDE_RIGHT;
911 if (dock_side == kDockSideBottom)
912 return DEVTOOLS_DOCK_SIDE_BOTTOM;
913 return DEVTOOLS_DOCK_SIDE_UNDOCKED;
914 }
OLDNEW
« no previous file with comments | « chrome/browser/debugger/devtools_window.h ('k') | chrome/browser/debugger/frontend/devtools_discovery_page.html » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698