From c28047e3a151314830b1fd9788f5763148b7e31c Mon Sep 17 00:00:00 2001 From: Gustavo Sverzut Barbieri Date: Fri, 1 Aug 2008 03:08:16 +0000 Subject: [PATCH] Add mixer module. This is the mixer modules as in: git://staff.get-e.org/users/barbieri/e_module-mixer.git it's being used with ALSA backend for some time without problems and it's ready for inclusion. We still lack OSS4 engine. SVN revision: 35282 --- configure.in | 31 + data/themes/Makefile.am | 3 +- data/themes/default.edc | 1 + data/themes/default_mixer.edc | 246 ++++ data/themes/images/e17_mixer_base.png | Bin 0 -> 2707 bytes data/themes/images/e17_mixer_left_high.png | Bin 0 -> 748 bytes data/themes/images/e17_mixer_left_low.png | Bin 0 -> 543 bytes data/themes/images/e17_mixer_left_medium.png | Bin 0 -> 667 bytes data/themes/images/e17_mixer_module_icon.png | Bin 0 -> 3232 bytes data/themes/images/e17_mixer_mute.png | Bin 0 -> 705 bytes data/themes/images/e17_mixer_right_high.png | Bin 0 -> 761 bytes data/themes/images/e17_mixer_right_low.png | Bin 0 -> 545 bytes data/themes/images/e17_mixer_right_medium.png | Bin 0 -> 672 bytes src/modules/Makefile.am | 1 + src/modules/mixer/Makefile.am | 39 + src/modules/mixer/app_mixer.c | 614 ++++++++ src/modules/mixer/conf_gadget.c | 389 +++++ src/modules/mixer/conf_module.c | 192 +++ src/modules/mixer/e-module-mixer.edj | Bin 0 -> 9041 bytes src/modules/mixer/e_mod_main.c | 1252 +++++++++++++++++ src/modules/mixer/e_mod_main.h | 89 ++ src/modules/mixer/e_mod_system.h | 48 + src/modules/mixer/module.desktop.in | 5 + src/modules/mixer/sys_alsa.c | 618 ++++++++ src/modules/mixer/sys_dummy.c | 166 +++ 25 files changed, 3693 insertions(+), 1 deletion(-) create mode 100644 data/themes/default_mixer.edc create mode 100644 data/themes/images/e17_mixer_base.png create mode 100644 data/themes/images/e17_mixer_left_high.png create mode 100644 data/themes/images/e17_mixer_left_low.png create mode 100644 data/themes/images/e17_mixer_left_medium.png create mode 100644 data/themes/images/e17_mixer_module_icon.png create mode 100644 data/themes/images/e17_mixer_mute.png create mode 100644 data/themes/images/e17_mixer_right_high.png create mode 100644 data/themes/images/e17_mixer_right_low.png create mode 100644 data/themes/images/e17_mixer_right_medium.png create mode 100644 src/modules/mixer/Makefile.am create mode 100644 src/modules/mixer/app_mixer.c create mode 100644 src/modules/mixer/conf_gadget.c create mode 100644 src/modules/mixer/conf_module.c create mode 100644 src/modules/mixer/e-module-mixer.edj create mode 100644 src/modules/mixer/e_mod_main.c create mode 100644 src/modules/mixer/e_mod_main.h create mode 100644 src/modules/mixer/e_mod_system.h create mode 100644 src/modules/mixer/module.desktop.in create mode 100644 src/modules/mixer/sys_alsa.c create mode 100644 src/modules/mixer/sys_dummy.c diff --git a/configure.in b/configure.in index 8e9fca779..133117857 100644 --- a/configure.in +++ b/configure.in @@ -262,6 +262,35 @@ AC_SUBST(edje_cc) AC_DEFINE(E_INTERNAL, 1, "This define can be used to wrap internal E stuff, as config.h isn't exported") +dnl Check for Alsa +AC_ARG_ENABLE(alsa, AS_HELP_STRING([--enable-alsa], + [enable support for alsa(default=autodetect)]), + [ enable_alsa=$enableval ], [ enable_alsa=default ]) + +AM_CONDITIONAL(HAVE_ALSA, false) +if test "x$enable_alsa" = "xdefault" || test "x$enable_alsa" = "xyes"; then + PKG_CHECK_MODULES(ALSA, [alsa >= 1.0.8], + [ SOUND_CFLAGS="$ALSA_CFLAGS -DHAVE_ALSA $SOUND_CFLAGS" + SOUND_LDFLAGS="$ALSA_LIBS $SOUND_LDFLAGS" + AM_CONDITIONAL(HAVE_ALSA, true) + have_alsa=yes ], + [ if test "x$enable_alsa" = "xyes"; then + AC_MSG_ERROR([alsa library >= 1.0.8 not found]) + fi + ]) +else + have_alsa=no +fi + +if test "$have_alsa" = "yes"; then + AC_DEFINE(HAVE_ALSA, 1, [Define if the ALSA output plugin should be built]) +else + have_alsa=no +fi + +AC_SUBST(SOUND_CFLAGS) +AC_SUBST(SOUND_LDFLAGS) + AC_OUTPUT([ Makefile enlightenment.spec @@ -375,6 +404,8 @@ src/modules/conf_interaction/Makefile src/modules/conf_interaction/module.desktop src/modules/gadman/Makefile src/modules/gadman/module.desktop +src/modules/mixer/Makefile +src/modules/mixer/module.desktop src/preload/Makefile data/Makefile data/fonts/Makefile diff --git a/data/themes/Makefile.am b/data/themes/Makefile.am index 56a8e8bef..a03529afa 100644 --- a/data/themes/Makefile.am +++ b/data/themes/Makefile.am @@ -62,7 +62,8 @@ default_deskpreview.edc \ default_fontpreview.edc \ default_wizard.edc \ default_toolbar.edc \ -default_slidesel.edc +default_slidesel.edc \ +default_mixer.edc default.edj: Makefile $(EXTRA_DIST) $(EDJE_CC) $(EDJE_FLAGS) \ diff --git a/data/themes/default.edc b/data/themes/default.edc index c7dc249b5..cf64f43c3 100644 --- a/data/themes/default.edc +++ b/data/themes/default.edc @@ -86,4 +86,5 @@ collections { #include "default_wizard.edc" #include "default_toolbar.edc" #include "default_slidesel.edc" +#include "default_mixer.edc" } diff --git a/data/themes/default_mixer.edc b/data/themes/default_mixer.edc new file mode 100644 index 000000000..dbe41f301 --- /dev/null +++ b/data/themes/default_mixer.edc @@ -0,0 +1,246 @@ +images { + image: "e17_mixer_base.png" COMP; + image: "e17_mixer_mute.png" COMP; + image: "e17_mixer_left_low.png" COMP; + image: "e17_mixer_left_medium.png" COMP; + image: "e17_mixer_left_high.png" COMP; + image: "e17_mixer_right_low.png" COMP; + image: "e17_mixer_right_medium.png" COMP; + image: "e17_mixer_right_high.png" COMP; +} + +group { + name: "e/modules/mixer/main"; + max: 128 128; + min: 1 1; + + script { + public message(Msg_Type:type, id, ...) { + if ((type == MSG_INT_SET) && (id == 0)) { + new mute, left, right; + + mute = getarg(2); + left = getarg(3); + right = getarg(4); + + if (mute) + run_program(PROGRAM:"mute"); + else + run_program(PROGRAM:"unmute"); + + if (left <= 0) + run_program(PROGRAM:"left_none"); + else if (left < 33) + run_program(PROGRAM:"left_low"); + else if (left < 66) + run_program(PROGRAM:"left_medium"); + else if (left >= 66) + run_program(PROGRAM:"left_high"); + + if (right <= 0) + run_program(PROGRAM:"right_none"); + else if (right < 33) + run_program(PROGRAM:"right_low"); + else if (right < 66) + run_program(PROGRAM:"right_medium"); + else if (right >= 66) + run_program(PROGRAM:"right_high"); + } + } + } + + parts { + part { + name: "base"; + mouse_events: 0; + type: RECT; + description { + state: "default" 0.0; + color: 255 255 255 0; + aspect: 1 1; + aspect_preference: BOTH; + } + } + + part { + name: "speaker"; + mouse_events: 0; + type: IMAGE; + description { + state: "default" 0.0; + aspect: 1 1; + aspect_preference: BOTH; + rel1.to: "base"; + rel2.to: "base"; + image.normal: "e17_mixer_base.png"; + } + } + + part { + name: "left"; + mouse_events: 0; + type: IMAGE; + description { + state: "default" 0.0; + visible: 0; + aspect: 1 1; + aspect_preference: BOTH; + rel1.to: "base"; + rel2.to: "base"; + image.normal: "e17_mixer_left_low.png"; + } + description { + state: "low" 0.0; + inherit: "default" 0.0; + visible: 1; + } + description { + state: "medium" 0.0; + inherit: "default" 0.0; + visible: 1; + image.normal: "e17_mixer_left_medium.png"; + } + description { + state: "high" 0.0; + inherit: "default" 0.0; + visible: 1; + image.normal: "e17_mixer_left_high.png"; + } + } + + part { + name: "right"; + mouse_events: 0; + type: IMAGE; + description { + state: "default" 0.0; + visible: 0; + aspect: 1 1; + aspect_preference: BOTH; + rel1.to: "base"; + rel2.to: "base"; + image.normal: "e17_mixer_right_low.png"; + } + description { + state: "low" 0.0; + inherit: "default" 0.0; + visible: 1; + } + description { + state: "medium" 0.0; + inherit: "default" 0.0; + visible: 1; + image.normal: "e17_mixer_right_medium.png"; + } + description { + state: "high" 0.0; + inherit: "default" 0.0; + visible: 1; + image.normal: "e17_mixer_right_high.png"; + } + } + + part { + name: "mute"; + mouse_events: 0; + type: IMAGE; + description { + state: "default" 0.0; + aspect: 1 1; + aspect_preference: BOTH; + visible: 0; + rel1.to: "base"; + rel2.to: "base"; + image.normal: "e17_mixer_mute.png"; + } + description { + state: "active" 0.0; + inherit: "default" 0.0; + visible: 1; + } + } + + part { + name: "over"; + type: RECT; + description { + state: "default" 0.0; + rel1.to: "base"; + rel2.to: "base"; + color: 255 255 255 0; + } + } + } + + programs { + program { + name: "mute"; + action: STATE_SET "active" 0.0; + transition: LINEAR 0.1; + target: "mute"; + } + + program { + name: "unmute"; + action: STATE_SET "default" 0.0; + transition: LINEAR 0.1; + target: "mute"; + } + + program { + name: "left_none"; + action: STATE_SET "default" 0.0; + transition: LINEAR 0.1; + target: "left"; + } + + program { + name: "left_low"; + action: STATE_SET "low" 0.0; + transition: LINEAR 0.1; + target: "left"; + } + + program { + name: "left_medium"; + action: STATE_SET "medium" 0.0; + transition: LINEAR 0.1; + target: "left"; + } + + program { + name: "left_high"; + action: STATE_SET "high" 0.0; + transition: LINEAR 0.1; + target: "left"; + } + + program { + name: "right_none"; + action: STATE_SET "default" 0.0; + transition: LINEAR 0.1; + target: "right"; + } + + program { + name: "right_low"; + action: STATE_SET "low" 0.0; + transition: LINEAR 0.1; + target: "right"; + } + + program { + name: "right_medium"; + action: STATE_SET "medium" 0.0; + transition: LINEAR 0.1; + target: "right"; + } + + program { + name: "right_high"; + action: STATE_SET "high" 0.0; + transition: LINEAR 0.1; + target: "right"; + } + } +} diff --git a/data/themes/images/e17_mixer_base.png b/data/themes/images/e17_mixer_base.png new file mode 100644 index 0000000000000000000000000000000000000000..d4b216307695e6083ef4f66191e4c21cc7fb406e GIT binary patch literal 2707 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 literal 0 HcmV?d00001 diff --git a/data/themes/images/e17_mixer_left_medium.png b/data/themes/images/e17_mixer_left_medium.png new file mode 100644 index 0000000000000000000000000000000000000000..63e84681973698f3664f4e768bc4e73f160d2ba2 GIT binary patch literal 667 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 literal 0 HcmV?d00001 diff --git a/data/themes/images/e17_mixer_right_high.png b/data/themes/images/e17_mixer_right_high.png new file mode 100644 index 0000000000000000000000000000000000000000..359159fc6befa077c97f9aca99ef8a78f6a0be25 GIT binary patch literal 761 zcmV&^M6$HdA}d%HcK2Nm3`Ub0O}vcB`#sG&nKzm5ywCg0Gebc^ zK|w)5LBU_SCHuESvnT})Ty#q_Jasj6|88g!+uR4P58OCfII6m6RoNOwv5V%@L`ty< zEVLI|*>?84eOKisaTc?fd0KcSF-B1R?fM6I-nw(em^D?O;tKqR5AiHgY-?zzF$(P5 z-}$C8U3sl{zE?9~Pa?sK*vA3pQT3kfQml!nwq9#$8_{(NO^o1G^za<&7>QP3?0D>E z*2*%+X7man4=XGg%E1*&=Vu4Bh?L--}6&j~z28RJ>Z z0{ZUBl~9(47S*u&738J3=ijF<(GNAzN#$_5`KCx>7pR5l_Cx+pL;JKZ?k~{pw`Ziv zIFvXD-FXn{p%b-0D{Wm+R+iY6sDvA$9&Nit8l7cO@ScRoY4oM;8kj6`qUWDKW@X*}+1b!V) zk}seXJPM|Q&_hK?z?M?~g~X;JE(vtm?CyB57Cgihyv)Enry1rqFb^*;120%C7K_DV zvHVRNdEKbgQeeUz+6*pt5iO!w(Ufj)PdC%MoUy}{IxT{$$IqyWb^`UF?#q$9%a|>m zv2}GYqYByy?7!OID;Z&g)K)|B^o6r zVWhx#Xh;1J0RT6{M` zpjxeZ-BI@;1y)JuBG}^z-{#%ZVlGsvRGPhhZ*#gaU1Y+01P9#b_&Rrmw!hf#Ign(| jV9R2$SS%Kc zU=VSZ115?v3kniH5=NaFLkAN-(k7a=(_Q7l%D{-C;HC=d-QD6W&P$zp@41JZoSdAT zoSdBhQx|?~XqZZYEl1Tgl2ym7&X+=iwB_D+vG4Nx>Gvf^Eh~DAVZ1`)b0R%y6PRvI zH^a5?2b)fb9L8Q$F!8zg)CtW0F@J4xX>!e$Np0ux4#zN~uJmbqA&pyL{ptFjz2m*7 zyZgIkeKrJwL}Jr#o~8N^>{5PGZfF_OaTW>;;g{5x&@LnGkt<;{47E*&3LrvFT{RN| zb2sK%gZ~aL=@=B5#2bv@cqRm3;Q7F^u06WO@e=#+Q)UGEJN>J6#3IAkz@B6?XG5SA zl^$tpiwxj(a%zrcMnLQ@kscI9qFt}d2*hGyfjH@jKIR)_NuZph8>5?)P@EZoR@|CU zP{g*tR`NN@j6k!{Jfx^7@JgUJDWhg)1UC0?PU+EA@DIw^!IMk~%*@P`nn#*bXeqdx zod4T+kO_emE0?3es9&fda1#fU%j|JB1P-rM6>TfHtza~{g`Z+Q^#Ws+v0oiAF7Qmz z@Aw&8nE&)0pE`l5lT#N~kFTE9XG77Pz5Y(R&=uS=Yaz7)wOVcBesI4Q567{<9igi@ zk@P_ec&TnEm1C7^wOU?WTfF3yQISP~>q)8ya1RS+wa`l4o48V`TzuGgcy8y%oqj!* z#cnubNnjLjv250hOw5J;state; + if (app->lock_sliders && (state->left != state->right)) + { + state->right = state->left; + e_widget_slider_value_int_set(app->ui.channel_editor.right, + state->right); + } + + e_mixer_system_set_volume(app->sys, app->channel_info->id, + state->left, state->right); +} + +static void +_cb_changed_right(void *data, Evas_Object *obj) +{ + E_Mixer_App_Dialog_Data *app = data; + E_Mixer_Channel_State *state; + + state = &app->state; + if (app->lock_sliders && (state->right != state->left)) + { + state->left = state->right; + e_widget_slider_value_int_set(app->ui.channel_editor.left, + state->left); + } + + e_mixer_system_set_volume(app->sys, app->channel_info->id, + state->left, state->right); +} + +static void +_cb_changed_mute(void *data, Evas_Object *obj) +{ + E_Mixer_App_Dialog_Data *app = data; + + e_mixer_system_set_mute(app->sys, app->channel_info->id, app->state.mute); +} + +static void +_cb_changed_lock_sliders(void *data, Evas_Object *obj) +{ + E_Mixer_App_Dialog_Data *app = data; + E_Mixer_Channel_State *state; + + if (!app->lock_sliders) + return; + + state = &app->state; + if (state->left == state->right) + return; + + state->left = state->right = (state->left + state->right) / 2; + + e_widget_slider_value_int_set(app->ui.channel_editor.left, state->left); + e_widget_slider_value_int_set(app->ui.channel_editor.right, state->right); + e_mixer_system_set_volume(app->sys, app->channel_info->id, + state->left, state->right); +} + +static void +_update_channel_editor_state(E_Mixer_App_Dialog_Data *app, const E_Mixer_Channel_State state) +{ + struct e_mixer_app_ui_channel_editor *ui; + + ui = &app->ui.channel_editor; + + e_widget_slider_value_int_set(ui->left, state.left); + e_widget_slider_value_int_set(ui->right, state.right); + + if (e_mixer_system_can_mute(app->sys, app->channel_info->id)) + { + e_widget_disabled_set(ui->mute, 0); + e_widget_check_checked_set(ui->mute, state.mute); + } + else + { + e_widget_disabled_set(ui->mute, 1); + e_widget_check_checked_set(ui->mute, 0); + } +} + +static void +_populate_channel_editor(E_Mixer_App_Dialog_Data *app) +{ + struct e_mixer_app_ui_channel_editor *ui; + E_Mixer_Channel_State state; + char *card_name; + + ui = &app->ui.channel_editor; + + card_name = e_mixer_system_get_card_name(app->card); + e_widget_entry_text_set(ui->card, card_name); + if (card_name) + free(card_name); + + e_widget_entry_text_set(ui->channel, app->channel_name); + + if (e_mixer_system_has_capture(app->sys, app->channel_info->id)) + e_widget_entry_text_set(ui->type, D_("Capture")); + else + e_widget_entry_text_set(ui->type, D_("Playback")); + + e_mixer_system_get_state(app->sys, app->channel_info->id, &state); + _update_channel_editor_state(app, state); + + app->lock_sliders = (state.left == state.right); + e_widget_check_checked_set(ui->lock_sliders, app->lock_sliders); +} + +static void +_cb_channel_selected(void *data) +{ + struct channel_info *info = data; + E_Mixer_App_Dialog_Data *app; + + app = info->app; + app->channel_info = info; + _populate_channel_editor(app); +} + +static int +_channel_info_cmp(void *data_a, void *data_b) +{ + struct channel_info *a = data_a, *b = data_b; + + if (a->has_capture < b->has_capture) + return -1; + else if (a->has_capture > b->has_capture) + return 1; + + return strcmp(a->name, b->name); +} + +static Evas_List * +_channels_info_new(E_Mixer_System *sys) +{ + Evas_List *channels, *channels_infos, *l; + + channels = e_mixer_system_get_channels(sys); + channels_infos = NULL; + for (l = channels; l != NULL; l = l->next) + { + struct channel_info *info; + + info = malloc(sizeof(*info)); + info->id = l->data; + info->name = e_mixer_system_get_channel_name(sys, info->id); + info->has_capture = e_mixer_system_has_capture(sys, info->id); + + channels_infos = evas_list_append(channels_infos, info); + } + e_mixer_system_free_channels(channels); + + return evas_list_sort(channels_infos, -1, _channel_info_cmp); +} + +static void +_channels_info_free(Evas_List *list) +{ + Evas_List *l; + + for (l = list; l != NULL; l = l->next) + { + struct channel_info *info = l->data; + free(info->name); + free(info); + } + + evas_list_free(list); +} + +static int +_cb_system_update(void *data, E_Mixer_System *sys) +{ + E_Mixer_App_Dialog_Data *app; + E_Mixer_Channel_State state; + + app = data; + + if ((!app->sys) || (!app->channel_info)) + return 1; + + e_mixer_system_get_state(app->sys, app->channel_info->id, &state); + _update_channel_editor_state(app, state); + + return 1; +} + + +static void +_populate_channels(E_Mixer_App_Dialog_Data *app) +{ + Evas_List *l; + Evas_Object *ilist; + int header_input; + int i; + + ilist = app->ui.channels.list; + edje_freeze(); + e_widget_ilist_freeze(ilist); + e_widget_ilist_clear(ilist); + + if (app->sys) + e_mixer_system_del(app->sys); + app->sys = e_mixer_system_new(app->card); + e_mixer_system_callback_set(app->sys, _cb_system_update, app); + + if (app->channel_name) + free(app->channel_name); + app->channel_name = e_mixer_system_get_default_channel_name(app->sys); + + if (app->channels_infos) + _channels_info_free(app->channels_infos); + app->channels_infos = _channels_info_new(app->sys); + + if (app->channels_infos) + { + struct channel_info *info = app->channels_infos->data; + if (info->has_capture) + { + e_widget_ilist_header_append(ilist, NULL, D_("Input")); + header_input = 1; + i = 1; + } + else + { + e_widget_ilist_header_append(ilist, NULL, D_("Output")); + header_input = 0; + i = 1; + } + } + + for (l = app->channels_infos; l != NULL; l = l->next, i++) + { + struct channel_info *info = l->data; + + if ((!header_input) && info->has_capture) + { + e_widget_ilist_header_append(ilist, NULL, D_("Input")); + header_input = 1; + i++; + } + + info->app = app; + e_widget_ilist_append(ilist, NULL, info->name, _cb_channel_selected, + info, info->name); + if (app->channel_name && info->name && + (strcmp(app->channel_name, info->name) == 0)) + { + e_widget_ilist_selected_set(ilist, i); + app->channel_info = info; + } + } + + e_widget_ilist_go(ilist); + e_widget_ilist_thaw(ilist); + edje_thaw(); +} + +static void +select_card(E_Mixer_App_Dialog_Data *app) +{ + _populate_channels(app); + e_widget_ilist_selected_set(app->ui.channels.list, 1); +} + +static void +_cb_card_selected(void *data) +{ + select_card(data); +} + +static void +_create_cards(E_Dialog *dialog, Evas *evas, E_Mixer_App_Dialog_Data *app) +{ + struct e_mixer_app_ui_cards *ui; + Evas_List *l; + + app->card = e_mixer_system_get_default_card(); + app->cards = e_mixer_system_get_cards(); + if (evas_list_count(app->cards) < 2) + return; + + ui = &app->ui.cards; + ui->list = e_widget_tlist_add(evas, &app->card); + e_widget_tlist_go(ui->list); + for (l = app->cards; l != NULL; l = l->next) + { + char *card, *card_name; + + card = l->data; + card_name = e_mixer_system_get_card_name(card); + + e_widget_tlist_append(ui->list, card_name, _cb_card_selected, + app, card); + + free(card_name); + } + + ui->frame = e_widget_framelist_add(evas, D_("Cards"), 0); + e_widget_framelist_object_append(ui->frame, ui->list); + e_widget_list_object_append(app->ui.hlayout, ui->frame, 1, 0, 0.0); +} + +static void +_create_channels(E_Dialog *dialog, Evas *evas, E_Mixer_App_Dialog_Data *app) +{ + struct e_mixer_app_ui_channels *ui; + + ui = &app->ui.channels; + ui->list = e_widget_ilist_add(evas, 24, 24, &app->channel_name); + e_widget_min_size_set(ui->list, 180, 100); + e_widget_ilist_go(ui->list); + + ui->frame = e_widget_framelist_add(evas, D_("Channels"), 0); + e_widget_framelist_object_append(ui->frame, ui->list); + e_widget_list_object_append(app->ui.hlayout, ui->frame, 1, 1, 0.0); +} + +static void +_create_channel_editor(E_Dialog *dialog, Evas *evas, E_Mixer_App_Dialog_Data *app) +{ + struct e_mixer_app_ui_channel_editor *ui; + + ui = &app->ui.channel_editor; + + ui->label_card = e_widget_label_add(evas, D_("Card:")); + ui->card = e_widget_entry_add(evas, NULL, NULL, NULL, NULL); + e_widget_entry_readonly_set(ui->card, 1); + + ui->label_channel = e_widget_label_add(evas, D_("Channel:")); + ui->channel = e_widget_entry_add(evas, NULL, NULL, NULL, NULL); + e_widget_entry_readonly_set(ui->channel, 1); + + ui->label_type = e_widget_label_add(evas, D_("Type:")); + ui->type = e_widget_entry_add(evas, NULL, NULL, NULL, NULL); + e_widget_entry_readonly_set(ui->type, 1); + + ui->label_left = e_widget_label_add(evas, D_("Left:")); + ui->left = e_widget_slider_add(evas, 1, 0, "%3.0f", 0.0, 100.0, 10.0, 100.0, + NULL, &app->state.left, 150); + e_widget_on_change_hook_set(ui->left, _cb_changed_left, app); + + ui->label_right = e_widget_label_add(evas, D_("Right:")); + ui->right = e_widget_slider_add(evas, 1, 0, "%3.0f", 0.0, 100.0, 10.0, 100.0, + NULL, &app->state.right, 150); + e_widget_on_change_hook_set(ui->right, _cb_changed_right, app); + + ui->mute = e_widget_check_add(evas, D_("Mute"), &app->state.mute); + e_widget_on_change_hook_set(ui->mute, _cb_changed_mute, app); + + ui->lock_sliders = e_widget_check_add(evas, D_("Lock Sliders"), + &app->lock_sliders); + e_widget_on_change_hook_set(ui->lock_sliders, _cb_changed_lock_sliders, app); + + ui->frame = e_widget_framelist_add(evas, D_("Edit"), 0); + e_widget_framelist_object_append(ui->frame, ui->label_card); + e_widget_framelist_object_append(ui->frame, ui->card); + e_widget_framelist_object_append(ui->frame, ui->label_channel); + e_widget_framelist_object_append(ui->frame, ui->channel); + e_widget_framelist_object_append(ui->frame, ui->label_type); + e_widget_framelist_object_append(ui->frame, ui->type); + e_widget_framelist_object_append(ui->frame, ui->label_left); + e_widget_framelist_object_append(ui->frame, ui->left); + e_widget_framelist_object_append(ui->frame, ui->label_right); + e_widget_framelist_object_append(ui->frame, ui->right); + e_widget_framelist_object_append(ui->frame, ui->mute); + e_widget_framelist_object_append(ui->frame, ui->lock_sliders); + + e_widget_list_object_append(app->ui.hlayout, ui->frame, 1, 1, 0.5); +} + +static void +_create_ui(E_Dialog *dialog, E_Mixer_App_Dialog_Data *app) +{ + struct e_mixer_app_ui *ui; + Evas *evas; + int mw, mh; + + evas = e_win_evas_get(dialog->win); + + ui = &app->ui; + + ui->hlayout = e_widget_list_add(evas, 0, 1); + _create_cards(dialog, evas, app); + _create_channels(dialog, evas, app); + _create_channel_editor(dialog, evas, app); + + if (ui->cards.list) + e_widget_tlist_selected_set(ui->cards.list, 0); + else + select_card(app); + e_widget_ilist_selected_set(ui->channels.list, 1); + + e_widget_min_size_get(ui->hlayout, &mw, &mh); + if (mw < 300) + mw = 300; + if (mh < 200) + mh = 200; + e_dialog_content_set(dialog, ui->hlayout, mw, mh); +} + +static void +_mixer_app_dialog_del(E_Dialog *dialog, E_Mixer_App_Dialog_Data *app) +{ + if (app->del.func) + app->del.func(dialog, app->del.data); + + if (app->card) + free(app->card); + if (app->channel_name) + free(app->channel_name); + if (app->cards) + e_mixer_system_free_cards(app->cards); + if (app->channels_infos) + _channels_info_free(app->channels_infos); + e_mixer_system_del(app->sys); + + e_util_defer_object_del(E_OBJECT(dialog)); + dialog->data = NULL; + E_FREE(app); +} + +static void +_cb_win_del(E_Win *win) +{ + E_Dialog *dialog; + E_Mixer_App_Dialog_Data *app; + + dialog = win->data; + app = dialog->data; + + _mixer_app_dialog_del(dialog, app); +} + +static void +_cb_dialog_dismiss(void *data, E_Dialog *dialog) +{ + _mixer_app_dialog_del(dialog, data); +} + +E_Dialog * +e_mixer_app_dialog_new(E_Container *con, void (*func)(E_Dialog *dialog, void *data), void *data) +{ + E_Mixer_App_Dialog_Data *app; + E_Dialog *dialog; + + dialog = e_dialog_new(con, _Name, "e_mixer_app_dialog"); + if (!dialog) + return NULL; + + app = E_NEW(E_Mixer_App_Dialog_Data, 1); + if (!app) + { + e_object_del(E_OBJECT(dialog)); + return NULL; + } + + dialog->data = app; + app->del.data = data; + app->del.func = func; + + e_dialog_title_set(dialog, D_(_Name)); + e_dialog_resizable_set(dialog, 1); + + e_win_delete_callback_set(dialog->win, _cb_win_del); + + _create_ui(dialog, app); + + e_dialog_button_add(dialog, D_("Close"), NULL, _cb_dialog_dismiss, app); + e_dialog_button_focus_num(dialog, 1); + e_win_centered_set(dialog->win, 1); + e_dialog_show(dialog); + + return dialog; +} + +static inline int +_find_card_by_name(E_Mixer_App_Dialog_Data *app, const char *card_name) +{ + Evas_List *l; + int i; + + for (i = 0, l = app->cards; l != NULL; i++, l = l->next) + if (strcmp(card_name, l->data) == 0) + return i; + + return -1; +} + +static inline int +_find_channel_by_name(E_Mixer_App_Dialog_Data *app, const char *channel_name) +{ + Evas_List *l; + int i, header_input; + + if (app->channels_infos) + { + struct channel_info *info = app->channels_infos->data; + + header_input = !!info->has_capture; + i = 1; + } + + for (l = app->channels_infos; l != NULL; l = l->next, i++) + { + struct channel_info *info = l->data; + + if ((!header_input) && info->has_capture) + { + header_input = 1; + i++; + } + + if (strcmp(channel_name, info->name) == 0) + return i; + } + + return -1; +} + +int +e_mixer_app_dialog_select(E_Dialog *dialog, const char *card_name, const char *channel_name) +{ + E_Mixer_App_Dialog_Data *app; + int n; + + if (!dialog) + return 0; + + app = dialog->data; + if (!app) + return 0; + + n = _find_card_by_name(app, card_name); + if (n < 0) + return 0; + if (app->ui.cards.list) + e_widget_tlist_selected_set(app->ui.cards.list, n); + + n = _find_channel_by_name(app, channel_name); + if (n < 0) + return 0; + e_widget_ilist_selected_set(app->ui.channels.list, n); + + return 1; +} diff --git a/src/modules/mixer/conf_gadget.c b/src/modules/mixer/conf_gadget.c new file mode 100644 index 000000000..928dda856 --- /dev/null +++ b/src/modules/mixer/conf_gadget.c @@ -0,0 +1,389 @@ +#include "e_mod_main.h" + +extern const char _Name[]; + +struct _E_Config_Dialog_Data +{ + int lock_sliders; + int show_locked; + int card_num; + int channel; + const char *card; + const char *channel_name; + Evas_List *cards; + Evas_List *cards_names; + Evas_List *channels_names; + struct mixer_config_ui + { + Evas_Object *table; + struct mixer_config_ui_general + { + Evas_Object *frame; + Evas_Object *lock_sliders; + Evas_Object *show_locked; + } general; + struct mixer_config_ui_cards + { + Evas_Object *frame; + E_Radio_Group *radio; + } cards; + struct mixer_config_ui_channels + { + Evas_Object *frame; + Evas_Object *scroll; + Evas_Object *list; + E_Radio_Group *radio; + Evas_List *radios; + } channels; + } ui; + E_Mixer_Gadget_Config *conf; +}; + +static void +_mixer_fill_cards_info(E_Config_Dialog_Data *cfdata) +{ + Evas_List *l; + int i; + + cfdata->card_num = -1; + cfdata->cards = e_mixer_system_get_cards(); + cfdata->cards_names = NULL; + for (l = cfdata->cards, i = 0; l != NULL; l = l->next, i++) + { + char *card, *name; + + card = l->data; + name = e_mixer_system_get_card_name(card); + if ((cfdata->card_num < 0) && card && cfdata->card && + (strcmp(card, cfdata->card) == 0)) + cfdata->card_num = i; + + cfdata->cards_names = evas_list_append(cfdata->cards_names, name); + } + + if (cfdata->card_num < 0) + cfdata->card_num = 0; +} + +static void +_mixer_fill_channels_info(E_Config_Dialog_Data *cfdata) +{ + E_Mixer_System *sys; + Evas_List *l; + int i; + + sys = e_mixer_system_new(cfdata->card); + if (!sys) + return; + + cfdata->channel = 0; + cfdata->channel_name = evas_stringshare_add(cfdata->conf->channel_name); + cfdata->channels_names = e_mixer_system_get_channels_names(sys); + for (l = cfdata->channels_names, i = 0; l != NULL; l = l->next, i++) + { + char *channel; + + channel = l->data; + if (channel && cfdata->channel_name && + (strcmp(channel, cfdata->channel_name) == 0)) + { + cfdata->channel = i; + break; + } + } + e_mixer_system_del(sys); +} + +static void * +_create_data(E_Config_Dialog *dialog) +{ + E_Config_Dialog_Data *cfdata; + E_Mixer_Gadget_Config *conf; + + cfdata = E_NEW(E_Config_Dialog_Data, 1); + if (!cfdata) + return NULL; + + conf = dialog->data; + cfdata->conf = conf; + cfdata->lock_sliders = conf->lock_sliders; + cfdata->show_locked = conf->show_locked; + cfdata->card = evas_stringshare_add(conf->card); + _mixer_fill_cards_info(cfdata); + _mixer_fill_channels_info(cfdata); + + return cfdata; +} + +static void +_free_data(E_Config_Dialog *dialog, E_Config_Dialog_Data *cfdata) +{ + E_Mixer_Gadget_Config *conf; + Evas_List *l; + + conf = dialog->data; + if (conf) + conf->dialog = NULL; + + if (!cfdata) + return; + + for (l = cfdata->cards_names; l != NULL; l = l->next) + if (l->data) + free(l->data); + evas_list_free(cfdata->cards_names); + + if (cfdata->channels_names) + e_mixer_system_free_channels_names(cfdata->channels_names); + if (cfdata->cards) + e_mixer_system_free_cards(cfdata->cards); + + if (cfdata->card) + evas_stringshare_del(cfdata->card); + if (cfdata->channel_name) + evas_stringshare_del(cfdata->channel_name); + + evas_list_free(cfdata->ui.channels.radios); + + E_FREE(cfdata); +} + +static int +_basic_apply(E_Config_Dialog *dialog, E_Config_Dialog_Data *cfdata) +{ + E_Mixer_Gadget_Config *conf; + const char *card, *channel; + + conf = dialog->data; + conf->lock_sliders = cfdata->lock_sliders; + conf->show_locked = cfdata->show_locked; + + card = evas_list_nth(cfdata->cards, cfdata->card_num); + if (card) + { + if (conf->card && (strcmp(card, conf->card) != 0)) + evas_stringshare_del(conf->card); + conf->card = evas_stringshare_add(card); + } + + channel = evas_list_nth(cfdata->channels_names, cfdata->channel); + if (channel) + { + if (conf->channel_name && (strcmp(channel, conf->channel_name) != 0)) + evas_stringshare_del(conf->channel_name); + conf->channel_name = evas_stringshare_add(channel); + } + + e_mixer_update(conf->instance); + return 1; +} + +static void +_lock_change(void *data, Evas_Object *obj, void *event) +{ + E_Config_Dialog_Data *cfdata; + + cfdata = data; + e_widget_disabled_set(cfdata->ui.general.show_locked, !cfdata->lock_sliders); +} + +static void +_basic_create_general(Evas *evas, E_Config_Dialog_Data *cfdata) +{ + struct mixer_config_ui_general *ui; + + ui = &cfdata->ui.general; + + ui->frame = e_widget_framelist_add(evas, D_("General Settings"), 0); + + ui->lock_sliders = e_widget_check_add( + evas, D_("Lock Sliders"), &cfdata->lock_sliders); + evas_object_smart_callback_add( + ui->lock_sliders, "changed", _lock_change, cfdata); + e_widget_framelist_object_append(ui->frame, ui->lock_sliders); + + ui->show_locked = e_widget_check_add( + evas, D_("Show both sliders when locked"), &cfdata->show_locked); + e_widget_disabled_set(ui->show_locked, !cfdata->lock_sliders); + e_widget_framelist_object_append(ui->frame, ui->show_locked); +} + +static void +_clear_channels(E_Config_Dialog_Data *cfdata) +{ + Evas_List *l; + + for (l = cfdata->ui.channels.radios; l != NULL; l = l->next) + evas_object_del(l->data); + cfdata->ui.channels.radios = evas_list_free(cfdata->ui.channels.radios); +} + +static void +_fill_channels(Evas *evas, E_Config_Dialog_Data *cfdata) +{ + struct mixer_config_ui_channels *ui; + Evas_Object *selected; + Evas_Coord mw, mh; + Evas_List *l; + int i; + + ui = &cfdata->ui.channels; + ui->radio = e_widget_radio_group_new(&cfdata->channel); + for (i = 0, l = cfdata->channels_names; l != NULL; l = l->next, i++) + { + Evas_Object *ow; + const char *name; + + name = l->data; + if (!name) + continue; + + ow = e_widget_radio_add(evas, name, i, ui->radio); + ui->radios = evas_list_append(ui->radios, ow); + e_widget_list_object_append(ui->list, ow, 1, 1, 0.0); + } + + e_widget_min_size_get(ui->list, &mw, &mh); + evas_object_resize(ui->list, mw, mh); + + selected = evas_list_nth(ui->radios, cfdata->channel); + if (selected) + { + Evas_Coord x, y, w, h, lx, ly; + evas_object_geometry_get(selected, &x, &y, &w, &h); + evas_object_geometry_get(ui->list, &lx, &ly, NULL, NULL); + x -= lx; + y -= ly - 10; + h += 20; + e_widget_scrollframe_child_region_show(ui->scroll, x, y, w, h); + } +} + +static void +_channel_scroll_set_min_size(struct mixer_config_ui_channels *ui) +{ + Evas_Coord w, h; + int len; + + len = evas_list_count(ui->radios); + if (len < 1) + return; + + e_widget_min_size_get(ui->list, &w, &h); + h = 4 * h / len; + e_widget_min_size_set(ui->scroll, w, h); +} + +static void +_basic_create_channels(Evas *evas, E_Config_Dialog_Data *cfdata) +{ + struct mixer_config_ui_channels *ui; + + ui = &cfdata->ui.channels; + ui->list = e_widget_list_add(evas, 1, 0); + ui->scroll = e_widget_scrollframe_simple_add(evas, ui->list); + ui->frame = e_widget_framelist_add(evas, D_("Channels"), 0); + + _fill_channels(evas, cfdata); + + _channel_scroll_set_min_size(ui); + e_widget_framelist_object_append(ui->frame, ui->scroll); +} + +static void +_card_change(void *data, Evas_Object *obj, void *event) +{ + E_Config_Dialog_Data *cfdata; + Evas *evas; + char *card; + + cfdata = data; + + if (cfdata->card) + evas_stringshare_del(cfdata->card); + + e_mixer_system_free_channels_names(cfdata->channels_names); + if (cfdata->channel_name) + evas_stringshare_del(cfdata->channel_name); + + card = evas_list_nth(cfdata->cards, cfdata->card_num); + cfdata->card = evas_stringshare_add(card); + _mixer_fill_channels_info(cfdata); + + evas = evas_object_evas_get(obj); + _clear_channels(cfdata); + _fill_channels(evas, cfdata); +} + +static void +_basic_create_cards(Evas *evas, E_Config_Dialog_Data *cfdata) +{ + struct mixer_config_ui_cards *ui; + Evas_List *l; + int i; + + ui = &cfdata->ui.cards; + + ui->frame = e_widget_framelist_add(evas, D_("Sound Cards"), 0); + ui->radio = e_widget_radio_group_new(&cfdata->card_num); + for (i = 0, l = cfdata->cards_names; l != NULL; l = l->next, i++) + { + Evas_Object *ow; + const char *card; + + card = l->data; + if (!card) + continue; + + ow = e_widget_radio_add(evas, card, i, ui->radio); + e_widget_framelist_object_append(ui->frame, ow); + evas_object_smart_callback_add(ow, "changed", _card_change, cfdata); + } +} + +static Evas_Object * +_basic_create(E_Config_Dialog *cfd, Evas *evas, E_Config_Dialog_Data *cfdata) +{ + if (!cfdata) + return NULL; + + cfdata->ui.table = e_widget_table_add(evas, 0); + _basic_create_general(evas, cfdata); + _basic_create_cards(evas, cfdata); + _basic_create_channels(evas, cfdata); + + e_widget_table_object_append(cfdata->ui.table, cfdata->ui.general.frame, + 0, 0, 1, 1, 1, 1, 1, 0); + e_widget_table_object_append(cfdata->ui.table, cfdata->ui.cards.frame, + 0, 1, 1, 1, 1, 1, 1, 0); + e_widget_table_object_append(cfdata->ui.table, cfdata->ui.channels.frame, + 0, 2, 1, 1, 1, 1, 1, 1); + + return cfdata->ui.table; +} + +E_Config_Dialog * +e_mixer_config_dialog_new(E_Container *con, E_Mixer_Gadget_Config *conf) +{ + E_Config_Dialog *dialog; + E_Config_Dialog_View *view; + + if (e_config_dialog_find(_Name, "e_mixer_config_dialog_new")) + return NULL; + + view = E_NEW(E_Config_Dialog_View, 1); + if (!view) + return NULL; + + view->create_cfdata = _create_data; + view->free_cfdata = _free_data; + view->basic.create_widgets = _basic_create; + view->basic.apply_cfdata = _basic_apply; + + dialog = e_config_dialog_new(con, D_("Mixer Configuration"), + _Name, "e_mixer_config_dialog_new", + e_mixer_theme_path(), 0, view, conf); + e_dialog_resizable_set(dialog->dia, 1); + + return dialog; +} diff --git a/src/modules/mixer/conf_module.c b/src/modules/mixer/conf_module.c new file mode 100644 index 000000000..80fa88306 --- /dev/null +++ b/src/modules/mixer/conf_module.c @@ -0,0 +1,192 @@ +#include "e_mod_main.h" + +extern const char _Name[]; + +struct _E_Config_Dialog_Data +{ + int default_instance; + struct mixer_config_ui + { + Evas_Object *list; + struct mixer_config_ui_general + { + Evas_Object *frame; + E_Radio_Group *radio; + } general; + } ui; +}; + +static int +_find_default_instance_index(E_Mixer_Module_Context *ctxt) +{ + Evas_List *l; + int i; + + for (i = 0, l = ctxt->instances; l != NULL; l = l->next, i++) + if (l->data == ctxt->default_instance) + return i; + + return 0; +} + +static void * +_create_data(E_Config_Dialog *dialog) +{ + E_Config_Dialog_Data *cfdata; + E_Mixer_Module_Context *ctxt; + + cfdata = E_NEW(E_Config_Dialog_Data, 1); + if (!cfdata) + return NULL; + + ctxt = dialog->data; + cfdata->default_instance = _find_default_instance_index(ctxt); + + return cfdata; +} + +static void +_free_data(E_Config_Dialog *dialog, E_Config_Dialog_Data *cfdata) +{ + E_Mixer_Module_Context *ctxt; + + ctxt = dialog->data; + if (ctxt) + ctxt->conf_dialog = NULL; + + E_FREE(cfdata); +} + +static int +_basic_apply(E_Config_Dialog *dialog, E_Config_Dialog_Data *cfdata) +{ + E_Mixer_Module_Context *ctxt; + + ctxt = dialog->data; + ctxt->default_instance = evas_list_nth(ctxt->instances, + cfdata->default_instance); + if (ctxt->default_instance) + { + E_Mixer_Module_Config *conf; + const char *id; + + conf = ctxt->conf; + if (conf->default_gc_id) + evas_stringshare_del(conf->default_gc_id); + + id = ctxt->default_instance->gcc->cf->id; + conf->default_gc_id = evas_stringshare_add(id); + } + + return 1; +} + +static void +_basic_create_general(E_Config_Dialog *dialog, Evas *evas, E_Config_Dialog_Data *cfdata) +{ + struct mixer_config_ui_general *ui; + E_Mixer_Module_Context *ctxt; + Evas_Object *label; + Evas_List *l; + int i; + + ui = &cfdata->ui.general; + ctxt = dialog->data; + + ui->frame = e_widget_framelist_add(evas, D_("General Settings"), 0); + + label = e_widget_label_add(evas, D_("Mixer to use for global actions:")); + e_widget_framelist_object_append(ui->frame, label); + + ui->radio = e_widget_radio_group_new(&cfdata->default_instance); + for (i = 0, l = ctxt->instances; l != NULL; l = l->next, i++) + { + E_Mixer_Instance *inst; + E_Mixer_Gadget_Config *conf; + Evas_Object *o; + char name[128]; + char *card_name; + + inst = l->data; + conf = inst->conf; + + card_name = e_mixer_system_get_card_name(conf->card); + snprintf(name, sizeof(name), "%s: %s", card_name, conf->channel_name); + free(card_name); + + o = e_widget_radio_add(evas, name, i, ui->radio); + e_widget_framelist_object_append(ui->frame, o); + } + + e_widget_list_object_append(cfdata->ui.list, ui->frame, 1, 1, 0.5); +} + +static void +cb_mixer_app_del(E_Dialog *dialog, void *data) +{ + E_Mixer_Module_Context *ctxt = data; + ctxt->mixer_dialog = NULL; +} + +static void +cb_mixer_call(void *data, void *data2) +{ + E_Mixer_Module_Context *ctxt = data; + E_Container *con; + + if (ctxt->mixer_dialog) + { + e_dialog_show(ctxt->mixer_dialog); + return; + } + + con = e_container_current_get(e_manager_current_get()); + ctxt->mixer_dialog = e_mixer_app_dialog_new(con, cb_mixer_app_del, ctxt); +} + +static void +_basic_create_mixer_call(E_Config_Dialog *dialog, Evas *evas, E_Config_Dialog_Data *cfdata) +{ + Evas_Object *button; + + button = e_widget_button_add(evas, D_("Launch mixer..."), NULL, + cb_mixer_call, dialog->data, NULL); + e_widget_list_object_append(cfdata->ui.list, button, 0, 0, 0.0); +} + +static Evas_Object * +_basic_create(E_Config_Dialog *dialog, Evas *evas, E_Config_Dialog_Data *cfdata) +{ + if (!cfdata) + return NULL; + + cfdata->ui.list = e_widget_list_add(evas, 0, 0); + _basic_create_general(dialog, evas, cfdata); + _basic_create_mixer_call(dialog, evas, cfdata); + return cfdata->ui.list; +} + +E_Config_Dialog * +e_mixer_config_module_dialog_new(E_Container *con, E_Mixer_Module_Context *ctxt) +{ + E_Config_Dialog *dialog; + E_Config_Dialog_View *view; + + if (e_config_dialog_find(_Name, "e_mixer_config_module_dialog_new")) + return NULL; + + view = E_NEW(E_Config_Dialog_View, 1); + if (!view) + return NULL; + + view->create_cfdata = _create_data; + view->free_cfdata = _free_data; + view->basic.create_widgets = _basic_create; + view->basic.apply_cfdata = _basic_apply; + + dialog = e_config_dialog_new(con, D_("Mixer Module Configuration"), + _Name, "e_mixer_config_module_dialog_new", + e_mixer_theme_path(), 0, view, ctxt); + + return dialog; +} diff --git a/src/modules/mixer/e-module-mixer.edj b/src/modules/mixer/e-module-mixer.edj new file mode 100644 index 0000000000000000000000000000000000000000..6b2108ab00499081da34596ba58aad66614b5bcb GIT binary patch literal 9041 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 literal 0 HcmV?d00001 diff --git a/src/modules/mixer/e_mod_main.c b/src/modules/mixer/e_mod_main.c new file mode 100644 index 000000000..035365b49 --- /dev/null +++ b/src/modules/mixer/e_mod_main.c @@ -0,0 +1,1252 @@ +#include "e_mod_main.h" +#include "e_mod_system.h" + +static E_Module *mixer_mod = NULL; +static char tmpbuf[PATH_MAX]; /* general purpose buffer, just use immediately */ + +static const char _conf_domain[] = "module.mixer"; +static const char _name[] = "mixer"; +const char _Name[] = "Mixer"; + +const char * +e_mixer_theme_path(void) +{ +#define TF "/e-module-mixer.edj" + int dirlen; + + dirlen = strlen(mixer_mod->dir); + if (dirlen >= sizeof(tmpbuf) - sizeof(TF)) + return NULL; + + memcpy(tmpbuf, mixer_mod->dir, dirlen); + memcpy(tmpbuf + dirlen, TF, sizeof(TF)); + + return tmpbuf; +#undef TF +} + +static int +_mixer_gadget_configuration_defaults(E_Mixer_Gadget_Config *conf) +{ + E_Mixer_System *sys; + char *card, *channel; + + card = e_mixer_system_get_default_card(); + if (!card) + return 0; + + sys = e_mixer_system_new(card); + if (!sys) + { + free(card); + return 0; + } + + channel = e_mixer_system_get_default_channel_name(sys); + e_mixer_system_del(sys); + + if (!channel) + { + free(card); + return 0; + } + + conf->card = evas_stringshare_add(card); + conf->channel_name = evas_stringshare_add(channel); + conf->lock_sliders = 1; + conf->show_locked = 0; + + free(card); + free(channel); + + return 1; +} + +static E_Mixer_Gadget_Config * +_mixer_gadget_configuration_new(E_Mixer_Module_Config *mod_conf, const char *id) +{ + E_Mixer_Gadget_Config *conf; + + conf = E_NEW(E_Mixer_Gadget_Config, 1); + if (!conf) + return NULL; + + if (!_mixer_gadget_configuration_defaults(conf)) + { + E_FREE(conf); + return NULL; + } + + conf->id = evas_stringshare_add(id); + mod_conf->gadgets = evas_hash_direct_add(mod_conf->gadgets, conf->id, conf); + + return conf; +} + +static inline void +_mixer_gadget_configuration_free_int(E_Mixer_Gadget_Config *conf) +{ + if (conf->dialog) + e_object_del(E_OBJECT(conf->dialog)); + + if (conf->card) + evas_stringshare_del(conf->card); + if (conf->channel_name) + evas_stringshare_del(conf->channel_name); + + evas_stringshare_del(conf->id); + free(conf); +} + +static void +_mixer_gadget_configuration_free(E_Mixer_Module_Config *mod_conf, E_Mixer_Gadget_Config *conf) +{ + if (!mod_conf) + return; + if (!conf) + return; + mod_conf->gadgets = evas_hash_del(mod_conf->gadgets, conf->id, conf); + _mixer_gadget_configuration_free_int(conf); +} + +static Evas_Bool +_mixer_gadget_configuration_free_foreach(const Evas_Hash *hash, const char *key, void *hdata, void *fdata) +{ + _mixer_gadget_configuration_free_int(hdata); + return 1; +} + +static int +_mixer_module_configuration_alert(void *data) +{ + e_util_dialog_show(D_("Mixer Configuration Updated"), data); + return 0; +} + +static E_Mixer_Module_Config * +_mixer_module_configuration_new(void) +{ + E_Mixer_Module_Config *conf; + + conf = E_NEW(E_Mixer_Module_Config, 1); + if (!conf) + return NULL; + + conf->version = MOD_CONF_VERSION; + + return conf; +} + +static void +_mixer_module_configuration_free(E_Mixer_Module_Config *conf) +{ + if (!conf) + return; + + evas_hash_foreach(conf->gadgets, + _mixer_gadget_configuration_free_foreach, NULL); + evas_hash_free(conf->gadgets); + free(conf); +} + +static void +_mixer_popup_update(E_Mixer_Instance *inst) +{ + E_Mixer_Channel_State *state; + + state = &inst->mixer_state; + + if (inst->ui.left) + e_slider_value_set(inst->ui.left, state->left); + if (inst->ui.right) + e_slider_value_set(inst->ui.right, state->right); + if (inst->ui.mute) + e_widget_check_checked_set(inst->ui.mute, state->mute); +} + +static void +_mixer_gadget_update(E_Mixer_Instance *inst) +{ + Edje_Message_Int_Set *msg; + + if (!inst) + return; + + e_mixer_system_get_state(inst->sys, inst->channel, &inst->mixer_state); + + msg = alloca(sizeof(Edje_Message_Int_Set) + 2 * sizeof(int)); + msg->count = 3; + msg->val[0] = inst->mixer_state.mute; + msg->val[1] = inst->mixer_state.left; + msg->val[2] = inst->mixer_state.right; + edje_object_message_send(inst->ui.gadget, EDJE_MESSAGE_INT_SET, 0, msg); + + edje_object_signal_emit(inst->ui.gadget, "e,action,volume,change", ""); + + if (inst->popup) + _mixer_popup_update(inst); +} + +static void +_mixer_volume_increase(E_Mixer_Instance *inst) +{ + E_Mixer_Channel_State *state; + + state = &inst->mixer_state; + e_mixer_system_get_volume(inst->sys, inst->channel, + &state->left, &state->right); + if (state->left >= 0) + { + if (state->left < 95) + state->left += 5; + else + state->left = 100; + } + + if (state->right >= 0) + { + if (state->right < 95) + state->right += 5; + else + state->right = 100; + } + + e_mixer_system_set_volume(inst->sys, inst->channel, + state->left, state->right); + _mixer_gadget_update(inst); +} + +static void +_mixer_volume_decrease(E_Mixer_Instance *inst) +{ + E_Mixer_Channel_State *state; + + state = &inst->mixer_state; + e_mixer_system_get_volume(inst->sys, inst->channel, + &state->left, &state->right); + if (state->left >= 0) + { + if (state->left > 5) + state->left -= 5; + else + state->left = 0; + } + if (state->right >= 0) + { + if (state->right > 5) + state->right -= 5; + else + state->right = 0; + } + + e_mixer_system_set_volume(inst->sys, inst->channel, + state->left, state->right); + _mixer_gadget_update(inst); +} + +static void +_mixer_toggle_mute(E_Mixer_Instance *inst) +{ + E_Mixer_Channel_State *state; + + if (!e_mixer_system_can_mute(inst->sys, inst->channel)) + return; + + state = &inst->mixer_state; + e_mixer_system_get_mute(inst->sys, inst->channel, &state->mute); + state->mute = !state->mute; + e_mixer_system_set_mute(inst->sys, inst->channel, state->mute); + _mixer_gadget_update(inst); +} + +static void +_mixer_popup_cb_volume_left_change(void *data, Evas_Object *obj, void *event) +{ + E_Mixer_Instance *inst; + E_Mixer_Channel_State *state; + + inst = data; + if (!inst) + return; + + state = &inst->mixer_state; + e_mixer_system_get_volume(inst->sys, inst->channel, + &state->left, &state->right); + + state->left = (int)e_slider_value_get(obj); + if (inst->conf->lock_sliders) + { + state->right = state->left; + e_slider_value_set(inst->ui.right, state->right); + } + + e_mixer_system_set_volume(inst->sys, inst->channel, + state->left, state->right); + _mixer_gadget_update(inst); +} + +static void +_mixer_popup_cb_volume_right_change(void *data, Evas_Object *obj, void *event) +{ + E_Mixer_Instance *inst; + E_Mixer_Channel_State *state; + + inst = data; + if (!inst) + return; + + state = &inst->mixer_state; + e_mixer_system_get_volume(inst->sys, inst->channel, + &state->left, &state->right); + + state->right = (int)e_slider_value_get(obj); + if (inst->conf->lock_sliders) + { + state->left = state->right; + e_slider_value_set(inst->ui.left, state->left); + } + + e_mixer_system_set_volume(inst->sys, inst->channel, + state->left, state->right); + _mixer_gadget_update(inst); +} + +static void +_mixer_popup_cb_mute_change(void *data, Evas_Object *obj, void *event) +{ + E_Mixer_Instance *inst; + E_Mixer_Channel_State *state; + + inst = data; + if (!inst) + return; + + state = &inst->mixer_state; + state->mute = e_widget_check_checked_get(obj); + e_mixer_system_set_mute(inst->sys, inst->channel, state->mute); + + _mixer_gadget_update(inst); +} + +static void +_mixer_popup_cb_resize(Evas_Object *obj, int *w, int *h) +{ + int mw, mh; + + e_widget_min_size_get(obj, &mw, &mh); + if (mh < 200) mh = 200; + if (mw < 60) mw = 60; + if (*w) *w = (mw + 8); + if (*h) *h = (mh + 8); +} + +static Evas_Object * +_mixer_popup_add_slider(E_Mixer_Instance *inst, int value, void (*cb) (void *data, Evas_Object *obj, void *event_info)) +{ + Evas_Object *slider; + + slider = e_slider_add(inst->popup->win->evas); + evas_object_show(slider); + e_slider_orientation_set(slider, 0); + e_slider_value_set(slider, value); + e_slider_value_range_set(slider, 0.0, 100.0); + e_slider_value_format_display_set(slider, NULL); + evas_object_smart_callback_add(slider, "changed", cb, inst); + + return slider; +} + +static void +_mixer_app_cb_del(E_Dialog *dialog, void *data) +{ + E_Mixer_Module_Context *ctxt = data; + ctxt->mixer_dialog = NULL; +} + +static void _mixer_popup_del(E_Mixer_Instance *inst); + +static int +_mixer_popup_input_window_mouse_up_cb(void *data, int type, void *event) +{ + Ecore_X_Event_Mouse_Button_Up *ev = event; + E_Mixer_Instance *inst = data; + + if (ev->win != inst->ui.input.win) + return 1; + + _mixer_popup_del(inst); + + return 1; +} + +static int +_mixer_popup_input_window_key_down_cb(void *data, int type, void *event) +{ + Ecore_X_Event_Key_Down *ev = event; + E_Mixer_Instance *inst = data; + const char *keysym; + + if (ev->win != inst->ui.input.win) + return 1; + + keysym = ev->keysymbol; + if (strcmp(keysym, "Escape") == 0) + _mixer_popup_del(inst); + else if (strcmp(keysym, "Up") == 0) + _mixer_volume_increase(inst); + else if (strcmp(keysym, "Down") == 0) + _mixer_volume_decrease(inst); + else if ((strcmp(keysym, "Return") == 0) || + (strcmp(keysym, "KP_Enter") == 0)) + _mixer_toggle_mute(inst); + else + _mixer_popup_del(inst); /* XXX really? */ + + return 1; +} + +static void +_mixer_popup_input_window_destroy(E_Mixer_Instance *inst) +{ + ecore_x_window_del(inst->ui.input.win); + inst->ui.input.win = 0; + + ecore_event_handler_del(inst->ui.input.mouse_up); + inst->ui.input.mouse_up = NULL; + + ecore_event_handler_del(inst->ui.input.key_down); + inst->ui.input.key_down = NULL; +} + +static void +_mixer_popup_input_window_create(E_Mixer_Instance *inst) +{ + Ecore_X_Window_Configure_Mask mask; + Ecore_X_Window w, popup_w; + E_Manager *man; + + man = e_manager_current_get(); + + w = ecore_x_window_input_new(man->root, 0, 0, man->w, man->h); + mask = (ECORE_X_WINDOW_CONFIGURE_MASK_STACK_MODE | + ECORE_X_WINDOW_CONFIGURE_MASK_SIBLING); + popup_w = inst->popup->win->evas_win; + ecore_x_window_configure(w, mask, 0, 0, 0, 0, 0, popup_w, + ECORE_X_WINDOW_STACK_BELOW); + ecore_x_window_show(w); + + inst->ui.input.mouse_up = + ecore_event_handler_add(ECORE_X_EVENT_MOUSE_BUTTON_UP, + _mixer_popup_input_window_mouse_up_cb, inst); + + inst->ui.input.key_down = + ecore_event_handler_add(ECORE_X_EVENT_KEY_DOWN, + _mixer_popup_input_window_key_down_cb, inst); + + inst->ui.input.win = w; +} + +static void +_mixer_popup_del(E_Mixer_Instance *inst) +{ + _mixer_popup_input_window_destroy(inst); + e_object_del(E_OBJECT(inst->popup)); + inst->ui.label = NULL; + inst->ui.left = NULL; + inst->ui.right = NULL; + inst->ui.mute = NULL; + inst->ui.table = NULL; + inst->ui.button = NULL; + inst->popup = NULL; +} + +static void +_mixer_app_select_current(E_Dialog *dialog, E_Mixer_Instance *inst) +{ + E_Mixer_Gadget_Config *conf = inst->conf; + + e_mixer_app_dialog_select(dialog, conf->card, conf->channel_name); +} + + +static void +_mixer_popup_cb_mixer(void *data, void *data2) +{ + E_Mixer_Instance *inst = data; + E_Mixer_Module_Context *ctxt; + E_Container *con; + + _mixer_popup_del(inst); + + ctxt = mixer_mod->data; + if (ctxt->mixer_dialog) + { + _mixer_app_select_current(ctxt->mixer_dialog, inst); + e_dialog_show(ctxt->mixer_dialog); + return; + } + + con = e_container_current_get(e_manager_current_get()); + ctxt->mixer_dialog = e_mixer_app_dialog_new( + con, _mixer_app_cb_del, ctxt); + + _mixer_app_select_current(ctxt->mixer_dialog, inst); +} + +static void +_mixer_popup_new(E_Mixer_Instance *inst) +{ + E_Mixer_Channel_State *state; + Evas *evas; + int colspan; + + if (inst->conf->dialog) + return; + + state = &inst->mixer_state; + e_mixer_system_get_state(inst->sys, inst->channel, state); + + if ((state->right >= 0) && + (inst->conf->show_locked || (!inst->conf->lock_sliders))) + colspan = 2; + else + colspan = 1; + + inst->popup = e_gadcon_popup_new(inst->gcc, _mixer_popup_cb_resize); + evas = inst->popup->win->evas; + + inst->ui.table = e_widget_table_add(evas, 0); + + inst->ui.label = e_widget_label_add(evas, inst->conf->channel_name); + e_widget_table_object_append(inst->ui.table, inst->ui.label, + 0, 0, colspan, 1, 0, 0, 0, 0); + + if (state->left >= 0) + { + inst->ui.left = _mixer_popup_add_slider( + inst, state->left, _mixer_popup_cb_volume_left_change); + e_widget_table_object_append(inst->ui.table, inst->ui.left, + 0, 1, 1, 1, 1, 1, 1, 1); + } + else + inst->ui.left = NULL; + + if ((state->right >= 0) && + (inst->conf->show_locked || (!inst->conf->lock_sliders))) + { + inst->ui.right = _mixer_popup_add_slider( + inst, state->right, _mixer_popup_cb_volume_right_change); + e_widget_table_object_append(inst->ui.table, inst->ui.right, + 1, 1, 1, 1, 1, 1, 1, 1); + } + else + inst->ui.right = NULL; + + if (e_mixer_system_can_mute(inst->sys, inst->channel)) + { + inst->ui.mute = e_widget_check_add(evas, D_("Mute"), &state->mute); + evas_object_show(inst->ui.mute); + e_widget_table_object_append(inst->ui.table, inst->ui.mute, + 0, 2, colspan, 1, 1, 1, 1, 0); + evas_object_smart_callback_add(inst->ui.mute, "changed", + _mixer_popup_cb_mute_change, inst); + } + else + inst->ui.mute = NULL; + + inst->ui.button = e_widget_button_add(evas, D_(_Name), NULL, + _mixer_popup_cb_mixer, inst, NULL); + e_widget_table_object_append(inst->ui.table, inst->ui.button, + 0, 7, colspan, 1, 1, 1, 1, 0); + + e_gadcon_popup_content_set(inst->popup, inst->ui.table); + e_gadcon_popup_show(inst->popup); + _mixer_popup_input_window_create(inst); +} + +static void +_mixer_menu_cb_post(void *data, E_Menu *menu) +{ + E_Mixer_Instance *inst; + + inst = data; + if ((!inst) || (!inst->menu)) + return; + if (inst->menu) + { + e_object_del(E_OBJECT(inst->menu)); + inst->menu = NULL; + } +} + +static void +_mixer_menu_cb_cfg(void *data, E_Menu *menu, E_Menu_Item *mi) +{ + E_Mixer_Instance *inst; + E_Container *con; + + inst = data; + if (!inst) + return; + if (inst->popup) + _mixer_popup_del(inst); + con = e_container_current_get(e_manager_current_get()); + inst->conf->dialog = e_mixer_config_dialog_new(con, inst->conf); +} + +static void +_mixer_menu_new(E_Mixer_Instance *inst, Evas_Event_Mouse_Down *ev) +{ + E_Zone *zone; + E_Menu *mn; + E_Menu_Item *mi; + int x, y; + + zone = e_util_zone_current_get(e_manager_current_get()); + + mn = e_menu_new(); + e_menu_post_deactivate_callback_set(mn, _mixer_menu_cb_post, inst); + inst->menu = mn; + + mi = e_menu_item_new(mn); + e_menu_item_label_set(mi, D_("Configuration")); + e_util_menu_item_edje_icon_set(mi, "enlightenment/configuration"); + e_menu_item_callback_set(mi, _mixer_menu_cb_cfg, inst); + + e_gadcon_client_util_menu_items_append(inst->gcc, mn, 0); + e_gadcon_canvas_zone_geometry_get(inst->gcc->gadcon, &x, &y, NULL, NULL); + e_menu_activate_mouse(mn, zone, x + ev->output.x, y + ev->output.y, + 1, 1, E_MENU_POP_DIRECTION_AUTO, ev->timestamp); + evas_event_feed_mouse_up(inst->gcc->gadcon->evas, ev->button, + EVAS_BUTTON_NONE, ev->timestamp, NULL); +} + +static void +_mixer_cb_mouse_down(void *data, Evas *evas, Evas_Object *obj, void *event) +{ + E_Mixer_Instance *inst; + Evas_Event_Mouse_Down *ev; + + inst = data; + if (!inst) + return; + + ev = event; + if (ev->button == 1) + { + if (!inst->popup) + _mixer_popup_new(inst); + else + _mixer_popup_del(inst); + } + else if (ev->button == 2) + _mixer_toggle_mute(inst); + else if ((ev->button == 3) && (!inst->menu)) + _mixer_menu_new(inst, ev); +} + +static void +_mixer_cb_mouse_wheel(void *data, Evas *evas, Evas_Object *obj, void *event) +{ + E_Mixer_Instance *inst; + Evas_Event_Mouse_Wheel *ev; + + inst = data; + if (!inst) + return; + + ev = event; + if (ev->direction == 0) + { + if (ev->z > 0) + _mixer_volume_decrease(inst); + else if (ev->z < 0) + _mixer_volume_increase(inst); + } +} + +static int +_mixer_sys_setup(E_Mixer_Instance *inst) +{ + E_Mixer_Gadget_Config *conf; + + conf = inst->conf; + + if (inst->sys) + e_mixer_system_del(inst->sys); + + inst->sys = e_mixer_system_new(conf->card); + if (!inst->sys) + { + inst->channel = NULL; + return 0; + } + + inst->channel = e_mixer_system_get_channel_by_name(inst->sys, + conf->channel_name); + return inst->channel != NULL; +} + +static int +_mixer_system_cb_update(void *data, E_Mixer_System *sys) +{ + E_Mixer_Instance *inst; + + inst = data; + e_mixer_system_get_state(inst->sys, inst->channel, &inst->mixer_state); + _mixer_gadget_update(inst); + + return 1; +} + +int +e_mixer_update(E_Mixer_Instance *inst) +{ + int r; + + e_modapi_save(mixer_mod); + if ((!inst) || (!inst->conf)) + return 0; + + r = _mixer_sys_setup(inst); + if (r) + e_mixer_system_callback_set(inst->sys, _mixer_system_cb_update, inst); + + return r; +} + +static int +_mixer_sys_setup_default_card(E_Mixer_Instance *inst) +{ + E_Mixer_Gadget_Config *conf; + char *card; + + conf = inst->conf; + if (conf->card) + evas_stringshare_del(conf->card); + + card = e_mixer_system_get_default_card(); + if (!card) + goto error; + + inst->sys = e_mixer_system_new(card); + if (!inst->sys) + goto system_error; + + conf->card = evas_stringshare_add(card); + free(card); + return 1; + + + system_error: + free(card); + error: + conf->card = NULL; + return 0; +} + +static int +_mixer_sys_setup_default_channel(E_Mixer_Instance *inst) +{ + E_Mixer_Gadget_Config *conf; + char *channel_name; + + conf = inst->conf; + if (conf->channel_name) + evas_stringshare_del(conf->channel_name); + + channel_name = e_mixer_system_get_default_channel_name(inst->sys); + if (!channel_name) + goto error; + + inst->channel = e_mixer_system_get_channel_by_name(inst->sys, channel_name); + if (!inst->channel) + goto system_error; + + conf->channel_name = evas_stringshare_add(channel_name); + free(channel_name); + return 1; + + system_error: + free(channel_name); + error: + conf->channel_name = NULL; + return 0; +} + +static int +_mixer_sys_setup_defaults(E_Mixer_Instance *inst) +{ + if ((!inst->sys) && (!_mixer_sys_setup_default_card(inst))) + return 0; + + return _mixer_sys_setup_default_channel(inst); +} + +/* Gadcon Api Functions */ +static void _mixer_module_configuration_setup(E_Mixer_Module_Context *ctxt); + +static E_Gadcon_Client * +_gc_init(E_Gadcon *gc, const char *name, const char *id, const char *style) +{ + E_Mixer_Instance *inst; + E_Mixer_Module_Context *ctxt; + E_Mixer_Gadget_Config *conf; + + if (!mixer_mod) + return NULL; + + ctxt = mixer_mod->data; + if (!ctxt->conf) + { + _mixer_module_configuration_setup(ctxt); + if (!ctxt->conf) + return NULL; + } + + conf = evas_hash_find(ctxt->conf->gadgets, id); + if (!conf) + { + conf = _mixer_gadget_configuration_new(ctxt->conf, id); + if (!conf) + return NULL; + } + + inst = E_NEW(E_Mixer_Instance, 1); + inst->conf = conf; + conf->instance = inst; + if ((!_mixer_sys_setup(inst)) && (!_mixer_sys_setup_defaults(inst))) + { + if (inst->sys) + e_mixer_system_del(inst->sys); + _mixer_gadget_configuration_free(ctxt->conf, conf); + E_FREE(inst); + return NULL; + } + e_mixer_system_callback_set(inst->sys, _mixer_system_cb_update, inst); + + inst->ui.gadget = edje_object_add(gc->evas); + if (!e_theme_edje_object_set(inst->ui.gadget, "base/theme/modules/mixer", + "e/modules/mixer/main")) + edje_object_file_set(inst->ui.gadget, e_mixer_theme_path(), + "e/modules/mixer/main"); + + inst->gcc = e_gadcon_client_new(gc, name, id, style, inst->ui.gadget); + inst->gcc->data = inst; + + evas_object_event_callback_add(inst->ui.gadget, EVAS_CALLBACK_MOUSE_DOWN, + _mixer_cb_mouse_down, inst); + evas_object_event_callback_add(inst->ui.gadget, EVAS_CALLBACK_MOUSE_WHEEL, + _mixer_cb_mouse_wheel, inst); + + e_mixer_system_get_state(inst->sys, inst->channel, &inst->mixer_state); + _mixer_gadget_update(inst); + + if (!ctxt->conf->default_gc_id) + { + ctxt->conf->default_gc_id = evas_stringshare_add(id); + ctxt->default_instance = inst; + } + else if ((!ctxt->default_instance) || + (strcmp(id, ctxt->conf->default_gc_id) == 0)) + ctxt->default_instance = inst; + + ctxt->instances = evas_list_append(ctxt->instances, inst); + + return inst->gcc; +} + +static void +_gc_shutdown(E_Gadcon_Client *gcc) +{ + E_Mixer_Module_Context *ctxt; + E_Mixer_Instance *inst; + + if (!mixer_mod) + return; + + ctxt = mixer_mod->data; + if (!ctxt) + return; + + inst = gcc->data; + if (!inst) + return; + + if (inst->menu) + { + e_menu_post_deactivate_callback_set(inst->menu, NULL, NULL); + e_object_del(E_OBJECT(inst->menu)); + } + evas_object_del(inst->ui.gadget); + e_mixer_system_channel_del(inst->channel); + e_mixer_system_del(inst->sys); + + inst->conf->instance = NULL; + ctxt->instances = evas_list_remove(ctxt->instances, inst); + + E_FREE(inst); +} + +static void +_gc_orient(E_Gadcon_Client *gcc) +{ + e_gadcon_client_aspect_set(gcc, 16, 16); + e_gadcon_client_min_size_set(gcc, 16, 16); +} + +static char * +_gc_label(void) +{ + return D_(_Name); +} + +static Evas_Object * +_gc_icon(Evas *evas) +{ + Evas_Object *o; + + o = edje_object_add(evas); + edje_object_file_set(o, e_mixer_theme_path(), "icon"); + return o; +} + +static const char * +_gc_id_new(void) +{ + E_Mixer_Module_Context *ctxt; + Evas_List *instances; + + if (!mixer_mod) + return NULL; + + ctxt = mixer_mod->data; + if (!ctxt) + return NULL; + + instances = ctxt->instances; + snprintf(tmpbuf, sizeof(tmpbuf), "mixer.%d", evas_list_count(instances)); + return tmpbuf; +} + +static const E_Gadcon_Client_Class _gc_class = +{ + GADCON_CLIENT_CLASS_VERSION, _name, + {_gc_init, _gc_shutdown, _gc_orient, _gc_label, _gc_icon, _gc_id_new, NULL}, + E_GADCON_CLIENT_STYLE_PLAIN +}; + + + +EAPI E_Module_Api e_modapi = {E_MODULE_API_VERSION, _Name}; + +static void +_mixer_cb_volume_increase(E_Object *obj, const char *params) +{ + E_Mixer_Module_Context *ctxt; + + if (!mixer_mod) + return; + + ctxt = mixer_mod->data; + if (!ctxt->conf) + return; + + if (ctxt->default_instance) + _mixer_volume_increase(ctxt->default_instance); +} + +static void +_mixer_cb_volume_decrease(E_Object *obj, const char *params) +{ + E_Mixer_Module_Context *ctxt; + + if (!mixer_mod) + return; + + ctxt = mixer_mod->data; + if (!ctxt->conf) + return; + + if (ctxt->default_instance) + _mixer_volume_decrease(ctxt->default_instance); +} + +static void +_mixer_cb_volume_mute(E_Object *obj, const char *params) +{ + E_Mixer_Module_Context *ctxt; + + if (!mixer_mod) + return; + + ctxt = mixer_mod->data; + if (!ctxt->conf) + return; + + if (ctxt->default_instance) + _mixer_toggle_mute(ctxt->default_instance); +} + +static E_Config_Dialog * +_mixer_module_config(E_Container *con, const char *params __UNUSED__) +{ + E_Mixer_Module_Context *ctxt; + + if (!mixer_mod) + return NULL; + + ctxt = mixer_mod->data; + if (!ctxt) + return NULL; + + if (ctxt->conf_dialog) + return NULL; + + if (!ctxt->conf) + { + _mixer_module_configuration_setup(ctxt); + if (!ctxt->conf) + return NULL; + } + + ctxt->conf_dialog = e_mixer_config_module_dialog_new(con, ctxt); + return ctxt->conf_dialog; +} + +static const char _reg_cat[] = "extensions"; +static const char _reg_item[] = "extensions/e"; + +static void +_mixer_configure_registry_register(void) +{ + e_configure_registry_category_add(_reg_cat, 90, D_("Extensions"), NULL, + "enlightenment/extensions"); + e_configure_registry_item_add(_reg_item, 30, D_(_Name), NULL, + "enlightenment/e", + _mixer_module_config); +} + +static void +_mixer_configure_registry_unregister(void) +{ + e_configure_registry_item_del(_reg_item); + e_configure_registry_category_del(_reg_cat); +} + +static E_Config_DD * +_mixer_module_configuration_descriptor_new(E_Config_DD *gadget_conf_edd) +{ + E_Config_DD *conf_edd; + + conf_edd = E_CONFIG_DD_NEW("Mixer_Module_Config", E_Mixer_Module_Config); + if (!conf_edd) + return NULL; + E_CONFIG_VAL(conf_edd, E_Mixer_Module_Config, version, INT); + E_CONFIG_VAL(conf_edd, E_Mixer_Module_Config, default_gc_id, STR); + E_CONFIG_HASH(conf_edd, E_Mixer_Module_Config, gadgets, gadget_conf_edd); + + return conf_edd; +} + +static inline void +_mixer_module_configuration_descriptor_free(E_Config_DD *conf_edd) +{ + if (!conf_edd) + return; + E_CONFIG_DD_FREE(conf_edd); +} + +static E_Config_DD * +_mixer_gadget_configuration_descriptor_new(void) +{ + E_Config_DD *conf_edd; + + conf_edd = E_CONFIG_DD_NEW("Mixer_Gadget_Config", E_Mixer_Gadget_Config); + if (!conf_edd) + return NULL; + E_CONFIG_VAL(conf_edd, E_Mixer_Gadget_Config, lock_sliders, INT); + E_CONFIG_VAL(conf_edd, E_Mixer_Gadget_Config, show_locked, INT); + E_CONFIG_VAL(conf_edd, E_Mixer_Gadget_Config, card, STR); + E_CONFIG_VAL(conf_edd, E_Mixer_Gadget_Config, channel_name, STR); + + return conf_edd; +} + +static inline void +_mixer_gadget_configuration_descriptor_free(E_Config_DD *conf_edd) +{ + if (!conf_edd) + return; + E_CONFIG_DD_FREE(conf_edd); +} + +static E_Mixer_Module_Config * +_mixer_module_configuration_load(E_Config_DD *module_conf_edd) +{ + E_Mixer_Module_Config *conf; + + conf = e_config_domain_load(_conf_domain, module_conf_edd); + if (!conf) + return _mixer_module_configuration_new(); + + if (conf->version != MOD_CONF_VERSION) + { + _mixer_module_configuration_free(conf); + conf = _mixer_module_configuration_new(); + if (!conf) + return NULL; + + ecore_timer_add(1.0, _mixer_module_configuration_alert, + D_("Mixer Module Configuration data changed.
" + "Your old configuration has been replaced with " + "new default.
Sorry for the inconvenience.")); + return conf; + } + + return conf; +} + +static void +_mixer_module_configuration_setup(E_Mixer_Module_Context *ctxt) +{ + E_Config_DD *module_edd, *gadget_edd; + + gadget_edd = _mixer_gadget_configuration_descriptor_new(); + module_edd = _mixer_module_configuration_descriptor_new(gadget_edd); + ctxt->gadget_conf_edd = gadget_edd; + ctxt->module_conf_edd = module_edd; + ctxt->conf = _mixer_module_configuration_load(module_edd); +} + +static const char _act_increase[] = "volume_increase"; +static const char _act_decrease[] = "volume_decrease"; +static const char _act_mute[] = "volume_mute"; +static const char _lbl_increase[] = "Increase Volume"; +static const char _lbl_decrease[] = "Decrease Volume"; +static const char _lbl_mute[] = "Mute Volume"; + +static void +_mixer_actions_register(E_Mixer_Module_Context *ctxt) +{ + ctxt->actions.incr = e_action_add(_act_increase); + if (ctxt->actions.incr) + { + ctxt->actions.incr->func.go = _mixer_cb_volume_increase; + e_action_predef_name_set(D_(_Name), D_(_lbl_increase), _act_increase, + NULL, NULL, 0); + } + + ctxt->actions.decr = e_action_add(_act_decrease); + if (ctxt->actions.decr) + { + ctxt->actions.decr->func.go = _mixer_cb_volume_decrease; + e_action_predef_name_set(D_(_Name), D_(_lbl_decrease), _act_decrease, + NULL, NULL, 0); + } + + ctxt->actions.mute = e_action_add(_act_mute); + if (ctxt->actions.mute) + { + ctxt->actions.mute->func.go = _mixer_cb_volume_mute; + e_action_predef_name_set(D_(_Name), D_(_lbl_mute), _act_mute, + NULL, NULL, 0); + } +} + +static void +_mixer_actions_unregister(E_Mixer_Module_Context *ctxt) +{ + if (ctxt->actions.incr) + { + e_action_predef_name_del(D_(_Name), D_(_lbl_increase)); + e_action_del(_act_increase); + } + + if (ctxt->actions.decr) + { + e_action_predef_name_del(D_(_Name), D_(_lbl_decrease)); + e_action_del(_act_decrease); + } + + if (ctxt->actions.mute) + { + e_action_predef_name_del(D_(_Name), D_(_lbl_mute)); + e_action_del(_act_mute); + } +} + +EAPI void * +e_modapi_init(E_Module *m) +{ + E_Mixer_Module_Context *ctxt; + + ctxt = E_NEW(E_Mixer_Module_Context, 1); + if (!ctxt) + return NULL; + + _mixer_configure_registry_register(); + _mixer_actions_register(ctxt); + e_gadcon_provider_register(&_gc_class); + mixer_mod = m; + return ctxt; +} + +static void +_mixer_instances_free(E_Mixer_Module_Context *ctxt) +{ + while (ctxt->instances) + { + E_Mixer_Instance *inst; + + inst = ctxt->instances->data; + e_object_del(E_OBJECT(inst->gcc)); + } +} + +EAPI int +e_modapi_shutdown(E_Module *m) +{ + E_Mixer_Module_Context *ctxt; + + ctxt = m->data; + if (!ctxt) + return 0; + + _mixer_instances_free(ctxt); + + if (ctxt->conf_dialog) + e_object_del(E_OBJECT(ctxt->conf_dialog)); + + if (ctxt->mixer_dialog) + e_object_del(E_OBJECT(ctxt->mixer_dialog)); + + _mixer_configure_registry_unregister(); + _mixer_actions_unregister(ctxt); + e_gadcon_provider_unregister(&_gc_class); + + if (ctxt->conf) + { + _mixer_module_configuration_free(ctxt->conf); + _mixer_gadget_configuration_descriptor_free(ctxt->gadget_conf_edd); + _mixer_module_configuration_descriptor_free(ctxt->module_conf_edd); + } + + E_FREE(ctxt); + mixer_mod = NULL; + return 1; +} + +EAPI int +e_modapi_save(E_Module *m) +{ + E_Mixer_Module_Context *ctxt; + + ctxt = m->data; + if (!ctxt) + return 0; + if (!ctxt->conf) + return 1; + + return e_config_domain_save(_conf_domain, ctxt->module_conf_edd, ctxt->conf); +} diff --git a/src/modules/mixer/e_mod_main.h b/src/modules/mixer/e_mod_main.h new file mode 100644 index 000000000..5bc2f022c --- /dev/null +++ b/src/modules/mixer/e_mod_main.h @@ -0,0 +1,89 @@ +#define D_(str) dgettext(PACKAGE, str) + +#ifndef E_MOD_MAIN_H +#define E_MOD_MAIN_H + +#include "config.h" +#include "e_mod_system.h" +#include + +#define MOD_CONF_VERSION 3 + +typedef struct E_Mixer_Gadget_Config +{ + int lock_sliders; + int show_locked; + const char *card; + const char *channel_name; + const char *id; + E_Config_Dialog *dialog; + struct E_Mixer_Instance *instance; +} E_Mixer_Gadget_Config; + +typedef struct E_Mixer_Module_Config +{ + int version; + const char *default_gc_id; + Evas_Hash *gadgets; +} E_Mixer_Module_Config; + +typedef struct E_Mixer_Instance +{ + E_Gadcon_Client *gcc; + E_Gadcon_Popup *popup; + E_Menu *menu; + + struct + { + Evas_Object *gadget; + Evas_Object *label; + Evas_Object *left; + Evas_Object *right; + Evas_Object *mute; + Evas_Object *table; + Evas_Object *button; + struct + { + Ecore_X_Window win; + Ecore_Event_Handler *mouse_up; + Ecore_Event_Handler *key_down; + } input; + } ui; + + E_Mixer_System *sys; + E_Mixer_Channel *channel; + E_Mixer_Channel_State mixer_state; + E_Mixer_Gadget_Config *conf; +} E_Mixer_Instance; + +typedef struct E_Mixer_Module_Context +{ + E_Config_DD *module_conf_edd; + E_Config_DD *gadget_conf_edd; + E_Mixer_Module_Config *conf; + E_Config_Dialog *conf_dialog; + E_Mixer_Instance *default_instance; + Evas_List *instances; + E_Dialog *mixer_dialog; + struct st_mixer_actions + { + E_Action *incr; + E_Action *decr; + E_Action *mute; + } actions; +} E_Mixer_Module_Context; + +EAPI extern E_Module_Api e_modapi; +EAPI void *e_modapi_init(E_Module *m); +EAPI int e_modapi_shutdown(E_Module *m); +EAPI int e_modapi_save(E_Module *m); + +E_Config_Dialog *e_mixer_config_module_dialog_new(E_Container *con, E_Mixer_Module_Context *ctxt); +E_Config_Dialog *e_mixer_config_dialog_new(E_Container *con, E_Mixer_Gadget_Config *conf); +E_Dialog *e_mixer_app_dialog_new(E_Container *con, void (*func)(E_Dialog *dialog, void *data), void *data); +int e_mixer_app_dialog_select(E_Dialog *dialog, const char *card_name, const char *channel_name); + +int e_mixer_update(E_Mixer_Instance *inst); +const char *e_mixer_theme_path(void); + +#endif diff --git a/src/modules/mixer/e_mod_system.h b/src/modules/mixer/e_mod_system.h new file mode 100644 index 000000000..e65566115 --- /dev/null +++ b/src/modules/mixer/e_mod_system.h @@ -0,0 +1,48 @@ +#ifndef E_MOD_SYSTEM_H +#define E_MOD_SYSTEM_H + +#include + +typedef void E_Mixer_System; +typedef void E_Mixer_Channel; + +struct E_Mixer_Channel_State +{ + int mute; + int left; + int right; +}; +typedef struct E_Mixer_Channel_State E_Mixer_Channel_State; + +Evas_List *e_mixer_system_get_cards(void); +void e_mixer_system_free_cards(Evas_List *cards); +char *e_mixer_system_get_default_card(void); +char *e_mixer_system_get_card_name(const char *card); + + +E_Mixer_System *e_mixer_system_new(const char *card); +void e_mixer_system_del(E_Mixer_System *self); + +int e_mixer_system_callback_set(E_Mixer_System *self, int (*func)(void *data, E_Mixer_System *self), void *data); + +Evas_List *e_mixer_system_get_channels(E_Mixer_System *self); +void e_mixer_system_free_channels(Evas_List *channels); +Evas_List *e_mixer_system_get_channels_names(E_Mixer_System *self); +void e_mixer_system_free_channels_names(Evas_List *channels_names); +char *e_mixer_system_get_default_channel_name(E_Mixer_System *self); +E_Mixer_Channel *e_mixer_system_get_channel_by_name(E_Mixer_System *self, const char *name); +char *e_mixer_system_get_channel_name(E_Mixer_System *self, E_Mixer_Channel *channel); +void e_mixer_system_channel_del(E_Mixer_Channel *channel); + + +int e_mixer_system_get_state(E_Mixer_System *self, E_Mixer_Channel *channel, E_Mixer_Channel_State *state); +int e_mixer_system_set_state(E_Mixer_System *self, E_Mixer_Channel *channel, const E_Mixer_Channel_State *state); +int e_mixer_system_get_volume(E_Mixer_System *self, E_Mixer_Channel *channel, int *left, int *right); +int e_mixer_system_set_volume(E_Mixer_System *self, E_Mixer_Channel *channel, int left, int right); +int e_mixer_system_get_mute(E_Mixer_System *self, E_Mixer_Channel *channel, int *mute); +int e_mixer_system_set_mute(E_Mixer_System *self, E_Mixer_Channel *channel, int mute); +int e_mixer_system_can_mute(E_Mixer_System *self, E_Mixer_Channel *channel); +int e_mixer_system_has_capture(E_Mixer_System *self, E_Mixer_Channel *channel); + + +#endif /* E_MOD_SYSTEM_H */ diff --git a/src/modules/mixer/module.desktop.in b/src/modules/mixer/module.desktop.in new file mode 100644 index 000000000..54ff6d45b --- /dev/null +++ b/src/modules/mixer/module.desktop.in @@ -0,0 +1,5 @@ +[Desktop Entry] +Type=Link +Name=Mixer +Icon=e-module-mixer +Comment=Mixer Gadget

A module to provide a mixer for changing volume. diff --git a/src/modules/mixer/sys_alsa.c b/src/modules/mixer/sys_alsa.c new file mode 100644 index 000000000..75fd7b0a4 --- /dev/null +++ b/src/modules/mixer/sys_alsa.c @@ -0,0 +1,618 @@ +#include +#include +#include +#include +#include +#include +#include "e_mod_system.h" + +struct e_mixer_callback_desc +{ + int (*func)(void *data, E_Mixer_System *self); + void *data; + E_Mixer_System *self; + Ecore_Idler *idler; + Evas_List *handlers; +}; + + +static int _mixer_callback_add(E_Mixer_System *self, int (*func)(void *data, E_Mixer_System *self), void *data); +static int _mixer_callback_del(E_Mixer_System *self, struct e_mixer_callback_desc *desc); + + +static int +_cb_dispatch(void *data) +{ + struct e_mixer_callback_desc *desc; + int r; + + desc = data; + snd_mixer_handle_events(desc->self); + r = desc->func(desc->data, desc->self); + desc->idler = NULL; + + if (!r) + _mixer_callback_del(desc->self, desc); /* desc is invalid then. */ + + return 0; +} + +static int +_cb_fd_handler(void *data, Ecore_Fd_Handler *fd_handler) +{ + struct e_mixer_callback_desc *desc; + + desc = data; + + if (ecore_main_fd_handler_active_get(fd_handler, ECORE_FD_ERROR)) + { + desc->handlers = evas_list_remove(desc->handlers, fd_handler); + if (!desc->handlers) + { + E_Mixer_System *s; + int (*f)(void *, E_Mixer_System *); + void *d; + + s = desc->self; + f = desc->func; + d = desc->data; + _mixer_callback_del(s, desc); + _mixer_callback_add(s, f, d); + } + return 0; + } + + if (!desc->idler) + desc->idler = ecore_idler_add(_cb_dispatch, desc); + return 1; +} + +static int +_mixer_callback_add(E_Mixer_System *self, int (*func)(void *data, E_Mixer_System *self), void *data) +{ + struct e_mixer_callback_desc *desc; + struct pollfd *pfds; + int len; + + len = snd_mixer_poll_descriptors_count(self); + if (len <= 0) + return 0; + + desc = malloc(sizeof(struct e_mixer_callback_desc)); + if (!desc) + return 0; + + desc->func = func; + desc->data = data; + desc->self = self; + desc->idler = NULL; + desc->handlers = NULL; + + pfds = alloca(len * sizeof(struct pollfd)); + len = snd_mixer_poll_descriptors(self, pfds, len); + if (len <= 0) + { + free(desc); + return 0; + } + + while (len > 0) + { + Ecore_Fd_Handler *fd_handler; + + len--; + fd_handler = ecore_main_fd_handler_add( + pfds[len].fd, ECORE_FD_READ, _cb_fd_handler, desc, NULL, NULL); + desc->handlers = evas_list_prepend(desc->handlers, fd_handler); + } + + snd_mixer_set_callback_private(self, desc); + + return 1; +} + +static int +_mixer_callback_del(E_Mixer_System *self, struct e_mixer_callback_desc *desc) +{ + Evas_List *l; + + snd_mixer_set_callback_private(self, NULL); + + for (l = desc->handlers; l != NULL; l = l->next) + ecore_main_fd_handler_del(l->data); + + evas_list_free(desc->handlers); + free(desc); + + return 1; +} + +static int +_mixer_callback_replace(E_Mixer_System *self, struct e_mixer_callback_desc *desc, int (*func)(void *data, E_Mixer_System *self), void *data) +{ + desc->func = func; + desc->data = data; + + return 1; +} + +E_Mixer_System * +e_mixer_system_new(const char *name) +{ + snd_mixer_t *handle; + int err; + + if (!name) + return NULL; + + err = snd_mixer_open(&handle, 0); + if (err < 0) + goto error_open; + + err = snd_mixer_attach(handle, name); + if (err < 0) + goto error_load; + + err = snd_mixer_selem_register(handle, NULL, NULL); + if (err < 0) + goto error_load; + + err = snd_mixer_load(handle); + if (err < 0) + goto error_load; + + return handle; + + error_load: + snd_mixer_close(handle); + error_open: + fprintf(stderr, "MIXER: Cannot get hardware info: %s\n", snd_strerror(err)); + return NULL; +} + +void +e_mixer_system_del(E_Mixer_System *self) +{ + struct e_mixer_callback_desc *desc; + + if (self <= 0) + return; + + desc = snd_mixer_get_callback_private(self); + if (desc) + _mixer_callback_del(self, desc); + + snd_mixer_close(self); +} + +int +e_mixer_system_callback_set(E_Mixer_System *self, int (*func)(void *data, E_Mixer_System *self), void *data) +{ + struct e_mixer_callback_desc *desc; + + if (!self) + return 0; + + desc = snd_mixer_get_callback_private(self); + if (!desc) + { + if (func) + return _mixer_callback_add(self, func, data); + return 1; + } + else + { + if (func) + return _mixer_callback_replace(self, desc, func, data); + else + return _mixer_callback_del(self, desc); + } +} + +Evas_List * +e_mixer_system_get_cards(void) +{ + int err, card_num; + Evas_List *cards; + + cards = NULL; + card_num = -1; + while (((err = snd_card_next(&card_num)) == 0) && (card_num >= 0)) + { + snd_ctl_t *control; + char buf[256]; + + snprintf(buf, sizeof(buf), "hw:%d", card_num); + + if (snd_ctl_open(&control, buf, 0) < 0) + break; + snd_ctl_close(control); + cards = evas_list_append(cards, strdup(buf)); + } + + if (err < 0) + fprintf(stderr, "MIXER: Cannot get available card number: %s\n", + snd_strerror(err)); + + return cards; +} + +void +e_mixer_system_free_cards(Evas_List *cards) +{ + Evas_List *e; + + for (e = cards; e != NULL; e = e->next) + free(e->data); + + evas_list_free(cards); +} + +char * +e_mixer_system_get_default_card(void) +{ + static const char buf[] = "hw:0"; + snd_ctl_t *control; + + if (snd_ctl_open(&control, buf, 0) < 0) + return NULL; + snd_ctl_close(control); + return strdup(buf); +} + +char * +e_mixer_system_get_card_name(const char *card) +{ + snd_ctl_card_info_t *hw_info; + const char *name; + snd_ctl_t *control; + int err; + + if (!card) + return NULL; + + snd_ctl_card_info_alloca(&hw_info); + + err = snd_ctl_open(&control, card, 0); + if (err < 0) + return NULL; + + err = snd_ctl_card_info(control, hw_info); + if (err < 0) + { + fprintf(stderr, "MIXER: Cannot get hardware info: %s: %s\n", card, + snd_strerror(err)); + snd_ctl_close(control); + return NULL; + } + + snd_ctl_close(control); + name = snd_ctl_card_info_get_name(hw_info); + if (!name) + { + fprintf(stderr, "MIXER: Cannot get hardware name: %s\n", card); + return NULL; + } + + return strdup(name); +} + +Evas_List * +e_mixer_system_get_channels(E_Mixer_System *self) +{ + Evas_List *channels; + snd_mixer_elem_t *elem; + + if (!self) + return NULL; + + channels = NULL; + + elem = snd_mixer_first_elem(self); + for (; elem != NULL; elem = snd_mixer_elem_next(elem)) + { + if ((!snd_mixer_selem_is_active(elem)) || + (!snd_mixer_selem_has_playback_volume(elem))) + continue; + + channels = evas_list_append(channels, elem); + } + + return channels; +} + +void +e_mixer_system_free_channels(Evas_List *channels) +{ + evas_list_free(channels); +} + +Evas_List * +e_mixer_system_get_channels_names(E_Mixer_System *self) +{ + Evas_List *channels; + snd_mixer_elem_t *elem; + snd_mixer_selem_id_t *sid; + + if (!self) + return NULL; + + channels = NULL; + snd_mixer_selem_id_alloca(&sid); + + elem = snd_mixer_first_elem(self); + for (; elem != NULL; elem = snd_mixer_elem_next(elem)) + { + const char *name; + if ((!snd_mixer_selem_is_active(elem)) || + (!snd_mixer_selem_has_playback_volume(elem))) + continue; + + snd_mixer_selem_get_id(elem, sid); + name = snd_mixer_selem_id_get_name(sid); + if (name) + channels = evas_list_append(channels, strdup(name)); + } + + return channels; +} + +void +e_mixer_system_free_channels_names(Evas_List *channels_names) +{ + Evas_List *e; + + for (e = channels_names; e != NULL; e = e->next) + free(e->data); + + evas_list_free(channels_names); +} + +char * +e_mixer_system_get_default_channel_name(E_Mixer_System *self) +{ + snd_mixer_elem_t *elem; + snd_mixer_selem_id_t *sid; + + if (!self) + return NULL; + + snd_mixer_selem_id_alloca(&sid); + + elem = snd_mixer_first_elem(self); + for (; elem != NULL; elem = snd_mixer_elem_next(elem)) + { + const char *name; + if ((!snd_mixer_selem_is_active(elem)) || + (!snd_mixer_selem_has_playback_volume(elem))) + continue; + + snd_mixer_selem_get_id(elem, sid); + name = snd_mixer_selem_id_get_name(sid); + if (name) + return strdup(name); + } + + return NULL; +} + +E_Mixer_Channel * +e_mixer_system_get_channel_by_name(E_Mixer_System *self, const char *name) +{ + snd_mixer_elem_t *elem; + snd_mixer_selem_id_t *sid; + + if ((!self) || (!name)) + return NULL; + + snd_mixer_selem_id_alloca(&sid); + + elem = snd_mixer_first_elem(self); + for (; elem != NULL; elem = snd_mixer_elem_next(elem)) + { + const char *n; + if ((!snd_mixer_selem_is_active(elem)) || + (!snd_mixer_selem_has_playback_volume(elem))) + continue; + + snd_mixer_selem_get_id(elem, sid); + n = snd_mixer_selem_id_get_name(sid); + if (n && (strcmp(n, name) == 0)) + return elem; + } + + return NULL; +} + +void +e_mixer_system_channel_del(E_Mixer_Channel *channel) +{ +} + +char * +e_mixer_system_get_channel_name(E_Mixer_System *self, E_Mixer_Channel *channel) +{ + snd_mixer_selem_id_t *sid; + const char *n; + char *name; + + if ((!self) || (!channel)) + return NULL; + + snd_mixer_selem_id_alloca(&sid); + snd_mixer_selem_get_id(channel, sid); + n = snd_mixer_selem_id_get_name(sid); + if (n) + name = strdup(n); + else + name = NULL; + + return name; +} + +int +e_mixer_system_get_volume(E_Mixer_System *self, E_Mixer_Channel *channel, int *left, int *right) +{ + long lvol, rvol, range, min, max; + + if ((!self) || (!channel) || (!left) || (!right)) + return 0; + + snd_mixer_handle_events(self); + snd_mixer_selem_get_playback_volume_range(channel, &min, &max); + range = max - min; + if (range < 1) + return 0; + + if (snd_mixer_selem_has_playback_channel(channel, 0)) + snd_mixer_selem_get_playback_volume(channel, 0, &lvol); + else + lvol = min; + + if (snd_mixer_selem_has_playback_channel(channel, 1)) + snd_mixer_selem_get_playback_volume(channel, 1, &rvol); + else + rvol = min; + + if (snd_mixer_selem_is_playback_mono(channel) || + snd_mixer_selem_has_playback_volume_joined(channel)) + rvol = lvol; + + *left = rint((double)(lvol - min) * 100 / (double)range); + *right = rint((double)(rvol - min) * 100 / (double)range); + + return 1; +} + +int +e_mixer_system_set_volume(E_Mixer_System *self, E_Mixer_Channel *channel, int left, int right) +{ + long range, min, max, div; + int mode; + + if ((!self) || (!channel)) + return 0; + + snd_mixer_handle_events(self); + snd_mixer_selem_get_playback_volume_range(channel, &min, &max); + div = 100 + min; + if (div == 0) + { + div = 1; /* no zero-division */ + min++; + } + + range = max - min; + if (range < 1) + return 0; + + mode = 0; + if (left >= 0) + { + left = (((range * left) + (range / 2)) / div) - min; + mode |= 1; + } + + if (right >= 0) + { + right = (((range * right) + (range / 2)) / div) - min; + mode |= 2; + } + + if (mode & 1) + snd_mixer_selem_set_playback_volume(channel, 0, left); + + if ((!snd_mixer_selem_is_playback_mono(channel)) && + (!snd_mixer_selem_has_playback_volume_joined(channel)) && + (mode & 2)) + { + if (snd_mixer_selem_has_playback_channel(channel, 1)) + snd_mixer_selem_set_playback_volume(channel, 1, right); + } + + return 1; +} + +int +e_mixer_system_can_mute(E_Mixer_System *self, E_Mixer_Channel *channel) +{ + if ((!self) || (!channel)) + return 0; + + snd_mixer_handle_events(self); + return (snd_mixer_selem_has_playback_switch(channel) || + snd_mixer_selem_has_playback_switch_joined(channel)); +} + +int +e_mixer_system_get_mute(E_Mixer_System *self, E_Mixer_Channel *channel, int *mute) +{ + if ((!self) || (!channel) || (!mute)) + return 0; + + snd_mixer_handle_events(self); + if (snd_mixer_selem_has_playback_switch(channel) || + snd_mixer_selem_has_playback_switch_joined(channel)) + { + int m; + + /* XXX: not checking for return, always returns 0 even if it worked. + * alsamixer also don't check it. Bug? + */ + snd_mixer_selem_get_playback_switch(channel, 0, &m); + *mute = !m; + } + else + *mute = 0; + + return 1; +} + +int +e_mixer_system_set_mute(E_Mixer_System *self, E_Mixer_Channel *channel, int mute) +{ + if ((!self) || (!channel)) + return 0; + + snd_mixer_handle_events(self); + if (snd_mixer_selem_has_playback_switch(channel) || + snd_mixer_selem_has_playback_switch_joined(channel)) + return snd_mixer_selem_set_playback_switch_all(channel, !mute); + else + return 0; +} + +int +e_mixer_system_get_state(E_Mixer_System *self, E_Mixer_Channel *channel, E_Mixer_Channel_State *state) +{ + int r; + + if (!state) + return 0; + + r = e_mixer_system_get_mute(self, channel, &state->mute); + r &= e_mixer_system_get_volume(self, channel, &state->left, &state->right); + return r; +} + +int +e_mixer_system_set_state(E_Mixer_System *self, E_Mixer_Channel *channel, const E_Mixer_Channel_State *state) +{ + int r; + + if (!state) + return 0; + + r = e_mixer_system_set_mute(self, channel, state->mute); + r &= e_mixer_system_set_volume(self, channel, state->left, state->right); + return r; +} + +int +e_mixer_system_has_capture(E_Mixer_System *self, E_Mixer_Channel *channel) +{ + if ((!self) || (!channel)) + return 0; + + return snd_mixer_selem_has_capture_switch(channel); +} diff --git a/src/modules/mixer/sys_dummy.c b/src/modules/mixer/sys_dummy.c new file mode 100644 index 000000000..783e4a123 --- /dev/null +++ b/src/modules/mixer/sys_dummy.c @@ -0,0 +1,166 @@ +#include "e_mod_system.h" +#include +#include + +static const char _name[] = "dummy"; + +E_Mixer_System * +e_mixer_system_new(const char *name) +{ + if (strcmp(name, _name) == 0) + return (E_Mixer_System *)-1; + else + return NULL; +} + +void +e_mixer_system_del(E_Mixer_System *self) +{ +} + +int +e_mixer_system_callback_set(E_Mixer_System *self, int (*func)(void *data, E_Mixer_System *self), void *data) +{ + return 0; +} + +Evas_List * +e_mixer_system_get_cards(void) +{ + return evas_list_append(NULL, _name); +} + +void +e_mixer_system_free_cards(Evas_List *cards) +{ + evas_list_free(cards); +} + +char * +e_mixer_system_get_default_card(void) +{ + return strdup(_name); +} + +char * +e_mixer_system_get_card_name(const char *card) +{ + if (strcmp(card, _name) == 0) + return strdup(_name); + else + return NULL; +} + +Evas_List * +e_mixer_system_get_channels(E_Mixer_System *self) +{ + return evas_list_append(NULL, (void *)-2); +} + +void +e_mixer_system_free_channels(Evas_List *channels) +{ + evas_list_free(channels); +} + +Evas_List * +e_mixer_system_get_channels_names(E_Mixer_System *self) +{ + return evas_list_append(NULL, _name); +} + +void +e_mixer_system_free_channels_names(Evas_List *channels_names) +{ + evas_list_free(channels_names); +} + +char * +e_mixer_system_get_default_channel_name(E_Mixer_System *self) +{ + return strdup(_name); +} + +E_Mixer_Channel * +e_mixer_system_get_channel_by_name(E_Mixer_System *self, const char *name) +{ + if (strcmp(name, _name) == 0) + return (E_Mixer_Channel *)-2; + else + return NULL; +} + +void +e_mixer_system_channel_del(E_Mixer_Channel *channel) +{ +} + +char * +e_mixer_system_get_channel_name(E_Mixer_System *self, E_Mixer_Channel *channel) +{ + if (channel == (E_Mixer_Channel *)-2) + return strdup(_name); + else + return NULL; +} + +int +e_mixer_system_get_volume(E_Mixer_System *self, E_Mixer_Channel *channel, int *left, int *right) +{ + if (left) + *left = 0; + if (right) + *right = 0; + + return 1; +} + +int +e_mixer_system_set_volume(E_Mixer_System *self, E_Mixer_Channel *channel, int left, int right) +{ + return 0; +} + +int +e_mixer_system_can_mute(E_Mixer_System *self, E_Mixer_Channel *channel) +{ + return 1; +} + +int +e_mixer_system_get_mute(E_Mixer_System *self, E_Mixer_Channel *channel, int *mute) +{ + if (mute) + *mute = 1; + + return 1; +} + +int +e_mixer_system_set_mute(E_Mixer_System *self, E_Mixer_Channel *channel, int mute) +{ + return 0; +} + +int +e_mixer_system_get_state(E_Mixer_System *self, E_Mixer_Channel *channel, E_Mixer_Channel_State *state) +{ + const E_Mixer_Channel_State def = {1, 0, 0}; + + if (state) + *state = def; + + return 1; +} + +int +e_mixer_system_set_state(E_Mixer_System *self, E_Mixer_Channel *channel, const E_Mixer_Channel_State *state) +{ + return 0; +} + +int +e_mixer_system_has_capture(E_Mixer_System *self, E_Mixer_Channel *channel) +{ + return 0; +}