File: | capplets/appearance/theme-save.c |
Warning: | line 72, column 9 Out of bound memory access (access exceeds upper limit of memory block) |
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 | } |