initial import
[vuplus_webkit] / Source / 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 "InspectorController.h"
25 #include "NotImplemented.h"
26 #include "Page.h"
27 #include "PlatformString.h"
28 #include "webkitversion.h"
29 #include "webkitwebinspector.h"
30 #include "webkitwebinspectorprivate.h"
31 #include "webkitwebview.h"
32 #include "webkitwebviewprivate.h"
33 #include <wtf/text/CString.h>
34
35 using namespace WebCore;
36
37 namespace WebKit {
38
39 static void notifyWebViewDestroyed(WebKitWebView* webView, InspectorFrontendClient* inspectorFrontendClient)
40 {
41     inspectorFrontendClient->destroyInspectorWindow(true);
42 }
43
44 namespace {
45
46 class InspectorFrontendSettingsGtk : public InspectorFrontendClientLocal::Settings {
47 public:
48     virtual ~InspectorFrontendSettingsGtk() { }
49
50 private:
51 #ifdef HAVE_GSETTINGS
52     static bool shouldIgnoreSetting(const String& key)
53     {
54         // GSettings considers trying to fetch or set a setting that is
55         // not backed by a schema as programmer error, and aborts the
56         // program's execution. We check here to avoid having an unhandled
57         // setting as a fatal error.
58         LOG_VERBOSE(NotYetImplemented, "Unknown key ignored: %s", key.ascii().data());
59         return true;
60     }
61
62     virtual String getProperty(const String& name)
63     {
64         if (shouldIgnoreSetting(name))
65             return String();
66
67         GSettings* settings = inspectorGSettings();
68         if (!settings)
69             return String();
70
71         GRefPtr<GVariant> variant = adoptGRef(g_settings_get_value(settings, name.utf8().data()));
72         return String(g_variant_get_string(variant.get(), 0));
73     }
74
75     virtual void setProperty(const String& name, const String& value)
76     {
77         // Avoid setting unknown keys to avoid aborting the execution.
78         if (shouldIgnoreSetting(name))
79             return;
80
81         GSettings* settings = inspectorGSettings();
82         if (!settings)
83             return;
84
85         GRefPtr<GVariant> variant = adoptGRef(g_variant_new_string(value.utf8().data()));
86         g_settings_set_value(settings, name.utf8().data(), variant.get());
87     }
88 #else
89     virtual String getProperty(const String&)
90     {
91         notImplemented();
92         return String();
93     }
94
95     virtual void setProperty(const String&, const String&)
96     {
97         notImplemented();
98     }
99 #endif // HAVE_GSETTINGS
100 };
101
102 } // namespace
103
104 InspectorClient::InspectorClient(WebKitWebView* webView)
105     : m_inspectedWebView(webView)
106     , m_frontendPage(0)
107     , m_frontendClient(0)
108 {}
109
110 InspectorClient::~InspectorClient()
111 {
112     if (m_frontendClient) {
113         m_frontendClient->disconnectInspectorClient();
114         m_frontendClient = 0;
115     }
116 }
117
118 void InspectorClient::inspectorDestroyed()
119 {
120     delete this;
121 }
122
123 void InspectorClient::openInspectorFrontend(InspectorController* controller)
124 {
125     // This g_object_get will ref the inspector. We're not doing an
126     // unref if this method succeeds because the inspector object must
127     // be alive even after the inspected WebView is destroyed - the
128     // close-window and destroy signals still need to be
129     // emitted.
130     WebKitWebInspector* webInspector = 0;
131     g_object_get(m_inspectedWebView, "web-inspector", &webInspector, NULL);
132     ASSERT(webInspector);
133
134     WebKitWebView* inspectorWebView = 0;
135     g_signal_emit_by_name(webInspector, "inspect-web-view", m_inspectedWebView, &inspectorWebView);
136
137     if (!inspectorWebView) {
138         g_object_unref(webInspector);
139         return;
140     }
141
142     webkit_web_inspector_set_web_view(webInspector, inspectorWebView);
143  
144     GOwnPtr<gchar> inspectorPath(g_build_filename(inspectorFilesPath(), "inspector.html", NULL));
145     GOwnPtr<gchar> inspectorURI(g_filename_to_uri(inspectorPath.get(), 0, 0));
146     webkit_web_view_load_uri(inspectorWebView, inspectorURI.get());
147
148     gtk_widget_show(GTK_WIDGET(inspectorWebView));
149
150     m_frontendPage = core(inspectorWebView);
151     OwnPtr<InspectorFrontendClient> frontendClient = adoptPtr(new InspectorFrontendClient(m_inspectedWebView, inspectorWebView, webInspector, m_frontendPage, this));
152     m_frontendClient = frontendClient.get();
153     m_frontendPage->inspectorController()->setInspectorFrontendClient(frontendClient.release());
154
155     // The inspector must be in it's own PageGroup to avoid deadlock while debugging.
156     m_frontendPage->setGroupName("");
157 }
158
159 void InspectorClient::releaseFrontendPage()
160 {
161     m_frontendPage = 0;
162 }
163
164 void InspectorClient::highlight()
165 {
166     hideHighlight();
167 }
168
169 void InspectorClient::hideHighlight()
170 {
171     // FIXME: we should be able to only invalidate the actual rects of
172     // the new and old nodes. We need to track the nodes, and take the
173     // actual highlight size into account when calculating the damage
174     // rect.
175     gtk_widget_queue_draw(GTK_WIDGET(m_inspectedWebView));
176 }
177
178 bool InspectorClient::sendMessageToFrontend(const String& message)
179 {
180     return doDispatchMessageOnFrontendPage(m_frontendPage, message);
181 }
182
183 const char* InspectorClient::inspectorFilesPath()
184 {
185     if (m_inspectorFilesPath)
186         m_inspectorFilesPath.get();
187
188     const char* environmentPath = getenv("WEBKIT_INSPECTOR_PATH");
189     if (environmentPath && g_file_test(environmentPath, G_FILE_TEST_IS_DIR))
190         m_inspectorFilesPath.set(g_strdup(environmentPath));
191     else
192         m_inspectorFilesPath.set(g_build_filename(DATA_DIR, "webkitgtk-"WEBKITGTK_API_VERSION_STRING, "webinspector", NULL));
193
194     return m_inspectorFilesPath.get();
195 }
196
197 InspectorFrontendClient::InspectorFrontendClient(WebKitWebView* inspectedWebView, WebKitWebView* inspectorWebView, WebKitWebInspector* webInspector, Page* inspectorPage, InspectorClient* inspectorClient)
198     : InspectorFrontendClientLocal(core(inspectedWebView)->inspectorController(), inspectorPage, adoptPtr(new InspectorFrontendSettingsGtk()))
199     , m_inspectorWebView(inspectorWebView)
200     , m_inspectedWebView(inspectedWebView)
201     , m_webInspector(webInspector)
202     , m_inspectorClient(inspectorClient)
203 {
204     g_signal_connect(m_inspectorWebView, "destroy",
205                      G_CALLBACK(notifyWebViewDestroyed), (gpointer)this);
206 }
207
208 InspectorFrontendClient::~InspectorFrontendClient()
209 {
210     if (m_inspectorClient) {
211         m_inspectorClient->disconnectFrontendClient();
212         m_inspectorClient = 0;
213     }
214     ASSERT(!m_webInspector);
215 }
216
217 void InspectorFrontendClient::destroyInspectorWindow(bool notifyInspectorController)
218 {
219     if (!m_webInspector)
220         return;
221     WebKitWebInspector* webInspector = m_webInspector;
222     m_webInspector = 0;
223
224     g_signal_handlers_disconnect_by_func(m_inspectorWebView, (gpointer)notifyWebViewDestroyed, (gpointer)this);
225     m_inspectorWebView = 0;
226
227     if (notifyInspectorController)
228         core(m_inspectedWebView)->inspectorController()->disconnectFrontend();
229
230     if (m_inspectorClient)
231         m_inspectorClient->releaseFrontendPage();
232
233     gboolean handled = FALSE;
234     g_signal_emit_by_name(webInspector, "close-window", &handled);
235     ASSERT(handled);
236
237     // Please do not use member variables here because InspectorFrontendClient object pointed by 'this'
238     // has been implicitly deleted by "close-window" function.
239
240     /* we should now dispose our own reference */
241     g_object_unref(webInspector);
242 }
243
244 String InspectorFrontendClient::localizedStringsURL()
245 {
246     GOwnPtr<gchar> stringsPath(g_build_filename(m_inspectorClient->inspectorFilesPath(), "localizedStrings.js", NULL));
247     GOwnPtr<gchar> stringsURI(g_filename_to_uri(stringsPath.get(), 0, 0));
248
249     // FIXME: support l10n of localizedStrings.js
250     return String::fromUTF8(stringsURI.get());
251 }
252
253 String InspectorFrontendClient::hiddenPanels()
254 {
255     notImplemented();
256     return String();
257 }
258
259 void InspectorFrontendClient::bringToFront()
260 {
261     if (!m_inspectorWebView)
262         return;
263
264     gboolean handled = FALSE;
265     g_signal_emit_by_name(m_webInspector, "show-window", &handled);
266 }
267
268 void InspectorFrontendClient::closeWindow()
269 {
270     destroyInspectorWindow(true);
271 }
272
273 void InspectorFrontendClient::disconnectFromBackend()
274 {
275     destroyInspectorWindow(false);
276 }
277
278 void InspectorFrontendClient::attachWindow()
279 {
280     if (!m_inspectorWebView)
281         return;
282
283     gboolean handled = FALSE;
284     g_signal_emit_by_name(m_webInspector, "attach-window", &handled);
285 }
286
287 void InspectorFrontendClient::detachWindow()
288 {
289     if (!m_inspectorWebView)
290         return;
291
292     gboolean handled = FALSE;
293     g_signal_emit_by_name(m_webInspector, "detach-window", &handled);
294 }
295
296 void InspectorFrontendClient::setAttachedWindowHeight(unsigned height)
297 {
298     notImplemented();
299 }
300
301 void InspectorFrontendClient::inspectedURLChanged(const String& newURL)
302 {
303     if (!m_inspectorWebView)
304         return;
305
306     webkit_web_inspector_set_inspected_uri(m_webInspector, newURL.utf8().data());
307 }
308
309 }
310