netsurf/gtk/preferences.c

1208 lines
32 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 <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/theme.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 *themes;
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_comboTheme_changed(GtkComboBox *combo, struct ppref *priv);
G_MODULE_EXPORT void nsgtk_preferences_comboTheme_realize(GtkWidget *widget, struct ppref *priv);
G_MODULE_EXPORT void nsgtk_preferences_buttonAddTheme_clicked(GtkButton *button, 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 **********/
/* Themes */
/* select theme */
G_MODULE_EXPORT void
nsgtk_preferences_comboTheme_changed(GtkComboBox *combo, struct ppref *priv)
{
struct nsgtk_scaffolding *current;
int theme = 0;
gchar *name;
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)) {
/* get the row number for the config */
theme = gtk_combo_box_get_active(combo);
nsoption_set_int(current_theme, theme);
/* retrive the theme name if it is not the default */
if (theme != 0) {
/* Obtain data model from combo box. */
model = gtk_combo_box_get_model(combo);
/* Obtain string from model. */
gtk_tree_model_get(model, &iter, 0, &name, -1);
} else {
name = NULL;
}
nsgtk_theme_set_name(name);
if (name != NULL) {
g_free(name);
}
current = nsgtk_scaffolding_iterate(NULL);
while (current != NULL) {
nsgtk_theme_implement(current);
current = nsgtk_scaffolding_iterate(current);
}
}
}
G_MODULE_EXPORT void
nsgtk_preferences_comboTheme_realize(GtkWidget *widget, struct ppref *priv)
{
/* Fill theme list store */
FILE *fp;
GtkTreeIter iter;
char buf[50];
int combo_row_count = 0;
int selected_theme = 0;
if ((priv->themes != NULL) &&
(themelist_file_location != NULL) &&
((fp = fopen(themelist_file_location, "r")) != NULL)) {
gtk_list_store_clear(priv->themes);
LOG("Used %s for themelist", themelist_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(priv->themes, &iter);
gtk_list_store_set(priv->themes, &iter, 0, buf, -1);
combo_row_count++;
}
fclose(fp);
} else {
LOG("Failed opening themes file");
}
/* get configured theme and sanity check value */
selected_theme = nsoption_int(current_theme);
if (selected_theme > combo_row_count) {
selected_theme = combo_row_count;
}
if (selected_theme < 0) {
selected_theme = 0;
}
gtk_combo_box_set_active(GTK_COMBO_BOX(widget), selected_theme);
}
/* add theme */
G_MODULE_EXPORT void
nsgtk_preferences_buttonAddTheme_clicked(GtkButton *button, struct ppref *priv)
{
char *filename, *directory;
size_t len;
GtkWidget *fc;
char *themesfolder;
gint res;
fc = gtk_file_chooser_dialog_new(messages_get("gtkAddThemeTitle"),
GTK_WINDOW(priv->dialog),
GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER,
NSGTK_STOCK_OK,
GTK_RESPONSE_ACCEPT,
NSGTK_STOCK_CANCEL,
GTK_RESPONSE_CANCEL,
NULL);
len = SLEN("themes") + strlen(res_dir_location) + 1;
themesfolder = malloc(len);
snprintf(themesfolder, len, "%sthemes", res_dir_location);
gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(fc), themesfolder);
res = gtk_dialog_run(GTK_DIALOG(fc));
if (res == GTK_RESPONSE_ACCEPT) {
filename = gtk_file_chooser_get_current_folder(GTK_FILE_CHOOSER(fc));
if (filename != NULL) {
if (strcmp(filename, themesfolder) != 0) {
directory = strrchr(filename, '/');
*directory = '\0';
if (strcmp(filename, themesfolder) != 0) {
warn_user(messages_get(
"gtkThemeFolderInstructions"),
0);
if (filename != NULL)
g_free(filename);
} else {
directory++;
nsgtk_theme_add(directory);
}
} else {
g_free(filename);
filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(fc));
if (strcmp(filename, themesfolder) == 0) {
warn_user(messages_get("gtkThemeFolderSub"),
0);
} else {
directory = strrchr(filename, '/') + 1;
nsgtk_theme_add(directory);
}
}
g_free(filename);
}
}
free(themesfolder);
gtk_widget_destroy(fc);
}
/* 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->themes = GB(LIST_STORE, liststore_themes);
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);
}
/* exported interface documented in gtk/preferences.h */
void nsgtk_preferences_theme_add(const char *themename)
{
struct ppref *priv = &ppref;
GtkTreeIter iter;
gtk_list_store_append(priv->themes, &iter);
gtk_list_store_set(priv->themes, &iter, 0, themename, -1 );
}