netsurf/gtk/preferences.c
Vincent Sanders 7d9c9dba36 Split utils header into string functions and everything else
split out the string handling API from the rest of the utils header
and fix up all the fallout.
2016-04-21 22:36:21 +01:00

1032 lines
28 KiB
C

/*
* Copyright 2012 Vincent Sanders <vince@netsurf-browser.org>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdlib.h>
#include <stdint.h>
#include <math.h>
#include <string.h>
#include "utils/utils.h"
#include "utils/messages.h"
#include "utils/nsoption.h"
#include "utils/file.h"
#include "utils/log.h"
#include "utils/nsurl.h"
#include "desktop/browser.h"
#include "desktop/searchweb.h"
#include "gtk/compat.h"
#include "gtk/window.h"
#include "gtk/gui.h"
#include "gtk/scaffolding.h"
#include "gtk/resources.h"
#include "gtk/preferences.h"
/* private prefs */
struct ppref {
/** dialog handle created when window first accessed */
GObject *dialog;
struct browser_window *bw;
/* widgets which are accessed from outside their own signal handlers */
GtkEntry *entryHomePageURL;
GtkEntry *entryProxyHost;
GtkEntry *entryProxyUser;
GtkEntry *entryProxyPassword;
GtkEntry *entryProxyNoproxy;
GtkSpinButton *spinProxyPort;
/* dynamic list stores */
GtkListStore *content_language;
GtkListStore *search_providers;
};
static struct ppref ppref;
/* Set netsurf option based on toggle button state
*
* This works for any widget which subclasses togglebutton (checkbox,
* radiobutton etc.)
*/
#define TOGGLEBUTTON_SIGNALS(WIDGET, OPTION) \
G_MODULE_EXPORT void \
nsgtk_preferences_##WIDGET##_toggled(GtkToggleButton *togglebutton, \
struct ppref *priv); \
G_MODULE_EXPORT void \
nsgtk_preferences_##WIDGET##_toggled(GtkToggleButton *togglebutton, \
struct ppref *priv) \
{ \
nsoption_set_bool(OPTION, \
gtk_toggle_button_get_active(togglebutton)); \
} \
\
G_MODULE_EXPORT void \
nsgtk_preferences_##WIDGET##_realize(GtkWidget *widget, \
struct ppref *priv); \
G_MODULE_EXPORT void \
nsgtk_preferences_##WIDGET##_realize(GtkWidget *widget, \
struct ppref *priv) \
{ \
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget), \
nsoption_bool(OPTION)); \
}
#define SPINBUTTON_SIGNALS(WIDGET, OPTION, MULTIPLIER) \
G_MODULE_EXPORT void \
nsgtk_preferences_##WIDGET##_valuechanged(GtkSpinButton *spinbutton, \
struct ppref *priv); \
G_MODULE_EXPORT void \
nsgtk_preferences_##WIDGET##_valuechanged(GtkSpinButton *spinbutton, \
struct ppref *priv) \
{ \
nsoption_set_int(OPTION, \
round(gtk_spin_button_get_value(spinbutton) * MULTIPLIER)); \
} \
\
G_MODULE_EXPORT void \
nsgtk_preferences_##WIDGET##_realize(GtkWidget *widget, struct ppref *priv); \
G_MODULE_EXPORT void \
nsgtk_preferences_##WIDGET##_realize(GtkWidget *widget, struct ppref *priv) \
{ \
gtk_spin_button_set_value(GTK_SPIN_BUTTON(widget), \
((gdouble)nsoption_int(OPTION)) / MULTIPLIER); \
}
#define SPINBUTTON_UINT_SIGNALS(WIDGET, OPTION, MULTIPLIER) \
G_MODULE_EXPORT void \
nsgtk_preferences_##WIDGET##_valuechanged(GtkSpinButton *spinbutton, \
struct ppref *priv); \
G_MODULE_EXPORT void \
nsgtk_preferences_##WIDGET##_valuechanged(GtkSpinButton *spinbutton, \
struct ppref *priv) \
{ \
nsoption_set_uint(OPTION, \
round(gtk_spin_button_get_value(spinbutton) * MULTIPLIER)); \
} \
\
G_MODULE_EXPORT void \
nsgtk_preferences_##WIDGET##_realize(GtkWidget *widget, struct ppref *priv); \
G_MODULE_EXPORT void \
nsgtk_preferences_##WIDGET##_realize(GtkWidget *widget, struct ppref *priv) \
{ \
gtk_spin_button_set_value(GTK_SPIN_BUTTON(widget), \
((gdouble)nsoption_uint(OPTION)) / MULTIPLIER); \
}
#define ENTRY_SIGNALS(WIDGET, OPTION) \
G_MODULE_EXPORT void \
nsgtk_preferences_##WIDGET##_changed(GtkEditable *editable, struct ppref *priv); \
G_MODULE_EXPORT void \
nsgtk_preferences_##WIDGET##_changed(GtkEditable *editable, struct ppref *priv)\
{ \
nsoption_set_charp(OPTION, \
strdup(gtk_entry_get_text(GTK_ENTRY(editable)))); \
} \
\
G_MODULE_EXPORT void \
nsgtk_preferences_##WIDGET##_realize(GtkWidget *widget, struct ppref *priv); \
G_MODULE_EXPORT void \
nsgtk_preferences_##WIDGET##_realize(GtkWidget *widget, struct ppref *priv) \
{ \
const char *OPTION; \
OPTION = nsoption_charp(OPTION); \
if (OPTION != NULL) { \
gtk_entry_set_text(GTK_ENTRY(widget), OPTION); \
} \
}
/* GTK module requires these to be exported symbols so these all need
* forward declaring to avoid warnings
*/
G_MODULE_EXPORT void nsgtk_preferences_comboProxyType_changed(GtkComboBox *combo, struct ppref *priv);
G_MODULE_EXPORT void nsgtk_preferences_comboProxyType_realize(GtkWidget *widget, struct ppref *priv);
G_MODULE_EXPORT void nsgtk_preferences_comboboxLoadImages_changed(GtkComboBox *combo, struct ppref *priv);
G_MODULE_EXPORT void nsgtk_preferences_comboboxLoadImages_realize(GtkWidget *widget, struct ppref *priv);
G_MODULE_EXPORT void nsgtk_preferences_comboDefault_changed(GtkComboBox *combo, struct ppref *priv);
G_MODULE_EXPORT void nsgtk_preferences_comboDefault_realize(GtkWidget *widget, struct ppref *priv);
G_MODULE_EXPORT void nsgtk_preferences_fontPreview_clicked(GtkButton *button, struct ppref *priv);
G_MODULE_EXPORT void nsgtk_preferences_comboboxLanguage_changed(GtkComboBox *combo, struct ppref *priv);
G_MODULE_EXPORT void nsgtk_preferences_comboboxLanguage_realize(GtkWidget *widget, struct ppref *priv);
G_MODULE_EXPORT void nsgtk_preferences_checkShowSingleTab_toggled(GtkToggleButton *togglebutton, struct ppref *priv);
G_MODULE_EXPORT void nsgtk_preferences_checkShowSingleTab_realize(GtkWidget *widget, struct ppref *priv);
G_MODULE_EXPORT void nsgtk_preferences_comboTabPosition_changed(GtkComboBox *widget, struct ppref *priv);
G_MODULE_EXPORT void nsgtk_preferences_comboTabPosition_realize(GtkWidget *widget, struct ppref *priv);
G_MODULE_EXPORT void nsgtk_preferences_comboDeveloperView_changed(GtkComboBox *widget, struct ppref *priv);
G_MODULE_EXPORT void nsgtk_preferences_comboDeveloperView_realize(GtkWidget *widget, struct ppref *priv);
G_MODULE_EXPORT void nsgtk_preferences_comboButtonType_changed(GtkComboBox *widget, struct ppref *priv);
G_MODULE_EXPORT void nsgtk_preferences_comboButtonType_realize(GtkWidget *widget, struct ppref *priv);
G_MODULE_EXPORT void nsgtk_preferences_setCurrentPage_clicked(GtkButton *button, struct ppref *priv);
G_MODULE_EXPORT void nsgtk_preferences_setDefaultPage_clicked(GtkButton *button, struct ppref *priv);
G_MODULE_EXPORT void nsgtk_preferences_comboSearch_changed(GtkComboBox *widget, struct ppref *priv);
G_MODULE_EXPORT void nsgtk_preferences_comboSearch_realize(GtkWidget *widget, struct ppref *priv);
G_MODULE_EXPORT void nsgtk_preferences_fileChooserDownloads_selectionchanged(GtkFileChooser *chooser, struct ppref *priv);
G_MODULE_EXPORT void nsgtk_preferences_fileChooserDownloads_realize(GtkWidget *widget, struct ppref *priv);
G_MODULE_EXPORT void nsgtk_preferences_dialogPreferences_response(GtkDialog *dlg, gint resid);
G_MODULE_EXPORT gboolean nsgtk_preferences_dialogPreferences_deleteevent(GtkDialog *dlg, struct ppref *priv);
G_MODULE_EXPORT void nsgtk_preferences_dialogPreferences_destroy(GtkDialog *dlg, struct ppref *priv);
/********* PDF **********/
/* Appearance */
/* no images in output */
TOGGLEBUTTON_SIGNALS(checkSuppressImages, suppress_images)
/* no background images */
TOGGLEBUTTON_SIGNALS(checkRemoveBackgrounds, remove_backgrounds)
/* scale to fit page */
TOGGLEBUTTON_SIGNALS(checkFitPage, enable_loosening)
/* port */
SPINBUTTON_SIGNALS(spinExportScale, export_scale, 1.0)
/* Margins */
SPINBUTTON_SIGNALS(spinMarginTop, margin_top, 1.0)
SPINBUTTON_SIGNALS(spinMarginBottom, margin_bottom, 1.0)
SPINBUTTON_SIGNALS(spinMarginLeft, margin_left, 1.0)
SPINBUTTON_SIGNALS(spinMarginRight, margin_right, 1.0)
/* Generation */
/* output is compressed */
TOGGLEBUTTON_SIGNALS(checkCompressPDF, enable_PDF_compression)
/* output has a password */
TOGGLEBUTTON_SIGNALS(checkPasswordPDF, enable_PDF_password)
/********* Network **********/
/* HTTP proxy */
static void set_proxy_widgets_sensitivity(int proxyval, struct ppref *priv)
{
gboolean host;
gboolean port;
gboolean user;
gboolean pass;
gboolean noproxy;
switch (proxyval) {
case 0: /* no proxy */
host = FALSE;
port = FALSE;
user = FALSE;
pass = FALSE;
noproxy = FALSE;
break;
case 1: /* proxy with no auth */
host = TRUE;
port = TRUE;
user = FALSE;
pass = FALSE;
noproxy = TRUE;
break;
case 2: /* proxy with basic auth */
host = TRUE;
port = TRUE;
user = TRUE;
pass = TRUE;
noproxy = TRUE;
break;
case 3: /* proxy with ntlm auth */
host = TRUE;
port = TRUE;
user = TRUE;
pass = TRUE;
noproxy = TRUE;
break;
case 4: /* system proxy */
host = FALSE;
port = FALSE;
user = FALSE;
pass = FALSE;
noproxy = FALSE;
break;
default:
return;
}
gtk_widget_set_sensitive(GTK_WIDGET(priv->entryProxyHost), host);
gtk_widget_set_sensitive(GTK_WIDGET(priv->spinProxyPort), port);
gtk_widget_set_sensitive(GTK_WIDGET(priv->entryProxyUser), user);
gtk_widget_set_sensitive(GTK_WIDGET(priv->entryProxyPassword), pass);
gtk_widget_set_sensitive(GTK_WIDGET(priv->entryProxyNoproxy), noproxy);
}
G_MODULE_EXPORT void
nsgtk_preferences_comboProxyType_changed(GtkComboBox *combo, struct ppref *priv)
{
int proxy_sel;
proxy_sel = gtk_combo_box_get_active(combo);
switch (proxy_sel) {
case 0: /* no proxy */
nsoption_set_bool(http_proxy, false);
break;
case 1: /* proxy with no auth */
nsoption_set_bool(http_proxy, true);
nsoption_set_int(http_proxy_auth, OPTION_HTTP_PROXY_AUTH_NONE);
break;
case 2: /* proxy with basic auth */
nsoption_set_bool(http_proxy, true);
nsoption_set_int(http_proxy_auth, OPTION_HTTP_PROXY_AUTH_BASIC);
break;
case 3: /* proxy with ntlm auth */
nsoption_set_bool(http_proxy, true);
nsoption_set_int(http_proxy_auth, OPTION_HTTP_PROXY_AUTH_NTLM);
break;
case 4: /* system proxy */
nsoption_set_bool(http_proxy, true);
nsoption_set_int(http_proxy_auth, OPTION_HTTP_PROXY_AUTH_NONE);
break;
}
set_proxy_widgets_sensitivity(proxy_sel, priv);
}
G_MODULE_EXPORT void
nsgtk_preferences_comboProxyType_realize(GtkWidget *widget, struct ppref *priv)
{
int proxytype = 0; /* no proxy by default */
if (nsoption_bool(http_proxy) == true) {
/* proxy type combo box starts with disabled, to allow
* for this the http_proxy option needs combining with
* the http_proxy_auth option
*/
proxytype = nsoption_int(http_proxy_auth) + 1;
if (nsoption_charp(http_proxy_host) == NULL) {
/* set to use a proxy without a host, turn proxy off */
proxytype = 0;
} else if (((proxytype == 2) ||
(proxytype == 3)) &&
((nsoption_charp(http_proxy_auth_user) == NULL) ||
(nsoption_charp(http_proxy_auth_pass) == NULL))) {
/* authentication selected with empty credentials, turn proxy off */
proxytype = 0;
}
}
gtk_combo_box_set_active(GTK_COMBO_BOX(widget), proxytype);
set_proxy_widgets_sensitivity(proxytype, priv);
}
/* host */
ENTRY_SIGNALS(entryProxyHost, http_proxy_host)
/* port */
SPINBUTTON_SIGNALS(spinProxyPort, http_proxy_port, 1.0)
/* user */
ENTRY_SIGNALS(entryProxyUser, http_proxy_auth_user)
/* password */
ENTRY_SIGNALS(entryProxyPassword, http_proxy_auth_pass)
/* no proxy */
ENTRY_SIGNALS(entryProxyNoproxy, http_proxy_noproxy)
/* Fetching */
/* maximum fetchers */
SPINBUTTON_SIGNALS(spinMaxFetchers, max_fetchers, 1.0)
/* fetches per host */
SPINBUTTON_SIGNALS(spinFetchesPerHost, max_fetchers_per_host, 1.0)
/* cached connections */
SPINBUTTON_SIGNALS(spinCachedConnections, max_cached_fetch_handles, 1.0)
/********* Privacy **********/
/* General */
/* enable referral submission */
TOGGLEBUTTON_SIGNALS(checkSendReferer, send_referer)
/* send do not track */
TOGGLEBUTTON_SIGNALS(checkSendDNT, do_not_track)
/* History */
/* local history shows url tooltips */
TOGGLEBUTTON_SIGNALS(checkHoverURLs, hover_urls)
/* remember browsing history */
SPINBUTTON_SIGNALS(spinHistoryAge, history_age, 1.0)
/* Cache */
/* memory cache size */
SPINBUTTON_SIGNALS(spinMemoryCacheSize, memory_cache_size, (1024*1024))
/* disc cache size */
SPINBUTTON_UINT_SIGNALS(spinDiscCacheSize, disc_cache_size, (1024*1024))
/* disc cache age */
SPINBUTTON_SIGNALS(spinDiscCacheAge, disc_cache_age, 1.0)
/********* Content **********/
/* Control */
/* prevent popups */
TOGGLEBUTTON_SIGNALS(checkDisablePopups, disable_popups)
/* hide adverts */
TOGGLEBUTTON_SIGNALS(checkHideAdverts, block_advertisements)
/* enable javascript */
TOGGLEBUTTON_SIGNALS(checkEnableJavascript, enable_javascript)
/* disable plugins */
TOGGLEBUTTON_SIGNALS(checkDisablePlugins, disable_plugins)
/* high quality image scaling */
TOGGLEBUTTON_SIGNALS(checkResampleImages, render_resample)
/* load and display of images */
G_MODULE_EXPORT void
nsgtk_preferences_comboboxLoadImages_changed(GtkComboBox *combo,
struct ppref *priv)
{
int img_sel;
/* get the row number for the selection */
img_sel = gtk_combo_box_get_active(combo);
switch (img_sel) {
case 0:
/* background and foreground */
nsoption_set_bool(foreground_images, true);
nsoption_set_bool(background_images, true);
break;
case 1:
/* foreground only */
nsoption_set_bool(foreground_images, true);
nsoption_set_bool(background_images, false);
break;
case 2:
/* background only */
nsoption_set_bool(foreground_images, false);
nsoption_set_bool(background_images, true);
break;
case 3:
/* no images */
nsoption_set_bool(foreground_images, false);
nsoption_set_bool(background_images, false);
break;
}
}
G_MODULE_EXPORT void
nsgtk_preferences_comboboxLoadImages_realize(GtkWidget *widget,
struct ppref *priv)
{
if (nsoption_bool(foreground_images)) {
if (nsoption_bool(background_images)) {
/* background and foreground */
gtk_combo_box_set_active(GTK_COMBO_BOX(widget), 0);
} else {
/* foreground only */
gtk_combo_box_set_active(GTK_COMBO_BOX(widget), 1);
}
} else {
if (nsoption_bool(background_images)) {
/* background only */
gtk_combo_box_set_active(GTK_COMBO_BOX(widget), 2);
} else {
/* no images */
gtk_combo_box_set_active(GTK_COMBO_BOX(widget), 3);
}
}
}
/* Animation */
/* enable animation */
TOGGLEBUTTON_SIGNALS(checkEnableAnimations, animate_images)
/* frame time */
SPINBUTTON_SIGNALS(spinAnimationSpeed, minimum_gif_delay, 100.0)
/* Fonts */
/* default font */
G_MODULE_EXPORT void
nsgtk_preferences_comboDefault_changed(GtkComboBox *combo, struct ppref *priv)
{
int font_sel;
/* get the row number for the selection */
font_sel = gtk_combo_box_get_active(combo);
if ((font_sel >= 0) && (font_sel <= 4)) {
nsoption_set_int(font_default, font_sel);
}
}
G_MODULE_EXPORT void
nsgtk_preferences_comboDefault_realize(GtkWidget *widget, struct ppref *priv)
{
gtk_combo_box_set_active(GTK_COMBO_BOX(widget),
nsoption_int(font_default));
}
/* default font size */
SPINBUTTON_SIGNALS(spinDefaultSize, font_size, 10.0)
/* preview - actually reflow all views */
G_MODULE_EXPORT void
nsgtk_preferences_fontPreview_clicked(GtkButton *button, struct ppref *priv)
{
nsgtk_reflow_all_windows();
}
/* Language */
/* accept language */
G_MODULE_EXPORT void
nsgtk_preferences_comboboxLanguage_changed(GtkComboBox *combo,
struct ppref *priv)
{
gchar *lang = NULL;
GtkTreeIter iter;
GtkTreeModel *model;
/* Obtain currently selected item from combo box.
* If nothing is selected, do nothing.
*/
if (gtk_combo_box_get_active_iter(combo, &iter)) {
/* Obtain data model from combo box. */
model = gtk_combo_box_get_model(combo);
/* Obtain string from model. */
gtk_tree_model_get(model, &iter, 0, &lang, -1);
}
if (lang != NULL) {
nsoption_set_charp(accept_language, strdup(lang));
g_free(lang);
}
}
/**
* populate language combo from data
*/
static nserror
comboboxLanguage_add_from_data(GtkListStore *liststore,
GtkComboBox *combobox,
const char *accept_language,
const uint8_t *data,
size_t data_size)
{
int active_language = -1;
GtkTreeIter iter;
int combo_row_count = 0;
const uint8_t *s;
const uint8_t *nl;
char buf[50];
int bufi = 0;
gtk_list_store_clear(liststore);
s = data;
while (s < (data + data_size)) {
/* find nl and copy buffer */
for (nl = s; nl < data + data_size; nl++) {
if ((*nl == '\n') || (bufi == (sizeof(buf) - 2))) {
buf[bufi] = 0; /* null terminate */
break;
}
buf[bufi++] = *nl;
}
if (bufi > 0) {
gtk_list_store_append(liststore, &iter);
gtk_list_store_set(liststore, &iter, 0, buf, -1 );
if (strcmp(buf, accept_language) == 0) {
active_language = combo_row_count;
}
combo_row_count++;
}
bufi = 0;
s = nl + 1; /* skip newline */
}
/* if configured language was not in list, add it */
if (active_language == -1) {
gtk_list_store_append(liststore, &iter);
gtk_list_store_set(liststore, &iter, 0, accept_language, -1);
active_language = combo_row_count;
}
gtk_combo_box_set_active(combobox, active_language);
return NSERROR_OK;
}
/**
* populate language combo from file
*/
static nserror
comboboxLanguage_add_from_file(GtkListStore *liststore,
GtkComboBox *combobox,
const char *accept_language,
const char *file_location)
{
int active_language = -1;
GtkTreeIter iter;
int combo_row_count = 0;
FILE *fp;
char buf[50];
fp = fopen(file_location, "r");
if (fp == NULL) {
return NSERROR_NOT_FOUND;
}
gtk_list_store_clear(liststore);
LOG("Used %s for languages", file_location);
while (fgets(buf, sizeof(buf), fp)) {
/* Ignore blank lines */
if (buf[0] == '\0')
continue;
/* Remove trailing \n */
buf[strlen(buf) - 1] = '\0';
gtk_list_store_append(liststore, &iter);
gtk_list_store_set(liststore, &iter, 0, buf, -1 );
if (strcmp(buf, accept_language) == 0) {
active_language = combo_row_count;
}
combo_row_count++;
}
/* if configured language was not in list, add it */
if (active_language == -1) {
gtk_list_store_append(liststore, &iter);
gtk_list_store_set(liststore, &iter, 0, accept_language, -1);
active_language = combo_row_count;
}
fclose(fp);
gtk_combo_box_set_active(combobox, active_language);
return NSERROR_OK;
}
/**
* Fill content language list store.
*/
G_MODULE_EXPORT void
nsgtk_preferences_comboboxLanguage_realize(GtkWidget *widget,
struct ppref *priv)
{
nserror res;
const uint8_t *data;
size_t data_size;
const char *languages_file;
const char *accept_language;
if (priv->content_language == NULL) {
LOG("content language list store unavailable");
return;
}
/* get current accept language */
accept_language = nsoption_charp(accept_language);
if (accept_language == NULL) {
accept_language = "en";
}
/* attempt to read languages from inline resource */
res = nsgtk_data_from_resname("languages", &data, &data_size);
if (res == NSERROR_OK) {
res = comboboxLanguage_add_from_data(priv->content_language,
GTK_COMBO_BOX(widget),
accept_language,
data,
data_size);
} else {
/* attempt to read languages from file */
res = nsgtk_path_from_resname("languages", &languages_file);
if (res == NSERROR_OK) {
res = comboboxLanguage_add_from_file(priv->content_language,
GTK_COMBO_BOX(widget),
accept_language,
languages_file);
}
}
if (res != NSERROR_OK) {
LOG("error populatiung languages combo");
}
}
/********* Apperance **********/
/* Tabs */
/* always show tab bar */
G_MODULE_EXPORT void
nsgtk_preferences_checkShowSingleTab_toggled(GtkToggleButton *togglebutton,
struct ppref *priv)
{
nsoption_set_bool(show_single_tab,
gtk_toggle_button_get_active(togglebutton));
nsgtk_reflow_all_windows();
}
G_MODULE_EXPORT void
nsgtk_preferences_checkShowSingleTab_realize(GtkWidget *widget,
struct ppref *priv)
{
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget),
nsoption_bool(show_single_tab));
}
/* switch to newly opened tabs immediately */
TOGGLEBUTTON_SIGNALS(checkFocusNew, focus_new)
/* newly opened tabs are blank */
TOGGLEBUTTON_SIGNALS(checkNewBlank, new_blank)
/* tab position */
G_MODULE_EXPORT void
nsgtk_preferences_comboTabPosition_changed(GtkComboBox *widget,
struct ppref *priv)
{
struct nsgtk_scaffolding *current;
/* set the option */
nsoption_set_int(position_tab, gtk_combo_box_get_active(widget));
/* update all notebooks in all scaffolds */
current = nsgtk_scaffolding_iterate(NULL);
while (current) {
nsgtk_scaffolding_reset_offset(current);
nsgtk_reflow_all_windows();
current = nsgtk_scaffolding_iterate(current);
}
}
G_MODULE_EXPORT void
nsgtk_preferences_comboTabPosition_realize(GtkWidget *widget,
struct ppref *priv)
{
gtk_combo_box_set_active(GTK_COMBO_BOX(widget),
nsoption_int(position_tab));
}
/* Tools */
/* developer view opening */
G_MODULE_EXPORT void
nsgtk_preferences_comboDeveloperView_changed(GtkComboBox *widget,
struct ppref *priv)
{
/* set the option */
nsoption_set_int(developer_view, gtk_combo_box_get_active(widget));
}
G_MODULE_EXPORT void
nsgtk_preferences_comboDeveloperView_realize(GtkWidget *widget,
struct ppref *priv)
{
gtk_combo_box_set_active(GTK_COMBO_BOX(widget),
nsoption_int(developer_view));
}
/* URLbar */
/* show recently visited urls as you type */
TOGGLEBUTTON_SIGNALS(checkDisplayRecentURLs, url_suggestion)
/* Toolbar */
/* button position */
G_MODULE_EXPORT void
nsgtk_preferences_comboButtonType_changed(GtkComboBox *widget,
struct ppref *priv)
{
struct nsgtk_scaffolding *current;
nsoption_set_int(button_type, gtk_combo_box_get_active(widget) + 1);
current = nsgtk_scaffolding_iterate(NULL);
while (current != NULL) {
nsgtk_scaffolding_reset_offset(current);
nsgtk_scaffolding_toolbars(current, nsoption_int(button_type));
current = nsgtk_scaffolding_iterate(current);
}
}
G_MODULE_EXPORT void
nsgtk_preferences_comboButtonType_realize(GtkWidget *widget,
struct ppref *priv)
{
gtk_combo_box_set_active(GTK_COMBO_BOX(widget),
nsoption_int(button_type) - 1);
}
/************ Main ************/
/* Startup */
/* entry HomePageURL widget */
ENTRY_SIGNALS(entryHomePageURL, homepage_url)
/* put current page into homepage url */
G_MODULE_EXPORT void
nsgtk_preferences_setCurrentPage_clicked(GtkButton *button, struct ppref *priv)
{
const gchar *url = nsurl_access(browser_window_get_url(priv->bw));
if (priv->entryHomePageURL != NULL) {
gtk_entry_set_text(GTK_ENTRY(priv->entryHomePageURL), url);
nsoption_set_charp(homepage_url, strdup(url));
}
}
/* put default page into homepage */
G_MODULE_EXPORT void
nsgtk_preferences_setDefaultPage_clicked(GtkButton *button, struct ppref *priv)
{
const gchar *url = NETSURF_HOMEPAGE;
if (priv->entryHomePageURL != NULL) {
gtk_entry_set_text(GTK_ENTRY(priv->entryHomePageURL), url);
nsoption_set_charp(homepage_url, strdup(url));
}
}
/* Search */
/* Url Search widget */
TOGGLEBUTTON_SIGNALS(checkUrlSearch, search_url_bar)
/* provider combo */
G_MODULE_EXPORT void
nsgtk_preferences_comboSearch_changed(GtkComboBox *widget, struct ppref *priv)
{
int provider;
provider = gtk_combo_box_get_active(widget);
/* set the option */
nsoption_set_int(search_provider, provider);
/* set search provider */
search_web_select_provider(provider);
}
G_MODULE_EXPORT void
nsgtk_preferences_comboSearch_realize(GtkWidget *widget, struct ppref *priv)
{
int iter;
const char *name;
int provider = nsoption_int(search_provider);
if (priv->search_providers != NULL) {
gtk_list_store_clear(priv->search_providers);
for (iter = search_web_iterate_providers(0, &name);
iter != -1;
iter = search_web_iterate_providers(iter, &name)) {
gtk_list_store_insert_with_values(priv->search_providers,
NULL, -1,
0, name, -1);
}
}
gtk_combo_box_set_active(GTK_COMBO_BOX(widget), provider);
}
/* Downloads */
/* clear downloads */
TOGGLEBUTTON_SIGNALS(checkClearDownloads, downloads_clear)
/* request overwite */
TOGGLEBUTTON_SIGNALS(checkRequestOverwrite, request_overwrite)
/* download location
*
* note selection-changed is used instead of file-set as the returned
* filename when that signal are used is incorrect. Though this signal
* does update frequently often with the same data.
*/
G_MODULE_EXPORT void
nsgtk_preferences_fileChooserDownloads_selectionchanged(GtkFileChooser *chooser,
struct ppref *priv)
{
gchar *dir;
dir = gtk_file_chooser_get_filename(chooser);
nsoption_set_charp(downloads_directory, strdup(dir));
g_free(dir);
}
G_MODULE_EXPORT void
nsgtk_preferences_fileChooserDownloads_realize(GtkWidget *widget,
struct ppref *priv)
{
gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(widget),
nsoption_charp(downloads_directory));
}
/************* Dialog window ***********/
/* dialog close and destroy events */
G_MODULE_EXPORT void
nsgtk_preferences_dialogPreferences_response(GtkDialog *dlg, gint resid)
{
char *choices = NULL;
if (resid == GTK_RESPONSE_CLOSE) {
netsurf_mkpath(&choices, NULL, 2, nsgtk_config_home, "Choices");
if (choices != NULL) {
nsoption_write(choices, NULL, NULL);
free(choices);
}
gtk_widget_hide(GTK_WIDGET(dlg));
}
}
G_MODULE_EXPORT gboolean
nsgtk_preferences_dialogPreferences_deleteevent(GtkDialog *dlg,
struct ppref *priv)
{
char *choices = NULL;
netsurf_mkpath(&choices, NULL, 2, nsgtk_config_home, "Choices");
if (choices != NULL) {
nsoption_write(choices, NULL, NULL);
free(choices);
}
gtk_widget_hide(GTK_WIDGET(dlg));
/* Delt with it by hiding window, no need to destory widget by
* default.
*/
return TRUE;
}
G_MODULE_EXPORT void
nsgtk_preferences_dialogPreferences_destroy(GtkDialog *dlg, struct ppref *priv)
{
char *choices = NULL;
netsurf_mkpath(&choices, NULL, 2, nsgtk_config_home, "Choices");
if (choices != NULL) {
nsoption_write(choices, NULL, NULL);
free(choices);
}
}
/* exported interface documented in gtk/preferences.h */
GtkWidget* nsgtk_preferences(struct browser_window *bw, GtkWindow *parent)
{
GtkBuilder *preferences_builder;
struct ppref *priv = &ppref;
nserror res;
priv->bw = bw; /* for setting "current" page */
/* memoised dialog creation */
if (priv->dialog != NULL) {
gtk_window_set_transient_for(GTK_WINDOW(priv->dialog), parent);
return GTK_WIDGET(priv->dialog);
}
res = nsgtk_builder_new_from_resname("options", &preferences_builder);
if (res != NSERROR_OK) {
LOG("Preferences UI builder init failed");
return NULL;
}
priv->dialog = gtk_builder_get_object(preferences_builder,
"dialogPreferences");
if (priv->dialog == NULL) {
LOG("Unable to get object for preferences dialog");
/* release builder as were done with it */
g_object_unref(G_OBJECT(preferences_builder));
return NULL;
}
/* need to explicitly obtain handles for some widgets enabling
* updates by other widget events
*/
#define GB(TYPE, NAME) GTK_##TYPE(gtk_builder_get_object(preferences_builder, #NAME))
priv->entryHomePageURL = GB(ENTRY, entryHomePageURL);
priv->content_language = GB(LIST_STORE, liststore_content_language);
priv->search_providers = GB(LIST_STORE, liststore_search_provider);
priv->entryProxyHost = GB(ENTRY, entryProxyHost);
priv->spinProxyPort = GB(SPIN_BUTTON, spinProxyPort);
priv->entryProxyUser = GB(ENTRY, entryProxyUser);
priv->entryProxyPassword = GB(ENTRY, entryProxyPassword);
priv->entryProxyNoproxy = GB(ENTRY, entryProxyNoproxy);
#undef GB
/* connect all signals ready to use */
gtk_builder_connect_signals(preferences_builder, priv);
/* release builder as were done with it */
g_object_unref(G_OBJECT(preferences_builder));
/* mark dialog as transient on parent */
gtk_window_set_transient_for(GTK_WINDOW(priv->dialog), parent);
return GTK_WIDGET(priv->dialog);
}