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