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