Merge lp:~bbboson/ubuntu/precise/gnome-control-center/fix-for-1236612 into lp:ubuntu/precise-updates/gnome-control-center
- Precise (12.04)
- fix-for-1236612
- Merge into precise-updates
Proposed by
Madper Xie
Status: | Merged | ||||
---|---|---|---|---|---|
Merge reported by: | Sebastien Bacher | ||||
Merged at revision: | not available | ||||
Proposed branch: | lp:~bbboson/ubuntu/precise/gnome-control-center/fix-for-1236612 | ||||
Merge into: | lp:ubuntu/precise-updates/gnome-control-center | ||||
Diff against target: |
902 lines (+854/-0) 6 files modified
.pc/applied-patches (+1/-0) .pc/sound-fix-potential-memory-corruption.patch/panels/sound/gvc-sound-theme-chooser.c (+833/-0) debian/changelog (+6/-0) debian/patches/series (+1/-0) debian/patches/sound-fix-potential-memory-corruption.patch (+12/-0) panels/sound/gvc-sound-theme-chooser.c (+1/-0) |
||||
To merge this branch: | bzr merge lp:~bbboson/ubuntu/precise/gnome-control-center/fix-for-1236612 | ||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Sebastien Bacher | Approve | ||
Review via email: mp+225776@code.launchpad.net |
Commit message
Description of the change
To post a comment you must log in.
Revision history for this message
Sebastien Bacher (seb128) wrote : | # |
(could you make the bug SRU compliant, see https:/
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file '.pc/applied-patches' |
2 | --- .pc/applied-patches 2014-04-02 10:52:39 +0000 |
3 | +++ .pc/applied-patches 2014-07-07 05:56:11 +0000 |
4 | @@ -44,3 +44,4 @@ |
5 | use_rfkill_airplane_mode.patch |
6 | more-power-suspend-options.patch |
7 | fix-input-device-bar-status.patch |
8 | +sound-fix-potential-memory-corruption.patch |
9 | |
10 | === added directory '.pc/sound-fix-potential-memory-corruption.patch' |
11 | === added file '.pc/sound-fix-potential-memory-corruption.patch/.timestamp' |
12 | === added directory '.pc/sound-fix-potential-memory-corruption.patch/panels' |
13 | === added directory '.pc/sound-fix-potential-memory-corruption.patch/panels/sound' |
14 | === added file '.pc/sound-fix-potential-memory-corruption.patch/panels/sound/gvc-sound-theme-chooser.c' |
15 | --- .pc/sound-fix-potential-memory-corruption.patch/panels/sound/gvc-sound-theme-chooser.c 1970-01-01 00:00:00 +0000 |
16 | +++ .pc/sound-fix-potential-memory-corruption.patch/panels/sound/gvc-sound-theme-chooser.c 2014-07-07 05:56:11 +0000 |
17 | @@ -0,0 +1,833 @@ |
18 | +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- |
19 | + * |
20 | + * Copyright (C) 2008 Bastien Nocera <hadess@hadess.net> |
21 | + * Copyright (C) 2008 William Jon McCann |
22 | + * |
23 | + * This program is free software; you can redistribute it and/or modify |
24 | + * it under the terms of the GNU General Public License as published by |
25 | + * the Free Software Foundation; either version 2 of the License, or |
26 | + * (at your option) any later version. |
27 | + * |
28 | + * This program is distributed in the hope that it will be useful, |
29 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
30 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
31 | + * GNU General Public License for more details. |
32 | + * |
33 | + * You should have received a copy of the GNU General Public License |
34 | + * along with this program; if not, write to the Free Software |
35 | + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
36 | + * |
37 | + */ |
38 | + |
39 | +#include "config.h" |
40 | + |
41 | +#include <stdlib.h> |
42 | +#include <stdio.h> |
43 | +#include <unistd.h> |
44 | +#include <utime.h> |
45 | +#include <errno.h> |
46 | + |
47 | +#include <glib.h> |
48 | +#include <glib/gi18n-lib.h> |
49 | +#include <gtk/gtk.h> |
50 | +#include <canberra-gtk.h> |
51 | +#include <libxml/tree.h> |
52 | + |
53 | +#include <gsettings-desktop-schemas/gdesktop-enums.h> |
54 | + |
55 | +#include "gvc-sound-theme-chooser.h" |
56 | +#include "sound-theme-file-utils.h" |
57 | + |
58 | +#define GVC_SOUND_THEME_CHOOSER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GVC_TYPE_SOUND_THEME_CHOOSER, GvcSoundThemeChooserPrivate)) |
59 | + |
60 | +struct GvcSoundThemeChooserPrivate |
61 | +{ |
62 | + GtkWidget *treeview; |
63 | + GtkWidget *selection_box; |
64 | + GSettings *settings; |
65 | + GSettings *sound_settings; |
66 | + char *current_theme; |
67 | + char *current_parent; |
68 | +}; |
69 | + |
70 | +static void gvc_sound_theme_chooser_class_init (GvcSoundThemeChooserClass *klass); |
71 | +static void gvc_sound_theme_chooser_init (GvcSoundThemeChooser *sound_theme_chooser); |
72 | +static void gvc_sound_theme_chooser_finalize (GObject *object); |
73 | + |
74 | +G_DEFINE_TYPE (GvcSoundThemeChooser, gvc_sound_theme_chooser, GTK_TYPE_VBOX) |
75 | + |
76 | +#define KEY_SOUNDS_SCHEMA "org.gnome.desktop.sound" |
77 | +#define EVENT_SOUNDS_KEY "event-sounds" |
78 | +#define INPUT_SOUNDS_KEY "input-feedback-sounds" |
79 | +#define SOUND_THEME_KEY "theme-name" |
80 | + |
81 | +#define WM_SCHEMA "org.gnome.desktop.wm.preferences" |
82 | +#define AUDIO_BELL_KEY "audible-bell" |
83 | + |
84 | +#define DEFAULT_ALERT_ID "__default" |
85 | +#define CUSTOM_THEME_NAME "__custom" |
86 | +#define NO_SOUNDS_THEME_NAME "__no_sounds" |
87 | +#define DEFAULT_THEME "ubuntu" |
88 | + |
89 | +enum { |
90 | + THEME_DISPLAY_COL, |
91 | + THEME_IDENTIFIER_COL, |
92 | + THEME_PARENT_ID_COL, |
93 | + THEME_NUM_COLS |
94 | +}; |
95 | + |
96 | +enum { |
97 | + ALERT_DISPLAY_COL, |
98 | + ALERT_IDENTIFIER_COL, |
99 | + ALERT_SOUND_TYPE_COL, |
100 | + ALERT_NUM_COLS |
101 | +}; |
102 | + |
103 | +enum { |
104 | + SOUND_TYPE_UNSET, |
105 | + SOUND_TYPE_OFF, |
106 | + SOUND_TYPE_DEFAULT_FROM_THEME, |
107 | + SOUND_TYPE_BUILTIN, |
108 | + SOUND_TYPE_CUSTOM |
109 | +}; |
110 | + |
111 | +#define GVC_SOUND_SOUND (xmlChar *) "sound" |
112 | +#define GVC_SOUND_NAME (xmlChar *) "name" |
113 | +#define GVC_SOUND_FILENAME (xmlChar *) "filename" |
114 | + |
115 | +/* Adapted from yelp-toc-pager.c */ |
116 | +static xmlChar * |
117 | +xml_get_and_trim_names (xmlNodePtr node) |
118 | +{ |
119 | + xmlNodePtr cur; |
120 | + xmlChar *keep_lang = NULL; |
121 | + xmlChar *value; |
122 | + int j, keep_pri = INT_MAX; |
123 | + |
124 | + const gchar * const * langs = g_get_language_names (); |
125 | + |
126 | + value = NULL; |
127 | + |
128 | + for (cur = node->children; cur; cur = cur->next) { |
129 | + if (! xmlStrcmp (cur->name, GVC_SOUND_NAME)) { |
130 | + xmlChar *cur_lang = NULL; |
131 | + int cur_pri = INT_MAX; |
132 | + |
133 | + cur_lang = xmlNodeGetLang (cur); |
134 | + |
135 | + if (cur_lang) { |
136 | + for (j = 0; langs[j]; j++) { |
137 | + if (g_str_equal (cur_lang, langs[j])) { |
138 | + cur_pri = j; |
139 | + break; |
140 | + } |
141 | + } |
142 | + } else { |
143 | + cur_pri = INT_MAX - 1; |
144 | + } |
145 | + |
146 | + if (cur_pri <= keep_pri) { |
147 | + if (keep_lang) |
148 | + xmlFree (keep_lang); |
149 | + if (value) |
150 | + xmlFree (value); |
151 | + |
152 | + value = xmlNodeGetContent (cur); |
153 | + |
154 | + keep_lang = cur_lang; |
155 | + keep_pri = cur_pri; |
156 | + } else { |
157 | + if (cur_lang) |
158 | + xmlFree (cur_lang); |
159 | + } |
160 | + } |
161 | + } |
162 | + |
163 | + /* Delete all GVC_SOUND_NAME nodes */ |
164 | + cur = node->children; |
165 | + while (cur) { |
166 | + xmlNodePtr this = cur; |
167 | + cur = cur->next; |
168 | + if (! xmlStrcmp (this->name, GVC_SOUND_NAME)) { |
169 | + xmlUnlinkNode (this); |
170 | + xmlFreeNode (this); |
171 | + } |
172 | + } |
173 | + |
174 | + return value; |
175 | +} |
176 | + |
177 | +static void |
178 | +populate_model_from_node (GvcSoundThemeChooser *chooser, |
179 | + GtkTreeModel *model, |
180 | + xmlNodePtr node) |
181 | +{ |
182 | + xmlNodePtr child; |
183 | + xmlChar *filename; |
184 | + xmlChar *name; |
185 | + |
186 | + filename = NULL; |
187 | + name = xml_get_and_trim_names (node); |
188 | + for (child = node->children; child; child = child->next) { |
189 | + if (xmlNodeIsText (child)) { |
190 | + continue; |
191 | + } |
192 | + |
193 | + if (xmlStrcmp (child->name, GVC_SOUND_FILENAME) == 0) { |
194 | + filename = xmlNodeGetContent (child); |
195 | + } else if (xmlStrcmp (child->name, GVC_SOUND_NAME) == 0) { |
196 | + /* EH? should have been trimmed */ |
197 | + } |
198 | + } |
199 | + |
200 | + if (filename != NULL && name != NULL) { |
201 | + gtk_list_store_insert_with_values (GTK_LIST_STORE (model), |
202 | + NULL, |
203 | + G_MAXINT, |
204 | + ALERT_IDENTIFIER_COL, filename, |
205 | + ALERT_DISPLAY_COL, name, |
206 | + ALERT_SOUND_TYPE_COL, _("Built-in"), |
207 | + -1); |
208 | + } |
209 | + |
210 | + xmlFree (filename); |
211 | + xmlFree (name); |
212 | +} |
213 | + |
214 | +static void |
215 | +populate_model_from_file (GvcSoundThemeChooser *chooser, |
216 | + GtkTreeModel *model, |
217 | + const char *filename) |
218 | +{ |
219 | + xmlDocPtr doc; |
220 | + xmlNodePtr root; |
221 | + xmlNodePtr child; |
222 | + gboolean exists; |
223 | + |
224 | + exists = g_file_test (filename, G_FILE_TEST_EXISTS); |
225 | + if (! exists) { |
226 | + return; |
227 | + } |
228 | + |
229 | + doc = xmlParseFile (filename); |
230 | + if (doc == NULL) { |
231 | + return; |
232 | + } |
233 | + |
234 | + root = xmlDocGetRootElement (doc); |
235 | + |
236 | + for (child = root->children; child; child = child->next) { |
237 | + if (xmlNodeIsText (child)) { |
238 | + continue; |
239 | + } |
240 | + if (xmlStrcmp (child->name, GVC_SOUND_SOUND) != 0) { |
241 | + continue; |
242 | + } |
243 | + |
244 | + populate_model_from_node (chooser, model, child); |
245 | + } |
246 | + |
247 | + xmlFreeDoc (doc); |
248 | +} |
249 | + |
250 | +static void |
251 | +populate_model_from_dir (GvcSoundThemeChooser *chooser, |
252 | + GtkTreeModel *model, |
253 | + const char *dirname) |
254 | +{ |
255 | + GDir *d; |
256 | + const char *name; |
257 | + |
258 | + d = g_dir_open (dirname, 0, NULL); |
259 | + if (d == NULL) { |
260 | + return; |
261 | + } |
262 | + |
263 | + while ((name = g_dir_read_name (d)) != NULL) { |
264 | + char *path; |
265 | + |
266 | + if (! g_str_has_suffix (name, ".xml")) { |
267 | + continue; |
268 | + } |
269 | + |
270 | + path = g_build_filename (dirname, name, NULL); |
271 | + populate_model_from_file (chooser, model, path); |
272 | + g_free (path); |
273 | + } |
274 | +} |
275 | + |
276 | +static gboolean |
277 | +save_alert_sounds (GvcSoundThemeChooser *chooser, |
278 | + const char *id) |
279 | +{ |
280 | + const char *sounds[3] = { "bell-terminal", "bell-window-system", NULL }; |
281 | + char *path; |
282 | + |
283 | + if (strcmp (id, DEFAULT_ALERT_ID) == 0) { |
284 | + delete_old_files (sounds); |
285 | + delete_disabled_files (sounds); |
286 | + } else { |
287 | + delete_old_files (sounds); |
288 | + delete_disabled_files (sounds); |
289 | + add_custom_file (sounds, id); |
290 | + } |
291 | + |
292 | + /* And poke the directory so the theme gets updated */ |
293 | + path = custom_theme_dir_path (NULL); |
294 | + if (utime (path, NULL) != 0) { |
295 | + g_warning ("Failed to update mtime for directory '%s': %s", |
296 | + path, g_strerror (errno)); |
297 | + } |
298 | + g_free (path); |
299 | + |
300 | + return FALSE; |
301 | +} |
302 | + |
303 | + |
304 | +static void |
305 | +update_alert_model (GvcSoundThemeChooser *chooser, |
306 | + const char *id) |
307 | +{ |
308 | + GtkTreeModel *model; |
309 | + GtkTreeIter iter; |
310 | + |
311 | + model = gtk_tree_view_get_model (GTK_TREE_VIEW (chooser->priv->treeview)); |
312 | + gtk_tree_model_get_iter_first (model, &iter); |
313 | + do { |
314 | + char *this_id; |
315 | + |
316 | + gtk_tree_model_get (model, &iter, |
317 | + ALERT_IDENTIFIER_COL, &this_id, |
318 | + -1); |
319 | + |
320 | + if (strcmp (this_id, id) == 0) { |
321 | + GtkTreeSelection *selection; |
322 | + |
323 | + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (chooser->priv->treeview)); |
324 | + gtk_tree_selection_select_iter (selection, &iter); |
325 | + } |
326 | + |
327 | + g_free (this_id); |
328 | + } while (gtk_tree_model_iter_next (model, &iter)); |
329 | +} |
330 | + |
331 | +static void |
332 | +save_theme_name (GvcSoundThemeChooser *chooser, |
333 | + const char *theme_name) |
334 | +{ |
335 | + /* If the name is empty, use "freedesktop" */ |
336 | + if (theme_name == NULL || *theme_name == '\0') { |
337 | + theme_name = DEFAULT_THEME; |
338 | + } |
339 | + |
340 | + /* special case for no sounds */ |
341 | + if (strcmp (theme_name, NO_SOUNDS_THEME_NAME) == 0) { |
342 | + g_settings_set_boolean (chooser->priv->sound_settings, EVENT_SOUNDS_KEY, FALSE); |
343 | + return; |
344 | + } else { |
345 | + g_settings_set_boolean (chooser->priv->sound_settings, EVENT_SOUNDS_KEY, TRUE); |
346 | + } |
347 | + |
348 | + g_settings_set_string (chooser->priv->sound_settings, SOUND_THEME_KEY, theme_name); |
349 | +} |
350 | + |
351 | +static gboolean |
352 | +load_theme_file (const char *path, |
353 | + char **parent) |
354 | +{ |
355 | + GKeyFile *file; |
356 | + gboolean hidden; |
357 | + |
358 | + file = g_key_file_new (); |
359 | + if (g_key_file_load_from_file (file, path, G_KEY_FILE_KEEP_TRANSLATIONS, NULL) == FALSE) { |
360 | + g_key_file_free (file); |
361 | + return FALSE; |
362 | + } |
363 | + /* Don't add hidden themes to the list */ |
364 | + hidden = g_key_file_get_boolean (file, "Sound Theme", "Hidden", NULL); |
365 | + if (!hidden) { |
366 | + /* Save the parent theme, if there's one */ |
367 | + if (parent != NULL) { |
368 | + *parent = g_key_file_get_string (file, |
369 | + "Sound Theme", |
370 | + "Inherits", |
371 | + NULL); |
372 | + } |
373 | + } |
374 | + |
375 | + g_key_file_free (file); |
376 | + |
377 | + return TRUE; |
378 | +} |
379 | + |
380 | +static gboolean |
381 | +load_theme_name (const char *name, |
382 | + char **parent) |
383 | +{ |
384 | + const char * const *data_dirs; |
385 | + const char *data_dir; |
386 | + char *path; |
387 | + guint i; |
388 | + gboolean res; |
389 | + |
390 | + data_dir = g_get_user_data_dir (); |
391 | + path = g_build_filename (data_dir, "sounds", name, "index.theme", NULL); |
392 | + res = load_theme_file (path, parent); |
393 | + g_free (path); |
394 | + if (res) |
395 | + return TRUE; |
396 | + |
397 | + data_dirs = g_get_system_data_dirs (); |
398 | + for (i = 0; data_dirs[i] != NULL; i++) { |
399 | + path = g_build_filename (data_dirs[i], "sounds", name, "index.theme", NULL); |
400 | + res = load_theme_file (path, parent); |
401 | + g_free (path); |
402 | + if (res) |
403 | + return TRUE; |
404 | + } |
405 | + |
406 | + return FALSE; |
407 | +} |
408 | + |
409 | +static void |
410 | +update_alert (GvcSoundThemeChooser *chooser, |
411 | + const char *alert_id) |
412 | +{ |
413 | + gboolean is_custom; |
414 | + gboolean is_default; |
415 | + gboolean add_custom; |
416 | + gboolean remove_custom; |
417 | + |
418 | + is_custom = strcmp (chooser->priv->current_theme, CUSTOM_THEME_NAME) == 0; |
419 | + is_default = strcmp (alert_id, DEFAULT_ALERT_ID) == 0; |
420 | + |
421 | + /* So a few possibilities: |
422 | + * 1. Named theme, default alert selected: noop |
423 | + * 2. Named theme, alternate alert selected: create new custom with sound |
424 | + * 3. Custom theme, default alert selected: remove sound and possibly custom |
425 | + * 4. Custom theme, alternate alert selected: update custom sound |
426 | + */ |
427 | + add_custom = FALSE; |
428 | + remove_custom = FALSE; |
429 | + if (! is_custom && is_default) { |
430 | + /* remove custom just in case */ |
431 | + remove_custom = TRUE; |
432 | + } else if (! is_custom && ! is_default) { |
433 | + if (chooser->priv->current_parent) |
434 | + create_custom_theme (chooser->priv->current_parent); |
435 | + else |
436 | + create_custom_theme (DEFAULT_THEME); |
437 | + save_alert_sounds (chooser, alert_id); |
438 | + add_custom = TRUE; |
439 | + } else if (is_custom && is_default) { |
440 | + save_alert_sounds (chooser, alert_id); |
441 | + /* after removing files check if it is empty */ |
442 | + if (custom_theme_dir_is_empty ()) { |
443 | + remove_custom = TRUE; |
444 | + } |
445 | + } else if (is_custom && ! is_default) { |
446 | + save_alert_sounds (chooser, alert_id); |
447 | + } |
448 | + |
449 | + if (add_custom) { |
450 | + save_theme_name (chooser, CUSTOM_THEME_NAME); |
451 | + } else if (remove_custom) { |
452 | + delete_custom_theme_dir (); |
453 | + if (is_custom) { |
454 | + save_theme_name (chooser, chooser->priv->current_parent); |
455 | + } |
456 | + } |
457 | + |
458 | + update_alert_model (chooser, alert_id); |
459 | +} |
460 | + |
461 | +static void |
462 | +play_preview_for_id (GvcSoundThemeChooser *chooser, |
463 | + const char *id) |
464 | +{ |
465 | + g_return_if_fail (id != NULL); |
466 | + |
467 | + /* special case: for the default item on custom themes |
468 | + * play the alert for the parent theme */ |
469 | + if (strcmp (id, DEFAULT_ALERT_ID) == 0) { |
470 | + if (chooser->priv->current_parent != NULL) { |
471 | + ca_gtk_play_for_widget (GTK_WIDGET (chooser), 0, |
472 | + CA_PROP_APPLICATION_NAME, _("Sound Preferences"), |
473 | + CA_PROP_EVENT_ID, "bell-window-system", |
474 | + CA_PROP_CANBERRA_XDG_THEME_NAME, chooser->priv->current_parent, |
475 | + CA_PROP_EVENT_DESCRIPTION, _("Testing event sound"), |
476 | + CA_PROP_CANBERRA_CACHE_CONTROL, "never", |
477 | + CA_PROP_APPLICATION_ID, "org.gnome.VolumeControl", |
478 | +#ifdef CA_PROP_CANBERRA_ENABLE |
479 | + CA_PROP_CANBERRA_ENABLE, "1", |
480 | +#endif |
481 | + NULL); |
482 | + } else { |
483 | + ca_gtk_play_for_widget (GTK_WIDGET (chooser), 0, |
484 | + CA_PROP_APPLICATION_NAME, _("Sound Preferences"), |
485 | + CA_PROP_EVENT_ID, "bell-window-system", |
486 | + CA_PROP_EVENT_DESCRIPTION, _("Testing event sound"), |
487 | + CA_PROP_CANBERRA_CACHE_CONTROL, "never", |
488 | + CA_PROP_APPLICATION_ID, "org.gnome.VolumeControl", |
489 | +#ifdef CA_PROP_CANBERRA_ENABLE |
490 | + CA_PROP_CANBERRA_ENABLE, "1", |
491 | +#endif |
492 | + NULL); |
493 | + } |
494 | + } else { |
495 | + ca_gtk_play_for_widget (GTK_WIDGET (chooser), 0, |
496 | + CA_PROP_APPLICATION_NAME, _("Sound Preferences"), |
497 | + CA_PROP_MEDIA_FILENAME, id, |
498 | + CA_PROP_EVENT_DESCRIPTION, _("Testing event sound"), |
499 | + CA_PROP_CANBERRA_CACHE_CONTROL, "never", |
500 | + CA_PROP_APPLICATION_ID, "org.gnome.VolumeControl", |
501 | +#ifdef CA_PROP_CANBERRA_ENABLE |
502 | + CA_PROP_CANBERRA_ENABLE, "1", |
503 | +#endif |
504 | + NULL); |
505 | + |
506 | + } |
507 | +} |
508 | + |
509 | +static void |
510 | +on_treeview_selection_changed (GtkTreeSelection *selection, |
511 | + GvcSoundThemeChooser *chooser) |
512 | +{ |
513 | + GtkTreeModel *model; |
514 | + GtkTreeIter iter; |
515 | + char *id; |
516 | + |
517 | + if (chooser->priv->treeview == NULL) { |
518 | + return; |
519 | + } |
520 | + |
521 | + model = gtk_tree_view_get_model (GTK_TREE_VIEW (chooser->priv->treeview)); |
522 | + |
523 | + if (gtk_tree_selection_get_selected (selection, &model, &iter) == FALSE) { |
524 | + return; |
525 | + } |
526 | + |
527 | + id = NULL; |
528 | + gtk_tree_model_get (model, &iter, |
529 | + ALERT_IDENTIFIER_COL, &id, |
530 | + -1); |
531 | + if (id == NULL) { |
532 | + return; |
533 | + } |
534 | + |
535 | + play_preview_for_id (chooser, id); |
536 | + update_alert (chooser, id); |
537 | + g_free (id); |
538 | +} |
539 | + |
540 | +static gboolean |
541 | +on_treeview_button_pressed (GtkTreeView *treeview, |
542 | + GdkEventButton *event, |
543 | + GvcSoundThemeChooser *chooser) |
544 | +{ |
545 | + GtkTreeSelection *selection; |
546 | + GtkTreePath *path; |
547 | + |
548 | + selection = gtk_tree_view_get_selection (treeview); |
549 | + if (gtk_tree_view_get_path_at_pos (GTK_TREE_VIEW (treeview), |
550 | + event->x, event->y, &path, NULL, NULL, NULL) == FALSE) { |
551 | + return FALSE; |
552 | + } |
553 | + |
554 | + if (gtk_tree_selection_path_is_selected (selection, path) == FALSE) { |
555 | + gtk_tree_path_free (path); |
556 | + return FALSE; |
557 | + } |
558 | + gtk_tree_path_free (path); |
559 | + |
560 | + on_treeview_selection_changed (selection, chooser); |
561 | + |
562 | + return FALSE; |
563 | +} |
564 | + |
565 | +static GtkWidget * |
566 | +create_alert_treeview (GvcSoundThemeChooser *chooser) |
567 | +{ |
568 | + GtkListStore *store; |
569 | + GtkWidget *treeview; |
570 | + GtkCellRenderer *renderer; |
571 | + GtkTreeViewColumn *column; |
572 | + GtkTreeSelection *selection; |
573 | + |
574 | + treeview = gtk_tree_view_new (); |
575 | + gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (treeview), FALSE); |
576 | + g_signal_connect (treeview, |
577 | + "button-press-event", |
578 | + G_CALLBACK (on_treeview_button_pressed), |
579 | + chooser); |
580 | + |
581 | + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview)); |
582 | + gtk_tree_selection_set_mode (selection, GTK_SELECTION_SINGLE); |
583 | + g_signal_connect (selection, |
584 | + "changed", |
585 | + G_CALLBACK (on_treeview_selection_changed), |
586 | + chooser); |
587 | + |
588 | + /* Setup the tree model, 3 columns: |
589 | + * - display name |
590 | + * - sound id |
591 | + * - sound type |
592 | + */ |
593 | + store = gtk_list_store_new (ALERT_NUM_COLS, |
594 | + G_TYPE_STRING, |
595 | + G_TYPE_STRING, |
596 | + G_TYPE_STRING); |
597 | + |
598 | + gtk_list_store_insert_with_values (store, |
599 | + NULL, |
600 | + G_MAXINT, |
601 | + ALERT_IDENTIFIER_COL, DEFAULT_ALERT_ID, |
602 | + ALERT_DISPLAY_COL, _("Default"), |
603 | + ALERT_SOUND_TYPE_COL, _("From theme"), |
604 | + -1); |
605 | + |
606 | + populate_model_from_dir (chooser, GTK_TREE_MODEL (store), SOUND_SET_DIR); |
607 | + |
608 | + gtk_tree_view_set_model (GTK_TREE_VIEW (treeview), |
609 | + GTK_TREE_MODEL (store)); |
610 | + |
611 | + renderer = gtk_cell_renderer_text_new (); |
612 | + column = gtk_tree_view_column_new_with_attributes (_("Name"), |
613 | + renderer, |
614 | + "text", ALERT_DISPLAY_COL, |
615 | + NULL); |
616 | + gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column); |
617 | + |
618 | + return treeview; |
619 | +} |
620 | + |
621 | +static int |
622 | +get_file_type (const char *sound_name, |
623 | + char **linked_name) |
624 | +{ |
625 | + char *name, *filename; |
626 | + |
627 | + *linked_name = NULL; |
628 | + |
629 | + name = g_strdup_printf ("%s.disabled", sound_name); |
630 | + filename = custom_theme_dir_path (name); |
631 | + g_free (name); |
632 | + |
633 | + if (g_file_test (filename, G_FILE_TEST_IS_REGULAR) != FALSE) { |
634 | + g_free (filename); |
635 | + return SOUND_TYPE_OFF; |
636 | + } |
637 | + g_free (filename); |
638 | + |
639 | + /* We only check for .ogg files because those are the |
640 | + * only ones we create */ |
641 | + name = g_strdup_printf ("%s.ogg", sound_name); |
642 | + filename = custom_theme_dir_path (name); |
643 | + g_free (name); |
644 | + |
645 | + if (g_file_test (filename, G_FILE_TEST_IS_SYMLINK) != FALSE) { |
646 | + *linked_name = g_file_read_link (filename, NULL); |
647 | + g_free (filename); |
648 | + return SOUND_TYPE_CUSTOM; |
649 | + } |
650 | + g_free (filename); |
651 | + |
652 | + return SOUND_TYPE_BUILTIN; |
653 | +} |
654 | + |
655 | +static void |
656 | +update_alerts_from_theme_name (GvcSoundThemeChooser *chooser, |
657 | + const char *name) |
658 | +{ |
659 | + if (strcmp (name, CUSTOM_THEME_NAME) != 0) { |
660 | + /* reset alert to default */ |
661 | + update_alert (chooser, DEFAULT_ALERT_ID); |
662 | + } else { |
663 | + int sound_type; |
664 | + char *linkname; |
665 | + |
666 | + linkname = NULL; |
667 | + sound_type = get_file_type ("bell-terminal", &linkname); |
668 | + g_debug ("Found link: %s", linkname); |
669 | + if (sound_type == SOUND_TYPE_CUSTOM) { |
670 | + update_alert (chooser, linkname); |
671 | + } |
672 | + } |
673 | +} |
674 | + |
675 | +static void |
676 | +update_theme (GvcSoundThemeChooser *chooser) |
677 | +{ |
678 | + gboolean events_enabled; |
679 | + char *last_theme; |
680 | + |
681 | + events_enabled = g_settings_get_boolean (chooser->priv->sound_settings, EVENT_SOUNDS_KEY); |
682 | + |
683 | + last_theme = chooser->priv->current_theme; |
684 | + if (events_enabled) { |
685 | + chooser->priv->current_theme = g_settings_get_string (chooser->priv->sound_settings, SOUND_THEME_KEY); |
686 | + } else { |
687 | + chooser->priv->current_theme = g_strdup (NO_SOUNDS_THEME_NAME); |
688 | + } |
689 | + |
690 | + if (g_strcmp0 (last_theme, chooser->priv->current_theme) != 0) { |
691 | + g_free (chooser->priv->current_parent); |
692 | + if (load_theme_name (chooser->priv->current_theme, |
693 | + &chooser->priv->current_parent) == FALSE) { |
694 | + g_free (chooser->priv->current_theme); |
695 | + chooser->priv->current_theme = g_strdup (DEFAULT_THEME); |
696 | + load_theme_name (DEFAULT_THEME, |
697 | + &chooser->priv->current_parent); |
698 | + } |
699 | + } |
700 | + g_free (last_theme); |
701 | + |
702 | + gtk_widget_set_sensitive (chooser->priv->selection_box, events_enabled); |
703 | + |
704 | + update_alerts_from_theme_name (chooser, chooser->priv->current_theme); |
705 | +} |
706 | + |
707 | +static GObject * |
708 | +gvc_sound_theme_chooser_constructor (GType type, |
709 | + guint n_construct_properties, |
710 | + GObjectConstructParam *construct_params) |
711 | +{ |
712 | + GObject *object; |
713 | + GvcSoundThemeChooser *self; |
714 | + |
715 | + object = G_OBJECT_CLASS (gvc_sound_theme_chooser_parent_class)->constructor (type, n_construct_properties, construct_params); |
716 | + |
717 | + self = GVC_SOUND_THEME_CHOOSER (object); |
718 | + |
719 | + update_theme (self); |
720 | + |
721 | + return object; |
722 | +} |
723 | + |
724 | +static void |
725 | +gvc_sound_theme_chooser_class_init (GvcSoundThemeChooserClass *klass) |
726 | +{ |
727 | + GObjectClass *object_class = G_OBJECT_CLASS (klass); |
728 | + |
729 | + object_class->constructor = gvc_sound_theme_chooser_constructor; |
730 | + object_class->finalize = gvc_sound_theme_chooser_finalize; |
731 | + |
732 | + g_type_class_add_private (klass, sizeof (GvcSoundThemeChooserPrivate)); |
733 | +} |
734 | + |
735 | +static void |
736 | +on_sound_settings_changed (GSettings *settings, |
737 | + const char *key, |
738 | + GvcSoundThemeChooser *chooser) |
739 | +{ |
740 | + if (strcmp (key, EVENT_SOUNDS_KEY) == 0) { |
741 | + update_theme (chooser); |
742 | + } else if (strcmp (key, SOUND_THEME_KEY) == 0) { |
743 | + update_theme (chooser); |
744 | + } else if (strcmp (key, INPUT_SOUNDS_KEY) == 0) { |
745 | + update_theme (chooser); |
746 | + } |
747 | +} |
748 | + |
749 | +static void |
750 | +on_audible_bell_changed (GSettings *settings, |
751 | + const char *key, |
752 | + GvcSoundThemeChooser *chooser) |
753 | +{ |
754 | + update_theme (chooser); |
755 | +} |
756 | + |
757 | +static void |
758 | +setup_list_size_constraint (GtkWidget *widget, |
759 | + GtkWidget *to_size) |
760 | +{ |
761 | + GtkRequisition req; |
762 | + int max_height; |
763 | + |
764 | + /* constrain height to be the tree height up to a max */ |
765 | + max_height = (gdk_screen_get_height (gtk_widget_get_screen (widget))) / 4; |
766 | + |
767 | + gtk_widget_get_preferred_size (to_size, NULL, &req); |
768 | + |
769 | + gtk_scrolled_window_set_min_content_height (GTK_SCROLLED_WINDOW (widget), |
770 | + MIN (req.height, max_height)); |
771 | +} |
772 | + |
773 | +static void |
774 | +gvc_sound_theme_chooser_init (GvcSoundThemeChooser *chooser) |
775 | +{ |
776 | + GtkWidget *box; |
777 | + GtkWidget *label; |
778 | + GtkWidget *scrolled_window; |
779 | + GtkWidget *alignment; |
780 | + char *str; |
781 | + |
782 | + chooser->priv = GVC_SOUND_THEME_CHOOSER_GET_PRIVATE (chooser); |
783 | + |
784 | + chooser->priv->settings = g_settings_new (WM_SCHEMA); |
785 | + chooser->priv->sound_settings = g_settings_new (KEY_SOUNDS_SCHEMA); |
786 | + |
787 | + str = g_strdup_printf ("<b>%s</b>", _("C_hoose an alert sound:")); |
788 | + chooser->priv->selection_box = box = gtk_frame_new (str); |
789 | + g_free (str); |
790 | + label = gtk_frame_get_label_widget (GTK_FRAME (box)); |
791 | + gtk_label_set_use_underline (GTK_LABEL (label), TRUE); |
792 | + gtk_label_set_use_markup (GTK_LABEL (label), TRUE); |
793 | + gtk_frame_set_shadow_type (GTK_FRAME (box), GTK_SHADOW_NONE); |
794 | + |
795 | + alignment = gtk_alignment_new (0, 0, 1, 1); |
796 | + gtk_alignment_set_padding (GTK_ALIGNMENT (alignment), 6, 0, 0, 0); |
797 | + gtk_container_add (GTK_CONTAINER (alignment), box); |
798 | + gtk_box_pack_start (GTK_BOX (chooser), alignment, TRUE, TRUE, 6); |
799 | + |
800 | + alignment = gtk_alignment_new (0, 0, 1, 1); |
801 | + gtk_alignment_set_padding (GTK_ALIGNMENT (alignment), 6, 0, 0, 0); |
802 | + gtk_container_add (GTK_CONTAINER (box), alignment); |
803 | + |
804 | + chooser->priv->treeview = create_alert_treeview (chooser); |
805 | + gtk_label_set_mnemonic_widget (GTK_LABEL (label), chooser->priv->treeview); |
806 | + |
807 | + scrolled_window = gtk_scrolled_window_new (NULL, NULL); |
808 | + setup_list_size_constraint (scrolled_window, chooser->priv->treeview); |
809 | + |
810 | + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window), |
811 | + GTK_POLICY_NEVER, |
812 | + GTK_POLICY_AUTOMATIC); |
813 | + gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled_window), |
814 | + GTK_SHADOW_IN); |
815 | + gtk_container_add (GTK_CONTAINER (scrolled_window), chooser->priv->treeview); |
816 | + gtk_container_add (GTK_CONTAINER (alignment), scrolled_window); |
817 | + |
818 | + g_signal_connect (G_OBJECT (chooser->priv->sound_settings), "changed", |
819 | + G_CALLBACK (on_sound_settings_changed), chooser); |
820 | + g_signal_connect (chooser->priv->settings, "changed::" AUDIO_BELL_KEY, |
821 | + G_CALLBACK (on_audible_bell_changed), chooser); |
822 | +} |
823 | + |
824 | +static void |
825 | +gvc_sound_theme_chooser_finalize (GObject *object) |
826 | +{ |
827 | + GvcSoundThemeChooser *sound_theme_chooser; |
828 | + |
829 | + g_return_if_fail (object != NULL); |
830 | + g_return_if_fail (GVC_IS_SOUND_THEME_CHOOSER (object)); |
831 | + |
832 | + sound_theme_chooser = GVC_SOUND_THEME_CHOOSER (object); |
833 | + |
834 | + if (sound_theme_chooser->priv != NULL) { |
835 | + g_object_unref (sound_theme_chooser->priv->settings); |
836 | + g_object_unref (sound_theme_chooser->priv->sound_settings); |
837 | + } |
838 | + |
839 | + G_OBJECT_CLASS (gvc_sound_theme_chooser_parent_class)->finalize (object); |
840 | +} |
841 | + |
842 | +GtkWidget * |
843 | +gvc_sound_theme_chooser_new (void) |
844 | +{ |
845 | + GObject *chooser; |
846 | + chooser = g_object_new (GVC_TYPE_SOUND_THEME_CHOOSER, |
847 | + "spacing", 6, |
848 | + NULL); |
849 | + return GTK_WIDGET (chooser); |
850 | +} |
851 | |
852 | === modified file 'debian/changelog' |
853 | --- debian/changelog 2014-04-02 10:52:39 +0000 |
854 | +++ debian/changelog 2014-07-07 05:56:11 +0000 |
855 | @@ -1,3 +1,9 @@ |
856 | +gnome-control-center (1:3.4.2-0ubuntu0.13.3) precise; urgency=medium |
857 | + |
858 | + * sound: fix potential memory corruption (LP: #1236612) |
859 | + |
860 | + -- Madper Xie <madper.xie@canonical.com> Mon, 07 Jul 2014 13:41:57 +0800 |
861 | + |
862 | gnome-control-center (1:3.4.2-0ubuntu0.13.2) precise; urgency=medium |
863 | |
864 | * Disable the input/output bar when no input/output devices (LP: #1291862) |
865 | |
866 | === modified file 'debian/patches/series' |
867 | --- debian/patches/series 2014-04-02 10:52:39 +0000 |
868 | +++ debian/patches/series 2014-07-07 05:56:11 +0000 |
869 | @@ -44,3 +44,4 @@ |
870 | use_rfkill_airplane_mode.patch |
871 | more-power-suspend-options.patch |
872 | fix-input-device-bar-status.patch |
873 | +sound-fix-potential-memory-corruption.patch |
874 | |
875 | === added file 'debian/patches/sound-fix-potential-memory-corruption.patch' |
876 | --- debian/patches/sound-fix-potential-memory-corruption.patch 1970-01-01 00:00:00 +0000 |
877 | +++ debian/patches/sound-fix-potential-memory-corruption.patch 2014-07-07 05:56:11 +0000 |
878 | @@ -0,0 +1,12 @@ |
879 | +Index: gnome-control-center/panels/sound/gvc-sound-theme-chooser.c |
880 | +=================================================================== |
881 | +--- gnome-control-center.orig/panels/sound/gvc-sound-theme-chooser.c 2014-07-07 12:40:00.839504000 +0800 |
882 | ++++ gnome-control-center/panels/sound/gvc-sound-theme-chooser.c 2014-07-07 12:48:15.822986459 +0800 |
883 | +@@ -672,6 +672,7 @@ |
884 | + |
885 | + if (g_strcmp0 (last_theme, chooser->priv->current_theme) != 0) { |
886 | + g_free (chooser->priv->current_parent); |
887 | ++ chooser->priv->current_parent = NULL; |
888 | + if (load_theme_name (chooser->priv->current_theme, |
889 | + &chooser->priv->current_parent) == FALSE) { |
890 | + g_free (chooser->priv->current_theme); |
891 | |
892 | === modified file 'panels/sound/gvc-sound-theme-chooser.c' |
893 | --- panels/sound/gvc-sound-theme-chooser.c 2012-02-15 23:16:31 +0000 |
894 | +++ panels/sound/gvc-sound-theme-chooser.c 2014-07-07 05:56:11 +0000 |
895 | @@ -672,6 +672,7 @@ |
896 | |
897 | if (g_strcmp0 (last_theme, chooser->priv->current_theme) != 0) { |
898 | g_free (chooser->priv->current_parent); |
899 | + chooser->priv->current_parent = NULL; |
900 | if (load_theme_name (chooser->priv->current_theme, |
901 | &chooser->priv->current_parent) == FALSE) { |
902 | g_free (chooser->priv->current_theme); |
Thanks, the vcs to use is lp:~ubuntu-desktop/gnome-control-center/precise (see debian/control), I've merged there and uploaded for you