mixer: use the new e_client api to export volume control by app.
We use the pulseaudio backend to export volume control by app. This commit introduce 3 news shortcuts to control the volume with the current focused window. @features
This commit is contained in:
parent
06ea6cadbd
commit
307f0831ce
|
@ -14,6 +14,7 @@
|
||||||
|
|
||||||
int _e_emix_log_domain;
|
int _e_emix_log_domain;
|
||||||
static Eina_Bool init;
|
static Eina_Bool init;
|
||||||
|
static Eina_List *_client_sinks = NULL;
|
||||||
|
|
||||||
/* module requirements */
|
/* module requirements */
|
||||||
E_API E_Module_Api e_modapi =
|
E_API E_Module_Api e_modapi =
|
||||||
|
@ -62,6 +63,9 @@ struct _Context
|
||||||
E_Action *incr;
|
E_Action *incr;
|
||||||
E_Action *decr;
|
E_Action *decr;
|
||||||
E_Action *mute;
|
E_Action *mute;
|
||||||
|
E_Action *incr_app;
|
||||||
|
E_Action *decr_app;
|
||||||
|
E_Action *mute_app;
|
||||||
} actions;
|
} actions;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -241,6 +245,42 @@ _volume_mute_cb(E_Object *obj EINA_UNUSED, const char *params EINA_UNUSED)
|
||||||
if (emix_config_save_get()) e_config_save_queue();
|
if (emix_config_save_get()) e_config_save_queue();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
_volume_increase_app_cb(E_Object *obj EINA_UNUSED, const char *params EINA_UNUSED)
|
||||||
|
{
|
||||||
|
E_Client *ec;
|
||||||
|
|
||||||
|
ec = e_client_focused_get();
|
||||||
|
if (ec && ec->volume_control_enabled)
|
||||||
|
{
|
||||||
|
e_client_volume_set(ec, ec->volume + VOLUME_STEP);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
_volume_decrease_app_cb(E_Object *obj EINA_UNUSED, const char *params EINA_UNUSED)
|
||||||
|
{
|
||||||
|
E_Client *ec;
|
||||||
|
|
||||||
|
ec = e_client_focused_get();
|
||||||
|
if (ec && ec->volume_control_enabled)
|
||||||
|
{
|
||||||
|
e_client_volume_set(ec, ec->volume - VOLUME_STEP);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
_volume_mute_app_cb(E_Object *obj EINA_UNUSED, const char *params EINA_UNUSED)
|
||||||
|
{
|
||||||
|
E_Client *ec;
|
||||||
|
|
||||||
|
ec = e_client_focused_get();
|
||||||
|
if (ec && ec->volume_control_enabled)
|
||||||
|
{
|
||||||
|
e_client_volume_mute_set(ec, !ec->mute);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
_actions_register(void)
|
_actions_register(void)
|
||||||
{
|
{
|
||||||
|
@ -267,6 +307,30 @@ _actions_register(void)
|
||||||
e_action_predef_name_set("Mixer", _("Mute volume"), "volume_mute",
|
e_action_predef_name_set("Mixer", _("Mute volume"), "volume_mute",
|
||||||
NULL, NULL, 0);
|
NULL, NULL, 0);
|
||||||
}
|
}
|
||||||
|
mixer_context->actions.incr_app = e_action_add("volume_increase_app");
|
||||||
|
if (mixer_context->actions.incr_app)
|
||||||
|
{
|
||||||
|
mixer_context->actions.incr_app->func.go = _volume_increase_app_cb;
|
||||||
|
e_action_predef_name_set("Mixer",
|
||||||
|
_("Increase Volume of Focused Application"),
|
||||||
|
"volume_increase_app", NULL, NULL, 0);
|
||||||
|
}
|
||||||
|
mixer_context->actions.decr_app = e_action_add("volume_decrease_app");
|
||||||
|
if (mixer_context->actions.decr_app)
|
||||||
|
{
|
||||||
|
mixer_context->actions.decr_app->func.go = _volume_decrease_app_cb;
|
||||||
|
e_action_predef_name_set("Mixer",
|
||||||
|
_("Decrease Volume of Focused Application"),
|
||||||
|
"volume_decrease_app", NULL, NULL, 0);
|
||||||
|
}
|
||||||
|
mixer_context->actions.mute_app = e_action_add("volume_mute_app");
|
||||||
|
if (mixer_context->actions.mute_app)
|
||||||
|
{
|
||||||
|
mixer_context->actions.mute_app->func.go = _volume_mute_app_cb;
|
||||||
|
e_action_predef_name_set("Mixer",
|
||||||
|
_("Mute Volume of Focused Application"),
|
||||||
|
"volume_mute_app", NULL, NULL, 0);
|
||||||
|
}
|
||||||
|
|
||||||
e_comp_canvas_keys_ungrab();
|
e_comp_canvas_keys_ungrab();
|
||||||
e_comp_canvas_keys_grab();
|
e_comp_canvas_keys_grab();
|
||||||
|
@ -296,6 +360,30 @@ _actions_unregister(void)
|
||||||
mixer_context->actions.mute = NULL;
|
mixer_context->actions.mute = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (mixer_context->actions.incr_app)
|
||||||
|
{
|
||||||
|
e_action_predef_name_del("Mixer",
|
||||||
|
_("Increase Volume of Focuse Application"));
|
||||||
|
e_action_del("volume_increase_app");
|
||||||
|
mixer_context->actions.incr_app = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mixer_context->actions.decr_app)
|
||||||
|
{
|
||||||
|
e_action_predef_name_del("Mixer",
|
||||||
|
_("Decrease Volume of Focuse Application"));
|
||||||
|
e_action_del("volume_decrease_app");
|
||||||
|
mixer_context->actions.decr_app = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mixer_context->actions.incr_app)
|
||||||
|
{
|
||||||
|
e_action_predef_name_del("Mixer",
|
||||||
|
_("Mute Volume of Focuse Application"));
|
||||||
|
e_action_del("volume_mute_app");
|
||||||
|
mixer_context->actions.mute_app = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
e_comp_canvas_keys_ungrab();
|
e_comp_canvas_keys_ungrab();
|
||||||
e_comp_canvas_keys_grab();
|
e_comp_canvas_keys_grab();
|
||||||
}
|
}
|
||||||
|
@ -758,6 +846,126 @@ _ready(void)
|
||||||
init = EINA_FALSE;
|
init = EINA_FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
_sink_input_get(int *volume, Eina_Bool *muted, void *data)
|
||||||
|
{
|
||||||
|
Emix_Sink_Input *input;
|
||||||
|
|
||||||
|
input = data;
|
||||||
|
|
||||||
|
if (volume) *volume = input->volume.volumes[0];
|
||||||
|
if (muted) *muted = input->mute;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
_sink_input_set(int volume, Eina_Bool muted, void *data)
|
||||||
|
{
|
||||||
|
Emix_Sink_Input *input;
|
||||||
|
|
||||||
|
input = data;
|
||||||
|
|
||||||
|
VOLSET(volume, input->volume, input, emix_sink_input_volume_set);
|
||||||
|
emix_sink_input_mute_set(input, muted);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
_sink_input_min_get(void *data)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
_sink_input_max_get(void *data)
|
||||||
|
{
|
||||||
|
return emix_max_volume_get();
|
||||||
|
}
|
||||||
|
|
||||||
|
static pid_t
|
||||||
|
_get_ppid(pid_t pid)
|
||||||
|
{
|
||||||
|
int fd;
|
||||||
|
char buf[128];
|
||||||
|
char *s;
|
||||||
|
pid_t ppid;
|
||||||
|
|
||||||
|
/* Open the status info process file provided by kernel to get the parent
|
||||||
|
* process id. 'man 5 proc' and go to /proc/[pid]/stat to get information
|
||||||
|
* about the content of this file.
|
||||||
|
*/
|
||||||
|
snprintf(buf, sizeof(buf), "/proc/%d/stat", pid);
|
||||||
|
fd = open(buf, O_RDONLY);
|
||||||
|
if (fd == -1)
|
||||||
|
{
|
||||||
|
ERR("Can't open %s, maybee the process exited.", buf);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
read(fd, buf, sizeof(buf));
|
||||||
|
buf[sizeof(buf) - 1] = '0';
|
||||||
|
s = strrchr(buf, ')');
|
||||||
|
s += 3;
|
||||||
|
ppid = atoi(s);
|
||||||
|
close(fd);
|
||||||
|
return ppid;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
_sink_input_event(int type, Emix_Sink_Input *input)
|
||||||
|
{
|
||||||
|
Eina_List *clients, *l, *ll;
|
||||||
|
E_Client *ec;
|
||||||
|
E_Client_Volume_Sink *sink;
|
||||||
|
pid_t pid;
|
||||||
|
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
case EMIX_SINK_INPUT_ADDED_EVENT:
|
||||||
|
pid = input->pid;
|
||||||
|
while (42)
|
||||||
|
{
|
||||||
|
if (pid <= 1 || pid == getpid()) return;
|
||||||
|
clients = e_client_focus_stack_get();
|
||||||
|
EINA_LIST_FOREACH(clients, l, ec)
|
||||||
|
{
|
||||||
|
if ((ec->netwm.pid == pid) && (!ec->parent))
|
||||||
|
{
|
||||||
|
DBG("Sink found the client %s",
|
||||||
|
e_client_util_name_get(ec));
|
||||||
|
sink = e_client_volume_sink_new(_sink_input_get,
|
||||||
|
_sink_input_set,
|
||||||
|
_sink_input_min_get,
|
||||||
|
_sink_input_max_get,
|
||||||
|
input);
|
||||||
|
e_client_volume_sink_append(ec, sink);
|
||||||
|
_client_sinks = eina_list_append(_client_sinks, sink);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pid = _get_ppid(pid);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case EMIX_SINK_INPUT_REMOVED_EVENT:
|
||||||
|
EINA_LIST_FOREACH(_client_sinks, l, sink)
|
||||||
|
{
|
||||||
|
if (sink->data == input)
|
||||||
|
{
|
||||||
|
e_client_volume_sink_del(sink);
|
||||||
|
_client_sinks = eina_list_remove_list(_client_sinks, l);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case EMIX_SINK_INPUT_CHANGED_EVENT:
|
||||||
|
EINA_LIST_FOREACH(_client_sinks, l, sink)
|
||||||
|
{
|
||||||
|
if (sink->data == input)
|
||||||
|
{
|
||||||
|
e_client_volume_sink_update(sink);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
_events_cb(void *data EINA_UNUSED, enum Emix_Event type, void *event_info)
|
_events_cb(void *data EINA_UNUSED, enum Emix_Event type, void *event_info)
|
||||||
{
|
{
|
||||||
|
@ -774,6 +982,12 @@ _events_cb(void *data EINA_UNUSED, enum Emix_Event type, void *event_info)
|
||||||
case EMIX_READY_EVENT:
|
case EMIX_READY_EVENT:
|
||||||
_ready();
|
_ready();
|
||||||
break;
|
break;
|
||||||
|
case EMIX_SINK_INPUT_ADDED_EVENT:
|
||||||
|
case EMIX_SINK_INPUT_REMOVED_EVENT:
|
||||||
|
case EMIX_SINK_INPUT_CHANGED_EVENT:
|
||||||
|
_sink_input_event(type, event_info);
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -892,6 +1106,8 @@ err:
|
||||||
E_API int
|
E_API int
|
||||||
e_modapi_shutdown(E_Module *m EINA_UNUSED)
|
e_modapi_shutdown(E_Module *m EINA_UNUSED)
|
||||||
{
|
{
|
||||||
|
E_Client_Volume_Sink *sink;
|
||||||
|
|
||||||
_actions_unregister();
|
_actions_unregister();
|
||||||
e_gadcon_provider_unregister((const E_Gadcon_Client_Class *)&_gadcon_class);
|
e_gadcon_provider_unregister((const E_Gadcon_Client_Class *)&_gadcon_class);
|
||||||
|
|
||||||
|
@ -901,6 +1117,9 @@ e_modapi_shutdown(E_Module *m EINA_UNUSED)
|
||||||
E_FREE(mixer_context);
|
E_FREE(mixer_context);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
EINA_LIST_FREE(_client_sinks, sink)
|
||||||
|
e_client_volume_sink_del(sink);
|
||||||
|
|
||||||
emix_event_callback_del(_events_cb);
|
emix_event_callback_del(_events_cb);
|
||||||
emix_shutdown();
|
emix_shutdown();
|
||||||
emix_config_shutdown();
|
emix_config_shutdown();
|
||||||
|
|
|
@ -24,26 +24,6 @@ _backend_init(const char *back)
|
||||||
return EINA_FALSE;
|
return EINA_FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
#define VOLSET(vol, srcvol, target, func) \
|
|
||||||
do { \
|
|
||||||
Emix_Volume _v; \
|
|
||||||
int _pvol = srcvol.volumes[0]; \
|
|
||||||
if ((_pvol > 80) && (_pvol <= 100) && \
|
|
||||||
(vol > 100) && (vol < 120)) vol = 100; \
|
|
||||||
_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
|
static void
|
||||||
_cb_sink_port_change(void *data,
|
_cb_sink_port_change(void *data,
|
||||||
Evas_Object *obj,
|
Evas_Object *obj,
|
||||||
|
|
|
@ -308,6 +308,7 @@ _sink_input_cb(pa_context *c EINA_UNUSED, const pa_sink_input_info *info,
|
||||||
Sink_Input *input;
|
Sink_Input *input;
|
||||||
Eina_List *l;
|
Eina_List *l;
|
||||||
Sink *s;
|
Sink *s;
|
||||||
|
const char *t;
|
||||||
EINA_SAFETY_ON_NULL_RETURN(ctx);
|
EINA_SAFETY_ON_NULL_RETURN(ctx);
|
||||||
|
|
||||||
if (eol < 0)
|
if (eol < 0)
|
||||||
|
@ -340,6 +341,11 @@ _sink_input_cb(pa_context *c EINA_UNUSED, const pa_sink_input_info *info,
|
||||||
input->icon = eina_stringshare_add(_icon_from_properties(info->proplist));
|
input->icon = eina_stringshare_add(_icon_from_properties(info->proplist));
|
||||||
ctx->inputs = eina_list_append(ctx->inputs, input);
|
ctx->inputs = eina_list_append(ctx->inputs, input);
|
||||||
|
|
||||||
|
if ((t = pa_proplist_gets(info->proplist, PA_PROP_APPLICATION_PROCESS_ID)))
|
||||||
|
{
|
||||||
|
input->base.pid = atoi(t);
|
||||||
|
}
|
||||||
|
|
||||||
if (ctx->cb)
|
if (ctx->cb)
|
||||||
ctx->cb((void *)ctx->userdata, EMIX_SINK_INPUT_ADDED_EVENT,
|
ctx->cb((void *)ctx->userdata, EMIX_SINK_INPUT_ADDED_EVENT,
|
||||||
(Emix_Sink_Input *)input);
|
(Emix_Sink_Input *)input);
|
||||||
|
@ -353,6 +359,7 @@ _sink_input_changed_cb(pa_context *c EINA_UNUSED,
|
||||||
Sink_Input *input = NULL, *i;
|
Sink_Input *input = NULL, *i;
|
||||||
Sink *s = NULL;
|
Sink *s = NULL;
|
||||||
Eina_List *l;
|
Eina_List *l;
|
||||||
|
const char *t;
|
||||||
|
|
||||||
EINA_SAFETY_ON_NULL_RETURN(ctx);
|
EINA_SAFETY_ON_NULL_RETURN(ctx);
|
||||||
if (eol < 0)
|
if (eol < 0)
|
||||||
|
@ -393,6 +400,10 @@ _sink_input_changed_cb(pa_context *c EINA_UNUSED,
|
||||||
if (s->idx == (int)info->sink)
|
if (s->idx == (int)info->sink)
|
||||||
input->base.sink = (Emix_Sink *)s;
|
input->base.sink = (Emix_Sink *)s;
|
||||||
}
|
}
|
||||||
|
if ((t = pa_proplist_gets(info->proplist, PA_PROP_APPLICATION_PROCESS_ID)))
|
||||||
|
{
|
||||||
|
input->base.pid = atoi(t);
|
||||||
|
}
|
||||||
|
|
||||||
if (ctx->cb)
|
if (ctx->cb)
|
||||||
ctx->cb((void *)ctx->userdata, EMIX_SINK_INPUT_CHANGED_EVENT,
|
ctx->cb((void *)ctx->userdata, EMIX_SINK_INPUT_CHANGED_EVENT,
|
||||||
|
|
|
@ -64,6 +64,7 @@ typedef struct _Emix_Sink_Input {
|
||||||
Emix_Volume volume;
|
Emix_Volume volume;
|
||||||
Eina_Bool mute;
|
Eina_Bool mute;
|
||||||
Emix_Sink *sink;
|
Emix_Sink *sink;
|
||||||
|
pid_t pid;
|
||||||
} Emix_Sink_Input;
|
} Emix_Sink_Input;
|
||||||
|
|
||||||
typedef struct _Emix_Source {
|
typedef struct _Emix_Source {
|
||||||
|
@ -110,6 +111,26 @@ typedef struct _Emix_Backend {
|
||||||
Evas_Object* (*ebackend_advanced_options_add)(Evas_Object *parent);
|
Evas_Object* (*ebackend_advanced_options_add)(Evas_Object *parent);
|
||||||
} Emix_Backend;
|
} Emix_Backend;
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#define VOLSET(vol, srcvol, target, func) \
|
||||||
|
do { \
|
||||||
|
Emix_Volume _v; \
|
||||||
|
int _pvol = srcvol.volumes[0]; \
|
||||||
|
if ((_pvol > 80) && (_pvol <= 100) && \
|
||||||
|
(vol > 100) && (vol < 120)) vol = 100; \
|
||||||
|
_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)
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
|
||||||
E_API Eina_Bool emix_init(void);
|
E_API Eina_Bool emix_init(void);
|
||||||
E_API void emix_shutdown(void);
|
E_API void emix_shutdown(void);
|
||||||
|
|
Loading…
Reference in New Issue