alsamixer: fix handling of removed controls

When we get a notification that an element has been removed, we have to
recreate our internal control representation to avoid accessing freed
memory.  (And the checking for SND_CTL_EVENT_MASK_REMOVE should actually
be done correctly while we're at it.)

Signed-off-by: Clemens Ladisch <clemens@ladisch.de>
This commit is contained in:
Clemens Ladisch 2012-10-19 12:16:33 +02:00
parent 6017849f1b
commit f282607273
4 changed files with 17 additions and 14 deletions

View file

@ -128,8 +128,15 @@ void mainloop(void)
} }
if (!active_widget) if (!active_widget)
break; break;
if (controls_changed) if (controls_changed) {
controls_changed = FALSE;
create_controls();
control_values_changed = FALSE;
display_controls(); display_controls();
} else if (control_values_changed) {
control_values_changed = FALSE;
display_controls();
}
} }
free(pollfds); free(pollfds);
} }

View file

@ -657,7 +657,6 @@ void display_controls(void)
display_no_controls(); display_no_controls();
} }
display_scroll_indicators(); display_scroll_indicators();
controls_changed = FALSE;
} }
void compute_controls_layout(void) void compute_controls_layout(void)

View file

@ -50,6 +50,7 @@ int focus_control_index;
snd_mixer_selem_id_t *current_selem_id; snd_mixer_selem_id_t *current_selem_id;
unsigned int current_control_flags; unsigned int current_control_flags;
bool control_values_changed;
bool controls_changed; bool controls_changed;
enum channel_mask { enum channel_mask {
@ -59,20 +60,15 @@ enum channel_mask {
static int elem_callback(snd_mixer_elem_t *elem, unsigned int mask) static int elem_callback(snd_mixer_elem_t *elem, unsigned int mask)
{ {
unsigned int i; if (mask == SND_CTL_EVENT_MASK_REMOVE) {
if (mask & (SND_CTL_EVENT_MASK_REMOVE |
SND_CTL_EVENT_MASK_INFO |
SND_CTL_EVENT_MASK_VALUE))
controls_changed = TRUE; controls_changed = TRUE;
} else {
if (mask & SND_CTL_EVENT_MASK_VALUE)
control_values_changed = TRUE;
if (mask & SND_CTL_EVENT_MASK_INFO) if (mask & SND_CTL_EVENT_MASK_INFO)
for (i = 0; i < controls_count; ++i) controls_changed = TRUE;
if (controls[i].elem == elem) { }
controls[i].flags &= ~IS_ACTIVE;
if (snd_mixer_selem_is_active(controls[i].elem))
controls[i].flags |= IS_ACTIVE;
}
return 0; return 0;
} }

View file

@ -24,6 +24,7 @@ extern int focus_control_index;
extern snd_mixer_selem_id_t *current_selem_id; extern snd_mixer_selem_id_t *current_selem_id;
extern unsigned int current_control_flags; extern unsigned int current_control_flags;
extern bool control_values_changed;
extern bool controls_changed; extern bool controls_changed;
void create_mixer_object(struct snd_mixer_selem_regopt *selem_regopt); void create_mixer_object(struct snd_mixer_selem_regopt *selem_regopt);