2 * Copyright (C) 2006, 2007 Apple Inc.
3 * Copyright (C) 2007 Alp Toker <alp@atoker.com>
4 * Copyright (C) 2011 Igalia S.L.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
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.
15 * THIS SOFTWARE IS PROVIDED BY APPLE 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 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.
28 #include "cmakeconfig.h"
30 #include "BrowserWindow.h"
34 #include <webkit2/webkit2.h>
36 #define MINI_BROWSER_ERROR (miniBrowserErrorQuark())
38 static const gchar **uriArguments = NULL;
39 static const char *miniBrowserAboutScheme = "minibrowser-about";
40 static GdkRGBA *backgroundColor;
41 static gboolean editorMode;
42 static const char *sessionFile;
43 static char *geometry;
46 MINI_BROWSER_ERROR_INVALID_ABOUT_PATH
49 static GQuark miniBrowserErrorQuark()
51 return g_quark_from_string("minibrowser-quark");
54 static gchar *argumentToURL(const char *filename)
56 GFile *gfile = g_file_new_for_commandline_arg(filename);
57 gchar *fileURL = g_file_get_uri(gfile);
58 g_object_unref(gfile);
63 static void createBrowserWindow(const gchar *uri, WebKitSettings *webkitSettings, gboolean shouldLoadSession)
65 GtkWidget *webView = webkit_web_view_new();
67 webkit_web_view_set_editable(WEBKIT_WEB_VIEW(webView), TRUE);
68 GtkWidget *mainWindow = browser_window_new(WEBKIT_WEB_VIEW(webView), NULL);
70 browser_window_set_background_color(BROWSER_WINDOW(mainWindow), backgroundColor);
72 gtk_window_parse_geometry(GTK_WINDOW(mainWindow), geometry);
75 webkit_web_view_set_settings(WEBKIT_WEB_VIEW(webView), webkitSettings);
78 if (shouldLoadSession && sessionFile)
79 browser_window_load_session(BROWSER_WINDOW(mainWindow), sessionFile);
81 gchar *url = argumentToURL(uri);
82 browser_window_load_uri(BROWSER_WINDOW(mainWindow), url);
87 gtk_widget_grab_focus(webView);
88 gtk_widget_show(mainWindow);
91 static gboolean parseBackgroundColor(const char *optionName, const char *value, gpointer data, GError **error)
94 if (gdk_rgba_parse(&rgba, value)) {
95 backgroundColor = gdk_rgba_copy(&rgba);
99 g_set_error(error, G_OPTION_ERROR, G_OPTION_ERROR_FAILED, "Failed to parse '%s' as RGBA color", value);
103 static const GOptionEntry commandLineOptions[] =
105 { "bg-color", 0, 0, G_OPTION_ARG_CALLBACK, parseBackgroundColor, "Background color", NULL },
106 { "editor-mode", 'e', 0, G_OPTION_ARG_NONE, &editorMode, "Run in editor mode", NULL },
107 { "session-file", 's', 0, G_OPTION_ARG_FILENAME, &sessionFile, "Session file", "FILE" },
108 { "geometry", 'g', 0, G_OPTION_ARG_STRING, &geometry, "Set the size and position of the window (WIDTHxHEIGHT+X+Y)", "GEOMETRY" },
109 { G_OPTION_REMAINING, 0, 0, G_OPTION_ARG_FILENAME_ARRAY, &uriArguments, 0, "[URL…]" },
110 { 0, 0, 0, 0, 0, 0, 0 }
113 static gboolean parseOptionEntryCallback(const gchar *optionNameFull, const gchar *value, WebKitSettings *webSettings, GError **error)
115 if (strlen(optionNameFull) <= 2) {
116 g_set_error(error, G_OPTION_ERROR, G_OPTION_ERROR_FAILED, "Invalid option %s", optionNameFull);
120 /* We have two -- in option name so remove them. */
121 const gchar *optionName = optionNameFull + 2;
122 GParamSpec *spec = g_object_class_find_property(G_OBJECT_GET_CLASS(webSettings), optionName);
124 g_set_error(error, G_OPTION_ERROR, G_OPTION_ERROR_FAILED, "Cannot find web settings for option %s", optionNameFull);
128 switch (G_PARAM_SPEC_VALUE_TYPE(spec)) {
129 case G_TYPE_BOOLEAN: {
130 gboolean propertyValue = !(value && g_ascii_strcasecmp(value, "true") && strcmp(value, "1"));
131 g_object_set(G_OBJECT(webSettings), optionName, propertyValue, NULL);
135 g_object_set(G_OBJECT(webSettings), optionName, value, NULL);
142 propertyValue = g_ascii_strtoll(value, &end, 0);
143 if (errno == ERANGE || propertyValue > G_MAXINT || propertyValue < G_MININT) {
144 g_set_error(error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE, "Integer value '%s' for %s out of range", value, optionNameFull);
147 if (errno || value == end) {
148 g_set_error(error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE, "Cannot parse integer value '%s' for %s", value, optionNameFull);
151 g_object_set(G_OBJECT(webSettings), optionName, propertyValue, NULL);
155 gdouble propertyValue;
159 propertyValue = g_ascii_strtod(value, &end);
160 if (errno == ERANGE || propertyValue > G_MAXFLOAT || propertyValue < G_MINFLOAT) {
161 g_set_error(error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE, "Float value '%s' for %s out of range", value, optionNameFull);
164 if (errno || value == end) {
165 g_set_error(error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE, "Cannot parse float value '%s' for %s", value, optionNameFull);
168 g_object_set(G_OBJECT(webSettings), optionName, propertyValue, NULL);
172 g_assert_not_reached();
178 static gboolean isValidParameterType(GType gParamType)
180 return (gParamType == G_TYPE_BOOLEAN || gParamType == G_TYPE_STRING || gParamType == G_TYPE_INT
181 || gParamType == G_TYPE_FLOAT);
184 static GOptionEntry* getOptionEntriesFromWebKitSettings(WebKitSettings *webSettings)
186 GParamSpec **propertySpecs;
187 GOptionEntry *optionEntries;
188 guint numProperties, numEntries, i;
190 propertySpecs = g_object_class_list_properties(G_OBJECT_GET_CLASS(webSettings), &numProperties);
194 optionEntries = g_new0(GOptionEntry, numProperties + 1);
196 for (i = 0; i < numProperties; i++) {
197 GParamSpec *param = propertySpecs[i];
199 /* Fill in structures only for writable and not construct-only properties. */
200 if (!param || !(param->flags & G_PARAM_WRITABLE) || (param->flags & G_PARAM_CONSTRUCT_ONLY))
203 GType gParamType = G_PARAM_SPEC_VALUE_TYPE(param);
204 if (!isValidParameterType(gParamType))
207 GOptionEntry *optionEntry = &optionEntries[numEntries++];
208 optionEntry->long_name = g_param_spec_get_name(param);
210 /* There is no easy way to figure our short name for generated option entries.
211 optionEntry.short_name=*/
212 /* For bool arguments "enable" type make option argument not required. */
213 if (gParamType == G_TYPE_BOOLEAN && (strstr(optionEntry->long_name, "enable")))
214 optionEntry->flags = G_OPTION_FLAG_OPTIONAL_ARG;
215 optionEntry->arg = G_OPTION_ARG_CALLBACK;
216 optionEntry->arg_data = parseOptionEntryCallback;
217 optionEntry->description = g_param_spec_get_blurb(param);
218 optionEntry->arg_description = g_type_name(gParamType);
220 g_free(propertySpecs);
222 return optionEntries;
225 static gboolean addSettingsGroupToContext(GOptionContext *context, WebKitSettings* webkitSettings)
227 GOptionEntry *optionEntries = getOptionEntriesFromWebKitSettings(webkitSettings);
231 GOptionGroup *webSettingsGroup = g_option_group_new("websettings",
232 "WebKitSettings writable properties for default WebKitWebView",
233 "WebKitSettings properties",
236 g_option_group_add_entries(webSettingsGroup, optionEntries);
237 g_free(optionEntries);
239 /* Option context takes ownership of the group. */
240 g_option_context_add_group(context, webSettingsGroup);
246 aboutURISchemeRequestCallback(WebKitURISchemeRequest *request, gpointer userData)
248 GInputStream *stream;
254 path = webkit_uri_scheme_request_get_path(request);
255 if (!g_strcmp0(path, "minibrowser")) {
256 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>",
257 webkit_get_major_version(),
258 webkit_get_minor_version(),
259 webkit_get_micro_version());
260 streamLength = strlen(contents);
261 stream = g_memory_input_stream_new_from_data(contents, streamLength, g_free);
263 webkit_uri_scheme_request_finish(request, stream, streamLength, "text/html");
264 g_object_unref(stream);
266 error = g_error_new(MINI_BROWSER_ERROR, MINI_BROWSER_ERROR_INVALID_ABOUT_PATH, "Invalid about:%s page.", path);
267 webkit_uri_scheme_request_finish_error(request, error);
272 int main(int argc, char *argv[])
274 gtk_init(&argc, &argv);
275 #if ENABLE_DEVELOPER_MODE
276 g_setenv("WEBKIT_INJECTED_BUNDLE_PATH", WEBKIT_INJECTED_BUNDLE_PATH, FALSE);
279 const gchar *singleprocess = g_getenv("MINIBROWSER_SINGLEPROCESS");
280 webkit_web_context_set_process_model(webkit_web_context_get_default(), (singleprocess && *singleprocess) ?
281 WEBKIT_PROCESS_MODEL_SHARED_SECONDARY_PROCESS : WEBKIT_PROCESS_MODEL_MULTIPLE_SECONDARY_PROCESSES);
283 GOptionContext *context = g_option_context_new(NULL);
284 g_option_context_add_main_entries(context, commandLineOptions, 0);
285 g_option_context_add_group(context, gtk_get_option_group(TRUE));
287 WebKitSettings *webkitSettings = webkit_settings_new();
288 webkit_settings_set_enable_developer_extras(webkitSettings, TRUE);
289 webkit_settings_set_enable_webgl(webkitSettings, TRUE);
290 if (!addSettingsGroupToContext(context, webkitSettings))
291 g_clear_object(&webkitSettings);
294 if (!g_option_context_parse(context, &argc, &argv, &error)) {
295 g_printerr("Cannot parse arguments: %s\n", error->message);
297 g_option_context_free(context);
301 g_option_context_free (context);
303 // Enable the favicon database, by specifying the default directory.
304 webkit_web_context_set_favicon_database_directory(webkit_web_context_get_default(), NULL);
306 webkit_web_context_register_uri_scheme(webkit_web_context_get_default(), miniBrowserAboutScheme, aboutURISchemeRequestCallback, NULL, NULL);
311 for (i = 0; uriArguments[i]; i++)
312 createBrowserWindow(uriArguments[i], webkitSettings, FALSE);
314 createBrowserWindow(BROWSER_DEFAULT_URL, webkitSettings, TRUE);
316 g_clear_object(&webkitSettings);