update for beta release
[framework/uifw/e17.git] / src / modules / mixer / e_mod_main.c
1 #include "e_mod_main.h"
2 #include "e_mod_system.h"
3 #ifdef HAVE_ENOTIFY
4 #include <E_Notify.h>
5 #endif
6
7 static void _mixer_popup_timer_new(E_Mixer_Instance *inst);
8 static Eina_Bool _mixer_popup_timer_cb(void *data);
9
10 static E_Module *mixer_mod = NULL;
11 static char tmpbuf[PATH_MAX]; /* general purpose buffer, just use immediately */
12
13 static const char _conf_domain[] = "module.mixer";
14 static const char _name[] = "mixer";
15 const char _e_mixer_Name[] = "Mixer";
16 Eina_Bool _mixer_using_default = EINA_FALSE;
17 E_Mixer_Volume_Get_Cb e_mod_mixer_volume_get;
18 E_Mixer_Volume_Set_Cb e_mod_mixer_volume_set;
19 E_Mixer_Mute_Get_Cb e_mod_mixer_mute_get;
20 E_Mixer_Mute_Set_Cb e_mod_mixer_mute_set;
21 E_Mixer_Capture_Cb e_mod_mixer_mutable_get;
22 E_Mixer_State_Get_Cb e_mod_mixer_state_get;
23 E_Mixer_Capture_Cb e_mod_mixer_capture_get;
24 E_Mixer_Cb e_mod_mixer_new;
25 E_Mixer_Cb e_mod_mixer_del;
26 E_Mixer_Cb e_mod_mixer_channel_default_name_get;
27 E_Mixer_Cb e_mod_mixer_channel_get_by_name;
28 E_Mixer_Cb e_mod_mixer_channel_name_get;
29 E_Mixer_Cb e_mod_mixer_channel_del;
30 E_Mixer_Cb e_mod_mixer_channel_free;
31 E_Mixer_Cb e_mod_mixer_channels_free;
32 E_Mixer_Cb e_mod_mixer_channels_get;
33 E_Mixer_Cb e_mod_mixer_channels_names_get;
34 E_Mixer_Cb e_mod_mixer_card_name_get;
35 E_Mixer_Cb e_mod_mixer_cards_get;
36 E_Mixer_Cb e_mod_mixer_cards_free;
37 E_Mixer_Cb e_mod_mixer_card_default_get;
38
39 static void
40 _mixer_notify(const float val, E_Mixer_Instance *inst __UNUSED__)
41 {
42 #ifdef HAVE_ENOTIFY
43    E_Notification *n;
44    E_Mixer_Module_Context *ctxt;
45    char *icon, buf[56];
46    int ret;
47
48    if (val > 100.0 || val < 0.0)
49      return;
50
51    if (!(ctxt = (E_Mixer_Module_Context*)mixer_mod->data) || !ctxt->desktop_notification)
52      return;
53
54    ret = snprintf(buf, (sizeof(buf) - 1), "%s: %d%%", _("New volume"), (int)(val + 0.5));
55    if ((ret < 0) || ((unsigned int)ret > sizeof(buf)))
56      return;
57    //Names are taken from FDO icon naming scheme
58    if (val == 0.0)
59      icon = "audio-volume-muted";
60    else if ((val > 33.3) && (val < 66.6))
61      icon = "audio-volume-medium";
62    else if (val < 33.3)
63      icon = "audio-volume-low";
64    else
65      icon = "audio-volume-high";
66
67    n = e_notification_full_new(_("Mixer"), 0, icon, _("Volume changed"), buf, 2000);
68    e_notification_replaces_id_set(n, EINA_TRUE);
69    e_notification_send(n, NULL, NULL);
70    e_notification_unref(n);
71 #endif
72 }
73
74 const char *
75 e_mixer_theme_path(void)
76 {
77 #define TF "/e-module-mixer.edj"
78    size_t dirlen;
79
80    dirlen = strlen(mixer_mod->dir);
81    if (dirlen >= sizeof(tmpbuf) - sizeof(TF))
82       return NULL;
83
84    memcpy(tmpbuf, mixer_mod->dir, dirlen);
85    memcpy(tmpbuf + dirlen, TF, sizeof(TF));
86
87    return tmpbuf;
88 #undef TF
89 }
90
91 static int
92 _mixer_gadget_configuration_defaults(E_Mixer_Gadget_Config *conf)
93 {
94    E_Mixer_System *sys;
95    const char *card, *channel;
96
97    card = e_mod_mixer_card_default_get();
98    if (!card)
99       return 0;
100
101    sys = e_mod_mixer_new(card);
102    if (!sys)
103    {
104       eina_stringshare_del(card);
105       return 0;
106    }
107
108    channel = e_mod_mixer_channel_default_name_get(sys);
109    e_mod_mixer_del(sys);
110
111    if (!channel)
112    {
113       eina_stringshare_del(card);
114       return 0;
115    }
116
117    conf->card = card;
118    conf->channel_name = channel;
119    conf->lock_sliders = 1;
120    conf->show_locked = 0;
121    conf->keybindings_popup = 0;
122
123    return 1;
124 }
125
126 static E_Mixer_Gadget_Config *
127 _mixer_gadget_configuration_new(E_Mixer_Module_Config *mod_conf, const char *id)
128 {
129    E_Mixer_Gadget_Config *conf;
130
131    conf = E_NEW(E_Mixer_Gadget_Config, 1);
132    if (!conf)
133       return NULL;
134
135    if (!_mixer_gadget_configuration_defaults(conf))
136    {
137       E_FREE(conf);
138       return NULL;
139    }
140
141    conf->id = eina_stringshare_add(id);
142    if (!mod_conf->gadgets)
143       mod_conf->gadgets = eina_hash_string_superfast_new(NULL);
144    eina_hash_direct_add(mod_conf->gadgets, conf->id, conf);
145
146    return conf;
147 }
148
149 static inline void
150 _mixer_gadget_configuration_free_int(E_Mixer_Gadget_Config *conf)
151 {
152    if (conf->dialog)
153       e_object_del(E_OBJECT(conf->dialog));
154
155    if (conf->card)
156       eina_stringshare_del(conf->card);
157    if (conf->channel_name)
158       eina_stringshare_del(conf->channel_name);
159
160    eina_stringshare_del(conf->id);
161    free(conf);
162 }
163
164 static void
165 _mixer_gadget_configuration_free(E_Mixer_Module_Config *mod_conf, E_Mixer_Gadget_Config *conf)
166 {
167    if (!mod_conf)
168       return;
169    if (!conf)
170       return;
171    eina_hash_del(mod_conf->gadgets, conf->id, conf);
172    if (!eina_hash_population(mod_conf->gadgets))
173       eina_hash_free(mod_conf->gadgets);
174    _mixer_gadget_configuration_free_int(conf);
175 }
176
177 static Eina_Bool
178 _mixer_gadget_configuration_free_foreach(const Eina_Hash *hash __UNUSED__, const void *key __UNUSED__, void *hdata, void *fdata __UNUSED__)
179 {
180    _mixer_gadget_configuration_free_int(hdata);
181    return 1;
182 }
183
184 static Eina_Bool
185 _mixer_module_configuration_alert(void *data)
186 {
187    e_util_dialog_show(_("Mixer Settings Updated"), "%s", (char *)data);
188    return ECORE_CALLBACK_CANCEL;
189 }
190
191 static E_Mixer_Module_Config *
192 _mixer_module_configuration_new(void)
193 {
194    E_Mixer_Module_Config *conf;
195
196    conf = E_NEW(E_Mixer_Module_Config, 1);
197    if (!conf)
198       return NULL;
199
200    return conf;
201 }
202
203 static void
204 _mixer_module_configuration_free(E_Mixer_Module_Config *conf)
205 {
206    if (!conf)
207       return;
208
209    eina_hash_foreach(conf->gadgets,
210                      _mixer_gadget_configuration_free_foreach, NULL);
211    eina_hash_free(conf->gadgets);
212    eina_stringshare_del(conf->default_gc_id);
213    free(conf);
214 }
215
216 static void
217 _mixer_popup_update(E_Mixer_Instance *inst)
218 {
219    E_Mixer_Channel_State *state;
220
221    state = &inst->mixer_state;
222
223    if (inst->ui.left)
224       e_slider_value_set(inst->ui.left, state->left);
225    if (inst->ui.right)
226       e_slider_value_set(inst->ui.right, state->right);
227    if (inst->ui.mute)
228       e_widget_check_checked_set(inst->ui.mute, state->mute);
229 }
230
231 static void
232 _mixer_gadget_update(E_Mixer_Instance *inst)
233 {
234    Edje_Message_Int_Set *msg;
235
236    if (!inst)
237       return;
238
239    e_mod_mixer_state_get(inst->sys, inst->channel, &inst->mixer_state);
240
241    msg = alloca(sizeof(Edje_Message_Int_Set) + (2 * sizeof(int)));
242    msg->count = 3;
243    msg->val[0] = inst->mixer_state.mute;
244    msg->val[1] = inst->mixer_state.left;
245    msg->val[2] = inst->mixer_state.right;
246    edje_object_message_send(inst->ui.gadget, EDJE_MESSAGE_INT_SET, 0, msg);
247
248    edje_object_signal_emit(inst->ui.gadget, "e,action,volume,change", "e");
249
250    if (inst->popup)
251       _mixer_popup_update(inst);
252 }
253
254 static void
255 _mixer_balance_left(E_Mixer_Instance *inst)
256 {
257    E_Mixer_Channel_State *state;
258
259    state = &inst->mixer_state;
260    e_mod_mixer_volume_get(inst->sys, inst->channel,
261                              &state->left, &state->right);
262    if (state->left >= 0)
263    {
264       if (state->left > 5)
265          state->left -= 5;
266       else
267          state->left = 0;
268    }
269    if (state->right >= 0)
270    {
271       if (state->right < 95)
272          state->right += 5;
273       else
274          state->right = 100;
275    }
276
277    e_mod_mixer_volume_set(inst->sys, inst->channel,
278                              state->left, state->right);
279    _mixer_gadget_update(inst);
280 }
281
282 static void
283 _mixer_balance_right(E_Mixer_Instance *inst)
284 {
285    E_Mixer_Channel_State *state;
286
287    state = &inst->mixer_state;
288    e_mod_mixer_volume_get(inst->sys, inst->channel,
289                              &state->left, &state->right);
290    if (state->left >= 0)
291    {
292       if (state->left < 95)
293          state->left += 5;
294       else
295          state->left = 100;
296    }
297    if (state->right >= 0)
298    {
299       if (state->right > 5)
300          state->right -= 5;
301       else
302          state->right = 0;
303    }
304    e_mod_mixer_volume_set(inst->sys, inst->channel,
305                              state->left, state->right);
306    _mixer_gadget_update(inst);
307 }
308
309 static void
310 _mixer_volume_increase(E_Mixer_Instance *inst, Eina_Bool non_ui)
311 {
312    E_Mixer_Channel_State *state;
313
314    state = &inst->mixer_state;
315    e_mod_mixer_volume_get(inst->sys, inst->channel,
316                              &state->left, &state->right);
317    if (state->left >= 0)
318    {
319       if (state->left < 95)
320          state->left += 5;
321       else
322          state->left = 100;
323    }
324
325    if (state->right >= 0)
326    {
327       if (state->right < 95)
328          state->right += 5;
329       else
330          state->right = 100;
331    }
332
333    e_mod_mixer_volume_set(inst->sys, inst->channel,
334                              state->left, state->right);
335    _mixer_gadget_update(inst);
336    if (non_ui)
337      _mixer_notify(((float)state->left + (float)state->right) / 2.0, inst);
338 }
339
340 static void
341 _mixer_volume_decrease(E_Mixer_Instance *inst, Eina_Bool non_ui)
342 {
343    E_Mixer_Channel_State *state;
344
345    state = &inst->mixer_state;
346    e_mod_mixer_volume_get(inst->sys, inst->channel,
347                              &state->left, &state->right);
348    if (state->left >= 0)
349    {
350       if (state->left > 5)
351          state->left -= 5;
352       else
353          state->left = 0;
354    }
355    if (state->right >= 0)
356    {
357       if (state->right > 5)
358          state->right -= 5;
359       else
360          state->right = 0;
361    }
362
363    e_mod_mixer_volume_set(inst->sys, inst->channel,
364                              state->left, state->right);
365    _mixer_gadget_update(inst);
366    if (non_ui)
367      _mixer_notify(((float)state->left + (float)state->right) / 2.0, inst);
368 }
369
370 static void
371 _mixer_toggle_mute(E_Mixer_Instance *inst, Eina_Bool non_ui)
372 {
373    E_Mixer_Channel_State *state;
374
375    if (!e_mod_mixer_mutable_get(inst->sys, inst->channel))
376       return;
377
378    state = &inst->mixer_state;
379    e_mod_mixer_mute_get(inst->sys, inst->channel, &state->mute);
380    state->mute = !state->mute;
381    e_mod_mixer_mute_set(inst->sys, inst->channel, state->mute);
382    if (!state->mute) e_mod_mixer_volume_set(inst->sys, inst->channel, state->left, state->right);
383    _mixer_gadget_update(inst);
384    if (non_ui)
385      {
386         if (state->mute)
387           _mixer_notify(0.0, inst);
388         else
389           _mixer_notify(((float)state->left + (float)state->right) / 2.0, inst);
390      }
391 }
392
393 static void
394 _mixer_popup_cb_volume_left_change(void *data, Evas_Object *obj, void *event __UNUSED__)
395 {
396    E_Mixer_Instance *inst = data;
397    E_Mixer_Channel_State *state = &inst->mixer_state;
398
399    e_mod_mixer_volume_get(inst->sys, inst->channel,
400                              &state->left, &state->right);
401
402    state->left = (int)e_slider_value_get(obj);
403    if (inst->conf->lock_sliders)
404    {
405       state->right = state->left;
406       e_slider_value_set(inst->ui.right, state->right);
407    }
408
409    e_mod_mixer_volume_set(inst->sys, inst->channel,
410                              state->left, state->right);
411    _mixer_gadget_update(inst);
412 }
413
414 static void
415 _mixer_popup_cb_volume_right_change(void *data, Evas_Object *obj, void *event __UNUSED__)
416 {
417    E_Mixer_Instance *inst = data;
418    E_Mixer_Channel_State *state = &inst->mixer_state;
419
420    e_mod_mixer_volume_get(inst->sys, inst->channel,
421                              &state->left, &state->right);
422
423    state->right = (int)e_slider_value_get(obj);
424    if (inst->conf->lock_sliders)
425    {
426       state->left = state->right;
427       e_slider_value_set(inst->ui.left, state->left);
428    }
429
430    e_mod_mixer_volume_set(inst->sys, inst->channel,
431                              state->left, state->right);
432    _mixer_gadget_update(inst);
433 }
434
435 static void
436 _mixer_popup_cb_mute_change(void *data, Evas_Object *obj, void *event __UNUSED__)
437 {
438    E_Mixer_Instance *inst = data;
439    E_Mixer_Channel_State *state = &inst->mixer_state;
440
441    state->mute = e_widget_check_checked_get(obj);
442    e_mod_mixer_mute_set(inst->sys, inst->channel, state->mute);
443    if (!state->mute) e_mod_mixer_volume_set(inst->sys, inst->channel, state->left, state->right);
444
445    _mixer_gadget_update(inst);
446 }
447
448 static Evas_Object *
449 _mixer_popup_add_slider(E_Mixer_Instance *inst, int value, void (*cb) (void *data, Evas_Object *obj, void *event_info))
450 {
451    Evas_Object *slider = e_slider_add(inst->popup->win->evas);
452    evas_object_show(slider);
453    e_slider_orientation_set(slider, 0);
454    e_slider_value_set(slider, value);
455    e_slider_value_range_set(slider, 0.0, 100.0);
456    e_slider_value_format_display_set(slider, NULL);
457    evas_object_smart_callback_add(slider, "changed", cb, inst);
458
459    return slider;
460 }
461
462 static void
463 _mixer_app_cb_del(E_Dialog *dialog __UNUSED__, void *data)
464 {
465    E_Mixer_Module_Context *ctxt = data;
466    ctxt->mixer_dialog = NULL;
467 }
468
469 static void _mixer_popup_del(E_Mixer_Instance *inst);
470
471 static Eina_Bool
472 _mixer_popup_input_window_mouse_up_cb(void *data, int type __UNUSED__, void *event)
473 {
474    Ecore_Event_Mouse_Button *ev = event;
475    E_Mixer_Instance *inst = data;
476
477    if (ev->window != inst->ui.input.win)
478       return ECORE_CALLBACK_PASS_ON;
479
480    _mixer_popup_del(inst);
481
482    return ECORE_CALLBACK_PASS_ON;
483 }
484
485 static Eina_Bool
486 _mixer_popup_input_window_key_down_cb(void *data, int type __UNUSED__, void *event)
487 {
488    Ecore_Event_Key *ev = event;
489    E_Mixer_Instance *inst = data;
490    const char *keysym;
491
492    if (ev->window != inst->ui.input.win)
493       return ECORE_CALLBACK_PASS_ON;
494
495    keysym = ev->key;
496    if (strcmp(keysym, "Escape") == 0)
497       _mixer_popup_del(inst);
498    else if (strcmp(keysym, "Up") == 0)
499       _mixer_volume_increase(inst, EINA_FALSE);
500    else if (strcmp(keysym, "Down") == 0)
501       _mixer_volume_decrease(inst, EINA_FALSE);
502    else if ((strcmp(keysym, "Return") == 0) ||
503             (strcmp(keysym, "KP_Enter") == 0))
504       _mixer_toggle_mute(inst, EINA_FALSE);
505    else
506      {
507         E_Action *act;
508         Eina_List *l;
509         E_Config_Binding_Key *bind;
510         E_Binding_Modifier mod;
511         Eina_Bool handled = EINA_FALSE;
512         
513         for (l = e_config->key_bindings; l; l = l->next)
514           {
515              bind = l->data;
516              
517              if (bind->action && 
518                  (strcmp(bind->action, "volume_increase") &&
519                      strcmp(bind->action, "volume_decrease") &&
520                      strcmp(bind->action, "volume_mute")))
521                 continue;
522              
523              mod = 0;
524              
525              if (ev->modifiers & ECORE_EVENT_MODIFIER_SHIFT)
526                 mod |= E_BINDING_MODIFIER_SHIFT;
527              if (ev->modifiers & ECORE_EVENT_MODIFIER_CTRL)
528                 mod |= E_BINDING_MODIFIER_CTRL;
529              if (ev->modifiers & ECORE_EVENT_MODIFIER_ALT)
530                 mod |= E_BINDING_MODIFIER_ALT;
531              if (ev->modifiers & ECORE_EVENT_MODIFIER_WIN)
532                 mod |= E_BINDING_MODIFIER_WIN;
533              
534              if (bind->key && (!strcmp(bind->key, ev->keyname)) &&
535                  ((bind->modifiers == mod) || (bind->any_mod)))
536                {
537                   if (!(act = e_action_find(bind->action))) continue;
538                   if (act->func.go_key)
539                      act->func.go_key(E_OBJECT(inst->gcc->gadcon->zone), bind->params, ev);
540                   else if (act->func.go)
541                      act->func.go(E_OBJECT(inst->gcc->gadcon->zone), bind->params);
542                   handled = EINA_TRUE;
543                }
544           }
545         if (!handled) _mixer_popup_del(inst);
546      }
547
548    return ECORE_CALLBACK_PASS_ON;
549 }
550
551 static void
552 _mixer_popup_input_window_destroy(E_Mixer_Instance *inst)
553 {
554    e_grabinput_release(0, inst->ui.input.win);
555    ecore_x_window_free(inst->ui.input.win);
556    inst->ui.input.win = 0;
557
558    ecore_event_handler_del(inst->ui.input.mouse_up);
559    inst->ui.input.mouse_up = NULL;
560
561    ecore_event_handler_del(inst->ui.input.key_down);
562    inst->ui.input.key_down = NULL;
563 }
564
565 static void
566 _mixer_popup_input_window_create(E_Mixer_Instance *inst)
567 {
568    Ecore_X_Window_Configure_Mask mask;
569    Ecore_X_Window w, popup_w;
570    E_Manager *man;
571
572    man = e_manager_current_get();
573
574    w = ecore_x_window_input_new(man->root, 0, 0, man->w, man->h);
575    mask = (ECORE_X_WINDOW_CONFIGURE_MASK_STACK_MODE |
576            ECORE_X_WINDOW_CONFIGURE_MASK_SIBLING);
577    popup_w = inst->popup->win->evas_win;
578    ecore_x_window_configure(w, mask, 0, 0, 0, 0, 0, popup_w,
579                             ECORE_X_WINDOW_STACK_BELOW);
580    ecore_x_window_show(w);
581
582    inst->ui.input.mouse_up =
583       ecore_event_handler_add(ECORE_EVENT_MOUSE_BUTTON_UP,
584                               _mixer_popup_input_window_mouse_up_cb, inst);
585
586    inst->ui.input.key_down =
587       ecore_event_handler_add(ECORE_EVENT_KEY_DOWN,
588                               _mixer_popup_input_window_key_down_cb, inst);
589
590    inst->ui.input.win = w;
591    e_grabinput_get(0, 0, inst->ui.input.win);
592 }
593
594 static void
595 _mixer_popup_del(E_Mixer_Instance *inst)
596 {
597    _mixer_popup_input_window_destroy(inst);
598    e_object_del(E_OBJECT(inst->popup));
599    inst->ui.label = NULL;
600    inst->ui.left = NULL;
601    inst->ui.right = NULL;
602    inst->ui.mute = NULL;
603    inst->ui.table = NULL;
604    inst->ui.button = NULL;
605    inst->popup = NULL;
606    if (inst->popup_timer)
607       ecore_timer_del(inst->popup_timer);
608    inst->popup_timer = NULL;
609 }
610
611 static void
612 _mixer_app_select_current(E_Dialog *dialog, E_Mixer_Instance *inst)
613 {
614    E_Mixer_Gadget_Config *conf = inst->conf;
615
616    e_mixer_app_dialog_select(dialog, conf->card, conf->channel_name);
617 }
618
619
620 static void
621 _mixer_popup_cb_mixer(void *data, void *data2 __UNUSED__)
622 {
623    E_Mixer_Instance *inst = data;
624    E_Mixer_Module_Context *ctxt;
625    E_Container *con;
626
627    _mixer_popup_del(inst);
628
629    ctxt = mixer_mod->data;
630    if (ctxt->mixer_dialog)
631    {
632       _mixer_app_select_current(ctxt->mixer_dialog, inst);
633       e_dialog_show(ctxt->mixer_dialog);
634       return;
635    }
636
637    con = e_container_current_get(e_manager_current_get());
638    ctxt->mixer_dialog = e_mixer_app_dialog_new(
639                            con, _mixer_app_cb_del, ctxt);
640
641    _mixer_app_select_current(ctxt->mixer_dialog, inst);
642 }
643
644 static void
645 _mixer_popup_new(E_Mixer_Instance *inst)
646 {
647    E_Mixer_Channel_State *state;
648    Evas *evas;
649    Evas_Coord mw, mh;
650    int colspan;
651
652    if (inst->conf->dialog)
653       return;
654
655    state = &inst->mixer_state;
656    e_mod_mixer_state_get(inst->sys, inst->channel, state);
657
658    if ((state->right >= 0) &&
659          (inst->conf->show_locked || (!inst->conf->lock_sliders)))
660       colspan = 2;
661    else
662       colspan = 1;
663
664    inst->popup = e_gadcon_popup_new(inst->gcc);
665    evas = inst->popup->win->evas;
666
667    inst->ui.table = e_widget_table_add(evas, 0);
668
669    inst->ui.label = e_widget_label_add(evas, inst->conf->channel_name);
670    e_widget_table_object_append(inst->ui.table, inst->ui.label,
671                                 0, 0, colspan, 1, 0, 0, 0, 0);
672
673    if (state->left >= 0)
674    {
675       inst->ui.left = _mixer_popup_add_slider(
676                          inst, state->left, _mixer_popup_cb_volume_left_change);
677       e_widget_table_object_append(inst->ui.table, inst->ui.left,
678                                    0, 1, 1, 1, 1, 1, 1, 1);
679    }
680    else
681       inst->ui.left = NULL;
682
683    if ((state->right >= 0) &&
684          (inst->conf->show_locked || (!inst->conf->lock_sliders)))
685    {
686       inst->ui.right = _mixer_popup_add_slider(
687                           inst, state->right, _mixer_popup_cb_volume_right_change);
688       e_widget_table_object_append(inst->ui.table, inst->ui.right,
689                                    1, 1, 1, 1, 1, 1, 1, 1);
690    }
691    else
692       inst->ui.right = NULL;
693
694    if (e_mod_mixer_mutable_get(inst->sys, inst->channel))
695    {
696       inst->ui.mute = e_widget_check_add(evas, _("Mute"), &state->mute);
697       evas_object_show(inst->ui.mute);
698       e_widget_table_object_append(inst->ui.table, inst->ui.mute,
699                                    0, 2, colspan, 1, 1, 1, 1, 0);
700       evas_object_smart_callback_add(inst->ui.mute, "changed",
701                                      _mixer_popup_cb_mute_change, inst);
702    }
703    else
704       inst->ui.mute = NULL;
705
706    inst->ui.button = e_widget_button_add(evas, NULL, "preferences-system",
707                                          _mixer_popup_cb_mixer, inst, NULL);
708    e_widget_table_object_append(inst->ui.table, inst->ui.button,
709                                 0, 7, colspan, 1, 1, 1, 1, 0);
710
711    e_widget_size_min_get(inst->ui.table, &mw, &mh);
712    if (mh < 208) mh = 208;
713    e_widget_size_min_set(inst->ui.table, mw, mh);
714
715    e_gadcon_popup_content_set(inst->popup, inst->ui.table);
716    e_gadcon_popup_show(inst->popup);
717    _mixer_popup_input_window_create(inst);
718 }
719
720 static void
721 _mixer_popup_timer_new(E_Mixer_Instance *inst)
722 {
723    if (inst->popup)
724      {
725         if (inst->popup_timer)
726           {
727              ecore_timer_del(inst->popup_timer); 
728              inst->popup_timer = ecore_timer_add(1.0, _mixer_popup_timer_cb, inst);
729           }
730      }
731    else
732      {
733         _mixer_popup_new(inst);
734         inst->popup_timer = ecore_timer_add(1.0, _mixer_popup_timer_cb, inst);
735      }
736 }
737
738 static Eina_Bool
739 _mixer_popup_timer_cb(void *data)
740 {
741    E_Mixer_Instance *inst;
742    inst = data;
743
744    if (inst->popup)
745       _mixer_popup_del(inst);
746    inst->popup_timer = NULL;
747
748    return ECORE_CALLBACK_CANCEL;
749 }
750
751 static void
752 _mixer_menu_cb_post(void *data, E_Menu *menu __UNUSED__)
753 {
754    E_Mixer_Instance *inst = data;
755    if ((!inst) || (!inst->menu))
756       return;
757    if (inst->menu)
758    {
759       e_object_del(E_OBJECT(inst->menu));
760       inst->menu = NULL;
761    }
762 }
763
764 static void
765 _mixer_menu_cb_cfg(void *data, E_Menu *menu __UNUSED__, E_Menu_Item *mi __UNUSED__)
766 {
767    E_Mixer_Instance *inst = data;
768    E_Container *con;
769
770    if (inst->popup)
771       _mixer_popup_del(inst);
772    con = e_container_current_get(e_manager_current_get());
773    inst->conf->dialog = e_mixer_config_dialog_new(con, inst->conf);
774 }
775
776 static void
777 _mixer_menu_new(E_Mixer_Instance *inst, Evas_Event_Mouse_Down *ev)
778 {
779    E_Zone *zone;
780    E_Menu *m;
781    E_Menu_Item *mi;
782    int x, y;
783
784    zone = e_util_zone_current_get(e_manager_current_get());
785
786    m = e_menu_new();
787
788    mi = e_menu_item_new(m);
789    e_menu_item_label_set(mi, _("Settings"));
790    e_util_menu_item_theme_icon_set(mi, "configure");
791    e_menu_item_callback_set(mi, _mixer_menu_cb_cfg, inst);
792
793    m = e_gadcon_client_util_menu_items_append(inst->gcc, m, 0);
794    e_menu_post_deactivate_callback_set(m, _mixer_menu_cb_post, inst);
795    inst->menu = m;
796
797    e_gadcon_canvas_zone_geometry_get(inst->gcc->gadcon, &x, &y, NULL, NULL);
798    e_menu_activate_mouse(m, zone, x + ev->output.x, y + ev->output.y,
799                          1, 1, E_MENU_POP_DIRECTION_AUTO, ev->timestamp);
800    evas_event_feed_mouse_up(inst->gcc->gadcon->evas, ev->button,
801                             EVAS_BUTTON_NONE, ev->timestamp, NULL);
802 }
803
804 static void
805 _mixer_cb_mouse_down(void *data, Evas *evas __UNUSED__, Evas_Object *obj __UNUSED__, void *event)
806 {
807    E_Mixer_Instance *inst = data;
808    Evas_Event_Mouse_Down *ev = event;
809
810    if (ev->button == 1)
811    {
812       if (!inst->popup)
813          _mixer_popup_new(inst);
814       else
815          _mixer_popup_del(inst);
816    }
817    else if (ev->button == 2)
818       _mixer_toggle_mute(inst, EINA_FALSE);
819    else if ((ev->button == 3) && (!inst->menu))
820       _mixer_menu_new(inst, ev);
821 }
822
823 static void
824 _mixer_cb_mouse_wheel(void *data, Evas *evas __UNUSED__, Evas_Object *obj __UNUSED__, void *event)
825 {
826    E_Mixer_Instance *inst = data;
827    Evas_Event_Mouse_Wheel *ev = event;
828
829    if (ev->direction == 0)
830    {
831       if (ev->z > 0)
832          _mixer_volume_decrease(inst, EINA_FALSE);
833       else if (ev->z < 0)
834          _mixer_volume_increase(inst, EINA_FALSE);
835    }
836    else if (_mixer_using_default && (ev->direction == 1)) /* invalid with pulse */
837    {
838       if (ev->z > 0)
839          _mixer_balance_left(inst);
840       else if (ev->z < 0)
841          _mixer_balance_right(inst);
842    }
843 }
844
845 static int
846 _mixer_sys_setup(E_Mixer_Instance *inst)
847 {
848    E_Mixer_Gadget_Config *conf;
849
850    conf = inst->conf;
851    if ((!_mixer_using_default) && (!e_mixer_pulse_ready())) return 1;
852
853    if (inst->sys)
854       e_mod_mixer_del(inst->sys);
855
856    inst->sys = e_mod_mixer_new(conf->card);
857    if (!inst->sys)
858    {
859       inst->channel = NULL;
860       return 0;
861    }
862
863    inst->channel = e_mod_mixer_channel_get_by_name(inst->sys, conf->channel_name);
864    return !!inst->channel;
865 }
866
867 static int
868 _mixer_system_cb_update(void *data, E_Mixer_System *sys __UNUSED__)
869 {
870    E_Mixer_Instance *inst = data;
871    e_mod_mixer_state_get(inst->sys, inst->channel, &inst->mixer_state);
872    _mixer_gadget_update(inst);
873
874    return 1;
875 }
876
877 int
878 e_mixer_update(E_Mixer_Instance *inst)
879 {
880    int r;
881
882    e_modapi_save(mixer_mod);
883    if ((!inst) || (!inst->conf))
884       return 0;
885
886    r = _mixer_sys_setup(inst);
887    if (r && _mixer_using_default)
888       e_mixer_system_callback_set(inst->sys, _mixer_system_cb_update, inst);
889
890    return r;
891 }
892
893 static int
894 _mixer_sys_setup_default_card(E_Mixer_Instance *inst)
895 {
896    E_Mixer_Gadget_Config *conf;
897    const char *card;
898
899    conf = inst->conf;
900    if (conf->card)
901       eina_stringshare_del(conf->card);
902
903    card = e_mod_mixer_card_default_get();
904    if (!card)
905       goto error;
906
907    inst->sys = e_mod_mixer_new(card);
908    if (!inst->sys)
909       goto system_error;
910
911    conf->card = card;
912    return 1;
913
914
915 system_error:
916    eina_stringshare_del(card);
917 error:
918    conf->card = NULL;
919    return 0;
920 }
921
922 static int
923 _mixer_sys_setup_default_channel(E_Mixer_Instance *inst)
924 {
925    E_Mixer_Gadget_Config *conf;
926    const char *channel_name;
927
928    conf = inst->conf;
929    if (conf->channel_name)
930       eina_stringshare_del(conf->channel_name);
931
932    channel_name = e_mod_mixer_channel_default_name_get(inst->sys);
933    if (!channel_name)
934       goto error;
935
936    inst->channel = e_mod_mixer_channel_get_by_name(inst->sys, channel_name);
937    if (!inst->channel)
938       goto system_error;
939
940    conf->channel_name = channel_name;
941    return 1;
942
943 system_error:
944    eina_stringshare_del(channel_name);
945 error:
946    conf->channel_name = NULL;
947    return 0;
948 }
949
950 static int
951 _mixer_sys_setup_defaults(E_Mixer_Instance *inst)
952 {
953    if ((!_mixer_using_default) && (!e_mixer_pulse_ready())) return 1;
954    if ((!inst->sys) && (!_mixer_sys_setup_default_card(inst)))
955       return 0;
956
957    return _mixer_sys_setup_default_channel(inst);
958 }
959
960 void
961 e_mod_mixer_pulse_ready(Eina_Bool ready)
962 {
963    E_Mixer_Instance *inst;
964    E_Mixer_Module_Context *ctxt;
965    Eina_List *l;
966
967    if (!mixer_mod) return;
968
969    if (ready) e_mixer_pulse_setup();
970    else e_mixer_default_setup();
971
972    ctxt = mixer_mod->data;
973    EINA_LIST_FOREACH(ctxt->instances, l, inst)
974      {
975         if ((!_mixer_sys_setup(inst)) && (!_mixer_sys_setup_defaults(inst)))
976            {
977               if (inst->sys)
978                  e_mod_mixer_del(inst->sys);
979               _mixer_gadget_configuration_free(ctxt->conf, inst->conf);
980               E_FREE(inst);
981               return;
982            }
983         e_mod_mixer_state_get(inst->sys, inst->channel, &inst->mixer_state);
984         _mixer_gadget_update(inst);
985      }
986 }
987
988 void
989 e_mod_mixer_pulse_update(void)
990 {
991    E_Mixer_Instance *inst;
992    E_Mixer_Module_Context *ctxt;
993    Eina_List *l;
994
995    if (!mixer_mod) return;
996
997    ctxt = mixer_mod->data;
998    EINA_LIST_FOREACH(ctxt->instances, l, inst)
999      {
1000         e_mod_mixer_state_get(inst->sys, inst->channel, &inst->mixer_state);
1001         _mixer_gadget_update(inst);
1002      }
1003 }
1004
1005 /* Gadcon Api Functions */
1006 static void _mixer_module_configuration_setup(E_Mixer_Module_Context *ctxt);
1007
1008 static E_Gadcon_Client *
1009 _gc_init(E_Gadcon *gc, const char *name, const char *id, const char *style)
1010 {
1011    E_Mixer_Instance *inst;
1012    E_Mixer_Module_Context *ctxt;
1013    E_Mixer_Gadget_Config *conf;
1014
1015    if (!mixer_mod)
1016       return NULL;
1017
1018    ctxt = mixer_mod->data;
1019    if (!ctxt->conf)
1020    {
1021       _mixer_module_configuration_setup(ctxt);
1022       if (!ctxt->conf)
1023          return NULL;
1024    }
1025
1026    conf = eina_hash_find(ctxt->conf->gadgets, id);
1027    if (!conf)
1028    {
1029       conf = _mixer_gadget_configuration_new(ctxt->conf, id);
1030       if (!conf)
1031          return NULL;
1032    }
1033
1034    inst = E_NEW(E_Mixer_Instance, 1);
1035    inst->conf = conf;
1036    conf->instance = inst;
1037    if ((!_mixer_sys_setup(inst)) && (!_mixer_sys_setup_defaults(inst)))
1038    {
1039       if (inst->sys)
1040          e_mod_mixer_del(inst->sys);
1041       _mixer_gadget_configuration_free(ctxt->conf, conf);
1042       E_FREE(inst);
1043       return NULL;
1044    }
1045    
1046    if (_mixer_using_default) e_mixer_system_callback_set(inst->sys, _mixer_system_cb_update, inst);
1047
1048    inst->ui.gadget = edje_object_add(gc->evas);
1049    e_theme_edje_object_set(inst->ui.gadget, "base/theme/modules/mixer",
1050                            "e/modules/mixer/main");
1051
1052    inst->gcc = e_gadcon_client_new(gc, name, id, style, inst->ui.gadget);
1053    inst->gcc->data = inst;
1054
1055    evas_object_event_callback_add(inst->ui.gadget, EVAS_CALLBACK_MOUSE_DOWN,
1056                                   _mixer_cb_mouse_down, inst);
1057    evas_object_event_callback_add(inst->ui.gadget, EVAS_CALLBACK_MOUSE_WHEEL,
1058                                   _mixer_cb_mouse_wheel, inst);
1059
1060    if (inst->sys)
1061      {
1062         e_mod_mixer_state_get(inst->sys, inst->channel, &inst->mixer_state);
1063         _mixer_gadget_update(inst);
1064      }
1065
1066    if (!ctxt->conf->default_gc_id)
1067    {
1068       ctxt->conf->default_gc_id = eina_stringshare_add(id);
1069       ctxt->default_instance = inst;
1070    }
1071    else if ((!ctxt->default_instance) ||
1072             (strcmp(id, ctxt->conf->default_gc_id) == 0))
1073       ctxt->default_instance = inst;
1074
1075    ctxt->instances = eina_list_append(ctxt->instances, inst);
1076
1077    return inst->gcc;
1078 }
1079
1080 static void
1081 _gc_shutdown(E_Gadcon_Client *gcc)
1082 {
1083    E_Mixer_Module_Context *ctxt;
1084    E_Mixer_Instance *inst;
1085
1086    if (!mixer_mod)
1087       return;
1088
1089    ctxt = mixer_mod->data;
1090    if (!ctxt)
1091       return;
1092
1093    inst = gcc->data;
1094    if (!inst)
1095       return;
1096
1097    if (inst->menu)
1098    {
1099       e_menu_post_deactivate_callback_set(inst->menu, NULL, NULL);
1100       e_object_del(E_OBJECT(inst->menu));
1101    }
1102    evas_object_del(inst->ui.gadget);
1103    e_mod_mixer_channel_del(inst->channel);
1104    e_mod_mixer_del(inst->sys);
1105
1106    inst->conf->instance = NULL;
1107    ctxt->instances = eina_list_remove(ctxt->instances, inst);
1108
1109    if (ctxt->default_instance == inst)
1110      ctxt->default_instance = NULL;
1111
1112    E_FREE(inst);
1113 }
1114
1115 static void
1116 _gc_orient(E_Gadcon_Client *gcc, E_Gadcon_Orient orient __UNUSED__)
1117 {
1118    e_gadcon_client_aspect_set(gcc, 16, 16);
1119    e_gadcon_client_min_size_set(gcc, 16, 16);
1120 }
1121
1122 static const char *
1123 _gc_label(E_Gadcon_Client_Class *client_class __UNUSED__)
1124 {
1125    return (char*)_(_e_mixer_Name);
1126 }
1127
1128 static Evas_Object *
1129 _gc_icon(E_Gadcon_Client_Class *client_class __UNUSED__, Evas *evas)
1130 {
1131    Evas_Object *o = edje_object_add(evas);
1132    edje_object_file_set(o, e_mixer_theme_path(), "icon");
1133    return o;
1134 }
1135
1136 static const char *
1137 _gc_id_new(E_Gadcon_Client_Class *client_class __UNUSED__)
1138 {
1139    E_Mixer_Module_Context *ctxt;
1140    Eina_List *instances;
1141
1142    if (!mixer_mod)
1143       return NULL;
1144
1145    ctxt = mixer_mod->data;
1146    if (!ctxt)
1147       return NULL;
1148
1149    instances = ctxt->instances;
1150    snprintf(tmpbuf, sizeof(tmpbuf), "mixer.%d", eina_list_count(instances));
1151    return tmpbuf;
1152 }
1153
1154 static const E_Gadcon_Client_Class _gc_class =
1155 {
1156    GADCON_CLIENT_CLASS_VERSION, _name,
1157    { 
1158       _gc_init, _gc_shutdown, _gc_orient, _gc_label, _gc_icon, _gc_id_new, NULL,
1159       e_gadcon_site_is_not_toolbar 
1160    },
1161    E_GADCON_CLIENT_STYLE_PLAIN
1162 };
1163
1164
1165
1166 EAPI E_Module_Api e_modapi = {E_MODULE_API_VERSION, _e_mixer_Name};
1167
1168 static void
1169 _mixer_cb_volume_increase(E_Object *obj __UNUSED__, const char *params __UNUSED__)
1170 {
1171    E_Mixer_Module_Context *ctxt;
1172
1173    if (!mixer_mod)
1174       return;
1175
1176    ctxt = mixer_mod->data;
1177    if (!ctxt->conf)
1178       return;
1179
1180
1181    if (!ctxt->default_instance)
1182       return;
1183
1184    if (ctxt->default_instance->conf->keybindings_popup)
1185      _mixer_popup_timer_new(ctxt->default_instance);
1186    _mixer_volume_increase(ctxt->default_instance, EINA_TRUE);
1187 }
1188
1189 static void
1190 _mixer_cb_volume_decrease(E_Object *obj __UNUSED__, const char *params __UNUSED__)
1191 {
1192    E_Mixer_Module_Context *ctxt;
1193
1194    if (!mixer_mod)
1195       return;
1196
1197    ctxt = mixer_mod->data;
1198    if (!ctxt->conf)
1199       return;
1200
1201    if (!ctxt->default_instance)
1202       return;
1203
1204    if (ctxt->default_instance->conf->keybindings_popup)
1205      _mixer_popup_timer_new(ctxt->default_instance);
1206    _mixer_volume_decrease(ctxt->default_instance, EINA_TRUE);
1207 }
1208
1209 static void
1210 _mixer_cb_volume_mute(E_Object *obj __UNUSED__, const char *params __UNUSED__)
1211 {
1212    E_Mixer_Module_Context *ctxt;
1213
1214    if (!mixer_mod)
1215       return;
1216
1217    ctxt = mixer_mod->data;
1218    if (!ctxt->conf)
1219       return;
1220
1221    if (!ctxt->default_instance)
1222       return;
1223
1224    if (ctxt->default_instance->conf->keybindings_popup)
1225      _mixer_popup_timer_new(ctxt->default_instance);
1226    _mixer_toggle_mute(ctxt->default_instance, EINA_TRUE);
1227 }
1228
1229 static E_Config_Dialog *
1230 _mixer_module_config(E_Container *con, const char *params __UNUSED__)
1231 {
1232    E_Mixer_Module_Context *ctxt;
1233
1234    if (!mixer_mod)
1235       return NULL;
1236
1237    ctxt = mixer_mod->data;
1238    if (!ctxt)
1239       return NULL;
1240
1241    if (ctxt->conf_dialog)
1242       return NULL;
1243
1244    if (!ctxt->conf)
1245    {
1246       _mixer_module_configuration_setup(ctxt);
1247       if (!ctxt->conf)
1248          return NULL;
1249    }
1250
1251    ctxt->conf_dialog = e_mixer_config_module_dialog_new(con, ctxt);
1252    return ctxt->conf_dialog;
1253 }
1254
1255 static const char _reg_cat[] = "extensions";
1256 static const char _reg_item[] = "extensions/mixer";
1257
1258 static void
1259 _mixer_configure_registry_register(void)
1260 {
1261    e_configure_registry_category_add(_reg_cat, 90, _("Extensions"), NULL,
1262                                      "preferences-extensions");
1263    e_configure_registry_item_add(_reg_item, 30, _(_e_mixer_Name), NULL,
1264                                  "preferences-desktop-mixer",
1265                                  _mixer_module_config);
1266 }
1267
1268 static void
1269 _mixer_configure_registry_unregister(void)
1270 {
1271    e_configure_registry_item_del(_reg_item);
1272    e_configure_registry_category_del(_reg_cat);
1273 }
1274
1275 static E_Config_DD *
1276 _mixer_module_configuration_descriptor_new(E_Config_DD *gadget_conf_edd)
1277 {
1278    E_Config_DD *conf_edd;
1279
1280    conf_edd = E_CONFIG_DD_NEW("Mixer_Module_Config", E_Mixer_Module_Config);
1281    if (!conf_edd)
1282       return NULL;
1283    E_CONFIG_VAL(conf_edd, E_Mixer_Module_Config, version, INT);
1284    E_CONFIG_VAL(conf_edd, E_Mixer_Module_Config, default_gc_id, STR);
1285    E_CONFIG_HASH(conf_edd, E_Mixer_Module_Config, gadgets, gadget_conf_edd);
1286    E_CONFIG_VAL(conf_edd, E_Mixer_Module_Config, desktop_notification, INT);
1287
1288    return conf_edd;
1289 }
1290
1291 static inline void
1292 _mixer_module_configuration_descriptor_free(E_Config_DD *conf_edd)
1293 {
1294    if (!conf_edd)
1295       return;
1296    E_CONFIG_DD_FREE(conf_edd);
1297 }
1298
1299 static E_Config_DD *
1300 _mixer_gadget_configuration_descriptor_new(void)
1301 {
1302    E_Config_DD *conf_edd;
1303
1304    conf_edd = E_CONFIG_DD_NEW("Mixer_Gadget_Config", E_Mixer_Gadget_Config);
1305    if (!conf_edd)
1306       return NULL;
1307    E_CONFIG_VAL(conf_edd, E_Mixer_Gadget_Config, lock_sliders, INT);
1308    E_CONFIG_VAL(conf_edd, E_Mixer_Gadget_Config, show_locked, INT);
1309    E_CONFIG_VAL(conf_edd, E_Mixer_Gadget_Config, keybindings_popup, INT);
1310    E_CONFIG_VAL(conf_edd, E_Mixer_Gadget_Config, card, STR);
1311    E_CONFIG_VAL(conf_edd, E_Mixer_Gadget_Config, channel_name, STR);
1312
1313    return conf_edd;
1314 }
1315
1316 static inline void
1317 _mixer_gadget_configuration_descriptor_free(E_Config_DD *conf_edd)
1318 {
1319    if (!conf_edd)
1320       return;
1321    E_CONFIG_DD_FREE(conf_edd);
1322 }
1323
1324 static E_Mixer_Module_Config *
1325 _mixer_module_configuration_load(E_Config_DD *module_conf_edd)
1326 {
1327    E_Mixer_Module_Config *conf;
1328
1329    conf = e_config_domain_load(_conf_domain, module_conf_edd);
1330
1331    if (!conf)
1332      return _mixer_module_configuration_new();
1333    
1334    if (conf && !e_util_module_config_check (_("Mixer Module"), conf->version,
1335                                             MOD_CONFIG_FILE_VERSION))
1336      {
1337         _mixer_module_configuration_free(conf);
1338         return _mixer_module_configuration_new();
1339      }
1340
1341    return conf;
1342 }
1343
1344 static void
1345 _mixer_module_configuration_setup(E_Mixer_Module_Context *ctxt)
1346 {
1347    E_Config_DD *module_edd, *gadget_edd;
1348
1349    gadget_edd = _mixer_gadget_configuration_descriptor_new();
1350    module_edd = _mixer_module_configuration_descriptor_new(gadget_edd);
1351    ctxt->gadget_conf_edd = gadget_edd;
1352    ctxt->module_conf_edd = module_edd;
1353    ctxt->conf = _mixer_module_configuration_load(module_edd);
1354
1355 #define IFMODCFG(v) if ((ctxt->conf->version & 0xffff) < v) {
1356 #define IFMODCFGEND } 
1357
1358    IFMODCFG(0x0003);
1359    ctxt->conf->desktop_notification = 1;
1360    IFMODCFGEND;
1361
1362    ctxt->conf->version = MOD_CONFIG_FILE_VERSION;
1363    ctxt->desktop_notification = ctxt->conf->desktop_notification;
1364 }
1365
1366 static const char _act_increase[] = "volume_increase";
1367 static const char _act_decrease[] = "volume_decrease";
1368 static const char _act_mute[] = "volume_mute";
1369 static const char _lbl_increase[] = "Increase Volume";
1370 static const char _lbl_decrease[] = "Decrease Volume";
1371 static const char _lbl_mute[] = "Mute Volume";
1372
1373 static void
1374 _mixer_actions_register(E_Mixer_Module_Context *ctxt)
1375 {
1376    ctxt->actions.incr = e_action_add(_act_increase);
1377    if (ctxt->actions.incr)
1378    {
1379       ctxt->actions.incr->func.go = _mixer_cb_volume_increase;
1380       e_action_predef_name_set(_(_e_mixer_Name), _(_lbl_increase),
1381                                _act_increase, NULL, NULL, 0);
1382    }
1383
1384    ctxt->actions.decr = e_action_add(_act_decrease);
1385    if (ctxt->actions.decr)
1386    {
1387       ctxt->actions.decr->func.go = _mixer_cb_volume_decrease;
1388       e_action_predef_name_set(_(_e_mixer_Name), _(_lbl_decrease),
1389                                _act_decrease, NULL, NULL, 0);
1390    }
1391
1392    ctxt->actions.mute = e_action_add(_act_mute);
1393    if (ctxt->actions.mute)
1394    {
1395       ctxt->actions.mute->func.go = _mixer_cb_volume_mute;
1396       e_action_predef_name_set(_(_e_mixer_Name), _(_lbl_mute), _act_mute,
1397                                NULL, NULL, 0);
1398    }
1399 }
1400
1401 static void
1402 _mixer_actions_unregister(E_Mixer_Module_Context *ctxt)
1403 {
1404    if (ctxt->actions.incr)
1405    {
1406       e_action_predef_name_del(_(_e_mixer_Name), _(_lbl_increase));
1407       e_action_del(_act_increase);
1408    }
1409
1410    if (ctxt->actions.decr)
1411    {
1412       e_action_predef_name_del(_(_e_mixer_Name), _(_lbl_decrease));
1413       e_action_del(_act_decrease);
1414    }
1415
1416    if (ctxt->actions.mute)
1417    {
1418       e_action_predef_name_del(_(_e_mixer_Name), _(_lbl_mute));
1419       e_action_del(_act_mute);
1420    }
1421 }
1422
1423 void
1424 e_mixer_default_setup(void)
1425 {
1426    e_mod_mixer_volume_get = (void*)e_mixer_system_get_volume;
1427    e_mod_mixer_volume_set = (void*)e_mixer_system_set_volume;
1428    e_mod_mixer_mute_get = (void*)e_mixer_system_get_mute;
1429    e_mod_mixer_mute_set = (void*)e_mixer_system_set_mute;
1430    e_mod_mixer_mutable_get = (void*)e_mixer_system_can_mute;
1431    e_mod_mixer_state_get = (void*)e_mixer_system_get_state;
1432    e_mod_mixer_capture_get = (void*)e_mixer_system_has_capture;
1433    e_mod_mixer_new = (void*)e_mixer_system_new;
1434    e_mod_mixer_del = (void*)e_mixer_system_del;
1435    e_mod_mixer_channel_default_name_get = (void*)e_mixer_system_get_default_channel_name;
1436    e_mod_mixer_channel_get_by_name = (void*)e_mixer_system_get_channel_by_name;
1437    e_mod_mixer_channel_name_get = (void*)e_mixer_system_get_channel_name;
1438    e_mod_mixer_channel_del = (void*)e_mixer_system_channel_del;
1439    e_mod_mixer_channels_free = (void*)e_mixer_system_free_channels;
1440    e_mod_mixer_channels_get = (void*)e_mixer_system_get_channels;
1441    e_mod_mixer_channels_names_get = (void*)e_mixer_system_get_channels_names;
1442    e_mod_mixer_card_name_get = (void*)e_mixer_system_get_card_name;
1443    e_mod_mixer_cards_get = (void*)e_mixer_system_get_cards;
1444    e_mod_mixer_cards_free = (void*)e_mixer_system_free_cards;
1445    e_mod_mixer_card_default_get = (void*)e_mixer_system_get_default_card;
1446    _mixer_using_default = EINA_TRUE;
1447 }
1448
1449 void
1450 e_mixer_pulse_setup(void)
1451 {
1452    e_mod_mixer_volume_get = (void*)e_mixer_pulse_get_volume;
1453    e_mod_mixer_volume_set = (void*)e_mixer_pulse_set_volume;
1454    e_mod_mixer_mute_get = (void*)e_mixer_pulse_get_mute;
1455    e_mod_mixer_mute_set = (void*)e_mixer_pulse_set_mute;
1456    e_mod_mixer_mutable_get = (void*)e_mixer_pulse_can_mute;
1457    e_mod_mixer_state_get = (void*)e_mixer_pulse_get_state;
1458    e_mod_mixer_capture_get = (void*)e_mixer_pulse_has_capture;
1459    e_mod_mixer_new = (void*)e_mixer_pulse_new;
1460    e_mod_mixer_del = (void*)e_mixer_pulse_del;
1461    e_mod_mixer_channel_default_name_get = (void*)e_mixer_pulse_get_default_channel_name;
1462    e_mod_mixer_channel_get_by_name = (void*)e_mixer_pulse_get_channel_by_name;
1463    e_mod_mixer_channel_name_get = (void*)e_mixer_pulse_get_channel_name;
1464    e_mod_mixer_channel_del = (void*)e_mixer_pulse_channel_del;
1465    e_mod_mixer_channels_free = (void*)e_mixer_pulse_free_channels;
1466    e_mod_mixer_channels_get = (void*)e_mixer_pulse_get_channels;
1467    e_mod_mixer_channels_names_get = (void*)e_mixer_pulse_get_channels_names;
1468    e_mod_mixer_card_name_get = (void*)e_mixer_pulse_get_card_name;
1469    e_mod_mixer_cards_get = (void*)e_mixer_pulse_get_cards;
1470    e_mod_mixer_cards_free = (void*)e_mixer_pulse_free_cards;
1471    e_mod_mixer_card_default_get = (void*)e_mixer_pulse_get_default_card;
1472    _mixer_using_default = EINA_FALSE;
1473 }
1474
1475 EAPI void *
1476 e_modapi_init(E_Module *m)
1477 {
1478    E_Mixer_Module_Context *ctxt;
1479
1480    ctxt = E_NEW(E_Mixer_Module_Context, 1);
1481    if (!ctxt)
1482       return NULL;
1483
1484 #ifdef HAVE_ENOTIFY
1485    e_notification_init();
1486 #endif
1487
1488    _mixer_configure_registry_register();
1489    _mixer_actions_register(ctxt);
1490    e_gadcon_provider_register(&_gc_class);
1491    if (!e_mixer_pulse_init()) e_mixer_default_setup();
1492    else e_mixer_pulse_setup();
1493
1494    mixer_mod = m;
1495    return ctxt;
1496 }
1497
1498 static void
1499 _mixer_instances_free(E_Mixer_Module_Context *ctxt)
1500 {
1501    while (ctxt->instances)
1502    {
1503       E_Mixer_Instance *inst = ctxt->instances->data;
1504       e_object_del(E_OBJECT(inst->gcc));
1505    }
1506 }
1507
1508 EAPI int
1509 e_modapi_shutdown(E_Module *m)
1510 {
1511    E_Mixer_Module_Context *ctxt;
1512
1513    ctxt = m->data;
1514    if (!ctxt)
1515       return 0;
1516
1517    _mixer_instances_free(ctxt);
1518
1519    if (ctxt->conf_dialog)
1520       e_object_del(E_OBJECT(ctxt->conf_dialog));
1521
1522    if (ctxt->mixer_dialog)
1523       e_object_del(E_OBJECT(ctxt->mixer_dialog));
1524
1525    _mixer_configure_registry_unregister();
1526    _mixer_actions_unregister(ctxt);
1527    e_gadcon_provider_unregister(&_gc_class);
1528
1529    if (ctxt->conf)
1530    {
1531       _mixer_module_configuration_free(ctxt->conf);
1532       _mixer_gadget_configuration_descriptor_free(ctxt->gadget_conf_edd);
1533       _mixer_module_configuration_descriptor_free(ctxt->module_conf_edd);
1534    }
1535
1536 #ifdef HAVE_ENOTIFY
1537    e_notification_shutdown();
1538 #endif
1539
1540    E_FREE(ctxt);
1541    mixer_mod = NULL;
1542    return 1;
1543 }
1544
1545 EAPI int
1546 e_modapi_save(E_Module *m)
1547 {
1548    E_Mixer_Module_Context *ctxt;
1549
1550    ctxt = m->data;
1551    if (!ctxt)
1552       return 0;
1553    if (!ctxt->conf)
1554       return 1;
1555
1556    return e_config_domain_save(_conf_domain, ctxt->module_conf_edd, ctxt->conf);
1557 }