494a26f942eb199c29607fd3b63d81157acd1edf
[WebKit-https.git] / WebKit / gtk / webkit / webkitwebview.cpp
1 /*
2  *  Copyright (C) 2007, 2008 Holger Hans Peter Freyther
3  *  Copyright (C) 2007, 2008 Christian Dywan <christian@imendio.com>
4  *  Copyright (C) 2007 Xan Lopez <xan@gnome.org>
5  *  Copyright (C) 2007, 2008 Alp Toker <alp@atoker.com>
6  *  Copyright (C) 2008 Jan Alonzo <jmalonzo@unpluggable.com>
7  *  Copyright (C) 2008 Gustavo Noronha Silva <gns@gnome.org>
8  *  Copyright (C) 2008 Nuanti Ltd.
9  *  Copyright (C) 2008 Collabora Ltd.
10  *
11  *  This library is free software; you can redistribute it and/or
12  *  modify it under the terms of the GNU Lesser General Public
13  *  License as published by the Free Software Foundation; either
14  *  version 2 of the License, or (at your option) any later version.
15  *
16  *  This library is distributed in the hope that it will be useful,
17  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
18  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19  *  Lesser General Public License for more details.
20  *
21  *  You should have received a copy of the GNU Lesser General Public
22  *  License along with this library; if not, write to the Free Software
23  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
24  */
25
26 #include "config.h"
27
28 #include "webkitwebview.h"
29 #include "webkitenumtypes.h"
30 #include "webkitmarshal.h"
31 #include "webkitprivate.h"
32 #include "webkitwebinspector.h"
33 #include "webkitwebbackforwardlist.h"
34 #include "webkitwebhistoryitem.h"
35
36 #include "AXObjectCache.h"
37 #include "NotImplemented.h"
38 #include "BackForwardList.h"
39 #include "CString.h"
40 #include "ChromeClientGtk.h"
41 #include "ContextMenu.h"
42 #include "ContextMenuClientGtk.h"
43 #include "ContextMenuController.h"
44 #include "Cursor.h"
45 #include "Document.h"
46 #include "DragClientGtk.h"
47 #include "Editor.h"
48 #include "EditorClientGtk.h"
49 #include "EventHandler.h"
50 #include "FloatQuad.h"
51 #include "FocusController.h"
52 #include "FrameLoaderTypes.h"
53 #include "HitTestRequest.h"
54 #include "HitTestResult.h"
55 #include "GraphicsContext.h"
56 #include "InspectorClientGtk.h"
57 #include "FrameLoader.h"
58 #include "FrameView.h"
59 #include "Editor.h"
60 #include "PasteboardHelper.h"
61 #include "PlatformKeyboardEvent.h"
62 #include "PlatformWheelEvent.h"
63 #include "ScriptValue.h"
64 #include "Scrollbar.h"
65 #include <wtf/GOwnPtr.h>
66
67 #include <gdk/gdkkeysyms.h>
68
69 /**
70  * SECTION:webkitwebview
71  * @short_description: The central class of the WebKit/Gtk+ API
72  * @see_also: #WebKitWebSettings, #WebKitWebFrame
73  *
74  * #WebKitWebView is the central class of the WebKit/Gtk+ API. It is a
75  * #GtkWidget implementing the scrolling interface which means you can
76  * embed in a #GtkScrolledWindow. It is responsible for managing the
77  * drawing of the content, forwarding of events. You can load any URI
78  * into the #WebKitWebView or any kind of data string. With #WebKitWebSettings
79  * you can control various aspects of the rendering and loading of the content.
80  * Each #WebKitWebView has exactly one #WebKitWebFrame as main frame. A
81  * #WebKitWebFrame can have n children.
82  *
83  * <programlisting>
84  * /<!-- -->* Create the widgets *<!-- -->/
85  * GtkWidget *main_window = gtk_window_new (GTK_WIDGET_TOPLEVEL);
86  * GtkWidget *scrolled_window = gtk_scrolled_window_new (NULL, NULL);
87  * GtkWidget *web_view = webkit_web_view_new ();
88  *
89  * /<!-- -->* Place the WebKitWebView in the GtkScrolledWindow *<!-- -->/
90  * gtk_container_add (GTK_CONTAINER (scrolled_window), web_view);
91  * gtk_container_add (GTK_CONTAINER (main_window), scrolled_window);
92  *
93  * /<!-- -->* Open a webpage *<!-- -->/
94  * webkit_web_view_open (WEBKIT_WEB_VIEW (web_view), "http://www.gnome.org");
95  *
96  * /<!-- -->* Show the result *<!-- -->/
97  * gtk_window_set_default_size (GTK_WINDOW (main_window), 800, 600);
98  * gtk_widget_show_all (main_window);
99  * </programlisting>
100  */
101
102 static const double defaultDPI = 96.0;
103
104 using namespace WebKit;
105 using namespace WebCore;
106
107 extern "C" {
108
109 enum {
110     /* normal signals */
111     NAVIGATION_REQUESTED,
112     NAVIGATION_POLICY_DECISION_REQUESTED,
113     MIME_TYPE_POLICY_DECISION_REQUESTED,
114     CREATE_WEB_VIEW,
115     WEB_VIEW_READY,
116     WINDOW_OBJECT_CLEARED,
117     LOAD_STARTED,
118     LOAD_COMMITTED,
119     LOAD_PROGRESS_CHANGED,
120     LOAD_FINISHED,
121     TITLE_CHANGED,
122     HOVERING_OVER_LINK,
123     POPULATE_POPUP,
124     STATUS_BAR_TEXT_CHANGED,
125     ICOND_LOADED,
126     SELECTION_CHANGED,
127     CONSOLE_MESSAGE,
128     SCRIPT_ALERT,
129     SCRIPT_CONFIRM,
130     SCRIPT_PROMPT,
131     SELECT_ALL,
132     COPY_CLIPBOARD,
133     PASTE_CLIPBOARD,
134     CUT_CLIPBOARD,
135     LAST_SIGNAL
136 };
137
138 enum {
139     PROP_0,
140
141     PROP_COPY_TARGET_LIST,
142     PROP_PASTE_TARGET_LIST,
143     PROP_EDITABLE,
144     PROP_SETTINGS,
145     PROP_WEB_INSPECTOR,
146     PROP_WINDOW_FEATURES,
147     PROP_TRANSPARENT,
148     PROP_ZOOM_LEVEL,
149     PROP_FULL_CONTENT_ZOOM
150 };
151
152 static guint webkit_web_view_signals[LAST_SIGNAL] = { 0, };
153
154 G_DEFINE_TYPE(WebKitWebView, webkit_web_view, GTK_TYPE_CONTAINER)
155
156 static void webkit_web_view_settings_notify(WebKitWebSettings* webSettings, GParamSpec* pspec, WebKitWebView* webView);
157 static void webkit_web_view_set_window_features(WebKitWebView* webView, WebKitWebWindowFeatures* webWindowFeatures);
158
159 static void webkit_web_view_context_menu_position_func(GtkMenu*, gint* x, gint* y, gboolean* pushIn, WebKitWebViewPrivate* data)
160 {
161     *pushIn = FALSE;
162     *x = data->lastPopupXPosition;
163     *y = data->lastPopupYPosition;
164 }
165
166 static gboolean webkit_web_view_forward_context_menu_event(WebKitWebView* webView, const PlatformMouseEvent& event)
167 {
168     Page* page = core(webView);
169     page->contextMenuController()->clearContextMenu();
170     Frame* focusedFrame = page->focusController()->focusedOrMainFrame();
171
172     if (!focusedFrame->view())
173         return FALSE;
174
175     focusedFrame->view()->setCursor(pointerCursor());
176     bool handledEvent = focusedFrame->eventHandler()->sendContextMenuEvent(event);
177     if (!handledEvent)
178         return FALSE;
179
180     ContextMenu* coreMenu = page->contextMenuController()->contextMenu();
181     if (!coreMenu)
182         return FALSE;
183
184     GtkMenu* menu = GTK_MENU(coreMenu->platformDescription());
185     if (!menu)
186         return FALSE;
187
188     g_signal_emit(webView, webkit_web_view_signals[POPULATE_POPUP], 0, menu);
189
190     GList* items = gtk_container_get_children(GTK_CONTAINER(menu));
191     bool empty = !g_list_nth(items, 0);
192     g_list_free(items);
193     if (empty)
194         return FALSE;
195
196     WebKitWebViewPrivate* priv = WEBKIT_WEB_VIEW_GET_PRIVATE(webView);
197     priv->lastPopupXPosition = event.globalX();
198     priv->lastPopupYPosition = event.globalY();
199     gtk_menu_popup(menu, NULL, NULL,
200                    reinterpret_cast<GtkMenuPositionFunc>(webkit_web_view_context_menu_position_func),
201                    priv, event.button() + 1, gtk_get_current_event_time());
202     return TRUE;
203 }
204
205 static gboolean webkit_web_view_popup_menu_handler(GtkWidget* widget)
206 {
207     static const int contextMenuMargin = 1;
208
209     // The context menu event was generated from the keyboard, so show the context menu by the current selection.
210     Page* page = core(WEBKIT_WEB_VIEW(widget));
211     FrameView* view = page->mainFrame()->view();
212     if (!view)
213         return FALSE;    
214
215     Position start = page->mainFrame()->selection()->selection().start();
216     Position end = page->mainFrame()->selection()->selection().end();
217
218     int rightAligned = FALSE;
219     IntPoint location;
220
221     if (!start.node() || !end.node())
222         location = IntPoint(rightAligned ? view->contentsWidth() - contextMenuMargin : contextMenuMargin, contextMenuMargin);
223     else {
224         RenderObject* renderer = start.node()->renderer();
225         if (!renderer)
226             return FALSE;
227
228         // Calculate the rect of the first line of the selection (cribbed from -[WebCoreFrameBridge firstRectForDOMRange:],
229         // now Frame::firstRectForRange(), which perhaps this should call).
230         int extraWidthToEndOfLine = 0;
231
232         InlineBox* startInlineBox;
233         int startCaretOffset;
234         start.getInlineBoxAndOffset(DOWNSTREAM, startInlineBox, startCaretOffset);
235         IntRect startCaretRect = renderer->localCaretRect(startInlineBox, startCaretOffset, &extraWidthToEndOfLine);
236         if (startCaretRect != IntRect())
237             startCaretRect = renderer->localToAbsoluteQuad(FloatRect(startCaretRect)).enclosingBoundingBox();
238
239         InlineBox* endInlineBox;
240         int endCaretOffset;
241         end.getInlineBoxAndOffset(UPSTREAM, endInlineBox, endCaretOffset);
242         IntRect endCaretRect = renderer->localCaretRect(endInlineBox, endCaretOffset);
243         if (endCaretRect != IntRect())
244             endCaretRect = renderer->localToAbsoluteQuad(FloatRect(endCaretRect)).enclosingBoundingBox();
245
246         IntRect firstRect;
247         if (startCaretRect.y() == endCaretRect.y())
248             firstRect = IntRect(MIN(startCaretRect.x(), endCaretRect.x()),
249                                 startCaretRect.y(),
250                                 abs(endCaretRect.x() - startCaretRect.x()),
251                                 MAX(startCaretRect.height(), endCaretRect.height()));
252         else
253             firstRect = IntRect(startCaretRect.x(),
254                                 startCaretRect.y(),
255                                 startCaretRect.width() + extraWidthToEndOfLine,
256                                 startCaretRect.height());
257
258         location = IntPoint(rightAligned ? firstRect.right() : firstRect.x(), firstRect.bottom());
259     }
260
261     int x, y;
262     gdk_window_get_origin(GTK_WIDGET(view->hostWindow()->platformWindow())->window, &x, &y);
263
264     // FIXME: The IntSize(0, -1) is a hack to get the hit-testing to result in the selected element.
265     // Ideally we'd have the position of a context menu event be separate from its target node.
266     location = view->contentsToWindow(location) + IntSize(0, -1);
267     IntPoint global = location + IntSize(x, y);
268     PlatformMouseEvent event(location, global, NoButton, MouseEventPressed, 0, false, false, false, false, gtk_get_current_event_time());
269
270     return webkit_web_view_forward_context_menu_event(WEBKIT_WEB_VIEW(widget), event);
271 }
272
273 static void webkit_web_view_get_property(GObject* object, guint prop_id, GValue* value, GParamSpec* pspec)
274 {
275     WebKitWebView* webView = WEBKIT_WEB_VIEW(object);
276
277     switch(prop_id) {
278 #if GTK_CHECK_VERSION(2,10,0)
279     case PROP_COPY_TARGET_LIST:
280         g_value_set_boxed(value, webkit_web_view_get_copy_target_list(webView));
281         break;
282     case PROP_PASTE_TARGET_LIST:
283         g_value_set_boxed(value, webkit_web_view_get_paste_target_list(webView));
284         break;
285 #endif
286     case PROP_EDITABLE:
287         g_value_set_boolean(value, webkit_web_view_get_editable(webView));
288         break;
289     case PROP_SETTINGS:
290         g_value_set_object(value, webkit_web_view_get_settings(webView));
291         break;
292     case PROP_WEB_INSPECTOR:
293         g_value_set_object(value, webkit_web_view_get_inspector(webView));
294         break;
295     case PROP_WINDOW_FEATURES:
296         g_value_set_object(value, webkit_web_view_get_window_features(webView));
297         break;
298     case PROP_TRANSPARENT:
299         g_value_set_boolean(value, webkit_web_view_get_transparent(webView));
300         break;
301     case PROP_ZOOM_LEVEL:
302         g_value_set_float(value, webkit_web_view_get_zoom_level(webView));
303         break;
304     case PROP_FULL_CONTENT_ZOOM:
305         g_value_set_boolean(value, webkit_web_view_get_full_content_zoom(webView));
306         break;
307     default:
308         G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
309     }
310 }
311
312 static void webkit_web_view_set_property(GObject* object, guint prop_id, const GValue* value, GParamSpec *pspec)
313 {
314     WebKitWebView* webView = WEBKIT_WEB_VIEW(object);
315
316     switch(prop_id) {
317     case PROP_EDITABLE:
318         webkit_web_view_set_editable(webView, g_value_get_boolean(value));
319         break;
320     case PROP_SETTINGS:
321         webkit_web_view_set_settings(webView, WEBKIT_WEB_SETTINGS(g_value_get_object(value)));
322         break;
323     case PROP_WINDOW_FEATURES:
324         webkit_web_view_set_window_features(webView, WEBKIT_WEB_WINDOW_FEATURES(g_value_get_object(value)));
325         break;
326     case PROP_TRANSPARENT:
327         webkit_web_view_set_transparent(webView, g_value_get_boolean(value));
328         break;
329     case PROP_ZOOM_LEVEL:
330         webkit_web_view_set_zoom_level(webView, g_value_get_float(value));
331         break;
332     case PROP_FULL_CONTENT_ZOOM:
333         webkit_web_view_set_full_content_zoom(webView, g_value_get_boolean(value));
334         break;
335     default:
336         G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
337     }
338 }
339
340 static bool shouldCoalesce(GdkRectangle rect, GdkRectangle* rects, int count)
341 {
342     const int cRectThreshold = 10;
343     const float cWastedSpaceThreshold = 0.75f;
344     bool useUnionedRect = (count <= 1) || (count > cRectThreshold);
345     if (!useUnionedRect) {
346         // Attempt to guess whether or not we should use the unioned rect or the individual rects.
347         // We do this by computing the percentage of "wasted space" in the union.  If that wasted space
348         // is too large, then we will do individual rect painting instead.
349         float unionPixels = (rect.width * rect.height);
350         float singlePixels = 0;
351         for (int i = 0; i < count; ++i)
352             singlePixels += rects[i].width * rects[i].height;
353         float wastedSpace = 1 - (singlePixels / unionPixels);
354         if (wastedSpace <= cWastedSpaceThreshold)
355             useUnionedRect = true;
356     }
357     return useUnionedRect;
358 }
359
360 static gboolean webkit_web_view_expose_event(GtkWidget* widget, GdkEventExpose* event)
361 {
362     WebKitWebView* webView = WEBKIT_WEB_VIEW(widget);
363     WebKitWebViewPrivate* priv = webView->priv;
364
365     Frame* frame = core(webView)->mainFrame();
366     if (frame->contentRenderer() && frame->view()) {
367         frame->view()->layoutIfNeededRecursive();
368
369         cairo_t* cr = gdk_cairo_create(event->window);
370         GraphicsContext ctx(cr);
371         cairo_destroy(cr);
372         ctx.setGdkExposeEvent(event);
373
374         GOwnPtr<GdkRectangle> rects;
375         int rectCount;
376         gdk_region_get_rectangles(event->region, &rects.outPtr(), &rectCount);
377
378         // Avoid recursing into the render tree excessively
379         bool coalesce = shouldCoalesce(event->area, rects.get(), rectCount);
380
381         if (coalesce) {
382             IntRect rect = event->area;
383             ctx.clip(rect);
384             if (priv->transparent)
385                 ctx.clearRect(rect);
386             frame->view()->paint(&ctx, rect);
387         } else {
388             for (int i = 0; i < rectCount; i++) {
389                 IntRect rect = rects.get()[i];
390                 ctx.save();
391                 ctx.clip(rect);
392                 if (priv->transparent)
393                     ctx.clearRect(rect);
394                 frame->view()->paint(&ctx, rect);
395                 ctx.restore();
396             }
397         }
398     }
399
400     return FALSE;
401 }
402
403 static gboolean webkit_web_view_key_press_event(GtkWidget* widget, GdkEventKey* event)
404 {
405     WebKitWebView* webView = WEBKIT_WEB_VIEW(widget);
406
407     Frame* frame = core(webView)->focusController()->focusedOrMainFrame();
408     PlatformKeyboardEvent keyboardEvent(event);
409
410     if (!frame->view())
411         return FALSE;
412
413     if (frame->eventHandler()->keyEvent(keyboardEvent))
414         return TRUE;
415
416     FrameView* view = frame->view();
417     SelectionController::EAlteration alteration;
418     if (event->state & GDK_SHIFT_MASK)
419         alteration = SelectionController::EXTEND;
420     else
421         alteration = SelectionController::MOVE;
422
423     // TODO: We probably want to use GTK+ key bindings here and perhaps take an
424     // approach more like the Win and Mac ports for key handling.
425     switch (event->keyval) {
426     case GDK_Down:
427         view->scrollBy(IntSize(0, cScrollbarPixelsPerLineStep));
428         return TRUE;
429     case GDK_Up:
430         view->scrollBy(IntSize(0, -cScrollbarPixelsPerLineStep));
431         return TRUE;
432     case GDK_Right:
433         view->scrollBy(IntSize(cScrollbarPixelsPerLineStep, 0));
434         return TRUE;
435     case GDK_Left:
436         view->scrollBy(IntSize(-cScrollbarPixelsPerLineStep, 0));
437         return TRUE;
438     case GDK_Home:
439         frame->selection()->modify(alteration, SelectionController::BACKWARD, DocumentBoundary, true);
440         return TRUE;
441     case GDK_End:
442         frame->selection()->modify(alteration, SelectionController::FORWARD, DocumentBoundary, true);
443         return TRUE;
444     }
445
446     /* Chain up to our parent class for binding activation */
447     return GTK_WIDGET_CLASS(webkit_web_view_parent_class)->key_press_event(widget, event);
448 }
449
450 static gboolean webkit_web_view_key_release_event(GtkWidget* widget, GdkEventKey* event)
451 {
452     WebKitWebView* webView = WEBKIT_WEB_VIEW(widget);
453
454     Frame* frame = core(webView)->focusController()->focusedOrMainFrame();
455     if (!frame->view())
456         return FALSE;
457
458     PlatformKeyboardEvent keyboardEvent(event);
459
460     if (frame->eventHandler()->keyEvent(keyboardEvent))
461         return TRUE;
462
463     /* Chain up to our parent class for binding activation */
464     return GTK_WIDGET_CLASS(webkit_web_view_parent_class)->key_release_event(widget, event);
465 }
466
467 static gboolean webkit_web_view_button_press_event(GtkWidget* widget, GdkEventButton* event)
468 {
469     WebKitWebView* webView = WEBKIT_WEB_VIEW(widget);
470
471     // FIXME: need to keep track of subframe focus for key events
472     gtk_widget_grab_focus(widget);
473
474     if (event->button == 3)
475         return webkit_web_view_forward_context_menu_event(webView, PlatformMouseEvent(event));
476
477     Frame* frame = core(webView)->mainFrame();
478     if (!frame->view())
479         return FALSE;
480
481     return frame->eventHandler()->handleMousePressEvent(PlatformMouseEvent(event));
482 }
483
484 static gboolean webkit_web_view_button_release_event(GtkWidget* widget, GdkEventButton* event)
485 {
486     WebKitWebView* webView = WEBKIT_WEB_VIEW(widget);
487
488     Frame* focusedFrame = core(webView)->focusController()->focusedFrame();
489
490     if (focusedFrame && focusedFrame->editor()->canEdit()) {
491 #ifdef MAEMO_CHANGES
492         WebKitWebViewPrivate* priv = webView->priv;
493         hildon_gtk_im_context_filter_event(priv->imContext, (GdkEvent*)event);
494 #endif
495     }
496
497     Frame* mainFrame = core(webView)->mainFrame();
498     if (!mainFrame->view())
499         return FALSE;
500
501     return mainFrame->eventHandler()->handleMouseReleaseEvent(PlatformMouseEvent(event));
502 }
503
504 static gboolean webkit_web_view_motion_event(GtkWidget* widget, GdkEventMotion* event)
505 {
506     WebKitWebView* webView = WEBKIT_WEB_VIEW(widget);
507
508     Frame* frame = core(webView)->mainFrame();
509     if (!frame->view())
510         return FALSE;
511
512     return frame->eventHandler()->mouseMoved(PlatformMouseEvent(event));
513 }
514
515 static gboolean webkit_web_view_scroll_event(GtkWidget* widget, GdkEventScroll* event)
516 {
517     WebKitWebView* webView = WEBKIT_WEB_VIEW(widget);
518
519     Frame* frame = core(webView)->mainFrame();
520     if (!frame->view())
521         return FALSE;
522
523     PlatformWheelEvent wheelEvent(event);
524     return frame->eventHandler()->handleWheelEvent(wheelEvent);
525 }
526
527 static void webkit_web_view_size_allocate(GtkWidget* widget, GtkAllocation* allocation)
528 {
529     GTK_WIDGET_CLASS(webkit_web_view_parent_class)->size_allocate(widget,allocation);
530
531     WebKitWebView* webView = WEBKIT_WEB_VIEW(widget);
532
533     Frame* frame = core(webView)->mainFrame();
534     if (!frame->view())
535         return;
536
537     frame->view()->resize(allocation->width, allocation->height);
538     frame->view()->forceLayout();
539     frame->view()->adjustViewSize();
540 }
541
542 static gboolean webkit_web_view_focus_in_event(GtkWidget* widget, GdkEventFocus* event)
543 {
544     // TODO: Improve focus handling as suggested in
545     // http://bugs.webkit.org/show_bug.cgi?id=16910
546     GtkWidget* toplevel = gtk_widget_get_toplevel(widget);
547     if (GTK_WIDGET_TOPLEVEL(toplevel) && gtk_window_has_toplevel_focus(GTK_WINDOW(toplevel))) {
548         WebKitWebView* webView = WEBKIT_WEB_VIEW(widget);
549
550         Frame* frame = core(webView)->mainFrame();
551         core(webView)->focusController()->setActive(frame);
552     }
553     return GTK_WIDGET_CLASS(webkit_web_view_parent_class)->focus_in_event(widget, event);
554 }
555
556 static gboolean webkit_web_view_focus_out_event(GtkWidget* widget, GdkEventFocus* event)
557 {
558     WebKitWebView* webView = WEBKIT_WEB_VIEW(widget);
559
560     core(webView)->focusController()->setActive(false);
561
562     return GTK_WIDGET_CLASS(webkit_web_view_parent_class)->focus_out_event(widget, event);
563 }
564
565 static void webkit_web_view_realize(GtkWidget* widget)
566 {
567     GTK_WIDGET_SET_FLAGS(widget, GTK_REALIZED);
568
569     GdkWindowAttr attributes;
570     attributes.window_type = GDK_WINDOW_CHILD;
571     attributes.x = widget->allocation.x;
572     attributes.y = widget->allocation.y;
573     attributes.width = widget->allocation.width;
574     attributes.height = widget->allocation.height;
575     attributes.wclass = GDK_INPUT_OUTPUT;
576     attributes.visual = gtk_widget_get_visual (widget);
577     attributes.colormap = gtk_widget_get_colormap (widget);
578     attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK
579                             | GDK_EXPOSURE_MASK
580                             | GDK_BUTTON_PRESS_MASK
581                             | GDK_BUTTON_RELEASE_MASK
582                             | GDK_POINTER_MOTION_MASK
583                             | GDK_KEY_PRESS_MASK
584                             | GDK_KEY_RELEASE_MASK
585                             | GDK_BUTTON_MOTION_MASK
586                             | GDK_BUTTON1_MOTION_MASK
587                             | GDK_BUTTON2_MOTION_MASK
588                             | GDK_BUTTON3_MOTION_MASK;
589
590     gint attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
591     widget->window = gdk_window_new(gtk_widget_get_parent_window (widget), &attributes, attributes_mask);
592     gdk_window_set_user_data(widget->window, widget);
593
594     widget->style = gtk_style_attach(widget->style, widget->window);
595     gdk_window_set_background(widget->window, &widget->style->base[GTK_WIDGET_STATE(widget)]);
596
597     WebKitWebView* webView = WEBKIT_WEB_VIEW(widget);
598     WebKitWebViewPrivate* priv = webView->priv;
599     gtk_im_context_set_client_window(priv->imContext, widget->window);
600 }
601
602 static void webkit_web_view_set_scroll_adjustments(WebKitWebView* webView, GtkAdjustment* hadj, GtkAdjustment* vadj)
603 {
604     if (!core(webView))
605         return;
606
607     FrameView* view = core(webkit_web_view_get_main_frame(webView))->view();
608
609     if (hadj)
610         g_object_ref(hadj);
611     if (vadj)
612         g_object_ref(vadj);
613
614     WebKitWebViewPrivate* priv = webView->priv;
615
616     if (priv->horizontalAdjustment)
617         g_object_unref(priv->horizontalAdjustment);
618     if (priv->verticalAdjustment)
619         g_object_unref(priv->verticalAdjustment);
620
621     priv->horizontalAdjustment = hadj;
622     priv->verticalAdjustment = vadj;
623
624     if (!view)
625         return;
626
627     view->setGtkAdjustments(hadj, vadj);
628 }
629
630 static void webkit_web_view_container_add(GtkContainer* container, GtkWidget* widget)
631 {
632     WebKitWebView* webView = WEBKIT_WEB_VIEW(container);
633     WebKitWebViewPrivate* priv = webView->priv;
634
635     priv->children.add(widget);
636     if (GTK_WIDGET_REALIZED(container))
637         gtk_widget_set_parent_window(widget, GTK_WIDGET(webView)->window);
638     gtk_widget_set_parent(widget, GTK_WIDGET(container));
639 }
640
641 static void webkit_web_view_container_remove(GtkContainer* container, GtkWidget* widget)
642 {
643     WebKitWebView* webView = WEBKIT_WEB_VIEW(container);
644     WebKitWebViewPrivate* priv = webView->priv;
645
646     if (priv->children.contains(widget)) {
647         gtk_widget_unparent(widget);
648         priv->children.remove(widget);
649     }
650 }
651
652 static void webkit_web_view_container_forall(GtkContainer* container, gboolean, GtkCallback callback, gpointer callbackData)
653 {
654     WebKitWebView* webView = WEBKIT_WEB_VIEW(container);
655     WebKitWebViewPrivate* priv = webView->priv;
656
657     HashSet<GtkWidget*> children = priv->children;
658     HashSet<GtkWidget*>::const_iterator end = children.end();
659     for (HashSet<GtkWidget*>::const_iterator current = children.begin(); current != end; ++current)
660         (*callback)(*current, callbackData);
661 }
662
663 static WebKitWebView* webkit_web_view_real_create_web_view(WebKitWebView*, WebKitWebFrame*)
664 {
665     return 0;
666 }
667
668 static gboolean webkit_web_view_real_web_view_ready(WebKitWebView*)
669 {
670     return FALSE;
671 }
672
673 static WebKitNavigationResponse webkit_web_view_real_navigation_requested(WebKitWebView*, WebKitWebFrame*, WebKitNetworkRequest*)
674 {
675     return WEBKIT_NAVIGATION_RESPONSE_ACCEPT;
676 }
677
678 static void webkit_web_view_real_window_object_cleared(WebKitWebView*, WebKitWebFrame*, JSGlobalContextRef context, JSObjectRef window_object)
679 {
680     notImplemented();
681 }
682
683 static gchar* webkit_web_view_real_choose_file(WebKitWebView*, WebKitWebFrame*, const gchar* old_name)
684 {
685     notImplemented();
686     return g_strdup(old_name);
687 }
688
689 typedef enum {
690     WEBKIT_SCRIPT_DIALOG_ALERT,
691     WEBKIT_SCRIPT_DIALOG_CONFIRM,
692     WEBKIT_SCRIPT_DIALOG_PROMPT
693  } WebKitScriptDialogType;
694
695 static gboolean webkit_web_view_script_dialog(WebKitWebView* webView, WebKitWebFrame* frame, const gchar* message, WebKitScriptDialogType type, const gchar* defaultValue, gchar** value)
696 {
697     GtkMessageType messageType;
698     GtkButtonsType buttons;
699     gint defaultResponse;
700     GtkWidget* window;
701     GtkWidget* dialog;
702     GtkWidget* entry = 0;
703     gboolean didConfirm = FALSE;
704
705     switch (type) {
706     case WEBKIT_SCRIPT_DIALOG_ALERT:
707         messageType = GTK_MESSAGE_WARNING;
708         buttons = GTK_BUTTONS_CLOSE;
709         defaultResponse = GTK_RESPONSE_CLOSE;
710         break;
711     case WEBKIT_SCRIPT_DIALOG_CONFIRM:
712         messageType = GTK_MESSAGE_QUESTION;
713         buttons = GTK_BUTTONS_YES_NO;
714         defaultResponse = GTK_RESPONSE_YES;
715         break;
716     case WEBKIT_SCRIPT_DIALOG_PROMPT:
717         messageType = GTK_MESSAGE_QUESTION;
718         buttons = GTK_BUTTONS_OK_CANCEL;
719         defaultResponse = GTK_RESPONSE_OK;
720         break;
721     default:
722         g_warning("Unknown value for WebKitScriptDialogType.");
723         return FALSE;
724     }
725
726     window = gtk_widget_get_toplevel(GTK_WIDGET(webView));
727     dialog = gtk_message_dialog_new(GTK_WIDGET_TOPLEVEL(window) ? GTK_WINDOW(window) : 0, GTK_DIALOG_DESTROY_WITH_PARENT, messageType, buttons, "%s", message);
728     gchar* title = g_strconcat("JavaScript - ", webkit_web_frame_get_uri(frame), NULL);
729     gtk_window_set_title(GTK_WINDOW(dialog), title);
730     g_free(title);
731
732     if (type == WEBKIT_SCRIPT_DIALOG_PROMPT) {
733         entry = gtk_entry_new();
734         gtk_entry_set_text(GTK_ENTRY(entry), defaultValue);
735         gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), entry);
736         gtk_entry_set_activates_default(GTK_ENTRY(entry), TRUE);
737         gtk_widget_show(entry);
738     }
739
740     gtk_dialog_set_default_response(GTK_DIALOG(dialog), defaultResponse);
741     gint response = gtk_dialog_run(GTK_DIALOG(dialog));
742
743     switch (response) {
744     case GTK_RESPONSE_YES:
745         didConfirm = TRUE;
746         break;
747     case GTK_RESPONSE_OK:
748         didConfirm = TRUE;
749         if (entry)
750             *value = g_strdup(gtk_entry_get_text(GTK_ENTRY(entry)));
751         else
752             *value = 0;
753         break;
754     case GTK_RESPONSE_NO:
755     case GTK_RESPONSE_CANCEL:
756         didConfirm = FALSE;
757         break;
758
759     }
760     gtk_widget_destroy(GTK_WIDGET(dialog));
761     return didConfirm;
762 }
763
764 static gboolean webkit_web_view_real_script_alert(WebKitWebView* webView, WebKitWebFrame* frame, const gchar* message)
765 {
766     webkit_web_view_script_dialog(webView, frame, message, WEBKIT_SCRIPT_DIALOG_ALERT, 0, 0);
767     return TRUE;
768 }
769
770 static gboolean webkit_web_view_real_script_confirm(WebKitWebView* webView, WebKitWebFrame* frame, const gchar* message, gboolean* didConfirm)
771 {
772     *didConfirm = webkit_web_view_script_dialog(webView, frame, message, WEBKIT_SCRIPT_DIALOG_CONFIRM, 0, 0);
773     return TRUE;
774 }
775
776 static gboolean webkit_web_view_real_script_prompt(WebKitWebView* webView, WebKitWebFrame* frame, const gchar* message, const gchar* defaultValue, gchar** value)
777 {
778     if (!webkit_web_view_script_dialog(webView, frame, message, WEBKIT_SCRIPT_DIALOG_PROMPT, defaultValue, value))
779         *value = NULL;
780     return TRUE;
781 }
782
783 static gboolean webkit_web_view_real_console_message(WebKitWebView* webView, const gchar* message, unsigned int line, const gchar* sourceId)
784 {
785     g_print("console message: %s @%d: %s\n", sourceId, line, message);
786     return TRUE;
787 }
788
789 static void webkit_web_view_real_select_all(WebKitWebView* webView)
790 {
791     Frame* frame = core(webView)->focusController()->focusedOrMainFrame();
792     frame->editor()->command("SelectAll").execute();
793 }
794
795 static void webkit_web_view_real_cut_clipboard(WebKitWebView* webView)
796 {
797     Frame* frame = core(webView)->focusController()->focusedOrMainFrame();
798     frame->editor()->command("Cut").execute();
799 }
800
801 static void webkit_web_view_real_copy_clipboard(WebKitWebView* webView)
802 {
803     Frame* frame = core(webView)->focusController()->focusedOrMainFrame();
804     frame->editor()->command("Copy").execute();
805 }
806
807 static void webkit_web_view_real_paste_clipboard(WebKitWebView* webView)
808 {
809     Frame* frame = core(webView)->focusController()->focusedOrMainFrame();
810     frame->editor()->command("Paste").execute();
811 }
812
813 static void webkit_web_view_dispose(GObject* object)
814 {
815     WebKitWebView* webView = WEBKIT_WEB_VIEW(object);
816     WebKitWebViewPrivate* priv = webView->priv;
817
818     if (priv->corePage) {
819         webkit_web_view_stop_loading(WEBKIT_WEB_VIEW(object));
820
821         core(priv->mainFrame)->loader()->detachChildren();
822         delete priv->corePage;
823         priv->corePage = NULL;
824     }
825
826     if (priv->horizontalAdjustment) {
827         g_object_unref(priv->horizontalAdjustment);
828         priv->horizontalAdjustment = NULL;
829     }
830
831     if (priv->verticalAdjustment) {
832         g_object_unref(priv->verticalAdjustment);
833         priv->verticalAdjustment = NULL;
834     }
835
836     if (priv->backForwardList) {
837         g_object_unref(priv->backForwardList);
838         priv->backForwardList = NULL;
839
840         g_signal_handlers_disconnect_by_func(priv->webSettings, (gpointer)webkit_web_view_settings_notify, webView);
841         g_object_unref(priv->webSettings);
842         priv->webSettings = NULL;
843
844         g_object_unref(priv->webInspector);
845         priv->webInspector = NULL;
846
847         g_object_unref(priv->webWindowFeatures);
848         priv->webWindowFeatures = NULL;
849
850         g_object_unref(priv->imContext);
851         priv->imContext = NULL;
852
853         gtk_target_list_unref(priv->copy_target_list);
854         priv->copy_target_list = NULL;
855
856         gtk_target_list_unref(priv->paste_target_list);
857         priv->paste_target_list = NULL;
858
859         delete priv->userAgent;
860         priv->userAgent = NULL;
861     }
862
863     G_OBJECT_CLASS(webkit_web_view_parent_class)->dispose(object);
864 }
865
866 static gboolean webkit_create_web_view_request_handled(GSignalInvocationHint* ihint, GValue* returnAccu, const GValue* handlerReturn, gpointer dummy)
867 {
868     gpointer newWebView = g_value_get_object(handlerReturn);
869     g_value_set_object(returnAccu, newWebView);
870
871     // Continue if we don't have a newWebView
872     return !newWebView;
873 }
874
875 static gboolean webkit_navigation_request_handled(GSignalInvocationHint* ihint, GValue* returnAccu, const GValue* handlerReturn, gpointer dummy)
876 {
877     WebKitNavigationResponse navigationResponse = (WebKitNavigationResponse)g_value_get_enum(handlerReturn);
878     g_value_set_enum(returnAccu, navigationResponse);
879
880     if (navigationResponse != WEBKIT_NAVIGATION_RESPONSE_ACCEPT)
881         return FALSE;
882
883     return TRUE;
884 }
885
886 static AtkObject* webkit_web_view_get_accessible(GtkWidget* widget)
887 {
888     WebKitWebView* webView = WEBKIT_WEB_VIEW(widget);
889     if (!core(webView))
890         return NULL;
891
892     AXObjectCache::enableAccessibility();
893
894     Frame* coreFrame = core(webView)->mainFrame();
895     if (!coreFrame)
896         return NULL;
897
898     Document* doc = coreFrame->document();
899     if (!doc)
900         return NULL;
901
902     AccessibilityObject* coreAccessible = doc->axObjectCache()->get(doc->renderer());
903     if (!coreAccessible || !coreAccessible->wrapper())
904         return NULL;
905
906     return coreAccessible->wrapper();
907 }
908
909 static void webkit_web_view_class_init(WebKitWebViewClass* webViewClass)
910 {
911     GtkBindingSet* binding_set;
912
913     webkit_init();
914
915     /*
916      * Signals
917      */
918
919     /**
920      * WebKitWebView::create-web-view:
921      * @web_view: the object on which the signal is emitted
922      * @frame: the #WebKitWebFrame
923      * @return: a newly allocated #WebKitWebView or %NULL
924      *
925      * Emitted when the creation of a new window is requested.
926      * If this signal is handled the signal handler should return the
927      * newly created #WebKitWebView.
928      *
929      * The new #WebKitWebView should not be displayed to the user
930      * until the #WebKitWebView::web-view-ready signal is emitted.
931      *
932      * The signal handlers should not try to deal with the reference
933      * count for the new #WebKitWebView. The widget to which the
934      * widget is added will handle that.
935      *
936      * Since 1.0.3
937      */
938     webkit_web_view_signals[CREATE_WEB_VIEW] = g_signal_new("create-web-view",
939             G_TYPE_FROM_CLASS(webViewClass),
940             (GSignalFlags)(G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION),
941             G_STRUCT_OFFSET (WebKitWebViewClass, create_web_view),
942             webkit_create_web_view_request_handled,
943             NULL,
944             webkit_marshal_OBJECT__OBJECT,
945             WEBKIT_TYPE_WEB_VIEW , 1,
946             WEBKIT_TYPE_WEB_FRAME);
947
948     /**
949      * WebKitWebView::web-view-ready:
950      * @web_view: the object on which the signal is emitted
951      * @return: %TRUE to stop other handlers from being invoked for
952      * the event, %FALSE to propagate the event further
953      *
954      * Emitted after #WebKitWebView::create-web-view when the new #WebKitWebView
955      * should be displayed to the user. When this signal is emitted
956      * all the information about how the window should look, including
957      * size, position, whether the location, status and scroll bars
958      * should be displayed, is already set on the
959      * #WebKitWebWindowFeatures object contained by the #WebKitWebView.
960      *
961      * Notice that some of that information may change during the life
962      * time of the window, so you may want to connect to the ::notify
963      * signal of the #WebKitWebWindowFeatures object to handle those.
964      *
965      * Since 1.0.3
966      */
967     webkit_web_view_signals[WEB_VIEW_READY] = g_signal_new("web-view-ready",
968             G_TYPE_FROM_CLASS(webViewClass),
969             (GSignalFlags)(G_SIGNAL_RUN_LAST),
970             G_STRUCT_OFFSET (WebKitWebViewClass, web_view_ready),
971             g_signal_accumulator_true_handled,
972             NULL,
973             webkit_marshal_BOOLEAN__VOID,
974             G_TYPE_BOOLEAN, 0);
975
976     /**
977      * WebKitWebView::navigation-requested:
978      * @web_view: the object on which the signal is emitted
979      * @frame: the #WebKitWebFrame that required the navigation
980      * @request: a #WebKitNetworkRequest
981      * @return: a WebKitNavigationResponse
982      *
983      * Emitted when @frame requests a navigation to another page.
984      *
985      * Deprecated: Use WebKitWebView::navigation-policy-decision-requested
986      * instead
987      */
988     webkit_web_view_signals[NAVIGATION_REQUESTED] = g_signal_new("navigation-requested",
989             G_TYPE_FROM_CLASS(webViewClass),
990             (GSignalFlags)(G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION),
991             G_STRUCT_OFFSET (WebKitWebViewClass, navigation_requested),
992             webkit_navigation_request_handled,
993             NULL,
994             webkit_marshal_ENUM__OBJECT_OBJECT,
995             WEBKIT_TYPE_NAVIGATION_RESPONSE, 2,
996             WEBKIT_TYPE_WEB_FRAME,
997             WEBKIT_TYPE_NETWORK_REQUEST);
998
999     /**
1000      * WebKitWebView::navigation-policy-decision-requested:
1001      * @web_view: the object on which the signal is emitted
1002      * @frame: the #WebKitWebFrame that required the navigation
1003      * @request: a #WebKitNetworkRequest
1004      * @navigation_action: a #WebKitWebNavigation
1005      * @policy_decision: a #WebKitWebPolicyDecision
1006      * @return: TRUE if the signal will be handled, FALSE to have the
1007      *          default behavior apply
1008      *
1009      * Emitted when @frame requests a navigation to another page.
1010      * If this signal is not handled, the default behavior is to allow the
1011      * navigation.
1012      *
1013      * Since: 1.0.3
1014      */
1015     webkit_web_view_signals[NAVIGATION_POLICY_DECISION_REQUESTED] = g_signal_new("navigation-policy-decision-requested",
1016             G_TYPE_FROM_CLASS(webViewClass),
1017             (GSignalFlags)(G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION),
1018             0,
1019             g_signal_accumulator_true_handled,
1020             NULL,
1021             webkit_marshal_BOOLEAN__OBJECT_OBJECT_OBJECT_OBJECT,
1022             G_TYPE_BOOLEAN, 4,
1023             WEBKIT_TYPE_WEB_FRAME,
1024             WEBKIT_TYPE_NETWORK_REQUEST,
1025             WEBKIT_TYPE_WEB_NAVIGATION_ACTION,
1026             WEBKIT_TYPE_WEB_POLICY_DECISION);
1027
1028     /**
1029      * WebKitWebView::mime-type-policy-decision-requested:
1030      * @web_view: the object on which the signal is emitted
1031      * @frame: the #WebKitWebFrame that required the policy decision
1032      * @request: a WebKitNetworkRequest
1033      * @mimetype: the MIME type attempted to load
1034      * @policy_decision: a #WebKitWebPolicyDecision
1035      * @return: TRUE if the signal will be handled, FALSE to have the
1036      *          default behavior apply
1037      *
1038      * Decide whether or not to display the given MIME type.  If this
1039      * signal is not handled, the default behavior is to show the
1040      * content of the requested URI if WebKit can show this MIME
1041      * type; if WebKit is not able to show the MIME type nothing
1042      * happens.
1043      *
1044      * Since: 1.0.3
1045      */
1046     webkit_web_view_signals[MIME_TYPE_POLICY_DECISION_REQUESTED] = g_signal_new("mime-type-policy-decision-requested",
1047             G_TYPE_FROM_CLASS(webViewClass),
1048             (GSignalFlags)(G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION),
1049             0,
1050             g_signal_accumulator_true_handled,
1051             NULL,
1052             webkit_marshal_BOOLEAN__OBJECT_OBJECT_STRING_OBJECT,
1053             G_TYPE_BOOLEAN, 4,
1054             WEBKIT_TYPE_WEB_FRAME,
1055             WEBKIT_TYPE_NETWORK_REQUEST,
1056             G_TYPE_STRING,
1057             WEBKIT_TYPE_WEB_POLICY_DECISION);
1058
1059     /**
1060      * WebKitWebView::window-object-cleared:
1061      * @web_view: the object on which the signal is emitted
1062      * @frame: the #WebKitWebFrame to which @window_object belongs
1063      * @context: the #JSGlobalContextRef holding the global object and other
1064      * execution state; equivalent to the return value of
1065      * webkit_web_frame_get_global_context(@frame)
1066      *
1067      * @window_object: the #JSObjectRef representing the frame's JavaScript
1068      * window object
1069      *
1070      * Emitted when the JavaScript window object in a #WebKitWebFrame has been
1071      * cleared in preparation for a new load. This is the preferred place to
1072      * set custom properties on the window object using the JavaScriptCore API.
1073      */
1074     webkit_web_view_signals[WINDOW_OBJECT_CLEARED] = g_signal_new("window-object-cleared",
1075             G_TYPE_FROM_CLASS(webViewClass),
1076             (GSignalFlags)(G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION),
1077             G_STRUCT_OFFSET (WebKitWebViewClass, window_object_cleared),
1078             NULL,
1079             NULL,
1080             webkit_marshal_VOID__OBJECT_POINTER_POINTER,
1081             G_TYPE_NONE, 3,
1082             WEBKIT_TYPE_WEB_FRAME,
1083             G_TYPE_POINTER,
1084             G_TYPE_POINTER);
1085
1086     /**
1087      * WebKitWebView::load-started:
1088      * @web_view: the object on which the signal is emitted
1089      * @frame: the frame going to do the load
1090      *
1091      * When a #WebKitWebFrame begins to load this signal is emitted.
1092      */
1093     webkit_web_view_signals[LOAD_STARTED] = g_signal_new("load-started",
1094             G_TYPE_FROM_CLASS(webViewClass),
1095             (GSignalFlags)(G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION),
1096             0,
1097             NULL,
1098             NULL,
1099             g_cclosure_marshal_VOID__OBJECT,
1100             G_TYPE_NONE, 1,
1101             WEBKIT_TYPE_WEB_FRAME);
1102
1103     /**
1104      * WebKitWebView::load-committed:
1105      * @web_view: the object on which the signal is emitted
1106      * @frame: the main frame that received the first data
1107      *
1108      * When a #WebKitWebFrame loaded the first data this signal is emitted.
1109      */
1110     webkit_web_view_signals[LOAD_COMMITTED] = g_signal_new("load-committed",
1111             G_TYPE_FROM_CLASS(webViewClass),
1112             (GSignalFlags)(G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION),
1113             0,
1114             NULL,
1115             NULL,
1116             g_cclosure_marshal_VOID__OBJECT,
1117             G_TYPE_NONE, 1,
1118             WEBKIT_TYPE_WEB_FRAME);
1119
1120
1121     /**
1122      * WebKitWebView::load-progress-changed:
1123      * @web_view: the #WebKitWebView
1124      * @progress: the global progress
1125      */
1126     webkit_web_view_signals[LOAD_PROGRESS_CHANGED] = g_signal_new("load-progress-changed",
1127             G_TYPE_FROM_CLASS(webViewClass),
1128             (GSignalFlags)(G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION),
1129             0,
1130             NULL,
1131             NULL,
1132             g_cclosure_marshal_VOID__INT,
1133             G_TYPE_NONE, 1,
1134             G_TYPE_INT);
1135
1136     webkit_web_view_signals[LOAD_FINISHED] = g_signal_new("load-finished",
1137             G_TYPE_FROM_CLASS(webViewClass),
1138             (GSignalFlags)(G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION),
1139             0,
1140             NULL,
1141             NULL,
1142             g_cclosure_marshal_VOID__OBJECT,
1143             G_TYPE_NONE, 1,
1144             WEBKIT_TYPE_WEB_FRAME);
1145
1146     /**
1147      * WebKitWebView::title-changed:
1148      * @web_view: the object on which the signal is emitted
1149      * @frame: the main frame
1150      * @title: the new title
1151      *
1152      * When a #WebKitWebFrame changes the document title this signal is emitted.
1153      */
1154     webkit_web_view_signals[TITLE_CHANGED] = g_signal_new("title-changed",
1155             G_TYPE_FROM_CLASS(webViewClass),
1156             (GSignalFlags)(G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION),
1157             0,
1158             NULL,
1159             NULL,
1160             webkit_marshal_VOID__OBJECT_STRING,
1161             G_TYPE_NONE, 2,
1162             WEBKIT_TYPE_WEB_FRAME,
1163             G_TYPE_STRING);
1164
1165     /**
1166      * WebKitWebView::hovering-over-link:
1167      * @web_view: the object on which the signal is emitted
1168      * @title: the link's title
1169      * @uri: the URI the link points to
1170      *
1171      * When the cursor is over a link, this signal is emitted.
1172      */
1173     webkit_web_view_signals[HOVERING_OVER_LINK] = g_signal_new("hovering-over-link",
1174             G_TYPE_FROM_CLASS(webViewClass),
1175             (GSignalFlags)(G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION),
1176             0,
1177             NULL,
1178             NULL,
1179             webkit_marshal_VOID__STRING_STRING,
1180             G_TYPE_NONE, 2,
1181             G_TYPE_STRING,
1182             G_TYPE_STRING);
1183
1184     /**
1185      * WebKitWebView::populate-popup:
1186      * @web_view: the object on which the signal is emitted
1187      * @menu: the context menu
1188      *
1189      * When a context menu is about to be displayed this signal is emitted.
1190      *
1191      * Add menu items to #menu to extend the context menu.
1192      */
1193     webkit_web_view_signals[POPULATE_POPUP] = g_signal_new("populate-popup",
1194             G_TYPE_FROM_CLASS(webViewClass),
1195             (GSignalFlags)(G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION),
1196             0,
1197             NULL,
1198             NULL,
1199             g_cclosure_marshal_VOID__OBJECT,
1200             G_TYPE_NONE, 1,
1201             GTK_TYPE_MENU);
1202
1203     webkit_web_view_signals[STATUS_BAR_TEXT_CHANGED] = g_signal_new("status-bar-text-changed",
1204             G_TYPE_FROM_CLASS(webViewClass),
1205             (GSignalFlags)(G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION),
1206             0,
1207             NULL,
1208             NULL,
1209             g_cclosure_marshal_VOID__STRING,
1210             G_TYPE_NONE, 1,
1211             G_TYPE_STRING);
1212
1213     webkit_web_view_signals[ICOND_LOADED] = g_signal_new("icon-loaded",
1214             G_TYPE_FROM_CLASS(webViewClass),
1215             (GSignalFlags)(G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION),
1216             0,
1217             NULL,
1218             NULL,
1219             g_cclosure_marshal_VOID__VOID,
1220             G_TYPE_NONE, 0);
1221
1222     webkit_web_view_signals[SELECTION_CHANGED] = g_signal_new("selection-changed",
1223             G_TYPE_FROM_CLASS(webViewClass),
1224             (GSignalFlags)(G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION),
1225             0,
1226             NULL,
1227             NULL,
1228             g_cclosure_marshal_VOID__VOID,
1229             G_TYPE_NONE, 0);
1230
1231     /**
1232      * WebKitWebView::console-message:
1233      * @web_view: the object on which the signal is emitted
1234      * @message: the message text
1235      * @line: the line where the error occured
1236      * @source_id: the source id
1237      * @return: TRUE to stop other handlers from being invoked for the event. FALSE to propagate the event further.
1238      *
1239      * A JavaScript console message was created.
1240      */
1241     webkit_web_view_signals[CONSOLE_MESSAGE] = g_signal_new("console-message",
1242             G_TYPE_FROM_CLASS(webViewClass),
1243             (GSignalFlags)(G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION),
1244             G_STRUCT_OFFSET(WebKitWebViewClass, console_message),
1245             g_signal_accumulator_true_handled,
1246             NULL,
1247             webkit_marshal_BOOLEAN__STRING_INT_STRING,
1248             G_TYPE_BOOLEAN, 3,
1249             G_TYPE_STRING, G_TYPE_INT, G_TYPE_STRING);
1250
1251     /**
1252      * WebKitWebView::script-alert:
1253      * @web_view: the object on which the signal is emitted
1254      * @frame: the relevant frame
1255      * @message: the message text
1256      * @return: TRUE to stop other handlers from being invoked for the event. FALSE to propagate the event further.
1257      *
1258      * A JavaScript alert dialog was created.
1259      */
1260     webkit_web_view_signals[SCRIPT_ALERT] = g_signal_new("script-alert",
1261             G_TYPE_FROM_CLASS(webViewClass),
1262             (GSignalFlags)(G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION),
1263             G_STRUCT_OFFSET(WebKitWebViewClass, script_alert),
1264             g_signal_accumulator_true_handled,
1265             NULL,
1266             webkit_marshal_BOOLEAN__OBJECT_STRING,
1267             G_TYPE_BOOLEAN, 2,
1268             WEBKIT_TYPE_WEB_FRAME, G_TYPE_STRING);
1269
1270     /**
1271      * WebKitWebView::script-confirm:
1272      * @web_view: the object on which the signal is emitted
1273      * @frame: the relevant frame
1274      * @message: the message text
1275      * @confirmed: whether the dialog has been confirmed
1276      * @return: TRUE to stop other handlers from being invoked for the event. FALSE to propagate the event further.
1277      *
1278      * A JavaScript confirm dialog was created, providing Yes and No buttons.
1279      */
1280     webkit_web_view_signals[SCRIPT_CONFIRM] = g_signal_new("script-confirm",
1281             G_TYPE_FROM_CLASS(webViewClass),
1282             (GSignalFlags)(G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION),
1283             G_STRUCT_OFFSET(WebKitWebViewClass, script_confirm),
1284             g_signal_accumulator_true_handled,
1285             NULL,
1286             webkit_marshal_BOOLEAN__OBJECT_STRING_BOOLEAN,
1287             G_TYPE_BOOLEAN, 3,
1288             WEBKIT_TYPE_WEB_FRAME, G_TYPE_STRING, G_TYPE_BOOLEAN);
1289
1290     /**
1291      * WebKitWebView::script-prompt:
1292      * @web_view: the object on which the signal is emitted
1293      * @frame: the relevant frame
1294      * @message: the message text
1295      * @default: the default value
1296      * @text: To be filled with the return value or NULL if the dialog was cancelled.
1297      * @return: TRUE to stop other handlers from being invoked for the event. FALSE to propagate the event further.
1298      *
1299      * A JavaScript prompt dialog was created, providing an entry to input text.
1300      */
1301     webkit_web_view_signals[SCRIPT_PROMPT] = g_signal_new("script-prompt",
1302             G_TYPE_FROM_CLASS(webViewClass),
1303             (GSignalFlags)(G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION),
1304             G_STRUCT_OFFSET(WebKitWebViewClass, script_prompt),
1305             g_signal_accumulator_true_handled,
1306             NULL,
1307             webkit_marshal_BOOLEAN__OBJECT_STRING_STRING_STRING,
1308             G_TYPE_BOOLEAN, 4,
1309             WEBKIT_TYPE_WEB_FRAME, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_POINTER);
1310
1311     /**
1312      * WebKitWebView::select-all:
1313      * @web_view: the object which received the signal
1314      *
1315      * The #WebKitWebView::select-all signal is a keybinding signal which gets emitted to
1316      * select the complete contents of the text view.
1317      *
1318      * The default bindings for this signal is Ctrl-a.
1319      */
1320     webkit_web_view_signals[SELECT_ALL] = g_signal_new("select-all",
1321             G_TYPE_FROM_CLASS(webViewClass),
1322             (GSignalFlags)(G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION),
1323             G_STRUCT_OFFSET(WebKitWebViewClass, select_all),
1324             NULL, NULL,
1325             g_cclosure_marshal_VOID__VOID,
1326             G_TYPE_NONE, 0);
1327
1328     /**
1329      * WebKitWebView::cut-clipboard:
1330      * @web_view: the object which received the signal
1331      *
1332      * The #WebKitWebView::cut-clipboard signal is a keybinding signal which gets emitted to
1333      * cut the selection to the clipboard.
1334      *
1335      * The default bindings for this signal are Ctrl-x and Shift-Delete.
1336      */
1337     webkit_web_view_signals[CUT_CLIPBOARD] = g_signal_new("cut-clipboard",
1338             G_TYPE_FROM_CLASS(webViewClass),
1339             (GSignalFlags)(G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION),
1340             G_STRUCT_OFFSET(WebKitWebViewClass, cut_clipboard),
1341             NULL, NULL,
1342             g_cclosure_marshal_VOID__VOID,
1343             G_TYPE_NONE, 0);
1344
1345     /**
1346      * WebKitWebView::copy-clipboard:
1347      * @web_view: the object which received the signal
1348      *
1349      * The #WebKitWebView::copy-clipboard signal is a keybinding signal which gets emitted to
1350      * copy the selection to the clipboard.
1351      *
1352      * The default bindings for this signal are Ctrl-c and Ctrl-Insert.
1353      */
1354     webkit_web_view_signals[COPY_CLIPBOARD] = g_signal_new("copy-clipboard",
1355             G_TYPE_FROM_CLASS(webViewClass),
1356             (GSignalFlags)(G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION),
1357             G_STRUCT_OFFSET(WebKitWebViewClass, copy_clipboard),
1358             NULL, NULL,
1359             g_cclosure_marshal_VOID__VOID,
1360             G_TYPE_NONE, 0);
1361
1362     /**
1363      * WebKitWebView::paste-clipboard:
1364      * @web_view: the object which received the signal
1365      *
1366      * The #WebKitWebView::paste-clipboard signal is a keybinding signal which gets emitted to
1367      * paste the contents of the clipboard into the Web view.
1368      *
1369      * The default bindings for this signal are Ctrl-v and Shift-Insert.
1370      */
1371     webkit_web_view_signals[PASTE_CLIPBOARD] = g_signal_new("paste-clipboard",
1372             G_TYPE_FROM_CLASS(webViewClass),
1373             (GSignalFlags)(G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION),
1374             G_STRUCT_OFFSET(WebKitWebViewClass, paste_clipboard),
1375             NULL, NULL,
1376             g_cclosure_marshal_VOID__VOID,
1377             G_TYPE_NONE, 0);
1378
1379     /*
1380      * implementations of virtual methods
1381      */
1382     webViewClass->create_web_view = webkit_web_view_real_create_web_view;
1383     webViewClass->web_view_ready = webkit_web_view_real_web_view_ready;
1384     webViewClass->navigation_requested = webkit_web_view_real_navigation_requested;
1385     webViewClass->window_object_cleared = webkit_web_view_real_window_object_cleared;
1386     webViewClass->choose_file = webkit_web_view_real_choose_file;
1387     webViewClass->script_alert = webkit_web_view_real_script_alert;
1388     webViewClass->script_confirm = webkit_web_view_real_script_confirm;
1389     webViewClass->script_prompt = webkit_web_view_real_script_prompt;
1390     webViewClass->console_message = webkit_web_view_real_console_message;
1391     webViewClass->select_all = webkit_web_view_real_select_all;
1392     webViewClass->cut_clipboard = webkit_web_view_real_cut_clipboard;
1393     webViewClass->copy_clipboard = webkit_web_view_real_copy_clipboard;
1394     webViewClass->paste_clipboard = webkit_web_view_real_paste_clipboard;
1395
1396     GObjectClass* objectClass = G_OBJECT_CLASS(webViewClass);
1397     objectClass->dispose = webkit_web_view_dispose;
1398     objectClass->get_property = webkit_web_view_get_property;
1399     objectClass->set_property = webkit_web_view_set_property;
1400
1401     GtkWidgetClass* widgetClass = GTK_WIDGET_CLASS(webViewClass);
1402     widgetClass->realize = webkit_web_view_realize;
1403     widgetClass->expose_event = webkit_web_view_expose_event;
1404     widgetClass->key_press_event = webkit_web_view_key_press_event;
1405     widgetClass->key_release_event = webkit_web_view_key_release_event;
1406     widgetClass->button_press_event = webkit_web_view_button_press_event;
1407     widgetClass->button_release_event = webkit_web_view_button_release_event;
1408     widgetClass->motion_notify_event = webkit_web_view_motion_event;
1409     widgetClass->scroll_event = webkit_web_view_scroll_event;
1410     widgetClass->size_allocate = webkit_web_view_size_allocate;
1411     widgetClass->popup_menu = webkit_web_view_popup_menu_handler;
1412     widgetClass->focus_in_event = webkit_web_view_focus_in_event;
1413     widgetClass->focus_out_event = webkit_web_view_focus_out_event;
1414     widgetClass->get_accessible = webkit_web_view_get_accessible;
1415
1416     GtkContainerClass* containerClass = GTK_CONTAINER_CLASS(webViewClass);
1417     containerClass->add = webkit_web_view_container_add;
1418     containerClass->remove = webkit_web_view_container_remove;
1419     containerClass->forall = webkit_web_view_container_forall;
1420
1421     /*
1422      * make us scrollable (e.g. addable to a GtkScrolledWindow)
1423      */
1424     webViewClass->set_scroll_adjustments = webkit_web_view_set_scroll_adjustments;
1425     GTK_WIDGET_CLASS(webViewClass)->set_scroll_adjustments_signal = g_signal_new("set-scroll-adjustments",
1426             G_TYPE_FROM_CLASS(webViewClass),
1427             (GSignalFlags)(G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION),
1428             G_STRUCT_OFFSET(WebKitWebViewClass, set_scroll_adjustments),
1429             NULL, NULL,
1430             webkit_marshal_VOID__OBJECT_OBJECT,
1431             G_TYPE_NONE, 2,
1432             GTK_TYPE_ADJUSTMENT, GTK_TYPE_ADJUSTMENT);
1433
1434     /*
1435      * Key bindings
1436      */
1437
1438     binding_set = gtk_binding_set_by_class(webViewClass);
1439
1440     gtk_binding_entry_add_signal(binding_set, GDK_a, GDK_CONTROL_MASK,
1441                                  "select_all", 0);
1442
1443     /* Cut/copy/paste */
1444
1445     gtk_binding_entry_add_signal(binding_set, GDK_x, GDK_CONTROL_MASK,
1446                                  "cut_clipboard", 0);
1447     gtk_binding_entry_add_signal(binding_set, GDK_c, GDK_CONTROL_MASK,
1448                                  "copy_clipboard", 0);
1449     gtk_binding_entry_add_signal(binding_set, GDK_v, GDK_CONTROL_MASK,
1450                                  "paste_clipboard", 0);
1451
1452     gtk_binding_entry_add_signal(binding_set, GDK_Delete, GDK_SHIFT_MASK,
1453                                  "cut_clipboard", 0);
1454     gtk_binding_entry_add_signal(binding_set, GDK_Insert, GDK_CONTROL_MASK,
1455                                  "copy_clipboard", 0);
1456     gtk_binding_entry_add_signal(binding_set, GDK_Insert, GDK_SHIFT_MASK,
1457                                  "paste_clipboard", 0);
1458
1459     /*
1460      * properties
1461      */
1462
1463 #if GTK_CHECK_VERSION(2,10,0)
1464     /**
1465     * WebKitWebView:copy-target-list:
1466     *
1467     * The list of targets this web view supports for clipboard copying.
1468     *
1469     * Since: 1.0.2
1470     */
1471     g_object_class_install_property(objectClass, PROP_COPY_TARGET_LIST,
1472                                     g_param_spec_boxed("copy-target-list",
1473                                                        "Copy target list",
1474                                                        "The list of targets this web view supports for clipboard copying",
1475                                                        GTK_TYPE_TARGET_LIST,
1476                                                        WEBKIT_PARAM_READABLE));
1477
1478     /**
1479     * WebKitWebView:paste-target-list:
1480     *
1481     * The list of targets this web view supports for clipboard pasting.
1482     *
1483     * Since: 1.0.2
1484     */
1485     g_object_class_install_property(objectClass, PROP_PASTE_TARGET_LIST,
1486                                     g_param_spec_boxed("paste-target-list",
1487                                                        "Paste target list",
1488                                                        "The list of targets this web view supports for clipboard pasting",
1489                                                        GTK_TYPE_TARGET_LIST,
1490                                                        WEBKIT_PARAM_READABLE));
1491 #endif
1492
1493     g_object_class_install_property(objectClass, PROP_SETTINGS,
1494                                     g_param_spec_object("settings",
1495                                                         "Settings",
1496                                                         "An associated WebKitWebSettings instance",
1497                                                         WEBKIT_TYPE_WEB_SETTINGS,
1498                                                         WEBKIT_PARAM_READWRITE));
1499
1500     /**
1501     * WebKitWebView:web-inspector:
1502     *
1503     * The associated WebKitWebInspector instance.
1504     *
1505     * Since: 1.0.3
1506     */
1507     g_object_class_install_property(objectClass, PROP_WEB_INSPECTOR,
1508                                     g_param_spec_object("web-inspector",
1509                                                         "Web Inspector",
1510                                                         "The associated WebKitWebInspector instance",
1511                                                         WEBKIT_TYPE_WEB_INSPECTOR,
1512                                                         WEBKIT_PARAM_READABLE));
1513
1514     /**
1515     * WebKitWebView:window-features:
1516     *
1517     * An associated WebKitWebWindowFeatures instance.
1518     *
1519     * Since: 1.0.3
1520     */
1521     g_object_class_install_property(objectClass, PROP_WINDOW_FEATURES,
1522                                     g_param_spec_object("window-features",
1523                                                         "Window Features",
1524                                                         "An associated WebKitWebWindowFeatures instance",
1525                                                         WEBKIT_TYPE_WEB_WINDOW_FEATURES,
1526                                                         WEBKIT_PARAM_READWRITE));
1527
1528     g_object_class_install_property(objectClass, PROP_EDITABLE,
1529                                     g_param_spec_boolean("editable",
1530                                                          "Editable",
1531                                                          "Whether content can be modified by the user",
1532                                                          FALSE,
1533                                                          WEBKIT_PARAM_READWRITE));
1534
1535     g_object_class_install_property(objectClass, PROP_TRANSPARENT,
1536                                     g_param_spec_boolean("transparent",
1537                                                          "Transparent",
1538                                                          "Whether content has a transparent background",
1539                                                          FALSE,
1540                                                          WEBKIT_PARAM_READWRITE));
1541
1542     /**
1543     * WebKitWebView:zoom-level:
1544     *
1545     * The level of zoom of the content.
1546     *
1547     * Since: 1.0.1
1548     */
1549     g_object_class_install_property(objectClass, PROP_ZOOM_LEVEL,
1550                                     g_param_spec_float("zoom-level",
1551                                                        "Zoom level",
1552                                                        "The level of zoom of the content",
1553                                                        G_MINFLOAT,
1554                                                        G_MAXFLOAT,
1555                                                        1.0f,
1556                                                        WEBKIT_PARAM_READWRITE));
1557
1558     /**
1559     * WebKitWebView:full-content-zoom:
1560     *
1561     * Whether the full content is scaled when zooming.
1562     *
1563     * Since: 1.0.1
1564     */
1565     g_object_class_install_property(objectClass, PROP_FULL_CONTENT_ZOOM,
1566                                     g_param_spec_boolean("full-content-zoom",
1567                                                          "Full content zoom",
1568                                                          "Whether the full content is scaled when zooming",
1569                                                          FALSE,
1570                                                          WEBKIT_PARAM_READWRITE));
1571
1572     g_type_class_add_private(webViewClass, sizeof(WebKitWebViewPrivate));
1573 }
1574
1575 static gdouble webViewGetDPI(WebKitWebView* webView)
1576 {
1577     WebKitWebViewPrivate* priv = webView->priv;
1578     WebKitWebSettings* webSettings = priv->webSettings;
1579     gboolean enforce96DPI;
1580     g_object_get(webSettings, "enforce-96-dpi", &enforce96DPI, NULL);
1581     if (enforce96DPI)
1582         return 96.0;
1583
1584     gdouble DPI = defaultDPI;
1585 #if GTK_CHECK_VERSION(2,10,0)
1586     GdkScreen* screen = gtk_widget_has_screen(GTK_WIDGET(webView)) ? gtk_widget_get_screen(GTK_WIDGET(webView)) : gdk_screen_get_default();
1587     if (screen) {
1588         DPI = gdk_screen_get_resolution(screen);
1589         // gdk_screen_get_resolution() returns -1 when no DPI is set.
1590         if (DPI == -1)
1591             DPI = defaultDPI;
1592     }
1593 #endif
1594     ASSERT(DPI > 0);
1595     return DPI;
1596 }
1597
1598 static void webkit_web_view_screen_changed(WebKitWebView* webView, GdkScreen* previousScreen, gpointer userdata)
1599 {
1600     WebKitWebViewPrivate* priv = webView->priv;
1601     WebKitWebSettings* webSettings = priv->webSettings;
1602     Settings* settings = core(webView)->settings();
1603     gdouble DPI = webViewGetDPI(webView);
1604
1605     guint defaultFontSize, defaultMonospaceFontSize, minimumFontSize, minimumLogicalFontSize;
1606
1607     g_object_get(webSettings,
1608                  "default-font-size", &defaultFontSize,
1609                  "default-monospace-font-size", &defaultMonospaceFontSize,
1610                  "minimum-font-size", &minimumFontSize,
1611                  "minimum-logical-font-size", &minimumLogicalFontSize,
1612                  NULL);
1613
1614     settings->setDefaultFontSize(defaultFontSize / 72.0 * DPI);
1615     settings->setDefaultFixedFontSize(defaultMonospaceFontSize / 72.0 * DPI);
1616     settings->setMinimumFontSize(minimumFontSize / 72.0 * DPI);
1617     settings->setMinimumLogicalFontSize(minimumLogicalFontSize / 72.0 * DPI);
1618 }
1619
1620 static void webkit_web_view_update_settings(WebKitWebView* webView)
1621 {
1622     WebKitWebViewPrivate* priv = webView->priv;
1623     WebKitWebSettings* webSettings = priv->webSettings;
1624     Settings* settings = core(webView)->settings();
1625
1626     gchar* defaultEncoding, *cursiveFontFamily, *defaultFontFamily, *fantasyFontFamily, *monospaceFontFamily, *sansSerifFontFamily, *serifFontFamily, *userStylesheetUri;
1627     gboolean autoLoadImages, autoShrinkImages, printBackgrounds, enableScripts, enablePlugins, enableDeveloperExtras, resizableTextAreas;
1628
1629     g_object_get(webSettings,
1630                  "default-encoding", &defaultEncoding,
1631                  "cursive-font-family", &cursiveFontFamily,
1632                  "default-font-family", &defaultFontFamily,
1633                  "fantasy-font-family", &fantasyFontFamily,
1634                  "monospace-font-family", &monospaceFontFamily,
1635                  "sans-serif-font-family", &sansSerifFontFamily,
1636                  "serif-font-family", &serifFontFamily,
1637                  "auto-load-images", &autoLoadImages,
1638                  "auto-shrink-images", &autoShrinkImages,
1639                  "print-backgrounds", &printBackgrounds,
1640                  "enable-scripts", &enableScripts,
1641                  "enable-plugins", &enablePlugins,
1642                  "resizable-text-areas", &resizableTextAreas,
1643                  "user-stylesheet-uri", &userStylesheetUri,
1644                  "enable-developer-extras", &enableDeveloperExtras,
1645                  NULL);
1646
1647     settings->setDefaultTextEncodingName(defaultEncoding);
1648     settings->setCursiveFontFamily(cursiveFontFamily);
1649     settings->setStandardFontFamily(defaultFontFamily);
1650     settings->setFantasyFontFamily(fantasyFontFamily);
1651     settings->setFixedFontFamily(monospaceFontFamily);
1652     settings->setSansSerifFontFamily(sansSerifFontFamily);
1653     settings->setSerifFontFamily(serifFontFamily);
1654     settings->setLoadsImagesAutomatically(autoLoadImages);
1655     settings->setShrinksStandaloneImagesToFit(autoShrinkImages);
1656     settings->setShouldPrintBackgrounds(printBackgrounds);
1657     settings->setJavaScriptEnabled(enableScripts);
1658     settings->setPluginsEnabled(enablePlugins);
1659     settings->setTextAreasAreResizable(resizableTextAreas);
1660     settings->setUserStyleSheetLocation(KURL(KURL(), userStylesheetUri));
1661     settings->setDeveloperExtrasEnabled(enableDeveloperExtras);
1662
1663     g_free(defaultEncoding);
1664     g_free(cursiveFontFamily);
1665     g_free(defaultFontFamily);
1666     g_free(fantasyFontFamily);
1667     g_free(monospaceFontFamily);
1668     g_free(sansSerifFontFamily);
1669     g_free(serifFontFamily);
1670     g_free(userStylesheetUri);
1671
1672     webkit_web_view_screen_changed(webView, NULL, NULL);
1673 }
1674
1675 static inline gint pixelsFromSize(WebKitWebView* webView, gint size)
1676 {
1677     gdouble DPI = webViewGetDPI(webView);
1678     return size / 72.0 * DPI;
1679 }
1680
1681 static void webkit_web_view_settings_notify(WebKitWebSettings* webSettings, GParamSpec* pspec, WebKitWebView* webView)
1682 {
1683     Settings* settings = core(webView)->settings();
1684
1685     const gchar* name = g_intern_string(pspec->name);
1686     GValue value = { 0, { { 0 } } };
1687     g_value_init(&value, pspec->value_type);
1688     g_object_get_property(G_OBJECT(webSettings), name, &value);
1689
1690     if (name == g_intern_string("default-encoding"))
1691         settings->setDefaultTextEncodingName(g_value_get_string(&value));
1692     else if (name == g_intern_string("cursive-font-family"))
1693         settings->setCursiveFontFamily(g_value_get_string(&value));
1694     else if (name == g_intern_string("default-font-family"))
1695         settings->setStandardFontFamily(g_value_get_string(&value));
1696     else if (name == g_intern_string("fantasy-font-family"))
1697         settings->setFantasyFontFamily(g_value_get_string(&value));
1698     else if (name == g_intern_string("monospace-font-family"))
1699         settings->setFixedFontFamily(g_value_get_string(&value));
1700     else if (name == g_intern_string("sans-serif-font-family"))
1701         settings->setSansSerifFontFamily(g_value_get_string(&value));
1702     else if (name == g_intern_string("serif-font-family"))
1703         settings->setSerifFontFamily(g_value_get_string(&value));
1704     else if (name == g_intern_string("default-font-size"))
1705         settings->setDefaultFontSize(pixelsFromSize(webView, g_value_get_int(&value)));
1706     else if (name == g_intern_string("default-monospace-font-size"))
1707         settings->setDefaultFixedFontSize(pixelsFromSize(webView, g_value_get_int(&value)));
1708     else if (name == g_intern_string("minimum-font-size"))
1709         settings->setMinimumFontSize(pixelsFromSize(webView, g_value_get_int(&value)));
1710     else if (name == g_intern_string("minimum-logical-font-size"))
1711         settings->setMinimumLogicalFontSize(pixelsFromSize(webView, g_value_get_int(&value)));
1712     else if (name == g_intern_string("enforce-96-dpi"))
1713         webkit_web_view_screen_changed(webView, NULL, NULL);
1714     else if (name == g_intern_string("auto-load-images"))
1715         settings->setLoadsImagesAutomatically(g_value_get_boolean(&value));
1716     else if (name == g_intern_string("auto-shrink-images"))
1717         settings->setShrinksStandaloneImagesToFit(g_value_get_boolean(&value));
1718     else if (name == g_intern_string("print-backgrounds"))
1719         settings->setShouldPrintBackgrounds(g_value_get_boolean(&value));
1720     else if (name == g_intern_string("enable-scripts"))
1721         settings->setJavaScriptEnabled(g_value_get_boolean(&value));
1722     else if (name == g_intern_string("enable-plugins"))
1723         settings->setPluginsEnabled(g_value_get_boolean(&value));
1724     else if (name == g_intern_string("resizable-text-areas"))
1725         settings->setTextAreasAreResizable(g_value_get_boolean(&value));
1726     else if (name == g_intern_string("user-stylesheet-uri"))
1727         settings->setUserStyleSheetLocation(KURL(KURL(), g_value_get_string(&value)));
1728     else if (name == g_intern_string("enable-developer-extras"))
1729         settings->setDeveloperExtrasEnabled(g_value_get_boolean(&value));
1730     else if (!g_object_class_find_property(G_OBJECT_GET_CLASS(webSettings), name))
1731         g_warning("Unexpected setting '%s'", name);
1732     g_value_unset(&value);
1733 }
1734
1735 static void webkit_web_view_init(WebKitWebView* webView)
1736 {
1737     WebKitWebViewPrivate* priv = WEBKIT_WEB_VIEW_GET_PRIVATE(webView);
1738     webView->priv = priv;
1739
1740     priv->imContext = gtk_im_multicontext_new();
1741
1742     WebKit::InspectorClient* inspectorClient = new WebKit::InspectorClient(webView);
1743     priv->corePage = new Page(new WebKit::ChromeClient(webView), new WebKit::ContextMenuClient(webView), new WebKit::EditorClient(webView), new WebKit::DragClient, inspectorClient);
1744
1745     // We also add a simple wrapper class to provide the public
1746     // interface for the Web Inspector.
1747     priv->webInspector = WEBKIT_WEB_INSPECTOR(g_object_new(WEBKIT_TYPE_WEB_INSPECTOR, NULL));
1748     webkit_web_inspector_set_inspector_client(priv->webInspector, inspectorClient);
1749
1750     priv->horizontalAdjustment = GTK_ADJUSTMENT(gtk_adjustment_new(0.0, 0.0, 0.0, 0.0, 0.0, 0.0));
1751     priv->verticalAdjustment = GTK_ADJUSTMENT(gtk_adjustment_new(0.0, 0.0, 0.0, 0.0, 0.0, 0.0));
1752
1753 #if GLIB_CHECK_VERSION(2,10,0)
1754     g_object_ref_sink(priv->horizontalAdjustment);
1755     g_object_ref_sink(priv->verticalAdjustment);
1756 #else
1757     g_object_ref(priv->horizontalAdjustment);
1758     gtk_object_sink(GTK_OBJECT(priv->horizontalAdjustment));
1759     g_object_ref(priv->verticalAdjustment);
1760     gtk_object_sink(GTK_OBJECT(priv->verticalAdjustment));
1761 #endif
1762
1763     GTK_WIDGET_SET_FLAGS(webView, GTK_CAN_FOCUS);
1764     priv->mainFrame = WEBKIT_WEB_FRAME(webkit_web_frame_new(webView));
1765     priv->lastPopupXPosition = priv->lastPopupYPosition = -1;
1766     priv->editable = false;
1767
1768     priv->backForwardList = webkit_web_back_forward_list_new_with_web_view(webView);
1769
1770     priv->zoomFullContent = FALSE;
1771
1772 #if GTK_CHECK_VERSION(2,10,0)
1773     GdkAtom textHtml = gdk_atom_intern_static_string("text/html");
1774 #else
1775     GdkAtom textHtml = gdk_atom_intern("text/html", false);
1776 #endif
1777     /* Targets for copy */
1778     priv->copy_target_list = gtk_target_list_new(NULL, 0);
1779     gtk_target_list_add(priv->copy_target_list, textHtml, 0, WEBKIT_WEB_VIEW_TARGET_INFO_HTML);
1780     gtk_target_list_add_text_targets(priv->copy_target_list, WEBKIT_WEB_VIEW_TARGET_INFO_TEXT);
1781
1782     /* Targets for pasting */
1783     priv->paste_target_list = gtk_target_list_new(NULL, 0);
1784     gtk_target_list_add(priv->paste_target_list, textHtml, 0, WEBKIT_WEB_VIEW_TARGET_INFO_HTML);
1785     gtk_target_list_add_text_targets(priv->paste_target_list, WEBKIT_WEB_VIEW_TARGET_INFO_TEXT);
1786
1787     priv->webSettings = webkit_web_settings_new();
1788     webkit_web_view_update_settings(webView);
1789     g_signal_connect(webView, "screen-changed", G_CALLBACK(webkit_web_view_screen_changed), NULL);
1790     g_signal_connect(priv->webSettings, "notify", G_CALLBACK(webkit_web_view_settings_notify), webView);
1791
1792     priv->webWindowFeatures = webkit_web_window_features_new();
1793 }
1794
1795 GtkWidget* webkit_web_view_new(void)
1796 {
1797     WebKitWebView* webView = WEBKIT_WEB_VIEW(g_object_new(WEBKIT_TYPE_WEB_VIEW, NULL));
1798
1799     return GTK_WIDGET(webView);
1800 }
1801
1802 // for internal use only
1803 void webkit_web_view_notify_ready(WebKitWebView* webView)
1804 {
1805     g_return_if_fail(WEBKIT_IS_WEB_VIEW(webView));
1806
1807     gboolean isHandled = FALSE;
1808     g_signal_emit(webView, webkit_web_view_signals[WEB_VIEW_READY], 0, &isHandled);
1809 }
1810
1811
1812 void webkit_web_view_set_settings(WebKitWebView* webView, WebKitWebSettings* webSettings)
1813 {
1814     g_return_if_fail(WEBKIT_IS_WEB_VIEW(webView));
1815     g_return_if_fail(WEBKIT_IS_WEB_SETTINGS(webSettings));
1816
1817     WebKitWebViewPrivate* priv = webView->priv;
1818     g_signal_handlers_disconnect_by_func(priv->webSettings, (gpointer)webkit_web_view_settings_notify, webView);
1819     g_object_unref(priv->webSettings);
1820     g_object_ref(webSettings);
1821     priv->webSettings = webSettings;
1822     webkit_web_view_update_settings(webView);
1823     g_signal_connect(webSettings, "notify", G_CALLBACK(webkit_web_view_settings_notify), webView);
1824     g_object_notify(G_OBJECT(webView), "settings");
1825 }
1826
1827 WebKitWebSettings* webkit_web_view_get_settings(WebKitWebView* webView)
1828 {
1829     g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), NULL);
1830
1831     WebKitWebViewPrivate* priv = webView->priv;
1832     return priv->webSettings;
1833 }
1834
1835 /**
1836  * webkit_web_view_get_inspector:
1837  * @web_view: a #WebKitWebView
1838  *
1839  * Obtains the #WebKitWebInspector associated with the
1840  * #WebKitWebView. Every #WebKitWebView object has a
1841  * #WebKitWebInspector object attached to it as soon as it is created,
1842  * so this function will only return NULL if the argument is not a
1843  * valid #WebKitWebView.
1844  *
1845  * Returns: the #WebKitWebInspector instance associated with the
1846  * #WebKitWebView; %NULL is only returned if the argument is not a
1847  * valid #WebKitWebView.
1848  *
1849  * Since: 1.0.3
1850  */
1851 WebKitWebInspector* webkit_web_view_get_inspector(WebKitWebView* webView)
1852 {
1853     g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), NULL);
1854
1855     WebKitWebViewPrivate* priv = webView->priv;
1856     return priv->webInspector;
1857 }
1858
1859 // internal
1860 static void webkit_web_view_set_window_features(WebKitWebView* webView, WebKitWebWindowFeatures* webWindowFeatures)
1861 {
1862     WebKitWebViewPrivate* priv = webView->priv;
1863
1864     if(webkit_web_window_features_equal(priv->webWindowFeatures, webWindowFeatures))
1865       return;
1866
1867     g_object_unref(priv->webWindowFeatures);
1868     g_object_ref(webWindowFeatures);
1869     priv->webWindowFeatures = webWindowFeatures;
1870 }
1871
1872 /**
1873  * webkit_web_view_get_window_features
1874  * @web_view: a #WebKitWebView
1875  *
1876  * Returns the instance of #WebKitWebWindowFeatures held by the given
1877  * #WebKitWebView.
1878  *
1879  * Return value: the #WebKitWebWindowFeatures
1880  *
1881  * Since: 1.0.3
1882  */
1883 WebKitWebWindowFeatures* webkit_web_view_get_window_features(WebKitWebView* webView)
1884 {
1885     g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), NULL);
1886
1887     WebKitWebViewPrivate* priv = webView->priv;
1888     return priv->webWindowFeatures;
1889 }
1890
1891 /**
1892  * webkit_web_view_set_maintains_back_forward_list:
1893  * @web_view: a #WebKitWebView
1894  * @flag: to tell the view to maintain a back or forward list
1895  *
1896  * Set the view to maintain a back or forward list of history items.
1897  */
1898 void webkit_web_view_set_maintains_back_forward_list(WebKitWebView* webView, gboolean flag)
1899 {
1900     g_return_if_fail(WEBKIT_IS_WEB_VIEW(webView));
1901
1902     core(webView)->backForwardList()->setEnabled(flag);
1903 }
1904
1905 /**
1906  * webkit_web_view_get_back_forward_list:
1907  * @web_view: a #WebKitWebView
1908  *
1909  * Returns a #WebKitWebBackForwardList
1910  *
1911  * Return value: the #WebKitWebBackForwardList
1912  */
1913 WebKitWebBackForwardList* webkit_web_view_get_back_forward_list(WebKitWebView* webView)
1914 {
1915     g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), NULL);
1916
1917     WebKitWebViewPrivate* priv = webView->priv;
1918
1919     if (!core(webView) || !core(webView)->backForwardList()->enabled())
1920         return NULL;
1921
1922     return priv->backForwardList;
1923 }
1924
1925 /**
1926  * webkit_web_view_go_to_back_forward_item:
1927  * @web_view: a #WebKitWebView
1928  * @item: a #WebKitWebHistoryItem*
1929  *
1930  * Go to the specified #WebKitWebHistoryItem
1931  *
1932  * Return value: %TRUE if loading of item is successful, %FALSE if not
1933  */
1934 gboolean webkit_web_view_go_to_back_forward_item(WebKitWebView* webView, WebKitWebHistoryItem* item)
1935 {
1936     g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), FALSE);
1937     g_return_val_if_fail(WEBKIT_IS_WEB_HISTORY_ITEM(item), FALSE);
1938
1939     WebKitWebBackForwardList* backForwardList = webkit_web_view_get_back_forward_list(webView);
1940     if (!webkit_web_back_forward_list_contains_item(backForwardList, item))
1941         return FALSE;
1942
1943     core(webView)->goToItem(core(item), FrameLoadTypeIndexedBackForward);
1944     return TRUE;
1945 }
1946
1947 /**
1948  * webkit_web_view_go_back:
1949  * @web_view: a #WebKitWebView
1950  *
1951  * Loads the previous history item.
1952  */
1953 void webkit_web_view_go_back(WebKitWebView* webView)
1954 {
1955     g_return_if_fail(WEBKIT_IS_WEB_VIEW(webView));
1956
1957     core(webView)->goBack();
1958 }
1959
1960 /**
1961  * webkit_web_view_go_back_or_forward:
1962  * @web_view: a #WebKitWebView
1963  * @steps: the number of steps
1964  *
1965  * Loads the history item that is the number of @steps away from the current
1966  * item. Negative values represent steps backward while positive values
1967  * represent steps forward.
1968  */
1969 void webkit_web_view_go_back_or_forward(WebKitWebView* webView, gint steps)
1970 {
1971     g_return_if_fail(WEBKIT_IS_WEB_VIEW(webView));
1972
1973     Frame* frame = core(webView)->mainFrame();
1974     frame->loader()->goBackOrForward(steps);
1975 }
1976
1977 /**
1978  * webkit_web_view_go_forward:
1979  * @web_view: a #WebKitWebView
1980  *
1981  * Loads the next history item.
1982  */
1983 void webkit_web_view_go_forward(WebKitWebView* webView)
1984 {
1985     g_return_if_fail(WEBKIT_IS_WEB_VIEW(webView));
1986
1987     core(webView)->goForward();
1988 }
1989
1990 /**
1991  * webkit_web_view_can_go_back:
1992  * @web_view: a #WebKitWebView
1993  *
1994  * Determines whether #web_view has a previous history item.
1995  *
1996  * Return value: %TRUE if able to move back, %FALSE otherwise
1997  */
1998 gboolean webkit_web_view_can_go_back(WebKitWebView* webView)
1999 {
2000     g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), FALSE);
2001
2002     if (!core(webView) || !core(webView)->backForwardList()->backItem())
2003         return FALSE;
2004
2005     return TRUE;
2006 }
2007
2008 /**
2009  * webkit_web_view_can_go_back_or_forward:
2010  * @web_view: a #WebKitWebView
2011  * @steps: the number of steps
2012  *
2013  * Determines whether #web_view has a history item of @steps. Negative values
2014  * represent steps backward while positive values represent steps forward.
2015  *
2016  * Return value: %TRUE if able to move back or forward the given number of
2017  * steps, %FALSE otherwise
2018  */
2019 gboolean webkit_web_view_can_go_back_or_forward(WebKitWebView* webView, gint steps)
2020 {
2021     g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), FALSE);
2022
2023     Frame* frame = core(webView)->mainFrame();
2024     return frame->loader()->canGoBackOrForward(steps);
2025 }
2026
2027 /**
2028  * webkit_web_view_can_go_forward:
2029  * @web_view: a #WebKitWebView
2030  *
2031  * Determines whether #web_view has a next history item.
2032  *
2033  * Return value: %TRUE if able to move forward, %FALSE otherwise
2034  */
2035 gboolean webkit_web_view_can_go_forward(WebKitWebView* webView)
2036 {
2037     g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), FALSE);
2038
2039     Page* page = core(webView);
2040
2041     if (!page)
2042         return FALSE;
2043
2044     if (!page->backForwardList()->forwardItem())
2045         return FALSE;
2046
2047     return TRUE;
2048 }
2049
2050 /**
2051  * webkit_web_view_open:
2052  * @web_view: a #WebKitWebView
2053  *
2054  * Requests loading of the specified URI string.
2055  *
2056  * Deprecated: 1.1.1: Use webkit_web_view_load_uri() instead.
2057   */
2058 void webkit_web_view_open(WebKitWebView* webView, const gchar* uri)
2059 {
2060     g_return_if_fail(WEBKIT_IS_WEB_VIEW(webView));
2061     g_return_if_fail(uri);
2062
2063     webkit_web_view_load_uri(webView, uri);
2064 }
2065
2066 void webkit_web_view_reload(WebKitWebView* webView)
2067 {
2068     g_return_if_fail(WEBKIT_IS_WEB_VIEW(webView));
2069
2070     core(webView)->mainFrame()->loader()->reload();
2071 }
2072
2073 /**
2074  * webkit_web_view_reload_bypass_cache:
2075  * @web_view: a #WebKitWebView
2076  *
2077  * Reloads the @web_view without using any cached data.
2078  *
2079  * Since: 1.0.3
2080  */
2081 void webkit_web_view_reload_bypass_cache(WebKitWebView* webView)
2082 {
2083     g_return_if_fail(WEBKIT_IS_WEB_VIEW(webView));
2084
2085     core(webView)->mainFrame()->loader()->reload(true);
2086 }
2087
2088 /**
2089  * webkit_web_view_load_uri:
2090  * @web_view: a #WebKitWebView
2091  * @uri: an URI string
2092  *
2093  * Requests loading of the specified URI string.
2094  *
2095  * Since: 1.1.1
2096  */
2097 void webkit_web_view_load_uri(WebKitWebView* webView, const gchar* uri)
2098 {
2099     g_return_if_fail(WEBKIT_IS_WEB_VIEW(webView));
2100     g_return_if_fail(uri);
2101
2102     WebKitWebFrame* frame = webView->priv->mainFrame;
2103     webkit_web_frame_load_uri(frame, uri);
2104 }
2105
2106 /**
2107 +  * webkit_web_view_load_string:
2108 +  * @web_view: a #WebKitWebView
2109 +  * @content: an URI string
2110 +  * @mime_type: the MIME type, or %NULL
2111 +  * @encoding: the encoding, or %NULL
2112 +  * @base_uri: the base URI for relative locations
2113 +  *
2114 +  * Requests loading of the given @content with the specified @mime_type,
2115 +  * @encoding and @base_uri.
2116 +  *
2117 +  * If @mime_type is %NULL, "text/html" is assumed.
2118 +  *
2119 +  * If @encoding is %NULL, "UTF-8" is assumed.
2120 +  */
2121 void webkit_web_view_load_string(WebKitWebView* webView, const gchar* content, const gchar* mimeType, const gchar* encoding, const gchar* baseUri)
2122 {
2123     g_return_if_fail(WEBKIT_IS_WEB_VIEW(webView));
2124     g_return_if_fail(content);
2125
2126     WebKitWebFrame* frame = webView->priv->mainFrame;
2127     webkit_web_frame_load_string(frame, content, mimeType, encoding, baseUri);
2128 }
2129 /**
2130  * webkit_web_view_load_html_string:
2131  * @web_view: a #WebKitWebView
2132  * @content: an URI string
2133  * @base_uri: the base URI for relative locations
2134  *
2135  * Requests loading of the given @content with the specified @base_uri.
2136  *
2137  * Deprecated: 1.1.1: Use webkit_web_view_load_string() instead.
2138  */
2139 void webkit_web_view_load_html_string(WebKitWebView* webView, const gchar* content, const gchar* baseUri)
2140 {
2141     g_return_if_fail(WEBKIT_IS_WEB_VIEW(webView));
2142     g_return_if_fail(content);
2143
2144     webkit_web_view_load_string(webView, content, NULL, NULL, baseUri);
2145 }
2146
2147 /**
2148  * webkit_web_view_load_request:
2149  * @web_view: a #WebKitWebView
2150  * @request: a #WebKitNetworkRequest
2151  *
2152  * Requests loading of the specified asynchronous client request.
2153  *
2154  * Creates a provisional data source that will transition to a committed data
2155  * source once any data has been received. Use webkit_web_view_stop_loading() to
2156  * stop the load.
2157  *
2158  * Since: 1.1.1
2159  */
2160 void webkit_web_view_load_request(WebKitWebView* webView, WebKitNetworkRequest* request)
2161 {
2162     g_return_if_fail(WEBKIT_IS_WEB_VIEW(webView));
2163     g_return_if_fail(WEBKIT_IS_NETWORK_REQUEST(request));
2164
2165     WebKitWebFrame* frame = webView->priv->mainFrame;
2166     webkit_web_frame_load_request(frame, request);
2167 }
2168
2169 void webkit_web_view_stop_loading(WebKitWebView* webView)
2170 {
2171     g_return_if_fail(WEBKIT_IS_WEB_VIEW(webView));
2172
2173     Frame* frame = core(webView)->mainFrame();
2174
2175     if (FrameLoader* loader = frame->loader())
2176         loader->stopAllLoaders();
2177 }
2178
2179 /**
2180  * webkit_web_view_search_text:
2181  * @web_view: a #WebKitWebView
2182  * @text: a string to look for
2183  * @forward: whether to find forward or not
2184  * @case_sensitive: whether to respect the case of text
2185  * @wrap: whether to continue looking at the beginning after reaching the end
2186  *
2187  * Looks for a specified string inside #web_view.
2188  *
2189  * Return value: %TRUE on success or %FALSE on failure
2190  */
2191 gboolean webkit_web_view_search_text(WebKitWebView* webView, const gchar* string, gboolean caseSensitive, gboolean forward, gboolean shouldWrap)
2192 {
2193     g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), FALSE);
2194     g_return_val_if_fail(string, FALSE);
2195
2196     TextCaseSensitivity caseSensitivity = caseSensitive ? TextCaseSensitive : TextCaseInsensitive;
2197     FindDirection direction = forward ? FindDirectionForward : FindDirectionBackward;
2198
2199     return core(webView)->findString(String::fromUTF8(string), caseSensitivity, direction, shouldWrap);
2200 }
2201
2202 /**
2203  * webkit_web_view_mark_text_matches:
2204  * @web_view: a #WebKitWebView
2205  * @string: a string to look for
2206  * @case_sensitive: whether to respect the case of text
2207  * @limit: the maximum number of strings to look for or %0 for all
2208  *
2209  * Attempts to highlight all occurances of #string inside #web_view.
2210  *
2211  * Return value: the number of strings highlighted
2212  */
2213 guint webkit_web_view_mark_text_matches(WebKitWebView* webView, const gchar* string, gboolean caseSensitive, guint limit)
2214 {
2215     g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), 0);
2216     g_return_val_if_fail(string, 0);
2217
2218     TextCaseSensitivity caseSensitivity = caseSensitive ? TextCaseSensitive : TextCaseInsensitive;
2219
2220     return core(webView)->markAllMatchesForText(String::fromUTF8(string), caseSensitivity, false, limit);
2221 }
2222
2223 /**
2224  * webkit_web_view_set_highlight_text_matches:
2225  * @web_view: a #WebKitWebView
2226  * @highlight: whether to highlight text matches
2227  *
2228  * Highlights text matches previously marked by webkit_web_view_mark_text_matches.
2229  */
2230 void webkit_web_view_set_highlight_text_matches(WebKitWebView* webView, gboolean shouldHighlight)
2231 {
2232     g_return_if_fail(WEBKIT_IS_WEB_VIEW(webView));
2233
2234     core(webView)->mainFrame()->setMarkedTextMatchesAreHighlighted(shouldHighlight);
2235 }
2236
2237 /**
2238  * webkit_web_view_unmark_text_matches:
2239  * @web_view: a #WebKitWebView
2240  *
2241  * Removes highlighting previously set by webkit_web_view_mark_text_matches.
2242  */
2243 void webkit_web_view_unmark_text_matches(WebKitWebView* webView)
2244 {
2245     g_return_if_fail(WEBKIT_IS_WEB_VIEW(webView));
2246
2247     return core(webView)->unmarkAllTextMatches();
2248 }
2249
2250 WebKitWebFrame* webkit_web_view_get_main_frame(WebKitWebView* webView)
2251 {
2252     g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), NULL);
2253
2254     WebKitWebViewPrivate* priv = webView->priv;
2255     return priv->mainFrame;
2256 }
2257
2258 /**
2259  * webkit_web_view_get_focused_frame:
2260  * @web_view: a #WebKitWebView
2261  *
2262  * Returns the frame that has focus or an active text selection.
2263  *
2264  * Return value: The focused #WebKitWebFrame or %NULL if no frame is focused
2265  */
2266 WebKitWebFrame* webkit_web_view_get_focused_frame(WebKitWebView* webView)
2267 {
2268     g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), NULL);
2269
2270     Frame* focusedFrame = core(webView)->focusController()->focusedFrame();
2271     return kit(focusedFrame);
2272 }
2273
2274 void webkit_web_view_execute_script(WebKitWebView* webView, const gchar* script)
2275 {
2276     g_return_if_fail(WEBKIT_IS_WEB_VIEW(webView));
2277     g_return_if_fail(script);
2278
2279     if (FrameLoader* loader = core(webView)->mainFrame()->loader())
2280         loader->executeScript(String::fromUTF8(script), true);
2281 }
2282
2283 /**
2284  * webkit_web_view_cut_clipboard:
2285  * @web_view: a #WebKitWebView
2286  *
2287  * Determines whether or not it is currently possible to cut to the clipboard.
2288  *
2289  * Return value: %TRUE if a selection can be cut, %FALSE if not
2290  */
2291 gboolean webkit_web_view_can_cut_clipboard(WebKitWebView* webView)
2292 {
2293     g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), FALSE);
2294
2295     Frame* frame = core(webView)->focusController()->focusedOrMainFrame();
2296     return frame->editor()->canCut() || frame->editor()->canDHTMLCut();
2297 }
2298
2299 /**
2300  * webkit_web_view_copy_clipboard:
2301  * @web_view: a #WebKitWebView
2302  *
2303  * Determines whether or not it is currently possible to copy to the clipboard.
2304  *
2305  * Return value: %TRUE if a selection can be copied, %FALSE if not
2306  */
2307 gboolean webkit_web_view_can_copy_clipboard(WebKitWebView* webView)
2308 {
2309     g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), FALSE);
2310
2311     Frame* frame = core(webView)->focusController()->focusedOrMainFrame();
2312     return frame->editor()->canCopy() || frame->editor()->canDHTMLCopy();
2313 }
2314
2315 /**
2316  * webkit_web_view_paste_clipboard:
2317  * @web_view: a #WebKitWebView
2318  *
2319  * Determines whether or not it is currently possible to paste from the clipboard.
2320  *
2321  * Return value: %TRUE if a selection can be pasted, %FALSE if not
2322  */
2323 gboolean webkit_web_view_can_paste_clipboard(WebKitWebView* webView)
2324 {
2325     g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), FALSE);
2326
2327     Frame* frame = core(webView)->focusController()->focusedOrMainFrame();
2328     return frame->editor()->canPaste() || frame->editor()->canDHTMLPaste();
2329 }
2330
2331 /**
2332  * webkit_web_view_cut_clipboard:
2333  * @web_view: a #WebKitWebView
2334  *
2335  * Cuts the current selection inside the @web_view to the clipboard.
2336  */
2337 void webkit_web_view_cut_clipboard(WebKitWebView* webView)
2338 {
2339     g_return_if_fail(WEBKIT_IS_WEB_VIEW(webView));
2340
2341     if (webkit_web_view_can_cut_clipboard(webView))
2342         g_signal_emit(webView, webkit_web_view_signals[CUT_CLIPBOARD], 0);
2343 }
2344
2345 /**
2346  * webkit_web_view_copy_clipboard:
2347  * @web_view: a #WebKitWebView
2348  *
2349  * Copies the current selection inside the @web_view to the clipboard.
2350  */
2351 void webkit_web_view_copy_clipboard(WebKitWebView* webView)
2352 {
2353     g_return_if_fail(WEBKIT_IS_WEB_VIEW(webView));
2354
2355     if (webkit_web_view_can_copy_clipboard(webView))
2356         g_signal_emit(webView, webkit_web_view_signals[COPY_CLIPBOARD], 0);
2357 }
2358
2359 /**
2360  * webkit_web_view_paste_clipboard:
2361  * @web_view: a #WebKitWebView
2362  *
2363  * Pastes the current contents of the clipboard to the @web_view.
2364  */
2365 void webkit_web_view_paste_clipboard(WebKitWebView* webView)
2366 {
2367     g_return_if_fail(WEBKIT_IS_WEB_VIEW(webView));
2368
2369     if (webkit_web_view_can_paste_clipboard(webView))
2370         g_signal_emit(webView, webkit_web_view_signals[PASTE_CLIPBOARD], 0);
2371 }
2372
2373 /**
2374  * webkit_web_view_delete_selection:
2375  * @web_view: a #WebKitWebView
2376  *
2377  * Deletes the current selection inside the @web_view.
2378  */
2379 void webkit_web_view_delete_selection(WebKitWebView* webView)
2380 {
2381     g_return_if_fail(WEBKIT_IS_WEB_VIEW(webView));
2382
2383     Frame* frame = core(webView)->focusController()->focusedOrMainFrame();
2384     frame->editor()->performDelete();
2385 }
2386
2387 /**
2388  * webkit_web_view_has_selection:
2389  * @web_view: a #WebKitWebView
2390  *
2391  * Determines whether text was selected.
2392  *
2393  * Return value: %TRUE if there is selected text, %FALSE if not
2394  */
2395 gboolean webkit_web_view_has_selection(WebKitWebView* webView)
2396 {
2397     g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), FALSE);
2398
2399     return !core(webView)->selection().isNone();
2400 }
2401
2402 /**
2403  * webkit_web_view_get_selected_text:
2404  * @web_view: a #WebKitWebView
2405  *
2406  * Retrieves the selected text if any.
2407  *
2408  * Return value: a newly allocated string with the selection or %NULL
2409  */
2410 gchar* webkit_web_view_get_selected_text(WebKitWebView* webView)
2411 {
2412     g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), 0);
2413
2414     Frame* frame = core(webView)->focusController()->focusedOrMainFrame();
2415     return g_strdup(frame->selectedText().utf8().data());
2416 }
2417
2418 /**
2419  * webkit_web_view_select_all:
2420  * @web_view: a #WebKitWebView
2421  *
2422  * Attempts to select everything inside the @web_view.
2423  */
2424 void webkit_web_view_select_all(WebKitWebView* webView)
2425 {
2426     g_return_if_fail(WEBKIT_IS_WEB_VIEW(webView));
2427
2428     g_signal_emit(webView, webkit_web_view_signals[SELECT_ALL], 0);
2429 }
2430
2431 /**
2432  * webkit_web_view_get_editable:
2433  * @web_view: a #WebKitWebView
2434  *
2435  * Returns whether the user is allowed to edit the document.
2436  *
2437  * Returns %TRUE if @web_view allows the user to edit the HTML document, %FALSE if
2438  * it doesn't. You can change @web_view's document programmatically regardless of
2439  * this setting.
2440  *
2441  * Return value: a #gboolean indicating the editable state
2442  */
2443 gboolean webkit_web_view_get_editable(WebKitWebView* webView)
2444 {
2445     g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), FALSE);
2446
2447     WebKitWebViewPrivate* priv = webView->priv;
2448
2449     return priv->editable;
2450 }
2451
2452 /**
2453  * webkit_web_view_set_editable:
2454  * @web_view: a #WebKitWebView
2455  * @flag: a #gboolean indicating the editable state
2456  *
2457  * Sets whether @web_view allows the user to edit its HTML document.
2458  *
2459  * If @flag is %TRUE, @web_view allows the user to edit the document. If @flag is
2460  * %FALSE, an element in @web_view's document can only be edited if the
2461  * CONTENTEDITABLE attribute has been set on the element or one of its parent
2462  * elements. You can change @web_view's document programmatically regardless of
2463  * this setting. By default a #WebKitWebView is not editable.
2464
2465  * Normally, an HTML document is not editable unless the elements within the
2466  * document are editable. This function provides a low-level way to make the
2467  * contents of a #WebKitWebView editable without altering the document or DOM
2468  * structure.
2469  */
2470 void webkit_web_view_set_editable(WebKitWebView* webView, gboolean flag)
2471 {
2472     g_return_if_fail(WEBKIT_IS_WEB_VIEW(webView));
2473
2474     WebKitWebViewPrivate* priv = webView->priv;
2475
2476     Frame* frame = core(webView)->mainFrame();
2477     g_return_if_fail(frame);
2478
2479     // TODO: What happens when the frame is replaced?
2480     flag = flag != FALSE;
2481     if (flag == priv->editable)
2482         return;
2483
2484     priv->editable = flag;
2485
2486     if (flag) {
2487         frame->applyEditingStyleToBodyElement();
2488         // TODO: If the WebKitWebView is made editable and the selection is empty, set it to something.
2489         //if (!webkit_web_view_get_selected_dom_range(webView))
2490         //    mainFrame->setSelectionFromNone();
2491     } else
2492         frame->removeEditingStyleFromBodyElement();
2493     g_object_notify(G_OBJECT(webView), "editable");
2494 }
2495
2496 /**
2497  * webkit_web_view_get_copy_target_list:
2498  * @web_view: a #WebKitWebView
2499  *
2500  * This function returns the list of targets this #WebKitWebView can
2501  * provide for clipboard copying and as DND source. The targets in the list are
2502  * added with %info values from the #WebKitWebViewTargetInfo enum,
2503  * using gtk_target_list_add() and
2504  * gtk_target_list_add_text_targets().
2505  *
2506  * Return value: the #GtkTargetList
2507  **/
2508 GtkTargetList* webkit_web_view_get_copy_target_list(WebKitWebView* webView)
2509 {
2510     g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), NULL);
2511
2512     WebKitWebViewPrivate* priv = webView->priv;
2513     return priv->copy_target_list;
2514 }
2515
2516 /**
2517  * webkit_web_view_get_paste_target_list:
2518  * @web_view: a #WebKitWebView
2519  *
2520  * This function returns the list of targets this #WebKitWebView can
2521  * provide for clipboard pasting and as DND destination. The targets in the list are
2522  * added with %info values from the #WebKitWebViewTargetInfo enum,
2523  * using gtk_target_list_add() and
2524  * gtk_target_list_add_text_targets().
2525  *
2526  * Return value: the #GtkTargetList
2527  **/
2528 GtkTargetList* webkit_web_view_get_paste_target_list(WebKitWebView* webView)
2529 {
2530     g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), NULL);
2531
2532     WebKitWebViewPrivate* priv = webView->priv;
2533     return priv->paste_target_list;
2534 }
2535
2536 /**
2537  * webkit_web_view_can_show_mime_type:
2538  * @web_view: a #WebKitWebView
2539  * @mime_type: a MIME type
2540  *
2541  * This functions returns whether or not a MIME type can be displayed using this view.
2542  *
2543  * Return value: a #gboolean indicating if the MIME type can be displayed
2544  *
2545  * Since: 1.0.3
2546  **/
2547
2548 gboolean webkit_web_view_can_show_mime_type(WebKitWebView* webView, const gchar* mimeType)
2549 {
2550     g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), FALSE);
2551
2552     Frame* frame = core(webkit_web_view_get_main_frame(webView));
2553     if (FrameLoader* loader = frame->loader())
2554         return loader->canShowMIMEType(String::fromUTF8(mimeType));
2555     else
2556         return FALSE;
2557 }
2558
2559 /**
2560  * webkit_web_view_get_transparent:
2561  * @web_view: a #WebKitWebView
2562  *
2563  * Returns whether the #WebKitWebView has a transparent background.
2564  *
2565  * Return value: %FALSE when the #WebKitWebView draws a solid background
2566  * (the default), otherwise %TRUE.
2567  */
2568 gboolean webkit_web_view_get_transparent(WebKitWebView* webView)
2569 {
2570     g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), FALSE);
2571
2572     WebKitWebViewPrivate* priv = webView->priv;
2573     return priv->transparent;
2574 }
2575
2576 /**
2577  * webkit_web_view_set_transparent:
2578  * @web_view: a #WebKitWebView
2579  *
2580  * Sets whether the #WebKitWebView has a transparent background.
2581  *
2582  * Pass %FALSE to have the #WebKitWebView draw a solid background
2583  * (the default), otherwise %TRUE.
2584  */
2585 void webkit_web_view_set_transparent(WebKitWebView* webView, gboolean flag)
2586 {
2587     g_return_if_fail(WEBKIT_IS_WEB_VIEW(webView));
2588
2589     WebKitWebViewPrivate* priv = webView->priv;
2590     priv->transparent = flag;
2591
2592     // TODO: This needs to be made persistent or it could become a problem when
2593     // the main frame is replaced.
2594     Frame* frame = core(webView)->mainFrame();
2595     g_return_if_fail(frame);
2596     frame->view()->setTransparent(flag);
2597     g_object_notify(G_OBJECT(webView), "transparent");
2598 }
2599
2600 /**
2601  * webkit_web_view_get_zoom_level:
2602  * @web_view: a #WebKitWebView
2603  *
2604  * Returns the zoom level of @web_view, i.e. the factor by which elements in
2605  * the page are scaled with respect to their original size.
2606  * If the "full-content-zoom" property is set to %FALSE (the default)
2607  * the zoom level changes the text size, or if %TRUE, scales all
2608  * elements in the page.
2609  *
2610  * Return value: the zoom level of @web_view
2611  *
2612  * Since: 1.0.1
2613  */
2614 gfloat webkit_web_view_get_zoom_level(WebKitWebView* webView)
2615 {
2616     g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), 1.0f);
2617
2618     Frame* frame = core(webView)->mainFrame();
2619     if (!frame)
2620         return 1.0f;
2621
2622     return frame->zoomFactor();
2623 }
2624
2625 static void webkit_web_view_apply_zoom_level(WebKitWebView* webView, gfloat zoomLevel)
2626 {
2627     Frame* frame = core(webView)->mainFrame();
2628     if (!frame)
2629         return;
2630
2631     WebKitWebViewPrivate* priv = webView->priv;
2632     frame->setZoomFactor(zoomLevel, !priv->zoomFullContent);
2633 }
2634
2635 /**
2636  * webkit_web_view_set_zoom_level:
2637  * @web_view: a #WebKitWebView
2638  * @zoom_level: the new zoom level
2639  *
2640  * Sets the zoom level of @web_view, i.e. the factor by which elements in
2641  * the page are scaled with respect to their original size.
2642  * If the "full-content-zoom" property is set to %FALSE (the default)
2643  * the zoom level changes the text size, or if %TRUE, scales all
2644  * elements in the page.
2645  *
2646  * Since: 1.0.1
2647  */
2648 void webkit_web_view_set_zoom_level(WebKitWebView* webView, gfloat zoomLevel)
2649 {
2650     g_return_if_fail(WEBKIT_IS_WEB_VIEW(webView));
2651
2652     webkit_web_view_apply_zoom_level(webView, zoomLevel);
2653     g_object_notify(G_OBJECT(webView), "zoom-level");
2654 }
2655
2656 /**
2657  * webkit_web_view_zoom_in:
2658  * @web_view: a #WebKitWebView
2659  *
2660  * Increases the zoom level of @web_view. The current zoom
2661  * level is incremented by the value of the "zoom-step"
2662  * property of the #WebKitWebSettings associated with @web_view.
2663  *
2664  * Since: 1.0.1
2665  */
2666 void webkit_web_view_zoom_in(WebKitWebView* webView)
2667 {
2668     g_return_if_fail(WEBKIT_IS_WEB_VIEW(webView));
2669
2670     WebKitWebViewPrivate* priv = webView->priv;
2671     gfloat zoomMultiplierRatio;
2672     g_object_get(priv->webSettings, "zoom-step", &zoomMultiplierRatio, NULL);
2673
2674     webkit_web_view_set_zoom_level(webView, webkit_web_view_get_zoom_level(webView) + zoomMultiplierRatio);
2675 }
2676
2677 /**
2678  * webkit_web_view_zoom_out:
2679  * @web_view: a #WebKitWebView
2680  *
2681  * Decreases the zoom level of @web_view. The current zoom
2682  * level is decremented by the value of the "zoom-step"
2683  * property of the #WebKitWebSettings associated with @web_view.
2684  *
2685  * Since: 1.0.1
2686  */
2687 void webkit_web_view_zoom_out(WebKitWebView* webView)
2688 {
2689     g_return_if_fail(WEBKIT_IS_WEB_VIEW(webView));
2690
2691     WebKitWebViewPrivate* priv = webView->priv;
2692     gfloat zoomMultiplierRatio;
2693     g_object_get(priv->webSettings, "zoom-step", &zoomMultiplierRatio, NULL);
2694
2695     webkit_web_view_set_zoom_level(webView, webkit_web_view_get_zoom_level(webView) - zoomMultiplierRatio);
2696 }
2697
2698 /**
2699  * webkit_web_view_get_full_content_zoom:
2700  * @web_view: a #WebKitWebView
2701  *
2702  * Returns whether the zoom level affects only text or all elements.
2703  *
2704  * Return value: %FALSE if only text should be scaled (the default),
2705  * %TRUE if the full content of the view should be scaled.
2706  *
2707  * Since: 1.0.1
2708  */
2709 gboolean webkit_web_view_get_full_content_zoom(WebKitWebView* webView)
2710 {
2711     g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), FALSE);
2712
2713     WebKitWebViewPrivate* priv = webView->priv;
2714     return priv->zoomFullContent;
2715 }
2716
2717 /**
2718  * webkit_web_view_set_full_content_zoom:
2719  * @web_view: a #WebKitWebView
2720  * @full_content_zoom: %FALSE if only text should be scaled (the default),
2721  * %TRUE if the full content of the view should be scaled.
2722  *
2723  * Sets whether the zoom level affects only text or all elements.
2724  *
2725  * Since: 1.0.1
2726  */
2727 void webkit_web_view_set_full_content_zoom(WebKitWebView* webView, gboolean zoomFullContent)
2728 {
2729     g_return_if_fail(WEBKIT_IS_WEB_VIEW(webView));
2730
2731     WebKitWebViewPrivate* priv = webView->priv;
2732     if (priv->zoomFullContent == zoomFullContent)
2733       return;
2734
2735     priv->zoomFullContent = zoomFullContent;
2736     webkit_web_view_apply_zoom_level(webView, webkit_web_view_get_zoom_level(webView));
2737
2738     g_object_notify(G_OBJECT(webView), "full-content-zoom");
2739 }
2740
2741 }