| File: | capplets/appearance/theme-save.c |
| Warning: | line 79, column 4 Access of the heap area at index 2, while it holds only 2 'char' elements |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
| 1 | /* | |||
| 2 | * Copyright (C) 2007 The GNOME Foundation | |||
| 3 | * Written by Thomas Wood <thos@gnome.org> | |||
| 4 | * Jens Granseuer <jensgr@gmx.net> | |||
| 5 | * All Rights Reserved | |||
| 6 | * | |||
| 7 | * This program is free software; you can redistribute it and/or modify | |||
| 8 | * it under the terms of the GNU General Public License as published by | |||
| 9 | * the Free Software Foundation; either version 2 of the License, or | |||
| 10 | * (at your option) any later version. | |||
| 11 | * | |||
| 12 | * This program is distributed in the hope that it will be useful, | |||
| 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
| 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
| 15 | * GNU General Public License for more details. | |||
| 16 | * | |||
| 17 | * You should have received a copy of the GNU General Public License along | |||
| 18 | * with this program; if not, write to the Free Software Foundation, Inc., | |||
| 19 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | |||
| 20 | */ | |||
| 21 | ||||
| 22 | #include "appearance.h" | |||
| 23 | ||||
| 24 | #include <glib/gstdio.h> | |||
| 25 | #include <glib/gi18n.h> | |||
| 26 | #include <gio/gio.h> | |||
| 27 | #include <string.h> | |||
| 28 | ||||
| 29 | #include "theme-save.h" | |||
| 30 | #include "theme-util.h" | |||
| 31 | #include "capplet-util.h" | |||
| 32 | ||||
| 33 | static GQuark error_quark; | |||
| 34 | enum { | |||
| 35 | INVALID_THEME_NAME | |||
| 36 | }; | |||
| 37 | ||||
| 38 | /* taken from cafe-desktop-item.c */ | |||
| 39 | static gchar * | |||
| 40 | escape_string_and_dup (const gchar *s) | |||
| 41 | { | |||
| 42 | gchar *return_value, *p; | |||
| 43 | const gchar *q; | |||
| 44 | int len = 0; | |||
| 45 | ||||
| 46 | if (s == NULL((void*)0)) | |||
| 47 | return g_strdup("")g_strdup_inline (""); | |||
| 48 | ||||
| 49 | q = s; | |||
| 50 | while (*q) | |||
| 51 | { | |||
| 52 | len++; | |||
| 53 | if (strchr ("\n\r\t\\", *q) != NULL((void*)0)) | |||
| 54 | len++; | |||
| 55 | q++; | |||
| 56 | } | |||
| 57 | return_value = p = (gchar *) g_malloc (len + 1); | |||
| 58 | do | |||
| 59 | { | |||
| 60 | switch (*s) | |||
| 61 | { | |||
| 62 | case '\t': | |||
| 63 | *p++ = '\\'; | |||
| 64 | *p++ = 't'; | |||
| 65 | break; | |||
| 66 | case '\n': | |||
| 67 | *p++ = '\\'; | |||
| 68 | *p++ = 'n'; | |||
| 69 | break; | |||
| 70 | case '\r': | |||
| 71 | *p++ = '\\'; | |||
| 72 | *p++ = 'r'; | |||
| 73 | break; | |||
| 74 | case '\\': | |||
| 75 | *p++ = '\\'; | |||
| 76 | *p++ = '\\'; | |||
| 77 | break; | |||
| 78 | default: | |||
| 79 | *p++ = *s; | |||
| ||||
| 80 | } | |||
| 81 | } | |||
| 82 | while (*s++); | |||
| 83 | return return_value; | |||
| 84 | } | |||
| 85 | ||||
| 86 | static gboolean | |||
| 87 | check_theme_name (const gchar *theme_name, | |||
| 88 | GError **error) | |||
| 89 | { | |||
| 90 | if (theme_name == NULL((void*)0)) { | |||
| 91 | g_set_error (error, | |||
| 92 | error_quark, | |||
| 93 | INVALID_THEME_NAME, | |||
| 94 | _("Theme name must be present")gettext ("Theme name must be present")); | |||
| 95 | return FALSE(0); | |||
| 96 | } | |||
| 97 | return TRUE(!(0)); | |||
| 98 | } | |||
| 99 | ||||
| 100 | static gchar * | |||
| 101 | str_remove_slash (const gchar *src) | |||
| 102 | { | |||
| 103 | const gchar *i; | |||
| 104 | gchar *rtn; | |||
| 105 | gint len = 0; | |||
| 106 | i = src; | |||
| 107 | ||||
| 108 | while (*i) { | |||
| 109 | if (*i != '/') | |||
| 110 | len++; | |||
| 111 | i++; | |||
| 112 | } | |||
| 113 | ||||
| 114 | rtn = (gchar *) g_malloc (len + 1); | |||
| 115 | while (*src) { | |||
| 116 | if (*src != '/') { | |||
| 117 | *rtn = *src; | |||
| 118 | rtn++; | |||
| 119 | } | |||
| 120 | src++; | |||
| 121 | } | |||
| 122 | *rtn = '\0'; | |||
| 123 | return rtn - len; | |||
| 124 | } | |||
| 125 | ||||
| 126 | static gboolean | |||
| 127 | setup_directory_structure (const gchar *theme_name, | |||
| 128 | GError **error) | |||
| 129 | { | |||
| 130 | gchar *dir, *theme_name_dir; | |||
| 131 | gboolean retval = TRUE(!(0)); | |||
| 132 | ||||
| 133 | theme_name_dir = str_remove_slash (theme_name); | |||
| 134 | ||||
| 135 | dir = g_build_filename (g_get_home_dir (), ".themes", NULL((void*)0)); | |||
| 136 | if (!g_file_test (dir, G_FILE_TEST_EXISTS)) | |||
| 137 | g_mkdirmkdir (dir, 0775); | |||
| 138 | g_free (dir); | |||
| 139 | ||||
| 140 | dir = g_build_filename (g_get_home_dir (), ".themes", theme_name_dir, NULL((void*)0)); | |||
| 141 | if (!g_file_test (dir, G_FILE_TEST_EXISTS)) | |||
| 142 | g_mkdirmkdir (dir, 0775); | |||
| 143 | g_free (dir); | |||
| 144 | ||||
| 145 | dir = g_build_filename (g_get_home_dir (), ".themes", theme_name_dir, "index.theme", NULL((void*)0)); | |||
| 146 | g_free (theme_name_dir); | |||
| 147 | ||||
| 148 | if (g_file_test (dir, G_FILE_TEST_EXISTS)) { | |||
| 149 | CtkDialog *dialog; | |||
| 150 | CtkWidget *button; | |||
| 151 | gint response; | |||
| 152 | ||||
| 153 | dialog = (CtkDialog *) ctk_message_dialog_new (NULL((void*)0), | |||
| 154 | CTK_DIALOG_MODAL, | |||
| 155 | CTK_MESSAGE_QUESTION, | |||
| 156 | CTK_BUTTONS_CANCEL, | |||
| 157 | _("The theme already exists. Would you like to replace it?")gettext ("The theme already exists. Would you like to replace it?" )); | |||
| 158 | button = ctk_dialog_add_button (dialog, _("_Overwrite")gettext ("_Overwrite"), CTK_RESPONSE_ACCEPT); | |||
| 159 | ctk_button_set_image (CTK_BUTTON (button)((((CtkButton*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((button)), ((ctk_button_get_type ())))))), | |||
| 160 | ctk_image_new_from_icon_name ("document-save", CTK_ICON_SIZE_BUTTON)); | |||
| 161 | response = ctk_dialog_run (dialog); | |||
| 162 | ctk_widget_destroy (CTK_WIDGET (dialog)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((dialog)), ((ctk_widget_get_type ()))))))); | |||
| 163 | retval = (response != CTK_RESPONSE_CANCEL); | |||
| 164 | } | |||
| 165 | g_free (dir); | |||
| 166 | ||||
| 167 | return retval; | |||
| 168 | } | |||
| 169 | ||||
| 170 | static gboolean | |||
| 171 | write_theme_to_disk (CafeThemeMetaInfo *theme_info, | |||
| 172 | const gchar *theme_name, | |||
| 173 | const gchar *theme_description, | |||
| 174 | gboolean save_background, | |||
| 175 | gboolean save_notification, | |||
| 176 | GError **error) | |||
| 177 | { | |||
| 178 | gchar* dir; | |||
| 179 | gchar* theme_name_dir; | |||
| 180 | GFile* tmp_file; | |||
| 181 | GFile* target_file; | |||
| 182 | GOutputStream* output; | |||
| 183 | ||||
| 184 | gchar* str; | |||
| 185 | gchar* current_background; | |||
| 186 | ||||
| 187 | GSettings* settings; | |||
| 188 | const gchar* theme_header = "" | |||
| 189 | "[Desktop Entry]\n" | |||
| 190 | "Name=%s\n" | |||
| 191 | "Type=X-GNOME-Metatheme\n" | |||
| 192 | "Comment=%s\n" | |||
| 193 | "\n" | |||
| 194 | "[X-GNOME-Metatheme]\n" | |||
| 195 | "CtkTheme=%s\n" | |||
| 196 | "MetacityTheme=%s\n" | |||
| 197 | "IconTheme=%s\n"; | |||
| 198 | ||||
| 199 | theme_name_dir = str_remove_slash (theme_name); | |||
| 200 | dir = g_build_filename (g_get_home_dir (), ".themes", theme_name_dir, "index.theme~", NULL((void*)0)); | |||
| 201 | g_free (theme_name_dir); | |||
| 202 | ||||
| 203 | tmp_file = g_file_new_for_path (dir); | |||
| 204 | dir [strlen (dir) - 1] = '\000'; | |||
| 205 | target_file = g_file_new_for_path (dir); | |||
| 206 | g_free (dir); | |||
| 207 | ||||
| 208 | /* start making the theme file */ | |||
| 209 | str = g_strdup_printf(theme_header, theme_name, theme_description, theme_info->ctk_theme_name, theme_info->croma_theme_name, theme_info->icon_theme_name); | |||
| 210 | ||||
| 211 | output = G_OUTPUT_STREAM (g_file_replace (tmp_file, NULL, FALSE, G_FILE_CREATE_NONE, NULL, NULL))((((GOutputStream*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((g_file_replace (tmp_file, ((void*)0), (0), G_FILE_CREATE_NONE , ((void*)0), ((void*)0)))), ((g_output_stream_get_type ()))) ))); | |||
| 212 | g_output_stream_write (output, str, strlen (str), NULL((void*)0), NULL((void*)0)); | |||
| 213 | g_free (str); | |||
| 214 | ||||
| 215 | if (theme_info->ctk_color_scheme) { | |||
| 216 | gchar *a, *tmp; | |||
| 217 | tmp = g_strdup (theme_info->ctk_color_scheme)g_strdup_inline (theme_info->ctk_color_scheme); | |||
| 218 | for (a = tmp; *a != '\0'; a++) | |||
| 219 | if (*a == '\n') | |||
| 220 | *a = ','; | |||
| 221 | str = g_strdup_printf ("CtkColorScheme=%s\n", tmp); | |||
| 222 | g_output_stream_write (output, str, strlen (str), NULL((void*)0), NULL((void*)0)); | |||
| 223 | ||||
| 224 | g_free (str); | |||
| 225 | g_free (tmp); | |||
| 226 | } | |||
| 227 | ||||
| 228 | if (theme_info->cursor_theme_name) { | |||
| 229 | str = g_strdup_printf ("CursorTheme=%s\n" | |||
| 230 | "CursorSize=%i\n", | |||
| 231 | theme_info->cursor_theme_name, | |||
| 232 | theme_info->cursor_size); | |||
| 233 | g_output_stream_write (output, str, strlen (str), NULL((void*)0), NULL((void*)0)); | |||
| 234 | g_free (str); | |||
| 235 | } | |||
| 236 | ||||
| 237 | if (theme_info->notification_theme_name && save_notification) { | |||
| 238 | str = g_strdup_printf ("NotificationTheme=%s\n", theme_info->notification_theme_name); | |||
| 239 | g_output_stream_write (output, str, strlen (str), NULL((void*)0), NULL((void*)0)); | |||
| 240 | g_free (str); | |||
| 241 | } | |||
| 242 | ||||
| 243 | if (save_background) { | |||
| 244 | settings = g_settings_new (WP_SCHEMA"org.cafe.background"); | |||
| 245 | current_background = g_settings_get_string (settings, WP_FILE_KEY"picture-filename"); | |||
| 246 | ||||
| 247 | if (current_background != NULL((void*)0)) { | |||
| 248 | str = g_strdup_printf ("BackgroundImage=%s\n", current_background); | |||
| 249 | ||||
| 250 | g_output_stream_write (output, str, strlen (str), NULL((void*)0), NULL((void*)0)); | |||
| 251 | ||||
| 252 | g_free (current_background); | |||
| 253 | g_free (str); | |||
| 254 | } | |||
| 255 | g_object_unref (settings); | |||
| 256 | } | |||
| 257 | ||||
| 258 | g_file_move (tmp_file, target_file, G_FILE_COPY_OVERWRITE, NULL((void*)0), NULL((void*)0), NULL((void*)0), NULL((void*)0)); | |||
| 259 | g_output_stream_close (output, NULL((void*)0), NULL((void*)0)); | |||
| 260 | ||||
| 261 | g_object_unref (tmp_file); | |||
| 262 | g_object_unref (target_file); | |||
| 263 | ||||
| 264 | return TRUE(!(0)); | |||
| 265 | } | |||
| 266 | ||||
| 267 | static gboolean | |||
| 268 | save_theme_to_disk (CafeThemeMetaInfo *theme_info, | |||
| 269 | const gchar *theme_name, | |||
| 270 | const gchar *theme_description, | |||
| 271 | gboolean save_background, | |||
| 272 | gboolean save_notification, | |||
| 273 | GError **error) | |||
| 274 | { | |||
| 275 | if (!check_theme_name (theme_name, error)) | |||
| 276 | return FALSE(0); | |||
| 277 | ||||
| 278 | if (!setup_directory_structure (theme_name, error)) | |||
| 279 | return FALSE(0); | |||
| 280 | ||||
| 281 | if (!write_theme_to_disk (theme_info, theme_name, theme_description, save_background, save_notification, error)) | |||
| 282 | return FALSE(0); | |||
| 283 | ||||
| 284 | return TRUE(!(0)); | |||
| 285 | } | |||
| 286 | ||||
| 287 | static void | |||
| 288 | save_dialog_response (CtkWidget *save_dialog, | |||
| 289 | gint response_id, | |||
| 290 | AppearanceData *data) | |||
| 291 | { | |||
| 292 | if (response_id == CTK_RESPONSE_OK) { | |||
| ||||
| 293 | CtkWidget *entry; | |||
| 294 | CtkWidget *text_view; | |||
| 295 | CtkTextBuffer *buffer; | |||
| 296 | CtkTextIter start_iter; | |||
| 297 | CtkTextIter end_iter; | |||
| 298 | gchar *buffer_text; | |||
| 299 | CafeThemeMetaInfo *theme_info; | |||
| 300 | gchar *theme_description = NULL((void*)0); | |||
| 301 | gchar *theme_name = NULL((void*)0); | |||
| 302 | gboolean save_background; | |||
| 303 | gboolean save_notification; | |||
| 304 | GError *error = NULL((void*)0); | |||
| 305 | ||||
| 306 | entry = appearance_capplet_get_widget (data, "save_dialog_entry")(CtkWidget*) ctk_builder_get_object(data->ui, "save_dialog_entry" ); | |||
| 307 | theme_name = escape_string_and_dup (ctk_entry_get_text (CTK_ENTRY (entry)((((CtkEntry*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((entry)), ((ctk_entry_get_type ())))))))); | |||
| 308 | ||||
| 309 | text_view = appearance_capplet_get_widget (data, "save_dialog_textview")(CtkWidget*) ctk_builder_get_object(data->ui, "save_dialog_textview" ); | |||
| 310 | buffer = ctk_text_view_get_buffer (CTK_TEXT_VIEW (text_view)((((CtkTextView*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((text_view)), ((ctk_text_view_get_type ()))))))); | |||
| 311 | ctk_text_buffer_get_start_iter (buffer, &start_iter); | |||
| 312 | ctk_text_buffer_get_end_iter (buffer, &end_iter); | |||
| 313 | buffer_text = ctk_text_buffer_get_text (buffer, &start_iter, &end_iter, FALSE(0)); | |||
| 314 | theme_description = escape_string_and_dup (buffer_text); | |||
| 315 | g_free (buffer_text); | |||
| 316 | theme_info = (CafeThemeMetaInfo *) g_object_get_data (G_OBJECT (save_dialog)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((save_dialog)), (((GType) ((20) << (2)))))))), "meta-theme-info"); | |||
| 317 | save_background = ctk_toggle_button_get_active (CTK_TOGGLE_BUTTON (((((CtkToggleButton*) (void *) g_type_check_instance_cast ((GTypeInstance *) (((CtkWidget*) ctk_builder_get_object(data->ui, "save_background_checkbutton" ))), ((ctk_toggle_button_get_type ())))))) | |||
| 318 | appearance_capplet_get_widget (data, "save_background_checkbutton"))((((CtkToggleButton*) (void *) g_type_check_instance_cast ((GTypeInstance *) (((CtkWidget*) ctk_builder_get_object(data->ui, "save_background_checkbutton" ))), ((ctk_toggle_button_get_type ()))))))); | |||
| 319 | save_notification = ctk_toggle_button_get_active (CTK_TOGGLE_BUTTON (((((CtkToggleButton*) (void *) g_type_check_instance_cast ((GTypeInstance *) (((CtkWidget*) ctk_builder_get_object(data->ui, "save_notification_checkbutton" ))), ((ctk_toggle_button_get_type ())))))) | |||
| 320 | appearance_capplet_get_widget (data, "save_notification_checkbutton"))((((CtkToggleButton*) (void *) g_type_check_instance_cast ((GTypeInstance *) (((CtkWidget*) ctk_builder_get_object(data->ui, "save_notification_checkbutton" ))), ((ctk_toggle_button_get_type ()))))))); | |||
| 321 | ||||
| 322 | if (save_theme_to_disk (theme_info, theme_name, theme_description, save_background, save_notification, &error)) { | |||
| 323 | /* remove the custom theme */ | |||
| 324 | CtkTreeIter iter; | |||
| 325 | ||||
| 326 | if (theme_find_in_model (CTK_TREE_MODEL (data->theme_store)((((CtkTreeModel*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((data->theme_store)), ((ctk_tree_model_get_type ())))) )), "__custom__", &iter)) | |||
| 327 | ctk_list_store_remove (data->theme_store, &iter); | |||
| 328 | } | |||
| 329 | ||||
| 330 | g_free (theme_name); | |||
| 331 | g_free (theme_description); | |||
| 332 | g_clear_error (&error); | |||
| 333 | } | |||
| 334 | ||||
| 335 | ctk_widget_hide (save_dialog); | |||
| 336 | } | |||
| 337 | ||||
| 338 | static void | |||
| 339 | entry_text_changed (CtkEditable *editable, | |||
| 340 | AppearanceData *data) | |||
| 341 | { | |||
| 342 | const gchar *text; | |||
| 343 | CtkWidget *button; | |||
| 344 | ||||
| 345 | text = ctk_entry_get_text (CTK_ENTRY (editable)((((CtkEntry*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((editable)), ((ctk_entry_get_type ()))))))); | |||
| 346 | button = appearance_capplet_get_widget (data, "save_dialog_save_button")(CtkWidget*) ctk_builder_get_object(data->ui, "save_dialog_save_button" ); | |||
| 347 | ||||
| 348 | ctk_widget_set_sensitive (button, text != NULL((void*)0) && text[0] != '\000'); | |||
| 349 | } | |||
| 350 | ||||
| 351 | void | |||
| 352 | theme_save_dialog_run (CafeThemeMetaInfo *theme_info, | |||
| 353 | AppearanceData *data) | |||
| 354 | { | |||
| 355 | CtkWidget *entry; | |||
| 356 | CtkWidget *text_view; | |||
| 357 | CtkTextBuffer *text_buffer; | |||
| 358 | ||||
| 359 | entry = appearance_capplet_get_widget (data, "save_dialog_entry")(CtkWidget*) ctk_builder_get_object(data->ui, "save_dialog_entry" ); | |||
| 360 | text_view = appearance_capplet_get_widget (data, "save_dialog_textview")(CtkWidget*) ctk_builder_get_object(data->ui, "save_dialog_textview" ); | |||
| 361 | ||||
| 362 | if (data->theme_save_dialog == NULL((void*)0)) { | |||
| 363 | data->theme_save_dialog = appearance_capplet_get_widget (data, "theme_save_dialog")(CtkWidget*) ctk_builder_get_object(data->ui, "theme_save_dialog" ); | |||
| 364 | ||||
| 365 | g_signal_connect (data->theme_save_dialog, "response", (GCallback) save_dialog_response, data)g_signal_connect_data ((data->theme_save_dialog), ("response" ), ((GCallback) save_dialog_response), (data), ((void*)0), (GConnectFlags ) 0); | |||
| 366 | g_signal_connect (data->theme_save_dialog, "delete-event", (GCallback) ctk_true, NULL)g_signal_connect_data ((data->theme_save_dialog), ("delete-event" ), ((GCallback) ctk_true), (((void*)0)), ((void*)0), (GConnectFlags ) 0); | |||
| 367 | g_signal_connect (entry, "changed", (GCallback) entry_text_changed, data)g_signal_connect_data ((entry), ("changed"), ((GCallback) entry_text_changed ), (data), ((void*)0), (GConnectFlags) 0); | |||
| 368 | ||||
| 369 | error_quark = g_quark_from_string ("cafe-theme-save"); | |||
| 370 | ctk_widget_set_size_request (text_view, 300, 100); | |||
| 371 | } | |||
| 372 | ||||
| 373 | ctk_entry_set_text (CTK_ENTRY (entry)((((CtkEntry*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((entry)), ((ctk_entry_get_type ())))))), ""); | |||
| 374 | entry_text_changed (CTK_EDITABLE (entry)((((CtkEditable*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((entry)), ((ctk_editable_get_type ())))))), data); | |||
| 375 | ctk_widget_grab_focus (entry); | |||
| 376 | ||||
| 377 | text_buffer = ctk_text_view_get_buffer (CTK_TEXT_VIEW (text_view)((((CtkTextView*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((text_view)), ((ctk_text_view_get_type ()))))))); | |||
| 378 | ctk_text_buffer_set_text (text_buffer, "", 0); | |||
| 379 | g_object_set_data (G_OBJECT (data->theme_save_dialog)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((data->theme_save_dialog)), (((GType) ((20) << ( 2)))))))), "meta-theme-info", theme_info); | |||
| 380 | ctk_window_set_transient_for (CTK_WINDOW (data->theme_save_dialog)((((CtkWindow*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((data->theme_save_dialog)), ((ctk_window_get_type ())) )))), | |||
| 381 | CTK_WINDOW (appearance_capplet_get_widget (data, "appearance_window"))((((CtkWindow*) (void *) g_type_check_instance_cast ((GTypeInstance *) (((CtkWidget*) ctk_builder_get_object(data->ui, "appearance_window" ))), ((ctk_window_get_type ()))))))); | |||
| 382 | ctk_widget_show (data->theme_save_dialog); | |||
| 383 | } |