1/* 2 * Copyright (C) 2007 Holger Hans Peter Freyther 3 * Copyright (C) 2008, 2010 Collabora Ltd. 4 * 5 * This library is free software; you can redistribute it and/or 6 * modify it under the terms of the GNU Library General Public 7 * License as published by the Free Software Foundation; either 8 * version 2 of the License, or (at your option) any later version. 9 * 10 * This library is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 * Library General Public License for more details. 14 * 15 * You should have received a copy of the GNU Library General Public License 16 * along with this library; see the file COPYING.LIB. If not, write to 17 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 18 * Boston, MA 02110-1301, USA. 19 */ 20 21#include "config.h" 22#include "webkitglobals.h" 23 24#include "ApplicationCacheStorage.h" 25#include "Chrome.h" 26#include "ContextMenuItem.h" 27#include "FrameNetworkingContextGtk.h" 28#include "IconDatabase.h" 29#include "InitializeLogging.h" 30#include "MemoryCache.h" 31#include "Page.h" 32#include "PageCache.h" 33#include "PageGroup.h" 34#include "PlatformStrategiesGtk.h" 35#include "TextEncodingRegistry.h" 36#include "Pasteboard.h" 37#include "PasteboardHelperGtk.h" 38#include "ResourceHandle.h" 39#include "ResourceHandleClient.h" 40#include "ResourceHandleInternal.h" 41#include "ResourceResponse.h" 42#include "SchemeRegistry.h" 43#include "webkitapplicationcache.h" 44#include "webkitfavicondatabase.h" 45#include "webkitglobalsprivate.h" 46#include "webkiticondatabase.h" 47#include "webkitspellchecker.h" 48#include "webkitspellcheckerenchant.h" 49#include "webkitwebdatabase.h" 50#include "webkitwebplugindatabaseprivate.h" 51#include <libintl.h> 52#include <runtime/InitializeThreading.h> 53#include <stdlib.h> 54#include <wtf/MainThread.h> 55#include <wtf/gobject/GOwnPtr.h> 56#include <wtf/gobject/GRefPtr.h> 57 58#if USE(CLUTTER) 59#include <clutter-gtk/clutter-gtk.h> 60#endif 61 62static WebKitCacheModel cacheModel = WEBKIT_CACHE_MODEL_DEFAULT; 63 64using namespace WebCore; 65 66/** 67 * SECTION:webkit 68 * @short_description: Global functions controlling WebKit 69 * 70 * WebKit manages many resources which are not related to specific 71 * views. These functions relate to cross-view limits, such as cache 72 * sizes, database quotas, and the HTTP session management. 73 */ 74 75/** 76 * webkit_get_default_session: 77 * 78 * Retrieves the default #SoupSession used by all web views. 79 * Note that the session features are added by WebKit on demand, 80 * so if you insert your own #SoupCookieJar before any network 81 * traffic occurs, WebKit will use it instead of the default. 82 * 83 * Return value: (transfer none): the default #SoupSession 84 * 85 * Since: 1.1.1 86 */ 87SoupSession* webkit_get_default_session () 88{ 89 webkitInit(); 90 return ResourceHandle::defaultSession(); 91} 92 93/** 94 * webkit_set_cache_model: 95 * @cache_model: a #WebKitCacheModel 96 * 97 * Specifies a usage model for WebViews, which WebKit will use to 98 * determine its caching behavior. All web views follow the cache 99 * model. This cache model determines the RAM and disk space to use 100 * for caching previously viewed content . 101 * 102 * Research indicates that users tend to browse within clusters of 103 * documents that hold resources in common, and to revisit previously 104 * visited documents. WebKit and the frameworks below it include 105 * built-in caches that take advantage of these patterns, 106 * substantially improving document load speed in browsing 107 * situations. The WebKit cache model controls the behaviors of all of 108 * these caches, including various WebCore caches. 109 * 110 * Browsers can improve document load speed substantially by 111 * specifying WEBKIT_CACHE_MODEL_WEB_BROWSER. Applications without a 112 * browsing interface can reduce memory usage substantially by 113 * specifying WEBKIT_CACHE_MODEL_DOCUMENT_VIEWER. Default value is 114 * WEBKIT_CACHE_MODEL_WEB_BROWSER. 115 * 116 * Since: 1.1.18 117 */ 118void webkit_set_cache_model(WebKitCacheModel model) 119{ 120 webkitInit(); 121 122 if (cacheModel == model) 123 return; 124 125 // FIXME: Add disk cache handling when soup has the API 126 guint cacheTotalCapacity; 127 guint cacheMinDeadCapacity; 128 guint cacheMaxDeadCapacity; 129 gdouble deadDecodedDataDeletionInterval; 130 guint pageCacheCapacity; 131 132 // FIXME: The Mac port calculates these values based on the amount of physical memory that's 133 // installed on the system. Currently these values match the Mac port for users with more than 134 // 512 MB and less than 1024 MB of physical memory. 135 switch (model) { 136 case WEBKIT_CACHE_MODEL_DOCUMENT_VIEWER: 137 pageCacheCapacity = 0; 138 cacheTotalCapacity = 0; // FIXME: The Mac port actually sets this to larger than 0. 139 cacheMinDeadCapacity = 0; 140 cacheMaxDeadCapacity = 0; 141 deadDecodedDataDeletionInterval = 0; 142 break; 143 case WEBKIT_CACHE_MODEL_DOCUMENT_BROWSER: 144 pageCacheCapacity = 2; 145 cacheTotalCapacity = 16 * 1024 * 1024; 146 cacheMinDeadCapacity = cacheTotalCapacity / 8; 147 cacheMaxDeadCapacity = cacheTotalCapacity / 4; 148 deadDecodedDataDeletionInterval = 0; 149 break; 150 case WEBKIT_CACHE_MODEL_WEB_BROWSER: 151 // Page cache capacity (in pages). Comment from Mac port: 152 // (Research indicates that value / page drops substantially after 3 pages.) 153 pageCacheCapacity = 3; 154 cacheTotalCapacity = 32 * 1024 * 1024; 155 cacheMinDeadCapacity = cacheTotalCapacity / 4; 156 cacheMaxDeadCapacity = cacheTotalCapacity / 2; 157 deadDecodedDataDeletionInterval = 60; 158 break; 159 default: 160 g_return_if_reached(); 161 } 162 163 memoryCache()->setCapacities(cacheMinDeadCapacity, cacheMaxDeadCapacity, cacheTotalCapacity); 164 memoryCache()->setDeadDecodedDataDeletionInterval(deadDecodedDataDeletionInterval); 165 pageCache()->setCapacity(pageCacheCapacity); 166 cacheModel = model; 167} 168 169/** 170 * webkit_get_cache_model: 171 * 172 * Returns the current cache model. For more information about this 173 * value check the documentation of the function 174 * webkit_set_cache_model(). 175 * 176 * Return value: the current #WebKitCacheModel 177 * 178 * Since: 1.1.18 179 */ 180WebKitCacheModel webkit_get_cache_model() 181{ 182 webkitInit(); 183 return cacheModel; 184} 185 186/** 187 * webkit_get_web_plugin_database: 188 * 189 * Returns the current #WebKitWebPluginDatabase with information about 190 * all the plugins WebKit knows about in this instance. 191 * 192 * Return value: (transfer none): the current #WebKitWebPluginDatabase 193 * 194 * Since: 1.3.8 195 */ 196WebKitWebPluginDatabase* webkit_get_web_plugin_database() 197{ 198 static WebKitWebPluginDatabase* database = 0; 199 200 webkitInit(); 201 202 if (!database) 203 database = webkit_web_plugin_database_new(); 204 205 return database; 206} 207 208/** 209 * webkit_get_icon_database: 210 * 211 * Returns the #WebKitIconDatabase providing access to website icons. 212 * 213 * Return value: (transfer none): the current #WebKitIconDatabase 214 * 215 * Since: 1.3.13 216 * 217 * Deprecated: 1.8: Use webkit_get_favicon_database() instead 218 */ 219WebKitIconDatabase* webkit_get_icon_database() 220{ 221 webkitInit(); 222 223 static WebKitIconDatabase* database = 0; 224 if (!database) 225 database = WEBKIT_ICON_DATABASE(g_object_new(WEBKIT_TYPE_ICON_DATABASE, NULL)); 226 227 return database; 228} 229 230/** 231 * webkit_get_favicon_database: 232 * 233 * Returns the #WebKitFaviconDatabase providing access to website 234 * icons. 235 * 236 * Return value: (transfer none): the current #WebKitFaviconDatabase 237 * 238 * Since: 1.8 239 */ 240WebKitFaviconDatabase* webkit_get_favicon_database() 241{ 242 webkitInit(); 243 244 static WebKitFaviconDatabase* database = 0; 245 if (!database) 246 database = WEBKIT_FAVICON_DATABASE(g_object_new(WEBKIT_TYPE_FAVICON_DATABASE, NULL)); 247 248 return database; 249} 250 251static GRefPtr<WebKitSpellChecker> textChecker = 0; 252 253static void webkitExit() 254{ 255 g_object_unref(webkit_get_default_session()); 256#if ENABLE(ICONDATABASE) 257 g_object_unref(webkit_get_favicon_database()); 258#endif 259 textChecker = 0; 260} 261 262/** 263 * webkit_get_text_checker: 264 * 265 * Returns: (transfer none): the #WebKitSpellChecker used by WebKit, or %NULL if spell 266 * checking is not enabled 267 * 268 * Since: 1.5.1 269 **/ 270GObject* webkit_get_text_checker() 271{ 272 webkitInit(); 273 274#if ENABLE(SPELLCHECK) 275 if (!textChecker) 276 textChecker = adoptGRef(WEBKIT_SPELL_CHECKER(g_object_new(WEBKIT_TYPE_SPELL_CHECKER_ENCHANT, NULL))); 277#endif 278 279 return G_OBJECT(textChecker.get()); 280} 281 282/** 283 * webkit_set_text_checker: 284 * @checker: a #WebKitSpellChecker or %NULL 285 * 286 * Sets @checker as the spell checker to be used by WebKit. The API 287 * accepts GObject since in the future we might accept objects 288 * implementing multiple interfaces (for example, spell checking and 289 * grammar checking). 290 * 291 * Since: 1.5.1 292 **/ 293void webkit_set_text_checker(GObject* checker) 294{ 295 g_return_if_fail(!checker || WEBKIT_IS_SPELL_CHECKER(checker)); 296 297 webkitInit(); 298 299 // We need to do this because we need the cast, and casting NULL 300 // is not kosher. 301 textChecker = checker ? WEBKIT_SPELL_CHECKER(checker) : 0; 302} 303 304/** 305 * webkit_context_menu_item_get_action: 306 * @item: a #GtkMenuItem of the default context menu 307 * 308 * Returns the #WebKitContextMenuAction of the given @item. This function 309 * can be used to determine the items present in the default context menu. 310 * In order to inspect the default context menu, you should connect to 311 * #WebKitWebView::context-menu signal. 312 * 313 * <example> 314 * <title>Inspecting the default context menu</title> 315 * <programlisting> 316 * static gboolean context_menu_cb (WebKitWebView *webView, 317 * GtkWidget *default_menu, 318 * WebKitHitTestResult *hit_test_result, 319 * gboolean triggered_with_keyboard, 320 * gpointer user_data) 321 * { 322 * GList *items = gtk_container_get_children (GTK_CONTAINER (default_menu)); 323 * GList *l; 324 * GtkAction *action; 325 * GtkWidget *sub_menu; 326 * 327 * for (l = items; l; l = g_list_next (l)) { 328 * GtkMenuItem *item = (GtkMenuItem *)l->data; 329 * 330 * if (GTK_IS_SEPARATOR_MENU_ITEM (item)) { 331 * /* It's separator, do nothing */ 332 * continue; 333 * } 334 * 335 * switch (webkit_context_menu_item_get_action (item)) { 336 * case WEBKIT_CONTEXT_MENU_ACTION_NO_ACTION: 337 * /* No action for this item */ 338 * break; 339 * /* Don't allow to ope links from context menu */ 340 * case WEBKIT_CONTEXT_MENU_ACTION_OPEN_LINK: 341 * case WEBKIT_CONTEXT_MENU_ACTION_OPEN_LINK_IN_NEW_WINDOW: 342 * action = gtk_activatable_get_related_action (GTK_ACTIVATABLE (item)); 343 * gtk_action_set_sensitive (action, FALSE); 344 * break; 345 * default: 346 * break; 347 * } 348 * 349 * sub_menu = gtk_menu_item_get_submenu (item); 350 * if (sub_menu) { 351 * GtkWidget *menu_item; 352 * 353 * /* Add custom action to submenu */ 354 * action = gtk_action_new ("CustomItemName", "Custom Action", NULL, NULL); 355 * g_signal_connect (action, "activate", G_CALLBACK (custom_menu_item_activated), NULL); 356 * 357 * menu_item = gtk_action_create_menu_item (action); 358 * g_object_unref (action); 359 * gtk_menu_shell_append (GTK_MENU_SHELL (sub_menu), menu_item); 360 * gtk_widget_show (menu_item); 361 * } 362 * } 363 * 364 * g_list_free(items); 365 * } 366 * </programlisting> 367 * </example> 368 * 369 * Note that you can get the #GtkAction of any item in the default context menu with 370 * gtk_activatable_get_related_action(). 371 * 372 * Returns: the #WebKitContextMenuAction of the given @item 373 * 374 * Since: 1.10 375 */ 376WebKitContextMenuAction webkit_context_menu_item_get_action(GtkMenuItem* item) 377{ 378#if ENABLE(CONTEXT_MENUS) 379 g_return_val_if_fail(GTK_IS_MENU_ITEM(item), WEBKIT_CONTEXT_MENU_ACTION_NO_ACTION); 380 381 ContextMenuItem menuItem(item); 382 switch (menuItem.action()) { 383 case ContextMenuItemTagNoAction: 384 return WEBKIT_CONTEXT_MENU_ACTION_NO_ACTION; 385 case ContextMenuItemTagOpenLink: 386 return WEBKIT_CONTEXT_MENU_ACTION_OPEN_LINK; 387 case ContextMenuItemTagOpenLinkInNewWindow: 388 return WEBKIT_CONTEXT_MENU_ACTION_OPEN_LINK_IN_NEW_WINDOW; 389 case ContextMenuItemTagDownloadLinkToDisk: 390 return WEBKIT_CONTEXT_MENU_ACTION_DOWNLOAD_LINK_TO_DISK; 391 case ContextMenuItemTagCopyLinkToClipboard: 392 return WEBKIT_CONTEXT_MENU_ACTION_COPY_LINK_TO_CLIPBOARD; 393 case ContextMenuItemTagOpenImageInNewWindow: 394 return WEBKIT_CONTEXT_MENU_ACTION_OPEN_IMAGE_IN_NEW_WINDOW; 395 case ContextMenuItemTagDownloadImageToDisk: 396 return WEBKIT_CONTEXT_MENU_ACTION_DOWNLOAD_IMAGE_TO_DISK; 397 case ContextMenuItemTagCopyImageToClipboard: 398 return WEBKIT_CONTEXT_MENU_ACTION_COPY_IMAGE_TO_CLIPBOARD; 399 case ContextMenuItemTagCopyImageUrlToClipboard: 400 return WEBKIT_CONTEXT_MENU_ACTION_COPY_IMAGE_URL_TO_CLIPBOARD; 401 case ContextMenuItemTagOpenFrameInNewWindow: 402 return WEBKIT_CONTEXT_MENU_ACTION_OPEN_FRAME_IN_NEW_WINDOW; 403 case ContextMenuItemTagGoBack: 404 return WEBKIT_CONTEXT_MENU_ACTION_GO_BACK; 405 case ContextMenuItemTagGoForward: 406 return WEBKIT_CONTEXT_MENU_ACTION_GO_FORWARD; 407 case ContextMenuItemTagStop: 408 return WEBKIT_CONTEXT_MENU_ACTION_STOP; 409 case ContextMenuItemTagReload: 410 return WEBKIT_CONTEXT_MENU_ACTION_RELOAD; 411 case ContextMenuItemTagCopy: 412 return WEBKIT_CONTEXT_MENU_ACTION_COPY; 413 case ContextMenuItemTagCut: 414 return WEBKIT_CONTEXT_MENU_ACTION_CUT; 415 case ContextMenuItemTagPaste: 416 return WEBKIT_CONTEXT_MENU_ACTION_PASTE; 417 case ContextMenuItemTagDelete: 418 return WEBKIT_CONTEXT_MENU_ACTION_DELETE; 419 case ContextMenuItemTagSelectAll: 420 return WEBKIT_CONTEXT_MENU_ACTION_SELECT_ALL; 421 case ContextMenuItemTagInputMethods: 422 return WEBKIT_CONTEXT_MENU_ACTION_INPUT_METHODS; 423 case ContextMenuItemTagUnicode: 424 return WEBKIT_CONTEXT_MENU_ACTION_UNICODE; 425 case ContextMenuItemTagSpellingGuess: 426 return WEBKIT_CONTEXT_MENU_ACTION_SPELLING_GUESS; 427 case ContextMenuItemTagIgnoreSpelling: 428 return WEBKIT_CONTEXT_MENU_ACTION_IGNORE_SPELLING; 429 case ContextMenuItemTagLearnSpelling: 430 return WEBKIT_CONTEXT_MENU_ACTION_LEARN_SPELLING; 431 case ContextMenuItemTagIgnoreGrammar: 432 return WEBKIT_CONTEXT_MENU_ACTION_IGNORE_GRAMMAR; 433 case ContextMenuItemTagFontMenu: 434 return WEBKIT_CONTEXT_MENU_ACTION_FONT_MENU; 435 case ContextMenuItemTagBold: 436 return WEBKIT_CONTEXT_MENU_ACTION_BOLD; 437 case ContextMenuItemTagItalic: 438 return WEBKIT_CONTEXT_MENU_ACTION_ITALIC; 439 case ContextMenuItemTagUnderline: 440 return WEBKIT_CONTEXT_MENU_ACTION_UNDERLINE; 441 case ContextMenuItemTagOutline: 442 return WEBKIT_CONTEXT_MENU_ACTION_OUTLINE; 443 case ContextMenuItemTagInspectElement: 444 return WEBKIT_CONTEXT_MENU_ACTION_INSPECT_ELEMENT; 445 case ContextMenuItemTagOpenMediaInNewWindow: 446 return WEBKIT_CONTEXT_MENU_ACTION_OPEN_MEDIA_IN_NEW_WINDOW; 447 case ContextMenuItemTagCopyMediaLinkToClipboard: 448 return WEBKIT_CONTEXT_MENU_ACTION_COPY_MEDIA_LINK_TO_CLIPBOARD; 449 case ContextMenuItemTagToggleMediaControls: 450 return WEBKIT_CONTEXT_MENU_ACTION_TOGGLE_MEDIA_CONTROLS; 451 case ContextMenuItemTagToggleMediaLoop: 452 return WEBKIT_CONTEXT_MENU_ACTION_TOGGLE_MEDIA_LOOP; 453 case ContextMenuItemTagEnterVideoFullscreen: 454 return WEBKIT_CONTEXT_MENU_ACTION_ENTER_VIDEO_FULLSCREEN; 455 case ContextMenuItemTagMediaPlayPause: 456 return WEBKIT_CONTEXT_MENU_ACTION_MEDIA_PLAY_PAUSE; 457 case ContextMenuItemTagMediaMute: 458 return WEBKIT_CONTEXT_MENU_ACTION_MEDIA_MUTE; 459 default: 460 g_assert_not_reached(); 461 } 462#else 463 return WEBKIT_CONTEXT_MENU_ACTION_NO_ACTION; 464#endif 465} 466 467/** 468 * webkit_set_security_policy_for_uri_scheme: 469 * @scheme: a URI scheme 470 * @policy: a #WebKitSecurityPolicy 471 * 472 * Set the security policy for the given URI scheme. 473 * 474 * Since: 2.0 475 */ 476void webkit_set_security_policy_for_uri_scheme(const char *scheme, WebKitSecurityPolicy policy) 477{ 478 g_return_if_fail(scheme); 479 480 if (!policy) 481 return; 482 483 String urlScheme = String::fromUTF8(scheme); 484 485 if (policy & WEBKIT_SECURITY_POLICY_LOCAL) 486 SchemeRegistry::registerURLSchemeAsLocal(urlScheme); 487 if (policy & WEBKIT_SECURITY_POLICY_NO_ACCESS_TO_OTHER_SCHEME) 488 SchemeRegistry::registerURLSchemeAsNoAccess(urlScheme); 489 if (policy & WEBKIT_SECURITY_POLICY_DISPLAY_ISOLATED) 490 SchemeRegistry::registerURLSchemeAsDisplayIsolated(urlScheme); 491 if (policy & WEBKIT_SECURITY_POLICY_SECURE) 492 SchemeRegistry::registerURLSchemeAsSecure(urlScheme); 493 if (policy & WEBKIT_SECURITY_POLICY_CORS_ENABLED) 494 SchemeRegistry::registerURLSchemeAsCORSEnabled(urlScheme); 495 if (policy & WEBKIT_SECURITY_POLICY_EMPTY_DOCUMENT) 496 SchemeRegistry::registerURLSchemeAsEmptyDocument(urlScheme); 497} 498 499/** 500 * webkit_get_security_policy_for_uri_scheme: 501 * @scheme: a URI scheme 502 * 503 * Get the security policy for the given URI scheme. 504 * 505 * Returns: a #WebKitSecurityPolicy 506 * 507 * Since: 2.0 508 */ 509WebKitSecurityPolicy webkit_get_security_policy_for_uri_scheme(const char *scheme) 510{ 511 g_return_val_if_fail(scheme, static_cast<WebKitSecurityPolicy>(0)); 512 513 guint policy = 0; 514 String urlScheme = String::fromUTF8(scheme); 515 516 if (SchemeRegistry::shouldTreatURLSchemeAsLocal(urlScheme)) 517 policy |= WEBKIT_SECURITY_POLICY_LOCAL; 518 if (SchemeRegistry::shouldTreatURLSchemeAsNoAccess(urlScheme)) 519 policy |= WEBKIT_SECURITY_POLICY_NO_ACCESS_TO_OTHER_SCHEME; 520 if (SchemeRegistry::shouldTreatURLSchemeAsDisplayIsolated(urlScheme)) 521 policy |= WEBKIT_SECURITY_POLICY_DISPLAY_ISOLATED; 522 if (SchemeRegistry::shouldTreatURLSchemeAsSecure(urlScheme)) 523 policy |= WEBKIT_SECURITY_POLICY_SECURE; 524 if (SchemeRegistry::shouldTreatURLSchemeAsCORSEnabled(urlScheme)) 525 policy |= WEBKIT_SECURITY_POLICY_CORS_ENABLED; 526 if (SchemeRegistry::shouldLoadURLSchemeAsEmptyDocument(urlScheme)) 527 policy |= WEBKIT_SECURITY_POLICY_EMPTY_DOCUMENT; 528 529 return static_cast<WebKitSecurityPolicy>(policy); 530} 531 532void webkitInit() 533{ 534 static bool isInitialized = false; 535 if (isInitialized) 536 return; 537 isInitialized = true; 538 539 bindtextdomain(GETTEXT_PACKAGE, PACKAGE_LOCALE_DIR); 540 bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8"); 541 542 JSC::initializeThreading(); 543 WTF::initializeMainThread(); 544 545#if !LOG_DISABLED 546 WebCore::initializeLoggingChannelsIfNecessary(); 547#endif // !LOG_DISABLED 548 PlatformStrategiesGtk::initialize(); 549 550 // We make sure the text codecs have been initialized, because 551 // that may only be done by the main thread. 552 atomicCanonicalTextEncodingName("UTF-8"); 553 554 GOwnPtr<gchar> databaseDirectory(g_build_filename(g_get_user_data_dir(), "webkit", "databases", NULL)); 555 webkit_set_web_database_directory_path(databaseDirectory.get()); 556 557 GOwnPtr<gchar> cacheDirectory(g_build_filename(g_get_user_cache_dir(), "webkitgtk", "applications", NULL)); 558 WebCore::cacheStorage().setCacheDirectory(cacheDirectory.get()); 559 560 PageGroup::setShouldTrackVisitedLinks(true); 561 562 GOwnPtr<gchar> iconDatabasePath(g_build_filename(g_get_user_data_dir(), "webkit", "icondatabase", NULL)); 563 webkit_icon_database_set_path(webkit_get_icon_database(), iconDatabasePath.get()); 564 565 WebCore::ResourceHandle::setIgnoreSSLErrors(true); 566 567#if USE(CLUTTER) 568 gtk_clutter_init(0, 0); 569#endif 570 571 atexit(webkitExit); 572} 573 574const char* webkitPageGroupName() 575{ 576 return "org.webkit.gtk.WebKitGTK"; 577} 578