+ + * Get rid of a number of unnecessary gnome.h includes + + * capplets/keybindings/gnome-keybinding-properties.c: Use + gtk_init() instead of gnome_program_init(). + + * A couple of formatting fixes + svn path=/trunk/; revision=9098
379 lines
10 KiB
C
379 lines
10 KiB
C
/*
|
|
* Copyright (C) 2007 The GNOME Foundation
|
|
* Written by Thomas Wood <thos@gnome.org>
|
|
* Jens Granseuer <jensgr@gmx.net>
|
|
* All Rights Reserved
|
|
*
|
|
* This program 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; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program 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, write to the Free Software Foundation, Inc.,
|
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
*/
|
|
|
|
#include "appearance.h"
|
|
|
|
#include <glib/gstdio.h>
|
|
#include <glib/gi18n.h>
|
|
#include <string.h>
|
|
|
|
#include "theme-save.h"
|
|
#include "theme-util.h"
|
|
#include "capplet-util.h"
|
|
|
|
static GQuark error_quark;
|
|
enum {
|
|
INVALID_THEME_NAME
|
|
};
|
|
|
|
/* taken from gnome-desktop-item.c */
|
|
static gchar *
|
|
escape_string_and_dup (const gchar *s)
|
|
{
|
|
gchar *return_value, *p;
|
|
const gchar *q;
|
|
int len = 0;
|
|
|
|
if (s == NULL)
|
|
return g_strdup("");
|
|
|
|
q = s;
|
|
while (*q)
|
|
{
|
|
len++;
|
|
if (strchr ("\n\r\t\\", *q) != NULL)
|
|
len++;
|
|
q++;
|
|
}
|
|
return_value = p = (gchar *) g_malloc (len + 1);
|
|
do
|
|
{
|
|
switch (*s)
|
|
{
|
|
case '\t':
|
|
*p++ = '\\';
|
|
*p++ = 't';
|
|
break;
|
|
case '\n':
|
|
*p++ = '\\';
|
|
*p++ = 'n';
|
|
break;
|
|
case '\r':
|
|
*p++ = '\\';
|
|
*p++ = 'r';
|
|
break;
|
|
case '\\':
|
|
*p++ = '\\';
|
|
*p++ = '\\';
|
|
break;
|
|
default:
|
|
*p++ = *s;
|
|
}
|
|
}
|
|
while (*s++);
|
|
return return_value;
|
|
}
|
|
|
|
static gboolean
|
|
check_theme_name (const gchar *theme_name,
|
|
GError **error)
|
|
{
|
|
if (theme_name == NULL) {
|
|
g_set_error (error,
|
|
error_quark,
|
|
INVALID_THEME_NAME,
|
|
_("Theme name must be present"));
|
|
return FALSE;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
static gchar *
|
|
str_remove_slash (const gchar *src)
|
|
{
|
|
const gchar *i;
|
|
gchar *rtn;
|
|
gint len = 0;
|
|
i = src;
|
|
|
|
while (*i) {
|
|
if (*i != '/')
|
|
len++;
|
|
i++;
|
|
}
|
|
|
|
rtn = (gchar *) g_malloc (len + 1);
|
|
while (*src) {
|
|
if (*src != '/') {
|
|
*rtn = *src;
|
|
rtn++;
|
|
}
|
|
src++;
|
|
}
|
|
*rtn = '\0';
|
|
return rtn - len;
|
|
}
|
|
|
|
static gboolean
|
|
setup_directory_structure (const gchar *theme_name,
|
|
GError **error)
|
|
{
|
|
gchar *dir, *theme_name_dir;
|
|
gboolean retval = TRUE;
|
|
|
|
theme_name_dir = str_remove_slash (theme_name);
|
|
|
|
dir = g_build_filename (g_get_home_dir (), ".themes", NULL);
|
|
if (!g_file_test (dir, G_FILE_TEST_EXISTS))
|
|
g_mkdir (dir, 0775);
|
|
g_free (dir);
|
|
|
|
dir = g_build_filename (g_get_home_dir (), ".themes", theme_name_dir, NULL);
|
|
if (!g_file_test (dir, G_FILE_TEST_EXISTS))
|
|
g_mkdir (dir, 0775);
|
|
g_free (dir);
|
|
|
|
dir = g_build_filename (g_get_home_dir (), ".themes", theme_name_dir, "index.theme", NULL);
|
|
g_free (theme_name_dir);
|
|
|
|
if (g_file_test (dir, G_FILE_TEST_EXISTS)) {
|
|
GtkDialog *dialog;
|
|
GtkWidget *button;
|
|
gint response;
|
|
|
|
dialog = (GtkDialog *) gtk_message_dialog_new (NULL,
|
|
GTK_DIALOG_MODAL,
|
|
GTK_MESSAGE_QUESTION,
|
|
GTK_BUTTONS_CANCEL,
|
|
_("The theme already exists. Would you like to replace it?"));
|
|
button = gtk_dialog_add_button (dialog, _("_Overwrite"), GTK_RESPONSE_ACCEPT);
|
|
gtk_button_set_image (GTK_BUTTON (button),
|
|
gtk_image_new_from_stock (GTK_STOCK_SAVE, GTK_ICON_SIZE_BUTTON));
|
|
response = gtk_dialog_run (dialog);
|
|
gtk_widget_destroy (GTK_WIDGET (dialog));
|
|
retval = (response != GTK_RESPONSE_CANCEL);
|
|
}
|
|
g_free (dir);
|
|
|
|
return retval;
|
|
}
|
|
|
|
static gboolean
|
|
write_theme_to_disk (GnomeThemeMetaInfo *theme_info,
|
|
const gchar *theme_name,
|
|
const gchar *theme_description,
|
|
gboolean save_background,
|
|
GError **error)
|
|
{
|
|
gchar *dir, *theme_name_dir;
|
|
GFile *tmp_file;
|
|
GFile *target_file;
|
|
GOutputStream *output;
|
|
|
|
gchar *str, *current_background;
|
|
GConfClient *client;
|
|
const gchar *theme_header =
|
|
"[Desktop Entry]\n"
|
|
"Name=%s\n"
|
|
"Type=X-GNOME-Metatheme\n"
|
|
"Comment=%s\n"
|
|
"\n"
|
|
"[X-GNOME-Metatheme]\n"
|
|
"GtkTheme=%s\n"
|
|
"MetacityTheme=%s\n"
|
|
"IconTheme=%s\n";
|
|
|
|
theme_name_dir = str_remove_slash (theme_name);
|
|
dir = g_build_filename (g_get_home_dir (), ".themes", theme_name_dir, "index.theme~", NULL);
|
|
g_free (theme_name_dir);
|
|
|
|
tmp_file = g_file_new_for_path (dir);
|
|
dir [strlen (dir) - 1] = '\000';
|
|
target_file = g_file_new_for_path (dir);
|
|
g_free (dir);
|
|
|
|
/* start making the theme file */
|
|
str = g_strdup_printf (theme_header, theme_name, theme_description,
|
|
theme_info->gtk_theme_name,
|
|
theme_info->metacity_theme_name,
|
|
theme_info->icon_theme_name);
|
|
|
|
output = G_OUTPUT_STREAM (g_file_replace (tmp_file, NULL, FALSE, G_FILE_CREATE_NONE, NULL, NULL));
|
|
g_output_stream_write (output, str, strlen (str), NULL, NULL);
|
|
g_free (str);
|
|
|
|
if (theme_info->gtk_color_scheme) {
|
|
gchar *a, *tmp;
|
|
tmp = g_strdup (theme_info->gtk_color_scheme);
|
|
for (a = tmp; *a != '\0'; a++)
|
|
if (*a == '\n')
|
|
*a = ',';
|
|
str = g_strdup_printf ("GtkColorScheme=%s\n", tmp);
|
|
g_output_stream_write (output, str, strlen (str), NULL, NULL);
|
|
|
|
g_free (str);
|
|
g_free (tmp);
|
|
}
|
|
|
|
if (theme_info->cursor_theme_name) {
|
|
#ifdef HAVE_XCURSOR
|
|
str = g_strdup_printf ("CursorTheme=%s\n"
|
|
"CursorSize=%i\n",
|
|
theme_info->cursor_theme_name,
|
|
theme_info->cursor_size);
|
|
#else
|
|
str = g_strdup_printf ("CursorFont=%s\n", theme_info->cursor_theme_name);
|
|
#endif
|
|
g_output_stream_write (output, str, strlen (str), NULL, NULL);
|
|
g_free (str);
|
|
}
|
|
|
|
if (theme_info->notification_theme_name) {
|
|
str = g_strdup_printf ("NotificationTheme=%s\n", theme_info->notification_theme_name);
|
|
g_output_stream_write (output, str, strlen (str), NULL, NULL);
|
|
g_free (str);
|
|
}
|
|
|
|
if (save_background) {
|
|
client = gconf_client_get_default ();
|
|
current_background = gconf_client_get_string (client, BACKGROUND_KEY, NULL);
|
|
|
|
if (current_background != NULL) {
|
|
str = g_strdup_printf ("BackgroundImage=%s\n", current_background);
|
|
|
|
g_output_stream_write (output, str, strlen (str), NULL, NULL);
|
|
|
|
g_free (current_background);
|
|
g_free (str);
|
|
}
|
|
g_object_unref (client);
|
|
}
|
|
|
|
g_file_move (tmp_file, target_file, G_FILE_COPY_OVERWRITE, NULL, NULL, NULL, NULL);
|
|
g_output_stream_close (output, NULL, NULL);
|
|
|
|
g_object_unref (tmp_file);
|
|
g_object_unref (target_file);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static gboolean
|
|
save_theme_to_disk (GnomeThemeMetaInfo *theme_info,
|
|
const gchar *theme_name,
|
|
const gchar *theme_description,
|
|
gboolean save_background,
|
|
GError **error)
|
|
{
|
|
if (!check_theme_name (theme_name, error))
|
|
return FALSE;
|
|
|
|
if (!setup_directory_structure (theme_name, error))
|
|
return FALSE;
|
|
|
|
if (!write_theme_to_disk (theme_info, theme_name, theme_description, save_background, error))
|
|
return FALSE;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static void
|
|
save_dialog_response (GtkWidget *save_dialog,
|
|
gint response_id,
|
|
AppearanceData *data)
|
|
{
|
|
if (response_id == GTK_RESPONSE_OK) {
|
|
GtkWidget *entry;
|
|
GtkWidget *text_view;
|
|
GtkTextBuffer *buffer;
|
|
GtkTextIter start_iter;
|
|
GtkTextIter end_iter;
|
|
gchar *buffer_text;
|
|
GnomeThemeMetaInfo *theme_info;
|
|
gchar *theme_description = NULL;
|
|
gchar *theme_name = NULL;
|
|
gboolean save_background;
|
|
GError *error = NULL;
|
|
|
|
entry = glade_xml_get_widget (data->xml, "save_dialog_entry");
|
|
theme_name = escape_string_and_dup (gtk_entry_get_text (GTK_ENTRY (entry)));
|
|
|
|
text_view = glade_xml_get_widget (data->xml, "save_dialog_textview");
|
|
buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (text_view));
|
|
gtk_text_buffer_get_start_iter (buffer, &start_iter);
|
|
gtk_text_buffer_get_end_iter (buffer, &end_iter);
|
|
buffer_text = gtk_text_buffer_get_text (buffer, &start_iter, &end_iter, FALSE);
|
|
theme_description = escape_string_and_dup (buffer_text);
|
|
g_free (buffer_text);
|
|
theme_info = (GnomeThemeMetaInfo *) g_object_get_data (G_OBJECT (save_dialog), "meta-theme-info");
|
|
save_background = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (
|
|
glade_xml_get_widget (data->xml, "save_background_checkbutton")));
|
|
|
|
if (save_theme_to_disk (theme_info, theme_name, theme_description, save_background, &error)) {
|
|
/* remove the custom theme */
|
|
GtkTreeIter iter;
|
|
|
|
if (theme_find_in_model (GTK_TREE_MODEL (data->theme_store), "__custom__", &iter))
|
|
gtk_list_store_remove (data->theme_store, &iter);
|
|
}
|
|
|
|
g_free (theme_name);
|
|
g_free (theme_description);
|
|
g_clear_error (&error);
|
|
}
|
|
|
|
gtk_widget_hide (save_dialog);
|
|
}
|
|
|
|
static void
|
|
entry_text_changed (GtkEditable *editable,
|
|
GladeXML *dialog)
|
|
{
|
|
const gchar *text;
|
|
|
|
text = gtk_entry_get_text (GTK_ENTRY (editable));
|
|
gtk_widget_set_sensitive (glade_xml_get_widget (dialog, "save_dialog_save_button"),
|
|
text != NULL && text[0] != '\000');
|
|
}
|
|
|
|
void
|
|
theme_save_dialog_run (GnomeThemeMetaInfo *theme_info,
|
|
AppearanceData *data)
|
|
{
|
|
GtkWidget *entry;
|
|
GtkWidget *text_view;
|
|
GtkTextBuffer *text_buffer;
|
|
|
|
entry = glade_xml_get_widget (data->xml, "save_dialog_entry");
|
|
text_view = glade_xml_get_widget (data->xml, "save_dialog_textview");
|
|
|
|
if (data->theme_save_dialog == NULL) {
|
|
data->theme_save_dialog = glade_xml_get_widget (data->xml, "theme_save_dialog");
|
|
|
|
g_signal_connect (data->theme_save_dialog, "response", (GCallback) save_dialog_response, data);
|
|
g_signal_connect (data->theme_save_dialog, "delete-event", (GCallback) gtk_true, NULL);
|
|
g_signal_connect (entry, "changed", (GCallback) entry_text_changed, data->xml);
|
|
|
|
error_quark = g_quark_from_string ("gnome-theme-save");
|
|
gtk_widget_set_size_request (text_view, 300, 100);
|
|
}
|
|
|
|
gtk_entry_set_text (GTK_ENTRY (entry), "");
|
|
entry_text_changed (GTK_EDITABLE (entry), data->xml);
|
|
gtk_widget_grab_focus (entry);
|
|
|
|
text_buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (text_view));
|
|
gtk_text_buffer_set_text (text_buffer, "", 0);
|
|
g_object_set_data (G_OBJECT (data->theme_save_dialog), "meta-theme-info", theme_info);
|
|
gtk_window_set_transient_for (GTK_WINDOW (data->theme_save_dialog),
|
|
GTK_WINDOW (glade_xml_get_widget (data->xml, "appearance_window")));
|
|
gtk_widget_show (data->theme_save_dialog);
|
|
}
|