this is emixer (epulse) from http://git.enlightenment.org/devs/ceolin/epulse.git the emixer binar is rewritten though and the emix lib is compiled-in into the module and into the binary as oppopsed to a shared lib with loadable modules. this supports alsa and pulse. a much more solid mixer.devs/stefan/wl-session-recovery
parent
d17851f714
commit
4f6df6b7ca
14 changed files with 4243 additions and 50 deletions
@ -0,0 +1 @@ |
||||
emixer |
@ -0,0 +1,201 @@ |
||||
#include "e.h" |
||||
#include "e_mod_config.h" |
||||
#include "e_mod_main.h" |
||||
#include "emix.h" |
||||
|
||||
typedef struct _Emix_Config |
||||
{ |
||||
const char *backend; |
||||
int notify; |
||||
int mute; |
||||
|
||||
emix_config_backend_changed cb; |
||||
const void *userdata; |
||||
} Emix_Config; |
||||
|
||||
struct _E_Config_Dialog_Data |
||||
{ |
||||
Emix_Config config; |
||||
Evas_Object *list; |
||||
}; |
||||
|
||||
static E_Config_DD *cd; |
||||
static Emix_Config *_config; |
||||
|
||||
static E_Config_DD* |
||||
_emix_config_dd_new(void) |
||||
{ |
||||
E_Config_DD *result = E_CONFIG_DD_NEW("Emix_Config", Emix_Config); |
||||
|
||||
E_CONFIG_VAL(result, Emix_Config, backend, STR); |
||||
E_CONFIG_VAL(result, Emix_Config, notify, INT); |
||||
E_CONFIG_VAL(result, Emix_Config, mute, INT); |
||||
|
||||
return result; |
||||
} |
||||
|
||||
const char * |
||||
emix_config_backend_get(void) |
||||
{ |
||||
return _config->backend; |
||||
} |
||||
|
||||
void |
||||
emix_config_backend_set(const char *backend) |
||||
{ |
||||
eina_stringshare_replace(&_config->backend, backend); |
||||
e_config_domain_save("module.emix", cd, _config); |
||||
} |
||||
|
||||
Eina_Bool |
||||
emix_config_notify_get(void) |
||||
{ |
||||
return _config->notify; |
||||
} |
||||
|
||||
Eina_Bool |
||||
emix_config_desklock_mute_get(void) |
||||
{ |
||||
return _config->mute; |
||||
} |
||||
|
||||
static void |
||||
_config_set(Emix_Config *config) |
||||
{ |
||||
if ((config->backend) && (_config->backend != config->backend)) |
||||
eina_stringshare_replace(&_config->backend, config->backend); |
||||
|
||||
_config->notify = config->notify; |
||||
_config->mute = config->mute; |
||||
|
||||
DBG("SAVING CONFIG %s %d %d", _config->backend, config->notify, |
||||
config->mute); |
||||
e_config_domain_save("module.emix", cd, config); |
||||
} |
||||
|
||||
void |
||||
emix_config_init(emix_config_backend_changed cb, const void *userdata) |
||||
{ |
||||
const Eina_List *l; |
||||
|
||||
EINA_SAFETY_ON_FALSE_RETURN(emix_init()); |
||||
cd = _emix_config_dd_new(); |
||||
_config = e_config_domain_load("module.emix", cd); |
||||
if (!_config) |
||||
{ |
||||
_config = E_NEW(Emix_Config, 1); |
||||
l = emix_backends_available(); |
||||
if (l) |
||||
_config->backend = eina_stringshare_add(l->data); |
||||
} |
||||
|
||||
_config->cb = cb; |
||||
_config->userdata = userdata; |
||||
DBG("Config loaded, backend to use: %s", _config->backend); |
||||
} |
||||
|
||||
void |
||||
emix_config_shutdown(void) |
||||
{ |
||||
E_CONFIG_DD_FREE(cd); |
||||
if (_config->backend) |
||||
eina_stringshare_del(_config->backend); |
||||
free(_config); |
||||
emix_shutdown(); |
||||
} |
||||
|
||||
static void* |
||||
_create_data(E_Config_Dialog *cfg EINA_UNUSED) |
||||
{ |
||||
E_Config_Dialog_Data *d; |
||||
|
||||
d = E_NEW(E_Config_Dialog_Data, 1); |
||||
d->config.backend = eina_stringshare_add(_config->backend); |
||||
d->config.notify = _config->notify; |
||||
d->config.mute = _config->mute; |
||||
|
||||
return d; |
||||
} |
||||
|
||||
static void |
||||
_free_data(E_Config_Dialog *c EINA_UNUSED, E_Config_Dialog_Data *cf) |
||||
{ |
||||
eina_stringshare_del(cf->config.backend); |
||||
free(cf); |
||||
} |
||||
|
||||
static Evas_Object * |
||||
_basic_create_widgets(E_Config_Dialog *cfd EINA_UNUSED, Evas *evas, |
||||
E_Config_Dialog_Data *cfdata) |
||||
{ |
||||
Evas_Object *o, *l; |
||||
const Eina_List *node; |
||||
char *name; |
||||
int i = 0; |
||||
|
||||
o = e_widget_list_add(evas, 0, 0); |
||||
|
||||
l = e_widget_check_add(evas, "Notify on volume change", &cfdata->config.notify); |
||||
e_widget_list_object_append(o, l, 0, 0, 0); |
||||
|
||||
l = e_widget_check_add(evas, "Mute on lock", &cfdata->config.mute); |
||||
e_widget_list_object_append(o, l, 0, 0, 0); |
||||
|
||||
l = e_widget_label_add(evas, "Backend to use:"); |
||||
e_widget_list_object_append(o, l, 0, 0, 0); |
||||
|
||||
cfdata->list = l = e_widget_ilist_add(evas, 0, 0, NULL); |
||||
e_widget_ilist_multi_select_set(l, EINA_FALSE); |
||||
e_widget_size_min_set(l, 100, 100); |
||||
EINA_LIST_FOREACH(emix_backends_available(), node, name) |
||||
{ |
||||
e_widget_ilist_append(l, NULL, name, NULL, NULL, NULL); |
||||
i ++; |
||||
if (_config->backend && !strcmp(_config->backend, name)) |
||||
e_widget_ilist_selected_set(l, i); |
||||
} |
||||
e_widget_ilist_go(l); |
||||
e_widget_ilist_thaw(l); |
||||
e_widget_list_object_append(o, l, 1, 1, 0); |
||||
|
||||
return o; |
||||
} |
||||
|
||||
static int |
||||
_basic_apply_data(E_Config_Dialog *cfd EINA_UNUSED, |
||||
E_Config_Dialog_Data *cfdata) |
||||
{ |
||||
char *new_backend = eina_list_nth( |
||||
emix_backends_available(), |
||||
e_widget_ilist_selected_get(cfdata->list)); |
||||
|
||||
eina_stringshare_replace(&cfdata->config.backend, new_backend); |
||||
|
||||
_config_set(&cfdata->config); |
||||
if (_config->cb) |
||||
_config->cb(new_backend, (void *)_config->userdata); |
||||
return 1; |
||||
} |
||||
|
||||
E_Config_Dialog* |
||||
emix_config_popup_new(Evas_Object *comp, const char *p EINA_UNUSED) |
||||
{ |
||||
E_Config_Dialog *cfd; |
||||
E_Config_Dialog_View *v; |
||||
|
||||
if (e_config_dialog_find("E", "windows/emix")) |
||||
return NULL; |
||||
|
||||
v = E_NEW(E_Config_Dialog_View, 1); |
||||
v->create_cfdata = _create_data; |
||||
v->free_cfdata = _free_data; |
||||
v->basic.apply_cfdata = _basic_apply_data; |
||||
v->basic.create_widgets = _basic_create_widgets; |
||||
|
||||
cfd = e_config_dialog_new(comp, |
||||
"Emix Configuration", |
||||
"E", "windows/emix", |
||||
NULL, |
||||
0, v, NULL); |
||||
return cfd; |
||||
} |
@ -0,0 +1,18 @@ |
||||
#ifndef E_MOD_CONFIG_H |
||||
#define E_MOD_CONFIG_H |
||||
|
||||
#include <e.h> |
||||
|
||||
typedef void (*emix_config_backend_changed)(const char *backend, void *data); |
||||
typedef void (*emix_config_meter_changed)(Eina_Bool enable, void *data); |
||||
|
||||
void emix_config_init(emix_config_backend_changed cb, const void *userdata); |
||||
void emix_config_shutdown(void); |
||||
const char *emix_config_backend_get(void); |
||||
void emix_config_backend_set(const char *backend); |
||||
Eina_Bool emix_config_desklock_mute_get(void); |
||||
Eina_Bool emix_config_meter_get(void); |
||||
Eina_Bool emix_config_notify_get(void); |
||||
E_Config_Dialog* emix_config_popup_new(Evas_Object *comp, const char*p); |
||||
|
||||
#endif |
@ -0,0 +1,817 @@ |
||||
#include <e.h> |
||||
#include <Eina.h> |
||||
#include "emix.h" |
||||
#include "e_mod_main.h" |
||||
#include "e_mod_config.h" |
||||
|
||||
#define VOLUME_STEP 5 |
||||
|
||||
int _e_emix_log_domain; |
||||
|
||||
/* module requirements */ |
||||
E_API E_Module_Api e_modapi = |
||||
{ |
||||
E_MODULE_API_VERSION, |
||||
"Mixer" |
||||
}; |
||||
|
||||
/* necessary forward delcaration */ |
||||
static E_Gadcon_Client *_gc_init(E_Gadcon *gc, const char *name, |
||||
const char *id, const char *style); |
||||
static void _gc_shutdown(E_Gadcon_Client *gcc); |
||||
static void _gc_orient(E_Gadcon_Client *gcc, |
||||
E_Gadcon_Orient orient); |
||||
static const char *_gc_label(const E_Gadcon_Client_Class *client_class); |
||||
static Evas_Object *_gc_icon(const E_Gadcon_Client_Class *client_class, |
||||
Evas *evas); |
||||
static const char *_gc_id_new(const E_Gadcon_Client_Class *client_class); |
||||
|
||||
static const E_Gadcon_Client_Class _gadcon_class = |
||||
{ |
||||
GADCON_CLIENT_CLASS_VERSION, |
||||
"emix", |
||||
{ |
||||
_gc_init, _gc_shutdown, |
||||
_gc_orient, _gc_label, _gc_icon, _gc_id_new, NULL, |
||||
e_gadcon_site_is_not_toolbar |
||||
}, |
||||
E_GADCON_CLIENT_STYLE_PLAIN |
||||
}; |
||||
|
||||
typedef struct _Context Context; |
||||
struct _Context |
||||
{ |
||||
char *theme; |
||||
Ecore_Exe *emixer; |
||||
Ecore_Event_Handler *desklock_handler; |
||||
Ecore_Event_Handler *emix_event_handler; |
||||
const Emix_Sink *sink_default; |
||||
E_Module *module; |
||||
Eina_List *instances; |
||||
E_Menu *menu; |
||||
unsigned int notification_id; |
||||
|
||||
struct { |
||||
E_Action *incr; |
||||
E_Action *decr; |
||||
E_Action *mute; |
||||
} actions; |
||||
}; |
||||
|
||||
typedef struct _Instance Instance; |
||||
struct _Instance |
||||
{ |
||||
E_Gadcon_Client *gcc; |
||||
E_Gadcon_Orient orient; |
||||
|
||||
E_Gadcon_Popup *popup; |
||||
Evas *evas; |
||||
Evas_Object *gadget; |
||||
Evas_Object *list; |
||||
Evas_Object *slider; |
||||
Evas_Object *check; |
||||
|
||||
Eina_Bool mute; |
||||
}; |
||||
|
||||
static Context *mixer_context = NULL; |
||||
|
||||
static void |
||||
_notify_cb(void *data EINA_UNUSED, unsigned int id) |
||||
{ |
||||
mixer_context->notification_id = id; |
||||
} |
||||
|
||||
static void |
||||
_notify(const int val) |
||||
{ |
||||
E_Notification_Notify n; |
||||
char *icon, buf[56]; |
||||
int ret; |
||||
|
||||
if (!emix_config_notify_get()) |
||||
return; |
||||
|
||||
memset(&n, 0, sizeof(E_Notification_Notify)); |
||||
if (val > EMIX_VOLUME_MAX || val < 0) |
||||
return; |
||||
|
||||
ret = snprintf(buf, (sizeof(buf) - 1), "%s: %d%%", _("New volume"), val); |
||||
if ((ret < 0) || ((unsigned int)ret > sizeof(buf))) |
||||
return; |
||||
//Names are taken from FDO icon naming scheme
|
||||
if (val == 0) |
||||
icon = "audio-volume-muted"; |
||||
else if ((val > 33) && (val < 66)) |
||||
icon = "audio-volume-medium"; |
||||
else if (val < 33) |
||||
icon = "audio-volume-low"; |
||||
else |
||||
icon = "audio-volume-high"; |
||||
|
||||
n.app_name = _("Emix"); |
||||
n.replaces_id = mixer_context->notification_id; |
||||
n.icon.icon = icon; |
||||
n.summary = _("Volume changed"); |
||||
n.body = buf; |
||||
n.timeout = 2000; |
||||
e_notification_client_send(&n, _notify_cb, NULL); |
||||
} |
||||
|
||||
static void |
||||
_mixer_popup_update(Instance *inst, int mute, int vol) |
||||
{ |
||||
elm_check_state_set(inst->check, !!mute); |
||||
elm_slider_value_set(inst->slider, vol); |
||||
} |
||||
|
||||
static void _popup_del(Instance *inst); |
||||
|
||||
static void |
||||
_mixer_gadget_update(void) |
||||
{ |
||||
Edje_Message_Int_Set *msg; |
||||
Instance *inst; |
||||
Eina_List *l; |
||||
|
||||
EINA_LIST_FOREACH(mixer_context->instances, l, inst) |
||||
{ |
||||
msg = alloca(sizeof(Edje_Message_Int_Set) + (2 * sizeof(int))); |
||||
msg->count = 3; |
||||
|
||||
if (!mixer_context->sink_default) |
||||
{ |
||||
msg->val[0] = EINA_FALSE; |
||||
msg->val[1] = 0; |
||||
msg->val[2] = 0; |
||||
if (inst->popup) |
||||
_popup_del(inst); |
||||
} |
||||
else |
||||
{ |
||||
int vol = 0; |
||||
unsigned int i = 0; |
||||
for (i = 0; i < |
||||
mixer_context->sink_default->volume.channel_count; i++) |
||||
vol += mixer_context->sink_default->volume.volumes[i]; |
||||
if (mixer_context->sink_default->volume.channel_count) |
||||
vol /= mixer_context->sink_default->volume.channel_count; |
||||
msg->val[0] = mixer_context->sink_default->mute; |
||||
msg->val[1] = vol; |
||||
msg->val[2] = msg->val[1]; |
||||
if (inst->popup) |
||||
_mixer_popup_update(inst, mixer_context->sink_default->mute, |
||||
msg->val[1]); |
||||
} |
||||
edje_object_message_send(inst->gadget, EDJE_MESSAGE_INT_SET, 0, msg); |
||||
edje_object_signal_emit(inst->gadget, "e,action,volume,change", "e"); |
||||
} |
||||
} |
||||
|
||||
static void |
||||
_volume_increase_cb(E_Object *obj EINA_UNUSED, const char *params EINA_UNUSED) |
||||
{ |
||||
unsigned int i; |
||||
EINA_SAFETY_ON_NULL_RETURN(mixer_context->sink_default); |
||||
Emix_Volume volume; |
||||
|
||||
Emix_Sink *s = (Emix_Sink *)mixer_context->sink_default; |
||||
volume.channel_count = s->volume.channel_count; |
||||
volume.volumes = calloc(s->volume.channel_count, sizeof(int)); |
||||
for (i = 0; i < volume.channel_count; i++) |
||||
{ |
||||
if (s->volume.volumes[i] < EMIX_VOLUME_MAX - VOLUME_STEP) |
||||
volume.volumes[i] = s->volume.volumes[i] + VOLUME_STEP; |
||||
else if (s->volume.volumes[i] < EMIX_VOLUME_MAX) |
||||
volume.volumes[i] = EMIX_VOLUME_MAX; |
||||
else |
||||
volume.volumes[i] = s->volume.volumes[i]; |
||||
} |
||||
|
||||
emix_sink_volume_set(s, volume); |
||||
free(volume.volumes); |
||||
} |
||||
|
||||
static void |
||||
_volume_decrease_cb(E_Object *obj EINA_UNUSED, const char *params EINA_UNUSED) |
||||
{ |
||||
unsigned int i; |
||||
EINA_SAFETY_ON_NULL_RETURN(mixer_context->sink_default); |
||||
Emix_Volume volume; |
||||
|
||||
Emix_Sink *s = (Emix_Sink *)mixer_context->sink_default; |
||||
volume.channel_count = s->volume.channel_count; |
||||
volume.volumes = calloc(s->volume.channel_count, sizeof(int)); |
||||
for (i = 0; i < volume.channel_count; i++) |
||||
{ |
||||
if (s->volume.volumes[i] > VOLUME_STEP) |
||||
volume.volumes[i] = s->volume.volumes[i] - VOLUME_STEP; |
||||
else if (s->volume.volumes[i] < VOLUME_STEP) |
||||
volume.volumes[i] = 0; |
||||
else |
||||
volume.volumes[i] = s->volume.volumes[i]; |
||||
} |
||||
|
||||
emix_sink_volume_set(s, volume); |
||||
free(volume.volumes); |
||||
} |
||||
|
||||
static void |
||||
_volume_mute_cb(E_Object *obj EINA_UNUSED, const char *params EINA_UNUSED) |
||||
{ |
||||
EINA_SAFETY_ON_NULL_RETURN(mixer_context->sink_default); |
||||
|
||||
Emix_Sink *s = (Emix_Sink *)mixer_context->sink_default; |
||||
Eina_Bool mute = !s->mute; |
||||
emix_sink_mute_set(s, mute); |
||||
} |
||||
|
||||
static void |
||||
_actions_register(void) |
||||
{ |
||||
mixer_context->actions.incr = e_action_add("volume_increase"); |
||||
if (mixer_context->actions.incr) |
||||
{ |
||||
mixer_context->actions.incr->func.go = _volume_increase_cb; |
||||
e_action_predef_name_set("Mixer", _("Increase Volume"), |
||||
"volume_increase", NULL, NULL, 0); |
||||
} |
||||
|
||||
mixer_context->actions.decr = e_action_add("volume_decrease"); |
||||
if (mixer_context->actions.decr) |
||||
{ |
||||
mixer_context->actions.decr->func.go = _volume_decrease_cb; |
||||
e_action_predef_name_set("Mixer", _("Decrease Volume"), |
||||
"volume_decrease", NULL, NULL, 0); |
||||
} |
||||
|
||||
mixer_context->actions.mute = e_action_add("volume_mute"); |
||||
if (mixer_context->actions.mute) |
||||
{ |
||||
mixer_context->actions.mute->func.go = _volume_mute_cb; |
||||
e_action_predef_name_set("Mixer", _("Mute volume"), "volume_mute", |
||||
NULL, NULL, 0); |
||||
} |
||||
|
||||
e_comp_canvas_keys_ungrab(); |
||||
e_comp_canvas_keys_grab(); |
||||
} |
||||
|
||||
static void |
||||
_actions_unregister(void) |
||||
{ |
||||
if (mixer_context->actions.incr) |
||||
{ |
||||
e_action_predef_name_del("Mixer", _("Increase Volume")); |
||||
e_action_del("volume_increase"); |
||||
mixer_context->actions.incr = NULL; |
||||
} |
||||
|
||||
if (mixer_context->actions.decr) |
||||
{ |
||||
e_action_predef_name_del("Mixer", _("Decrease Volume")); |
||||
e_action_del("volume_decrease"); |
||||
mixer_context->actions.decr = NULL; |
||||
} |
||||
|
||||
if (mixer_context->actions.mute) |
||||
{ |
||||
e_action_predef_name_del("Mixer", _("Mute Volume")); |
||||
e_action_del("volume_mute"); |
||||
mixer_context->actions.mute = NULL; |
||||
} |
||||
|
||||
e_comp_canvas_keys_ungrab(); |
||||
e_comp_canvas_keys_grab(); |
||||
} |
||||
|
||||
static void |
||||
_popup_del(Instance *inst) |
||||
{ |
||||
inst->slider = NULL; |
||||
inst->check = NULL; |
||||
E_FREE_FUNC(inst->popup, e_object_del); |
||||
} |
||||
|
||||
static void |
||||
_popup_del_cb(void *obj) |
||||
{ |
||||
_popup_del(e_object_data_get(obj)); |
||||
} |
||||
|
||||
static void |
||||
_popup_comp_del_cb(void *data, Evas_Object *obj EINA_UNUSED) |
||||
{ |
||||
Instance *inst = data; |
||||
|
||||
E_FREE_FUNC(inst->popup, e_object_del); |
||||
} |
||||
|
||||
static Eina_Bool |
||||
_emixer_del_cb(void *data EINA_UNUSED, int type EINA_UNUSED, |
||||
void *info EINA_UNUSED) |
||||
{ |
||||
mixer_context->emixer = NULL; |
||||
if (mixer_context->emix_event_handler) |
||||
ecore_event_handler_del(mixer_context->emix_event_handler); |
||||
|
||||
return EINA_TRUE; |
||||
} |
||||
|
||||
static void |
||||
_emixer_exec_cb(void *data, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED) |
||||
{ |
||||
Instance *inst = data; |
||||
char buf[PATH_MAX]; |
||||
|
||||
_popup_del(inst); |
||||
if (mixer_context->emixer) |
||||
return; |
||||
|
||||
snprintf(buf, sizeof(buf), "%s/%s/emixer %s", |
||||
e_module_dir_get(mixer_context->module), |
||||
MODULE_ARCH, emix_config_backend_get()); |
||||
mixer_context->emixer = ecore_exe_run(buf, NULL); |
||||
if (mixer_context->emix_event_handler) |
||||
ecore_event_handler_del(mixer_context->emix_event_handler); |
||||
mixer_context->emix_event_handler = |
||||
ecore_event_handler_add(ECORE_EXE_EVENT_DEL, _emixer_del_cb, NULL); |
||||
} |
||||
|
||||
static void |
||||
_check_changed_cb(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED, |
||||
void *event EINA_UNUSED) |
||||
{ |
||||
Emix_Sink *s = (Emix_Sink *)mixer_context->sink_default; |
||||
emix_sink_mute_set(s, !s->mute); |
||||
/*
|
||||
*TODO: is it really necessary ? or it will be update |
||||
* with the sink changed hanlder |
||||
*/ |
||||
_mixer_gadget_update(); |
||||
} |
||||
|
||||
static void |
||||
_slider_changed_cb(void *data EINA_UNUSED, Evas_Object *obj, |
||||
void *event EINA_UNUSED) |
||||
{ |
||||
int val; |
||||
Emix_Volume v; |
||||
unsigned int i; |
||||
Emix_Sink *s = (Emix_Sink *)mixer_context->sink_default; |
||||
|
||||
val = (int)elm_slider_value_get(obj); |
||||
v.volumes = calloc(s->volume.channel_count, sizeof(int)); |
||||
v.channel_count = s->volume.channel_count; |
||||
for (i = 0; i < s->volume.channel_count; i++) |
||||
v.volumes[i] = val; |
||||
|
||||
emix_sink_volume_set(s, v); |
||||
} |
||||
|
||||
static Evas_Object * |
||||
_popup_add_slider(void) |
||||
{ |
||||
unsigned int volume, i; |
||||
unsigned int channels = mixer_context->sink_default->volume.channel_count; |
||||
|
||||
Evas_Object *slider = elm_slider_add(e_comp->elm); |
||||
evas_object_size_hint_align_set(slider, EVAS_HINT_FILL, EVAS_HINT_FILL); |
||||
evas_object_size_hint_weight_set(slider, EVAS_HINT_EXPAND, 0.0); |
||||
|
||||
for (volume = 0, i = 0; i < channels; i++) |
||||
volume += mixer_context->sink_default->volume.volumes[i]; |
||||
|
||||
if (channels) |
||||
volume = volume / channels; |
||||
|
||||
evas_object_show(slider); |
||||
elm_slider_min_max_set(slider, 0.0, (double) EMIX_VOLUME_MAX); |
||||
evas_object_smart_callback_add(slider, "changed", _slider_changed_cb, |
||||
NULL); |
||||
|
||||
elm_slider_value_set(slider, volume); |
||||
return slider; |
||||
} |
||||
|
||||
static void |
||||
_sink_selected_cb(void *data, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED) |
||||
{ |
||||
Emix_Sink *s = data; |
||||
|
||||
mixer_context->sink_default = s; |
||||
_mixer_gadget_update(); |
||||
} |
||||
|
||||
static void |
||||
_popup_new(Instance *inst) |
||||
{ |
||||
Evas_Object *button, *list, *icon; |
||||
Emix_Sink *s; |
||||
Eina_List *l; |
||||
|
||||
EINA_SAFETY_ON_NULL_RETURN(mixer_context->sink_default); |
||||
|
||||
inst->popup = e_gadcon_popup_new(inst->gcc, 0); |
||||
list = elm_box_add(e_comp->elm); |
||||
|
||||
inst->list = elm_list_add(e_comp->elm); |
||||
evas_object_size_hint_align_set(inst->list, EVAS_HINT_FILL, EVAS_HINT_FILL); |
||||
evas_object_size_hint_weight_set(inst->list, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); |
||||
evas_object_show(inst->list); |
||||
|
||||
EINA_LIST_FOREACH((Eina_List *)emix_sinks_get(), l, s) |
||||
{ |
||||
Elm_Object_Item *it; |
||||
|
||||
it = elm_list_item_append(inst->list, s->name, NULL, NULL, _sink_selected_cb, s); |
||||
if (mixer_context->sink_default == s) |
||||
elm_list_item_selected_set(it, EINA_TRUE); |
||||
} |
||||
elm_box_pack_end(list, inst->list); |
||||
|
||||
inst->slider = _popup_add_slider(); |
||||
elm_box_pack_end(list, inst->slider); |
||||
evas_object_show(inst->slider); |
||||
|
||||
inst->mute = (int) mixer_context->sink_default->mute; |
||||
|
||||
inst->check = elm_check_add(e_comp->elm); |
||||
elm_object_text_set(inst->check, _("Mute")); |
||||
elm_check_state_pointer_set(inst->check, &(inst->mute)); |
||||
evas_object_smart_callback_add(inst->check, "changed", _check_changed_cb, |
||||
NULL); |
||||
elm_box_pack_end(list, inst->check); |
||||
evas_object_show(inst->check); |
||||
|
||||
icon = elm_icon_add(e_comp->elm); |
||||
elm_icon_standard_set(icon, "preferences-system"); |
||||
|
||||
button = elm_button_add(e_comp->elm); |
||||
evas_object_size_hint_align_set(button, EVAS_HINT_FILL, EVAS_HINT_FILL); |
||||
evas_object_size_hint_weight_set(button, EVAS_HINT_EXPAND, 0.0); |
||||
elm_object_part_content_set(button, "icon", icon); |
||||
evas_object_smart_callback_add(button, "clicked", _emixer_exec_cb, inst); |
||||
elm_box_pack_end(list, button); |
||||
evas_object_show(button); |
||||
|
||||
evas_object_size_hint_min_set(list, 208, 208); |
||||
|
||||
|
||||
e_gadcon_popup_content_set(inst->popup, list); |
||||
e_comp_object_util_autoclose(inst->popup->comp_object, |
||||
_popup_comp_del_cb, NULL, inst); |
||||
e_gadcon_popup_show(inst->popup); |
||||
e_object_data_set(E_OBJECT(inst->popup), inst); |
||||
E_OBJECT_DEL_SET(inst->popup, _popup_del_cb); |
||||
} |
||||
|
||||
static void |
||||
_menu_cb(void *data, E_Menu *menu EINA_UNUSED, E_Menu_Item *mi EINA_UNUSED) |
||||
{ |
||||
_emixer_exec_cb(data, NULL, NULL); |
||||
} |
||||
|
||||
static void |
||||
_settings_cb(void *data EINA_UNUSED, E_Menu *menu EINA_UNUSED, |
||||
E_Menu_Item *mi EINA_UNUSED) |
||||
{ |
||||
emix_config_popup_new(NULL, NULL); |
||||
} |
||||
|
||||
static void |
||||
_menu_new(Instance *inst, Evas_Event_Mouse_Down *ev) |
||||
{ |
||||
E_Zone *zone; |
||||
E_Menu *m; |
||||
E_Menu_Item *mi; |
||||
int x, y; |
||||
|
||||
zone = e_zone_current_get(); |
||||
|
||||
m = e_menu_new(); |
||||
|
||||
mi = e_menu_item_new(m); |
||||
e_menu_item_label_set(mi, _("Advanced")); |
||||
e_util_menu_item_theme_icon_set(mi, "configure"); |
||||
e_menu_item_callback_set(mi, _menu_cb, inst); |
||||
|
||||
mi = e_menu_item_new(m); |
||||
e_menu_item_label_set(mi, _("Settings")); |
||||
e_util_menu_item_theme_icon_set(mi, "configure"); |
||||
e_menu_item_callback_set(mi, _settings_cb, inst); |
||||
|
||||
m = e_gadcon_client_util_menu_items_append(inst->gcc, m, 0); |
||||
|
||||
e_gadcon_canvas_zone_geometry_get(inst->gcc->gadcon, &x, &y, NULL, NULL); |
||||
e_menu_activate_mouse(m, 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 |
||||
_mouse_down_cb(void *data, Evas *evas EINA_UNUSED, |
||||
Evas_Object *obj EINA_UNUSED, void *event) |
||||
{ |
||||
Instance *inst = data; |
||||
Evas_Event_Mouse_Down *ev = event; |
||||
|
||||
if (ev->button == 1) |
||||
{ |
||||
if (!inst->popup) |
||||
_popup_new(inst); |
||||
} |
||||
else if (ev->button == 2) |
||||
{ |
||||
_volume_mute_cb(NULL, NULL); |
||||
} |
||||
else if (ev->button == 3) |
||||
{ |
||||
_menu_new(inst, ev); |
||||
} |
||||
} |
||||
|
||||
static void |
||||
_mouse_wheel_cb(void *data EINA_UNUSED, Evas *evas EINA_UNUSED, |
||||
Evas_Object *obj EINA_UNUSED, void *event) |
||||
{ |
||||
Evas_Event_Mouse_Wheel *ev = event; |
||||
|
||||
if (ev->z > 0) |
||||
_volume_decrease_cb(NULL, NULL); |
||||
else if (ev->z < 0) |
||||
_volume_increase_cb(NULL, NULL); |
||||
} |
||||
|
||||
/*
|
||||
* Gadcon functions |
||||
*/ |
||||
static E_Gadcon_Client * |
||||
_gc_init(E_Gadcon *gc, const char *name, const char *id, const char *style) |
||||
{ |
||||
E_Gadcon_Client *gcc; |
||||
Instance *inst; |
||||
|
||||
inst = E_NEW(Instance, 1); |
||||
|
||||
inst->gadget = edje_object_add(gc->evas); |
||||
inst->evas = gc->evas; |
||||
e_theme_edje_object_set(inst->gadget, |
||||
"base/theme/modules/mixer", |
||||
"e/modules/mixer/main"); |
||||
|
||||
gcc = e_gadcon_client_new(gc, name, id, style, inst->gadget); |
||||
gcc->data = inst; |
||||
inst->gcc = gcc; |
||||
|
||||
evas_object_event_callback_add(inst->gadget, EVAS_CALLBACK_MOUSE_DOWN, |
||||
_mouse_down_cb, inst); |
||||
evas_object_event_callback_add(inst->gadget, EVAS_CALLBACK_MOUSE_WHEEL, |
||||
_mouse_wheel_cb, inst); |
||||
mixer_context->instances = eina_list_append(mixer_context->instances, inst); |
||||
|
||||
if (mixer_context->sink_default) |
||||
_mixer_gadget_update(); |
||||
|
||||
return gcc; |
||||
} |
||||
|
||||
static void |
||||
_gc_shutdown(E_Gadcon_Client *gcc) |
||||
{ |
||||
Instance *inst; |
||||
|
||||
inst = gcc->data; |
||||
evas_object_del(inst->gadget); |
||||
mixer_context->instances = eina_list_remove(mixer_context->instances, inst); |
||||
free(inst); |
||||
} |
||||
|
||||
static void |
||||
_gc_orient(E_Gadcon_Client *gcc, E_Gadcon_Orient orient EINA_UNUSED) |
||||
{ |
||||
e_gadcon_client_aspect_set(gcc, 16, 16); |
||||
e_gadcon_client_min_size_set(gcc, 16, 16); |
||||
} |
||||
|
||||
static const char * |
||||
_gc_label(const E_Gadcon_Client_Class *client_class EINA_UNUSED) |
||||
{ |
||||
return "Mixer"; |
||||
} |
||||
|
||||
static Evas_Object * |
||||
_gc_icon(const E_Gadcon_Client_Class *client_class EINA_UNUSED, Evas *evas) |
||||
{ |
||||
Evas_Object *o; |
||||
char buf[4096] = { 0 }; |
||||
|
||||
o = edje_object_add(evas); |
||||
snprintf(buf, sizeof(buf), "%s/e-module-mixer.edj", |
||||
e_module_dir_get(mixer_context->module)); |
||||
edje_object_file_set(o, buf, "icon"); |
||||
|
||||
return o; |
||||
} |
||||
|
||||
static const char * |
||||
_gc_id_new(const E_Gadcon_Client_Class *client_class EINA_UNUSED) |
||||
{ |
||||
return _gadcon_class.name; |
||||
} |
||||
|
||||
static void |
||||
_sink_event(int type, void *info) |
||||
{ |
||||
Emix_Sink *sink = info; |
||||
const Eina_List *l; |
||||
|
||||
if (type == EMIX_SINK_REMOVED_EVENT) |
||||
{ |
||||
if (sink == mixer_context->sink_default) |
||||
{ |
||||
l = emix_sinks_get(); |
||||
mixer_context->sink_default = l->data; |
||||
_mixer_gadget_update(); |
||||
} |
||||
} |
||||
else if (type == EMIX_SINK_CHANGED_EVENT) |
||||
{ |
||||
if (mixer_context->sink_default == sink) |
||||
{ |
||||
_mixer_gadget_update(); |
||||
_notify(sink->mute ? 0 : sink->volume.volumes[0]); |
||||
} |
||||
} |
||||
else |
||||
{ |
||||
DBG("Sink added"); |
||||
} |
||||
} |
||||
|
||||
static void |
||||
_disconnected(void) |
||||
{ |
||||
if (mixer_context) mixer_context->sink_default = NULL; |
||||
_mixer_gadget_update(); |
||||
} |
||||
|
||||
static void |
||||
_ready(void) |
||||
{ |
||||
if (emix_sink_default_support()) |
||||
mixer_context->sink_default = emix_sink_default_get(); |
||||
else |
||||
mixer_context->sink_default = emix_sinks_get()->data; |
||||
|
||||
_mixer_gadget_update(); |
||||
} |
||||
|
||||
static void |
||||
_events_cb(void *data EINA_UNUSED, enum Emix_Event type, void *event_info) |
||||
{ |
||||
switch (type) |
||||
{ |
||||
case EMIX_SINK_ADDED_EVENT: |
||||
case EMIX_SINK_CHANGED_EVENT: |
||||
case EMIX_SINK_REMOVED_EVENT: |
||||
_sink_event(type, event_info); |
||||
break; |
||||
case EMIX_DISCONNECTED_EVENT: |
||||
_disconnected(); |
||||
break; |
||||
case EMIX_READY_EVENT: |
||||
_ready(); |
||||
break; |
||||
default: |
||||
break; |
||||
} |
||||
} |
||||
|
||||
static Eina_Bool |
||||
_desklock_cb(void *data EINA_UNUSED, int type EINA_UNUSED, void *info) |
||||
{ |
||||
E_Event_Desklock *ev = info; |
||||
static Eina_Bool _was_mute = EINA_FALSE; |
||||
|
||||
if (emix_config_desklock_mute_get() == EINA_FALSE) |
||||
return ECORE_CALLBACK_PASS_ON; |
||||
|
||||
if (ev->on) |
||||
{ |
||||
_was_mute = mixer_context->sink_default->mute; |
||||
if (!_was_mute) |
||||
emix_sink_mute_set((Emix_Sink *)mixer_context->sink_default, EINA_TRUE); |
||||
} |
||||
else |
||||
{ |
||||
if (!_was_mute) |
||||
emix_sink_mute_set((Emix_Sink *)mixer_context->sink_default, EINA_FALSE); |
||||
} |
||||
|
||||
return ECORE_CALLBACK_PASS_ON; |
||||
} |
||||
|
||||
static void |
||||
_backend_changed(const char *backend, void *data EINA_UNUSED) |
||||
{ |
||||
_disconnected(); |
||||
|
||||
if (emix_backend_set(backend) == EINA_FALSE) |
||||
ERR("Could not load backend: %s", backend); |
||||
} |
||||
|
||||
E_API void * |
||||
e_modapi_init(E_Module *m) |
||||
{ |
||||
Eina_List *l; |
||||
char buf[4096]; |
||||
const char *backend; |
||||
Eina_Bool backend_loaded = EINA_FALSE; |
||||
|
||||
_e_emix_log_domain = eina_log_domain_register("mixer", EINA_COLOR_RED); |
||||
|
||||
if (!mixer_context) |
||||
{ |
||||
mixer_context = E_NEW(Context, 1); |
||||
|
||||
mixer_context->desklock_handler = |
||||
ecore_event_handler_add(E_EVENT_DESKLOCK, _desklock_cb, NULL); |
||||
mixer_context->module = m; |
||||
snprintf(buf, sizeof(buf), "%s/mixer.edj", |
||||
e_module_dir_get(mixer_context->module)); |
||||
mixer_context->theme = strdup(buf); |
||||
} |
||||
|
||||
|
||||
EINA_SAFETY_ON_FALSE_RETURN_VAL(emix_init(), NULL); |
||||
emix_config_init(_backend_changed, NULL); |
||||
emix_event_callback_add(_events_cb, NULL); |
||||
|
||||
backend = emix_config_backend_get(); |
||||
if (backend && emix_backend_set(backend)) |
||||
backend_loaded = EINA_TRUE; |
||||
else |
||||
{ |
||||
if (backend) |
||||
WRN("Could not load %s, trying another one ...", backend); |
||||
EINA_LIST_FOREACH((Eina_List *)emix_backends_available(), l, |
||||
backend) |
||||
{ |
||||
if (emix_backend_set(backend) == EINA_TRUE) |
||||
{ |
||||
DBG("Loaded backend: %s!", backend); |
||||
backend_loaded = EINA_TRUE; |
||||
emix_config_backend_set(backend); |
||||
break; |
||||
} |
||||
} |
||||
} |
||||
|
||||
if (!backend_loaded) goto err; |
||||
|
||||
e_configure_registry_category_add("extensions", 90, _("Extensions"), NULL, |
||||
"preferences-extensions"); |
||||
e_configure_registry_item_add("extensions/emix", 30, _("Mixer"), NULL, |
||||
"preferences-desktop-mixer", |
||||
emix_config_popup_new); |
||||
|
||||
if (emix_sink_default_support()) |
||||
mixer_context->sink_default = emix_sink_default_get(); |
||||
|
||||
e_gadcon_provider_register(&_gadcon_class); |
||||
_actions_register(); |
||||
|
||||
return m; |
||||
|
||||
err: |
||||
emix_config_shutdown(); |
||||
emix_shutdown(); |
||||
return NULL; |
||||
} |
||||
|
||||
E_API int |
||||
e_modapi_shutdown(E_Module *m EINA_UNUSED) |
||||
{ |
||||
_actions_unregister(); |
||||
e_gadcon_provider_unregister((const E_Gadcon_Client_Class *)&_gadcon_class); |
||||
|
||||
if (mixer_context) |
||||
{ |
||||
free(mixer_context->theme); |
||||
E_FREE(mixer_context); |
||||
} |
||||
|
||||
emix_event_callback_del(_events_cb); |
||||
emix_shutdown(); |
||||
emix_config_shutdown(); |
||||
return 1; |
||||
} |
||||
|
||||
E_API int |
||||
e_modapi_save(E_Module *m EINA_UNUSED) |
||||
{ |
||||
return 1; |
||||
} |
||||
|
@ -0,0 +1,25 @@ |
||||
#ifndef _E_MOD_MAIN_H_ |
||||
#define _E_MOD_MAIN_H_ |
||||
|
||||
#define CONFIG_VERSION 1 |
||||
|
||||
extern int _e_emix_log_domain; |
||||
|
||||
#undef DBG |
||||
#undef INF |
||||
#undef WRN |
||||
#undef ERR |
||||
#undef CRIT |
||||
#define DBG(...) EINA_LOG_DOM_DBG(_e_emix_log_domain, __VA_ARGS__) |
||||
#define INF(...) EINA_LOG_DOM_INF(_e_emix_log_domain, __VA_ARGS__) |
||||
#define WRN(...) EINA_LOG_DOM_WARN(_e_emix_log_domain, __VA_ARGS__) |
||||
#define ERR(...) EINA_LOG_DOM_ERR(_e_emix_log_domain, __VA_ARGS__) |
||||
#define CRIT(...) EINA_LOG_DOM_CRIT(_e_emix_log_domain, __VA_ARGS__) |
||||
|
||||
E_API extern E_Module_Api e_modapi; |
||||
|
||||
E_API void *e_modapi_init(E_Module *m); |
||||
E_API int e_modapi_shutdown(E_Module *m); |
||||
E_API int e_modapi_save(E_Module *m); |
||||
|
||||
#endif /* _E_MOD_MAIN_H_ */ |
@ -0,0 +1,727 @@ |
||||
#include <Elementary.h> |
||||
#include "emix.h" |
||||
|
||||
Evas_Object *win; |
||||
Evas_Object *source_scroller, *sink_input_scroller, *sink_scroller; |
||||
Evas_Object *source_box, *sink_input_box, *sink_box; |
||||
|
||||
Eina_List *source_list = NULL, *sink_input_list = NULL, *sink_list = NULL; |
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static Eina_Bool |
||||
_backend_init(const char *back) |
||||
{ |
||||
const Eina_List *l; |
||||
const char *name; |
||||
|
||||
if (!back) back = "PULSEAUDIO"; |
||||
if (emix_backend_set(back)) return EINA_TRUE; |
||||
EINA_LIST_FOREACH(emix_backends_available(), l, name) |
||||
{ |
||||
if (emix_backend_set(name)) return EINA_TRUE; |
||||
} |
||||
return EINA_FALSE; |
||||
} |
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#define VOLSET(vol, srcvol, target, func) \ |
||||
do { \
|
||||
Emix_Volume _v; \
|
||||
_v.channel_count = srcvol.channel_count; \
|
||||
_v.volumes = calloc(srcvol.channel_count, sizeof(int)); \
|
||||
if (_v.volumes) { \
|
||||
unsigned int _i; \
|
||||
for (_i = 0; _i < _v.channel_count; _i++) _v.volumes[_i] = vol; \
|
||||
func(target, _v); \
|
||||
free(_v.volumes); \
|
||||
} \
|
||||
} while (0) |
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
static void |
||||
_cb_sink_port_change(void *data, |
||||
Evas_Object *obj, |
||||
void *event_info EINA_UNUSED) |
||||
{ |
||||
Emix_Port *port = data; |
||||
Evas_Object *bxv = evas_object_data_get(obj, "parent"); |
||||
Emix_Sink *sink = evas_object_data_get(bxv, "sink"); |
||||
elm_object_text_set(obj, port->description); |
||||
emix_sink_port_set(sink, port); |
||||
} |
||||
|
||||
static void |
||||
_cb_sink_volume_change(void *data, |
||||
Evas_Object *obj, |
||||
void *event_info EINA_UNUSED) |
||||
{ |
||||
Evas_Object *bxv = data; |
||||
Emix_Sink *sink = evas_object_data_get(bxv, "sink"); |
||||
double vol = elm_slider_value_get(obj); |
||||
VOLSET(vol, sink->volume, sink, emix_sink_volume_set); |
||||
} |
||||
|
||||
static void |
||||
_cb_sink_mute_change(void *data, |
||||
Evas_Object *obj, |
||||
void *event_info EINA_UNUSED) |
||||
{ |
||||
Evas_Object *bxv = data; |
||||
Emix_Sink *sink = evas_object_data_get(bxv, "sink"); |
||||
Evas_Object *sl = evas_object_data_get(bxv, "volume"); |
||||
Eina_Bool mute = elm_check_state_get(obj); |
||||
elm_object_disabled_set(sl, mute); |
||||
emix_sink_mute_set(sink, mute); |
||||
} |
||||
|
||||
static void |
||||
_emix_sink_add(Emix_Sink *sink) |
||||
{ |
||||
Evas_Object *bxv, *bx, *lb, *ck, *sl, *hv, *sep; |
||||
const Eina_List *l; |
||||
Emix_Port *port; |
||||
|
||||
bxv = elm_box_add(win); |
||||
sink_list = eina_list_append(sink_list, bxv); |
||||
evas_object_data_set(bxv, "sink", sink); |
||||
evas_object_size_hint_weight_set(bxv, EVAS_HINT_EXPAND, 0.0); |
||||
evas_object_size_hint_align_set(bxv, EVAS_HINT_FILL, 0.0); |
||||
|
||||
bx = elm_box_add(win); |
||||
elm_box_horizontal_set(bx, EINA_TRUE); |
||||
evas_object_size_hint_weight_set(bx, EVAS_HINT_EXPAND, 0.0); |
||||
evas_object_size_hint_align_set(bx, EVAS_HINT_FILL, 0.0); |
||||
elm_box_pack_end(bxv, bx); |
||||
evas_object_show(bx); |
||||
|
||||
lb = elm_label_add(win); |
||||
elm_object_text_set(lb, sink->name); |
||||
evas_object_size_hint_weight_set(lb, EVAS_HINT_EXPAND, 0.5); |
||||
evas_object_size_hint_align_set(lb, 0.0, 0.5); |
||||
elm_box_pack_end(bx, lb); |
||||
evas_object_show(lb); |
||||
|
||||
hv = elm_hoversel_add(win); |
||||
evas_object_data_set(hv, "parent", bxv); |
||||
evas_object_data_set(bxv, "port", hv); |
||||
elm_hoversel_hover_parent_set(hv, win); |
||||
EINA_LIST_FOREACH(sink->ports, l, port) |
||||
{ |
||||
elm_hoversel_item_add(hv, port->description, |
||||
NULL, ELM_ICON_NONE, |
||||
_cb_sink_port_change, port); |
||||
if (port->active) elm_object_text_set(hv, port->description); |
||||
} |
||||
evas_object_size_hint_weight_set(hv, 0.0, 0.5); |
||||
evas_object_size_hint_align_set(hv, EVAS_HINT_FILL, 0.5); |
||||
elm_box_pack_end(bx, hv); |
||||
evas_object_show(hv); |
||||
|
||||
bx = elm_box_add(win); |
||||
elm_box_horizontal_set(bx, EINA_TRUE); |
||||
evas_object_size_hint_weight_set(bx, EVAS_HINT_EXPAND, 0.0); |
||||
evas_object_size_hint_align_set(bx, EVAS_HINT_FILL, 0.0); |
||||
elm_box_pack_end(bxv, bx); |
||||
evas_object_show(bx); |
||||
|
||||
sl = elm_slider_add(win); |
||||
evas_object_data_set(bxv, "volume", sl); |
||||
elm_slider_min_max_set(sl, 0.0, 100.0); |
||||
elm_slider_span_size_set(sl, 100 * elm_config_scale_get()); |
||||
elm_slider_unit_format_set(sl, "%1.0f"); |
||||
elm_slider_indicator_format_set(sl, "%1.0f"); |
||||
evas_object_size_hint_weight_set(sl, EVAS_HINT_EXPAND, 0.5); |
||||
evas_object_size_hint_align_set(sl, EVAS_HINT_FILL, 0.5); |
||||
elm_slider_value_set(sl, sink->volume.volumes[0]); |
||||
elm_box_pack_end(bx, sl); |
||||
evas_object_show(sl); |
||||
evas_object_smart_callback_add(sl, "changed", _cb_sink_volume_change, bxv); |
||||
|
||||
ck = elm_check_add(win); |
||||
evas_object_data_set(bxv, "mute", ck); |
||||
elm_object_text_set(ck, "Mute"); |
||||
elm_check_state_set(ck, sink->mute); |
||||
elm_object_disabled_set(sl, sink->mute); |
||||
elm_box_pack_end(bx, ck); |
||||
evas_object_show(ck); |
||||
evas_object_smart_callback_add(ck, "changed", _cb_sink_mute_change, bxv); |
||||
|
||||
sep = elm_separator_add(win); |
||||
elm_separator_horizontal_set(sep, EINA_TRUE); |
||||
evas_object_size_hint_weight_set(sep, EVAS_HINT_EXPAND, 0.0); |
||||
evas_object_size_hint_align_set(sep, EVAS_HINT_FILL, 0.0); |
||||
elm_box_pack_end(bxv, sep); |
||||
evas_object_show(sep); |
||||
|
||||
elm_box_pack_end(sink_box, bxv); |
||||
evas_object_show(bxv); |
||||
} |
||||
|
||||
static void |
||||
_emix_sink_del(Emix_Sink *sink) |
||||
{ |
||||
Eina_List *l; |
||||
Evas_Object *bxv; |
||||
EINA_LIST_FOREACH(sink_list, l, bxv) |
||||
{ |
||||
if (evas_object_data_get(bxv, "sink") == sink) |
||||
{ |
||||
sink_list = eina_list_remove_list(sink_list, l); |
||||
evas_object_del(bxv); |
||||
return; |
||||
} |
||||
} |
||||
} |
||||
|
||||
static void |
||||
_emix_sink_change(Emix_Sink *sink) |
||||
{ |
||||
const Eina_List *l; |
||||
Evas_Object *bxv, *hv, *ck, *sl; |
||||
Emix_Port *port; |
||||
|
||||
EINA_LIST_FOREACH(sink_list, l, bxv) |
||||
{ |
||||
if (evas_object_data_get(bxv, "sink") == sink) break; |
||||
} |
||||
if (!l) return; |
||||
hv = evas_object_data_get(bxv, "port"); |
||||
elm_hoversel_clear(hv); |
||||
EINA_LIST_FOREACH(sink->ports, l, port) |
||||
{ |
||||
elm_hoversel_item_add(hv, port->description, |
||||
NULL, ELM_ICON_NONE, |
||||
_cb_sink_port_change, port); |
||||
if (port->active) elm_object_text_set(hv, port->description); |
||||
} |
||||
sl = evas_object_data_get(bxv, "volume"); |
||||
elm_slider_value_set(sl, sink->volume.volumes[0]); |
||||
|
||||
ck = evas_object_data_get(bxv, "mute"); |
||||
elm_check_state_set(ck, sink->mute); |
||||
elm_object_disabled_set(sl, sink->mute); |
||||
} |
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static void |
||||
_cb_sink_input_port_change(void *data, |
||||
Evas_Object *obj, |
||||
void *event_info EINA_UNUSED) |
||||
{ |
||||
Emix_Sink *sink = data; |
||||
Evas_Object *bxv = evas_object_data_get(obj, "parent"); |
||||
Emix_Sink_Input *input = evas_object_data_get(bxv, "input"); |
||||
elm_object_text_set(obj, sink->name); |
||||
emix_sink_input_sink_change(input, sink); |
||||
} |
||||
|
||||
static void |
||||
_cb_sink_input_volume_change(void *data, |
||||
Evas_Object *obj, |
||||
void *event_info EINA_UNUSED) |
||||
{ |
||||
Evas_Object *bxv = data; |
||||
Emix_Sink_Input *input = evas_object_data_get(bxv, "input"); |
||||
double vol = elm_slider_value_get(obj); |
||||
VOLSET(vol, input->volume, input, emix_sink_input_volume_set); |
||||
} |
||||
|
||||
static void |
||||
_cb_sink_input_mute_change(void *data, |
||||
Evas_Object * |