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