1208 lines
32 KiB
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 );
|
|
}
|