2010-08-26 Yury Semikhatsky <yurys@chromium.org>
[WebKit-https.git] / WebKit / gtk / WebCoreSupport / InspectorClientGtk.cpp
1 /*
2  * Copyright (C) 2008 Gustavo Noronha Silva
3  * Copyright (C) 2010 Collabora Ltd.
4  *
5  *  This library is free software; you can redistribute it and/or
6  *  modify it under the terms of the GNU Lesser General Public
7  *  License as published by the Free Software Foundation; either
8  *  version 2 of the License, or (at your option) any later version.
9  *
10  *  This library is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  *  Lesser General Public License for more details.
14  *
15  *  You should have received a copy of the GNU Lesser General Public
16  *  License along with this library; if not, write to the Free Software
17  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
18  */
19
20 #include "config.h"
21 #include "InspectorClientGtk.h"
22
23 #include "Frame.h"
24 #include "webkitwebview.h"
25 #include "webkitwebinspector.h"
26 #include "webkitprivate.h"
27 #include "webkitversion.h"
28 #include "InspectorController.h"
29 #include "NotImplemented.h"
30 #include "PlatformString.h"
31 #include <wtf/text/CString.h>
32
33 using namespace WebCore;
34
35 namespace WebKit {
36
37 static void notifyWebViewDestroyed(WebKitWebView* webView, InspectorFrontendClient* inspectorFrontendClient)
38 {
39     inspectorFrontendClient->destroyInspectorWindow(true);
40 }
41
42 InspectorClient::InspectorClient(WebKitWebView* webView)
43     : m_inspectedWebView(webView)
44     , m_frontendPage(0)
45     , m_frontendClient(0)
46 {}
47
48 InspectorClient::~InspectorClient()
49 {
50     if (m_frontendClient) {
51         m_frontendClient->disconnectInspectorClient();
52         m_frontendClient = 0;
53     }
54 }
55
56 void InspectorClient::inspectorDestroyed()
57 {
58     delete this;
59 }
60
61 void InspectorClient::openInspectorFrontend(InspectorController* controller)
62 {
63     // This g_object_get will ref the inspector. We're not doing an
64     // unref if this method succeeds because the inspector object must
65     // be alive even after the inspected WebView is destroyed - the
66     // close-window and destroy signals still need to be
67     // emitted.
68     WebKitWebInspector* webInspector = 0;
69     g_object_get(m_inspectedWebView, "web-inspector", &webInspector, NULL);
70     ASSERT(webInspector);
71
72     WebKitWebView* inspectorWebView = 0;
73     g_signal_emit_by_name(webInspector, "inspect-web-view", m_inspectedWebView, &inspectorWebView);
74
75     if (!inspectorWebView) {
76         g_object_unref(webInspector);
77         return;
78     }
79
80     webkit_web_inspector_set_web_view(webInspector, inspectorWebView);
81
82     GOwnPtr<gchar> inspectorPath(g_build_filename(inspectorFilesPath(), "inspector.html", NULL));
83     GOwnPtr<gchar> inspectorURI(g_filename_to_uri(inspectorPath.get(), 0, 0));
84     webkit_web_view_load_uri(inspectorWebView, inspectorURI.get());
85
86     gtk_widget_show(GTK_WIDGET(inspectorWebView));
87
88     m_frontendPage = core(inspectorWebView);
89     m_frontendClient = new InspectorFrontendClient(m_inspectedWebView, inspectorWebView, webInspector, m_frontendPage, this);
90     m_frontendPage->inspectorController()->setInspectorFrontendClient(m_frontendClient);
91 }
92
93 void InspectorClient::releaseFrontendPage()
94 {
95     m_frontendPage = 0;
96 }
97
98 void InspectorClient::highlight(Node*)
99 {
100     hideHighlight();
101 }
102
103 void InspectorClient::hideHighlight()
104 {
105     // FIXME: we should be able to only invalidate the actual rects of
106     // the new and old nodes. We need to track the nodes, and take the
107     // actual highlight size into account when calculating the damage
108     // rect.
109     gtk_widget_queue_draw(GTK_WIDGET(m_inspectedWebView));
110 }
111
112 #ifdef HAVE_GSETTINGS
113 static String toGSettingName(String inspectorSettingName)
114 {
115     if (inspectorSettingName == "resourceTrackingEnabled")
116         return String("resource-tracking-enabled");
117
118     if (inspectorSettingName == "xhrMonitor")
119         return String("xhr-monitor-enabled");
120
121     if (inspectorSettingName == "frontendSettings")
122         return String("frontend-settings");
123
124     if (inspectorSettingName == "debuggerEnabled")
125         return String("debugger-enabled");
126
127     if (inspectorSettingName == "profilerEnabled")
128         return String("profiler-enabled");
129
130     return inspectorSettingName;
131 }
132
133 static String truthStringFromVariant(GVariant* variant)
134 {
135     if (g_variant_get_boolean(variant))
136         return String("true");
137
138     return String("false");
139 }
140
141 static GVariant* variantFromTruthString(const String& truth)
142 {
143     if (truth == "true")
144         return g_variant_new_boolean(TRUE);
145
146     return g_variant_new_boolean(FALSE);
147 }
148
149 static bool shouldIgnoreSetting(const String& key)
150 {
151     // Ignore this setting for now, it doesn't seem to be used for
152     // anything right now.
153     if (key == "lastActivePanel")
154         return true;
155
156     // GSettings considers trying to fetch or set a setting that is
157     // not backed by a schema as programmer error, and aborts the
158     // program's execution. We check here to avoid having an unhandled
159     // setting as a fatal error.
160     if (key == "resourceTrackingEnabled" || key == "xhrMonitor"
161         || key == "frontendSettings" || key == "debuggerEnabled"
162         || key == "profilerEnabled")
163         return false;
164
165     LOG_VERBOSE(NotYetImplemented, "Unknown key ignored: %s", key.ascii().data());
166     return true;
167 }
168
169 void InspectorClient::populateSetting(const String& key, String* value)
170 {
171     if (shouldIgnoreSetting(key))
172         return;
173
174     GSettings* settings = inspectorGSettings();
175     if (!settings)
176         return;
177
178     PlatformRefPtr<GVariant> variant = adoptPlatformRef(g_settings_get_value(settings, toGSettingName(key).utf8().data()));
179
180     if (key == "resourceTrackingEnabled" || key == "xhrMonitor"
181         || key == "debuggerEnabled" || key == "profilerEnabled")
182         *value = truthStringFromVariant(variant.get());
183     else if (key == "frontendSettings")
184         *value = String(g_variant_get_string(variant.get(), 0));
185 }
186
187 void InspectorClient::storeSetting(const String& key, const String& value)
188 {
189     if (shouldIgnoreSetting(key))
190         return;
191
192     GSettings* settings = inspectorGSettings();
193     if (!settings)
194         return;
195
196     PlatformRefPtr<GVariant> variant(0);
197
198     // Set the key with the appropriate type, and also avoid setting
199     // unknown keys to avoid aborting the execution.
200     if (key == "resourceTrackingEnabled" || key == "xhrMonitor"
201         || key == "debuggerEnabled" || key == "profilerEnabled")
202         variant = adoptPlatformRef(variantFromTruthString(value));
203     else if (key == "frontendSettings")
204         variant = adoptPlatformRef(g_variant_new_string(value.utf8().data()));
205
206     if (!variant)
207         return;
208
209     g_settings_set_value(settings, toGSettingName(key).utf8().data(), variant.get());
210 }
211 #else
212 void InspectorClient::populateSetting(const String&, String*)
213 {
214     notImplemented();
215 }
216
217 void InspectorClient::storeSetting(const String&, const String&)
218 {
219     notImplemented();
220 }
221 #endif // HAVE_GSETTINGS
222
223 bool InspectorClient::sendMessageToFrontend(const String& message)
224 {
225     if (!m_frontendPage)
226         return false;
227
228     Frame* frame = m_frontendPage->mainFrame();
229     if (!frame)
230         return false;
231
232     ScriptController* scriptController = frame->script();
233     if (!scriptController)
234         return false;
235
236     String dispatchToFrontend("WebInspector.dispatchMessageFromBackend(");
237     dispatchToFrontend += message;
238     dispatchToFrontend += ");";
239     scriptController->executeScript(dispatchToFrontend);
240     return true;
241 }
242
243 const char* InspectorClient::inspectorFilesPath()
244 {
245     if (m_inspectorFilesPath)
246         m_inspectorFilesPath.get();
247
248     const char* environmentPath = getenv("WEBKIT_INSPECTOR_PATH");
249     if (environmentPath && g_file_test(environmentPath, G_FILE_TEST_IS_DIR))
250         m_inspectorFilesPath.set(g_strdup(environmentPath));
251     else
252         m_inspectorFilesPath.set(g_build_filename(DATA_DIR, "webkitgtk-"WEBKITGTK_API_VERSION_STRING, "webinspector", NULL));
253
254     return m_inspectorFilesPath.get();
255 }
256
257 InspectorFrontendClient::InspectorFrontendClient(WebKitWebView* inspectedWebView, WebKitWebView* inspectorWebView, WebKitWebInspector* webInspector, Page* inspectorPage, InspectorClient* inspectorClient)
258     : InspectorFrontendClientLocal(core(inspectedWebView)->inspectorController(), inspectorPage)
259     , m_inspectorWebView(inspectorWebView)
260     , m_inspectedWebView(inspectedWebView)
261     , m_webInspector(webInspector)
262     , m_inspectorClient(inspectorClient)
263 {
264     g_signal_connect(m_inspectorWebView, "destroy",
265                      G_CALLBACK(notifyWebViewDestroyed), (gpointer)this);
266 }
267
268 InspectorFrontendClient::~InspectorFrontendClient()
269 {
270     if (m_inspectorClient) {
271         m_inspectorClient->disconnectFrontendClient();
272         m_inspectorClient = 0;
273     }
274     ASSERT(!m_webInspector);
275 }
276
277 void InspectorFrontendClient::destroyInspectorWindow(bool notifyInspectorController)
278 {
279     if (!m_webInspector)
280         return;
281     WebKitWebInspector* webInspector = m_webInspector;
282     m_webInspector = 0;
283
284     g_signal_handlers_disconnect_by_func(m_inspectorWebView, (gpointer)notifyWebViewDestroyed, (gpointer)this);
285     m_inspectorWebView = 0;
286
287     if (notifyInspectorController)
288         core(m_inspectedWebView)->inspectorController()->disconnectFrontend();
289
290     if (m_inspectorClient)
291         m_inspectorClient->releaseFrontendPage();
292
293     gboolean handled = FALSE;
294     g_signal_emit_by_name(webInspector, "close-window", &handled);
295     ASSERT(handled);
296
297     // Please do not use member variables here because InspectorFrontendClient object pointed by 'this'
298     // has been implicitly deleted by "close-window" function.
299
300     /* we should now dispose our own reference */
301     g_object_unref(webInspector);
302 }
303
304 String InspectorFrontendClient::localizedStringsURL()
305 {
306     GOwnPtr<gchar> stringsPath(g_build_filename(m_inspectorClient->inspectorFilesPath(), "localizedStrings.js", NULL));
307     GOwnPtr<gchar> stringsURI(g_filename_to_uri(stringsPath.get(), 0, 0));
308
309     // FIXME: support l10n of localizedStrings.js
310     return String::fromUTF8(stringsURI.get());
311 }
312
313 String InspectorFrontendClient::hiddenPanels()
314 {
315     notImplemented();
316     return String();
317 }
318
319 void InspectorFrontendClient::bringToFront()
320 {
321     if (!m_inspectorWebView)
322         return;
323
324     gboolean handled = FALSE;
325     g_signal_emit_by_name(m_webInspector, "show-window", &handled);
326 }
327
328 void InspectorFrontendClient::closeWindow()
329 {
330     destroyInspectorWindow(true);
331 }
332
333 void InspectorFrontendClient::disconnectFromBackend()
334 {
335     destroyInspectorWindow(false);
336 }
337
338 void InspectorFrontendClient::attachWindow()
339 {
340     if (!m_inspectorWebView)
341         return;
342
343     gboolean handled = FALSE;
344     g_signal_emit_by_name(m_webInspector, "attach-window", &handled);
345 }
346
347 void InspectorFrontendClient::detachWindow()
348 {
349     if (!m_inspectorWebView)
350         return;
351
352     gboolean handled = FALSE;
353     g_signal_emit_by_name(m_webInspector, "detach-window", &handled);
354 }
355
356 void InspectorFrontendClient::setAttachedWindowHeight(unsigned height)
357 {
358     notImplemented();
359 }
360
361 void InspectorFrontendClient::inspectedURLChanged(const String& newURL)
362 {
363     if (!m_inspectorWebView)
364         return;
365
366     webkit_web_inspector_set_inspected_uri(m_webInspector, newURL.utf8().data());
367 }
368
369 }
370