summaryrefslogtreecommitdiff
path: root/src/bin
diff options
context:
space:
mode:
authorFlavio Ceolin <flavio.ceolin@gmail.com>2013-09-01 19:41:13 -0300
committerFlavio Ceolin <flavio.ceolin@gmail.com>2014-04-03 16:23:04 -0300
commit196cdb70b84958dd827797f86e78abd798e48cf7 (patch)
treefa94c67c0794b8dd8d64b8e216daccc20801c584 /src/bin
parentc984cf740b8625571a5d1617e0c3911fc27c11f9 (diff)
Adding common code
Init/shutdown used libraries and including common headers.
Diffstat (limited to 'src/bin')
-rw-r--r--src/bin/main.c31
-rw-r--r--src/bin/main_window.c160
-rw-r--r--src/bin/main_window.h12
-rw-r--r--src/bin/playbacks_view.c375
-rw-r--r--src/bin/playbacks_view.h12
-rw-r--r--src/bin/sinks_view.c320
-rw-r--r--src/bin/sinks_view.h13
-rw-r--r--src/bin/sources_view.c263
-rw-r--r--src/bin/sources_view.h13
9 files changed, 1199 insertions, 0 deletions
diff --git a/src/bin/main.c b/src/bin/main.c
new file mode 100644
index 0000000..66cd35a
--- /dev/null
+++ b/src/bin/main.c
@@ -0,0 +1,31 @@
1#include <common.h>
2#include <epulse.h>
3#include "main_window.h"
4
5#define DEFAULT_HEIGHT 600
6#define DEFAULT_WIDTH 800
7
8EAPI int
9elm_main(int argc EINA_UNUSED, char *argv[] EINA_UNUSED)
10{
11 Evas_Object *win;
12
13 EINA_SAFETY_ON_FALSE_RETURN_VAL(epulse_common_init("epulse"), EXIT_FAILURE);
14 EINA_SAFETY_ON_FALSE_RETURN_VAL(epulse_init() > 0, EXIT_FAILURE);
15
16 win = main_window_add();
17 evas_object_resize(win, DEFAULT_WIDTH, DEFAULT_HEIGHT);
18 evas_object_show(win);
19
20 elm_run();
21
22 epulse_common_shutdown();
23 epulse_shutdown();
24 return 0;
25}
26
27/*
28 * Create the default main() that will work with both quicklaunch or
29 * regular applications.
30 */
31ELM_MAIN()
diff --git a/src/bin/main_window.c b/src/bin/main_window.c
new file mode 100644
index 0000000..6783384
--- /dev/null
+++ b/src/bin/main_window.c
@@ -0,0 +1,160 @@
1#include "main_window.h"
2
3#include "epulse.h"
4#include "playbacks_view.h"
5#include "sinks_view.h"
6#include "sources_view.h"
7
8#define MAIN_WINDOW_DATA "mainwindow.data"
9
10enum MAIN_SUBVIEWS {
11 PLAYBACKS,
12 OUTPUTS,
13 INPUTS
14};
15
16static const char *_views[] = {
17 "Playback",
18 "Output Devices",
19 "Input Devices"
20};
21
22typedef struct _Main_Window Main_Window;
23struct _Main_Window
24{
25 Evas_Object *win;
26 Evas_Object *toolbar;
27 Evas_Object *layout;
28 Evas_Object *naviframe;
29 Evas_Object *playbacks;
30 Evas_Object *inputs;
31 Evas_Object *outputs;
32 Elm_Object_Item *toolbar_items[3];
33 Elm_Object_Item *views[3];
34};
35
36static void
37_del_cb(void *data, Evas *e EINA_UNUSED, Evas_Object *o EINA_UNUSED,
38 void *event_info EINA_UNUSED)
39{
40 Main_Window *mw = data;
41
42 free(mw);
43}
44
45static void
46_delete_request_cb(void *data EINA_UNUSED, Evas_Object *o EINA_UNUSED,
47 void *event_info EINA_UNUSED)
48{
49 elm_exit();
50}
51
52static void
53_toolbar_item_cb(void *data, Evas_Object *obj EINA_UNUSED,
54 void *event_info EINA_UNUSED)
55{
56 Main_Window *mw = data;
57 Elm_Object_Item *it = elm_toolbar_selected_item_get(obj);
58
59 if (!mw->views[PLAYBACKS] || !mw->views[OUTPUTS] ||
60 !mw->views[INPUTS])
61 return;
62
63 if (it == mw->toolbar_items[PLAYBACKS])
64 elm_naviframe_item_promote(mw->views[PLAYBACKS]);
65 else if (it == mw->toolbar_items[OUTPUTS])
66 elm_naviframe_item_promote(mw->views[OUTPUTS]);
67 else
68 elm_naviframe_item_promote(mw->views[INPUTS]);
69}
70
71Evas_Object *
72main_window_add(void)
73{
74 Main_Window *mw;
75 Evas_Object *tmp, *box;
76 unsigned int i;
77
78 elm_theme_extension_add(NULL, EPULSE_THEME);
79 mw = calloc(1, sizeof(Main_Window));
80 if (!mw)
81 {
82 ERR("Could not allocate memmory to main window");
83 return NULL;
84 }
85
86 tmp = elm_win_add(NULL, PACKAGE_NAME, ELM_WIN_BASIC);
87 EINA_SAFETY_ON_NULL_GOTO(tmp, win_err);
88 evas_object_data_set(tmp, MAIN_WINDOW_DATA, mw);
89 evas_object_event_callback_add(tmp, EVAS_CALLBACK_DEL, _del_cb, mw);
90 elm_win_autodel_set(tmp, EINA_TRUE);
91 elm_win_title_set(tmp, "Efl Volume Control");
92 mw->win = tmp;
93
94 tmp = elm_bg_add(mw->win);
95 evas_object_size_hint_weight_set(tmp, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
96 evas_object_size_hint_align_set(tmp, EVAS_HINT_FILL, EVAS_HINT_FILL);
97 elm_win_resize_object_add(mw->win, tmp);
98 evas_object_show(tmp);
99
100 box = elm_box_add(mw->win);
101 evas_object_size_hint_weight_set(box, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
102 elm_box_horizontal_set(box, EINA_FALSE);
103 elm_win_resize_object_add(mw->win, box);
104 evas_object_show(box);
105
106 tmp = elm_toolbar_add(mw->win);
107 evas_object_size_hint_weight_set(tmp, EVAS_HINT_EXPAND, 0);
108 evas_object_size_hint_align_set(tmp, EVAS_HINT_FILL, EVAS_HINT_FILL);
109 elm_toolbar_select_mode_set(tmp, ELM_OBJECT_SELECT_MODE_ALWAYS);
110 elm_box_pack_start(box, tmp);
111 mw->toolbar = tmp;
112 evas_object_show(tmp);
113
114 tmp = elm_naviframe_add(mw->win);
115 elm_object_style_set(tmp, "no_transition");
116 elm_naviframe_prev_btn_auto_pushed_set(tmp, EINA_FALSE);
117 evas_object_size_hint_weight_set(tmp, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
118 evas_object_size_hint_align_set(tmp, EVAS_HINT_FILL, EVAS_HINT_FILL);
119 elm_box_pack_end(box, tmp);
120 evas_object_show(tmp);
121 mw->naviframe = tmp;
122
123 for (i = 0; i < EINA_C_ARRAY_LENGTH(_views); i++)
124 {
125 mw->toolbar_items[i] = elm_toolbar_item_append(mw->toolbar, NULL,
126 _views[i],
127 _toolbar_item_cb, mw);
128 }
129
130 evas_object_smart_callback_add(mw->win, "delete,request",
131 _delete_request_cb, mw);
132
133 /* Creating the playbacks view */
134 mw->playbacks = playbacks_view_add(mw->win);
135 evas_object_size_hint_weight_set(mw->playbacks, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
136 evas_object_size_hint_align_set(mw->playbacks, EVAS_HINT_FILL, EVAS_HINT_FILL);
137 evas_object_show(mw->playbacks);
138
139 /* Creating the outputs view */
140 mw->outputs = sinks_view_add(mw->win);
141 evas_object_size_hint_weight_set(mw->outputs, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
142 evas_object_size_hint_align_set(mw->outputs, EVAS_HINT_FILL, EVAS_HINT_FILL);
143 evas_object_show(mw->outputs);
144
145 /* Creating the inputs view */
146 mw->inputs = sources_view_add(mw->win);
147 evas_object_size_hint_weight_set(mw->inputs, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
148 evas_object_size_hint_align_set(mw->inputs, EVAS_HINT_FILL, EVAS_HINT_FILL);
149 evas_object_show(mw->inputs);
150
151 mw->views[INPUTS] = elm_naviframe_item_simple_push(mw->naviframe, mw->inputs);
152 mw->views[OUTPUTS] = elm_naviframe_item_simple_push(mw->naviframe, mw->outputs);
153 mw->views[PLAYBACKS] = elm_naviframe_item_simple_push(mw->naviframe, mw->playbacks);
154
155 return mw->win;
156
157 win_err:
158 free(mw);
159 return NULL;
160}
diff --git a/src/bin/main_window.h b/src/bin/main_window.h
new file mode 100644
index 0000000..dd63ae7
--- /dev/null
+++ b/src/bin/main_window.h
@@ -0,0 +1,12 @@
1#ifndef _MAIN_WINDOW_H_
2#define _MAIN_WINDOW_H_
3
4#include <common.h>
5
6#ifdef HAVE_CONFIG_H
7#include "config.h"
8#endif
9
10Evas_Object *main_window_add(void);
11
12#endif /* _MAIN_WINDOW_H_ */
diff --git a/src/bin/playbacks_view.c b/src/bin/playbacks_view.c
new file mode 100644
index 0000000..98edff4
--- /dev/null
+++ b/src/bin/playbacks_view.c
@@ -0,0 +1,375 @@
1#include "playbacks_view.h"
2
3#include "epulse.h"
4
5#define PLAYBACKS_KEY "playbacks.key"
6
7struct Sink
8{
9 int index;
10 const char *name;
11};
12
13struct Playbacks_View
14{
15 Evas_Object *self;
16 Evas_Object *genlist;
17 Elm_Genlist_Item_Class *itc;
18
19 Eina_List *inputs;
20 Eina_List *sinks;
21
22 Ecore_Event_Handler *sink_input_added;
23 Ecore_Event_Handler *sink_input_changed;
24 Ecore_Event_Handler *sink_input_removed;
25
26 Ecore_Event_Handler *sink_added;
27 Ecore_Event_Handler *sink_removed;
28};
29
30struct Sink_Input
31{
32 struct Playbacks_View *pv;
33
34 int index;
35 int sink_index;
36 pa_cvolume volume;
37 const char *name;
38 const char *icon;
39 Eina_Bool mute;
40
41 Elm_Object_Item *item;
42};
43
44static Eina_Bool
45_sink_input_add_cb(void *data, int type EINA_UNUSED,
46 void *info)
47{
48 struct Playbacks_View *pv = data;
49 Epulse_Event_Sink_Input *ev = info;
50 struct Sink_Input *input = calloc(1, sizeof(struct Sink_Input));
51 EINA_SAFETY_ON_NULL_RETURN_VAL(input, ECORE_CALLBACK_PASS_ON);
52
53 input->name = eina_stringshare_add(ev->base.name);
54 input->icon = eina_stringshare_add(ev->icon);
55 input->index = ev->base.index;
56 input->sink_index = ev->sink;
57 input->volume = ev->base.volume;
58 input->mute = ev->base.mute;
59 input->pv = pv;
60
61 pv->inputs = eina_list_append(pv->inputs, input);
62 input->item = elm_genlist_item_append(pv->genlist, pv->itc, input, NULL,
63 ELM_GENLIST_ITEM_NONE, NULL, pv);
64
65 return ECORE_CALLBACK_DONE;
66}
67
68static Eina_Bool
69_sink_input_removed_cb(void *data, int type EINA_UNUSED,
70 void *info)
71{
72 struct Playbacks_View *pv = data;
73 Epulse_Event_Sink_Input *ev = info;
74 Eina_List *l, *ll;
75 struct Sink_Input *input;
76
77 EINA_LIST_FOREACH_SAFE(pv->inputs, l, ll, input)
78 {
79 if (input->index == ev->base.index)
80 {
81 pv->inputs = eina_list_remove_list(pv->inputs, l);
82 elm_object_item_del(input->item);
83 break;
84 }
85 }
86
87 return ECORE_CALLBACK_DONE;
88}
89
90static Eina_Bool
91_sink_input_changed_cb(void *data, int type EINA_UNUSED,
92 void *info)
93{
94 struct Playbacks_View *pv = data;
95 Epulse_Event_Sink_Input *ev = info;
96 Eina_List *l;
97 struct Sink_Input *input;
98 Evas_Object *item = NULL;
99
100 EINA_LIST_FOREACH(pv->inputs, l, input)
101 {
102 if (input->index == ev->base.index)
103 {
104 pa_volume_t vol = pa_cvolume_avg(&ev->base.volume);
105
106 item = elm_object_item_part_content_get(input->item, "item");
107 input->volume = ev->base.volume;
108 if (item)
109 elm_slider_value_set(item, PA_VOLUME_TO_INT(vol));
110
111 item = elm_object_item_part_content_get(input->item, "mute");
112 input->mute = ev->base.mute;
113 if (item)
114 {
115 elm_check_state_set(item, input->mute);
116 }
117 break;
118 }
119 }
120
121 return ECORE_CALLBACK_DONE;
122}
123
124static Eina_Bool
125_sink_add_cb(void *data, int type EINA_UNUSED,
126 void *info)
127{
128 struct Playbacks_View *pv = data;
129 Epulse_Event_Sink *ev = info;
130 struct Sink *sink = calloc(1, sizeof(struct Sink));
131 EINA_SAFETY_ON_NULL_RETURN_VAL(sink, ECORE_CALLBACK_PASS_ON);
132
133 sink->name = eina_stringshare_add(ev->base.name);
134 sink->index = ev->base.index;
135
136 pv->sinks = eina_list_append(pv->sinks, sink);
137 elm_genlist_realized_items_update(pv->genlist);
138
139 return ECORE_CALLBACK_PASS_ON;
140}
141
142static Eina_Bool
143_sink_removed_cb(void *data, int type EINA_UNUSED,
144 void *info)
145{
146 struct Playbacks_View *pv = data;
147 Epulse_Event_Sink *ev = info;
148 Eina_List *l, *ll;
149 struct Sink *sink;
150
151 EINA_LIST_FOREACH_SAFE(pv->sinks, l, ll, sink)
152 {
153 if (sink->index == ev->base.index)
154 {
155 pv->sinks = eina_list_remove_list(pv->sinks, l);
156 break;
157 }
158 }
159
160 elm_genlist_realized_items_update(pv->genlist);
161 return ECORE_CALLBACK_PASS_ON;
162}
163
164static void
165_del_cb(void *data,
166 Evas *e EINA_UNUSED,
167 Evas_Object *o EINA_UNUSED,
168 void *event_info EINA_UNUSED)
169{
170 struct Playbacks_View *pv = data;
171 struct Sink *sink;
172 eina_list_free(pv->inputs);
173
174 EINA_LIST_FREE(pv->sinks, sink)
175 {
176 eina_stringshare_del(sink->name);
177 free(sink);
178 }
179
180#define ECORE_EVENT_HANDLER_DEL(_handle) \
181 if (pv->_handle) \
182 { \
183 ecore_event_handler_del(pv->_handle); \
184 pv->_handle = NULL; \
185 }
186
187 ECORE_EVENT_HANDLER_DEL(sink_input_added)
188 ECORE_EVENT_HANDLER_DEL(sink_input_changed)
189 ECORE_EVENT_HANDLER_DEL(sink_input_removed)
190 ECORE_EVENT_HANDLER_DEL(sink_added)
191 ECORE_EVENT_HANDLER_DEL(sink_removed)
192#undef ECORE_EVENT_HANDLER_DEL
193}
194
195static char *
196_item_text_get(void *data, Evas_Object *obj EINA_UNUSED, const char *part)
197{
198 struct Sink_Input *input = data;
199
200 if (!strcmp(part, "name"))
201 {
202 return strdup(input->name);
203 }
204
205 return NULL;
206}
207
208static void
209_item_del(void *data, Evas_Object *obj EINA_UNUSED)
210{
211 struct Sink_Input *input = data;
212
213 eina_stringshare_del(input->name);
214 eina_stringshare_del(input->icon);
215 free(input);
216}
217
218static void
219_volume_changed_cb(void *data, Evas_Object *o,
220 void *event_info EINA_UNUSED)
221{
222 struct Sink_Input *input = data;
223 double val = elm_slider_value_get(o);
224 pa_volume_t v = INT_TO_PA_VOLUME(val);
225
226 pa_cvolume_set(&input->volume, input->volume.channels, v);
227
228 epulse_sink_input_volume_set(input->index, input->volume);
229}
230
231static void
232_mute_changed_cb(void *data, Evas_Object *o EINA_UNUSED,
233 void *event_info EINA_UNUSED)
234{
235 struct Sink_Input *input = data;
236
237 if (!epulse_sink_input_mute_set(input->index, input->mute))
238 {
239 ERR("Could not mute the input: %d", input->index);
240 input->mute = !input->mute;
241 return;
242 }
243}
244
245static void
246_sink_selected(void *data, Evas_Object *obj, void *event_info)
247{
248 struct Sink_Input *input = data;
249 Elm_Object_Item *item = event_info;
250 struct Sink *sink = elm_object_item_data_get(item);
251
252 epulse_sink_input_move(input->index, sink->index);
253 elm_object_text_set(obj, sink->name);
254}
255
256static Evas_Object *
257_item_content_get(void *data, Evas_Object *obj, const char *part)
258{
259 Evas_Object *item = NULL;
260 struct Sink_Input *input = data;
261
262 if (!strcmp(part, "slider"))
263 {
264 pa_volume_t vol = pa_cvolume_avg(&input->volume);
265 item = elm_slider_add(obj);
266 EINA_SAFETY_ON_NULL_RETURN_VAL(item, NULL);
267
268 elm_slider_unit_format_set(item, "%1.0f");
269 elm_slider_indicator_format_set(item, "%1.0f");
270 elm_slider_span_size_set(item, 120);
271 elm_slider_min_max_set(item, 0.0, 100.0);
272 elm_slider_value_set(item, PA_VOLUME_TO_INT(vol));
273
274 evas_object_smart_callback_add(item, "delay,changed",
275 _volume_changed_cb, input);
276 }
277 else if (!strcmp(part, "mute"))
278 {
279 item = elm_check_add(obj);
280 EINA_SAFETY_ON_NULL_RETURN_VAL(item, NULL);
281
282 elm_object_style_set(item, "toggle");
283 elm_object_part_text_set(item, "off", "Mute");
284 elm_object_part_text_set(item, "on", "Unmute");
285
286 elm_check_state_set(item, input->mute);
287 elm_check_state_pointer_set(item, &input->mute);
288 evas_object_smart_callback_add(item, "changed", _mute_changed_cb,
289 input);
290 }
291 else if (!strcmp(part, "icon"))
292 {
293 EINA_SAFETY_ON_NULL_RETURN_VAL(input->icon, NULL);
294
295 item = elm_icon_add(obj);
296 EINA_SAFETY_ON_NULL_RETURN_VAL(item, NULL);
297
298 elm_icon_standard_set(item, input->icon);
299 }
300 else if (!strcmp(part, "hover"))
301 {
302 Eina_List *l;
303 struct Sink *sink;
304 item = elm_hoversel_add(obj);
305
306 EINA_LIST_FOREACH(input->pv->sinks, l, sink)
307 {
308 if (sink->index == input->sink_index)
309 elm_object_text_set(item, sink->name);
310 elm_hoversel_item_add(item, sink->name, NULL,
311 ELM_ICON_NONE, NULL, sink);
312 }
313 evas_object_smart_callback_add(item, "selected",
314 _sink_selected, input);
315 }
316
317 return item;
318}
319
320Evas_Object *
321playbacks_view_add(Evas_Object *parent)
322{
323 Evas_Object *layout;
324 struct Playbacks_View *pv;
325
326 pv = calloc(1, sizeof(struct Playbacks_View));
327 EINA_SAFETY_ON_NULL_RETURN_VAL(pv, NULL);
328
329 layout = epulse_layout_add(parent, "playbacks", "default");
330 EINA_SAFETY_ON_NULL_GOTO(layout, err);
331
332 evas_object_event_callback_add(layout, EVAS_CALLBACK_DEL, _del_cb, pv);
333
334 pv->genlist = elm_genlist_add(layout);
335 EINA_SAFETY_ON_NULL_GOTO(pv->genlist, err_genlist);
336
337 pv->sink_input_added = ecore_event_handler_add(SINK_INPUT_ADDED,
338 _sink_input_add_cb, pv);
339 pv->sink_input_added = ecore_event_handler_add(SINK_INPUT_CHANGED,
340 _sink_input_changed_cb, pv);
341 pv->sink_input_removed = ecore_event_handler_add(SINK_INPUT_REMOVED,
342 _sink_input_removed_cb, pv);
343 pv->sink_added = ecore_event_handler_add(SINK_ADDED,
344 _sink_add_cb, pv);
345 pv->sink_removed = ecore_event_handler_add(SINK_REMOVED,
346 _sink_removed_cb, pv);
347
348 pv->itc = elm_genlist_item_class_new();
349 EINA_SAFETY_ON_NULL_GOTO(pv->itc, err_genlist);
350 pv->itc->item_style = "playbacks";
351 pv->itc->func.text_get = _item_text_get;
352 pv->itc->func.content_get = _item_content_get;
353 pv->itc->func.del = _item_del;
354
355 evas_object_data_set(layout, PLAYBACKS_KEY, pv);
356 elm_layout_content_set(layout, "list", pv->genlist);
357
358 evas_object_size_hint_weight_set(pv->genlist, EVAS_HINT_EXPAND,
359 EVAS_HINT_EXPAND);
360 evas_object_size_hint_align_set(pv->genlist, EVAS_HINT_FILL,
361 EVAS_HINT_FILL);
362
363 return layout;
364
365 err_genlist:
366 ecore_event_handler_del(pv->sink_input_added);
367 ecore_event_handler_del(pv->sink_input_changed);
368 ecore_event_handler_del(pv->sink_input_removed);
369 ecore_event_handler_del(pv->sink_added);
370 ecore_event_handler_del(pv->sink_removed);
371 free(layout);
372 err:
373 free(pv);
374 return NULL;
375}
diff --git a/src/bin/playbacks_view.h b/src/bin/playbacks_view.h
new file mode 100644
index 0000000..a58d327
--- /dev/null
+++ b/src/bin/playbacks_view.h
@@ -0,0 +1,12 @@
1#ifndef _PLAYBACKS_VIEW_H_
2#define _PLAYBACKS_VIEW_H_
3
4#include "common.h"
5
6#ifdef HAVE_CONFIG_H
7#include "config.h"
8#endif
9
10Evas_Object *playbacks_view_add(Evas_Object *parent);
11
12#endif /* _PLAYBACKS_VIEW_H_ */
diff --git a/src/bin/sinks_view.c b/src/bin/sinks_view.c
new file mode 100644
index 0000000..7ddea2c
--- /dev/null
+++ b/src/bin/sinks_view.c
@@ -0,0 +1,320 @@
1#include "sinks_view.h"
2
3#include "epulse.h"
4
5#define SINKS_KEY "sinks.key"
6
7struct Sink
8{
9 int index;
10 pa_cvolume volume;
11 const char *name;
12 Eina_Bool mute;
13
14 Elm_Object_Item *item;
15 Eina_List *ports;
16};
17
18struct Sink_Port
19{
20 char *name;
21 Eina_Bool active;
22};
23
24struct Sinks_View
25{
26 Evas_Object *self;
27 Evas_Object *genlist;
28 Elm_Genlist_Item_Class *itc;
29
30 Eina_List *sinks;
31 Ecore_Event_Handler *sink_added;
32 Ecore_Event_Handler *sink_changed;
33 Ecore_Event_Handler *sink_removed;
34};
35
36
37static Eina_Bool
38_sink_add_cb(void *data, int type EINA_UNUSED, void *info)
39{
40 struct Sinks_View *sv = data;
41 struct Sink_Port *sp;
42 Epulse_Event_Sink *ev = info;
43 Port *port;
44 Eina_List *l;
45 struct Sink *sink = calloc(1, sizeof(struct Sink));
46 EINA_SAFETY_ON_NULL_RETURN_VAL(sink, ECORE_CALLBACK_PASS_ON);
47
48 sink->name = eina_stringshare_add(ev->base.name);
49 sink->index = ev->base.index;
50 sink->volume = ev->base.volume;
51 sink->mute = ev->base.mute;
52
53 EINA_LIST_FOREACH(ev->ports, l, port)
54 {
55 sp = calloc(1, sizeof(struct Sink_Port));
56 sp->name = strdup(port->name);
57 if (port->active)
58 sp->active = EINA_TRUE;
59 sink->ports = eina_list_append(sink->ports, sp);
60 }
61
62 sv->sinks = eina_list_append(sv->sinks, sink);
63 sink->item = elm_genlist_item_append(sv->genlist, sv->itc, sink, NULL,
64 ELM_GENLIST_ITEM_NONE, NULL, sv);
65
66 return ECORE_CALLBACK_PASS_ON;
67}
68
69static Eina_Bool
70_sink_removed_cb(void *data, int type EINA_UNUSED, void *info)
71{
72 struct Sinks_View *sv = data;
73 Epulse_Event_Sink *ev = info;
74 Eina_List *l, *ll;
75 struct Sink *sink;
76
77 EINA_LIST_FOREACH_SAFE(sv->sinks, l, ll, sink)
78 {
79 if (sink->index == ev->base.index)
80 {
81 sv->sinks = eina_list_remove_list(sv->sinks, l);
82 elm_object_item_del(sink->item);
83 break;
84 }
85 }
86
87 return ECORE_CALLBACK_PASS_ON;
88}
89
90static Eina_Bool
91_sink_changed_cb(void *data, int type EINA_UNUSED, void *info)
92{
93 struct Sinks_View *sv = data;
94 Epulse_Event_Sink *ev = info;
95 Eina_List *l;
96 struct Sink *sink;
97 Evas_Object *item = NULL;
98
99 EINA_LIST_FOREACH(sv->sinks, l, sink)
100 {
101 if (sink->index == ev->base.index)
102 {
103 pa_volume_t vol = pa_cvolume_avg(&ev->base.volume);
104
105 item = elm_object_item_part_content_get(sink->item, "slider");
106 sink->volume = ev->base.volume;
107 if (item)
108 elm_slider_value_set(item, PA_VOLUME_TO_INT(vol));
109
110 item = elm_object_item_part_content_get(sink->item, "mute");
111 sink->mute = ev->base.mute;
112 if (item)
113 elm_check_state_set(item, sink->mute);
114
115 break;
116 }
117 }
118
119 return ECORE_CALLBACK_DONE;
120}
121
122static void
123_del_cb(void *data, Evas *e EINA_UNUSED, Evas_Object *o EINA_UNUSED,
124 void *event_info EINA_UNUSED)
125{
126 struct Sinks_View *sv = data;
127
128 eina_list_free(sv->sinks);
129 if (sv->sink_added)
130 {
131 ecore_event_handler_del(sv->sink_added);
132 sv->sink_added = NULL;
133 }
134 if (sv->sink_changed)
135 {
136 ecore_event_handler_del(sv->sink_changed);
137 sv->sink_changed = NULL;
138 }
139 if (sv->sink_removed)
140 {
141 ecore_event_handler_del(sv->sink_removed);
142 sv->sink_removed = NULL;
143 }
144}
145
146static char *
147_item_text_get(void *data, Evas_Object *obj EINA_UNUSED, const char *part)
148{
149 struct Sink *sink = data;
150
151 if (!strcmp(part, "name"))
152 {
153 return strdup(sink->name);
154 }
155
156 return NULL;
157}
158
159static void
160_item_del(void *data, Evas_Object *obj EINA_UNUSED)
161{
162 struct Sink *sink = data;
163 struct Sink_Port *port;
164
165 eina_stringshare_del(sink->name);
166 EINA_LIST_FREE(sink->ports, port)
167 {
168 free(port->name);
169 free(port);
170 }
171 free(sink);
172}
173
174static void
175_volume_changed_cb(void *data, Evas_Object *o,
176 void *event_info EINA_UNUSED)
177{
178 struct Sink *sink = data;
179 double val = elm_slider_value_get(o);
180 pa_volume_t v = INT_TO_PA_VOLUME(val);
181
182 pa_cvolume_set(&sink->volume, sink->volume.channels, v);
183
184 epulse_sink_volume_set(sink->index, sink->volume);
185}
186
187static void
188_mute_changed_cb(void *data, Evas_Object *o EINA_UNUSED,
189 void *event_info EINA_UNUSED)
190{
191 struct Sink *sink = data;
192
193 if (!epulse_sink_mute_set(sink->index, sink->mute))
194 {
195 ERR("Could not mute the sink: %d", sink->index);
196 sink->mute = !sink->mute;
197 return;
198 }
199}
200
201static void
202_port_selected_cb(void *data, Evas_Object *o,
203 void *event_info EINA_UNUSED)
204{
205 struct Sink *sink = data;
206 Elm_Object_Item *item = event_info;
207 struct Sink_Port *port = elm_object_item_data_get(item);
208
209 if (!epulse_sink_port_set(sink->index, port->name))
210 ERR("Could not change the port");
211 else
212 elm_object_text_set(o, port->name);
213}
214
215static Evas_Object *
216_item_content_get(void *data, Evas_Object *obj, const char *part)
217{
218 Evas_Object *item = NULL;
219 struct Sink *sink = data;
220
221 if (!strcmp(part, "slider"))
222 {
223 pa_volume_t vol = pa_cvolume_avg(&sink->volume);
224 item = elm_slider_add(obj);
225 EINA_SAFETY_ON_NULL_RETURN_VAL(item, NULL);
226
227 elm_slider_unit_format_set(item, "%1.0f");
228 elm_slider_indicator_format_set(item, "%1.0f");
229 elm_slider_span_size_set(item, 120);
230 elm_slider_min_max_set(item, 0.0, 100.0);
231 elm_slider_value_set(item, PA_VOLUME_TO_INT(vol));
232 evas_object_smart_callback_add(item, "delay,changed",
233 _volume_changed_cb, sink);
234 }
235 else if (!strcmp(part, "mute"))
236 {
237 item = elm_check_add(obj);
238 EINA_SAFETY_ON_NULL_RETURN_VAL(item, NULL);
239
240 elm_object_style_set(item, "toggle");
241 elm_object_part_text_set(item, "off", "Mute");
242 elm_object_part_text_set(item, "on", "Unmute");
243
244 elm_check_state_set(item, sink->mute);
245 elm_check_state_pointer_set(item, &sink->mute);
246 evas_object_smart_callback_add(item, "changed", _mute_changed_cb,
247 sink);
248 }
249 else if (!strcmp(part, "hover"))
250 {
251 Eina_List *l;
252 struct Sink_Port *sp;
253
254 if (sink->ports)
255 item = elm_hoversel_add(obj);
256
257 EINA_LIST_FOREACH(sink->ports, l, sp)
258 {
259 elm_hoversel_item_add(item, sp->name, NULL,
260 ELM_ICON_NONE, NULL, sp);
261 if (sp->active)
262 elm_object_text_set(item, sp->name);
263 }
264 evas_object_smart_callback_add(item, "selected",
265 _port_selected_cb, sink);
266 }
267
268 return item;
269}
270
271
272Evas_Object *
273sinks_view_add(Evas_Object *parent)
274{
275 Evas_Object *layout;
276 struct Sinks_View *sv;
277
278 sv = calloc(1, sizeof(struct Sinks_View));
279 EINA_SAFETY_ON_NULL_RETURN_VAL(sv, NULL);
280
281 layout = epulse_layout_add(parent, "sinks", "default");
282 EINA_SAFETY_ON_NULL_GOTO(layout, err);
283
284 evas_object_event_callback_add(layout, EVAS_CALLBACK_DEL, _del_cb, sv);
285
286 sv->genlist = elm_genlist_add(layout);
287 EINA_SAFETY_ON_NULL_GOTO(sv->genlist, err_genlist);
288
289 sv->sink_added = ecore_event_handler_add(SINK_ADDED, _sink_add_cb, sv);
290 sv->sink_added = ecore_event_handler_add(SINK_CHANGED, _sink_changed_cb, sv);
291 sv->sink_removed = ecore_event_handler_add(SINK_REMOVED,
292 _sink_removed_cb, sv);
293
294 sv->itc = elm_genlist_item_class_new();
295 EINA_SAFETY_ON_NULL_GOTO(sv->itc, err_genlist);
296 sv->itc->item_style = "sinks";
297 sv->itc->func.text_get = _item_text_get;
298 sv->itc->func.content_get = _item_content_get;
299 sv->itc->func.del = _item_del;
300
301 evas_object_data_set(layout, SINKS_KEY, sv);
302 elm_layout_content_set(layout, "list", sv->genlist);
303
304 evas_object_size_hint_weight_set(sv->genlist, EVAS_HINT_EXPAND,
305 EVAS_HINT_EXPAND);
306 evas_object_size_hint_align_set(sv->genlist, EVAS_HINT_FILL,
307 EVAS_HINT_FILL);
308
309 return layout;
310
311 err_genlist:
312 ecore_event_handler_del(sv->sink_added);
313 ecore_event_handler_del(sv->sink_changed);
314 ecore_event_handler_del(sv->sink_removed);
315 free(layout);
316 err:
317 free(sv);
318
319 return NULL;
320}
diff --git a/src/bin/sinks_view.h b/src/bin/sinks_view.h
new file mode 100644
index 0000000..f222234
--- /dev/null
+++ b/src/bin/sinks_view.h
@@ -0,0 +1,13 @@
1#ifndef _SINKS_VIEW_H_
2#define _SINKS_VIEW_H_
3
4#include "common.h"
5
6#ifdef HAVE_CONFIG_H
7#include "config.h"
8#endif
9
10Evas_Object *sinks_view_add(Evas_Object *parent);
11
12
13#endif /* _SINKS_VIEW_H_ */
diff --git a/src/bin/sources_view.c b/src/bin/sources_view.c
new file mode 100644
index 0000000..aa6dafb
--- /dev/null
+++ b/src/bin/sources_view.c
@@ -0,0 +1,263 @@
1#include "sources_view.h"
2
3#include "epulse.h"
4
5#define SOURCES_KEY "sources.key"
6
7struct Source
8{
9 int index;
10 pa_cvolume volume;
11 const char *name;
12 Eina_Bool mute;
13
14 Elm_Object_Item *item;
15};
16
17struct Sources_View
18{
19 Evas_Object *self;
20 Evas_Object *genlist;
21 Elm_Genlist_Item_Class *itc;
22
23 Eina_List *sources;
24 Ecore_Event_Handler *source_added;
25 Ecore_Event_Handler *source_changed;
26 Ecore_Event_Handler *source_removed;
27};
28
29static Eina_Bool
30_source_add_cb(void *data, int type EINA_UNUSED, void *info)
31{
32 struct Sources_View *sv = data;
33 Epulse_Event *ev = info;
34 struct Source *source = calloc(1, sizeof(struct Source));
35 EINA_SAFETY_ON_NULL_RETURN_VAL(source, ECORE_CALLBACK_PASS_ON);
36
37 source->name = eina_stringshare_add(ev->name);
38 source->index = ev->index;
39 source->volume = ev->volume;
40 source->mute = ev->mute;
41
42 sv->sources = eina_list_append(sv->sources, source);
43 source->item = elm_genlist_item_append(sv->genlist, sv->itc, source, NULL,
44 ELM_GENLIST_ITEM_NONE, NULL, sv);
45
46 return ECORE_CALLBACK_DONE;
47}
48
49static Eina_Bool
50_source_removed_cb(void *data, int type EINA_UNUSED, void *info)
51{
52 struct Sources_View *sv = data;
53 Epulse_Event *ev = info;
54 Eina_List *l, *ll;
55 struct Source *source;
56
57 EINA_LIST_FOREACH_SAFE(sv->sources, l, ll, source)
58 {
59 if (source->index == ev->index)
60 {
61 sv->sources = eina_list_remove_list(sv->sources, l);
62 elm_object_item_del(source->item);
63 break;
64 }
65 }
66
67 return ECORE_CALLBACK_DONE;
68}
69
70static Eina_Bool
71_source_changed_cb(void *data, int type EINA_UNUSED, void *info)
72{
73 struct Sources_View *sv = data;
74 Epulse_Event *ev = info;
75 Eina_List *l;
76 struct Source *source;
77 Evas_Object *item = NULL;
78
79 EINA_LIST_FOREACH(sv->sources, l, source)
80 {
81 if (source->index == ev->index)
82 {
83 pa_volume_t vol = pa_cvolume_avg(&ev->volume);
84
85 item = elm_object_item_part_content_get(source->item, "slider");
86 source->volume = ev->volume;
87 if (item)
88 elm_slider_value_set(item, PA_VOLUME_TO_INT(vol));
89
90 item = elm_object_item_part_content_get(source->item, "mute");
91 source->mute = ev->mute;
92 if (item)
93 {
94 elm_check_state_set(item, source->mute);
95 }
96 break;
97 }
98 }
99
100 return ECORE_CALLBACK_DONE;
101}
102
103static void
104_del_cb(void *data, Evas *e EINA_UNUSED, Evas_Object *o EINA_UNUSED,
105 void *event_info EINA_UNUSED)
106{
107 struct Sources_View *sv = data;
108
109 eina_list_free(sv->sources);
110 if (sv->source_added)
111 {
112 ecore_event_handler_del(sv->source_added);
113 sv->source_added = NULL;
114 }
115 if (sv->source_changed)
116 {
117 ecore_event_handler_del(sv->source_changed);
118 sv->source_changed = NULL;
119 }
120 if (sv->source_removed)
121 {
122 ecore_event_handler_del(sv->source_removed);
123 sv->source_removed = NULL;
124 }
125}
126
127static char *
128_item_text_get(void *data, Evas_Object *obj EINA_UNUSED, const char *part)
129{
130 struct Source *source = data;
131
132 if (!strcmp(part, "name"))
133 {
134 return strdup(source->name);
135 }
136
137 return NULL;
138}
139
140static void
141_item_del(void *data, Evas_Object *obj EINA_UNUSED)
142{
143 struct Source *source = data;
144
145 eina_stringshare_del(source->name);
146 free(source);
147}
148
149static void
150_volume_changed_cb(void *data, Evas_Object *o,
151 void *event_info EINA_UNUSED)
152{
153 struct Source *source = data;
154 double val = elm_slider_value_get(o);
155 pa_volume_t v = INT_TO_PA_VOLUME(val);
156
157 pa_cvolume_set(&source->volume, source->volume.channels, v);
158
159 epulse_source_volume_set(source->index, source->volume);
160}
161
162static void
163_mute_changed_cb(void *data, Evas_Object *o EINA_UNUSED,
164 void *event_info EINA_UNUSED)
165{
166 struct Source *source = data;
167
168 if (!epulse_source_mute_set(source->index, source->mute))
169 {
170 ERR("Could not mute the source: %d", source->index);
171 source->mute = !source->mute;
172 return;
173 }
174}
175
176static Evas_Object *
177_item_content_get(void *data, Evas_Object *obj, const char *part)
178{
179 Evas_Object *item = NULL;
180 struct Source *source = data;
181
182 if (!strcmp(part, "slider"))
183 {
184 pa_volume_t vol = pa_cvolume_avg(&source->volume);
185 item = elm_slider_add(obj);
186 EINA_SAFETY_ON_NULL_RETURN_VAL(item, NULL);
187
188 elm_slider_unit_format_set(item, "%1.0f");
189 elm_slider_indicator_format_set(item, "%1.0f");
190 elm_slider_span_size_set(item, 120);
191 elm_slider_min_max_set(item, 0.0, 100.0);
192 elm_slider_value_set(item, PA_VOLUME_TO_INT(vol));
193 evas_object_smart_callback_add(item, "delay,changed",
194 _volume_changed_cb, source);
195 }
196 else if (!strcmp(part, "mute"))
197 {
198 item = elm_check_add(obj);
199 EINA_SAFETY_ON_NULL_RETURN_VAL(item, NULL);
200
201 elm_object_style_set(item, "toggle");
202 elm_object_part_text_set(item, "off", "Mute");
203 elm_object_part_text_set(item, "on", "Unmute");
204
205 elm_check_state_set(item, source->mute);
206 elm_check_state_pointer_set(item, &source->mute);
207 evas_object_smart_callback_add(item, "changed", _mute_changed_cb,
208 source);
209 }
210
211 return item;
212}
213
214Evas_Object *
215sources_view_add(Evas_Object *parent)
216{
217 Evas_Object *layout;
218 struct Sources_View *sv;
219
220 sv = calloc(1, sizeof(struct Sources_View));
221 EINA_SAFETY_ON_NULL_RETURN_VAL(sv, NULL);
222
223 layout = epulse_layout_add(parent, "sources", "default");
224 EINA_SAFETY_ON_NULL_GOTO(layout, err);
225
226 evas_object_event_callback_add(layout, EVAS_CALLBACK_DEL, _del_cb, sv);
227
228 sv->genlist = elm_genlist_add(layout);
229 EINA_SAFETY_ON_NULL_GOTO(sv->genlist, err_genlist);
230
231 sv->source_added = ecore_event_handler_add(SOURCE_ADDED, _source_add_cb, sv);
232 sv->source_added = ecore_event_handler_add(SOURCE_CHANGED,
233 _source_changed_cb, sv);
234 sv->source_removed = ecore_event_handler_add(SOURCE_REMOVED,
235 _source_removed_cb, sv);
236
237 sv->itc = elm_genlist_item_class_new();
238 EINA_SAFETY_ON_NULL_GOTO(sv->itc, err_genlist);
239 sv->itc->item_style = "sources";
240 sv->itc->func.text_get = _item_text_get;
241 sv->itc->func.content_get = _item_content_get;
242 sv->itc->func.del = _item_del;
243
244 evas_object_data_set(layout, SOURCES_KEY, sv);
245 elm_layout_content_set(layout, "list", sv->genlist);
246
247 evas_object_size_hint_weight_set(sv->genlist, EVAS_HINT_EXPAND,
248 EVAS_HINT_EXPAND);
249 evas_object_size_hint_align_set(sv->genlist, EVAS_HINT_FILL,
250 EVAS_HINT_FILL);
251
252 return layout;
253
254 err_genlist:
255 ecore_event_handler_del(sv->source_added);
256 ecore_event_handler_del(sv->source_changed);
257 ecore_event_handler_del(sv->source_removed);
258 free(layout);
259 err:
260 free(sv);
261
262 return NULL;
263}
diff --git a/src/bin/sources_view.h b/src/bin/sources_view.h
new file mode 100644
index 0000000..62697fe
--- /dev/null
+++ b/src/bin/sources_view.h
@@ -0,0 +1,13 @@
1#ifndef _SOURCES_VIEW_H_
2#define _SOURCES_VIEW_H_
3
4#include "common.h"
5
6#ifdef HAVE_CONFIG_H
7#include "config.h"
8#endif
9
10Evas_Object *sources_view_add(Evas_Object *parent);
11
12
13#endif /* _SOURCES_VIEW_H_ */