2008-01-22 Christian Dywan <christian@imendio.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  *  This library is free software; you can redistribute it and/or
8  *  modify it under the terms of the GNU Lesser General Public
9  *  License as published by the Free Software Foundation; either
10  *  version 2 of the License, or (at your option) any later version.
11  *
12  *  This library is distributed in the hope that it will be useful,
13  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  *  Lesser General Public License for more details.
16  *
17  *  You should have received a copy of the GNU Lesser General Public
18  *  License along with this library; if not, write to the Free Software
19  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
20  */
21
22 #include "config.h"
23
24 #include "webkitwebview.h"
25 #include "webkit-marshal.h"
26 #include "webkitprivate.h"
27
28 #include "NotImplemented.h"
29 #include "CString.h"
30 #include "ChromeClientGtk.h"
31 #include "ContextMenu.h"
32 #include "ContextMenuClientGtk.h"
33 #include "ContextMenuController.h"
34 #include "Cursor.h"
35 #include "DragClientGtk.h"
36 #include "Editor.h"
37 #include "EditorClientGtk.h"
38 #include "EventHandler.h"
39 #include "FocusController.h"
40 #include "HitTestRequest.h"
41 #include "HitTestResult.h"
42 #include "GraphicsContext.h"
43 #include "InspectorClientGtk.h"
44 #include "FrameLoader.h"
45 #include "FrameView.h"
46 #include "Editor.h"
47 #include "PasteboardHelper.h"
48 #include "PlatformKeyboardEvent.h"
49 #include "PlatformWheelEvent.h"
50 #include "SubstituteData.h"
51
52 #include <gdk/gdkkeysyms.h>
53
54 using namespace WebKit;
55 using namespace WebCore;
56
57 extern "C" {
58
59 enum {
60     /* normal signals */
61     NAVIGATION_REQUESTED,
62     WINDOW_OBJECT_CLEARED,
63     LOAD_STARTED,
64     LOAD_COMMITTED,
65     LOAD_PROGRESS_CHANGED,
66     LOAD_FINISHED,
67     TITLE_CHANGED,
68     HOVERING_OVER_LINK,
69     STATUS_BAR_TEXT_CHANGED,
70     ICOND_LOADED,
71     SELECTION_CHANGED,
72     CONSOLE_MESSAGE,
73     SCRIPT_ALERT,
74     SCRIPT_CONFIRM,
75     SCRIPT_PROMPT,
76     SELECT_ALL,
77     COPY_CLIPBOARD,
78     PASTE_CLIPBOARD,
79     CUT_CLIPBOARD,
80     LAST_SIGNAL
81 };
82
83 enum {
84     PROP_0,
85
86     PROP_COPY_TARGET_LIST,
87     PROP_PASTE_TARGET_LIST,
88     PROP_EDITABLE,
89     PROP_SETTINGS
90 };
91
92 static guint webkit_web_view_signals[LAST_SIGNAL] = { 0, };
93
94 G_DEFINE_TYPE(WebKitWebView, webkit_web_view, GTK_TYPE_CONTAINER)
95
96 static void webkit_web_view_context_menu_position_func(GtkMenu*, gint* x, gint* y, gboolean* pushIn, WebKitWebViewPrivate* data)
97 {
98     *pushIn = FALSE;
99     *x = data->lastPopupXPosition;
100     *y = data->lastPopupYPosition;
101 }
102
103 static gboolean webkit_web_view_forward_context_menu_event(WebKitWebView* webView, const PlatformMouseEvent& event)
104 {
105     Page* page = core(webView);
106     page->contextMenuController()->clearContextMenu();
107     Frame* focusedFrame = page->focusController()->focusedOrMainFrame();
108     focusedFrame->view()->setCursor(pointerCursor());
109     bool handledEvent = focusedFrame->eventHandler()->sendContextMenuEvent(event);
110     if (!handledEvent)
111         return FALSE;
112
113     ContextMenu* coreMenu = page->contextMenuController()->contextMenu();
114     if (!coreMenu)
115         return FALSE;
116
117     if (!coreMenu->platformDescription())
118         return FALSE;
119
120
121     WebKitWebViewPrivate* pageData = WEBKIT_WEB_VIEW_GET_PRIVATE(webView);
122     pageData->lastPopupXPosition = event.globalX();
123     pageData->lastPopupYPosition = event.globalY();
124     gtk_menu_popup(GTK_MENU(coreMenu->platformDescription()), NULL, NULL,
125                    reinterpret_cast<GtkMenuPositionFunc>(webkit_web_view_context_menu_position_func), pageData,
126                    event.button() + 1, gtk_get_current_event_time());
127     return TRUE;
128 }
129
130 static gboolean webkit_web_view_popup_menu_handler(GtkWidget* widget)
131 {
132     static const int contextMenuMargin = 1;
133
134     // The context menu event was generated from the keyboard, so show the context menu by the current selection.
135     Page* page = core(WEBKIT_WEB_VIEW(widget));
136     FrameView* view = page->mainFrame()->view();
137     Position start = page->mainFrame()->selectionController()->selection().start();
138     Position end = page->mainFrame()->selectionController()->selection().end();
139
140     int rightAligned = FALSE;
141     IntPoint location;
142
143     if (!start.node() || !end.node())
144         location = IntPoint(rightAligned ? view->contentsWidth() - contextMenuMargin : contextMenuMargin, contextMenuMargin);
145     else {
146         RenderObject* renderer = start.node()->renderer();
147         if (!renderer)
148             return FALSE;
149
150         // Calculate the rect of the first line of the selection (cribbed from -[WebCoreFrameBridge firstRectForDOMRange:]).
151         int extraWidthToEndOfLine = 0;
152         IntRect startCaretRect = renderer->caretRect(start.offset(), DOWNSTREAM, &extraWidthToEndOfLine);
153         IntRect endCaretRect = renderer->caretRect(end.offset(), UPSTREAM);
154
155         IntRect firstRect;
156         if (startCaretRect.y() == endCaretRect.y())
157             firstRect = IntRect(MIN(startCaretRect.x(), endCaretRect.x()),
158                                 startCaretRect.y(),
159                                 abs(endCaretRect.x() - startCaretRect.x()),
160                                 MAX(startCaretRect.height(), endCaretRect.height()));
161         else
162             firstRect = IntRect(startCaretRect.x(),
163                                 startCaretRect.y(),
164                                 startCaretRect.width() + extraWidthToEndOfLine,
165                                 startCaretRect.height());
166
167         location = IntPoint(rightAligned ? firstRect.right() : firstRect.x(), firstRect.bottom());
168     }
169
170     int x, y;
171     gdk_window_get_origin(GTK_WIDGET(view->containingWindow())->window, &x, &y);
172
173     // FIXME: The IntSize(0, -1) is a hack to get the hit-testing to result in the selected element.
174     // Ideally we'd have the position of a context menu event be separate from its target node.
175     location = view->contentsToWindow(location) + IntSize(0, -1);
176     IntPoint global = location + IntSize(x, y);
177     PlatformMouseEvent event(location, global, NoButton, MouseEventPressed, 0, false, false, false, false, gtk_get_current_event_time());
178
179     return webkit_web_view_forward_context_menu_event(WEBKIT_WEB_VIEW(widget), event);
180 }
181
182 static void webkit_web_view_get_property(GObject* object, guint prop_id, GValue* value, GParamSpec* pspec)
183 {
184     WebKitWebView* webView = WEBKIT_WEB_VIEW(object);
185
186     switch(prop_id) {
187     case PROP_COPY_TARGET_LIST:
188         g_value_set_boxed(value, webkit_web_view_get_copy_target_list(webView));
189         break;
190     case PROP_PASTE_TARGET_LIST:
191         g_value_set_boxed(value, webkit_web_view_get_paste_target_list(webView));
192         break;
193     case PROP_EDITABLE:
194         g_value_set_boolean(value, webkit_web_view_get_editable(webView));
195         break;
196     case PROP_SETTINGS:
197         g_value_set_object(value, webkit_web_view_get_settings(webView));
198         break;
199     default:
200         G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
201     }
202 }
203
204 static void webkit_web_view_set_property(GObject* object, guint prop_id, const GValue* value, GParamSpec *pspec)
205 {
206     WebKitWebView* webView = WEBKIT_WEB_VIEW(object);
207
208     switch(prop_id) {
209     case PROP_EDITABLE:
210         webkit_web_view_set_editable(webView, g_value_get_boolean(value));
211         break;
212     case PROP_SETTINGS:
213         webkit_web_view_set_settings(webView, WEBKIT_WEB_SETTINGS(g_value_get_object(value)));
214         break;
215     default:
216         G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
217     }
218 }
219
220 static gboolean webkit_web_view_expose_event(GtkWidget* widget, GdkEventExpose* event)
221 {
222     Frame* frame = core(webkit_web_view_get_main_frame(WEBKIT_WEB_VIEW(widget)));
223     GdkRectangle clip;
224     gdk_region_get_clipbox(event->region, &clip);
225     cairo_t* cr = gdk_cairo_create(event->window);
226     GraphicsContext ctx(cr);
227     ctx.setGdkExposeEvent(event);
228     if (frame->renderer()) {
229         frame->view()->layoutIfNeededRecursive();
230         frame->view()->paint(&ctx, clip);
231     }
232     cairo_destroy(cr);
233
234     return FALSE;
235 }
236
237 static gboolean webkit_web_view_key_press_event(GtkWidget* widget, GdkEventKey* event)
238 {
239     Frame* frame = core(WEBKIT_WEB_VIEW(widget))->focusController()->focusedOrMainFrame();
240     PlatformKeyboardEvent keyboardEvent(event);
241
242     if (frame->eventHandler()->keyEvent(keyboardEvent))
243         return TRUE;
244
245     FrameView* view = frame->view();
246     SelectionController::EAlteration alteration;
247     if (event->state & GDK_SHIFT_MASK)
248         alteration = SelectionController::EXTEND;
249     else
250         alteration = SelectionController::MOVE;
251
252     // TODO: We probably want to use GTK+ key bindings here and perhaps take an
253     // approach more like the Win and Mac ports for key handling.
254     switch (event->keyval) {
255     case GDK_Down:
256         view->scrollBy(0, LINE_STEP);
257         return TRUE;
258     case GDK_Up:
259         view->scrollBy(0, -LINE_STEP);
260         return TRUE;
261     case GDK_Right:
262         view->scrollBy(LINE_STEP, 0);
263         return TRUE;
264     case GDK_Left:
265         view->scrollBy(-LINE_STEP, 0);
266         return TRUE;
267     case GDK_Home:
268         frame->selectionController()->modify(alteration, SelectionController::BACKWARD, DocumentBoundary, true);
269         return TRUE;
270     case GDK_End:
271         frame->selectionController()->modify(alteration, SelectionController::FORWARD, DocumentBoundary, true);
272         return TRUE;
273     }
274
275     /* Chain up to our parent class for binding activation */
276     return GTK_WIDGET_CLASS(webkit_web_view_parent_class)->key_press_event(widget, event);
277 }
278
279 static gboolean webkit_web_view_key_release_event(GtkWidget* widget, GdkEventKey* event)
280 {
281     Frame* frame = core(WEBKIT_WEB_VIEW(widget))->focusController()->focusedOrMainFrame();
282     PlatformKeyboardEvent keyboardEvent(event);
283
284     if (frame->eventHandler()->keyEvent(keyboardEvent))
285         return TRUE;
286
287     /* Chain up to our parent class for binding activation */
288     return GTK_WIDGET_CLASS(webkit_web_view_parent_class)->key_release_event(widget, event);
289 }
290
291 static gboolean webkit_web_view_button_press_event(GtkWidget* widget, GdkEventButton* event)
292 {
293     Frame* frame = core(webkit_web_view_get_main_frame(WEBKIT_WEB_VIEW(widget)));
294
295     // FIXME: need to keep track of subframe focus for key events
296     gtk_widget_grab_focus(GTK_WIDGET(widget));
297
298     if (event->button == 3)
299         return webkit_web_view_forward_context_menu_event(WEBKIT_WEB_VIEW(widget), PlatformMouseEvent(event));
300
301     return frame->eventHandler()->handleMousePressEvent(PlatformMouseEvent(event));
302 }
303
304 static gboolean webkit_web_view_button_release_event(GtkWidget* widget, GdkEventButton* event)
305 {
306     Frame* frame = core(webkit_web_view_get_main_frame(WEBKIT_WEB_VIEW(widget)));
307
308     WebKitWebView* web_view = WEBKIT_WEB_VIEW(widget);
309     WebKitWebViewPrivate* webViewData = WEBKIT_WEB_VIEW_GET_PRIVATE(web_view);
310     Frame* focusedFrame = webViewData->corePage->focusController()->focusedFrame();
311
312     if (focusedFrame->editor()->canEdit()) {
313         GdkWindow* window = gtk_widget_get_parent_window(widget);
314         gtk_im_context_set_client_window(webViewData->imContext, window);
315 #ifdef MAEMO_CHANGES
316         hildon_gtk_im_context_filter_event(webViewData->imContext, (GdkEvent*)event);
317         hildon_gtk_im_context_show(webViewData->imContext);
318 #endif
319     }
320
321     return frame->eventHandler()->handleMouseReleaseEvent(PlatformMouseEvent(event));
322 }
323
324 static gboolean webkit_web_view_motion_event(GtkWidget* widget, GdkEventMotion* event)
325 {
326     Frame* frame = core(webkit_web_view_get_main_frame(WEBKIT_WEB_VIEW(widget)));
327     return frame->eventHandler()->mouseMoved(PlatformMouseEvent(event));
328 }
329
330 static gboolean webkit_web_view_scroll_event(GtkWidget* widget, GdkEventScroll* event)
331 {
332     Frame* frame = core(webkit_web_view_get_main_frame(WEBKIT_WEB_VIEW(widget)));
333     PlatformWheelEvent wheelEvent(event);
334     return frame->eventHandler()->handleWheelEvent(wheelEvent);
335 }
336
337 static void webkit_web_view_size_allocate(GtkWidget* widget, GtkAllocation* allocation)
338 {
339     GTK_WIDGET_CLASS(webkit_web_view_parent_class)->size_allocate(widget,allocation);
340
341     Frame* frame = core(webkit_web_view_get_main_frame(WEBKIT_WEB_VIEW(widget)));
342     frame->view()->resize(allocation->width, allocation->height);
343     frame->forceLayout();
344     frame->view()->adjustViewSize();
345 }
346
347 static gboolean webkit_web_view_focus_in_event(GtkWidget* widget, GdkEventFocus* event)
348 {
349     // TODO: Improve focus handling as suggested in
350     // http://bugs.webkit.org/show_bug.cgi?id=16910
351     GtkWidget* toplevel = gtk_widget_get_toplevel(widget);
352     if (GTK_WIDGET_TOPLEVEL(toplevel) && gtk_window_has_toplevel_focus(GTK_WINDOW(toplevel))) {
353         WebKitWebView* webView = WEBKIT_WEB_VIEW(widget);
354         Frame* frame = core(webkit_web_view_get_main_frame(webView));
355         core(webView)->focusController()->setActive(frame);
356     }
357     return GTK_WIDGET_CLASS(webkit_web_view_parent_class)->focus_in_event(widget, event);
358 }
359
360 static void webkit_web_view_realize(GtkWidget* widget)
361 {
362     GTK_WIDGET_SET_FLAGS(widget, GTK_REALIZED);
363
364     GdkWindowAttr attributes;
365     attributes.window_type = GDK_WINDOW_CHILD;
366     attributes.x = widget->allocation.x;
367     attributes.y = widget->allocation.y;
368     attributes.width = widget->allocation.width;
369     attributes.height = widget->allocation.height;
370     attributes.wclass = GDK_INPUT_OUTPUT;
371     attributes.visual = gtk_widget_get_visual (widget);
372     attributes.colormap = gtk_widget_get_colormap (widget);
373     attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK
374                             | GDK_EXPOSURE_MASK
375                             | GDK_BUTTON_PRESS_MASK
376                             | GDK_BUTTON_RELEASE_MASK
377                             | GDK_POINTER_MOTION_MASK
378                             | GDK_KEY_PRESS_MASK
379                             | GDK_KEY_RELEASE_MASK
380                             | GDK_BUTTON_MOTION_MASK
381                             | GDK_BUTTON1_MOTION_MASK
382                             | GDK_BUTTON2_MOTION_MASK
383                             | GDK_BUTTON3_MOTION_MASK;
384
385     gint attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
386     widget->window = gdk_window_new(gtk_widget_get_parent_window (widget), &attributes, attributes_mask);
387     gdk_window_set_user_data(widget->window, widget);
388
389     widget->style = gtk_style_attach(widget->style, widget->window);
390     gdk_window_set_background(widget->window, &widget->style->base[GTK_WIDGET_STATE(widget)]);
391 }
392
393 static void webkit_web_view_set_scroll_adjustments(WebKitWebView* webView, GtkAdjustment* hadj, GtkAdjustment* vadj)
394 {
395     FrameView* view = core(webkit_web_view_get_main_frame(webView))->view();
396     view->setGtkAdjustments(hadj, vadj);
397 }
398
399 static void webkit_web_view_container_add(GtkContainer* container, GtkWidget* widget)
400 {
401     WebKitWebView* webView = WEBKIT_WEB_VIEW(container);
402     WebKitWebViewPrivate* private_data = WEBKIT_WEB_VIEW_GET_PRIVATE(webView);
403
404     private_data->children.add(widget);
405     if (GTK_WIDGET_REALIZED(container))
406         gtk_widget_set_parent_window(widget, GTK_WIDGET(webView)->window);
407     gtk_widget_set_parent(widget, GTK_WIDGET(container));
408 }
409
410 static void webkit_web_view_container_remove(GtkContainer* container, GtkWidget* widget)
411 {
412     WebKitWebViewPrivate* private_data = WEBKIT_WEB_VIEW_GET_PRIVATE(WEBKIT_WEB_VIEW(container));
413
414     if (private_data->children.contains(widget)) {
415         gtk_widget_unparent(widget);
416         private_data->children.remove(widget);
417     }
418 }
419
420 static void webkit_web_view_container_forall(GtkContainer* container, gboolean, GtkCallback callback, gpointer callbackData)
421 {
422     WebKitWebViewPrivate* privateData = WEBKIT_WEB_VIEW_GET_PRIVATE(WEBKIT_WEB_VIEW(container));
423
424     HashSet<GtkWidget*> children = privateData->children;
425     HashSet<GtkWidget*>::const_iterator end = children.end();
426     for (HashSet<GtkWidget*>::const_iterator current = children.begin(); current != end; ++current)
427         (*callback)(*current, callbackData);
428 }
429
430 static WebKitWebView* webkit_web_view_real_create_web_view(WebKitWebView*)
431 {
432     notImplemented();
433     return 0;
434 }
435
436 static WebKitNavigationResponse webkit_web_view_real_navigation_requested(WebKitWebView*, WebKitWebFrame* frame, WebKitNetworkRequest*)
437 {
438     notImplemented();
439     return WEBKIT_NAVIGATION_RESPONSE_ACCEPT;
440 }
441
442 static void webkit_web_view_real_window_object_cleared(WebKitWebView*, WebKitWebFrame*, JSGlobalContextRef context, JSObjectRef window_object)
443 {
444     notImplemented();
445 }
446
447 static gchar* webkit_web_view_real_choose_file(WebKitWebView*, WebKitWebFrame*, const gchar* old_name)
448 {
449     notImplemented();
450     return g_strdup(old_name);
451 }
452
453 typedef enum {
454     WEBKIT_SCRIPT_DIALOG_ALERT,
455     WEBKIT_SCRIPT_DIALOG_CONFIRM,
456     WEBKIT_SCRIPT_DIALOG_PROMPT
457  } WebKitScriptDialogType;
458
459 static gboolean webkit_web_view_script_dialog(WebKitWebView* webView, WebKitWebFrame* frame, const gchar* message, WebKitScriptDialogType type, const gchar* defaultValue, gchar** value)
460 {
461     GtkMessageType messageType;
462     GtkButtonsType buttons;
463     gint defaultResponse;
464     GtkWidget* window;
465     GtkWidget* dialog;
466     GtkWidget* entry = 0;
467     gboolean didConfirm = FALSE;
468
469     switch (type) {
470     case WEBKIT_SCRIPT_DIALOG_ALERT:
471         messageType = GTK_MESSAGE_WARNING;
472         buttons = GTK_BUTTONS_CLOSE;
473         defaultResponse = GTK_RESPONSE_CLOSE;
474         break;
475     case WEBKIT_SCRIPT_DIALOG_CONFIRM:
476         messageType = GTK_MESSAGE_QUESTION;
477         buttons = GTK_BUTTONS_YES_NO;
478         defaultResponse = GTK_RESPONSE_YES;
479         break;
480     case WEBKIT_SCRIPT_DIALOG_PROMPT:
481         messageType = GTK_MESSAGE_QUESTION;
482         buttons = GTK_BUTTONS_OK_CANCEL;
483         defaultResponse = GTK_RESPONSE_OK;
484         break;
485     default:
486         g_warning("Unknown value for WebKitScriptDialogType.");
487         return FALSE;
488     }
489
490     window = gtk_widget_get_toplevel(GTK_WIDGET(webView));
491     dialog = gtk_message_dialog_new(GTK_WIDGET_TOPLEVEL(window) ? GTK_WINDOW(window) : 0, GTK_DIALOG_DESTROY_WITH_PARENT, messageType, buttons, "%s", message);
492     gchar* title = g_strconcat("JavaScript - ", webkit_web_frame_get_uri(frame), NULL);
493     gtk_window_set_title(GTK_WINDOW(dialog), title);
494     g_free(title);
495
496     if (type == WEBKIT_SCRIPT_DIALOG_PROMPT) {
497         entry = gtk_entry_new();
498         gtk_entry_set_text(GTK_ENTRY(entry), defaultValue);
499         gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), entry);
500         gtk_entry_set_activates_default(GTK_ENTRY(entry), TRUE);
501         gtk_widget_show(entry);
502     }
503
504     gtk_dialog_set_default_response(GTK_DIALOG(dialog), defaultResponse);
505     gint response = gtk_dialog_run(GTK_DIALOG(dialog));
506
507     switch (response) {
508     case GTK_RESPONSE_YES:
509         didConfirm = TRUE;
510         break;
511     case GTK_RESPONSE_OK:
512         didConfirm = TRUE;
513         if (entry)
514             *value = g_strdup(gtk_entry_get_text(GTK_ENTRY(entry)));
515         else
516             *value = 0;
517         break;
518     case GTK_RESPONSE_NO:
519     case GTK_RESPONSE_CANCEL:
520         didConfirm = FALSE;
521         break;
522
523     }
524     gtk_widget_destroy(GTK_WIDGET(dialog));
525     return didConfirm;
526 }
527
528 static gboolean webkit_web_view_real_script_alert(WebKitWebView* webView, WebKitWebFrame* frame, const gchar* message)
529 {
530     webkit_web_view_script_dialog(webView, frame, message, WEBKIT_SCRIPT_DIALOG_ALERT, 0, 0);
531     return TRUE;
532 }
533
534 static gboolean webkit_web_view_real_script_confirm(WebKitWebView* webView, WebKitWebFrame* frame, const gchar* message, gboolean* didConfirm)
535 {
536     *didConfirm = webkit_web_view_script_dialog(webView, frame, message, WEBKIT_SCRIPT_DIALOG_CONFIRM, 0, 0);
537     return TRUE;
538 }
539
540 static gboolean webkit_web_view_real_script_prompt(WebKitWebView* webView, WebKitWebFrame* frame, const gchar* message, const gchar* defaultValue, gchar** value)
541 {
542     if (!webkit_web_view_script_dialog(webView, frame, message, WEBKIT_SCRIPT_DIALOG_PROMPT, defaultValue, value))
543         *value = NULL;
544     return TRUE;
545 }
546
547 static gboolean webkit_web_view_real_console_message(WebKitWebView* webView, const gchar* message, unsigned int line, const gchar* sourceId)
548 {
549     g_print("console message: %s @%d: %s\n", sourceId, line, message);
550     return TRUE;
551 }
552
553 static void webkit_web_view_real_select_all(WebKitWebView* webView)
554 {
555     Frame* frame = core(webView)->focusController()->focusedOrMainFrame();
556     frame->editor()->command("SelectAll").execute();
557 }
558
559 static void webkit_web_view_real_cut_clipboard(WebKitWebView* webView)
560 {
561     Frame* frame = core(webView)->focusController()->focusedOrMainFrame();
562     frame->editor()->command("Cut").execute();
563 }
564
565 static void webkit_web_view_real_copy_clipboard(WebKitWebView* webView)
566 {
567     Frame* frame = core(webView)->focusController()->focusedOrMainFrame();
568     frame->editor()->command("Copy").execute();
569 }
570
571 static void webkit_web_view_real_paste_clipboard(WebKitWebView* webView)
572 {
573     Frame* frame = core(webView)->focusController()->focusedOrMainFrame();
574     frame->editor()->command("Paste").execute();
575 }
576
577 static void webkit_web_view_finalize(GObject* object)
578 {
579     webkit_web_view_stop_loading(WEBKIT_WEB_VIEW(object));
580
581     WebKitWebViewPrivate* webViewData = WEBKIT_WEB_VIEW_GET_PRIVATE(WEBKIT_WEB_VIEW(object));
582     delete webViewData->corePage;
583     g_object_unref(webViewData->webSettings);
584     g_object_unref(webViewData->mainFrame);
585     g_object_unref(webViewData->imContext);
586     gtk_target_list_unref(webViewData->copy_target_list);
587     gtk_target_list_unref(webViewData->paste_target_list);
588     delete webViewData->userAgent;
589
590     G_OBJECT_CLASS(webkit_web_view_parent_class)->finalize(object);
591 }
592
593 static gboolean webkit_navigation_request_handled(GSignalInvocationHint* ihint, GValue* returnAccu, const GValue* handlerReturn, gpointer dummy)
594 {
595   gboolean continueEmission = TRUE;
596   int signalHandled = g_value_get_int(handlerReturn);
597   g_value_set_int(returnAccu, signalHandled);
598
599   if (signalHandled != WEBKIT_NAVIGATION_RESPONSE_ACCEPT)
600       continueEmission = FALSE;
601
602   return continueEmission;
603 }
604
605 static void webkit_web_view_class_init(WebKitWebViewClass* webViewClass)
606 {
607     GtkBindingSet* binding_set;
608
609     webkit_init();
610
611     g_type_class_add_private(webViewClass, sizeof(WebKitWebViewPrivate));
612
613     /*
614      * Signals
615      */
616
617     webkit_web_view_signals[NAVIGATION_REQUESTED] = g_signal_new("navigation-requested",
618             G_TYPE_FROM_CLASS(webViewClass),
619             (GSignalFlags)(G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION),
620             G_STRUCT_OFFSET (WebKitWebViewClass, navigation_requested),
621             webkit_navigation_request_handled,
622             NULL,
623             webkit_marshal_INT__OBJECT_OBJECT,
624             G_TYPE_INT, 2,
625             G_TYPE_OBJECT,
626             G_TYPE_OBJECT);
627
628     /**
629      * WebKitWebView::window-object-cleared:
630      * @web_view: the object on which the signal is emitted
631      * @frame: the #WebKitWebFrame to which @window_object belongs
632      * @context: the #JSGlobalContextRef holding the global object and other
633      * execution state; equivalent to the return value of
634      * webkit_web_frame_get_global_context(@frame)
635      *
636      * @window_object: the #JSObjectRef representing the frame's JavaScript
637      * window object
638      *
639      * Emitted when the JavaScript window object in a #WebKitWebFrame has been
640      * cleared in preparation for a new load. This is the preferred place to
641      * set custom properties on the window object using the JavaScriptCore API.
642      */
643     webkit_web_view_signals[WINDOW_OBJECT_CLEARED] = g_signal_new("window-object-cleared",
644             G_TYPE_FROM_CLASS(webViewClass),
645             (GSignalFlags)(G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION),
646             G_STRUCT_OFFSET (WebKitWebViewClass, window_object_cleared),
647             NULL,
648             NULL,
649             webkit_marshal_VOID__OBJECT_POINTER_POINTER,
650             G_TYPE_NONE, 3,
651             WEBKIT_TYPE_WEB_FRAME,
652             G_TYPE_POINTER,
653             G_TYPE_POINTER);
654
655     /**
656      * WebKitWebView::load-started:
657      * @web_view: the object on which the signal is emitted
658      * @frame: the frame going to do the load
659      *
660      * When a #WebKitWebFrame begins to load this signal is emitted.
661      */
662     webkit_web_view_signals[LOAD_STARTED] = g_signal_new("load-started",
663             G_TYPE_FROM_CLASS(webViewClass),
664             (GSignalFlags)(G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION),
665             0,
666             NULL,
667             NULL,
668             g_cclosure_marshal_VOID__OBJECT,
669             G_TYPE_NONE, 1,
670             WEBKIT_TYPE_WEB_FRAME);
671
672     /**
673      * WebKitWebView::load-committed:
674      * @web_view: the object on which the signal is emitted
675      * @frame: the main frame that received the first data
676      *
677      * When a #WebKitWebFrame loaded the first data this signal is emitted.
678      */
679     webkit_web_view_signals[LOAD_COMMITTED] = g_signal_new("load-committed",
680             G_TYPE_FROM_CLASS(webViewClass),
681             (GSignalFlags)(G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION),
682             0,
683             NULL,
684             NULL,
685             g_cclosure_marshal_VOID__OBJECT,
686             G_TYPE_NONE, 1,
687             WEBKIT_TYPE_WEB_FRAME);
688
689
690     /**
691      * WebKitWebView::load-progress-changed:
692      * @web_view: the #WebKitWebView
693      * @progress: the global progress
694      */
695     webkit_web_view_signals[LOAD_PROGRESS_CHANGED] = g_signal_new("load-progress-changed",
696             G_TYPE_FROM_CLASS(webViewClass),
697             (GSignalFlags)(G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION),
698             0,
699             NULL,
700             NULL,
701             g_cclosure_marshal_VOID__INT,
702             G_TYPE_NONE, 1,
703             G_TYPE_INT);
704
705     webkit_web_view_signals[LOAD_FINISHED] = g_signal_new("load-finished",
706             G_TYPE_FROM_CLASS(webViewClass),
707             (GSignalFlags)(G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION),
708             0,
709             NULL,
710             NULL,
711             g_cclosure_marshal_VOID__OBJECT,
712             G_TYPE_NONE, 1,
713             WEBKIT_TYPE_WEB_FRAME);
714
715     /**
716      * WebKitWebView::title-changed:
717      * @web_view: the object on which the signal is emitted
718      * @frame: the main frame
719      * @title: the new title
720      *
721      * When a #WebKitWebFrame changes the document title this signal is emitted.
722      */
723     webkit_web_view_signals[TITLE_CHANGED] = g_signal_new("title-changed",
724             G_TYPE_FROM_CLASS(webViewClass),
725             (GSignalFlags)(G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION),
726             0,
727             NULL,
728             NULL,
729             webkit_marshal_VOID__OBJECT_STRING,
730             G_TYPE_NONE, 2,
731             WEBKIT_TYPE_WEB_FRAME,
732             G_TYPE_STRING);
733
734     webkit_web_view_signals[HOVERING_OVER_LINK] = g_signal_new("hovering-over-link",
735             G_TYPE_FROM_CLASS(webViewClass),
736             (GSignalFlags)(G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION),
737             0,
738             NULL,
739             NULL,
740             webkit_marshal_VOID__STRING_STRING,
741             G_TYPE_NONE, 2,
742             G_TYPE_STRING,
743             G_TYPE_STRING);
744
745     webkit_web_view_signals[STATUS_BAR_TEXT_CHANGED] = g_signal_new("status-bar-text-changed",
746             G_TYPE_FROM_CLASS(webViewClass),
747             (GSignalFlags)(G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION),
748             0,
749             NULL,
750             NULL,
751             g_cclosure_marshal_VOID__STRING,
752             G_TYPE_NONE, 1,
753             G_TYPE_STRING);
754
755     webkit_web_view_signals[ICOND_LOADED] = g_signal_new("icon-loaded",
756             G_TYPE_FROM_CLASS(webViewClass),
757             (GSignalFlags)(G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION),
758             0,
759             NULL,
760             NULL,
761             g_cclosure_marshal_VOID__VOID,
762             G_TYPE_NONE, 0);
763
764     webkit_web_view_signals[SELECTION_CHANGED] = g_signal_new("selection-changed",
765             G_TYPE_FROM_CLASS(webViewClass),
766             (GSignalFlags)(G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION),
767             0,
768             NULL,
769             NULL,
770             g_cclosure_marshal_VOID__VOID,
771             G_TYPE_NONE, 0);
772
773     /**
774      * WebKitWebView::console-message:
775      * @web_view: the object on which the signal is emitted
776      * @message: the message text
777      * @line: the line where the error occured
778      * @source_id: the source id
779      * @return: TRUE to stop other handlers from being invoked for the event. FALSE to propagate the event further.
780      *
781      * A JavaScript console message was created.
782      */
783     webkit_web_view_signals[CONSOLE_MESSAGE] = g_signal_new("console-message",
784             G_TYPE_FROM_CLASS(webViewClass),
785             (GSignalFlags)(G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION),
786             G_STRUCT_OFFSET(WebKitWebViewClass, console_message),
787             g_signal_accumulator_true_handled,
788             NULL,
789             webkit_marshal_BOOLEAN__STRING_INT_STRING,
790             G_TYPE_BOOLEAN, 3,
791             G_TYPE_STRING, G_TYPE_INT, G_TYPE_STRING);
792
793     /**
794      * WebKitWebView::script-alert:
795      * @web_view: the object on which the signal is emitted
796      * @frame: the relevant frame
797      * @message: the message text
798      * @return: TRUE to stop other handlers from being invoked for the event. FALSE to propagate the event further.
799      *
800      * A JavaScript alert dialog was created.
801      */
802     webkit_web_view_signals[SCRIPT_ALERT] = g_signal_new("script-alert",
803             G_TYPE_FROM_CLASS(webViewClass),
804             (GSignalFlags)(G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION),
805             G_STRUCT_OFFSET(WebKitWebViewClass, script_alert),
806             g_signal_accumulator_true_handled,
807             NULL,
808             webkit_marshal_BOOLEAN__OBJECT_STRING,
809             G_TYPE_BOOLEAN, 2,
810             G_TYPE_OBJECT, G_TYPE_STRING);
811
812     /**
813      * WebKitWebView::script-confirm:
814      * @web_view: the object on which the signal is emitted
815      * @frame: the relevant frame
816      * @message: the message text
817      * @confirmed: whether the dialog has been confirmed
818      * @return: TRUE to stop other handlers from being invoked for the event. FALSE to propagate the event further.
819      *
820      * A JavaScript confirm dialog was created, providing Yes and No buttons.
821      */
822     webkit_web_view_signals[SCRIPT_CONFIRM] = g_signal_new("script-confirm",
823             G_TYPE_FROM_CLASS(webViewClass),
824             (GSignalFlags)(G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION),
825             G_STRUCT_OFFSET(WebKitWebViewClass, script_confirm),
826             g_signal_accumulator_true_handled,
827             NULL,
828             webkit_marshal_BOOLEAN__OBJECT_STRING_BOOLEAN,
829             G_TYPE_BOOLEAN, 3,
830             G_TYPE_OBJECT, G_TYPE_STRING, G_TYPE_BOOLEAN);
831
832     /**
833      * WebKitWebView::script-prompt:
834      * @web_view: the object on which the signal is emitted
835      * @frame: the relevant frame
836      * @message: the message text
837      * @default: the default value
838      * @text: To be filled with the return value or NULL if the dialog was cancelled.
839      * @return: TRUE to stop other handlers from being invoked for the event. FALSE to propagate the event further.
840      *
841      * A JavaScript prompt dialog was created, providing an entry to input text.
842      */
843     webkit_web_view_signals[SCRIPT_PROMPT] = g_signal_new("script-prompt",
844             G_TYPE_FROM_CLASS(webViewClass),
845             (GSignalFlags)(G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION),
846             G_STRUCT_OFFSET(WebKitWebViewClass, script_prompt),
847             g_signal_accumulator_true_handled,
848             NULL,
849             webkit_marshal_BOOLEAN__OBJECT_STRING_STRING_STRING,
850             G_TYPE_BOOLEAN, 4,
851             G_TYPE_OBJECT, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_POINTER);
852
853     /**
854      * WebKitWebView::select-all:
855      * @web_view: the object which received the signal
856      *
857      * The ::select-all signal is a keybinding signal which gets emitted to
858      * select the complete contents of the text view.
859      *
860      * The default bindings for this signal is Ctrl-a.
861      */
862     webkit_web_view_signals[SELECT_ALL] = g_signal_new("select-all",
863             G_TYPE_FROM_CLASS(webViewClass),
864             (GSignalFlags)(G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION),
865             G_STRUCT_OFFSET(WebKitWebViewClass, select_all),
866             NULL, NULL,
867             g_cclosure_marshal_VOID__VOID,
868             G_TYPE_NONE, 0);
869
870     /**
871      * WebKitWebView::cut-clipboard:
872      * @web_view: the object which received the signal
873      *
874      * The ::cut-clipboard signal is a keybinding signal which gets emitted to
875      * cut the selection to the clipboard.
876      *
877      * The default bindings for this signal are Ctrl-x and Shift-Delete.
878      */
879     webkit_web_view_signals[CUT_CLIPBOARD] = g_signal_new("cut-clipboard",
880             G_TYPE_FROM_CLASS(webViewClass),
881             (GSignalFlags)(G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION),
882             G_STRUCT_OFFSET(WebKitWebViewClass, cut_clipboard),
883             NULL, NULL,
884             g_cclosure_marshal_VOID__VOID,
885             G_TYPE_NONE, 0);
886
887     /**
888      * WebKitWebView::copy-clipboard:
889      * @web_view: the object which received the signal
890      *
891      * The ::copy-clipboard signal is a keybinding signal which gets emitted to
892      * copy the selection to the clipboard.
893      *
894      * The default bindings for this signal are Ctrl-c and Ctrl-Insert.
895      */
896     webkit_web_view_signals[COPY_CLIPBOARD] = g_signal_new("copy-clipboard",
897             G_TYPE_FROM_CLASS(webViewClass),
898             (GSignalFlags)(G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION),
899             G_STRUCT_OFFSET(WebKitWebViewClass, copy_clipboard),
900             NULL, NULL,
901             g_cclosure_marshal_VOID__VOID,
902             G_TYPE_NONE, 0);
903
904     /**
905      * WebKitWebView::paste-clipboard:
906      * @web_view: the object which received the signal
907      *
908      * The ::paste-clipboard signal is a keybinding signal which gets emitted to
909      * paste the contents of the clipboard into the Web view.
910      *
911      * The default bindings for this signal are Ctrl-v and Shift-Insert.
912      */
913     webkit_web_view_signals[PASTE_CLIPBOARD] = g_signal_new("paste-clipboard",
914             G_TYPE_FROM_CLASS(webViewClass),
915             (GSignalFlags)(G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION),
916             G_STRUCT_OFFSET(WebKitWebViewClass, paste_clipboard),
917             NULL, NULL,
918             g_cclosure_marshal_VOID__VOID,
919             G_TYPE_NONE, 0);
920
921     /*
922      * implementations of virtual methods
923      */
924     webViewClass->create_web_view = webkit_web_view_real_create_web_view;
925     webViewClass->navigation_requested = webkit_web_view_real_navigation_requested;
926     webViewClass->window_object_cleared = webkit_web_view_real_window_object_cleared;
927     webViewClass->choose_file = webkit_web_view_real_choose_file;
928     webViewClass->script_alert = webkit_web_view_real_script_alert;
929     webViewClass->script_confirm = webkit_web_view_real_script_confirm;
930     webViewClass->script_prompt = webkit_web_view_real_script_prompt;
931     webViewClass->console_message = webkit_web_view_real_console_message;
932     webViewClass->select_all = webkit_web_view_real_select_all;
933     webViewClass->cut_clipboard = webkit_web_view_real_cut_clipboard;
934     webViewClass->copy_clipboard = webkit_web_view_real_copy_clipboard;
935     webViewClass->paste_clipboard = webkit_web_view_real_paste_clipboard;
936
937     GObjectClass* objectClass = G_OBJECT_CLASS(webViewClass);
938     objectClass->finalize = webkit_web_view_finalize;
939     objectClass->get_property = webkit_web_view_get_property;
940     objectClass->set_property = webkit_web_view_set_property;
941
942     GtkWidgetClass* widgetClass = GTK_WIDGET_CLASS(webViewClass);
943     widgetClass->realize = webkit_web_view_realize;
944     widgetClass->expose_event = webkit_web_view_expose_event;
945     widgetClass->key_press_event = webkit_web_view_key_press_event;
946     widgetClass->key_release_event = webkit_web_view_key_release_event;
947     widgetClass->button_press_event = webkit_web_view_button_press_event;
948     widgetClass->button_release_event = webkit_web_view_button_release_event;
949     widgetClass->motion_notify_event = webkit_web_view_motion_event;
950     widgetClass->scroll_event = webkit_web_view_scroll_event;
951     widgetClass->size_allocate = webkit_web_view_size_allocate;
952     widgetClass->popup_menu = webkit_web_view_popup_menu_handler;
953     widgetClass->focus_in_event = webkit_web_view_focus_in_event;
954
955     GtkContainerClass* containerClass = GTK_CONTAINER_CLASS(webViewClass);
956     containerClass->add = webkit_web_view_container_add;
957     containerClass->remove = webkit_web_view_container_remove;
958     containerClass->forall = webkit_web_view_container_forall;
959
960     /*
961      * make us scrollable (e.g. addable to a GtkScrolledWindow)
962      */
963     webViewClass->set_scroll_adjustments = webkit_web_view_set_scroll_adjustments;
964     GTK_WIDGET_CLASS(webViewClass)->set_scroll_adjustments_signal = g_signal_new("set-scroll-adjustments",
965             G_TYPE_FROM_CLASS(webViewClass),
966             (GSignalFlags)(G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION),
967             G_STRUCT_OFFSET(WebKitWebViewClass, set_scroll_adjustments),
968             NULL, NULL,
969             webkit_marshal_VOID__OBJECT_OBJECT,
970             G_TYPE_NONE, 2,
971             GTK_TYPE_ADJUSTMENT, GTK_TYPE_ADJUSTMENT);
972
973     /*
974      * Key bindings
975      */
976
977     binding_set = gtk_binding_set_by_class(webViewClass);
978
979     gtk_binding_entry_add_signal(binding_set, GDK_a, GDK_CONTROL_MASK,
980                                  "select_all", 0);
981
982     /* Cut/copy/paste */
983
984     gtk_binding_entry_add_signal(binding_set, GDK_x, GDK_CONTROL_MASK,
985                                  "cut_clipboard", 0);
986     gtk_binding_entry_add_signal(binding_set, GDK_c, GDK_CONTROL_MASK,
987                                  "copy_clipboard", 0);
988     gtk_binding_entry_add_signal(binding_set, GDK_v, GDK_CONTROL_MASK,
989                                  "paste_clipboard", 0);
990
991     gtk_binding_entry_add_signal(binding_set, GDK_Delete, GDK_SHIFT_MASK,
992                                  "cut_clipboard", 0);
993     gtk_binding_entry_add_signal(binding_set, GDK_Insert, GDK_CONTROL_MASK,
994                                  "copy_clipboard", 0);
995     gtk_binding_entry_add_signal(binding_set, GDK_Insert, GDK_SHIFT_MASK,
996                                  "paste_clipboard", 0);
997
998     /*
999      * properties
1000      */
1001     g_object_class_install_property(objectClass, PROP_COPY_TARGET_LIST,
1002                                     g_param_spec_boxed("copy-target-list",
1003                                                        "Target list",
1004                                                        "The list of targets this Web view supports for copying to the clipboard",
1005                                                        GTK_TYPE_TARGET_LIST,
1006                                                        WEBKIT_PARAM_READABLE));
1007
1008     g_object_class_install_property(objectClass, PROP_PASTE_TARGET_LIST,
1009                                     g_param_spec_boxed("paste-target-list",
1010                                                        "Target list",
1011                                                        "The list of targets this Web view supports for pasting to the clipboard",
1012                                                        GTK_TYPE_TARGET_LIST,
1013                                                        WEBKIT_PARAM_READABLE));
1014
1015     g_object_class_install_property(objectClass, PROP_SETTINGS,
1016                                     g_param_spec_object("settings",
1017                                                         "Settings",
1018                                                         "An associated WebKitWebSettings instance",
1019                                                         WEBKIT_TYPE_WEB_SETTINGS,
1020                                                         WEBKIT_PARAM_READWRITE));
1021
1022     g_object_class_install_property(objectClass, PROP_EDITABLE,
1023                                     g_param_spec_boolean("editable",
1024                                                          "Editable",
1025                                                          "Whether content can be modified by the user",
1026                                                          FALSE,
1027                                                          WEBKIT_PARAM_READWRITE));
1028 }
1029
1030 static void webkit_web_view_screen_changed(WebKitWebView* webView, GdkScreen* previousScreen, gpointer userdata)
1031 {
1032     WebKitWebViewPrivate* webViewData = WEBKIT_WEB_VIEW_GET_PRIVATE(webView);
1033     WebKitWebSettings* webSettings = webViewData->webSettings;
1034     Settings* settings = webViewData->corePage->settings();
1035
1036     guint defaultFontSize, defaultMonospaceFontSize, minimumFontSize, minimumLogicalFontSize;
1037
1038     g_object_get(G_OBJECT(webSettings),
1039                  "default-font-size", &defaultFontSize,
1040                  "default-monospace-font-size", &defaultMonospaceFontSize,
1041                  "minimum-font-size", &minimumFontSize,
1042                  "minimum-logical-font-size", &minimumLogicalFontSize,
1043                  NULL);
1044
1045 #if GTK_CHECK_VERSION(2, 10, 0)
1046     GdkScreen* screen = gtk_widget_has_screen(GTK_WIDGET(webView)) ? gtk_widget_get_screen(GTK_WIDGET(webView)) : gdk_screen_get_default();
1047     guint DPI = gdk_screen_get_resolution(screen);
1048 #else
1049     guint DPI = 96;
1050     g_warning("Cannot retrieve resolution, falling back to 96 DPI");
1051 #endif
1052     settings->setDefaultFontSize(defaultFontSize / 72.0 * DPI);
1053     settings->setDefaultFixedFontSize(defaultMonospaceFontSize / 72.0 * DPI);
1054     settings->setMinimumFontSize(minimumFontSize / 72.0 * DPI);
1055     settings->setMinimumLogicalFontSize(minimumLogicalFontSize / 72.0 * DPI);
1056 }
1057
1058 static void webkit_web_view_update_settings(WebKitWebView* webView)
1059 {
1060     WebKitWebViewPrivate* webViewData = WEBKIT_WEB_VIEW_GET_PRIVATE(webView);
1061     WebKitWebSettings* webSettings = webViewData->webSettings;
1062     Settings* settings = webViewData->corePage->settings();
1063
1064     gchar* defaultEncoding, *cursiveFontFamily, *defaultFontFamily, *fantasyFontFamily, *monospaceFontFamily, *sansSerifFontFamily, *serifFontFamily, *userStylesheetUri;
1065     gboolean autoLoadImages, autoShrinkImages, printBackgrounds, enableScripts, enablePlugins, resizableTextAreas;
1066
1067     g_object_get(G_OBJECT(webSettings),
1068                  "default-encoding", &defaultEncoding,
1069                  "cursive-font-family", &cursiveFontFamily,
1070                  "default-font-family", &defaultFontFamily,
1071                  "fantasy-font-family", &fantasyFontFamily,
1072                  "monospace-font-family", &monospaceFontFamily,
1073                  "sans-serif-font-family", &sansSerifFontFamily,
1074                  "serif-font-family", &serifFontFamily,
1075                  "auto-load-images", &autoLoadImages,
1076                  "auto-shrink-images", &autoShrinkImages,
1077                  "print-backgrounds", &printBackgrounds,
1078                  "enable-scripts", &enableScripts,
1079                  "enable-plugins", &enablePlugins,
1080                  "resizable-text-areas", &resizableTextAreas,
1081                  "user-stylesheet-uri", &userStylesheetUri,
1082                  NULL);
1083
1084     settings->setDefaultTextEncodingName(defaultEncoding);
1085     settings->setCursiveFontFamily(cursiveFontFamily);
1086     settings->setStandardFontFamily(defaultFontFamily);
1087     settings->setFantasyFontFamily(fantasyFontFamily);
1088     settings->setFixedFontFamily(monospaceFontFamily);
1089     settings->setSansSerifFontFamily(sansSerifFontFamily);
1090     settings->setSerifFontFamily(serifFontFamily);
1091     settings->setLoadsImagesAutomatically(autoLoadImages);
1092     settings->setShrinksStandaloneImagesToFit(autoShrinkImages);
1093     settings->setShouldPrintBackgrounds(printBackgrounds);
1094     settings->setJavaScriptEnabled(enableScripts);
1095     settings->setPluginsEnabled(enablePlugins);
1096     settings->setTextAreasAreResizable(resizableTextAreas);
1097     settings->setUserStyleSheetLocation(userStylesheetUri);
1098
1099     g_free(defaultEncoding);
1100     g_free(cursiveFontFamily);
1101     g_free(defaultFontFamily);
1102     g_free(fantasyFontFamily);
1103     g_free(monospaceFontFamily);
1104     g_free(sansSerifFontFamily);
1105     g_free(serifFontFamily);
1106     g_free(userStylesheetUri);
1107
1108     webkit_web_view_screen_changed(webView, NULL, NULL);
1109 }
1110
1111 static void webkit_web_view_settings_notify(WebKitWebSettings* webSettings, GParamSpec* pspec, WebKitWebView* webView)
1112 {
1113     WebKitWebViewPrivate* webViewData = WEBKIT_WEB_VIEW_GET_PRIVATE(webView);
1114     Settings* settings = webViewData->corePage->settings();
1115
1116     const gchar* name = g_intern_string(pspec->name);
1117     GValue value = {0, 0};
1118     g_value_init(&value, pspec->value_type);
1119     g_object_get_property(G_OBJECT(webSettings), name, &value);
1120
1121     if (name == g_intern_string("default-encoding"))
1122         settings->setDefaultTextEncodingName(g_value_get_string(&value));
1123     else if (name == g_intern_string("cursive-font-family"))
1124         settings->setCursiveFontFamily(g_value_get_string(&value));
1125     else if (name == g_intern_string("default-font-family"))
1126         settings->setStandardFontFamily(g_value_get_string(&value));
1127     else if (name == g_intern_string("fantasy-font-family"))
1128         settings->setFantasyFontFamily(g_value_get_string(&value));
1129     else if (name == g_intern_string("monospace-font-family"))
1130         settings->setFixedFontFamily(g_value_get_string(&value));
1131     else if (name == g_intern_string("sans-serif-font-family"))
1132         settings->setSansSerifFontFamily(g_value_get_string(&value));
1133     else if (name == g_intern_string("serif-font-family"))
1134         settings->setSerifFontFamily(g_value_get_string(&value)); 
1135     else if (name == g_intern_string("default-font-size"))
1136         settings->setDefaultFontSize(g_value_get_int(&value));
1137     else if (name == g_intern_string("default-monospace-font-size"))
1138         settings->setDefaultFixedFontSize(g_value_get_int(&value));
1139     else if (name == g_intern_string("minimum-font-size"))
1140         settings->setMinimumFontSize(g_value_get_int(&value));
1141     else if (name == g_intern_string("minimum-logical-font-size"))
1142         settings->setMinimumLogicalFontSize(g_value_get_int(&value));
1143     else if (name == g_intern_string("auto-load-images"))
1144         settings->setLoadsImagesAutomatically(g_value_get_boolean(&value));
1145     else if (name == g_intern_string("auto-shrink-images"))
1146         settings->setShrinksStandaloneImagesToFit(g_value_get_boolean(&value));
1147     else if (name == g_intern_string("print-backgrounds"))
1148         settings->setShouldPrintBackgrounds(g_value_get_boolean(&value));
1149     else if (name == g_intern_string("enable-scripts"))
1150         settings->setJavaScriptEnabled(g_value_get_boolean(&value));
1151     else if (name == g_intern_string("enable-plugins"))
1152         settings->setPluginsEnabled(g_value_get_boolean(&value));
1153     else if (name == g_intern_string("resizable-text-areas"))
1154         settings->setTextAreasAreResizable(g_value_get_boolean(&value));
1155     else if (name == g_intern_string("user-stylesheet-uri"))
1156         settings->setUserStyleSheetLocation(g_value_get_string(&value));
1157     else
1158         g_warning("Unexpected setting '%s'", name);
1159     g_value_unset(&value);
1160 }
1161
1162 static void webkit_web_view_init(WebKitWebView* webView)
1163 {
1164     WebKitWebViewPrivate* webViewData = WEBKIT_WEB_VIEW_GET_PRIVATE(webView);
1165     webViewData->imContext = gtk_im_multicontext_new();
1166     webViewData->corePage = new Page(new WebKit::ChromeClient(webView), new WebKit::ContextMenuClient, new WebKit::EditorClient(webView), new WebKit::DragClient, new WebKit::InspectorClient);
1167
1168     webViewData->webSettings = webkit_web_settings_new();
1169     webkit_web_view_update_settings(webView);
1170     g_signal_connect(webView, "screen-changed", G_CALLBACK(webkit_web_view_screen_changed), NULL);
1171     g_signal_connect(webViewData->webSettings, "notify", G_CALLBACK(webkit_web_view_settings_notify), webView);
1172
1173     GTK_WIDGET_SET_FLAGS(webView, GTK_CAN_FOCUS);
1174     webViewData->mainFrame = WEBKIT_WEB_FRAME(webkit_web_frame_new(webView));
1175     webViewData->lastPopupXPosition = webViewData->lastPopupYPosition = -1;
1176     webViewData->editable = false;
1177
1178 #if GTK_CHECK_VERSION(2,10,0)
1179     GdkAtom textHtml = gdk_atom_intern_static_string("text/html");
1180 #else
1181     GdkAtom textHtml = gdk_atom_intern("text/html", false);
1182 #endif
1183     /* Targets for copy */
1184     webViewData->copy_target_list = gtk_target_list_new(NULL, 0);
1185     gtk_target_list_add(webViewData->copy_target_list, textHtml, 0, WEBKIT_WEB_VIEW_TARGET_INFO_HTML);
1186     gtk_target_list_add_text_targets(webViewData->copy_target_list, WEBKIT_WEB_VIEW_TARGET_INFO_TEXT);
1187
1188     /* Targets for pasting */
1189     webViewData->paste_target_list = gtk_target_list_new(NULL, 0);
1190     gtk_target_list_add(webViewData->paste_target_list, textHtml, 0, WEBKIT_WEB_VIEW_TARGET_INFO_HTML);
1191     gtk_target_list_add_text_targets(webViewData->paste_target_list, WEBKIT_WEB_VIEW_TARGET_INFO_TEXT);
1192
1193 }
1194
1195 GtkWidget* webkit_web_view_new(void)
1196 {
1197     WebKitWebView* webView = WEBKIT_WEB_VIEW(g_object_new(WEBKIT_TYPE_WEB_VIEW, NULL));
1198
1199     return GTK_WIDGET(webView);
1200 }
1201
1202 void webkit_web_view_set_settings(WebKitWebView* webView, WebKitWebSettings* webSettings)
1203 {
1204     g_return_if_fail(WEBKIT_IS_WEB_VIEW(webView));
1205     g_return_if_fail(WEBKIT_IS_WEB_SETTINGS(webSettings));
1206
1207     WebKitWebViewPrivate* webViewData = WEBKIT_WEB_VIEW_GET_PRIVATE(webView);
1208     g_signal_handlers_disconnect_by_func(webViewData->webSettings, (gpointer)webkit_web_view_settings_notify, webView);
1209     g_object_unref(webViewData->webSettings);
1210     g_object_ref(webSettings);
1211     webViewData->webSettings = webSettings;
1212     webkit_web_view_update_settings(webView);
1213     g_signal_connect(webSettings, "notify", G_CALLBACK(webkit_web_view_settings_notify), webView);
1214 }
1215
1216 WebKitWebSettings* webkit_web_view_get_settings(WebKitWebView* webView)
1217 {
1218     g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), NULL);
1219
1220     WebKitWebViewPrivate* webViewData = WEBKIT_WEB_VIEW_GET_PRIVATE(webView);
1221     return webViewData->webSettings;
1222 }
1223
1224 void webkit_web_view_go_backward(WebKitWebView* webView)
1225 {
1226     g_warning("webkit_web_view_go_backward() is obsolete; use webkit_web_view_go_back()");
1227     webkit_web_view_go_back(webView);
1228 }
1229
1230 /**
1231  * webkit_web_view_go_back:
1232  * @web_view: a #WebKitWebView
1233  *
1234  * Loads the previous history item.
1235  */
1236 void webkit_web_view_go_back(WebKitWebView* webView)
1237 {
1238     g_return_if_fail(WEBKIT_IS_WEB_VIEW(webView));
1239
1240     Frame* frame = core(webkit_web_view_get_main_frame(webView));
1241     frame->loader()->goBackOrForward(-1);
1242 }
1243
1244 /**
1245  * webkit_web_view_go_back_or_forward:
1246  * @web_view: a #WebKitWebView
1247  * @steps: the number of steps
1248  *
1249  * Loads the history item that is the number of @steps away from the current
1250  * item. Negative values represent steps backward while positive values
1251  * represent steps forward.
1252  */
1253 void webkit_web_view_go_back_or_forward(WebKitWebView* webView, gint steps)
1254 {
1255     g_return_if_fail(WEBKIT_IS_WEB_VIEW(webView));
1256
1257     Frame* frame = core(webkit_web_view_get_main_frame(webView));
1258     frame->loader()->goBackOrForward(steps);
1259 }
1260
1261 /**
1262  * webkit_web_view_go_forward:
1263  * @web_view: a #WebKitWebView
1264  *
1265  * Loads the next history item.
1266  */
1267 void webkit_web_view_go_forward(WebKitWebView* webView)
1268 {
1269     g_return_if_fail(WEBKIT_IS_WEB_VIEW(webView));
1270
1271     Frame* frame = core(webkit_web_view_get_main_frame(webView));
1272     frame->loader()->goBackOrForward(1);
1273 }
1274
1275 gboolean webkit_web_view_can_go_backward(WebKitWebView* webView)
1276 {
1277     g_warning("webkit_web_view_can_go_backward() is obsolete; use webkit_web_view_can_go_back()");
1278     return webkit_web_view_can_go_back(webView);
1279 }
1280
1281 /**
1282  * webkit_web_view_can_go_back:
1283  * @web_view: a #WebKitWebView
1284  *
1285  * Determines whether #web_view has a previous history item.
1286  *
1287  * Return value: %TRUE if able to move back, %FALSE otherwise
1288  */
1289 gboolean webkit_web_view_can_go_back(WebKitWebView* webView)
1290 {
1291     g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), FALSE);
1292
1293     Frame* frame = core(webkit_web_view_get_main_frame(webView));
1294     return frame->loader()->canGoBackOrForward(-1);
1295 }
1296
1297 /**
1298  * webkit_web_view_can_go_back_or_forward:
1299  * @web_view: a #WebKitWebView
1300  * @steps: the number of steps
1301  *
1302  * Determines whether #web_view has a history item of @steps. Negative values
1303  * represent steps backward while positive values represent steps forward.
1304  *
1305  * Return value: %TRUE if able to move back or forward the given number of
1306  * steps, %FALSE otherwise
1307  */
1308 gboolean webkit_web_view_can_go_back_or_forward(WebKitWebView* webView, gint steps)
1309 {
1310     g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), FALSE);
1311
1312     Frame* frame = core(webkit_web_view_get_main_frame(webView));
1313     return frame->loader()->canGoBackOrForward(steps);
1314 }
1315
1316 /**
1317  * webkit_web_view_can_go_forward:
1318  * @web_view: a #WebKitWebView
1319  *
1320  * Determines whether #web_view has a next history item.
1321  *
1322  * Return value: %TRUE if able to move forward, %FALSE otherwise
1323  */
1324 gboolean webkit_web_view_can_go_forward(WebKitWebView* webView)
1325 {
1326     g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), FALSE);
1327
1328     Frame* frame = core(webkit_web_view_get_main_frame(webView));
1329     return frame->loader()->canGoBackOrForward(1);
1330 }
1331
1332 void webkit_web_view_open(WebKitWebView* webView, const gchar* uri)
1333 {
1334     g_return_if_fail(WEBKIT_IS_WEB_VIEW(webView));
1335     g_return_if_fail(uri);
1336
1337     Frame* frame = core(webkit_web_view_get_main_frame(webView));
1338     DeprecatedString string = DeprecatedString::fromUtf8(uri);
1339     frame->loader()->load(ResourceRequest(KURL(string)));
1340 }
1341
1342 void webkit_web_view_reload(WebKitWebView* webView)
1343 {
1344     g_return_if_fail(WEBKIT_IS_WEB_VIEW(webView));
1345
1346     Frame* frame = core(webkit_web_view_get_main_frame(webView));
1347     frame->loader()->reload();
1348 }
1349
1350 void webkit_web_view_load_string(WebKitWebView* webView, const gchar* content, const gchar* contentMimeType, const gchar* contentEncoding, const gchar* baseUri)
1351 {
1352     g_return_if_fail(WEBKIT_IS_WEB_VIEW(webView));
1353     g_return_if_fail(content);
1354
1355     Frame* frame = core(webkit_web_view_get_main_frame(webView));
1356
1357     KURL url(baseUri ? DeprecatedString::fromUtf8(baseUri) : "");
1358     RefPtr<SharedBuffer> sharedBuffer = new SharedBuffer(strdup(content), strlen(content));
1359     SubstituteData substituteData(sharedBuffer.release(), contentMimeType ? String(contentMimeType) : "text/html", contentEncoding ? String(contentEncoding) : "UTF-8", KURL("about:blank"), url);
1360
1361     frame->loader()->load(ResourceRequest(url), substituteData);
1362 }
1363
1364 void webkit_web_view_load_html_string(WebKitWebView* webView, const gchar* content, const gchar* baseUri)
1365 {
1366     g_return_if_fail(WEBKIT_IS_WEB_VIEW(webView));
1367     g_return_if_fail(content);
1368
1369     webkit_web_view_load_string(webView, content, NULL, NULL, baseUri);
1370 }
1371
1372 void webkit_web_view_stop_loading(WebKitWebView* webView)
1373 {
1374     g_return_if_fail(WEBKIT_IS_WEB_VIEW(webView));
1375
1376     Frame* frame = core(webkit_web_view_get_main_frame(webView));
1377
1378     if (FrameLoader* loader = frame->loader())
1379         loader->stopAllLoaders();
1380 }
1381
1382 /**
1383  * webkit_web_view_search_text:
1384  * @web_view: a #WebKitWebView
1385  * @text: a string to look for
1386  * @forward: whether to find forward or not
1387  * @case_sensitive: whether to respect the case of text
1388  * @wrap: whether to continue looking at the beginning after reaching the end
1389  *
1390  * Looks for a specified string inside #web_view.
1391  *
1392  * Return value: %TRUE on success or %FALSE on failure
1393  */
1394 gboolean webkit_web_view_search_text(WebKitWebView* webView, const gchar* string, gboolean caseSensitive, gboolean forward, gboolean shouldWrap)
1395 {
1396     g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), FALSE);
1397     g_return_val_if_fail(string, FALSE);
1398
1399     TextCaseSensitivity caseSensitivity = caseSensitive ? TextCaseSensitive : TextCaseInsensitive;
1400     FindDirection direction = forward ? FindDirectionForward : FindDirectionBackward;
1401
1402     WebKitWebViewPrivate* webViewData = WEBKIT_WEB_VIEW_GET_PRIVATE(webView);
1403     return webViewData->corePage->findString(String::fromUTF8(string), caseSensitivity, direction, shouldWrap);
1404 }
1405
1406 /**
1407  * webkit_web_view_mark_text_matches:
1408  * @web_view: a #WebKitWebView
1409  * @string: a string to look for
1410  * @case_sensitive: whether to respect the case of text
1411  * @limit: the maximum number of strings to look for or %0 for all
1412  *
1413  * Attempts to highlight all occurances of #string inside #web_view.
1414  *
1415  * Return value: the number of strings highlighted
1416  */
1417 guint webkit_web_view_mark_text_matches(WebKitWebView* webView, const gchar* string, gboolean caseSensitive, guint limit)
1418 {
1419     g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), 0);
1420     g_return_val_if_fail(string, 0);
1421
1422     TextCaseSensitivity caseSensitivity = caseSensitive ? TextCaseSensitive : TextCaseInsensitive;
1423
1424     WebKitWebViewPrivate* webViewData = WEBKIT_WEB_VIEW_GET_PRIVATE(webView);
1425     return webViewData->corePage->markAllMatchesForText(String::fromUTF8(string), caseSensitivity, false, limit);
1426 }
1427
1428 /**
1429  * webkit_web_view_set_highlight_text_matches:
1430  * @web_view: a #WebKitWebView
1431  * @highlight: whether to highlight text matches
1432  *
1433  * Highlights text matches previously marked by webkit_web_view_mark_text_matches.
1434  */
1435 void webkit_web_view_set_highlight_text_matches(WebKitWebView* webView, gboolean shouldHighlight)
1436 {
1437     g_return_if_fail(WEBKIT_IS_WEB_VIEW(webView));
1438
1439     WebKitWebViewPrivate* webViewData = WEBKIT_WEB_VIEW_GET_PRIVATE(webView);
1440     WebKitWebFramePrivate* frameData = WEBKIT_WEB_FRAME_GET_PRIVATE(webViewData->mainFrame);
1441     frameData->frame->setMarkedTextMatchesAreHighlighted(shouldHighlight);
1442 }
1443
1444 /**
1445  * webkit_web_view_unmark_text_matches:
1446  * @web_view: a #WebKitWebView
1447  *
1448  * Removes highlighting previously set by webkit_web_view_mark_text_matches.
1449  */
1450 void webkit_web_view_unmark_text_matches(WebKitWebView* webView)
1451 {
1452     g_return_if_fail(WEBKIT_IS_WEB_VIEW(webView));
1453
1454     WebKitWebViewPrivate* webViewData = WEBKIT_WEB_VIEW_GET_PRIVATE(webView);
1455     return webViewData->corePage->unmarkAllTextMatches();
1456 }
1457
1458 WebKitWebFrame* webkit_web_view_get_main_frame(WebKitWebView* webView)
1459 {
1460     g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), NULL);
1461
1462     WebKitWebViewPrivate* webViewData = WEBKIT_WEB_VIEW_GET_PRIVATE(webView);
1463     return webViewData->mainFrame;
1464 }
1465
1466 void webkit_web_view_execute_script(WebKitWebView* webView, const gchar* script)
1467 {
1468     g_return_if_fail(WEBKIT_IS_WEB_VIEW(webView));
1469     g_return_if_fail(script);
1470
1471     Frame* frame = core(webkit_web_view_get_main_frame(webView));
1472     if (FrameLoader* loader = frame->loader())
1473         loader->executeScript(String::fromUTF8(script), true);
1474 }
1475
1476 /**
1477  * webkit_web_view_cut_clipboard:
1478  * @web_view: a #WebKitWebView
1479  *
1480  * Determines whether or not it is currently possible to cut to the clipboard.
1481  *
1482  * Return value: %TRUE if a selection can be cut, %FALSE if not
1483  */
1484 gboolean webkit_web_view_can_cut_clipboard(WebKitWebView* webView)
1485 {
1486     g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), FALSE);
1487
1488     Frame* frame = core(webView)->focusController()->focusedOrMainFrame();
1489     return frame->editor()->canCut() || frame->editor()->canDHTMLCut();
1490 }
1491
1492 /**
1493  * webkit_web_view_copy_clipboard:
1494  * @web_view: a #WebKitWebView
1495  *
1496  * Determines whether or not it is currently possible to copy to the clipboard.
1497  *
1498  * Return value: %TRUE if a selection can be copied, %FALSE if not
1499  */
1500 gboolean webkit_web_view_can_copy_clipboard(WebKitWebView* webView)
1501 {
1502     g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), FALSE);
1503
1504     Frame* frame = core(webView)->focusController()->focusedOrMainFrame();
1505     return frame->editor()->canCopy() || frame->editor()->canDHTMLCopy();
1506 }
1507
1508 /**
1509  * webkit_web_view_paste_clipboard:
1510  * @web_view: a #WebKitWebView
1511  *
1512  * Determines whether or not it is currently possible to paste from the clipboard.
1513  *
1514  * Return value: %TRUE if a selection can be pasted, %FALSE if not
1515  */
1516 gboolean webkit_web_view_can_paste_clipboard(WebKitWebView* webView)
1517 {
1518     g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), FALSE);
1519
1520     Frame* frame = core(webView)->focusController()->focusedOrMainFrame();
1521     return frame->editor()->canPaste() || frame->editor()->canDHTMLPaste();
1522 }
1523
1524 /**
1525  * webkit_web_view_cut_clipboard:
1526  * @web_view: a #WebKitWebView
1527  *
1528  * Cuts the current selection inside the @web_view to the clipboard.
1529  */
1530 void webkit_web_view_cut_clipboard(WebKitWebView* webView)
1531 {
1532     g_return_if_fail(WEBKIT_IS_WEB_VIEW(webView));
1533
1534     if (webkit_web_view_can_cut_clipboard(webView))
1535         g_signal_emit(webView, webkit_web_view_signals[CUT_CLIPBOARD], 0);
1536 }
1537
1538 /**
1539  * webkit_web_view_copy_clipboard:
1540  * @web_view: a #WebKitWebView
1541  *
1542  * Copies the current selection inside the @web_view to the clipboard.
1543  */
1544 void webkit_web_view_copy_clipboard(WebKitWebView* webView)
1545 {
1546     g_return_if_fail(WEBKIT_IS_WEB_VIEW(webView));
1547
1548     if (webkit_web_view_can_copy_clipboard(webView))
1549         g_signal_emit(webView, webkit_web_view_signals[COPY_CLIPBOARD], 0);
1550 }
1551
1552 /**
1553  * webkit_web_view_paste_clipboard:
1554  * @web_view: a #WebKitWebView
1555  *
1556  * Pastes the current contents of the clipboard to the @web_view.
1557  */
1558 void webkit_web_view_paste_clipboard(WebKitWebView* webView)
1559 {
1560     g_return_if_fail(WEBKIT_IS_WEB_VIEW(webView));
1561
1562     if (webkit_web_view_can_paste_clipboard(webView))
1563         g_signal_emit(webView, webkit_web_view_signals[PASTE_CLIPBOARD], 0);
1564 }
1565
1566 /**
1567  * webkit_web_view_delete_selection:
1568  * @web_view: a #WebKitWebView
1569  *
1570  * Deletes the current selection inside the @web_view.
1571  */
1572 void webkit_web_view_delete_selection(WebKitWebView* webView)
1573 {
1574     g_return_if_fail(WEBKIT_IS_WEB_VIEW(webView));
1575
1576     Frame* frame = core(webView)->focusController()->focusedOrMainFrame();
1577     frame->editor()->performDelete();
1578 }
1579
1580 /**
1581  * webkit_web_view_has_selection:
1582  * @web_view: a #WebKitWebView
1583  *
1584  * Determines whether text was selected.
1585  *
1586  * Return value: %TRUE if there is selected text, %FALSE if not
1587  */
1588 gboolean webkit_web_view_has_selection(WebKitWebView* webView)
1589 {
1590     g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), FALSE);
1591
1592     WebKitWebViewPrivate* webViewData = WEBKIT_WEB_VIEW_GET_PRIVATE(webView);
1593     return !webViewData->corePage->selection().isNone();
1594 }
1595
1596 /**
1597  * webkit_web_view_get_selected_text:
1598  * @web_view: a #WebKitWebView
1599  *
1600  * Retrieves the selected text if any.
1601  *
1602  * Return value: a newly allocated string with the selection or %NULL
1603  */
1604 gchar* webkit_web_view_get_selected_text(WebKitWebView* webView)
1605 {
1606     g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), 0);
1607
1608     Frame* frame = core(webView)->focusController()->focusedOrMainFrame();
1609     return g_strdup(frame->selectedText().utf8().data());
1610 }
1611
1612 /**
1613  * webkit_web_view_select_all:
1614  * @web_view: a #WebKitWebView
1615  *
1616  * Attempts to select everything inside the @web_view.
1617  */
1618 void webkit_web_view_select_all(WebKitWebView* webView)
1619 {
1620     g_return_if_fail(WEBKIT_IS_WEB_VIEW(webView));
1621
1622     g_signal_emit(webView, webkit_web_view_signals[SELECT_ALL], 0);
1623 }
1624
1625 /**
1626  * webkit_web_view_get_editable:
1627  * @web_view: a #WebKitWebView
1628  *
1629  * Returns whether the user is allowed to edit the document.
1630  *
1631  * Returns %TRUE if @web_view allows the user to edit the HTML document, %FALSE if
1632  * it doesn't. You can change @web_view's document programmatically regardless of
1633  * this setting.
1634  *
1635  * Return value: a #gboolean indicating the editable state
1636  */
1637 gboolean webkit_web_view_get_editable(WebKitWebView* webView)
1638 {
1639     g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), FALSE);
1640
1641     WebKitWebViewPrivate* webViewData = WEBKIT_WEB_VIEW_GET_PRIVATE(webView);
1642     ASSERT(webViewData);
1643
1644     return webViewData->editable;
1645 }
1646
1647 /**
1648  * webkit_web_view_set_editable:
1649  * @web_view: a #WebKitWebView
1650  * @flag: a #gboolean indicating the editable state
1651  *
1652  * Sets whether @web_view allows the user to edit its HTML document.
1653  *
1654  * If @flag is %TRUE, @web_view allows the user to edit the document. If @flag is
1655  * %FALSE, an element in @web_view's document can only be edited if the
1656  * CONTENTEDITABLE attribute has been set on the element or one of its parent
1657  * elements. You can change @web_view's document programmatically regardless of
1658  * this setting. By default a #WebKitWebView is not editable.
1659
1660  * Normally, an HTML document is not editable unless the elements within the
1661  * document are editable. This function provides a low-level way to make the
1662  * contents of a #WebKitWebView editable without altering the document or DOM
1663  * structure.
1664  */
1665 void webkit_web_view_set_editable(WebKitWebView* webView, gboolean flag)
1666 {
1667     g_return_if_fail(WEBKIT_IS_WEB_VIEW(webView));
1668     flag = flag != FALSE;
1669
1670     WebKitWebViewPrivate* webViewData = WEBKIT_WEB_VIEW_GET_PRIVATE(webView);
1671     ASSERT(webViewData);
1672
1673     Frame* mainFrame = core(webViewData->mainFrame);
1674     g_return_if_fail(mainFrame);
1675
1676     // TODO: What happens when the frame is replaced?
1677     if (flag == webViewData->editable)
1678         return;
1679
1680     webViewData->editable = flag;
1681
1682     if (flag) {
1683         mainFrame->applyEditingStyleToBodyElement();
1684         // TODO: If the WebKitWebView is made editable and the selection is empty, set it to something.
1685         //if (!webkit_web_view_get_selected_dom_range(webView))
1686         //    mainFrame->setSelectionFromNone();
1687     } else
1688         mainFrame->removeEditingStyleFromBodyElement();
1689 }
1690
1691 /**
1692  * webkit_web_view_get_copy_target_list:
1693  * @web_view: a #WebKitWebView
1694  *
1695  * This function returns the list of targets this #WebKitWebView can
1696  * provide for clipboard copying and as DND source. The targets in the list are
1697  * added with %info values from the #WebKitWebViewTargetInfo enum,
1698  * using gtk_target_list_add() and
1699  * gtk_target_list_add_text_targets().
1700  *
1701  * Return value: the #GtkTargetList
1702  **/
1703 GtkTargetList* webkit_web_view_get_copy_target_list(WebKitWebView* webView)
1704 {
1705     g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), NULL);
1706
1707     WebKitWebViewPrivate* webViewData = WEBKIT_WEB_VIEW_GET_PRIVATE(webView);
1708     return webViewData->copy_target_list;
1709 }
1710
1711 /**
1712  * webkit_web_view_get_paste_target_list:
1713  * @web_view: a #WebKitWebView
1714  *
1715  * This function returns the list of targets this #WebKitWebView can
1716  * provide for clipboard pasting and as DND destination. The targets in the list are
1717  * added with %info values from the #WebKitWebViewTargetInfo enum,
1718  * using gtk_target_list_add() and
1719  * gtk_target_list_add_text_targets().
1720  *
1721  * Return value: the #GtkTargetList
1722  **/
1723 GtkTargetList* webkit_web_view_get_paste_target_list(WebKitWebView* webView)
1724 {
1725     g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), NULL);
1726
1727     WebKitWebViewPrivate* webViewData = WEBKIT_WEB_VIEW_GET_PRIVATE(webView);
1728     return webViewData->paste_target_list;
1729 }
1730
1731 }