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