2c1ffab5f5837656c57606400c1221eb14a9772d
[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     return doDispatchMessageOnFrontendPage(m_frontendPage, message);
226 }
227
228 const char* InspectorClient::inspectorFilesPath()
229 {
230     if (m_inspectorFilesPath)
231         m_inspectorFilesPath.get();
232
233     const char* environmentPath = getenv("WEBKIT_INSPECTOR_PATH");
234     if (environmentPath && g_file_test(environmentPath, G_FILE_TEST_IS_DIR))
235         m_inspectorFilesPath.set(g_strdup(environmentPath));
236     else
237         m_inspectorFilesPath.set(g_build_filename(DATA_DIR, "webkitgtk-"WEBKITGTK_API_VERSION_STRING, "webinspector", NULL));
238
239     return m_inspectorFilesPath.get();
240 }
241
242 InspectorFrontendClient::InspectorFrontendClient(WebKitWebView* inspectedWebView, WebKitWebView* inspectorWebView, WebKitWebInspector* webInspector, Page* inspectorPage, InspectorClient* inspectorClient)
243     : InspectorFrontendClientLocal(core(inspectedWebView)->inspectorController(), inspectorPage)
244     , m_inspectorWebView(inspectorWebView)
245     , m_inspectedWebView(inspectedWebView)
246     , m_webInspector(webInspector)
247     , m_inspectorClient(inspectorClient)
248 {
249     g_signal_connect(m_inspectorWebView, "destroy",
250                      G_CALLBACK(notifyWebViewDestroyed), (gpointer)this);
251 }
252
253 InspectorFrontendClient::~InspectorFrontendClient()
254 {
255     if (m_inspectorClient) {
256         m_inspectorClient->disconnectFrontendClient();
257         m_inspectorClient = 0;
258     }
259     ASSERT(!m_webInspector);
260 }
261
262 void InspectorFrontendClient::destroyInspectorWindow(bool notifyInspectorController)
263 {
264     if (!m_webInspector)
265         return;
266     WebKitWebInspector* webInspector = m_webInspector;
267     m_webInspector = 0;
268
269     g_signal_handlers_disconnect_by_func(m_inspectorWebView, (gpointer)notifyWebViewDestroyed, (gpointer)this);
270     m_inspectorWebView = 0;
271
272     if (notifyInspectorController)
273         core(m_inspectedWebView)->inspectorController()->disconnectFrontend();
274
275     if (m_inspectorClient)
276         m_inspectorClient->releaseFrontendPage();
277
278     gboolean handled = FALSE;
279     g_signal_emit_by_name(webInspector, "close-window", &handled);
280     ASSERT(handled);
281
282     // Please do not use member variables here because InspectorFrontendClient object pointed by 'this'
283     // has been implicitly deleted by "close-window" function.
284
285     /* we should now dispose our own reference */
286     g_object_unref(webInspector);
287 }
288
289 String InspectorFrontendClient::localizedStringsURL()
290 {
291     GOwnPtr<gchar> stringsPath(g_build_filename(m_inspectorClient->inspectorFilesPath(), "localizedStrings.js", NULL));
292     GOwnPtr<gchar> stringsURI(g_filename_to_uri(stringsPath.get(), 0, 0));
293
294     // FIXME: support l10n of localizedStrings.js
295     return String::fromUTF8(stringsURI.get());
296 }
297
298 String InspectorFrontendClient::hiddenPanels()
299 {
300     notImplemented();
301     return String();
302 }
303
304 void InspectorFrontendClient::bringToFront()
305 {
306     if (!m_inspectorWebView)
307         return;
308
309     gboolean handled = FALSE;
310     g_signal_emit_by_name(m_webInspector, "show-window", &handled);
311 }
312
313 void InspectorFrontendClient::closeWindow()
314 {
315     destroyInspectorWindow(true);
316 }
317
318 void InspectorFrontendClient::disconnectFromBackend()
319 {
320     destroyInspectorWindow(false);
321 }
322
323 void InspectorFrontendClient::attachWindow()
324 {
325     if (!m_inspectorWebView)
326         return;
327
328     gboolean handled = FALSE;
329     g_signal_emit_by_name(m_webInspector, "attach-window", &handled);
330 }
331
332 void InspectorFrontendClient::detachWindow()
333 {
334     if (!m_inspectorWebView)
335         return;
336
337     gboolean handled = FALSE;
338     g_signal_emit_by_name(m_webInspector, "detach-window", &handled);
339 }
340
341 void InspectorFrontendClient::setAttachedWindowHeight(unsigned height)
342 {
343     notImplemented();
344 }
345
346 void InspectorFrontendClient::inspectedURLChanged(const String& newURL)
347 {
348     if (!m_inspectorWebView)
349         return;
350
351     webkit_web_inspector_set_inspected_uri(m_webInspector, newURL.utf8().data());
352 }
353
354 }
355