main.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287
  1. /*
  2. * Copyright (C) 2006, 2007 Apple Inc.
  3. * Copyright (C) 2007 Alp Toker <alp@atoker.com>
  4. * Copyright (C) 2011 Igalia S.L.
  5. *
  6. * Redistribution and use in source and binary forms, with or without
  7. * modification, are permitted provided that the following conditions
  8. * are met:
  9. * 1. Redistributions of source code must retain the above copyright
  10. * notice, this list of conditions and the following disclaimer.
  11. * 2. Redistributions in binary form must reproduce the above copyright
  12. * notice, this list of conditions and the following disclaimer in the
  13. * documentation and/or other materials provided with the distribution.
  14. *
  15. * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
  16. * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  17. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  18. * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
  19. * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  20. * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  21. * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  22. * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
  23. * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  24. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  25. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  26. */
  27. #include "BrowserWindow.h"
  28. #include <errno.h>
  29. #include <gtk/gtk.h>
  30. #include <string.h>
  31. #include <webkit2/webkit2.h>
  32. #define MINI_BROWSER_ERROR (miniBrowserErrorQuark())
  33. static const gchar **uriArguments = NULL;
  34. static const char *miniBrowserAboutScheme = "minibrowser-about";
  35. typedef enum {
  36. MINI_BROWSER_ERROR_INVALID_ABOUT_PATH
  37. } MiniBrowserError;
  38. static GQuark miniBrowserErrorQuark()
  39. {
  40. return g_quark_from_string("minibrowser-quark");
  41. }
  42. static gchar *argumentToURL(const char *filename)
  43. {
  44. GFile *gfile = g_file_new_for_commandline_arg(filename);
  45. gchar *fileURL = g_file_get_uri(gfile);
  46. g_object_unref(gfile);
  47. return fileURL;
  48. }
  49. static void createBrowserWindow(const gchar *uri, WebKitSettings *webkitSettings)
  50. {
  51. GtkWidget *webView = webkit_web_view_new();
  52. GtkWidget *mainWindow = browser_window_new(WEBKIT_WEB_VIEW(webView), NULL);
  53. gchar *url = argumentToURL(uri);
  54. if (webkitSettings) {
  55. webkit_web_view_set_settings(WEBKIT_WEB_VIEW(webView), webkitSettings);
  56. g_object_unref(webkitSettings);
  57. }
  58. browser_window_load_uri(BROWSER_WINDOW(mainWindow), url);
  59. g_free(url);
  60. gtk_widget_grab_focus(webView);
  61. gtk_widget_show(mainWindow);
  62. }
  63. static const GOptionEntry commandLineOptions[] =
  64. {
  65. { G_OPTION_REMAINING, 0, 0, G_OPTION_ARG_FILENAME_ARRAY, &uriArguments, 0, "[URL…]" },
  66. { 0, 0, 0, 0, 0, 0, 0 }
  67. };
  68. static gboolean parseOptionEntryCallback(const gchar *optionNameFull, const gchar *value, WebKitSettings *webSettings, GError **error)
  69. {
  70. if (strlen(optionNameFull) <= 2) {
  71. g_set_error(error, G_OPTION_ERROR, G_OPTION_ERROR_FAILED, "Invalid option %s", optionNameFull);
  72. return FALSE;
  73. }
  74. /* We have two -- in option name so remove them. */
  75. const gchar *optionName = optionNameFull + 2;
  76. GParamSpec *spec = g_object_class_find_property(G_OBJECT_GET_CLASS(webSettings), optionName);
  77. if (!spec) {
  78. g_set_error(error, G_OPTION_ERROR, G_OPTION_ERROR_FAILED, "Cannot find web settings for option %s", optionNameFull);
  79. return FALSE;
  80. }
  81. switch (G_PARAM_SPEC_VALUE_TYPE(spec)) {
  82. case G_TYPE_BOOLEAN: {
  83. gboolean propertyValue = !(value && g_ascii_strcasecmp(value, "true") && strcmp(value, "1"));
  84. g_object_set(G_OBJECT(webSettings), optionName, propertyValue, NULL);
  85. break;
  86. }
  87. case G_TYPE_STRING:
  88. g_object_set(G_OBJECT(webSettings), optionName, value, NULL);
  89. break;
  90. case G_TYPE_INT: {
  91. glong propertyValue;
  92. gchar *end;
  93. errno = 0;
  94. propertyValue = g_ascii_strtoll(value, &end, 0);
  95. if (errno == ERANGE || propertyValue > G_MAXINT || propertyValue < G_MININT) {
  96. g_set_error(error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE, "Integer value '%s' for %s out of range", value, optionNameFull);
  97. return FALSE;
  98. }
  99. if (errno || value == end) {
  100. g_set_error(error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE, "Cannot parse integer value '%s' for %s", value, optionNameFull);
  101. return FALSE;
  102. }
  103. g_object_set(G_OBJECT(webSettings), optionName, propertyValue, NULL);
  104. break;
  105. }
  106. case G_TYPE_FLOAT: {
  107. gdouble propertyValue;
  108. gchar *end;
  109. errno = 0;
  110. propertyValue = g_ascii_strtod(value, &end);
  111. if (errno == ERANGE || propertyValue > G_MAXFLOAT || propertyValue < G_MINFLOAT) {
  112. g_set_error(error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE, "Float value '%s' for %s out of range", value, optionNameFull);
  113. return FALSE;
  114. }
  115. if (errno || value == end) {
  116. g_set_error(error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE, "Cannot parse float value '%s' for %s", value, optionNameFull);
  117. return FALSE;
  118. }
  119. g_object_set(G_OBJECT(webSettings), optionName, propertyValue, NULL);
  120. break;
  121. }
  122. default:
  123. g_assert_not_reached();
  124. }
  125. return TRUE;
  126. }
  127. static gboolean isValidParameterType(GType gParamType)
  128. {
  129. return (gParamType == G_TYPE_BOOLEAN || gParamType == G_TYPE_STRING || gParamType == G_TYPE_INT
  130. || gParamType == G_TYPE_FLOAT);
  131. }
  132. static GOptionEntry* getOptionEntriesFromWebKitSettings(WebKitSettings *webSettings)
  133. {
  134. GParamSpec **propertySpecs;
  135. GOptionEntry *optionEntries;
  136. guint numProperties, numEntries, i;
  137. propertySpecs = g_object_class_list_properties(G_OBJECT_GET_CLASS(webSettings), &numProperties);
  138. if (!propertySpecs)
  139. return NULL;
  140. optionEntries = g_new0(GOptionEntry, numProperties + 1);
  141. numEntries = 0;
  142. for (i = 0; i < numProperties; i++) {
  143. GParamSpec *param = propertySpecs[i];
  144. /* Fill in structures only for writable and not construct-only properties. */
  145. if (!param || !(param->flags & G_PARAM_WRITABLE) || (param->flags & G_PARAM_CONSTRUCT_ONLY))
  146. continue;
  147. GType gParamType = G_PARAM_SPEC_VALUE_TYPE(param);
  148. if (!isValidParameterType(gParamType))
  149. continue;
  150. GOptionEntry *optionEntry = &optionEntries[numEntries++];
  151. optionEntry->long_name = g_param_spec_get_name(param);
  152. /* There is no easy way to figure our short name for generated option entries.
  153. optionEntry.short_name=*/
  154. /* For bool arguments "enable" type make option argument not required. */
  155. if (gParamType == G_TYPE_BOOLEAN && (strstr(optionEntry->long_name, "enable")))
  156. optionEntry->flags = G_OPTION_FLAG_OPTIONAL_ARG;
  157. optionEntry->arg = G_OPTION_ARG_CALLBACK;
  158. optionEntry->arg_data = parseOptionEntryCallback;
  159. optionEntry->description = g_param_spec_get_blurb(param);
  160. optionEntry->arg_description = g_type_name(gParamType);
  161. }
  162. g_free(propertySpecs);
  163. return optionEntries;
  164. }
  165. static gboolean addSettingsGroupToContext(GOptionContext *context, WebKitSettings* webkitSettings)
  166. {
  167. GOptionEntry *optionEntries = getOptionEntriesFromWebKitSettings(webkitSettings);
  168. if (!optionEntries)
  169. return FALSE;
  170. GOptionGroup *webSettingsGroup = g_option_group_new("websettings",
  171. "WebKitSettings writable properties for default WebKitWebView",
  172. "WebKitSettings properties",
  173. webkitSettings,
  174. NULL);
  175. g_option_group_add_entries(webSettingsGroup, optionEntries);
  176. g_free(optionEntries);
  177. /* Option context takes ownership of the group. */
  178. g_option_context_add_group(context, webSettingsGroup);
  179. return TRUE;
  180. }
  181. static void
  182. aboutURISchemeRequestCallback(WebKitURISchemeRequest *request, gpointer userData)
  183. {
  184. GInputStream *stream;
  185. gsize streamLength;
  186. const gchar *path;
  187. gchar *contents;
  188. GError *error;
  189. path = webkit_uri_scheme_request_get_path(request);
  190. if (!g_strcmp0(path, "minibrowser")) {
  191. contents = g_strdup_printf("<html><body><h1>WebKitGTK+ MiniBrowser</h1><p>The WebKit2 test browser of the GTK+ port.</p><p>WebKit version: %d.%d.%d</p></body></html>",
  192. webkit_get_major_version(),
  193. webkit_get_minor_version(),
  194. webkit_get_micro_version());
  195. streamLength = strlen(contents);
  196. stream = g_memory_input_stream_new_from_data(contents, streamLength, g_free);
  197. webkit_uri_scheme_request_finish(request, stream, streamLength, "text/html");
  198. g_object_unref(stream);
  199. } else {
  200. error = g_error_new(MINI_BROWSER_ERROR, MINI_BROWSER_ERROR_INVALID_ABOUT_PATH, "Invalid about:%s page.", path);
  201. webkit_uri_scheme_request_finish_error(request, error);
  202. g_error_free(error);
  203. }
  204. }
  205. int main(int argc, char *argv[])
  206. {
  207. gtk_init(&argc, &argv);
  208. GOptionContext *context = g_option_context_new(NULL);
  209. g_option_context_add_main_entries(context, commandLineOptions, 0);
  210. g_option_context_add_group(context, gtk_get_option_group(TRUE));
  211. WebKitSettings *webkitSettings = webkit_settings_new();
  212. webkit_settings_set_enable_developer_extras(webkitSettings, TRUE);
  213. if (!addSettingsGroupToContext(context, webkitSettings)) {
  214. g_object_unref(webkitSettings);
  215. webkitSettings = 0;
  216. }
  217. GError *error = 0;
  218. if (!g_option_context_parse(context, &argc, &argv, &error)) {
  219. g_printerr("Cannot parse arguments: %s\n", error->message);
  220. g_error_free(error);
  221. g_option_context_free(context);
  222. return 1;
  223. }
  224. g_option_context_free (context);
  225. #ifdef WEBKIT_EXEC_PATH
  226. g_setenv("WEBKIT_INSPECTOR_PATH", WEBKIT_EXEC_PATH "resources/inspector", FALSE);
  227. #endif /* WEBKIT_EXEC_PATH */
  228. g_setenv("WEBKIT_INJECTED_BUNDLE_PATH", WEBKIT_INJECTED_BUNDLE_PATH, FALSE);
  229. // Enable the favicon database, by specifying the default directory.
  230. webkit_web_context_set_favicon_database_directory(webkit_web_context_get_default(), NULL);
  231. webkit_web_context_register_uri_scheme(webkit_web_context_get_default(), miniBrowserAboutScheme, aboutURISchemeRequestCallback, NULL, NULL);
  232. if (uriArguments) {
  233. int i;
  234. for (i = 0; uriArguments[i]; i++)
  235. createBrowserWindow(uriArguments[i], webkitSettings);
  236. } else
  237. createBrowserWindow("http://www.webkitgtk.org/", webkitSettings);
  238. gtk_main();
  239. return 0;
  240. }