forked from enlightenment/enlightenment
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;
|
||||
static Eina_Bool init;
|
||||
static Eina_List *_client_sinks = NULL;
|
||||
|
||||
/* module requirements */
|
||||
E_API E_Module_Api e_modapi =
|
||||
|
@ -62,6 +63,9 @@ struct _Context
|
|||
E_Action *incr;
|
||||
E_Action *decr;
|
||||
E_Action *mute;
|
||||
E_Action *incr_app;
|
||||
E_Action *decr_app;
|
||||
E_Action *mute_app;
|
||||
} 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();
|
||||
}
|
||||
|
||||
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
|
||||
_actions_register(void)
|
||||
{
|
||||
|
@ -267,6 +307,30 @@ _actions_register(void)
|
|||
e_action_predef_name_set("Mixer", _("Mute volume"), "volume_mute",
|
||||
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_grab();
|
||||
|
@ -296,6 +360,30 @@ _actions_unregister(void)
|
|||
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_grab();
|
||||
}
|
||||
|
@ -758,6 +846,126 @@ _ready(void)
|
|||
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
|
||||
_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:
|
||||
_ready();
|
||||
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:
|
||||
break;
|
||||
}
|
||||
|
@ -892,6 +1106,8 @@ err:
|
|||
E_API int
|
||||
e_modapi_shutdown(E_Module *m EINA_UNUSED)
|
||||
{
|
||||
E_Client_Volume_Sink *sink;
|
||||
|
||||
_actions_unregister();
|
||||
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);
|
||||
}
|
||||
|
||||
EINA_LIST_FREE(_client_sinks, sink)
|
||||
e_client_volume_sink_del(sink);
|
||||
|
||||
emix_event_callback_del(_events_cb);
|
||||
emix_shutdown();
|
||||
emix_config_shutdown();
|
||||
|
|
|
@ -24,26 +24,6 @@ _backend_init(const char *back)
|
|||
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
|
||||
_cb_sink_port_change(void *data,
|
||||
Evas_Object *obj,
|
||||
|
|
|
@ -308,6 +308,7 @@ _sink_input_cb(pa_context *c EINA_UNUSED, const pa_sink_input_info *info,
|
|||
Sink_Input *input;
|
||||
Eina_List *l;
|
||||
Sink *s;
|
||||
const char *t;
|
||||
EINA_SAFETY_ON_NULL_RETURN(ctx);
|
||||
|
||||
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));
|
||||
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)
|
||||
ctx->cb((void *)ctx->userdata, EMIX_SINK_INPUT_ADDED_EVENT,
|
||||
(Emix_Sink_Input *)input);
|
||||
|
@ -353,6 +359,7 @@ _sink_input_changed_cb(pa_context *c EINA_UNUSED,
|
|||
Sink_Input *input = NULL, *i;
|
||||
Sink *s = NULL;
|
||||
Eina_List *l;
|
||||
const char *t;
|
||||
|
||||
EINA_SAFETY_ON_NULL_RETURN(ctx);
|
||||
if (eol < 0)
|
||||
|
@ -393,6 +400,10 @@ _sink_input_changed_cb(pa_context *c EINA_UNUSED,
|
|||
if (s->idx == (int)info->sink)
|
||||
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)
|
||||
ctx->cb((void *)ctx->userdata, EMIX_SINK_INPUT_CHANGED_EVENT,
|
||||
|
|
|
@ -64,6 +64,7 @@ typedef struct _Emix_Sink_Input {
|
|||
Emix_Volume volume;
|
||||
Eina_Bool mute;
|
||||
Emix_Sink *sink;
|
||||
pid_t pid;
|
||||
} Emix_Sink_Input;
|
||||
|
||||
typedef struct _Emix_Source {
|
||||
|
@ -110,6 +111,26 @@ typedef struct _Emix_Backend {
|
|||
Evas_Object* (*ebackend_advanced_options_add)(Evas_Object *parent);
|
||||
} 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 void emix_shutdown(void);
|
||||
|
|
Loading…
Reference in New Issue