Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / chrome / browser / devtools / devtools_window.h
blobc9d9aaf60c7162066f30161b096550ff5d13eb9b
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 #ifndef CHROME_BROWSER_DEVTOOLS_DEVTOOLS_WINDOW_H_
6 #define CHROME_BROWSER_DEVTOOLS_DEVTOOLS_WINDOW_H_
8 #include "chrome/browser/devtools/devtools_contents_resizing_strategy.h"
9 #include "chrome/browser/devtools/devtools_toggle_action.h"
10 #include "chrome/browser/devtools/devtools_ui_bindings.h"
11 #include "content/public/browser/web_contents_delegate.h"
12 #include "content/public/browser/web_contents_observer.h"
14 class Browser;
15 class BrowserWindow;
16 class DevToolsWindowTesting;
17 class DevToolsEventForwarder;
19 namespace content {
20 class DevToolsAgentHost;
21 struct NativeWebKeyboardEvent;
22 class RenderViewHost;
25 namespace user_prefs {
26 class PrefRegistrySyncable;
29 class DevToolsWindow : public DevToolsUIBindings::Delegate,
30 public content::WebContentsDelegate {
31 public:
32 class ObserverWithAccessor : public content::WebContentsObserver {
33 public:
34 explicit ObserverWithAccessor(content::WebContents* web_contents);
35 ~ObserverWithAccessor() override;
37 private:
38 DISALLOW_COPY_AND_ASSIGN(ObserverWithAccessor);
41 static const char kDevToolsApp[];
43 ~DevToolsWindow() override;
45 static void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry);
47 // Return the DevToolsWindow for the given WebContents if one exists,
48 // otherwise NULL.
49 static DevToolsWindow* GetInstanceForInspectedWebContents(
50 content::WebContents* inspected_web_contents);
52 // Return the docked DevTools WebContents for the given inspected WebContents
53 // if one exists and should be shown in browser window, otherwise NULL.
54 // This method will return only fully initialized window ready to be
55 // presented in UI.
56 // If |out_strategy| is not NULL, it will contain resizing strategy.
57 // For immediately-ready-to-use but maybe not yet fully initialized DevTools
58 // use |GetInstanceForInspectedRenderViewHost| instead.
59 static content::WebContents* GetInTabWebContents(
60 content::WebContents* inspected_tab,
61 DevToolsContentsResizingStrategy* out_strategy);
63 static bool IsDevToolsWindow(content::WebContents* web_contents);
64 static DevToolsWindow* AsDevToolsWindow(content::WebContents* web_contents);
65 static DevToolsWindow* FindDevToolsWindow(content::DevToolsAgentHost*);
67 // Open or reveal DevTools window, and perform the specified action.
68 // How to get pointer to the created window see comments for
69 // ToggleDevToolsWindow().
70 static void OpenDevToolsWindow(content::WebContents* inspected_web_contents,
71 const DevToolsToggleAction& action);
73 // Open or reveal DevTools window, with no special action.
74 // How to get pointer to the created window see comments for
75 // ToggleDevToolsWindow().
76 static void OpenDevToolsWindow(content::WebContents* inspected_web_contents);
78 // Open or reveal DevTools window. This window will be undocked.
79 static void OpenDevToolsWindow(
80 Profile* profile,
81 const scoped_refptr<content::DevToolsAgentHost>& agent_host);
83 // Perform specified action for current WebContents inside a |browser|.
84 // This may close currently open DevTools window.
85 // If DeveloperToolsDisabled policy is set, no DevTools window created.
86 // In case if needed pointer to the created window one should use
87 // DevToolsAgentHost and DevToolsWindow::FindDevToolsWindow(). E.g.:
89 // scoped_refptr<content::DevToolsAgentHost> agent(
90 // content::DevToolsAgentHost::GetOrCreateFor(inspected_web_contents));
91 // DevToolsWindow::ToggleDevToolsWindow(
92 // inspected_web_contents, DevToolsToggleAction::Show());
93 // DevToolsWindow* window = DevToolsWindow::FindDevToolsWindow(agent.get());
95 static void ToggleDevToolsWindow(
96 Browser* browser,
97 const DevToolsToggleAction& action);
99 // External frontend is always undocked.
100 static void OpenExternalFrontend(
101 Profile* profile,
102 const std::string& frontend_uri,
103 const scoped_refptr<content::DevToolsAgentHost>& agent_host,
104 bool isWorker);
106 // Worker frontend is always undocked.
107 static void OpenDevToolsWindowForWorker(
108 Profile* profile,
109 const scoped_refptr<content::DevToolsAgentHost>& worker_agent);
111 static void InspectElement(content::WebContents* inspected_web_contents,
112 int x,
113 int y);
115 // Creates and opens the front-end API channel to applicable front-end in a
116 // form of devtools agent host.
117 static content::DevToolsExternalAgentProxyDelegate*
118 CreateWebSocketAPIChannel(const std::string& path);
120 // Sets closure to be called after load is done. If already loaded, calls
121 // closure immediately.
122 void SetLoadCompletedCallback(const base::Closure& closure);
124 // Forwards an unhandled keyboard event to the DevTools frontend.
125 bool ForwardKeyboardEvent(const content::NativeWebKeyboardEvent& event);
127 // Reloads inspected web contents as if it was triggered from DevTools.
128 void ReloadInspectedWebContents(bool ignore_cache);
130 content::WebContents* OpenURLFromTab(
131 content::WebContents* source,
132 const content::OpenURLParams& params) override;
134 void ShowCertificateViewer(int certificate_id);
136 // BeforeUnload interception ////////////////////////////////////////////////
138 // In order to preserve any edits the user may have made in devtools, the
139 // beforeunload event of the inspected page is hooked - devtools gets the
140 // first shot at handling beforeunload and presents a dialog to the user. If
141 // the user accepts the dialog then the script is given a chance to handle
142 // it. This way 2 dialogs may be displayed: one from the devtools asking the
143 // user to confirm that they're ok with their devtools edits going away and
144 // another from the webpage as the result of its beforeunload handler.
145 // The following set of methods handle beforeunload event flow through
146 // devtools window. When the |contents| with devtools opened on them are
147 // getting closed, the following sequence of calls takes place:
148 // 1. |DevToolsWindow::InterceptPageBeforeUnload| is called and indicates
149 // whether devtools intercept the beforeunload event.
150 // If InterceptPageBeforeUnload() returns true then the following steps
151 // will take place; otherwise only step 4 will be reached and none of the
152 // corresponding functions in steps 2 & 3 will get called.
153 // 2. |DevToolsWindow::InterceptPageBeforeUnload| fires beforeunload event
154 // for devtools frontend, which will asynchronously call
155 // |WebContentsDelegate::BeforeUnloadFired| method.
156 // In case of docked devtools window, devtools are set as a delegate for
157 // its frontend, so method |DevToolsWindow::BeforeUnloadFired| will be
158 // called directly.
159 // If devtools window is undocked it's not set as the delegate so the call
160 // to BeforeUnloadFired is proxied through HandleBeforeUnload() rather
161 // than getting called directly.
162 // 3a. If |DevToolsWindow::BeforeUnloadFired| is called with |proceed|=false
163 // it calls throught to the content's BeforeUnloadFired(), which from the
164 // WebContents perspective looks the same as the |content|'s own
165 // beforeunload dialog having had it's 'stay on this page' button clicked.
166 // 3b. If |proceed| = true, then it fires beforeunload event on |contents|
167 // and everything proceeds as it normally would without the Devtools
168 // interception.
169 // 4. If the user cancels the dialog put up by either the WebContents or
170 // devtools frontend, then |contents|'s |BeforeUnloadFired| callback is
171 // called with the proceed argument set to false, this causes
172 // |DevToolsWindow::OnPageCloseCancelled| to be called.
174 // Devtools window in undocked state is not set as a delegate of
175 // its frontend. Instead, an instance of browser is set as the delegate, and
176 // thus beforeunload event callback from devtools frontend is not delivered
177 // to the instance of devtools window, which is solely responsible for
178 // managing custom beforeunload event flow.
179 // This is a helper method to route callback from
180 // |Browser::BeforeUnloadFired| back to |DevToolsWindow::BeforeUnloadFired|.
181 // * |proceed| - true if the user clicked 'ok' in the beforeunload dialog,
182 // false otherwise.
183 // * |proceed_to_fire_unload| - output parameter, whether we should continue
184 // to fire the unload event or stop things here.
185 // Returns true if devtools window is in a state of intercepting beforeunload
186 // event and if it will manage unload process on its own.
187 static bool HandleBeforeUnload(content::WebContents* contents,
188 bool proceed,
189 bool* proceed_to_fire_unload);
191 // Returns true if this contents beforeunload event was intercepted by
192 // devtools and false otherwise. If the event was intercepted, caller should
193 // not fire beforeunlaod event on |contents| itself as devtools window will
194 // take care of it, otherwise caller should continue handling the event as
195 // usual.
196 static bool InterceptPageBeforeUnload(content::WebContents* contents);
198 // Returns true if devtools browser has already fired its beforeunload event
199 // as a result of beforeunload event interception.
200 static bool HasFiredBeforeUnloadEventForDevToolsBrowser(Browser* browser);
202 // Returns true if devtools window would like to hook beforeunload event
203 // of this |contents|.
204 static bool NeedsToInterceptBeforeUnload(content::WebContents* contents);
206 // Notify devtools window that closing of |contents| was cancelled
207 // by user.
208 static void OnPageCloseCanceled(content::WebContents* contents);
210 private:
211 friend class DevToolsWindowTesting;
213 // DevTools lifecycle typically follows this way:
214 // - Toggle/Open: client call;
215 // - Create;
216 // - ScheduleShow: setup window to be functional, but not yet show;
217 // - DocumentOnLoadCompletedInMainFrame: frontend loaded;
218 // - SetIsDocked: frontend decided on docking state;
219 // - OnLoadCompleted: ready to present frontend;
220 // - Show: actually placing frontend WebContents to a Browser or docked place;
221 // - DoAction: perform action passed in Toggle/Open;
222 // - ...;
223 // - CloseWindow: initiates before unload handling;
224 // - CloseContents: destroys frontend;
225 // - DevToolsWindow is dead once it's main_web_contents dies.
226 enum LifeStage {
227 kNotLoaded,
228 kOnLoadFired, // Implies SetIsDocked was not yet called.
229 kIsDockedSet, // Implies DocumentOnLoadCompleted was not yet called.
230 kLoadCompleted,
231 kClosing
234 DevToolsWindow(Profile* profile,
235 content::WebContents* main_web_contents,
236 DevToolsUIBindings* bindings,
237 content::WebContents* inspected_web_contents,
238 bool can_dock);
240 static DevToolsWindow* Create(Profile* profile,
241 const GURL& frontend_url,
242 content::WebContents* inspected_web_contents,
243 bool shared_worker_frontend,
244 const std::string& remote_frontend,
245 bool can_dock,
246 const std::string& settings);
247 static GURL GetDevToolsURL(Profile* profile,
248 const GURL& base_url,
249 bool shared_worker_frontend,
250 const std::string& remote_frontend,
251 bool can_dock,
252 const std::string& settings);
254 static DevToolsWindow* CreateDevToolsWindowForWorker(Profile* profile);
255 static void ToggleDevToolsWindow(
256 content::WebContents* web_contents,
257 bool force_open,
258 const DevToolsToggleAction& action,
259 const std::string& settings);
261 // content::WebContentsDelegate:
262 void ActivateContents(content::WebContents* contents) override;
263 void AddNewContents(content::WebContents* source,
264 content::WebContents* new_contents,
265 WindowOpenDisposition disposition,
266 const gfx::Rect& initial_rect,
267 bool user_gesture,
268 bool* was_blocked) override;
269 void WebContentsCreated(content::WebContents* source_contents,
270 int opener_render_frame_id,
271 const std::string& frame_name,
272 const GURL& target_url,
273 content::WebContents* new_contents) override;
274 void CloseContents(content::WebContents* source) override;
275 void ContentsZoomChange(bool zoom_in) override;
276 void BeforeUnloadFired(content::WebContents* tab,
277 bool proceed,
278 bool* proceed_to_fire_unload) override;
279 bool PreHandleKeyboardEvent(content::WebContents* source,
280 const content::NativeWebKeyboardEvent& event,
281 bool* is_keyboard_shortcut) override;
282 void HandleKeyboardEvent(
283 content::WebContents* source,
284 const content::NativeWebKeyboardEvent& event) override;
285 content::JavaScriptDialogManager* GetJavaScriptDialogManager(
286 content::WebContents* source) override;
287 content::ColorChooser* OpenColorChooser(
288 content::WebContents* web_contents,
289 SkColor color,
290 const std::vector<content::ColorSuggestion>& suggestions) override;
291 void RunFileChooser(content::WebContents* web_contents,
292 const content::FileChooserParams& params) override;
293 bool PreHandleGestureEvent(content::WebContents* source,
294 const blink::WebGestureEvent& event) override;
296 // content::DevToolsUIBindings::Delegate overrides
297 void ActivateWindow() override;
298 void CloseWindow() override;
299 void SetInspectedPageBounds(const gfx::Rect& rect) override;
300 void InspectElementCompleted() override;
301 void SetIsDocked(bool is_docked) override;
302 void OpenInNewTab(const std::string& url) override;
303 void SetWhitelistedShortcuts(const std::string& message) override;
304 void InspectedContentsClosing() override;
305 void OnLoadCompleted() override;
306 InfoBarService* GetInfoBarService() override;
307 void RenderProcessGone(bool crashed) override;
309 void CreateDevToolsBrowser();
310 BrowserWindow* GetInspectedBrowserWindow();
311 void ScheduleShow(const DevToolsToggleAction& action);
312 void Show(const DevToolsToggleAction& action);
313 void DoAction(const DevToolsToggleAction& action);
314 void LoadCompleted();
315 void UpdateBrowserToolbar();
316 void UpdateBrowserWindow();
317 content::WebContents* GetInspectedWebContents();
319 scoped_ptr<ObserverWithAccessor> inspected_contents_observer_;
321 Profile* profile_;
322 content::WebContents* main_web_contents_;
323 content::WebContents* toolbox_web_contents_;
324 DevToolsUIBindings* bindings_;
325 Browser* browser_;
326 bool is_docked_;
327 const bool can_dock_;
328 LifeStage life_stage_;
329 DevToolsToggleAction action_on_load_;
330 DevToolsContentsResizingStrategy contents_resizing_strategy_;
331 // True if we're in the process of handling a beforeunload event originating
332 // from the inspected webcontents, see InterceptPageBeforeUnload for details.
333 bool intercepted_page_beforeunload_;
334 base::Closure load_completed_callback_;
335 base::Closure close_callback_;
337 base::TimeTicks inspect_element_start_time_;
338 scoped_ptr<DevToolsEventForwarder> event_forwarder_;
340 friend class DevToolsEventForwarder;
341 DISALLOW_COPY_AND_ASSIGN(DevToolsWindow);
344 #endif // CHROME_BROWSER_DEVTOOLS_DEVTOOLS_WINDOW_H_