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