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