empc/empc.c

695 lines
22 KiB
C

#include "empd.h"
#include "eldbus_empd_empc.h"
#include <Eldbus.h>
#include <Elementary.h>
#include "Empd_Common_Azy.h"
#include "empc.h"
#include "empc_parts.h"
#define WEIGHT evas_object_size_hint_weight_set
#define ALIGN evas_object_size_hint_align_set
#define EXPAND(X) WEIGHT((X), EVAS_HINT_EXPAND, EVAS_HINT_EXPAND)
#define FILL(X) ALIGN((X), EVAS_HINT_FILL, EVAS_HINT_FILL)
enum
{
MPD_STATE_UNKNOWN = 0,
MPD_STATE_STOP = 1,
MPD_STATE_PLAY = 2,
MPD_STATE_PAUSE = 3,
};
#define HIDE_TIMEOUT 3.0
static int empd_state = 0;
static Evas_Object *win = NULL;
static Evas_Object *bg = NULL;
static Evas_Object *layout = NULL;
static Eina_Bool overlays_locked = EINA_FALSE;
static Evas_Object *queue_list = NULL;
static Evas_Object *controls = NULL;
static Ecore_Timer *queue_list_hide_timer = NULL;
static Ecore_Timer *controls_hide_timer = NULL;
static Eina_Bool queue_list_hiding = EINA_FALSE;
static Eina_Bool queue_list_state = EINA_TRUE;
static Eina_Bool controls_hiding = EINA_FALSE;
static Eina_Bool controls_state = EINA_TRUE;
static Eldbus_Proxy *empd_proxy = NULL;
static Eina_List *handlers = NULL;
static Eina_Hash *empd_current_queue = NULL;
static int empd_songid = -1;
static unsigned int empd_song_track = 0;
static Eina_Stringshare *empd_song_title = NULL;
static Eina_Stringshare *empd_song_artist = NULL;
static Eina_Stringshare *empd_song_album = NULL;
static Elm_Object_Item *empd_song_item = NULL;
static unsigned int empd_song_length = 0;
static unsigned int empd_song_elapsed = 0;
static unsigned int empd_queue_length = 0;
static void
queue_list_hidden(void *d EINA_UNUSED, Evas_Object *o EINA_UNUSED, const char *sig EINA_UNUSED, const char *src EINA_UNUSED)
{
queue_list_state = queue_list_hiding = EINA_FALSE;
}
static Eina_Bool
queue_list_hide(void *d EINA_UNUSED)
{
queue_list_hide_timer = NULL;
queue_list_hiding = EINA_TRUE;
elm_object_signal_emit(layout, "empc,playlist,hide", "empc");
return EINA_FALSE;
}
static void
queue_list_show(void)
{
queue_list_hiding = EINA_FALSE;
evas_object_show(queue_list);
queue_list_state = EINA_TRUE;
elm_object_signal_emit(layout, "empc,playlist,show", "empc");
}
static void
controls_hidden(void *d EINA_UNUSED, Evas_Object *o EINA_UNUSED, const char *sig EINA_UNUSED, const char *src EINA_UNUSED)
{
controls_state = controls_hiding = EINA_FALSE;
}
static Eina_Bool
controls_hide(void *d EINA_UNUSED)
{
controls_hide_timer = NULL;
controls_hiding = EINA_TRUE;
elm_object_signal_emit(layout, "empc,controls,hide", "empc");
return EINA_FALSE;
}
static void
controls_show(void)
{
controls_hiding = EINA_FALSE;
evas_object_show(controls);
controls_state = EINA_TRUE;
elm_object_signal_emit(layout, "empc,controls,show", "empc");
}
static void
title_changed(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED, const char *sig EINA_UNUSED, const char *src EINA_UNUSED)
{
if (empd_song_track)
{
char buf[1024];
snprintf(buf, sizeof(buf), "%.2d - %s", empd_song_track, empd_song_title);
elm_object_part_text_set(layout, EMPC_BASE_TEXT_TITLE, buf);
}
else
elm_object_part_text_set(layout, EMPC_BASE_TEXT_TITLE, empd_song_title);
elm_object_signal_emit(layout, "empc,title,change,2", "empc");
}
static void
title_update(void)
{
char buf[4096];
const char *st;
switch (empd_state)
{
case MPD_STATE_STOP:
st = "Stopped";
break;
case MPD_STATE_PLAY:
st = "Playing";
break;
case MPD_STATE_PAUSE:
st = "Paused";
break;
case MPD_STATE_UNKNOWN:
default:
st = "Unknown State";
break;
}
snprintf(buf, sizeof(buf), "EMPC | %s - %s (%s)", empd_song_artist, empd_song_title, st);
elm_win_title_set(win, buf);
}
static Eina_Bool
status_update(int state)
{
Evas_Object *button, *ic, *o;
if (state == empd_state) return EINA_FALSE;
empd_state = state;
o = evas_object_data_get(win, "slider");
button = evas_object_data_get(win, "play_button");
ic = elm_object_content_get(button);
switch (state)
{
case MPD_STATE_UNKNOWN:
elm_object_signal_emit(o, "empc,state,unknown", "empc");
elm_icon_standard_set(ic, "media_player/play");
break;
case MPD_STATE_STOP:
elm_object_signal_emit(o, "empc,state,stopped", "empc");
elm_icon_standard_set(ic, "media_player/play");
break;
case MPD_STATE_PLAY:
elm_object_signal_emit(o, "empc,state,playing", "empc");
elm_icon_standard_set(ic, "media_player/pause");
break;
case MPD_STATE_PAUSE:
elm_object_signal_emit(o, "empc,state,paused", "empc");
elm_icon_standard_set(ic, "media_player/play");
break;
}
return EINA_TRUE;
}
static Eina_Bool
songid_update(int songid)
{
Elm_Object_Item *it, *itp = NULL;
if (empd_songid == songid) return EINA_FALSE;
if (empd_songid != -1)
itp = eina_hash_find(empd_current_queue, &empd_songid);
empd_song_item = it = eina_hash_find(empd_current_queue, &songid);
/* don't allow set until item exists */
if (!it) return EINA_TRUE;
empd_songid = songid;
if (itp)
{
elm_object_item_signal_emit(itp, "empc,state,not_playing", "empc");
elm_genlist_item_fields_update(itp, EMPC_PLAYLIST_TEXT_TIME, ELM_GENLIST_ITEM_FIELD_TEXT);
}
if (it)
{
elm_genlist_item_show(it, ELM_GENLIST_ITEM_SCROLLTO_MIDDLE);
elm_object_item_signal_emit(it, "empc,state,playing", "empc");
elm_genlist_item_fields_update(it, EMPC_PLAYLIST_TEXT_TIME, ELM_GENLIST_ITEM_FIELD_TEXT);
}
if (songid >= empd_songid)
elm_object_signal_emit(layout, "empc,title,change,next", "empc");
else
elm_object_signal_emit(layout, "empc,title,change,prev", "empc");
return EINA_TRUE;
}
void
empc_cover_done(const char *artist, const char *album, const char *uri, void *data, size_t size)
{
if (album)
{
if ((!empd_song_album) || strcasecmp(album, empd_song_album)) goto fail;
}
if ((!artist) || (!empd_song_artist) || strcasecmp(artist, empd_song_artist)) goto fail;
if (uri)
elm_image_file_set(bg, uri, NULL);
else
elm_image_memfile_set(bg, data, size, NULL, NULL);
return;
fail:
free(data);
}
static Eina_Bool
empc_connected(void *d EINA_UNUSED, int t EINA_UNUSED, Empd_Empc_Connected_Data *ev)
{
return ECORE_CALLBACK_RENEW;
}
static Eina_Bool
empc_disconnected(void *d EINA_UNUSED, int t EINA_UNUSED, Empd_Empc_Disconnected_Data *ev)
{
return ECORE_CALLBACK_RENEW;
}
static Eina_Bool
empc_current_song(void *d EINA_UNUSED, int t EINA_UNUSED, Empd_Empc_CurrentSong_Data *ev)
{
empd_song_track = ev->track;
/* yes, | is intentional. */
if (songid_update(ev->songid) |
eina_stringshare_replace(&empd_song_title, ev->title) |
eina_stringshare_replace(&empd_song_artist, ev->artist))
title_update();
if (eina_stringshare_replace(&empd_song_album, ev->album))
empc_glyr_gmpc_fetch_image(empd_song_artist, empd_song_album);
elm_object_part_text_set(layout, EMPC_BASE_TEXT_ARTIST, empd_song_artist);
elm_object_part_text_set(layout, EMPC_BASE_TEXT_ALBUM, empd_song_album);
return ECORE_CALLBACK_RENEW;
}
static Eina_Bool
empc_status(void *d EINA_UNUSED, int t EINA_UNUSED, Empd_Empc_Status_Data *ev)
{
Eina_Bool up = EINA_FALSE;
Evas_Object *o;
up = (empd_song_length != ev->song_length) || (empd_song_elapsed != ev->song_elapsed);
if (up)
{
o = evas_object_data_get(win, "slider");
empd_song_length = ev->song_length;
empd_song_elapsed = ev->song_elapsed;
elm_slider_value_set(o, (double)ev->song_elapsed / (double)ev->song_length);
if (empd_song_item && queue_list_state)
elm_genlist_item_fields_update(empd_song_item, EMPC_PLAYLIST_TEXT_TIME, ELM_GENLIST_ITEM_FIELD_TEXT);
}
up = songid_update(ev->songid);
if (up)
empd_empc_current_song_call(empd_proxy);
up |= status_update(ev->state);
if (up) title_update();
if (empd_queue_length != ev->queue_length)
{
/* load current playlist incrementally (max 30):
* - don't block daemon forever with large playlists
* - GREATLY decreases startup delay when showing list
* - don't block ui when receiving huge playlists
*/
unsigned int i, step = (ev->queue_length / 4) % 31;
for (i = 0; i < ev->queue_length; i += step)
empd_empc_queue_list_range_call(empd_proxy, i, i + step);
elm_genlist_clear(queue_list);
}
empd_queue_length = ev->queue_length;
return ECORE_CALLBACK_RENEW;
}
static void
queue_list_item_realize(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info)
{
Elm_Object_Item *it = event_info;
Empd_Empc_Song *so;
so = elm_object_item_data_get(it);
if (empd_songid == so->songid)
elm_object_item_signal_emit(it, "empc,state,playing", "empc");
else
elm_object_item_signal_emit(it, "empc,state,not_playing", "empc");
}
static void
queue_list_double_click(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info)
{
Elm_Object_Item *it = event_info;
Empd_Empc_Song *so;
so = elm_object_item_data_get(it);
empd_empc_play_id_call(empd_proxy, so->songid);
}
static void
queue_list_key_down(void *data EINA_UNUSED, Evas *e EINA_UNUSED, Evas_Object *obj, void *event_info)
{
Elm_Object_Item *it;
Empd_Empc_Song *so;
Evas_Event_Key_Down *ev = event_info;
if ((!strcmp(ev->keyname, "Enter")) || (!strcmp(ev->keyname, "Return")))
{
it = elm_genlist_selected_item_get(obj);
if (!it) return;
so = elm_object_item_data_get(it);
empd_empc_play_id_call(empd_proxy, so->songid);
}
else if (!strcmp(ev->keyname, "Delete"))
{
const Eina_List *l, *ll;
int start = -1, num;
l = elm_genlist_selected_items_get(obj);
if (!l) return;
EINA_LIST_FOREACH(l, ll, it)
{
/* check for contiguous selection */
so = elm_object_item_data_get(it);
if (start == -1)
start = so->song_pos, num = 1;
/* fragmentation detected */
if ((elm_genlist_item_next_get(it) != eina_list_data_get(ll->next)) &&
(elm_genlist_item_prev_get(it) != eina_list_data_get(ll->next))) //selections can go both ways
{
if (so->song_pos < start) //backwards selection
start = so->song_pos;
//fprintf(stderr, "DEL %d:%d\n", start, num);
empd_empc_delete_list_range_call(empd_proxy, start, num);
start = -1, num = 0;
}
else
num++;
}
}
}
static char *
queue_list_item_text_get(Empd_Empc_Song *so, Evas_Object *obj EINA_UNUSED, const char *part)
{
char buf[1024];
if (!strcmp(part, "elm.text"))
return strdup(so->title ?: so->uri);
if (!strcmp(part, EMPC_PLAYLIST_TEXT_TRACK))
{
if (!so->track) return NULL;
snprintf(buf, sizeof(buf), "%.2d", so->track);
return strdup(buf);
}
if (empd_songid == so->songid)
snprintf(buf, sizeof(buf), "%.2d:%.2d / %.2d:%.2d",
empd_song_elapsed / 60, empd_song_elapsed % 60,
empd_song_length / 60, empd_song_length % 60);
else
snprintf(buf, sizeof(buf), "%.2ld:%.2ld", so->duration / 60, so->duration % 60);
return strdup(buf);
}
static void
queue_list_item_del(Empd_Empc_Song *so, Evas_Object *obj EINA_UNUSED)
{
if (empd_song_item && (elm_object_item_data_get(empd_song_item) == so))
empd_song_item = NULL;
eina_hash_del_by_key(empd_current_queue, &so->songid);
Empd_Empc_Song_free(so);
}
static int
queue_list_sort(Elm_Object_Item *a, Elm_Object_Item *b)
{
Empd_Empc_Song *a1, *b1;
a1 = elm_object_item_data_get(a);
b1 = elm_object_item_data_get(b);
return a1->song_pos - b1->song_pos;
}
static Eina_Bool
empc_queue_list(void *d EINA_UNUSED, int t EINA_UNUSED, Empd_Empc_QueueList_Data *ev)
{
Empd_Array_Songs *songs = NULL;
Empd_Empc_Song *so;
static Elm_Genlist_Item_Class queue_itc = {
.item_style = "playlist",
.func = {
.text_get = (Elm_Genlist_Item_Text_Get_Cb)queue_list_item_text_get,
.del = (Elm_Genlist_Item_Del_Cb)queue_list_item_del
},
.version = ELM_GENLIST_ITEM_CLASS_VERSION
};
if (!azy_value_to_Empd_Array_Songs(ev->value, &songs))
{
EINA_LOG_ERR("conversion failure");
return ECORE_CALLBACK_RENEW;
}
EINA_LIST_FREE(songs->songs, so)
{
Elm_Object_Item *it;
it = eina_hash_find(empd_current_queue, &so->songid);
if (it)
{
Empd_Empc_Song *ss = elm_object_item_data_get(it);
if (Empd_Empc_Song_eq(so, ss))
Empd_Empc_Song_free(so);
else
{
Empd_Empc_Song_free(ss);
elm_object_item_data_set(it, so);
elm_genlist_item_update(it);
}
}
else
{
it = elm_genlist_item_sorted_insert(queue_list, &queue_itc, so, NULL, 0, (Eina_Compare_Cb)queue_list_sort, NULL, NULL);
eina_hash_add(empd_current_queue, &so->songid, it);
}
}
free(songs);
return ECORE_CALLBACK_RENEW;
}
static Evas_Object *
button_add(const char *icon)
{
Evas_Object *o, *ic;
o = elm_button_add(win);
elm_object_style_set(o, "controls");
elm_object_focus_allow_set(o, EINA_FALSE);
EXPAND(o);
FILL(o);
ic = elm_icon_add(win);
elm_image_resizable_set(ic, 0, 0);
elm_icon_standard_set(ic, icon);
elm_object_part_content_set(o, "icon", ic);
evas_object_show(ic);
evas_object_show(o);
return o;
}
static void
control_skip_back(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
{
empd_empc_previous_call(empd_proxy);
}
static void
control_stop(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
{
empd_empc_stop_call(empd_proxy);
}
static void
control_toggle(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
{
if (empd_state == MPD_STATE_PLAY)
empd_empc_pause_call(empd_proxy, EINA_TRUE);
else
empd_empc_play_call(empd_proxy);
}
static void
control_skip_forward(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
{
empd_empc_next_call(empd_proxy);
}
static Eina_Bool
status_poller(void *d EINA_UNUSED)
{
empd_empc_status_call(empd_proxy);
return EINA_TRUE;
}
static void
slider_seek(void *data EINA_UNUSED, Evas_Object *obj, void *event_info EINA_UNUSED)
{
double val;
val = elm_slider_value_get(obj);
empd_empc_seek_call(empd_proxy, empd_songid, lround(val * empd_song_length));
}
static void
layout_mouse_move(void *data EINA_UNUSED, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
{
if (queue_list_hide_timer) ecore_timer_reset(queue_list_hide_timer);
}
static void
queue_list_mouse_in(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED, const char *sig EINA_UNUSED, const char *src EINA_UNUSED)
{
E_FREE_FUNC(queue_list_hide_timer, ecore_timer_del);
if (queue_list_state && (!queue_list_hiding)) return;
queue_list_show();
}
static void
queue_list_mouse_out(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED, const char *sig EINA_UNUSED, const char *src EINA_UNUSED)
{
if (overlays_locked) return;
if (!queue_list_hide_timer)
queue_list_hide_timer = ecore_timer_add(HIDE_TIMEOUT, queue_list_hide, NULL);
}
static void
controls_mouse_in(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED, const char *sig EINA_UNUSED, const char *src EINA_UNUSED)
{
E_FREE_FUNC(controls_hide_timer, ecore_timer_del);
if (controls_state && (!controls_hiding)) return;
controls_show();
}
static void
controls_mouse_out(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED, const char *sig EINA_UNUSED, const char *src EINA_UNUSED)
{
if (overlays_locked) return;
if (!controls_hide_timer)
controls_hide_timer = ecore_timer_add(HIDE_TIMEOUT, controls_hide, NULL);
}
static void
key_down(void *data EINA_UNUSED, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, Evas_Event_Key_Down *ev)
{
if ((!strcmp(ev->keyname, "q")) && evas_key_modifier_is_set(ev->modifiers, "Control"))
ecore_main_loop_quit();
else if (!strcmp(ev->keyname, "F1"))
{
overlays_locked = !overlays_locked;
if (overlays_locked)
{
E_FREE_FUNC(queue_list_hide_timer, ecore_timer_del);
E_FREE_FUNC(controls_hide_timer, ecore_timer_del);
if (!controls_state)
controls_show();
if (!queue_list_state)
queue_list_show();
}
else
{
controls_hide(NULL);
queue_list_hide(NULL);
}
}
}
int
main(int argc, char *argv[])
{
Evas_Object *o, *hbox;
eldbus_init();
elm_init(argc, argv);
empc_glyr_gmpc_init();
elm_theme_overlay_add(NULL, "./empc.edj");
empd_current_queue = eina_hash_int32_new(NULL);
ecore_poller_add(ECORE_POLLER_CORE, 8, status_poller, NULL);
elm_policy_set(ELM_POLICY_QUIT, ELM_POLICY_QUIT_LAST_WINDOW_CLOSED);
empd_proxy = empd_empc_proxy_get(eldbus_connection_get(ELDBUS_CONNECTION_TYPE_SESSION), EMPD_METHOD_BASE, NULL);
E_LIST_HANDLER_APPEND(handlers, EMPD_EMPC_CONNECTED_EVENT, empc_connected, NULL);
E_LIST_HANDLER_APPEND(handlers, EMPD_EMPC_DISCONNECTED_EVENT, empc_disconnected, NULL);
E_LIST_HANDLER_APPEND(handlers, EMPD_EMPC_CURRENT_SONG_EVENT, empc_current_song, NULL);
E_LIST_HANDLER_APPEND(handlers, EMPD_EMPC_STATUS_EVENT, empc_status, NULL);
E_LIST_HANDLER_APPEND(handlers, EMPD_EMPC_QUEUE_LIST_EVENT, empc_queue_list, NULL);
empd_empc_status_call(empd_proxy);
win = elm_win_add(NULL, "empc", ELM_WIN_BASIC);
elm_win_title_set(win, "empc");
elm_win_autodel_set(win, 1);
{
Evas_Modifier_Mask ctrl;//, shift, alt;
Evas *e = evas_object_evas_get(win);
ctrl = evas_key_modifier_mask_get(e, "Control");
//shift = evas_key_modifier_mask_get(e, "Shift");
//alt = evas_key_modifier_mask_get(e, "Alt");
1 | evas_object_key_grab(win, "q", 0, ctrl, 1);
1 | evas_object_key_grab(win, "F1", 0, 0, 1);
}
evas_object_event_callback_add(win, EVAS_CALLBACK_KEY_DOWN, (Evas_Object_Event_Cb)key_down, NULL);
layout = elm_layout_add(win);
EXPAND(layout);
FILL(layout);
elm_win_resize_object_add(win, layout);
elm_layout_theme_set(layout, "layout", "empc", "base");
elm_object_signal_callback_add(layout, "empc,title,changed,1", "empc", title_changed, NULL);
elm_object_signal_callback_add(layout, "empc,playlist,mouse_in", "empc", queue_list_mouse_in, NULL);
elm_object_signal_callback_add(layout, "empc,playlist,mouse_out", "empc", queue_list_mouse_out, NULL);
evas_object_event_callback_add(layout, EVAS_CALLBACK_MOUSE_MOVE, layout_mouse_move, NULL);
evas_object_event_callback_add(layout, EVAS_CALLBACK_MOUSE_DOWN, layout_mouse_move, NULL);
evas_object_event_callback_add(layout, EVAS_CALLBACK_MOUSE_UP, layout_mouse_move, NULL);
evas_object_event_callback_add(layout, EVAS_CALLBACK_MOUSE_WHEEL, layout_mouse_move, NULL);
elm_object_signal_callback_add(layout, "empc,playlist,hidden", "empc", queue_list_hidden, NULL);
elm_object_signal_emit(layout, "empc,playlist,show", "empc");
queue_list_hide_timer = ecore_timer_add(HIDE_TIMEOUT, queue_list_hide, NULL);
elm_object_signal_callback_add(layout, "empc,controls,mouse_in", "empc", controls_mouse_in, NULL);
elm_object_signal_callback_add(layout, "empc,controls,mouse_out", "empc", controls_mouse_out, NULL);
elm_object_signal_callback_add(layout, "empc,controls,hidden", "empc", controls_hidden, NULL);
elm_object_signal_emit(layout, "empc,controls,show", "empc");
controls_hide_timer = ecore_timer_add(HIDE_TIMEOUT, controls_hide, NULL);
evas_object_show(layout);
bg = elm_image_add(win);
elm_object_part_content_set(layout, EMPC_BASE_SWALLOW_BACKGROUND, bg);
elm_image_fill_outside_set(bg, EINA_FALSE);
evas_object_show(bg);
controls = hbox = elm_box_add(win);
elm_box_horizontal_set(hbox, EINA_TRUE);
elm_box_homogeneous_set(hbox, EINA_TRUE);
EXPAND(hbox);
FILL(hbox);
evas_object_show(hbox);
o = button_add("media_player/prev");
evas_object_smart_callback_add(o, "clicked", control_skip_back, NULL);
elm_box_pack_end(hbox, o);
o = button_add("media_player/stop");
evas_object_smart_callback_add(o, "clicked", control_stop, NULL);
elm_box_pack_end(hbox, o);
o = button_add("media_player/play");
evas_object_data_set(win, "play_button", o);
evas_object_smart_callback_add(o, "clicked", control_toggle, NULL);
elm_box_pack_end(hbox, o);
o = button_add("media_player/next");
evas_object_smart_callback_add(o, "clicked", control_skip_forward, NULL);
elm_box_pack_end(hbox, o);
elm_object_part_content_set(layout, EMPC_BASE_SWALLOW_CONTROLS, hbox);
o = elm_slider_add(win);
elm_object_style_set(o, "player");
evas_object_data_set(win, "slider", o);
WEIGHT(o, EVAS_HINT_EXPAND, 0);
FILL(o);
evas_object_smart_callback_add(o, "changed", slider_seek, NULL);
elm_slider_min_max_set(o, 0.0, 1.0);
elm_object_part_content_set(layout, EMPC_BASE_SWALLOW_POSITION, o);
evas_object_show(o);
queue_list = o = elm_genlist_add(win);
evas_object_smart_callback_add(o, "realized", queue_list_item_realize, NULL);
evas_object_smart_callback_add(o, "clicked,double", queue_list_double_click, NULL);
evas_object_event_callback_add(o, EVAS_CALLBACK_KEY_DOWN, queue_list_key_down, NULL);
elm_genlist_multi_select_mode_set(o, ELM_OBJECT_MULTI_SELECT_MODE_WITH_CONTROL);
elm_genlist_homogeneous_set(o, EINA_TRUE);
elm_genlist_multi_select_set(o, 1);
elm_scroller_bounce_set(o, 0, 0);
elm_scroller_policy_set(o, ELM_SCROLLER_POLICY_OFF, ELM_SCROLLER_POLICY_AUTO);
elm_genlist_mode_set(o, ELM_LIST_COMPRESS);
EXPAND(o);
FILL(o);
elm_object_part_content_set(layout, EMPC_BASE_SWALLOW_PLAYLIST, o);
evas_object_show(o);
evas_object_focus_set(o, EINA_TRUE);
evas_object_show(win);
evas_object_resize(win, 300, 400);
elm_run();
return 0;
}