f9118168ad347f097f7028a1f8a4237dc395d45f
[WebKit-https.git] / WebKit / gtk / WebView / webkitwebview.cpp
1 /*
2  * Copyright (C) 2007 Holger Hans Peter Freyther
3  * Copyright (C) 2007 Christian Dywan <christian@twotoasts.de>
4  * Copyright (C) 2007 Xan Lopez <xan@gnome.org>
5  * Copyright (C) 2007 Alp Toker <alp@atoker.com>
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * 1.  Redistributions of source code must retain the above copyright
12  *     notice, this list of conditions and the following disclaimer. 
13  * 2.  Redistributions in binary form must reproduce the above copyright
14  *     notice, this list of conditions and the following disclaimer in the
15  *     documentation and/or other materials provided with the distribution. 
16  * 3.  Neither the name of Apple, Inc. ("Apple") nor the names of
17  *     its contributors may be used to endorse or promote products derived
18  *     from this software without specific prior written permission. 
19  *
20  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
21  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
22  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23  * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
24  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
25  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
26  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
27  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
29  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30  */
31
32 #include "config.h"
33
34 #include "webkitwebview.h"
35 #include "webkit-marshal.h"
36 #include "webkitprivate.h"
37
38 #include "NotImplemented.h"
39 #include "ChromeClientGtk.h"
40 #include "ContextMenuClientGtk.h"
41 #include "DragClientGtk.h"
42 #include "Editor.h"
43 #include "EditorClientGtk.h"
44 #include "EventHandler.h"
45 #include "FocusController.h"
46 #include "HitTestRequest.h"
47 #include "HitTestResult.h"
48 #include "GraphicsContext.h"
49 #include "InspectorClientGtk.h"
50 #include "FrameLoader.h"
51 #include "FrameView.h"
52 #include "Editor.h"
53 #include "PlatformKeyboardEvent.h"
54 #include "PlatformWheelEvent.h"
55 #include "SubstituteData.h"
56
57 #include <gdk/gdkkeysyms.h>
58
59 using namespace WebKit;
60 using namespace WebCore;
61
62 extern "C" {
63
64 enum {
65     /* normal signals */
66     NAVIGATION_REQUESTED,
67     WINDOW_OBJECT_CLEARED,
68     LOAD_STARTED,
69     LOAD_PROGRESS_CHANGED,
70     LOAD_FINISHED,
71     TITLE_CHANGED,
72     HOVERING_OVER_LINK,
73     STATUS_BAR_TEXT_CHANGED,
74     ICOND_LOADED,
75     SELECTION_CHANGED,
76     CONSOLE_MESSAGE,
77     SCRIPT_ALERT,
78     SCRIPT_CONFIRM,
79     SCRIPT_PROMPT,
80     SELECT_ALL,
81     COPY_CLIPBOARD,
82     PASTE_CLIPBOARD,
83     CUT_CLIPBOARD,
84     LAST_SIGNAL
85 };
86
87 static guint webkit_web_view_signals[LAST_SIGNAL] = { 0, };
88
89 G_DEFINE_TYPE(WebKitWebView, webkit_web_view, GTK_TYPE_CONTAINER)
90
91 static gboolean webkit_web_view_expose_event(GtkWidget* widget, GdkEventExpose* event)
92 {
93     Frame* frame = core(webkit_web_view_get_main_frame(WEBKIT_WEB_VIEW(widget)));
94     GdkRectangle clip;
95     gdk_region_get_clipbox(event->region, &clip);
96     cairo_t* cr = gdk_cairo_create(event->window);
97     GraphicsContext ctx(cr);
98     ctx.setGdkExposeEvent(event);
99     if (frame->renderer()) {
100         frame->view()->layoutIfNeededRecursive();
101         frame->view()->paint(&ctx, clip);
102     }
103     cairo_destroy(cr);
104
105     return FALSE;
106 }
107
108 static gboolean webkit_web_view_key_press_event(GtkWidget* widget, GdkEventKey* event)
109 {
110     Frame* frame = core(WEBKIT_WEB_VIEW(widget))->focusController()->focusedOrMainFrame();
111     PlatformKeyboardEvent keyboardEvent(event);
112
113     if (frame->eventHandler()->keyEvent(keyboardEvent))
114         return TRUE;
115
116     FrameView* view = frame->view();
117     SelectionController::EAlteration alteration;
118     if (event->state & GDK_SHIFT_MASK)
119         alteration = SelectionController::EXTEND;
120     else
121         alteration = SelectionController::MOVE;
122
123     // TODO: We probably want to use GTK+ key bindings here and perhaps take an
124     // approach more like the Win and Mac ports for key handling.
125     switch (event->keyval) {
126     case GDK_Down:
127         view->scrollBy(0, LINE_STEP);
128         return TRUE;
129     case GDK_Up:
130         view->scrollBy(0, -LINE_STEP);
131         return TRUE;
132     case GDK_Right:
133         view->scrollBy(LINE_STEP, 0);
134         return TRUE;
135     case GDK_Left:
136         view->scrollBy(-LINE_STEP, 0);
137         return TRUE;
138     case GDK_Home:
139         frame->selectionController()->modify(alteration, SelectionController::BACKWARD, DocumentBoundary, true);
140         return TRUE;
141     case GDK_End:
142         frame->selectionController()->modify(alteration, SelectionController::FORWARD, DocumentBoundary, true);
143         return TRUE;
144     }
145
146     /* Chain up to our parent class for binding activation */
147     return GTK_WIDGET_CLASS(webkit_web_view_parent_class)->key_press_event(widget, event);
148 }
149
150 static gboolean webkit_web_view_key_release_event(GtkWidget* widget, GdkEventKey* event)
151 {
152     Frame* frame = core(WEBKIT_WEB_VIEW(widget))->focusController()->focusedOrMainFrame();
153     PlatformKeyboardEvent keyboardEvent(event);
154
155     if (frame->eventHandler()->keyEvent(keyboardEvent))
156         return TRUE;
157
158     /* Chain up to our parent class for binding activation */
159     return GTK_WIDGET_CLASS(webkit_web_view_parent_class)->key_release_event(widget, event);
160 }
161
162 static gboolean webkit_web_view_button_press_event(GtkWidget* widget, GdkEventButton* event)
163 {
164     Frame* frame = core(webkit_web_view_get_main_frame(WEBKIT_WEB_VIEW(widget)));
165
166     // FIXME: need to keep track of subframe focus for key events
167     gtk_widget_grab_focus(GTK_WIDGET(widget));
168     return frame->eventHandler()->handleMousePressEvent(PlatformMouseEvent(event));
169 }
170
171 static gboolean webkit_web_view_button_release_event(GtkWidget* widget, GdkEventButton* event)
172 {
173     Frame* frame = core(webkit_web_view_get_main_frame(WEBKIT_WEB_VIEW(widget)));
174
175     WebKitWebView* web_view = WEBKIT_WEB_VIEW(widget);
176     WebKitWebViewPrivate* webViewData = WEBKIT_WEB_VIEW_GET_PRIVATE(web_view);
177     Frame* focusedFrame = webViewData->corePage->focusController()->focusedFrame();
178
179     if (focusedFrame->editor()->canEdit()) {
180         GdkWindow* window = gtk_widget_get_parent_window(widget);
181         gtk_im_context_set_client_window(webViewData->imContext, window);
182 #ifdef MAEMO_CHANGES
183         hildon_gtk_im_context_filter_event(webViewData->imContext, (GdkEvent*)event);
184         hildon_gtk_im_context_show(webViewData->imContext);
185 #endif
186     }
187
188     return frame->eventHandler()->handleMouseReleaseEvent(PlatformMouseEvent(event));
189 }
190
191 static gboolean webkit_web_view_motion_event(GtkWidget* widget, GdkEventMotion* event)
192 {
193     Frame* frame = core(webkit_web_view_get_main_frame(WEBKIT_WEB_VIEW(widget)));
194     return frame->eventHandler()->mouseMoved(PlatformMouseEvent(event));
195 }
196
197 static gboolean webkit_web_view_scroll_event(GtkWidget* widget, GdkEventScroll* event)
198 {
199     Frame* frame = core(webkit_web_view_get_main_frame(WEBKIT_WEB_VIEW(widget)));
200     PlatformWheelEvent wheelEvent(event);
201     return frame->eventHandler()->handleWheelEvent(wheelEvent);
202 }
203
204 static void webkit_web_view_size_allocate(GtkWidget* widget, GtkAllocation* allocation)
205 {
206     GTK_WIDGET_CLASS(webkit_web_view_parent_class)->size_allocate(widget,allocation);
207
208     Frame* frame = core(webkit_web_view_get_main_frame(WEBKIT_WEB_VIEW(widget)));
209     frame->view()->resize(allocation->width, allocation->height);
210     frame->forceLayout();
211     frame->view()->adjustViewSize();
212 }
213
214 static void webkit_web_view_realize(GtkWidget* widget)
215 {
216     GTK_WIDGET_SET_FLAGS(widget, GTK_REALIZED);
217
218     GdkWindowAttr attributes;
219     attributes.window_type = GDK_WINDOW_CHILD;
220     attributes.x = widget->allocation.x;
221     attributes.y = widget->allocation.y;
222     attributes.width = widget->allocation.width;
223     attributes.height = widget->allocation.height;
224     attributes.wclass = GDK_INPUT_OUTPUT;
225     attributes.visual = gtk_widget_get_visual (widget);
226     attributes.colormap = gtk_widget_get_colormap (widget);
227     attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK
228                             | GDK_EXPOSURE_MASK
229                             | GDK_BUTTON_PRESS_MASK
230                             | GDK_BUTTON_RELEASE_MASK
231                             | GDK_POINTER_MOTION_MASK
232                             | GDK_KEY_PRESS_MASK
233                             | GDK_KEY_RELEASE_MASK
234                             | GDK_BUTTON_MOTION_MASK
235                             | GDK_BUTTON1_MOTION_MASK
236                             | GDK_BUTTON2_MOTION_MASK
237                             | GDK_BUTTON3_MOTION_MASK;
238
239     gint attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
240     widget->window = gdk_window_new(gtk_widget_get_parent_window (widget), &attributes, attributes_mask);
241     gdk_window_set_user_data(widget->window, widget);
242 }
243
244 static void webkit_web_view_set_scroll_adjustments(WebKitWebView* webView, GtkAdjustment* hadj, GtkAdjustment* vadj)
245 {
246     FrameView* view = core(webkit_web_view_get_main_frame(webView))->view();
247     view->setGtkAdjustments(hadj, vadj);
248 }
249
250 static void webkit_web_view_container_add(GtkContainer* container, GtkWidget* widget)
251 {
252     WebKitWebView* webView = WEBKIT_WEB_VIEW(container);
253     WebKitWebViewPrivate* private_data = WEBKIT_WEB_VIEW_GET_PRIVATE(webView);
254
255     private_data->children.add(widget);
256     if (GTK_WIDGET_REALIZED(container))
257         gtk_widget_set_parent_window(widget, GTK_WIDGET(webView)->window);
258     gtk_widget_set_parent(widget, GTK_WIDGET(container));
259 }
260
261 static void webkit_web_view_container_remove(GtkContainer* container, GtkWidget* widget)
262 {
263     WebKitWebViewPrivate* private_data = WEBKIT_WEB_VIEW_GET_PRIVATE(WEBKIT_WEB_VIEW(container));
264
265     if (private_data->children.contains(widget)) {
266         gtk_widget_unparent(widget);
267         private_data->children.remove(widget);
268     }
269 }
270
271 static void webkit_web_view_container_forall(GtkContainer* container, gboolean, GtkCallback callback, gpointer callbackData)
272 {
273     WebKitWebViewPrivate* privateData = WEBKIT_WEB_VIEW_GET_PRIVATE(WEBKIT_WEB_VIEW(container));
274
275     HashSet<GtkWidget*> children = privateData->children;
276     HashSet<GtkWidget*>::const_iterator end = children.end();
277     for (HashSet<GtkWidget*>::const_iterator current = children.begin(); current != end; ++current)
278         (*callback)(*current, callbackData);
279 }
280
281 static WebKitWebView* webkit_web_view_real_create_web_view(WebKitWebView*)
282 {
283     notImplemented();
284     return 0;
285 }
286
287 static WebKitNavigationResponse webkit_web_view_real_navigation_requested(WebKitWebView*, WebKitWebFrame* frame, WebKitNetworkRequest*)
288 {
289     notImplemented();
290     return WEBKIT_NAVIGATION_RESPONSE_ACCEPT;
291 }
292
293 static void webkit_web_view_real_window_object_cleared(WebKitWebView*, WebKitWebFrame*, JSGlobalContextRef context, JSObjectRef window_object)
294 {
295     notImplemented();
296 }
297
298 static gchar* webkit_web_view_real_choose_file(WebKitWebView*, WebKitWebFrame*, const gchar* old_name)
299 {
300     notImplemented();
301     return g_strdup(old_name);
302 }
303
304 typedef enum {
305     WEBKIT_SCRIPT_DIALOG_ALERT,
306     WEBKIT_SCRIPT_DIALOG_CONFIRM,
307     WEBKIT_SCRIPT_DIALOG_PROMPT
308  } WebKitScriptDialogType;
309
310 static gboolean webkit_web_view_script_dialog(WebKitWebView* webView, WebKitWebFrame* frame, const gchar* message, WebKitScriptDialogType type, const gchar* defaultValue, gchar** value)
311 {
312     GtkMessageType messageType;
313     GtkButtonsType buttons;
314     gint defaultResponse;
315     GtkWidget* window;
316     GtkWidget* dialog;
317     GtkWidget* entry = 0;
318     gboolean didConfirm = FALSE;
319
320     switch (type) {
321     case WEBKIT_SCRIPT_DIALOG_ALERT:
322         messageType = GTK_MESSAGE_WARNING;
323         buttons = GTK_BUTTONS_CLOSE;
324         defaultResponse = GTK_RESPONSE_CLOSE;
325         break;
326     case WEBKIT_SCRIPT_DIALOG_CONFIRM:
327         messageType = GTK_MESSAGE_QUESTION;
328         buttons = GTK_BUTTONS_YES_NO;
329         defaultResponse = GTK_RESPONSE_YES;
330         break;
331     case WEBKIT_SCRIPT_DIALOG_PROMPT:
332         messageType = GTK_MESSAGE_QUESTION;
333         buttons = GTK_BUTTONS_OK_CANCEL;
334         defaultResponse = GTK_RESPONSE_OK;
335         break;
336     default:
337         g_warning("Unknown value for WebKitScriptDialogType.");
338         return FALSE;
339     }
340
341     window = gtk_widget_get_toplevel(GTK_WIDGET(webView));
342     dialog = gtk_message_dialog_new(GTK_WIDGET_TOPLEVEL(window) ? GTK_WINDOW(window) : 0, GTK_DIALOG_DESTROY_WITH_PARENT, messageType, buttons, "%s", message);
343     gchar* title = g_strconcat("JavaScript - ", webkit_web_frame_get_location(frame), NULL);
344     gtk_window_set_title(GTK_WINDOW(dialog), title);
345     g_free(title);
346
347     if (type == WEBKIT_SCRIPT_DIALOG_PROMPT) {
348         entry = gtk_entry_new();
349         gtk_entry_set_text(GTK_ENTRY(entry), defaultValue);
350         gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), entry);
351         gtk_entry_set_activates_default(GTK_ENTRY(entry), TRUE);
352         gtk_widget_show(entry);
353     }
354
355     gtk_dialog_set_default_response(GTK_DIALOG(dialog), defaultResponse);
356     gint response = gtk_dialog_run(GTK_DIALOG(dialog));
357
358     switch (response) {
359     case GTK_RESPONSE_YES:
360         didConfirm = TRUE;
361         break;
362     case GTK_RESPONSE_OK:
363         didConfirm = TRUE;
364         if (entry)
365             *value = g_strdup(gtk_entry_get_text(GTK_ENTRY(entry)));
366         else
367             *value = 0;
368         break;
369     case GTK_RESPONSE_NO:
370     case GTK_RESPONSE_CANCEL:
371         didConfirm = FALSE;
372         break;
373
374     }
375     gtk_widget_destroy(GTK_WIDGET(dialog));
376     return didConfirm;
377 }
378
379 static gboolean webkit_web_view_real_script_alert(WebKitWebView* webView, WebKitWebFrame* frame, const gchar* message)
380 {
381     webkit_web_view_script_dialog(webView, frame, message, WEBKIT_SCRIPT_DIALOG_ALERT, 0, 0);
382     return TRUE;
383 }
384
385 static gboolean webkit_web_view_real_script_confirm(WebKitWebView* webView, WebKitWebFrame* frame, const gchar* message, gboolean* didConfirm)
386 {
387     *didConfirm = webkit_web_view_script_dialog(webView, frame, message, WEBKIT_SCRIPT_DIALOG_CONFIRM, 0, 0);
388     return TRUE;
389 }
390
391 static gboolean webkit_web_view_real_script_prompt(WebKitWebView* webView, WebKitWebFrame* frame, const gchar* message, const gchar* defaultValue, gchar** value)
392 {
393     if (!webkit_web_view_script_dialog(webView, frame, message, WEBKIT_SCRIPT_DIALOG_PROMPT, defaultValue, value))
394         *value = NULL;
395     return TRUE;
396 }
397
398 static gboolean webkit_web_view_real_console_message(WebKitWebView* webView, const gchar* message, unsigned int line, const gchar* sourceId)
399 {
400     g_print("console message: %s @%d: %s\n", sourceId, line, message);
401     return TRUE;
402 }
403
404 static void webkit_web_view_real_select_all(WebKitWebView* webView)
405 {
406     Frame* frame = core(webView)->focusController()->focusedOrMainFrame();
407     frame->editor()->execCommand("SelectAll");
408 }
409
410 static void webkit_web_view_real_cut_clipboard(WebKitWebView* webView)
411 {
412     Frame* frame = core(webView)->focusController()->focusedOrMainFrame();
413     frame->editor()->execCommand("Cut");
414 }
415
416 static void webkit_web_view_real_copy_clipboard(WebKitWebView* webView)
417 {
418     Frame* frame = core(webView)->focusController()->focusedOrMainFrame();
419     frame->editor()->execCommand("Copy");
420 }
421
422 static void webkit_web_view_real_paste_clipboard(WebKitWebView* webView)
423 {
424     Frame* frame = core(webView)->focusController()->focusedOrMainFrame();
425     frame->editor()->execCommand("Paste");
426 }
427
428 static void webkit_web_view_finalize(GObject* object)
429 {
430     webkit_web_view_stop_loading(WEBKIT_WEB_VIEW(object));
431
432     WebKitWebViewPrivate* webViewData = WEBKIT_WEB_VIEW_GET_PRIVATE(WEBKIT_WEB_VIEW(object));
433     delete webViewData->corePage;
434     delete webViewData->settings;
435     g_object_unref(webViewData->mainFrame);
436     g_object_unref(webViewData->imContext);
437     delete webViewData->userAgent;
438
439     G_OBJECT_CLASS(webkit_web_view_parent_class)->finalize(object);
440 }
441
442 static void webkit_web_view_class_init(WebKitWebViewClass* webViewClass)
443 {
444     GtkBindingSet* binding_set;
445
446     g_type_class_add_private(webViewClass, sizeof(WebKitWebViewPrivate));
447
448     /*
449      * Signals
450      */
451
452     webkit_web_view_signals[NAVIGATION_REQUESTED] = g_signal_new("navigation-requested",
453             G_TYPE_FROM_CLASS(webViewClass),
454             (GSignalFlags)(G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION),
455             G_STRUCT_OFFSET (WebKitWebViewClass, navigation_requested),
456             NULL,
457             NULL,
458             webkit_marshal_INT__OBJECT_OBJECT,
459             G_TYPE_INT, 2,
460             G_TYPE_OBJECT,
461             G_TYPE_OBJECT);
462
463     /**
464      * WebKitWebView::window-object-cleared:
465      * @web_view: the object on which the signal is emitted
466      * @frame: the #WebKitWebFrame to which @window_object belongs
467      * @context: the #JSGlobalContextRef holding the global object and other
468      * execution state; equivalent to the return value of
469      * webkit_web_frame_get_global_context(@frame)
470      *
471      * @window_object: the #JSObjectRef representing the frame's JavaScript
472      * window object
473      *
474      * Emitted when the JavaScript window object in a #WebKitWebFrame has been
475      * cleared in preparation for a new load. This is the preferred place to
476      * set custom properties on the window object using the JavaScriptCore API.
477      */
478     webkit_web_view_signals[WINDOW_OBJECT_CLEARED] = g_signal_new("window-object-cleared",
479             G_TYPE_FROM_CLASS(webViewClass),
480             (GSignalFlags)(G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION),
481             G_STRUCT_OFFSET (WebKitWebViewClass, window_object_cleared),
482             NULL,
483             NULL,
484             webkit_marshal_VOID__OBJECT_POINTER_POINTER,
485             G_TYPE_NONE, 3,
486             WEBKIT_TYPE_WEB_FRAME,
487             G_TYPE_POINTER,
488             G_TYPE_POINTER);
489
490     /**
491      * WebKitWebView::load-started:
492      * @web_view: the object on which the signal is emitted
493      * @frame: the frame going to do the load
494      *
495      * When a #WebKitWebFrame begins to load this signal is emitted.
496      */
497     webkit_web_view_signals[LOAD_STARTED] = g_signal_new("load-started",
498             G_TYPE_FROM_CLASS(webViewClass),
499             (GSignalFlags)(G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION),
500             0,
501             NULL,
502             NULL,
503             g_cclosure_marshal_VOID__OBJECT,
504             G_TYPE_NONE, 1,
505             WEBKIT_TYPE_WEB_FRAME);
506
507     /**
508      * WebKitWebView::load-progress-changed:
509      * @web_view: the #WebKitWebView
510      * @progress: the global progress
511      */
512     webkit_web_view_signals[LOAD_PROGRESS_CHANGED] = g_signal_new("load-progress-changed",
513             G_TYPE_FROM_CLASS(webViewClass),
514             (GSignalFlags)(G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION),
515             0,
516             NULL,
517             NULL,
518             g_cclosure_marshal_VOID__INT,
519             G_TYPE_NONE, 1,
520             G_TYPE_INT);
521
522     webkit_web_view_signals[LOAD_FINISHED] = g_signal_new("load-finished",
523             G_TYPE_FROM_CLASS(webViewClass),
524             (GSignalFlags)(G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION),
525             0,
526             NULL,
527             NULL,
528             g_cclosure_marshal_VOID__OBJECT,
529             G_TYPE_NONE, 1,
530             WEBKIT_TYPE_WEB_FRAME);
531
532     webkit_web_view_signals[TITLE_CHANGED] = g_signal_new("title-changed",
533             G_TYPE_FROM_CLASS(webViewClass),
534             (GSignalFlags)(G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION),
535             0,
536             NULL,
537             NULL,
538             webkit_marshal_VOID__STRING_STRING,
539             G_TYPE_NONE, 2,
540             G_TYPE_STRING, G_TYPE_STRING);
541
542     webkit_web_view_signals[HOVERING_OVER_LINK] = g_signal_new("hovering-over-link",
543             G_TYPE_FROM_CLASS(webViewClass),
544             (GSignalFlags)(G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION),
545             0,
546             NULL,
547             NULL,
548             webkit_marshal_VOID__STRING_STRING,
549             G_TYPE_NONE, 2,
550             G_TYPE_STRING,
551             G_TYPE_STRING);
552
553     webkit_web_view_signals[STATUS_BAR_TEXT_CHANGED] = g_signal_new("status-bar-text-changed",
554             G_TYPE_FROM_CLASS(webViewClass),
555             (GSignalFlags)(G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION),
556             0,
557             NULL,
558             NULL,
559             g_cclosure_marshal_VOID__STRING,
560             G_TYPE_NONE, 1,
561             G_TYPE_STRING);
562
563     webkit_web_view_signals[ICOND_LOADED] = g_signal_new("icon-loaded",
564             G_TYPE_FROM_CLASS(webViewClass),
565             (GSignalFlags)(G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION),
566             0,
567             NULL,
568             NULL,
569             g_cclosure_marshal_VOID__VOID,
570             G_TYPE_NONE, 0);
571
572     webkit_web_view_signals[SELECTION_CHANGED] = g_signal_new("selection-changed",
573             G_TYPE_FROM_CLASS(webViewClass),
574             (GSignalFlags)(G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION),
575             0,
576             NULL,
577             NULL,
578             g_cclosure_marshal_VOID__VOID,
579             G_TYPE_NONE, 0);
580
581     /**
582      * WebKitWebView::console-message:
583      * @web_view: the object on which the signal is emitted
584      * @message: the message text
585      * @line: the line where the error occured
586      * @source_id: the source id
587      * @return: TRUE to stop other handlers from being invoked for the event. FALSE to propagate the event further.
588      *
589      * A JavaScript console message was created.
590      */
591     webkit_web_view_signals[CONSOLE_MESSAGE] = g_signal_new("console-message",
592             G_TYPE_FROM_CLASS(webViewClass),
593             (GSignalFlags)(G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION),
594             G_STRUCT_OFFSET(WebKitWebViewClass, console_message),
595             g_signal_accumulator_true_handled,
596             NULL,
597             webkit_marshal_BOOLEAN__STRING_INT_STRING,
598             G_TYPE_BOOLEAN, 3,
599             G_TYPE_STRING, G_TYPE_INT, G_TYPE_STRING);
600
601     /**
602      * WebKitWebView::script-alert:
603      * @web_view: the object on which the signal is emitted
604      * @frame: the relevant frame
605      * @message: the message text
606      * @return: TRUE to stop other handlers from being invoked for the event. FALSE to propagate the event further.
607      *
608      * A JavaScript alert dialog was created.
609      */
610     webkit_web_view_signals[SCRIPT_ALERT] = g_signal_new("script-alert",
611             G_TYPE_FROM_CLASS(webViewClass),
612             (GSignalFlags)(G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION),
613             G_STRUCT_OFFSET(WebKitWebViewClass, script_alert),
614             g_signal_accumulator_true_handled,
615             NULL,
616             webkit_marshal_BOOLEAN__OBJECT_STRING,
617             G_TYPE_BOOLEAN, 2,
618             G_TYPE_OBJECT, G_TYPE_STRING);
619
620     /**
621      * WebKitWebView::script-confirm:
622      * @web_view: the object on which the signal is emitted
623      * @frame: the relevant frame
624      * @message: the message text
625      * @confirmed: whether the dialog has been confirmed
626      * @return: TRUE to stop other handlers from being invoked for the event. FALSE to propagate the event further.
627      *
628      * A JavaScript confirm dialog was created, providing Yes and No buttons.
629      */
630     webkit_web_view_signals[SCRIPT_CONFIRM] = g_signal_new("script-confirm",
631             G_TYPE_FROM_CLASS(webViewClass),
632             (GSignalFlags)(G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION),
633             G_STRUCT_OFFSET(WebKitWebViewClass, script_confirm),
634             g_signal_accumulator_true_handled,
635             NULL,
636             webkit_marshal_BOOLEAN__OBJECT_STRING_BOOLEAN,
637             G_TYPE_BOOLEAN, 3,
638             G_TYPE_OBJECT, G_TYPE_STRING, G_TYPE_BOOLEAN);
639
640     /**
641      * WebKitWebView::script-prompt:
642      * @web_view: the object on which the signal is emitted
643      * @frame: the relevant frame
644      * @message: the message text
645      * @default: the default value
646      * @text: To be filled with the return value or NULL if the dialog was cancelled.
647      * @return: TRUE to stop other handlers from being invoked for the event. FALSE to propagate the event further.
648      *
649      * A JavaScript prompt dialog was created, providing an entry to input text.
650      */
651     webkit_web_view_signals[SCRIPT_PROMPT] = g_signal_new("script-prompt",
652             G_TYPE_FROM_CLASS(webViewClass),
653             (GSignalFlags)(G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION),
654             G_STRUCT_OFFSET(WebKitWebViewClass, script_prompt),
655             g_signal_accumulator_true_handled,
656             NULL,
657             webkit_marshal_BOOLEAN__OBJECT_STRING_STRING_STRING,
658             G_TYPE_BOOLEAN, 4,
659             G_TYPE_OBJECT, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_POINTER);
660
661     /**
662      * WebKitWebView::select-all:
663      * @web_view: the object which received the signal
664      *
665      * The ::select-all signal is a keybinding signal which gets emitted to
666      * select the complete contents of the text view.
667      *
668      * The default bindings for this signal is Ctrl-a.
669      */
670     webkit_web_view_signals[SELECT_ALL] = g_signal_new("select-all",
671             G_TYPE_FROM_CLASS(webViewClass),
672             (GSignalFlags)(G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION),
673             G_STRUCT_OFFSET(WebKitWebViewClass, select_all),
674             NULL, NULL,
675             g_cclosure_marshal_VOID__VOID,
676             G_TYPE_NONE, 0);
677
678     /**
679      * WebKitWebView::cut-clipboard:
680      * @web_view: the object which received the signal
681      *
682      * The ::cut-clipboard signal is a keybinding signal which gets emitted to
683      * cut the selection to the clipboard.
684      *
685      * The default bindings for this signal are Ctrl-x and Shift-Delete.
686      */
687     webkit_web_view_signals[CUT_CLIPBOARD] = g_signal_new("cut-clipboard",
688             G_TYPE_FROM_CLASS(webViewClass),
689             (GSignalFlags)(G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION),
690             G_STRUCT_OFFSET(WebKitWebViewClass, cut_clipboard),
691             NULL, NULL,
692             g_cclosure_marshal_VOID__VOID,
693             G_TYPE_NONE, 0);
694
695     /**
696      * WebKitWebView::copy-clipboard:
697      * @web_view: the object which received the signal
698      *
699      * The ::copy-clipboard signal is a keybinding signal which gets emitted to
700      * copy the selection to the clipboard.
701      *
702      * The default bindings for this signal are Ctrl-c and Ctrl-Insert.
703      */
704     webkit_web_view_signals[COPY_CLIPBOARD] = g_signal_new("copy-clipboard",
705             G_TYPE_FROM_CLASS(webViewClass),
706             (GSignalFlags)(G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION),
707             G_STRUCT_OFFSET(WebKitWebViewClass, copy_clipboard),
708             NULL, NULL,
709             g_cclosure_marshal_VOID__VOID,
710             G_TYPE_NONE, 0);
711
712     /**
713      * WebKitWebView::paste-clipboard:
714      * @web_view: the object which received the signal
715      *
716      * The ::paste-clipboard signal is a keybinding signal which gets emitted to
717      * paste the contents of the clipboard into the Web view.
718      *
719      * The default bindings for this signal are Ctrl-v and Shift-Insert.
720      */
721     webkit_web_view_signals[PASTE_CLIPBOARD] = g_signal_new("paste-clipboard",
722             G_TYPE_FROM_CLASS(webViewClass),
723             (GSignalFlags)(G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION),
724             G_STRUCT_OFFSET(WebKitWebViewClass, paste_clipboard),
725             NULL, NULL,
726             g_cclosure_marshal_VOID__VOID,
727             G_TYPE_NONE, 0);
728
729     /*
730      * implementations of virtual methods
731      */
732     webViewClass->create_web_view = webkit_web_view_real_create_web_view;
733     webViewClass->navigation_requested = webkit_web_view_real_navigation_requested;
734     webViewClass->window_object_cleared = webkit_web_view_real_window_object_cleared;
735     webViewClass->choose_file = webkit_web_view_real_choose_file;
736     webViewClass->script_alert = webkit_web_view_real_script_alert;
737     webViewClass->script_confirm = webkit_web_view_real_script_confirm;
738     webViewClass->script_prompt = webkit_web_view_real_script_prompt;
739     webViewClass->console_message = webkit_web_view_real_console_message;
740     webViewClass->select_all = webkit_web_view_real_select_all;
741     webViewClass->cut_clipboard = webkit_web_view_real_cut_clipboard;
742     webViewClass->copy_clipboard = webkit_web_view_real_copy_clipboard;
743     webViewClass->paste_clipboard = webkit_web_view_real_paste_clipboard;
744
745     G_OBJECT_CLASS(webViewClass)->finalize = webkit_web_view_finalize;
746
747     GtkWidgetClass* widgetClass = GTK_WIDGET_CLASS(webViewClass);
748     widgetClass->realize = webkit_web_view_realize;
749     widgetClass->expose_event = webkit_web_view_expose_event;
750     widgetClass->key_press_event = webkit_web_view_key_press_event;
751     widgetClass->key_release_event = webkit_web_view_key_release_event;
752     widgetClass->button_press_event = webkit_web_view_button_press_event;
753     widgetClass->button_release_event = webkit_web_view_button_release_event;
754     widgetClass->motion_notify_event = webkit_web_view_motion_event;
755     widgetClass->scroll_event = webkit_web_view_scroll_event;
756     widgetClass->size_allocate = webkit_web_view_size_allocate;
757
758     GtkContainerClass* containerClass = GTK_CONTAINER_CLASS(webViewClass);
759     containerClass->add = webkit_web_view_container_add;
760     containerClass->remove = webkit_web_view_container_remove;
761     containerClass->forall = webkit_web_view_container_forall;
762
763     /*
764      * make us scrollable (e.g. addable to a GtkScrolledWindow)
765      */
766     webViewClass->set_scroll_adjustments = webkit_web_view_set_scroll_adjustments;
767     GTK_WIDGET_CLASS(webViewClass)->set_scroll_adjustments_signal = g_signal_new("set-scroll-adjustments",
768             G_TYPE_FROM_CLASS(webViewClass),
769             (GSignalFlags)(G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION),
770             G_STRUCT_OFFSET(WebKitWebViewClass, set_scroll_adjustments),
771             NULL, NULL,
772             webkit_marshal_VOID__OBJECT_OBJECT,
773             G_TYPE_NONE, 2,
774             GTK_TYPE_ADJUSTMENT, GTK_TYPE_ADJUSTMENT);
775
776     /*
777      * Key bindings
778      */
779
780     binding_set = gtk_binding_set_by_class(webViewClass);
781
782     gtk_binding_entry_add_signal(binding_set, GDK_a, GDK_CONTROL_MASK,
783                                  "select_all", 0);
784
785     /* Cut/copy/paste */
786
787     gtk_binding_entry_add_signal(binding_set, GDK_x, GDK_CONTROL_MASK,
788                                  "cut_clipboard", 0);
789     gtk_binding_entry_add_signal(binding_set, GDK_c, GDK_CONTROL_MASK,
790                                  "copy_clipboard", 0);
791     gtk_binding_entry_add_signal(binding_set, GDK_v, GDK_CONTROL_MASK,
792                                  "paste_clipboard", 0);
793
794     gtk_binding_entry_add_signal(binding_set, GDK_Delete, GDK_SHIFT_MASK,
795                                  "cut_clipboard", 0);
796     gtk_binding_entry_add_signal(binding_set, GDK_Insert, GDK_CONTROL_MASK,
797                                  "copy_clipboard", 0);
798     gtk_binding_entry_add_signal(binding_set, GDK_Insert, GDK_SHIFT_MASK,
799                                  "paste_clipboard", 0);
800 }
801
802 static void webkit_web_view_init(WebKitWebView* webView)
803 {
804     WebKitWebViewPrivate* webViewData = WEBKIT_WEB_VIEW_GET_PRIVATE(WEBKIT_WEB_VIEW(webView));
805     webViewData->imContext = gtk_im_multicontext_new();
806     webViewData->corePage = new Page(new WebKit::ChromeClient(webView), new WebKit::ContextMenuClient, new WebKit::EditorClient(webView), new WebKit::DragClient, new WebKit::InspectorClient);
807
808     Settings* settings = webViewData->corePage->settings();
809     settings->setLoadsImagesAutomatically(true);
810     settings->setMinimumFontSize(5);
811     settings->setDOMPasteAllowed(true);
812     settings->setMinimumLogicalFontSize(5);
813     settings->setShouldPrintBackgrounds(true);
814     settings->setJavaScriptEnabled(true);
815     settings->setDefaultFixedFontSize(14);
816     settings->setDefaultFontSize(14);
817     settings->setSerifFontFamily("Times New Roman");
818     settings->setSansSerifFontFamily("Arial");
819     settings->setFixedFontFamily("Courier New");
820     settings->setStandardFontFamily("Arial");
821
822     GTK_WIDGET_SET_FLAGS(webView, GTK_CAN_FOCUS);
823     webViewData->mainFrame = WEBKIT_WEB_FRAME(webkit_web_frame_new(webView));
824     webViewData->editable = false;
825 }
826
827 GtkWidget* webkit_web_view_new(void)
828 {
829     WebKitWebView* webView = WEBKIT_WEB_VIEW(g_object_new(WEBKIT_TYPE_WEB_VIEW, NULL));
830
831     return GTK_WIDGET(webView);
832 }
833
834 void webkit_web_view_set_settings(WebKitWebView* webView, WebKitSettings* settings)
835 {
836     g_return_if_fail(WEBKIT_IS_WEB_VIEW(webView));
837     g_return_if_fail(settings);
838
839     notImplemented();
840 }
841
842 WebKitSettings* webkit_web_view_get_settings(WebKitWebView* webView)
843 {
844     g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), NULL);
845
846     notImplemented();
847     return NULL;
848 }
849
850 void webkit_web_view_go_backward(WebKitWebView* webView)
851 {
852     g_return_if_fail(WEBKIT_IS_WEB_VIEW(webView));
853
854     Frame* frame = core(webkit_web_view_get_main_frame(webView));
855     frame->loader()->goBackOrForward(-1);
856 }
857
858 void webkit_web_view_go_forward(WebKitWebView* webView)
859 {
860     g_return_if_fail(WEBKIT_IS_WEB_VIEW(webView));
861
862     Frame* frame = core(webkit_web_view_get_main_frame(webView));
863     frame->loader()->goBackOrForward(1);
864 }
865
866 gboolean webkit_web_view_can_go_backward(WebKitWebView* webView)
867 {
868     g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), FALSE);
869
870     Frame* frame = core(webkit_web_view_get_main_frame(webView));
871     return frame->loader()->canGoBackOrForward(-1);
872 }
873
874 gboolean webkit_web_view_can_go_forward(WebKitWebView* webView)
875 {
876     g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), FALSE);
877
878     Frame* frame = core(webkit_web_view_get_main_frame(webView));
879     return frame->loader()->canGoBackOrForward(1);
880 }
881
882 void webkit_web_view_open(WebKitWebView* webView, const gchar* uri)
883 {
884     g_return_if_fail(WEBKIT_IS_WEB_VIEW(webView));
885
886     Frame* frame = core(webkit_web_view_get_main_frame(webView));
887     DeprecatedString string = DeprecatedString::fromUtf8(uri);
888     frame->loader()->load(ResourceRequest(KURL(string)));
889 }
890
891 void webkit_web_view_reload(WebKitWebView* webView)
892 {
893     g_return_if_fail(WEBKIT_IS_WEB_VIEW(webView));
894
895     Frame* frame = core(webkit_web_view_get_main_frame(webView));
896     frame->loader()->reload();
897 }
898
899 void webkit_web_view_load_string(WebKitWebView* webView, const gchar* content, const gchar* contentMimeType, const gchar* contentEncoding, const gchar* baseUri)
900 {
901     g_return_if_fail(WEBKIT_IS_WEB_VIEW(webView));
902
903     Frame* frame = core(webkit_web_view_get_main_frame(webView));
904
905     KURL url(DeprecatedString::fromUtf8(baseUri));
906     RefPtr<SharedBuffer> sharedBuffer = new SharedBuffer(strdup(content), strlen(content));
907     SubstituteData substituteData(sharedBuffer.release(), String(contentMimeType), String(contentEncoding), KURL("about:blank"), url);
908
909     frame->loader()->load(ResourceRequest(url), substituteData);
910 }
911
912 void webkit_web_view_load_html_string(WebKitWebView* webView, const gchar* content, const gchar* baseUrl)
913 {
914     g_return_if_fail(WEBKIT_IS_WEB_VIEW(webView));
915
916     webkit_web_view_load_string(webView, content, "text/html", "UTF-8", baseUrl);
917 }
918
919 void webkit_web_view_stop_loading(WebKitWebView* webView)
920 {
921     g_return_if_fail(WEBKIT_IS_WEB_VIEW(webView));
922
923     Frame* frame = core(webkit_web_view_get_main_frame(webView));
924
925     if (FrameLoader* loader = frame->loader())
926         loader->stopAllLoaders();
927 }
928
929 WebKitWebFrame* webkit_web_view_get_main_frame(WebKitWebView* webView)
930 {
931     g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), NULL);
932
933     WebKitWebViewPrivate* webViewData = WEBKIT_WEB_VIEW_GET_PRIVATE(webView);
934     return webViewData->mainFrame;
935 }
936
937 void webkit_web_view_execute_script(WebKitWebView* webView, const gchar* script)
938 {
939     g_return_if_fail(WEBKIT_IS_WEB_VIEW(webView));
940     g_return_if_fail(script);
941
942     Frame* frame = core(webkit_web_view_get_main_frame(webView));
943     if (FrameLoader* loader = frame->loader())
944         loader->executeScript(String::fromUTF8(script), true);
945 }
946
947 /**
948  * webkit_web_view_get_editable:
949  * @web_view: a #WebKitWebView
950  *
951  * Returns whether the user is allowed to edit the document.
952  *
953  * Returns %TRUE if @web_view allows the user to edit the HTML document, %FALSE if
954  * it doesn't. You can change @web_view's document programmatically regardless of
955  * this setting.
956  *
957  * Return value: a #gboolean indicating the editable state
958  */
959 gboolean webkit_web_view_get_editable(WebKitWebView* webView)
960 {
961     g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), FALSE);
962
963     WebKitWebViewPrivate* webViewData = WEBKIT_WEB_VIEW_GET_PRIVATE(webView);
964     ASSERT(webViewData);
965
966     return webViewData->editable;
967 }
968
969 /**
970  * webkit_web_view_set_editable:
971  * @web_view: a #WebKitWebView
972  * @flag: a #gboolean indicating the editable state
973  *
974  * Sets whether @web_view allows the user to edit its HTML document.
975  *
976  * If @flag is %TRUE, @web_view allows the user to edit the document. If @flag is
977  * %FALSE, an element in @web_view's document can only be edited if the
978  * CONTENTEDITABLE attribute has been set on the element or one of its parent
979  * elements. You can change @web_view's document programmatically regardless of
980  * this setting. By default a #WebKitWebView is not editable.
981
982  * Normally, an HTML document is not editable unless the elements within the
983  * document are editable. This function provides a low-level way to make the
984  * contents of a #WebKitWebView editable without altering the document or DOM
985  * structure.
986  */
987 void webkit_web_view_set_editable(WebKitWebView* webView, gboolean flag)
988 {
989     g_return_if_fail(WEBKIT_IS_WEB_VIEW(webView));
990     flag = flag != FALSE;
991
992     WebKitWebViewPrivate* webViewData = WEBKIT_WEB_VIEW_GET_PRIVATE(webView);
993     ASSERT(webViewData);
994
995     Frame* mainFrame = core(webViewData->mainFrame);
996     g_return_if_fail(mainFrame);
997
998     // TODO: What happens when the frame is replaced?
999     if (flag == webViewData->editable)
1000         return;
1001
1002     webViewData->editable = flag;
1003
1004     if (flag) {
1005         mainFrame->applyEditingStyleToBodyElement();
1006         // TODO: If the WebKitWebView is made editable and the selection is empty, set it to something.
1007         //if (!webkit_web_view_get_selected_dom_range(webView))
1008         //    mainFrame->setSelectionFromNone();
1009     } else
1010         mainFrame->removeEditingStyleFromBodyElement();
1011 }
1012
1013 }