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