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