2008-11-06 Alp Toker <alp@nuanti.com>
[WebKit-https.git] / WebKit / gtk / WebCoreSupport / ChromeClientGtk.cpp
1 /*
2  * Copyright (C) 2007 Holger Hans Peter Freyther
3  * Copyright (C) 2007, 2008 Christian Dywan <christian@imendio.com>
4  * Copyright (C) 2008 Nuanti Ltd.
5  * Copyright (C) 2008 Alp Toker <alp@atoker.com>
6  *
7  *  This library is free software; you can redistribute it and/or
8  *  modify it under the terms of the GNU Lesser General Public
9  *  License as published by the Free Software Foundation; either
10  *  version 2 of the License, or (at your option) any later version.
11  *
12  *  This library is distributed in the hope that it will be useful,
13  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  *  Lesser General Public License for more details.
16  *
17  *  You should have received a copy of the GNU Lesser General Public
18  *  License along with this library; if not, write to the Free Software
19  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
20  */
21
22 #include "config.h"
23 #include "ChromeClientGtk.h"
24
25 #include "FileSystem.h"
26 #include "FileChooser.h"
27 #include "FloatRect.h"
28 #include "IntRect.h"
29 #include "PlatformString.h"
30 #include "CString.h"
31 #include "HitTestResult.h"
32 #include "KURL.h"
33 #include "webkitwebview.h"
34 #include "webkitprivate.h"
35 #include "NotImplemented.h"
36 #include "WindowFeatures.h"
37 #if ENABLE(DATABASE)
38 #include "DatabaseTracker.h"
39 #endif
40
41 #include <glib.h>
42 #include <glib/gi18n.h>
43 #include <gtk/gtk.h>
44
45 using namespace WebCore;
46
47 namespace WebKit {
48
49 ChromeClient::ChromeClient(WebKitWebView* webView)
50     : m_webView(webView)
51 {
52 }
53
54 void ChromeClient::chromeDestroyed()
55 {
56     delete this;
57 }
58
59 FloatRect ChromeClient::windowRect()
60 {
61     if (!m_webView)
62         return FloatRect();
63     GtkWidget* window = gtk_widget_get_toplevel(GTK_WIDGET(m_webView));
64     if (window) {
65         gint left, top, width, height;
66         gtk_window_get_position(GTK_WINDOW(window), &left, &top);
67         gtk_window_get_size(GTK_WINDOW(window), &width, &height);
68         return IntRect(left, top, width, height);
69     }
70     return FloatRect();
71 }
72
73 void ChromeClient::setWindowRect(const FloatRect& r)
74 {
75     notImplemented();
76 }
77
78 FloatRect ChromeClient::pageRect()
79 {
80     if (!m_webView)
81         return FloatRect();
82     GtkAllocation allocation = GTK_WIDGET(m_webView)->allocation;
83     return IntRect(allocation.x, allocation.y, allocation.width, allocation.height);
84 }
85
86 float ChromeClient::scaleFactor()
87 {
88     // Not implementable
89     return 1.0;
90 }
91
92 void ChromeClient::focus()
93 {
94     if (!m_webView)
95         return;
96     gtk_widget_grab_focus(GTK_WIDGET(m_webView));
97 }
98
99 void ChromeClient::unfocus()
100 {
101     if (!m_webView)
102         return;
103     GtkWidget* window = gtk_widget_get_toplevel(GTK_WIDGET(m_webView));
104     if (window)
105         gtk_window_set_focus(GTK_WINDOW(window), NULL);
106 }
107
108 Page* ChromeClient::createWindow(Frame*, const FrameLoadRequest&, const WindowFeatures& features)
109 {
110     if (features.dialog) {
111         notImplemented();
112         return 0;
113     } else {
114         /* TODO: FrameLoadRequest is not used */
115         WebKitWebView* webView = WEBKIT_WEB_VIEW_GET_CLASS(m_webView)->create_web_view(m_webView);
116         if (!webView)
117             return 0;
118
119         WebKitWebViewPrivate* privateData = WEBKIT_WEB_VIEW_GET_PRIVATE(webView);
120         return privateData->corePage;
121     }
122 }
123
124 void ChromeClient::show()
125 {
126     notImplemented();
127 }
128
129 bool ChromeClient::canRunModal()
130 {
131     notImplemented();
132     return false;
133 }
134
135 void ChromeClient::runModal()
136 {
137     notImplemented();
138 }
139
140 void ChromeClient::setToolbarsVisible(bool)
141 {
142     notImplemented();
143 }
144
145 bool ChromeClient::toolbarsVisible()
146 {
147     notImplemented();
148     return false;
149 }
150
151 void ChromeClient::setStatusbarVisible(bool)
152 {
153     notImplemented();
154 }
155
156 bool ChromeClient::statusbarVisible()
157 {
158     notImplemented();
159     return false;
160 }
161
162 void ChromeClient::setScrollbarsVisible(bool)
163 {
164     notImplemented();
165 }
166
167 bool ChromeClient::scrollbarsVisible() {
168     notImplemented();
169     return false;
170 }
171
172 void ChromeClient::setMenubarVisible(bool)
173 {
174     notImplemented();
175 }
176
177 bool ChromeClient::menubarVisible()
178 {
179     notImplemented();
180     return false;
181 }
182
183 void ChromeClient::setResizable(bool)
184 {
185     notImplemented();
186 }
187
188 void ChromeClient::closeWindowSoon()
189 {
190     notImplemented();
191 }
192
193 bool ChromeClient::canTakeFocus(FocusDirection)
194 {
195     if (!m_webView)
196         return false;
197     return GTK_WIDGET_CAN_FOCUS(m_webView);
198 }
199
200 void ChromeClient::takeFocus(FocusDirection)
201 {
202     unfocus();
203 }
204
205 bool ChromeClient::canRunBeforeUnloadConfirmPanel()
206 {
207     return true;
208 }
209
210 bool ChromeClient::runBeforeUnloadConfirmPanel(const WebCore::String& message, WebCore::Frame* frame)
211 {
212     return runJavaScriptConfirm(frame, message);
213 }
214
215 void ChromeClient::addMessageToConsole(const WebCore::String& message, unsigned int lineNumber, const WebCore::String& sourceId)
216 {
217     gboolean retval;
218     g_signal_emit_by_name(m_webView, "console-message", message.utf8().data(), lineNumber, sourceId.utf8().data(), &retval);
219 }
220
221 void ChromeClient::runJavaScriptAlert(Frame* frame, const String& message)
222 {
223     gboolean retval;
224     g_signal_emit_by_name(m_webView, "script-alert", kit(frame), message.utf8().data(), &retval);
225 }
226
227 bool ChromeClient::runJavaScriptConfirm(Frame* frame, const String& message)
228 {
229     gboolean retval;
230     gboolean didConfirm;
231     g_signal_emit_by_name(m_webView, "script-confirm", kit(frame), message.utf8().data(), &didConfirm, &retval);
232     return didConfirm == TRUE;
233 }
234
235 bool ChromeClient::runJavaScriptPrompt(Frame* frame, const String& message, const String& defaultValue, String& result)
236 {
237     gboolean retval;
238     gchar* value = 0;
239     g_signal_emit_by_name(m_webView, "script-prompt", kit(frame), message.utf8().data(), defaultValue.utf8().data(), &value, &retval);
240     if (value) {
241         result = String::fromUTF8(value);
242         g_free(value);
243         return true;
244     }
245     return false;
246 }
247
248 void ChromeClient::setStatusbarText(const String& string)
249 {
250     CString stringMessage = string.utf8();
251     g_signal_emit_by_name(m_webView, "status-bar-text-changed", stringMessage.data());
252 }
253
254 bool ChromeClient::shouldInterruptJavaScript()
255 {
256     notImplemented();
257     return false;
258 }
259
260 bool ChromeClient::tabsToLinks() const
261 {
262     return true;
263 }
264
265 IntRect ChromeClient::windowResizerRect() const
266 {
267     notImplemented();
268     return IntRect();
269 }
270
271 void ChromeClient::repaint(const IntRect& windowRect, bool contentChanged, bool immediate, bool repaintContentOnly)
272 {
273     if (!m_webView)
274         return;
275
276     GdkRectangle rect = windowRect;
277     GdkWindow* window = GTK_WIDGET(m_webView)->window;
278
279     if (window) {
280         if (contentChanged)
281             gdk_window_invalidate_rect(window, &rect, FALSE);
282         // We don't currently do immediate updates since they delay other UI elements.
283         //if (immediate)
284         //    gdk_window_process_updates(window, FALSE);
285     }
286 }
287
288 void ChromeClient::scroll(const IntSize& delta, const IntRect& rectToScroll, const IntRect& clipRect)
289 {
290     if (!m_webView)
291         return;
292
293     GdkWindow* window = GTK_WIDGET(m_webView)->window;
294     if (!window)
295         return;
296
297     GdkRectangle area = clipRect;
298     GdkRectangle moveRect;
299
300     GdkRectangle sourceRect = area;
301     sourceRect.x -= delta.width();
302     sourceRect.y -= delta.height();
303
304     GdkRegion* invalidRegion = gdk_region_rectangle(&area);
305
306     if (gdk_rectangle_intersect(&area, &sourceRect, &moveRect)) {
307         GdkRegion* moveRegion = gdk_region_rectangle(&moveRect);
308         gdk_window_move_region(window, moveRegion, delta.width(), delta.height());
309         gdk_region_offset(moveRegion, delta.width(), delta.height());
310         gdk_region_subtract(invalidRegion, moveRegion);
311         gdk_region_destroy(moveRegion);
312     }
313
314     gdk_window_invalidate_region(window, invalidRegion, FALSE);
315     gdk_region_destroy(invalidRegion);
316 }
317
318 IntRect ChromeClient::windowToScreen(const IntRect& rect) const
319 {
320     notImplemented();
321     return rect;
322 }
323
324 IntPoint ChromeClient::screenToWindow(const IntPoint& point) const
325 {
326     notImplemented();
327     return point;
328 }
329
330 PlatformWidget ChromeClient::platformWindow() const
331 {
332     return m_webView ? GTK_WIDGET(m_webView) : 0;
333 }
334
335 void ChromeClient::mouseDidMoveOverElement(const HitTestResult& hit, unsigned modifierFlags)
336 {
337     // check if the element is a link...
338     bool isLink = hit.isLiveLink();
339     if (isLink) {
340         KURL url = hit.absoluteLinkURL();
341         if (!url.isEmpty() && url != m_hoveredLinkURL) {
342             CString titleString = hit.title().utf8();
343             CString urlString = url.prettyURL().utf8();
344             g_signal_emit_by_name(m_webView, "hovering-over-link", titleString.data(), urlString.data());
345             m_hoveredLinkURL = url;
346         }
347     } else if (!isLink && !m_hoveredLinkURL.isEmpty()) {
348         g_signal_emit_by_name(m_webView, "hovering-over-link", 0, 0);
349         m_hoveredLinkURL = KURL();
350     }
351 }
352
353 void ChromeClient::setToolTip(const String& toolTip)
354 {
355 #if GTK_CHECK_VERSION(2,12,0)
356     if (toolTip.isEmpty())
357         g_object_set(G_OBJECT(m_webView), "has-tooltip", FALSE, NULL);
358     else
359         gtk_widget_set_tooltip_text(GTK_WIDGET(m_webView), toolTip.utf8().data());
360 #else
361     // TODO: Support older GTK+ versions
362     // See http://bugs.webkit.org/show_bug.cgi?id=15793
363     notImplemented();
364 #endif
365 }
366
367 void ChromeClient::print(Frame* frame)
368 {
369     webkit_web_frame_print(kit(frame));
370 }
371
372 void ChromeClient::exceededDatabaseQuota(Frame* frame, const String&)
373 {
374 #if ENABLE(DATABASE)
375     // Set to 5M for testing
376     // FIXME: Make this configurable
377     notImplemented();
378     const unsigned long long defaultQuota = 5 * 1024 * 1024;
379     DatabaseTracker::tracker().setQuota(frame->document()->securityOrigin(), defaultQuota);
380 #endif
381 }
382
383 void ChromeClient::runOpenPanel(Frame*, PassRefPtr<FileChooser> prpFileChooser)
384 {
385     RefPtr<FileChooser> chooser = prpFileChooser;
386
387     GtkWidget* dialog = gtk_file_chooser_dialog_new(_("Upload File"),
388                                                     GTK_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(platformWindow()))),
389                                                     GTK_FILE_CHOOSER_ACTION_OPEN,
390                                                     GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
391                                                     GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
392                                                     NULL);
393
394     gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(dialog), chooser->allowsMultipleFiles());
395
396     if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
397         if (gtk_file_chooser_get_select_multiple(GTK_FILE_CHOOSER(dialog))) {
398             GSList* filenames = gtk_file_chooser_get_filenames(GTK_FILE_CHOOSER(dialog));
399             Vector<String> names;
400             for (GSList* item = filenames ; item ; item = item->next) {
401                 if (!item->data)
402                     continue;
403                 names.append(filenameToString(static_cast<char*>(item->data)));
404                 g_free(item->data);
405             }
406             g_slist_free(filenames);
407             chooser->chooseFiles(names);
408         } else {
409             gchar* filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
410             if (filename)
411                 chooser->chooseFile(filenameToString(filename));
412             g_free(filename);
413         }
414     }
415     gtk_widget_destroy(dialog);
416 }
417
418 }