midori/midori/sokoke.c
Christian Dywan be4038e555 Remove GIO HTTPS check again, it's not worth the trouble
Apparently lots of users cannot use Midori
after this change and with no way to track down
the cause of the issue, let's just not use this.
The check was only for minimal gain anyway
2008-08-28 00:55:35 +02:00

629 lines
20 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.
*/
#if HAVE_CONFIG_H
#include <config.h>
#endif
#include "sokoke.h"
#include "main.h"
#if HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <string.h>
#include <gdk/gdkkeysyms.h>
#include <glib/gi18n.h>
#include <glib/gprintf.h>
static void
error_dialog (const gchar* short_message,
const gchar* detailed_message)
{
GtkWidget* dialog = gtk_message_dialog_new (
NULL, 0, GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, short_message);
gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
"%s", detailed_message);
gtk_widget_show (dialog);
g_signal_connect_swapped (dialog, "response",
G_CALLBACK (gtk_widget_destroy), dialog);
}
gboolean
sokoke_spawn_program (const gchar* command,
const gchar* argument)
{
gchar* argument_escaped;
gchar* command_ready;
gchar** argv;
GError* error;
argument_escaped = g_shell_quote (argument);
if (strstr (command, "%s"))
command_ready = g_strdup_printf (command, argument_escaped);
else
command_ready = g_strconcat (command, " ", argument_escaped, NULL);
error = NULL;
if (!g_shell_parse_argv (command_ready, NULL, &argv, &error))
{
error_dialog (_("Could not run external program."), error->message);
g_error_free (error);
g_free (command_ready);
g_free (argument_escaped);
return FALSE;
}
error = NULL;
if (!g_spawn_async (NULL, argv, NULL,
(GSpawnFlags)G_SPAWN_SEARCH_PATH | G_SPAWN_DO_NOT_REAP_CHILD,
NULL, NULL, NULL, &error))
{
error_dialog (_("Could not run external program."), error->message);
g_error_free (error);
}
g_strfreev (argv);
g_free (command_ready);
g_free (argument_escaped);
return TRUE;
}
gchar*
sokoke_magic_uri (const gchar* uri,
KatzeArray* search_engines)
{
gchar* current_dir;
gchar* result;
gchar* search;
const gchar* search_uri;
gchar** parts;
KatzeItem* item;
g_return_val_if_fail (uri, NULL);
if (search_engines)
g_return_val_if_fail (katze_array_is_a (search_engines, KATZE_TYPE_ITEM), NULL);
/* Add file:// if we have a local path */
if (g_path_is_absolute (uri))
return g_strconcat ("file://", uri, NULL);
/* Construct an absolute path if the file is relative */
if (g_file_test (uri, G_FILE_TEST_EXISTS)
&& g_file_test (uri, G_FILE_TEST_IS_REGULAR))
{
current_dir = g_get_current_dir ();
result = g_strconcat ("file://", current_dir,
G_DIR_SEPARATOR_S, uri, NULL);
g_free (current_dir);
return result;
}
/* Do we need to add a protocol? */
if (!strstr (uri, "://"))
{
/* Do we have a domain, ip address or localhost? */
if (strchr (uri, '.') != NULL || !strcmp (uri, "localhost"))
return g_strconcat ("http://", uri, NULL);
/* We don't want to search? So return early. */
if (!search_engines)
return g_strdup (uri);
search = NULL;
search_uri = NULL;
/* Do we have a keyword and a string? */
parts = g_strsplit (uri, " ", 2);
if (parts[0] && parts[1])
{
item = katze_array_find_token (search_engines, parts[0]);
if (item)
search_uri = katze_item_get_uri (item);
}
g_free (parts);
if (search_uri)
search = g_strdup_printf (search_uri, parts[1]);
return search;
}
return g_strdup (uri);
}
void
sokoke_entry_setup_completion (GtkEntry* entry)
{
/* TODO: The current behavior works only with the beginning of strings
But we want to match "localhost" with "loc" and "hos" */
GtkEntryCompletion* completion = gtk_entry_completion_new ();
gtk_entry_completion_set_model (completion,
GTK_TREE_MODEL (gtk_list_store_new (1, G_TYPE_STRING)));
gtk_entry_completion_set_text_column (completion, 0);
gtk_entry_completion_set_minimum_key_length (completion, 3);
gtk_entry_set_completion (entry, completion);
/* FIXME: Completion doesn't work well, so it's disabled */
gtk_entry_completion_set_popup_completion (completion, FALSE);
}
void
sokoke_entry_append_completion (GtkEntry* entry, const gchar* text)
{
GtkEntryCompletion* completion = gtk_entry_get_completion (entry);
GtkTreeModel* completion_store = gtk_entry_completion_get_model (completion);
GtkTreeIter iter;
gtk_list_store_insert (GTK_LIST_STORE (completion_store), &iter, 0);
gtk_list_store_set (GTK_LIST_STORE (completion_store), &iter, 0, text, -1);
}
void
sokoke_combo_box_add_strings (GtkComboBox* combobox,
const gchar* label_first, ...)
{
/* Add a number of strings to a combobox, terminated with NULL
This works only for text comboboxes */
va_list args;
va_start (args, label_first);
const gchar* label;
for (label = label_first; 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);
}
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;
}
GtkWidget*
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;
}
GtkWidget*
sokoke_superuser_warning_new (void)
{
/* Create a horizontal bar with a security warning
This returns NULL if the user is no superuser */
#if 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,
&GTK_WIDGET (label)->style->fg[GTK_STATE_SELECTED]);
gtk_widget_show (label);
gtk_container_add (GTK_CONTAINER(hbox), GTK_WIDGET (label));
gtk_widget_show (hbox);
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* title_bold = g_strdup_printf ("<b>%s</b>", title);
GtkWidget* label = gtk_label_new (NULL);
gtk_label_set_markup (GTK_LABEL (label), title_bold);
g_free (title_bold);
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* font_description = pango_font_description_new ();
pango_font_description_set_style (font_description, PANGO_STYLE_ITALIC);
gtk_widget_modify_font (widget, font_description);
pango_font_description_free (font_description);
}
}
static gboolean
sokoke_on_entry_focus_in_event (GtkEntry* entry,
GdkEventFocus* event,
gpointer userdata)
{
gint has_default = GPOINTER_TO_INT (
g_object_get_data (G_OBJECT (entry), "sokoke_has_default"));
if (has_default)
{
gtk_entry_set_text (entry, "");
g_object_set_data (G_OBJECT(entry), "sokoke_has_default",
GINT_TO_POINTER (0));
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* default_text = (const gchar*)g_object_get_data (
G_OBJECT (entry), "sokoke_default_text");
gtk_entry_set_text (entry, default_text);
g_object_set_data (G_OBJECT(entry),
"sokoke_has_default", GINT_TO_POINTER (1));
sokoke_widget_set_pango_font_style (GTK_WIDGET (entry),
PANGO_STYLE_ITALIC);
}
return FALSE;
}
void
sokoke_entry_set_default_text (GtkEntry* entry,
const gchar* default_text)
{
/* Note: The default text initially overwrites any previous text */
gchar* old_value = g_object_get_data (G_OBJECT (entry),
"sokoke_default_text");
if (!old_value)
{
g_object_set_data (G_OBJECT (entry), "sokoke_has_default",
GINT_TO_POINTER (1));
sokoke_widget_set_pango_font_style (GTK_WIDGET (entry),
PANGO_STYLE_ITALIC);
gtk_entry_set_text (entry, default_text);
}
else if (!GTK_WIDGET_HAS_FOCUS (GTK_WIDGET (entry)))
{
gint has_default = GPOINTER_TO_INT (
g_object_get_data (G_OBJECT (entry), "sokoke_has_default"));
if (has_default)
{
gtk_entry_set_text (entry, default_text);
sokoke_widget_set_pango_font_style (GTK_WIDGET (entry),
PANGO_STYLE_ITALIC);
}
}
g_object_set_data (G_OBJECT (entry), "sokoke_default_text",
(gpointer)default_text);
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* key_file,
const gchar* group,
const gchar* key,
const gchar* default_value,
GError** error)
{
gchar* value = g_key_file_get_string (key_file, group, key, error);
return value == NULL ? g_strdup (default_value) : value;
}
gint
sokoke_key_file_get_integer_default (GKeyFile* key_file,
const gchar* group,
const gchar* key,
const gint default_value,
GError** error)
{
if (!g_key_file_has_key (key_file, group, key, NULL))
return default_value;
return g_key_file_get_integer (key_file, group, key, error);
}
gdouble
sokoke_key_file_get_double_default (GKeyFile* key_file,
const gchar* group,
const gchar* key,
const gdouble default_value,
GError** error)
{
if (!g_key_file_has_key (key_file, group, key, NULL))
return default_value;
return g_key_file_get_double (key_file, 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* key_file,
const gchar* filename,
GError** error)
{
gchar* data = g_key_file_to_data (key_file, 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* width,
gint* height)
{
PangoLayout* layout = gtk_widget_create_pango_layout (widget, text);
pango_layout_get_pixel_size (layout, width, height);
g_object_unref (layout);
}
GdkPixbuf*
sokoke_web_icon (const gchar* icon,
GtkIconSize size,
GtkWidget* widget)
{
g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL);
GdkPixbuf* pixbuf = NULL;
if (icon && *icon)
{
/* TODO: We want to allow http as well, maybe also base64? */
const gchar* icon_ready = g_str_has_prefix (icon, "file://")
? &icon[7] : icon;
GtkStockItem stock_id;
if (gtk_stock_lookup (icon, &stock_id))
pixbuf = gtk_widget_render_icon (widget, icon_ready, size, NULL);
else
{
gint width, height;
if (gtk_widget_has_screen (widget))
{
GdkScreen* screen = gtk_widget_get_screen (widget);
gtk_icon_size_lookup_for_settings (
gtk_settings_get_for_screen (screen),
size, &width, &height);
pixbuf = gtk_icon_theme_load_icon (
gtk_icon_theme_get_for_screen (screen), icon,
MAX (width, height), GTK_ICON_LOOKUP_USE_BUILTIN, NULL);
}
}
if (!pixbuf)
pixbuf = gdk_pixbuf_new_from_file_at_size (icon_ready, 16, 16, NULL);
}
if (!pixbuf)
pixbuf = gtk_widget_render_icon (widget, GTK_STOCK_FIND, size, NULL);
return pixbuf;
}
gint
sokoke_object_get_int (gpointer object,
const gchar* property)
{
gint value = 0;
g_return_val_if_fail (object != NULL, FALSE);
g_return_val_if_fail (G_IS_OBJECT (object), FALSE);
/* FIXME: Check value type */
g_object_get (object, property, &value, NULL);
return value;
}
gboolean
sokoke_object_get_boolean (gpointer object,
const gchar* property)
{
gboolean value = FALSE;
g_return_val_if_fail (object != NULL, FALSE);
g_return_val_if_fail (G_IS_OBJECT (object), FALSE);
/* FIXME: Check value type */
g_object_get (object, property, &value, NULL);
return value;
}
/**
* sokoke_action_create_popup_menu_item:
* @action: a #GtkAction
*
* Creates a menu item from an action, just like
* gtk_action_create_menu_item() but it won't
* display an accelerator.
*
* Return value: a new #GtkMenuItem
**/
GtkWidget*
sokoke_action_create_popup_menu_item (GtkAction* action)
{
GtkWidget* menuitem;
menuitem = gtk_image_menu_item_new_with_mnemonic ("");
gtk_action_connect_proxy (action, menuitem);
return menuitem;
}