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