Switch configuration logic from a custom structure to fully rely on MidoriWebSettings. This includes revamping the preferences dialog. The old logic is not yet replaced completely, this will follow soon, thus several settings will have no effect right now.
370 lines
12 KiB
C
370 lines
12 KiB
C
/*
|
|
Copyright (C) 2007-2008 Christian Dywan <christian@twotoasts.de>
|
|
|
|
This library is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU Lesser General Public
|
|
License as published by the Free Software Foundation; either
|
|
version 2.1 of the License, or (at your option) any later version.
|
|
|
|
See the file COPYING for the full license text.
|
|
*/
|
|
|
|
#include "sokoke.h"
|
|
|
|
#include "debug.h"
|
|
|
|
#include <string.h>
|
|
#ifdef HAVE_UNISTD_H
|
|
#include <unistd.h>
|
|
#endif
|
|
#include <gdk/gdkkeysyms.h>
|
|
#include <glib/gi18n.h>
|
|
|
|
void sokoke_combo_box_add_strings(GtkComboBox* combobox
|
|
, const gchar* labelFirst, ...)
|
|
{
|
|
// Add a number of strings to a combobox, terminated with NULL
|
|
// This works only for text comboboxes
|
|
va_list args;
|
|
va_start(args, labelFirst);
|
|
|
|
const gchar* label;
|
|
for(label = labelFirst; label; label = va_arg(args, const gchar*))
|
|
gtk_combo_box_append_text(combobox, label);
|
|
|
|
va_end(args);
|
|
}
|
|
|
|
void sokoke_widget_set_visible(GtkWidget* widget, gboolean visible)
|
|
{
|
|
// Show or hide the widget
|
|
if(visible)
|
|
gtk_widget_show(widget);
|
|
else
|
|
gtk_widget_hide(widget);
|
|
}
|
|
|
|
void sokoke_container_show_children(GtkContainer* container)
|
|
{
|
|
// Show every child but not the container itself
|
|
gtk_container_foreach(container, (GtkCallback)(gtk_widget_show_all), NULL);
|
|
}
|
|
|
|
void sokoke_widget_set_tooltip_text(GtkWidget* widget, const gchar* text)
|
|
{
|
|
#if GTK_CHECK_VERSION(2, 12, 0)
|
|
gtk_widget_set_tooltip_text(widget, text);
|
|
#else
|
|
static GtkTooltips* tooltips;
|
|
if(!tooltips)
|
|
tooltips = gtk_tooltips_new();
|
|
gtk_tooltips_set_tip(tooltips, widget, text, NULL);
|
|
#endif
|
|
}
|
|
|
|
void sokoke_tool_item_set_tooltip_text(GtkToolItem* toolitem, const gchar* text)
|
|
{
|
|
// TODO: Use 2.12 api if available
|
|
GtkTooltips* tooltips = gtk_tooltips_new();
|
|
gtk_tool_item_set_tooltip(toolitem, tooltips, text, NULL);
|
|
}
|
|
|
|
typedef struct
|
|
{
|
|
GtkWidget* widget;
|
|
SokokeMenuPos position;
|
|
} SokokePopupInfo;
|
|
|
|
static void
|
|
sokoke_widget_popup_position_menu (GtkMenu* menu,
|
|
gint* x,
|
|
gint* y,
|
|
gboolean* push_in,
|
|
gpointer user_data)
|
|
{
|
|
gint wx, wy;
|
|
gint menu_width;
|
|
GtkRequisition menu_req;
|
|
GtkRequisition widget_req;
|
|
SokokePopupInfo* info = user_data;
|
|
GtkWidget* widget = info->widget;
|
|
|
|
// Retrieve size and position of both widget and menu
|
|
if (GTK_WIDGET_NO_WINDOW (widget))
|
|
{
|
|
gdk_window_get_position (widget->window, &wx, &wy);
|
|
wx += widget->allocation.x;
|
|
wy += widget->allocation.y;
|
|
}
|
|
else
|
|
gdk_window_get_origin (widget->window, &wx, &wy);
|
|
gtk_widget_size_request (GTK_WIDGET (menu), &menu_req);
|
|
gtk_widget_size_request (widget, &widget_req);
|
|
menu_width = menu_req.width;
|
|
gint widget_height = widget_req.height; // Better than allocation.height
|
|
|
|
// Calculate menu position
|
|
if (info->position == SOKOKE_MENU_POSITION_CURSOR)
|
|
; // Do nothing?
|
|
else if (info->position == SOKOKE_MENU_POSITION_RIGHT)
|
|
{
|
|
*x = wx + widget->allocation.width - menu_width;
|
|
*y = wy + widget_height;
|
|
} else if (info->position == SOKOKE_MENU_POSITION_LEFT)
|
|
{
|
|
*x = wx;
|
|
*y = wy + widget_height;
|
|
}
|
|
|
|
*push_in = TRUE;
|
|
}
|
|
|
|
|
|
void
|
|
sokoke_widget_popup (GtkWidget* widget,
|
|
GtkMenu* menu,
|
|
GdkEventButton* event,
|
|
SokokeMenuPos pos)
|
|
{
|
|
int button, event_time;
|
|
if (event)
|
|
{
|
|
button = event->button;
|
|
event_time = event->time;
|
|
}
|
|
else
|
|
{
|
|
button = 0;
|
|
event_time = gtk_get_current_event_time ();
|
|
}
|
|
|
|
if (!gtk_menu_get_attach_widget(menu))
|
|
gtk_menu_attach_to_widget (menu, widget, NULL);
|
|
|
|
if (widget)
|
|
{
|
|
SokokePopupInfo info = { widget, pos };
|
|
gtk_menu_popup (menu, NULL, NULL,
|
|
sokoke_widget_popup_position_menu, &info,
|
|
button, event_time);
|
|
}
|
|
else
|
|
gtk_menu_popup (menu, NULL, NULL, NULL, NULL, button, event_time);
|
|
}
|
|
|
|
typedef enum
|
|
{
|
|
SOKOKE_DESKTOP_UNTESTED,
|
|
SOKOKE_DESKTOP_XFCE,
|
|
SOKOKE_DESKTOP_UNKNOWN
|
|
} SokokeDesktop;
|
|
|
|
static SokokeDesktop sokoke_get_desktop(void)
|
|
{
|
|
static SokokeDesktop desktop = SOKOKE_DESKTOP_UNTESTED;
|
|
if(G_UNLIKELY(desktop == SOKOKE_DESKTOP_UNTESTED))
|
|
{
|
|
// Are we running in Xfce?
|
|
gint result; gchar* out; gchar* err;
|
|
gboolean success = g_spawn_command_line_sync(
|
|
"xprop -root _DT_SAVE_MODE | grep -q xfce4"
|
|
, &out, &err, &result, NULL);
|
|
if(success && !result)
|
|
desktop = SOKOKE_DESKTOP_XFCE;
|
|
else
|
|
desktop = SOKOKE_DESKTOP_UNKNOWN;
|
|
}
|
|
|
|
return desktop;
|
|
}
|
|
|
|
gpointer sokoke_xfce_header_new(const gchar* icon, const gchar* title)
|
|
{
|
|
// Create an xfce header with icon and title
|
|
// This returns NULL if the desktop is not xfce
|
|
if(sokoke_get_desktop() == SOKOKE_DESKTOP_XFCE)
|
|
{
|
|
GtkWidget* entry = gtk_entry_new();
|
|
gchar* markup;
|
|
GtkWidget* xfce_heading = gtk_event_box_new();
|
|
gtk_widget_modify_bg(xfce_heading, GTK_STATE_NORMAL
|
|
, &entry->style->base[GTK_STATE_NORMAL]);
|
|
GtkWidget* hbox = gtk_hbox_new(FALSE, 12);
|
|
gtk_container_set_border_width(GTK_CONTAINER(hbox), 6);
|
|
GtkWidget* image = gtk_image_new_from_icon_name(icon, GTK_ICON_SIZE_DIALOG);
|
|
gtk_box_pack_start(GTK_BOX(hbox), image, FALSE, FALSE, 0);
|
|
GtkWidget* label = gtk_label_new(NULL);
|
|
gtk_widget_modify_fg(label, GTK_STATE_NORMAL
|
|
, &entry->style->text[GTK_STATE_NORMAL]);
|
|
markup = g_strdup_printf("<span size='large' weight='bold'>%s</span>", title);
|
|
gtk_label_set_markup(GTK_LABEL(label), markup);
|
|
gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
|
|
gtk_container_add(GTK_CONTAINER(xfce_heading), hbox);
|
|
g_free(markup);
|
|
return xfce_heading;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
gpointer sokoke_superuser_warning_new(void)
|
|
{
|
|
// Create a horizontal bar with a security warning
|
|
// This returns NULL if the user is no superuser
|
|
#ifdef HAVE_UNISTD_H
|
|
if(G_UNLIKELY(!geteuid())) // effective superuser?
|
|
{
|
|
GtkWidget* hbox = gtk_event_box_new();
|
|
gtk_widget_modify_bg(hbox, GTK_STATE_NORMAL
|
|
, &hbox->style->bg[GTK_STATE_SELECTED]);
|
|
GtkWidget* label = gtk_label_new(_("Warning: You are using a superuser account!"));
|
|
gtk_misc_set_padding(GTK_MISC(label), 0, 2);
|
|
gtk_widget_modify_fg(GTK_WIDGET(label), GTK_STATE_NORMAL
|
|
, >K_WIDGET(label)->style->fg[GTK_STATE_SELECTED]);
|
|
gtk_container_add(GTK_CONTAINER(hbox), GTK_WIDGET(label));
|
|
return hbox;
|
|
}
|
|
#endif
|
|
return NULL;
|
|
}
|
|
|
|
GtkWidget* sokoke_hig_frame_new(const gchar* title)
|
|
{
|
|
// Create a frame with no actual frame but a bold label and indentation
|
|
GtkWidget* frame = gtk_frame_new(NULL);
|
|
gchar* titleBold = g_strdup_printf("<b>%s</b>", title);
|
|
GtkWidget* label = gtk_label_new(NULL);
|
|
gtk_label_set_markup(GTK_LABEL(label), titleBold);
|
|
g_free(titleBold);
|
|
gtk_frame_set_label_widget(GTK_FRAME(frame), label);
|
|
gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_NONE);
|
|
return frame;
|
|
}
|
|
|
|
void sokoke_widget_set_pango_font_style(GtkWidget* widget, PangoStyle style)
|
|
{
|
|
// Conveniently change the pango font style
|
|
// For some reason we need to reset if we actually want the normal style
|
|
if(style == PANGO_STYLE_NORMAL)
|
|
gtk_widget_modify_font(widget, NULL);
|
|
else
|
|
{
|
|
PangoFontDescription* fontDescription = pango_font_description_new();
|
|
pango_font_description_set_style(fontDescription, PANGO_STYLE_ITALIC);
|
|
gtk_widget_modify_font(widget, fontDescription);
|
|
pango_font_description_free(fontDescription);
|
|
}
|
|
}
|
|
|
|
static gboolean sokoke_on_entry_focus_in_event(GtkEntry* entry, GdkEventFocus *event
|
|
, gpointer userdata)
|
|
{
|
|
gboolean defaultText = (gboolean)g_object_get_data(G_OBJECT(entry)
|
|
, "sokoke_hasDefaultText");
|
|
if(defaultText)
|
|
{
|
|
gtk_entry_set_text(entry, "");
|
|
g_object_set_data(G_OBJECT(entry), "sokoke_hasDefaultText", (gpointer)FALSE);
|
|
sokoke_widget_set_pango_font_style(GTK_WIDGET(entry), PANGO_STYLE_NORMAL);
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
static gboolean sokoke_on_entry_focus_out_event(GtkEntry* entry, GdkEventFocus* event
|
|
, gpointer userdata)
|
|
{
|
|
const gchar* text = gtk_entry_get_text(entry);
|
|
if(text && !*text)
|
|
{
|
|
const gchar* defaultText = (const gchar*)g_object_get_data(
|
|
G_OBJECT(entry), "sokoke_defaultText");
|
|
gtk_entry_set_text(entry, defaultText);
|
|
g_object_set_data(G_OBJECT(entry), "sokoke_hasDefaultText", (gpointer)TRUE);
|
|
sokoke_widget_set_pango_font_style(GTK_WIDGET(entry), PANGO_STYLE_ITALIC);
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
void sokoke_entry_set_default_text(GtkEntry* entry, const gchar* defaultText)
|
|
{
|
|
// Note: The default text initially overwrites any previous text
|
|
gchar* oldValue = g_object_get_data(G_OBJECT(entry), "sokoke_defaultText");
|
|
if(!oldValue)
|
|
{
|
|
g_object_set_data(G_OBJECT(entry), "sokoke_hasDefaultText", (gpointer)TRUE);
|
|
sokoke_widget_set_pango_font_style(GTK_WIDGET(entry), PANGO_STYLE_ITALIC);
|
|
gtk_entry_set_text(entry, defaultText);
|
|
}
|
|
g_object_set_data(G_OBJECT(entry), "sokoke_defaultText", (gpointer)defaultText);
|
|
g_signal_connect(entry, "focus-in-event"
|
|
, G_CALLBACK(sokoke_on_entry_focus_in_event), NULL);
|
|
g_signal_connect(entry, "focus-out-event"
|
|
, G_CALLBACK(sokoke_on_entry_focus_out_event), NULL);
|
|
}
|
|
|
|
gchar* sokoke_key_file_get_string_default(GKeyFile* keyFile
|
|
, const gchar* group, const gchar* key, const gchar* defaultValue, GError** error)
|
|
{
|
|
gchar* value = g_key_file_get_string(keyFile, group, key, error);
|
|
return value == NULL ? g_strdup(defaultValue) : value;
|
|
}
|
|
|
|
gint sokoke_key_file_get_integer_default(GKeyFile* keyFile
|
|
, const gchar* group, const gchar* key, const gint defaultValue, GError** error)
|
|
{
|
|
if(!g_key_file_has_key(keyFile, group, key, NULL))
|
|
return defaultValue;
|
|
return g_key_file_get_integer(keyFile, group, key, error);
|
|
}
|
|
|
|
gboolean
|
|
sokoke_key_file_get_boolean_default (GKeyFile* key_file,
|
|
const gchar* group,
|
|
const gchar* key,
|
|
const gboolean default_value,
|
|
GError** error)
|
|
{
|
|
if (!g_key_file_has_key (key_file, group, key, NULL))
|
|
return default_value;
|
|
return g_key_file_get_boolean (key_file, group, key, error);
|
|
}
|
|
|
|
gboolean sokoke_key_file_save_to_file(GKeyFile* keyFile
|
|
, const gchar* filename, GError** error)
|
|
{
|
|
gchar* data = g_key_file_to_data(keyFile, NULL, error);
|
|
if(!data)
|
|
return FALSE;
|
|
FILE* fp;
|
|
if(!(fp = fopen(filename, "w")))
|
|
{
|
|
*error = g_error_new(G_FILE_ERROR, G_FILE_ERROR_ACCES
|
|
, _("Writing failed."));
|
|
return FALSE;
|
|
}
|
|
fputs(data, fp);
|
|
fclose(fp);
|
|
g_free(data);
|
|
return TRUE;
|
|
}
|
|
|
|
void sokoke_widget_get_text_size(GtkWidget* widget, const gchar* text
|
|
, gint* w, gint* h)
|
|
{
|
|
PangoLayout* layout = gtk_widget_create_pango_layout(widget, text);
|
|
pango_layout_get_pixel_size(layout, w, h);
|
|
g_object_unref(layout);
|
|
}
|
|
|
|
void sokoke_menu_item_set_accel(GtkMenuItem* menuitem, const gchar* path
|
|
, const gchar* key, GdkModifierType modifiers)
|
|
{
|
|
if(path && *path)
|
|
{
|
|
gchar* accel = g_strconcat("<", g_get_prgname(), ">/", path, NULL);
|
|
gtk_menu_item_set_accel_path(GTK_MENU_ITEM(menuitem), accel);
|
|
guint keyVal = key ? gdk_keyval_from_name(key) : 0;
|
|
gtk_accel_map_add_entry(accel, keyVal, modifiers);
|
|
g_free(accel);
|
|
}
|
|
}
|