empc/src/bin/empc.c

4252 lines
142 KiB
C

#include "empc_private.h"
#include "eldbus_empd_empdd.h"
#include "eldbus_empd_empc.h"
#define EMPC_METHOD_BASE "org.empd.empc"
#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)
typedef enum
{
EMPC_SIGNAL_BACKGROUND_CHANGED,
} EMPC_Signals;
typedef struct Empc_Entity
{
int type;
void *value;
} Empc_Entity;
static Eina_Bool selecting, unselecting;
Eina_Bool master = EINA_FALSE;
static Eina_Bool bg_updated = EINA_FALSE;
static Eina_Stringshare *empd_host;
static unsigned int empd_port;
static Eldbus_Pending *config_call;
static int empd_state = 0;
static Evas_Object *win = NULL;
static Evas_Object *bg[2] = {NULL};
static Evas_Object *layout = NULL;
static Evas_Object *layout_filesystem = NULL;
static Eina_Bool ctxpopup_locked_overlay = EINA_FALSE;
static Eina_Bool overlay_locked_state = EINA_FALSE;
static Eina_Bool lyrics_visible = EINA_FALSE;
static Eina_Bool empd_connected = EINA_FALSE;
static Eina_Bool bgheader_dirty = EINA_FALSE;
static Eina_Bool bgchooser = EINA_FALSE;
static Empc_Fetch_Request *bgfetch = NULL;
static Eina_Bool bg_ignore = EINA_FALSE;
static Eina_Bool bg_pasting = EINA_FALSE;
static Eina_Bool queue_list_state = EINA_FALSE;
static Eina_Bool filesystem_state = EINA_FALSE;
static Evas_Object *ctxpopup = NULL;
EAPI Evas_Object *queue_list = NULL;
static Elm_Object_Item *queue_list_scroll_item = NULL;
static Eina_List *queue_list_realized = NULL;
static Eina_List *filesystems = NULL;
static Eina_List *filesystems_realized = NULL;
static Ecore_Idler *filesystem_idler = NULL;
static Elm_Object_Item *filesystem_idler_pos = NULL;
static Evas_Object *filesystem_entry = NULL;
static Evas_Object *controls = NULL;
static Evas_Object *repeat = NULL;
static Evas_Object *shuffle = NULL;
static Evas_Object *single = NULL;
static Evas_Object *consume = NULL;
static Eina_Bool login_visible = EINA_FALSE;
static Evas_Object *login_host = NULL;
static Evas_Object *login_port = NULL;
static Evas_Object *login_password = NULL;
static Eina_Array *clipboard = NULL;
static long long clipboard_paste_id = -1;
static unsigned int clipboard_paste_length = 0;
int empc_log_dom = -1;
EAPI void *empd_proxy = NULL;
EAPI void *empc_proxy = NULL;
static Eldbus_Service_Interface *empc_iface = NULL;
static Eldbus_Connection *dbus_conn = NULL;
static Eina_List *handlers = NULL;
EAPI Eina_Hash *empd_current_queue = NULL;
EAPI Eina_Hash *empd_current_queue_headers = NULL;
Eina_Stringshare *empd_music_directory = NULL;
static int empd_songid = -1;
static int empd_song_track = -1;
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;
EAPI unsigned int empd_queue_length = 0;
static unsigned char background_num = 0;
Eina_Hash *empc_metadata_fetch_reqs[EMPC_METADATA_TYPE_LAST];
Eina_Inlist *empc_modules[EMPC_MODULE_TYPE_LAST];
static size_t empc_module_size[EMPC_MODULE_TYPE_LAST] =
{
[EMPC_MODULE_TYPE_METADATA_FETCH] = sizeof(Empc_Module_Metadata_Fetch),
[EMPC_MODULE_TYPE_METADATA_SAVER] = sizeof(Empc_Module_Metadata_Save),
[EMPC_MODULE_TYPE_MISC] = sizeof(Empc_Module_Misc),
};
static void queue_list_header_image(void *data, Empc_Fetch_Request *req, Evas_Object *obj);
static void filesystem_base(Eldbus_Proxy *proxy, void *data, Eldbus_Pending *pending, Eldbus_Error_Info *error, Eina_Value *args);
static void filesystem_item_image(void *data, Empc_Fetch_Request *req, Evas_Object *obj);
static void queue_list_handler(Eina_Value *value, Eina_Bool update);
static void filesystem_next(void *data, Evas_Object *obj, void *event_info);
static void filesystem_prev(void);
static Evas_Object *filesystem_new(const char *uri);
static void
error_o_doom(void)
{
Evas_Object *o;
o = elm_popup_add(win);
elm_object_text_set(o, _("<b>THIS IS THE ANGRY ERROR MESSAGE!<br/>"
"DBUS </b>.service<b> INSTALLATION FAILED.<br/>"
"FIX YOUR INSTALL OR START '</b>empdd<b>' MANUALLY.<br/>"
"<br/>"
"RESTART EMPC WHEN YOU HAVE FIXED THIS.<br/>"
"<br/>"
"PS. CAPS LOCK IS FUN FOR DEVELOPERS!"));
evas_object_show(o);
}
static inline unsigned char
bg_next_get(void)
{
char num = background_num + 1;
return num % 2;
}
static void
queue_list_clear(void)
{
eina_hash_free_buckets(empd_current_queue_headers);
elm_genlist_clear(queue_list);
queue_list_scroll_item = NULL;
}
static void
ctxpopup_item_append(unsigned int *num, Evas_Object *ctx, const char *label, Evas_Object *icon, Evas_Smart_Cb cb, const void *data)
{
Elm_Object_Item *it;
char buf[128];
it = elm_ctxpopup_item_append(ctx, _(label), icon, cb, data);
snprintf(buf, sizeof(buf), "%u", ++(*num));
elm_object_item_part_text_set(it, "empc.text.hint", buf);
}
static void
item_box_del(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
{
evas_object_del(data);
}
static Evas_Object *
ee_image_add(void)
{
Evas_Object *o;
o = ecore_evas_object_image_new(ecore_evas_ecore_evas_get(evas_object_evas_get(win)));
ecore_evas_alpha_set(evas_object_data_get(o, "Ecore_Evas"), 1);
evas_object_image_filled_set(o, 1);
return o;
}
static void
ee_image_del(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
{
evas_object_del(data);
}
static void
ee_image_copy(Evas_Object *obj, Evas_Object *o, int size)
{
Evas_Object *orig, *copy;
const Eina_File *file;
Eina_Stringshare *f, *g;
int w, h;
orig = elm_image_object_get(obj);
evas_object_image_mmap_get(orig, &file, &g);
copy = evas_object_image_filled_add(ecore_evas_object_evas_get(o));
elm_image_object_size_get(obj, &w, &h);
evas_object_size_hint_aspect_set(o, EVAS_ASPECT_CONTROL_BOTH, w, h);
size *= elm_config_scale_get();
if (w > h)
{
h = size * h / w;
w = size;
}
else if (h > w)
{
w = size * w / h;
h = size;
}
else
w = h = size;
evas_object_data_set(o, "__empc_image", copy);
evas_object_image_size_set(o, w, h);
evas_object_resize(copy, w, h);
evas_object_show(copy);
evas_object_event_callback_add(o, EVAS_CALLBACK_DEL, ee_image_del, copy);
evas_object_image_smooth_scale_set(copy, 0);
if (file)
evas_object_image_mmap_set(copy, file, g);
else
{
evas_object_image_file_get(orig, &f, &g);
evas_object_image_file_set(copy, f, g);
}
}
static inline Elm_Object_Item *
queue_list_header_prev_get(Elm_Object_Item *it)
{
Elm_Object_Item *pick;
pick = elm_genlist_item_prev_get(it);
if (pick)
{
do
{
Elm_Object_Item *h = elm_genlist_item_parent_get(pick);
if ((!h) && (pick != it)) return pick;
if (h != it)
return h;
pick = elm_genlist_item_prev_get(pick);
} while (pick);
}
return elm_genlist_last_item_get(queue_list);
}
static inline Elm_Object_Item *
queue_list_header_next_get(Elm_Object_Item *it)
{
Elm_Object_Item *pick;
pick = elm_genlist_item_next_get(it);
if (pick)
{
do
{
Elm_Object_Item *h = elm_genlist_item_parent_get(pick);
if ((!h) && (pick != it)) return pick;
if (h != it)
return h;
pick = elm_genlist_item_next_get(pick);
} while (pick);
}
return elm_genlist_item_parent_get(elm_genlist_first_item_get(queue_list));
}
static int
queue_list_sort(Elm_Object_Item *a, Elm_Object_Item *b)
{
Empd_Empdd_Song *a1, *b1;
a1 = elm_object_item_data_get(a);
b1 = elm_object_item_data_get(b);
return a1->song_pos - b1->song_pos;
}
const char *
filesystem_entity_name_get(const Empc_Entity *ent)
{
Empd_Empdd_Directory *dir = ent->value;
Empd_Empdd_File *f = ent->value;
switch (ent->type)
{
case MPD_ENTITY_TYPE_DIRECTORY:
case MPD_ENTITY_TYPE_PLAYLIST:
return dir->uri;
case MPD_ENTITY_TYPE_SONG:
return f->uri;
}
return NULL;
}
static int
filesystem_sort(Elm_Object_Item *it1, Elm_Object_Item *it2)
{
Empc_Entity *a, *b;
const char *a1, *b1;
a = elm_object_item_data_get(it1);
b = elm_object_item_data_get(it2);
a1 = filesystem_entity_name_get(a);
b1 = filesystem_entity_name_get(b);
if (a->type == b->type)
return strcmp(a1, b1);
switch (a->type)
{
case MPD_ENTITY_TYPE_DIRECTORY:
if (b->type == MPD_ENTITY_TYPE_PLAYLIST) return -1;
return 1;
case MPD_ENTITY_TYPE_PLAYLIST:
return 1;
case MPD_ENTITY_TYPE_SONG:
return -1;
}
return -1;
}
static void
clipboard_entity_free(Empc_Entity *ent)
{
eina_stringshare_del(ent->value);
free(ent);
}
static void
clipboard_clear(void)
{
Eina_Iterator *it;
Empc_Entity *ent;
if (!eina_array_count(clipboard)) return;
it = eina_array_iterator_new(clipboard);
EINA_ITERATOR_FOREACH(it, ent)
clipboard_entity_free(ent);
eina_iterator_free(it);
eina_array_clean(clipboard);
}
static Eina_Bool
clipboard_copy(void)
{
const Eina_List *l;
Eina_List *sorted;
Elm_Object_Item *it;
Empd_Empdd_Song *so;
Empc_Entity *ent, *eso;
if (filesystem_state)
{
l = elm_gengrid_selected_items_get(eina_list_last_data_get(filesystems));
if (!l) return EINA_TRUE;
clipboard_clear();
sorted = eina_list_clone(l);
sorted = eina_list_sort(sorted, 0, (Eina_Compare_Cb)filesystem_sort);
EINA_LIST_FREE(sorted, it)
{
ent = malloc(sizeof(Empc_Entity));
eso = elm_object_item_data_get(it);
ent->type = eso->type;
ent->value = (void*)eina_stringshare_ref(filesystem_entity_name_get(eso));
eina_array_push(clipboard, ent);
}
return EINA_TRUE;
}
else if (queue_list_state)
{
l = elm_genlist_selected_items_get(queue_list);
if (!l) return EINA_TRUE;
clipboard_clear();
sorted = eina_list_clone(l);
sorted = eina_list_sort(sorted, 0, (Eina_Compare_Cb)queue_list_sort);
EINA_LIST_FREE(sorted, it)
{
ent = malloc(sizeof(Empc_Entity));
so = elm_object_item_data_get(it);
ent->value = (void*)eina_stringshare_ref(so->uri);
ent->type = MPD_ENTITY_TYPE_SONG;
eina_array_push(clipboard, ent);
}
return EINA_TRUE;
}
return EINA_FALSE;
}
static Eina_Bool
clipboard_paste(long long after)
{
Eina_Iterator *it;
Empc_Entity *ent;
if (!queue_list_state) return EINA_FALSE;
if (!eina_array_count(clipboard)) return EINA_TRUE;
if (clipboard_paste_length || (clipboard_paste_id != -1)) return EINA_FALSE;
if (after != empd_queue_length)
{
clipboard_paste_length = empd_queue_length;
clipboard_paste_id = after;
}
it = eina_array_iterator_new(clipboard);
EINA_ITERATOR_FOREACH(it, ent)
{
switch (ent->type)
{
case MPD_ENTITY_TYPE_DIRECTORY:
case MPD_ENTITY_TYPE_SONG:
empd_empdd_add_list_call(empd_proxy, ent->value);
break;
case MPD_ENTITY_TYPE_PLAYLIST:
empd_empdd_load_playlist_call(empd_proxy, ent->value);
break;
}
}
eina_iterator_free(it);
empd_empdd_status_call(empd_proxy);
return EINA_TRUE;
}
static void
ctxpopup_mouse(void *data EINA_UNUSED, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
{
elm_layout_signal_emit(layout, "empc,mouse,move", "empc");
}
static void
ctxpopup_dismiss(void *data EINA_UNUSED, Evas_Object *obj, void *event_info EINA_UNUSED)
{
if (ctxpopup == obj)
ctxpopup = NULL;
if (ctxpopup_locked_overlay)
{
ctxpopup_locked_overlay = EINA_FALSE;
if (overlay_locked_state)
elm_object_signal_emit(layout, "empc,overlay,toggle", "empc");
}
evas_object_del(obj);
}
static void
ctxpopup_copy(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
{
clipboard_copy();
elm_ctxpopup_dismiss(ctxpopup);
}
static Evas_Object *
ctxpopup_add(Evas_Object *obj, const char *style)
{
Evas_Object *ctx;
ctx = elm_ctxpopup_add(obj);
evas_object_event_callback_add(ctx, EVAS_CALLBACK_MOUSE_MOVE, ctxpopup_mouse, NULL);
elm_object_style_set(ctx, style);
evas_object_smart_callback_add(ctx, "dismissed", ctxpopup_dismiss, NULL);
if (!overlay_locked_state)
{
elm_object_signal_emit(layout, "empc,overlay,toggle", "empc");
ctxpopup_locked_overlay = EINA_TRUE;
}
return ctx;
}
static void
ctxpopup_mouse_position(Evas_Object *ctx)
{
//FIXME: T1211
int x, y, w, h, ow, oh, px, py;
evas_pointer_canvas_xy_get(evas_object_evas_get(ctx), &x, &y);
evas_object_geometry_get(layout, NULL, NULL, &w, &h);
evas_object_size_hint_min_get(ctx, &ow, &oh);
if (ow) ow = 200;
if (oh) oh = 200;
px = x, py = y;
if (px + ow >= w)
px -= ow;
if (px < 0)
px += (ow / 2);
if (py + oh >= h)
py -= oh;
if (py < 0)
py += (oh / 2);
evas_object_move(ctxpopup, px, py);
}
static Evas_Object *
tooltip_create(Evas_Object *tooltip, Elm_Object_Item *item)
{
Elm_Object_Item *it;
Evas_Object *o, *copy, *ly;
const Eina_File *f;
Eina_Stringshare *file, *key;
Empd_Empdd_Song *so;
char buf[1024];
const char *infos;
Eina_Bool playing;
it = elm_genlist_item_parent_get(item);
if (!it) it = item;
so = elm_object_item_data_get(item);
if (item == empd_song_item)
{
o = bgselector_get(bg[background_num]);
if (o)
o = elm_image_object_get(o);
}
else
{
o = elm_object_item_part_content_get(it, EMPC_SWALLOW_ALBUM);
if (o)
{
if (!strcmp(evas_object_type_get(o), "Evas_Object_Box"))
o = eina_list_data_get(evas_object_box_children_get(o));
if (o)
o = evas_object_data_get(o, "__empc_image");
}
}
ly = elm_layout_add(tooltip);
elm_layout_theme_set(ly, "layout", "empc", "tooltip");
if (o)
{
int w, h;
evas_object_image_mmap_get(o, &f, &key);
if (!f)
evas_object_image_file_get(o, &file, &key);
copy = elm_image_add(tooltip);
if (f)
elm_image_mmap_set(copy, f, key);
else
elm_image_file_set(copy, file, key);
elm_image_fill_outside_set(copy, EINA_FALSE);
elm_image_smooth_set(copy, EINA_FALSE);
elm_image_object_size_get(copy, &w, &h);
evas_object_size_hint_max_set(copy, w, h);
if (w > 256)
{
h = 256 * h / w;
w = 256;
}
else if (h > 256)
{
w = 256 * w / h;
h = 256;
}
evas_object_size_hint_min_set(copy, w, h);
elm_object_part_content_set(ly, "empc.swallow.icon", copy);
}
playing = (empd_song_item && (elm_genlist_item_parent_get(empd_song_item) == it));
infos = elm_layout_data_get(ly, "empc.infos");
if (infos && infos[0])
{
unsigned int num, i;
char **str;
str = eina_str_split_full(infos, " ", 0, &num);
for (i = 0; i < num; i++)
{
char *itemname = str[i];
Evas_Object *name, *value;
name = elm_label_add(tooltip);
elm_object_style_set(name, "tooltip_info");
value = elm_label_add(tooltip);
elm_object_style_set(value, "tooltip_info_value");
if (eina_streq(itemname, "artist"))
{
elm_object_text_set(name, _("Artist:"));
elm_object_text_set(value, so->artist);
}
else if (eina_streq(itemname, "album"))
{
elm_object_text_set(name, _("Album:"));
elm_object_text_set(value, so->album);
}
else if (eina_streq(itemname, "time"))
{
elm_object_text_set(name, _("Time:"));
snprintf(buf, sizeof(buf), "%.2ld:%.2ld", so->duration / 60, so->duration % 60);
elm_object_text_set(value, buf);
}
else if (eina_streq(itemname, "track"))
{
if (it == item) //header
{
elm_layout_signal_emit(ly, "empc,state,header", "empc");
elm_object_text_set(name, _("Tracks:"));
snprintf(buf, sizeof(buf), "%u", elm_genlist_item_subitems_count(it));
}
else
{
elm_object_text_set(name, _("Track:"));
if (so->track > (int)elm_genlist_item_subitems_count(it))
snprintf(buf, sizeof(buf), "%d", so->track);
else
snprintf(buf, sizeof(buf), "%d/%u", so->track, elm_genlist_item_subitems_count(it));
}
elm_object_text_set(value, buf);
}
else if (eina_streq(itemname, "index"))
{
elm_object_text_set(name, _("Index:"));
snprintf(buf, sizeof(buf), "%d", so->song_pos);
elm_object_text_set(value, buf);
}
if (playing)
elm_layout_signal_emit(value, "empc,state,playing", "empc");
evas_object_show(name);
evas_object_show(value);
elm_layout_table_pack(ly, "empc.table", name, 0, i, 1, 1);
elm_layout_table_pack(ly, "empc.table", value, 1, i, 1, 1);
}
if (num)
free(str[0]);
free(str);
}
if (playing)
elm_layout_signal_emit(ly, "empc,state,playing", "empc");
return ly;
}
static void
save_image(Eina_Bool force, Evas_Object *img, const char *uri, const char *artist, const char *album, Empc_Module_Metadata_Save_Post_Cb post_cb)
{
Empc_Module *mod;
Eina_Bool nosave = EINA_FALSE, override = EINA_FALSE;
if ((!force) && (!master)) return;
if (!master)
{
const char *f = NULL, *g;
elm_image_file_get(img, &f, &g);
if (f && f[0])
empd_empc_set_background_file_call(empc_proxy, artist, album ?: "", f, g ?: "");
else
{
Eldbus_Message *msg;
Eldbus_Message_Iter *iter, *array;
const Eina_File *eif;
Eina_File *e;
Evas_Object *o;
void *px;
o = elm_image_object_get(img);
evas_object_image_mmap_get(o, &eif, NULL);
e = eina_file_dup(eif);
msg = eldbus_proxy_method_call_new(empc_proxy, "SetBackgroundData");
iter = eldbus_message_iter_get(msg);
eldbus_message_iter_basic_append(iter, 's', artist);
eldbus_message_iter_basic_append(iter, 's', album ?: "");
px = eina_file_map_all(e, EINA_FILE_POPULATE);
eldbus_message_iter_basic_append(iter, 's', eina_file_filename_get(e));
array = eldbus_message_iter_container_new(iter, 'a', "y");
if (!eldbus_message_iter_fixed_array_append(array, 'y', px, eina_file_size_get(e)))
abort();
if (!eldbus_message_iter_container_close(iter, array))
abort();
eldbus_proxy_send(empc_proxy, msg, NULL, NULL, -1);
eina_file_map_free(e, px);
eina_file_close(e);
}
bg_ignore = EINA_TRUE;
return;
}
if (img)
{
override = !!evas_object_data_get(img, "__empc_override");
nosave = !!evas_object_data_get(img, "__empc_nosave");
if ((!override) && nosave) return;
}
EINA_INLIST_FOREACH(empc_modules[EMPC_MODULE_TYPE_METADATA_SAVER], mod)
{
Empc_Module_Metadata_Save *es = (Empc_Module_Metadata_Save *)mod;
INF("IMAGE SAVE(%s)", strrchr(eina_module_file_get(mod->module), '/') + 1);
if (es->save_image) es->save_image(img, uri, artist, album, post_cb);
}
}
static void
save_text(Evas_Object *obj, const char *artist, const char *song)
{
Empc_Module *mod;
if (!master) return;
if (evas_object_data_get(obj, "__empc_nosave")) return;
EINA_INLIST_FOREACH(empc_modules[EMPC_MODULE_TYPE_METADATA_SAVER], mod)
{
Empc_Module_Metadata_Save *es = (Empc_Module_Metadata_Save *)mod;
INF("TEXT SAVE(%s)", strrchr(eina_module_file_get(mod->module), '/') + 1);
if (es->save_text) es->save_text(elm_entry_entry_get(obj), artist, song);
}
}
static void
fetch_req_free(Empc_Fetch_Request_Internal *ireq)
{
if ((Empc_Fetch_Request*)ireq == bgfetch) bgfetch = NULL;
while (ireq->end_cbs)
{
Empc_Fetch_Request_End_Cb *ecb = (Empc_Fetch_Request_End_Cb *)ireq->end_cbs;
ecb->cb(ecb->data, ireq);
ireq->end_cbs = eina_inlist_remove(ireq->end_cbs, ireq->end_cbs);
free(ecb);
}
eina_stringshare_del(ireq->req.artist);
eina_stringshare_del(ireq->req.album);
eina_stringshare_del(ireq->req.song);
eina_stringshare_del(ireq->req.uri);
ecore_job_del(ireq->fail_job);
E_FREE_LIST(ireq->results, free);
E_FREE_LIST(ireq->urls_pending, eina_stringshare_del);
free(ireq);
}
void
lyrics_set(void *data EINA_UNUSED, Empc_Fetch_Request *req, Evas_Object *obj)
{
if (!obj) return;
elm_object_part_content_set(layout, EMPC_SWALLOW_LYRICS, obj);
save_text(obj, req->artist, req->song);
if (!lyrics_visible)
elm_object_signal_emit(layout, "empc,lyrics,show", "empc");
}
static void
bg_update_propogate(const char *artist, const char *album)
{
const Eina_List *l;
Elm_Object_Item *it;
EINA_LIST_FOREACH(empc_modapi_queue_list_header_items_find(artist, album), l, it)
elm_genlist_item_fields_update(it, EMPC_SWALLOW_ALBUM, ELM_GENLIST_ITEM_FIELD_CONTENT);
}
static void
bg_changed_post(void *d EINA_UNUSED, void *d2 EINA_UNUSED)
{
bg_update_propogate(empd_song_artist, empd_song_album);
}
static void
bg_update_signal(void)
{
if (master)
{
Evas_Object *cur, *o;
Eina_Stringshare *f = NULL, *g = NULL;
o = elm_object_part_content_get(layout, EMPC_SWALLOW_BACKGROUND);
cur = bgselector_get(o);
elm_image_file_get(cur, &f, &g);
eldbus_service_signal_emit(empc_iface, EMPC_SIGNAL_BACKGROUND_CHANGED, f ?: "", g ?: "");
}
bg_ignore = EINA_TRUE;
}
static Evas_Object *
bg_tooltip_cb(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED, Evas_Object *tooltip)
{
if (bgchooser || (!empd_song_item)) return NULL;
return tooltip_create(tooltip, empd_song_item);
}
void
bg_add(void *data EINA_UNUSED, Empc_Fetch_Request *req, Evas_Object *obj)
{
Evas_Object *parent;
if (!obj)
{
if (!bgchooser)
elm_object_signal_emit(layout, "empc,info,show", "empc");
return;
}
parent = elm_object_parent_widget_get(obj);
bgselector_image_add(parent, obj);
if (!bgchooser)
save_image(EINA_FALSE, obj, NULL, req->artist, req->album, (master && (!bg_updated)) ? bg_update_signal : NULL);
if (bg_updated) return;
bg_update_propogate(empd_song_artist, empd_song_album);
elm_object_signal_emit(layout, "empc,bg,done", "empc");
bg_updated = EINA_TRUE;
}
static void
bg_changed(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED, const char *sig EINA_UNUSED, const char *src EINA_UNUSED)
{
evas_object_hide(elm_object_part_content_unset(layout, EMPC_SWALLOW_BACKGROUND));
elm_object_part_content_set(layout, EMPC_SWALLOW_BACKGROUND, bg[background_num]);
elm_layout_sizing_eval(layout);
evas_object_smart_calculate(layout);
elm_object_signal_emit(layout, "empc,bg,done", "empc");
if (bgheader_dirty)
bg_changed_post(NULL, NULL);
bgheader_dirty = EINA_FALSE;
}
static Empc_Fetch_Request *
bg_update(int num, Eina_Stringshare *artist, Eina_Stringshare *album, Eina_Stringshare *uri)
{
Evas_Object *o;
o = bg[num];
if ((artist != bgselector_artist_get(o)) || (album != bgselector_album_get(o)))
{
bgselector_clear(o);
bgselector_info_set(o, artist, album);
return metadata_fetch_begin(EMPC_METADATA_TYPE_IMAGE, o, artist, album, uri, EINA_FALSE, EINA_FALSE, bg_add, NULL);
}
return NULL;
}
static void
bg_paste_download_start(void *data EINA_UNUSED, Evas_Object *obj, void *event_info EINA_UNUSED)
{
evas_object_data_set(obj, "__empc_downloading", (void*)1);
bg_pasting = EINA_TRUE;
}
static void
bg_paste_download_done(void *data EINA_UNUSED, Evas_Object *obj, void *event_info EINA_UNUSED)
{
evas_object_data_del(obj, "__empc_downloading");
bgselector_image_max_recalc(obj);
bg_pasting = EINA_FALSE;
if (bgchooser)
{
bgselector_image_add(bg[background_num], obj);
return;
}
background_num = bg_next_get();
bgselector_clear(bg[background_num]);
bgselector_info_set(bg[background_num], empd_song_artist, empd_song_album);
bgselector_image_add(bg[background_num], obj);
elm_object_signal_emit(layout, "empc,bg,next", "empc");
save_image(EINA_TRUE, obj, NULL, empd_song_artist, empd_song_album, bg_update_signal);
bg_update_propogate(empd_song_artist, empd_song_album);
}
static void
bg_paste_download_error(void *data EINA_UNUSED, Evas_Object *obj, void *event_info EINA_UNUSED)
{
evas_object_data_del(obj, "__empc_downloading");
bg_pasting = EINA_FALSE;
evas_object_del(obj);
}
static Eina_Bool
bg_paste(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED, Elm_Selection_Data *ev)
{
if (filesystem_state)
{
Elm_Object_Item *it;
Empc_Entity *ent;
it = elm_gengrid_selected_item_get(eina_list_last_data_get(filesystems));
if (!it) return EINA_TRUE;
ent = elm_object_item_data_get(it);
if (ent->type != MPD_ENTITY_TYPE_DIRECTORY) return EINA_TRUE;
evas_object_data_set(win, "__empc_bg_paste", ev);
elm_gengrid_item_update(it);
evas_object_data_del(win, "__empc_bg_paste");
return EINA_TRUE;
}
switch (ev->format)
{
case ELM_SEL_FORMAT_IMAGE:
{
Evas_Object *img;
img = elm_image_add(win);
elm_image_fill_outside_set(img, EINA_FALSE);
elm_image_smooth_set(img, EINA_FALSE);
if (elm_image_memfile_set(img, ev->data, ev->len, NULL, NULL))
{
unsigned int num = background_num;
if (!bgchooser)
{
num = background_num = bg_next_get();
elm_object_signal_emit(layout, "empc,bg,next", "empc");
bgselector_clear(bg[background_num]);
bgselector_info_set(bg[background_num], empd_song_artist, empd_song_album);
save_image(EINA_TRUE, img, NULL, empd_song_artist, empd_song_album, bg_update_signal);
bg_update_propogate(empd_song_artist, empd_song_album);
}
bgselector_image_add(bg[num], img);
}
else
evas_object_del(img);
}
break;
case ELM_SEL_FORMAT_TEXT:
{
Evas_Object *img;
char buf[4096];
if (ev->len > sizeof(buf) - 1) break;
img = elm_image_add(win);
elm_image_fill_outside_set(img, EINA_FALSE);
elm_image_smooth_set(img, EINA_FALSE);
memcpy(buf, ev->data, ev->len);
buf[ev->len] = 0;
evas_object_smart_callback_add(img, "download,start", bg_paste_download_start, buf);
evas_object_smart_callback_add(img, "download,done", bg_paste_download_done, NULL);
evas_object_smart_callback_add(img, "download,error", bg_paste_download_error, NULL);
if (elm_image_file_set(img, buf, NULL))
{
unsigned int num = background_num;
if ((!bgchooser) && (!evas_object_data_get(img, "__empc_downloading")))
{
num = bg_next_get();
bgselector_clear(bg[num]);
bgselector_info_set(bg[num], empd_song_artist, empd_song_album);
/* must be local file, only save uri */
save_image(EINA_TRUE, NULL, buf, empd_song_artist, empd_song_album, bg_update_signal);
bg_update_propogate(empd_song_artist, empd_song_album);
bgselector_image_add(bg[num], img);
}
}
else
evas_object_del(img);
}
break;
default: break;
}
return EINA_TRUE;
}
static void
artist_changed(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED, const char *sig EINA_UNUSED, const char *src EINA_UNUSED)
{
elm_object_part_text_set(layout, EMPC_TEXT_ARTIST, empd_song_artist);
elm_object_signal_emit(layout, "empc,artist,change,2", "empc");
}
static void
album_changed(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED, const char *sig EINA_UNUSED, const char *src EINA_UNUSED)
{
elm_object_part_text_set(layout, EMPC_TEXT_ALBUM, empd_song_album);
elm_object_signal_emit(layout, "empc,album,change,2", "empc");
}
static void
title_text_set(void)
{
if (empd_song_track > 0)
{
char buf[1024];
snprintf(buf, sizeof(buf), "%.2d - %s", empd_song_track, empd_song_title);
elm_object_part_text_set(layout, EMPC_TEXT_TITLE, buf);
}
else
elm_object_part_text_set(layout, EMPC_TEXT_TITLE, empd_song_title);
}
static void
title_changed(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED, const char *sig EINA_UNUSED, const char *src EINA_UNUSED)
{
title_text_set();
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;
}
if (empd_song_title && empd_song_artist)
snprintf(buf, sizeof(buf), "EMPC | %s - %s (%s)", empd_song_artist, empd_song_title, st);
else if (empd_song_title)
snprintf(buf, sizeof(buf), "EMPC | %s (%s)", empd_song_title, st);
else
snprintf(buf, sizeof(buf), "EMPC | (%s)", 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 int
songid_update(int songid)
{
Eina_Bool artist, album, first = (empd_songid == -1);
Elm_Object_Item *it, *itp = NULL;
Empd_Empdd_Song *so, *sop = NULL;
int ret, uid = background_num;
if (empd_songid == songid) return 0;
/* don't allow set until config has been checked */
if (config_call) return 0;
if (empd_songid != -1)
itp = eina_hash_find(empd_current_queue, &empd_songid);
it = eina_hash_find(empd_current_queue, &songid);
/* don't allow set until item exists */
if (!it) return 0;
so = elm_object_item_data_get(it);
/* don't allow set until song exists */
if (!so) return 0;
empd_song_item = it;
if (empd_song_track == -1)
elm_object_signal_callback_add(layout, "empc,bg,changed", "empc", bg_changed, NULL);
empd_song_track = so->track;
eina_stringshare_refplace(&empd_song_title, so->title);
artist = eina_stringshare_refplace(&empd_song_artist, so->artist);
album = eina_stringshare_refplace(&empd_song_album, so->album);
if (artist || album)
{
uid = first ? background_num : bg_next_get();
bg_update(uid, empd_song_artist, empd_song_album, so->uri);
}
ret = songid - empd_songid;
empd_songid = songid;
if (itp)
{
elm_object_item_signal_emit(itp, "empc,state,not_playing", "empc");
if (elm_genlist_item_parent_get(itp) != elm_genlist_item_parent_get(it))
{
elm_object_item_signal_emit(elm_genlist_item_parent_get(itp), "empc,state,not_playing", "empc");
elm_genlist_item_fields_update(elm_genlist_item_parent_get(itp), EMPC_TEXT_TIME, ELM_GENLIST_ITEM_FIELD_TEXT);
}
elm_genlist_item_fields_update(itp, EMPC_TEXT_TIME, ELM_GENLIST_ITEM_FIELD_TEXT);
sop = elm_object_item_data_get(itp);
}
else if (first)
elm_genlist_item_show(it, ELM_GENLIST_ITEM_SCROLLTO_MIDDLE);
{
char buf[128];
snprintf(buf, sizeof(buf), "%.2d:%.2d", empd_song_length / 60, empd_song_length % 60);
elm_object_part_text_set(evas_object_data_get(win, "slider"), "empc.text.length", buf);
}
elm_object_item_signal_emit(it, "empc,state,playing", "empc");
elm_object_item_signal_emit(elm_genlist_item_parent_get(it), "empc,state,playing", "empc");
elm_genlist_item_fields_update(it, EMPC_TEXT_TIME, ELM_GENLIST_ITEM_FIELD_TEXT);
elm_object_part_content_set(layout, EMPC_SWALLOW_LYRICS, NULL);
if (lyrics_visible)
metadata_fetch_begin(EMPC_METADATA_TYPE_TEXT, layout, empd_song_artist, empd_song_title, so->uri, EINA_FALSE, EINA_FALSE, lyrics_set, NULL);
so = elm_object_item_data_get(it);
if ((!itp) || (so->album != sop->album) || (so->artist != sop->artist))
{
if (bgchooser)
elm_object_signal_emit(layout, "empc,bg_chooser,stop", "empc");
if (!first)
{
if ((ret >= 0) || (itp && (!elm_genlist_item_next_get(itp))))
elm_object_signal_emit(layout, "empc,bg,next", "empc");
else
elm_object_signal_emit(layout, "empc,bg,prev", "empc");
}
if (itp || (uid != background_num))
background_num = bg_next_get();
elm_genlist_item_fields_update(elm_genlist_item_parent_get(it), EMPC_TEXT_TIME, ELM_GENLIST_ITEM_FIELD_TEXT);
if ((ret >= 0) || (itp && (!elm_genlist_item_next_get(itp))))
{
if ((!itp) || (so->artist != sop->artist))
elm_object_signal_emit(layout, "empc,artist,change,next", "empc");
elm_object_signal_emit(layout, "empc,album,change,next", "empc");
}
else
{
if ((!itp) || (so->artist != sop->artist))
elm_object_signal_emit(layout, "empc,artist,change,prev", "empc");
elm_object_signal_emit(layout, "empc,album,change,prev", "empc");
}
}
if (first)
title_changed(NULL, NULL, NULL, NULL);
else
{
if ((ret >= 0) || (itp && (!elm_genlist_item_next_get(itp))))
elm_object_signal_emit(layout, "empc,title,change,next", "empc");
else
elm_object_signal_emit(layout, "empc,title,change,prev", "empc");
}
return ret || artist || album;
}
static const char *
filesystem_text_helper(Empc_Entity *ent)
{
Empd_Empdd_File *file;
const char *str;
if (ent->type != MPD_ENTITY_TYPE_SONG)
{
/* playlist and directory structs are identical */
Empd_Empdd_Directory *dir = ent->value;
str = ecore_file_file_get(dir->uri);
return str ?: dir->uri;
}
file = ent->value;
return file->title;
}
static void
filesystem_search_visible(void *d EINA_UNUSED, Evas_Object *obj EINA_UNUSED, const char *sig EINA_UNUSED, const char *src EINA_UNUSED)
{
elm_object_focus_set(filesystem_entry, 1);
}
static void
filesystem_search_hidden(void *d EINA_UNUSED, Evas_Object *obj EINA_UNUSED, const char *sig EINA_UNUSED, const char *src EINA_UNUSED)
{
elm_entry_entry_set(filesystem_entry, NULL);
E_FREE_FUNC(filesystem_idler, ecore_idler_del);
filesystem_idler_pos = NULL;
}
static Eina_Bool
filesystem_idler_cb(void *ly EINA_UNUSED)
{
const char *str;
double t;
size_t len;
t = ecore_time_get();
str = elm_entry_entry_get(filesystem_entry);
len = strlen(str);
if (!filesystem_idler_pos)
filesystem_idler_pos = elm_gengrid_first_item_get(eina_list_last_data_get(filesystems));
while (filesystem_idler_pos && (ecore_time_get() - t < ecore_animator_frametime_get() / 4))
{
if (!strncasecmp(filesystem_text_helper(elm_object_item_data_get(filesystem_idler_pos)), str, len))
{
if ((eina_list_count(elm_gengrid_selected_items_get(eina_list_last_data_get(filesystems))) != 1) ||
(!elm_gengrid_item_selected_get(filesystem_idler_pos)))
{
const Eina_List *l, *ll;
Elm_Object_Item *it;
EINA_LIST_FOREACH_SAFE(elm_gengrid_selected_items_get(eina_list_last_data_get(filesystems)), l, ll, it)
elm_gengrid_item_selected_set(it, 0);
elm_gengrid_item_selected_set(filesystem_idler_pos, EINA_TRUE);
elm_gengrid_item_bring_in(filesystem_idler_pos, ELM_GENGRID_ITEM_SCROLLTO_MIDDLE);
}
E_FREE_FUNC(filesystem_idler, ecore_idler_del);
return EINA_FALSE;
}
filesystem_idler_pos = elm_gengrid_item_next_get(filesystem_idler_pos);
}
return EINA_TRUE;
}
static void
filesystem_mouse(void *data EINA_UNUSED, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
{
elm_object_focus_set(filesystem_entry, 1);
}
static void
filesystem_entry_hide(Evas_Object *ly)
{
Evas_Object *fs;
fs = elm_object_part_content_get(ly, EMPC_SWALLOW_FILESYSTEM);
elm_layout_signal_emit(ly, "empc,search,hide", "empc");
elm_layout_signal_emit(ly, "empc,buttons,show", "empc");
if (eina_list_count(filesystems) > 1)
elm_layout_signal_emit(ly, "empc,back,show", "empc");
else
elm_layout_signal_emit(ly, "empc,back,hide", "empc");
elm_object_focus_allow_set(fs, 1);
elm_object_focus_set(fs, 1);
}
static void
filesystem_entry_key_select(Eina_Bool forward, int dx, int dy, Eina_Bool multi)
{
const Eina_List *l;
Elm_Object_Item *it, *it2;
unsigned int x, y, wx, wy;
Elm_Object_Item *(*fn)(const Elm_Object_Item *) = elm_gengrid_item_next_get;
if (!forward)
fn = elm_gengrid_item_prev_get;
l = elm_gengrid_selected_items_get(eina_list_last_data_get(filesystems));
it = eina_list_last_data_get(l);
if ((eina_list_count(l) > 1) && (!multi))
while (eina_list_count(l) > 1)
{
elm_gengrid_item_selected_set(eina_list_data_get(l), 0);
l = elm_gengrid_selected_items_get(eina_list_last_data_get(filesystems));
}
elm_gengrid_item_pos_get(it, &x, &y);
if (((!x) && (dx < 0)) || ((!y) && (dy < 0))) return;
wx = x + dx, wy = y + dy;
while ((x != wx) || (y != wy))
{
it2 = it;
it = fn(it2);
if (!it) break;
elm_gengrid_item_pos_get(it, &x, &y);
if (forward && ((dx && (x > wx)) || (dy && (y > wy)))) break;
if ((!forward) && ((dx && (x < wx)) || (dy && (y < wy)))) break;
}
if (!it) it = it2;
if ((!multi) && (eina_list_data_get(l) != it))
elm_gengrid_item_selected_set(eina_list_data_get(l), 0);
elm_gengrid_item_selected_set(it, 1);
elm_gengrid_item_bring_in(filesystem_idler_pos, ELM_GENGRID_ITEM_SCROLLTO_MIDDLE);
filesystem_entry_hide(elm_object_parent_widget_get(eina_list_last_data_get(filesystems)));
}
static void
filesystem_entry_key(void *data EINA_UNUSED, Evas *e EINA_UNUSED, Evas_Object *obj, void *event_info)
{
Evas_Event_Key_Down *ev = event_info;
Evas_Object *ly;
ly = elm_object_parent_widget_get(obj);
if ((!strcmp(ev->key, "Escape")) || (!strcmp(ev->key, "Return")) || (!strcmp(ev->key, "KP_Enter")))
{
filesystem_entry_hide(ly);
if (strcmp(ev->key, "Escape"))
{
if (eina_list_count(elm_gengrid_selected_items_get(eina_list_last_data_get(filesystems))) == 1)
filesystem_next(NULL, NULL, elm_gengrid_selected_item_get(eina_list_last_data_get(filesystems)));
}
}
else
{
if (!filesystem_idler)
filesystem_idler = ecore_idler_add(filesystem_idler_cb, ly);
if (!strcmp(ev->key, "BackSpace"))
{
const char *str;
filesystem_idler_pos = NULL;
str = elm_entry_entry_get(filesystem_entry);
if ((!str) || (!str[0]))
{
filesystem_entry_hide(ly);
E_FREE_FUNC(filesystem_idler, ecore_idler_del);
}
}
}
elm_layout_signal_emit(layout, "empc,key,down", "empc");
}
static void
filesystem_key(void *data EINA_UNUSED, Evas *e EINA_UNUSED, Evas_Object *obj, void *event_info)
{
Evas_Event_Key_Down *ev = event_info;
Evas_Object *ly;
const char *str;
ly = elm_object_parent_widget_get(obj);
if ((!strcmp(ev->key, "Return")) || (!strcmp(ev->key, "KP_Enter")))
{
if (eina_list_count(elm_gengrid_selected_items_get(eina_list_last_data_get(filesystems))) == 1)
filesystem_next(NULL, NULL, elm_gengrid_selected_item_get(eina_list_last_data_get(filesystems)));
}
else if (!strcmp(ev->key, "Escape"))
{
if (eina_list_count(filesystems) > 1)
filesystem_prev();
}
else if (ev->compose && (((ev->compose[0] != '\\') && (ev->compose[0] >= ' ')) || ev->compose[1]))
{
str = elm_entry_entry_get(filesystem_entry);
if ((!str) || (!str[0]))
{
elm_layout_signal_emit(ly, "empc,search,show", "empc");
elm_layout_signal_emit(ly, "empc,buttons,hide", "empc");
elm_object_focus_set(filesystem_entry, 1);
elm_object_focus_allow_set(obj, 0);
}
elm_entry_entry_append(filesystem_entry, ev->compose);
elm_entry_cursor_end_set(filesystem_entry);
if (!filesystem_idler)
filesystem_idler = ecore_idler_add(filesystem_idler_cb, ly);
}
elm_layout_signal_emit(layout, "empc,key,down", "empc");
}
static void
filesystem_del(void *data EINA_UNUSED, Evas *e EINA_UNUSED, Evas_Object *obj, void *event_info EINA_UNUSED)
{
eina_stringshare_del(evas_object_data_del(obj, "uri"));
}
static void
filesystem_button_add(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
{
Evas_Object *o;
const Eina_List *l, *items;
Elm_Object_Item *it;
o = eina_list_last_data_get(filesystems);
items = elm_gengrid_selected_items_get(o);
EINA_LIST_FOREACH(items, l, it)
{
Empc_Entity *ent = elm_object_item_data_get(it);
switch (ent->type)
{
case MPD_ENTITY_TYPE_DIRECTORY:
case MPD_ENTITY_TYPE_SONG:
empd_empdd_add_list_call(empd_proxy, filesystem_entity_name_get(ent));
break;
case MPD_ENTITY_TYPE_PLAYLIST:
empd_empdd_load_playlist_call(empd_proxy, filesystem_entity_name_get(ent));
break;
}
}
if (items || (eina_list_count(filesystems) == 1)) return;
empd_empdd_add_list_call(empd_proxy, evas_object_data_get(o, "uri"));
}
static void
filesystem_button_append(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
{
Eina_Array *old = clipboard;
clipboard = eina_array_new(10);
clipboard_copy();
clipboard_paste(-1);
clipboard_clear();
eina_array_free(clipboard);
clipboard = old;
if (ctxpopup)
elm_ctxpopup_dismiss(ctxpopup);
}
static void
filesystem_button_insert_after(void *data, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
{
Eina_Array *old = clipboard;
Elm_Object_Item *it;
Empd_Empdd_Song *so;
unsigned int total, pos;
it = eina_hash_find(empd_current_queue, &empd_songid);
so = elm_object_item_data_get(it);
if (data) //after album
{
total = elm_genlist_item_subitems_count(elm_genlist_item_parent_get(it));
pos = so->song_pos + (total - so->track);
}
else
pos = so->song_pos;
clipboard = eina_array_new(10);
clipboard_copy();
clipboard_paste(pos + 1);
clipboard_clear();
eina_array_free(clipboard);
clipboard = old;
if (ctxpopup)
elm_ctxpopup_dismiss(ctxpopup);
}
static void
filesystem_button_replace(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
{
empd_empdd_clear_list_call(empd_proxy);
filesystem_button_add(NULL, NULL, NULL);
empd_empdd_play_call(empd_proxy);
if (ctxpopup)
elm_ctxpopup_dismiss(ctxpopup);
}
static void
filesystem_ctxpopup_show(Evas_Object *obj)
{
Evas_Object *ctx;
unsigned int num = 0;
if (!elm_gengrid_selected_items_get(obj)) return;
ctxpopup = ctx = ctxpopup_add(obj, "filesystem");
ctxpopup_item_append(&num, ctx, "Append selection", NULL, filesystem_button_append, NULL);
if ((empd_state == MPD_STATE_PLAY) || (empd_state == MPD_STATE_PAUSE))
{
ctxpopup_item_append(&num, ctx, "Insert after current song", NULL, filesystem_button_insert_after, NULL);
ctxpopup_item_append(&num, ctx, "Insert after current album", NULL, filesystem_button_insert_after, (void*)1);
}
ctxpopup_item_append(&num, ctx, "Replace queue with selection", NULL, filesystem_button_replace, NULL);
ctxpopup_item_append(&num, ctx, "Copy selection", NULL, ctxpopup_copy, NULL);
ctxpopup_mouse_position(ctx);
evas_object_show(ctx);
}
static void
filesystem_longpress(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
{
filesystem_ctxpopup_show(obj);
}
static void
filesystem_click(void *data EINA_UNUSED, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info)
{
Evas_Event_Mouse_Down *ev = event_info;
if (ev->button == 3)
filesystem_ctxpopup_show(obj);
}
static void
filesystem_item_realized(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info)
{
filesystems_realized = eina_list_append(filesystems_realized, event_info);
}
static void
filesystem_item_unrealized(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info)
{
filesystems_realized = eina_list_remove(filesystems_realized, event_info);
}
static Evas_Object *
filesystem_new(const char *uri)
{
Evas_Object *o;
o = elm_gengrid_add(win);
elm_object_style_set(o, "filesystem");
evas_object_data_set(o, "uri", eina_stringshare_add(uri));
evas_object_event_callback_add(o, EVAS_CALLBACK_DEL, filesystem_del, NULL);
filesystems = eina_list_append(filesystems, o);
evas_object_smart_callback_add(o, "realized", filesystem_item_realized, NULL);
evas_object_smart_callback_add(o, "unrealized", filesystem_item_unrealized, NULL);
evas_object_smart_callback_add(o, "longpressed", filesystem_longpress, NULL);
evas_object_event_callback_add(o, EVAS_CALLBACK_MOUSE_DOWN, filesystem_click, NULL);
evas_object_smart_callback_add(o, "clicked,double", filesystem_next, NULL);
evas_object_event_callback_add(o, EVAS_CALLBACK_KEY_DOWN, filesystem_key, NULL);
evas_object_event_callback_add(o, EVAS_CALLBACK_MOUSE_DOWN, filesystem_mouse, NULL);
elm_gengrid_item_size_set(o,
elm_config_scale_get() * 100,
elm_config_scale_get() * 125);
elm_gengrid_multi_select_mode_set(o, ELM_OBJECT_MULTI_SELECT_MODE_WITH_CONTROL);
elm_gengrid_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);
return o;
}
static void
filesystem_item_del(Empc_Entity *ent, Evas_Object *obj EINA_UNUSED)
{
switch (ent->type)
{
case MPD_ENTITY_TYPE_DIRECTORY:
Empd_Empdd_Directory_free(ent->value);
break;
case MPD_ENTITY_TYPE_PLAYLIST:
Empd_Empdd_Playlist_free(ent->value);
break;
case MPD_ENTITY_TYPE_SONG:
Empd_Empdd_Song_free(ent->value);
break;
}
free(ent);
}
static char *
filesystem_item_text_get(Empc_Entity *ent, Evas_Object *obj EINA_UNUSED, const char *part EINA_UNUSED)
{
return strdup(filesystem_text_helper(ent));
}
static void
filesystem_item_content_del(void *data, Evas *e EINA_UNUSED, Evas_Object *obj, void *event_info EINA_UNUSED)
{
metadata_fetch_cancel(data, NULL, filesystem_item_image, obj);
}
static void
filesystem_item_image(void *data, Empc_Fetch_Request *req, Evas_Object *obj)
{
Evas_Object *o;
int w, h;
if (req)
evas_object_event_callback_del_full(data, EVAS_CALLBACK_DEL, filesystem_item_content_del, req);
if (!obj) return;
o = ee_image_add();
ee_image_copy(obj, o, 128);
EXPAND(o);
FILL(o);
evas_object_show(o);
evas_object_box_append(data, o);
elm_gengrid_item_size_get(eina_list_data_get(filesystems), &w, &h);
evas_object_size_hint_max_set(data, w, h);
evas_object_size_hint_aspect_get(o, NULL, &w, &h);
evas_object_size_hint_aspect_set(data, EVAS_ASPECT_CONTROL_BOTH, w, h);
evas_object_event_callback_add(data, EVAS_CALLBACK_DEL, item_box_del, o);
if (req)
save_image(EINA_FALSE, obj, NULL, req->artist, req->album, NULL);
evas_object_del(obj);
}
static void
filesystem_item_content_get_post_save(void)
{
Eina_List *l;
Elm_Object_Item *it;
EINA_LIST_FOREACH(filesystems_realized, l, it)
elm_gengrid_item_update(it);
}
static void
filesystem_paste_download_start(void *data EINA_UNUSED, Evas_Object *obj, void *event_info EINA_UNUSED)
{
evas_object_data_set(obj, "__empc_downloading", (void*)1);
}
static Evas_Object *
filesystem_item_content_get(Empc_Entity *ent, Evas_Object *obj, const char *part EINA_UNUSED)
{
Empc_Fetch_Request *req = NULL;
Evas_Object *cur = NULL, *img = NULL;
Eina_Stringshare *uri = NULL;
Elm_Selection_Data *ev;
switch (ent->type)
{
case MPD_ENTITY_TYPE_DIRECTORY:
{
/* assumes directory structure:
*
* $artist/$album/songs
*/
const char *p;
Empd_Empdd_Directory *dir = ent->value;
cur = evas_object_box_add(evas_object_evas_get(obj));
ev = evas_object_data_get(win, "__empc_bg_paste");
p = strchr(dir->uri, '/');
if (ev)
{
img = elm_image_add(win);
if (ev->format == ELM_SEL_FORMAT_TEXT)
{
if (ev->len > 4096) break;
uri = eina_stringshare_add_length((char*)ev->data, ev->len);
evas_object_smart_callback_add(img, "download,start", filesystem_paste_download_start, NULL);
if (elm_image_file_set(img, uri, NULL))
{
if (evas_object_data_get(img, "__empc_downloading"))
E_FREE_FUNC(img, evas_object_del);
else
{
evas_object_ref(img);
filesystem_item_image(cur, NULL, img);
}
}
else
{
eina_stringshare_del(uri);
evas_object_del(img);
evas_object_del(cur);
return NULL;
}
}
else if (ev->format == ELM_SEL_FORMAT_IMAGE)
{
if (elm_image_memfile_set(img, ev->data, ev->len, NULL, NULL))
{
evas_object_ref(img);
filesystem_item_image(cur, NULL, img);
}
else
E_FREE_FUNC(img, evas_object_del);
}
}
if (p)
{
char artist[PATH_MAX];
const char *pp;
memcpy(&artist, dir->uri, p - dir->uri);
artist[p - dir->uri] = 0;
p += 1;
pp = strchr(p, '/');
if (pp)
{
char album[PATH_MAX];
memcpy(&album, p, pp - p);
album[pp - p] = 0;
if (img || uri)
save_image(EINA_TRUE, uri ? NULL : img, uri, artist, album, uri ? filesystem_item_content_get_post_save : NULL);
else
req = metadata_fetch_begin(EMPC_METADATA_TYPE_IMAGE, obj, artist, album, dir->uri, EINA_FALSE, EINA_FALSE, filesystem_item_image, cur);
}
else
{
if (img || uri)
save_image(EINA_TRUE, uri ? NULL : img, uri, artist, p, uri ? filesystem_item_content_get_post_save : NULL);
else
req = metadata_fetch_begin(EMPC_METADATA_TYPE_IMAGE, obj, artist, p, dir->uri, EINA_FALSE, EINA_FALSE, filesystem_item_image, cur);
}
}
else
{
if (img || uri)
save_image(EINA_TRUE, uri ? NULL : img, uri, dir->uri, NULL, uri ? filesystem_item_content_get_post_save : NULL);
else
req = metadata_fetch_begin(EMPC_METADATA_TYPE_IMAGE, obj, dir->uri, NULL, dir->uri, EINA_FALSE, EINA_FALSE, filesystem_item_image, cur);
}
if (img)
evas_object_unref(img);
else if (req && (!uri))
evas_object_event_callback_add(cur, EVAS_CALLBACK_DEL, filesystem_item_content_del, req);
eina_stringshare_del(uri);
break;
}
case MPD_ENTITY_TYPE_PLAYLIST:
cur = elm_icon_add(obj);
//elm_icon_standard_set(cur, ic
break;
case MPD_ENTITY_TYPE_SONG:
cur = elm_icon_add(obj);
elm_icon_standard_set(cur, "audio-x-generic");
break;
}
return cur;
}
static void
filesystem_item_add(Evas_Object *base, Empc_Entity *ent)
{
static Elm_Gengrid_Item_Class itc =
{
.item_style = "default",
.func = {
.content_get = (Elm_Gengrid_Item_Content_Get_Cb)filesystem_item_content_get,
.text_get = (Elm_Gengrid_Item_Text_Get_Cb)filesystem_item_text_get,
.del = (Elm_Gengrid_Item_Del_Cb)filesystem_item_del
},
.version = ELM_GENGRID_ITEM_CLASS_VERSION
};
elm_gengrid_item_append(base, &itc, ent, NULL, NULL);
}
static void
filesystem_base(Eldbus_Proxy *proxy EINA_UNUSED, void *data, Eldbus_Pending *pending EINA_UNUSED, Eldbus_Error_Info *error EINA_UNUSED, Eina_Value *args)
{
Eina_Value array;
unsigned int i;
Evas_Object *ly;
if (!args) return; //canceled
elm_gengrid_clear(data);
filesystems_realized = eina_list_free(filesystems_realized);
eina_value_struct_value_get(args, "arg0", &array);
for (i = 0; i < eina_value_array_count(&array); i++)
{
Eina_Value struc, val, realval;
int type;
Empc_Entity *ent;
eina_value_array_value_get(&array, i, &struc);
eina_value_struct_get(&struc, "arg0", &type);
eina_value_struct_value_get(&struc, "arg1", &val);
eina_value_struct_value_get(&val, "arg0", &realval);
ent = malloc(sizeof(Empc_Entity));
ent->type = type;
ent->value = NULL;
switch (type)
{
case MPD_ENTITY_TYPE_DIRECTORY:
azy_value_to_Empd_Empdd_Directory(&realval, (Empd_Empdd_Directory**)&ent->value);
break;
case MPD_ENTITY_TYPE_PLAYLIST:
azy_value_to_Empd_Empdd_Playlist(&realval, (Empd_Empdd_Playlist**)&ent->value);
break;
case MPD_ENTITY_TYPE_SONG:
azy_value_to_Empd_Empdd_File(&realval, (Empd_Empdd_File**)&ent->value);
break;
}
filesystem_item_add(data, ent);
eina_value_flush(&struc);
eina_value_flush(&val);
eina_value_flush(&realval);
}
eina_value_flush(&array);
if (eina_list_count(filesystems) == 1) return;
if (data != eina_list_last_data_get(filesystems)) return;
ly = elm_object_part_content_get(layout, EMPC_SWALLOW_FILESYSTEM);
evas_object_hide(elm_object_part_content_unset(ly, EMPC_SWALLOW_FILESYSTEM));
evas_object_show(data);
elm_object_part_content_set(ly, EMPC_SWALLOW_FILESYSTEM, data);
elm_object_part_text_set(ly, "empc.text.path", evas_object_data_get(data, "uri"));
filesystem_entry_hide(ly);
E_FREE_FUNC(filesystem_idler, ecore_idler_del);
filesystem_idler_pos = NULL;
}
static void
filesystem_next(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info)
{
Elm_Object_Item *it = event_info;
Empc_Entity *ent;
if (!empd_connected) return;
ent = elm_object_item_data_get(it);
switch (ent->type)
{
case MPD_ENTITY_TYPE_DIRECTORY:
{
Empd_Empdd_Directory *dir = ent->value;
empd_empdd_list_info_call(empd_proxy, filesystem_base, filesystem_new(dir->uri), dir->uri);
}
break;
case MPD_ENTITY_TYPE_PLAYLIST:
case MPD_ENTITY_TYPE_SONG:
break;
}
}
static void
filesystem_prev(void)
{
Evas_Object *ly, *fs;
const Eina_List *l, *ll;
Elm_Object_Item *it;
filesystems_realized = eina_list_free(filesystems_realized);
filesystems = eina_list_remove_list(filesystems, eina_list_last(filesystems));
ly = elm_object_part_content_get(layout, EMPC_SWALLOW_FILESYSTEM);
fs = eina_list_last_data_get(filesystems);
elm_object_part_content_set(ly, EMPC_SWALLOW_FILESYSTEM, fs);
E_FREE_FUNC(filesystem_idler, ecore_idler_del);
elm_object_part_content_set(ly, "empc.swallow.search", filesystem_entry);
filesystem_entry_hide(ly);
filesystem_idler_pos = NULL;
EINA_LIST_FOREACH_SAFE(elm_gengrid_selected_items_get(fs), l, ll, it)
elm_gengrid_item_selected_set(it, 0);
if (eina_list_count(filesystems) == 1)
elm_layout_signal_emit(ly, "empc,back,hide", "empc");
else
elm_object_part_text_set(ly, "empc.text.path", evas_object_data_get(fs, "uri"));
evas_object_show(fs);
elm_object_focus_set(fs, 1);
}
static void
filesystem_button_back(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
{
filesystem_prev();
}
static void
filesystem_button_update(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
{
const Eina_List *items, *l;
Elm_Object_Item *it;
items = elm_gengrid_selected_items_get(eina_list_last_data_get(filesystems));
EINA_LIST_FOREACH(items, l, it)
{
Empc_Entity *ent = elm_object_item_data_get(it);
Empd_Empdd_Directory *dir = ent->value;
Empd_Empdd_File *f = ent->value;
switch (ent->type)
{
case MPD_ENTITY_TYPE_DIRECTORY:
empd_empdd_update_call(empd_proxy, dir->uri);
break;
case MPD_ENTITY_TYPE_SONG:
empd_empdd_update_call(empd_proxy, f->uri);
break;
default: break;
}
}
if (!items)
empd_empdd_update_call(empd_proxy, evas_object_data_get(eina_list_last_data_get(filesystems), "uri"));
}
static void
filesystem_showing(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED, const char *sig EINA_UNUSED, const char *src EINA_UNUSED)
{
Elm_Object_Item *it;
Eina_List *l;
EINA_LIST_FOREACH(filesystems_realized, l, it)
elm_object_item_signal_emit(it, "empc,state,visible", "empc");
}
static void
filesystem_show(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED, const char *sig EINA_UNUSED, const char *src EINA_UNUSED)
{
filesystem_state = EINA_TRUE;
elm_object_focus_set(eina_list_last_data_get(filesystems), 1);
}
static void
filesystem_hide(void *data EINA_UNUSED, Evas_Object *obj, const char *sig EINA_UNUSED, const char *src EINA_UNUSED)
{
Elm_Object_Item *it;
Eina_List *l;
EINA_LIST_FOREACH(filesystems_realized, l, it)
elm_object_item_signal_emit(it, "empc,state,hidden", "empc");
filesystem_entry_hide(obj);
elm_object_focus_set(queue_list, 1);
filesystem_state = EINA_FALSE;
}
static void
filesystem_hiding(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED, const char *sig EINA_UNUSED, const char *src EINA_UNUSED)
{
evas_object_del(ctxpopup);
ctxpopup = NULL;
}
static void
queue_list_cached(Eldbus_Proxy *proxy EINA_UNUSED, void *data, Eldbus_Pending *pending EINA_UNUSED, Eldbus_Error_Info *error EINA_UNUSED, Eina_Value *value)
{
if (value)
queue_list_handler(value, EINA_FALSE);
if ((empd_songid == -1) && ((long)data == -1))
empd_empdd_status_call(empd_proxy);
}
static Eina_Bool
empc_bg_changed()
{
Empd_Empdd_Song *so;
const char *uri = NULL;
Empc_Fetch_Request *req;
if (bg_ignore)
{
bg_ignore = EINA_FALSE;
return ECORE_CALLBACK_RENEW;
}
if (empd_song_item)
{
so = elm_object_item_data_get(empd_song_item);
uri = so->uri;
}
background_num = bg_next_get();
bgselector_clear(bg[background_num]);
req = bg_update(background_num, empd_song_artist, empd_song_album, uri);
metadata_fetch_cb_add(req, bg_changed_post, NULL);
elm_object_signal_emit(layout, "empc,bg,next", "empc");
return ECORE_CALLBACK_RENEW;
}
static void
config_cb(Eldbus_Proxy *proxy EINA_UNUSED, void *data EINA_UNUSED, Eldbus_Pending *pending EINA_UNUSED, Eldbus_Error_Info *error EINA_UNUSED, const char *music_directory)
{
if (music_directory && music_directory[0])
eina_stringshare_replace(&empd_music_directory, music_directory);
else
eina_stringshare_replace(&empd_music_directory, NULL);
config_call = NULL;
}
static void
onconnected(Eina_Bool diff, const char *host, unsigned int port)
{
empd_connected = EINA_TRUE;
elm_layout_signal_emit(layout, "empc,login,hidden", "empc");
login_visible = EINA_FALSE;
config_call = empd_empdd_config_call(empd_proxy, config_cb, NULL);
empd_empdd_status_call(empd_proxy);
if (!diff) return;
if (!overlay_locked_state)
elm_layout_signal_emit(layout, "empc,playlist,show,timed", "empc");
queue_list_clear();
if (filesystems)
{
while (filesystems->next)
{
evas_object_del(eina_list_data_get(filesystems->next));
filesystems = eina_list_remove_list(filesystems, filesystems->next);
}
elm_gengrid_clear(eina_list_data_get(filesystems));
}
eina_stringshare_replace(&empd_host, host);
empd_port = port;
}
static void
login_show(const char *header, const char *host, unsigned int port)
{
char buf[8];
Eina_Stringshare *str;
if (host && host[0])
elm_entry_entry_set(login_host, host);
else
{
str = elm_entry_entry_get(login_host);
if ((!str) || (!str[0]))
elm_entry_entry_set(login_host, "127.0.0.1");
}
elm_entry_cursor_begin_set(login_host);
elm_entry_select_all(login_host);
if (port)
{
snprintf(buf, sizeof(buf), "%u", port);
elm_entry_entry_set(login_port, buf);
}
else
{
str = elm_entry_entry_get(login_port);
if ((!str) || (!str[0]))
elm_entry_entry_set(login_port, "6600");
}
elm_entry_cursor_begin_set(login_port);
login_visible = EINA_TRUE;
elm_object_part_text_set(layout, EMPC_LOGIN_TEXT_HEADER, header);
elm_layout_signal_emit(layout, "empc,login,visible", "empc");
elm_object_focus_set(login_host, 1);
}
static void
empc_isconnected(Eldbus_Proxy *proxy EINA_UNUSED, void *data EINA_UNUSED, Eldbus_Pending *pending EINA_UNUSED, Eldbus_Error_Info *error, Eina_Bool connected, const char *host, unsigned int port)
{
if (error && error->error && error->error[0])
{
error_o_doom();
return;
}
if (connected)
onconnected(EINA_TRUE, host, port);
else
login_show("Enter server info", host, port);
}
static void
login_close_request(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED, const char *sig EINA_UNUSED, const char *src EINA_UNUSED)
{
if (empd_connected)
{
elm_layout_signal_emit(layout, "empc,login,hidden", "empc");
login_visible = EINA_FALSE;
}
}
static void
login_connect(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
{
int port = -1;
const char *p;
p = elm_entry_entry_get(login_port);
if (p && p[0])
port = strtol(p, NULL, 10);
empd_empdd_connect_call(empd_proxy, elm_entry_entry_get(login_host), port, elm_entry_entry_get(login_password));
}
static Eina_Bool
empc_connected(void *d EINA_UNUSED, int t EINA_UNUSED, Empd_Empdd_Connected_Data *ev)
{
onconnected((!empd_host) || ((strcmp(empd_host, ev->host)) || (empd_port != ev->port)), ev->host, ev->port);
return ECORE_CALLBACK_RENEW;
}
static Eina_Bool
empc_disconnected(void *d EINA_UNUSED, int t EINA_UNUSED, Empd_Empdd_Disconnected_Data *ev EINA_UNUSED)
{
empd_connected = EINA_FALSE;
if (empd_state != MPD_STATE_UNKNOWN)
status_update(MPD_STATE_STOP);
login_show("Connection lost", empd_host, empd_port);
return ECORE_CALLBACK_RENEW;
}
static Eina_Bool
empc_login_fail(void *d EINA_UNUSED, int t EINA_UNUSED, Empd_Empdd_LoginFailed_Data *ev)
{
if (login_visible)
{
elm_object_part_text_set(layout, EMPC_LOGIN_TEXT_HEADER, "Authentication failed");
elm_layout_signal_emit(layout, "empc,login,failed", "empc");
}
else
login_show("Authentication failed", ev->host, ev->port);
return ECORE_CALLBACK_RENEW;
}
static Eina_Bool
empc_permission_fail(void *d EINA_UNUSED, int t EINA_UNUSED, Empd_Empdd_PermissionFailed_Data *ev)
{
if (ev->code) //code 0 is non-local clients denied
login_show("Enter password", ev->host, ev->port);
return ECORE_CALLBACK_RENEW;
}
static Eina_Bool
empc_database_end()
{
Evas_Object *o;
Eina_List *l;
EINA_LIST_REVERSE_FOREACH(filesystems, l, o)
empd_empdd_list_info_call(empd_proxy, filesystem_base, o, evas_object_data_get(o, "uri"));
return ECORE_CALLBACK_RENEW;
}
static Eina_Bool
empc_status(void *d EINA_UNUSED, int t EINA_UNUSED, Empd_Empdd_Status_Data *ev)
{
Eina_Bool up = EINA_FALSE;
Evas_Object *o;
elm_check_state_set(repeat, ev->repeat);
elm_check_state_set(shuffle, ev->random);
elm_check_state_set(single, ev->single);
elm_check_state_set(consume, ev->consume);
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;
if (evas_object_visible_get(win))
{
char buf[128];
snprintf(buf, sizeof(buf), "%.2d:%.2d", ev->song_elapsed / 60, ev->song_elapsed % 60);
elm_slider_value_set(o, (double)ev->song_elapsed / (double)ev->song_length);
elm_object_part_text_set(o, "empc.text.elapsed", buf);
}
if (empd_song_item && (empd_song_length - empd_song_elapsed == 5)) //try to fetch metadata at 5 seconds remaining
{
Elm_Object_Item *it;
Empd_Empdd_Song *so;
it = elm_genlist_item_next_get(empd_song_item);
if (!it)
it = elm_genlist_first_item_get(queue_list);
so = elm_object_item_data_get(it);
if ((so->artist != empd_song_artist) || (so->album != empd_song_album))
bg_update(bg_next_get(), so->artist, so->album, so->uri);
}
//if (empd_song_item && queue_list_state)
//elm_genlist_item_fields_update(empd_song_item, EMPC_TEXT_TIME, ELM_GENLIST_ITEM_FIELD_TEXT);
}
if (songid_update(ev->songid) | status_update(ev->state))
title_update();
if (clipboard_paste_length)
{
long num = ev->queue_length - clipboard_paste_length;
if (num)
{
empd_empdd_move_list_call(empd_proxy, clipboard_paste_length, num, clipboard_paste_id);
/* handle paste insertions */
clipboard_paste_length = 0;
clipboard_paste_id = -1;
}
}
/* this should only run on startup...other updates are automatic */
if ((!empd_queue_length) && ev->queue_length && (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) + 3;
for (i = 0; i < ev->queue_length; i += step)
{
long num = step;
if (i + num >= ev->queue_length)
num = -1;
empd_empdd_queue_list_cached_range_call(empd_proxy, queue_list_cached, (void*)num, i, num);
}
}
empd_queue_length = ev->queue_length;
if (!filesystems)
{
elm_object_part_content_set(layout_filesystem, EMPC_SWALLOW_FILESYSTEM, filesystem_new("/"));
empd_empdd_list_info_call(empd_proxy, filesystem_base, eina_list_data_get(filesystems), "/");
}
return ECORE_CALLBACK_RENEW;
}
static Evas_Object *
queue_list_item_tooltip_cb(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED, Evas_Object *tooltip, void *item)
{
return tooltip_create(tooltip, item);
}
static void
queue_list_item_unrealize(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info)
{
queue_list_realized = eina_list_remove(queue_list_realized, event_info);
}
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_Empdd_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 if (elm_genlist_item_subitems_count(it))
{
if (eina_list_data_find(elm_genlist_item_subitems_get(it), empd_song_item))
elm_object_item_signal_emit(it, "empc,state,playing", "empc");
else
elm_object_item_signal_emit(it, "empc,state,not_playing", "empc");
}
else
elm_object_item_signal_emit(it, "empc,state,not_playing", "empc");
elm_object_item_tooltip_content_cb_set(it, queue_list_item_tooltip_cb, NULL, NULL);
elm_object_item_tooltip_style_set(it, "empc");
elm_object_item_tooltip_window_mode_set(it, EINA_TRUE);
queue_list_realized = eina_list_append(queue_list_realized, it);
}
static void
queue_list_delete_list(const Eina_List *items)
{
Eina_List *l;
int start = -1, num = 0, total = 0;
Elm_Object_Item *it, *next;
Eina_Bool del_playing = EINA_FALSE;
Empd_Empdd_Song *so;
if (!items) return;
l = eina_list_sort(eina_list_clone(items), 0, (Eina_Compare_Cb)queue_list_sort);
EINA_LIST_FREE(l, it)
{
/* check for contiguous selection */
so = elm_object_item_data_get(it);
if (start == -1)
start = so->song_pos, num = 1;
if (empd_songid == so->songid)
del_playing = EINA_TRUE;
next = elm_genlist_item_next_get(it);
/* fragmentation detected */
if ((next != eina_list_data_get(l->next)) &&
(!elm_genlist_item_subitems_count(next)))
{
//fprintf(stderr, "DEL %d:%d\n", start, num);
empd_empdd_delete_list_range_call(empd_proxy, start, num);
if (del_playing && (empd_state == MPD_STATE_PLAY))
empd_empdd_play_pos_call(empd_proxy, start - total);
start = -1, num = 0;
if (!del_playing)
total += num;
}
else
num++;
}
if (!num) return;
empd_empdd_delete_list_range_call(empd_proxy, start, num - 1);
if ((!del_playing) || (empd_state != MPD_STATE_PLAY)) return;
if ((unsigned int)start < empd_queue_length - ((unsigned int)num - 1))
empd_empdd_play_pos_call(empd_proxy, start - total);
else
empd_empdd_play_call(empd_proxy);
}
static void
queue_list_delete_selected(void)
{
queue_list_delete_list(elm_genlist_selected_items_get(queue_list));
}
static void
queue_list_delete_inverted(void)
{
const Eina_List *items;
Eina_List *l;
int start = -1;
Elm_Object_Item *it, *prev, *next, *hdr = NULL;
int del_playing = -1;
long long song_pos = -1;
Empd_Empdd_Song *so;
items = elm_genlist_selected_items_get(queue_list);
if (!items) return;
l = eina_list_clone(items);
l = eina_list_sort(l, 0, (Eina_Compare_Cb)queue_list_sort);
it = eina_list_data_get(l);
so = elm_object_item_data_get(empd_song_item);
if (so)
song_pos = so->song_pos;
so = elm_object_item_data_get(it);
/* clear songs before selection */
if (so->song_pos)
{
empd_empdd_delete_list_range_call(empd_proxy, 0, so->song_pos);
if (song_pos < so->song_pos)
{
del_playing = 0;
empd_empdd_play_id_call(empd_proxy, 0);
}
}
EINA_LIST_FREE(l, it)
{
if (hdr != elm_genlist_item_parent_get(it))
hdr = elm_genlist_item_parent_get(it);
next = elm_genlist_item_next_get(it);
prev = elm_genlist_item_prev_get(it);
so = elm_object_item_data_get(next);
if (it == empd_song_item)
del_playing = 0;
/* check for contiguous selection */
if ((del_playing == 1) && (empd_state == MPD_STATE_PLAY))
{
empd_empdd_play_id_call(empd_proxy, so->songid);
del_playing = 0;
}
/* fragmentation detected */
if (next != eina_list_data_get(l->next))
{
so = elm_object_item_data_get(next);
start = so->song_pos;
}
if ((start != -1) && (hdr != elm_genlist_item_parent_get(prev)))
{
//fprintf(stderr, "DEL %d:%d\n", start, num);
so = elm_object_item_data_get(prev);
empd_empdd_delete_list_range_call(empd_proxy, start, (so->song_pos - start) + 1);
if ((del_playing == -1) && (song_pos < so->song_pos))
{
empd_empdd_play_id_call(empd_proxy, so->songid);
del_playing = 0;
}
start = -1;
}
}
if (start == -1) return;
empd_empdd_delete_list_range_call(empd_proxy, start, -1);
if ((!del_playing) || (empd_state != MPD_STATE_PLAY)) return;
empd_empdd_play_pos_call(empd_proxy, 0);
}
static void
queue_list_ctxpopup_delete(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
{
queue_list_delete_selected();
elm_ctxpopup_dismiss(ctxpopup);
}
static void
queue_list_ctxpopup_crop(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
{
queue_list_delete_inverted();
elm_ctxpopup_dismiss(ctxpopup);
}
static void
queue_list_ctxpopup_cut(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
{
clipboard_copy();
queue_list_delete_selected();
elm_ctxpopup_dismiss(ctxpopup);
}
static void
queue_list_ctxpopup_paste(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
{
clipboard_paste(-1);
elm_ctxpopup_dismiss(ctxpopup);
}
static void
queue_list_ctxpopup_paste_selection(void *data, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
{
const Eina_List *items;
Eina_List *l;
Elm_Object_Item *it;
Empd_Empdd_Song *so;
intptr_t *after = data;
items = elm_genlist_selected_items_get(queue_list);
if (!items) return;
l = eina_list_clone(items);
l = eina_list_sort(l, 0, (Eina_Compare_Cb)queue_list_sort);
if (after)
it = eina_list_last_data_get(l);
else
it = eina_list_data_get(l);
so = elm_object_item_data_get(it);
clipboard_paste(so->song_pos + (long)after);
elm_ctxpopup_dismiss(ctxpopup);
}
static void
playlist_ctxpopup_del(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
{
Eina_Stringshare *uri;
EINA_LIST_FREE(data, uri)
eina_stringshare_del(uri);
}
static void
playlist_save(void *data, Evas_Object *obj, void *event_info EINA_UNUSED)
{
Eina_Stringshare *uri, *name;
name = elm_entry_entry_get(obj);
if ((!name) || (!name[0])) return;
if (data)
{
evas_object_event_callback_del(ctxpopup, EVAS_CALLBACK_DEL, playlist_ctxpopup_del);
EINA_LIST_FREE(data, uri)
{
empd_empdd_add_to_playlist_call(empd_proxy, name, uri);
eina_stringshare_del(uri);
}
}
else
empd_empdd_save_playlist_call(empd_proxy, name);
elm_ctxpopup_dismiss(ctxpopup);
}
static void
queue_list_ctxpopup_save(void *data, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
{
Evas_Object *ctx, *o;
int x, y, w, h, ox, oy, ow, oh;
Eina_List *save = NULL;
evas_object_geometry_get(ctxpopup, &ox, &oy, &ow, &oh);
elm_ctxpopup_dismiss(ctxpopup);
if (data)
{
const Eina_List *items;
Eina_List *l;
Elm_Object_Item *it;
Empd_Empdd_Song *so;
items = elm_genlist_selected_items_get(queue_list);
if (!items) return;
l = eina_list_clone(items);
l = eina_list_sort(l, 0, (Eina_Compare_Cb)queue_list_sort);
EINA_LIST_FREE(l, it)
{
so = elm_object_item_data_get(it);
save = eina_list_append(save, eina_stringshare_ref(so->uri));
}
}
ctxpopup = ctx = ctxpopup_add(queue_list, "queue_list");
o = elm_entry_add(ctxpopup);
elm_entry_single_line_set(o, 1);
elm_entry_scrollable_set(o, 0);
elm_object_style_set(o, "playlist_save");
evas_object_smart_callback_add(o, "activated", playlist_save, save);
if (save)
evas_object_event_callback_add(ctxpopup, EVAS_CALLBACK_DEL, playlist_ctxpopup_del, save);
elm_entry_entry_set(o, "<Enter playlist name>");
evas_object_size_hint_min_set(o, 40, 10);
elm_object_content_set(ctx, o);
evas_object_show(ctx);
evas_object_geometry_get(ctx, NULL, NULL, &w, &h);
x = ox + (ow / 2);
y = oy + (oh / 2);
evas_object_move(ctx, x - (w / 2), y - (h / 2));
}
static void
queue_list_ctxpopup_show(Evas_Object *obj)
{
Evas_Object *ctx;
const Eina_List *sel;
unsigned int num = 0;
ctxpopup = ctx = ctxpopup_add(obj, "queue_list");
sel = elm_genlist_selected_items_get(queue_list);
ctxpopup_item_append(&num, ctx, "Save to playlist", NULL, queue_list_ctxpopup_save, NULL);
if (sel)
{
ctxpopup_item_append(&num, ctx, "Save selection to playlist", NULL, queue_list_ctxpopup_save, (void*)1);
ctxpopup_item_append(&num, ctx, "Delete selection", NULL, queue_list_ctxpopup_delete, NULL);
ctxpopup_item_append(&num, ctx, "Crop to selection", NULL, queue_list_ctxpopup_crop, NULL);
ctxpopup_item_append(&num, ctx, "Cut selection", NULL, queue_list_ctxpopup_cut, NULL);
ctxpopup_item_append(&num, ctx, "Copy selection", NULL, ctxpopup_copy, NULL);
}
if (eina_array_count(clipboard))
{
ctxpopup_item_append(&num, ctx, "Paste", NULL, queue_list_ctxpopup_paste, NULL);
if (sel)
{
ctxpopup_item_append(&num, ctx, "Paste before selection", NULL, queue_list_ctxpopup_paste_selection, NULL);
ctxpopup_item_append(&num, ctx, "Paste after selection", NULL, queue_list_ctxpopup_paste_selection, (void*)1);
}
}
ctxpopup_mouse_position(ctxpopup);
evas_object_show(ctxpopup);
}
static void
queue_list_item_longpress(void *data EINA_UNUSED, Evas_Object *obj, void *event_info EINA_UNUSED)
{
queue_list_ctxpopup_show(obj);
}
static void
queue_list_item_click(void *data EINA_UNUSED, Evas *e EINA_UNUSED, Evas_Object *obj, void *event_info)
{
Evas_Event_Mouse_Down *ev = event_info;
if (ev->button == 3)
queue_list_ctxpopup_show(obj);
}
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_Empdd_Song *so;
so = elm_object_item_data_get(it);
empd_empdd_play_id_call(empd_proxy, so->songid);
}
static void
queue_list_scroll_stop()
{
queue_list_scroll_item = NULL;
}
static char *
queue_list_header_text_get(Empd_Empdd_Song *so, Evas_Object *obj EINA_UNUSED, const char *part)
{
char buf[1024];
const Eina_List *l;
Elm_Object_Item *it, *itg, *iti;
size_t t = 0;
if (!strcmp(part, EMPC_TEXT_ALBUM))
{
if (so->artist && so->album)
{
snprintf(buf, sizeof(buf), "%s: %s", so->artist, so->album);
return strdup(buf);
}
if (so->artist)
return strdup(so->artist);
return strdup(so->album);
}
it = eina_hash_find(empd_current_queue, &so->songid);
if (!it) return NULL; //redo later
itg = elm_genlist_item_parent_get(it);
EINA_LIST_FOREACH(elm_genlist_item_subitems_get(itg), l, iti)
{
Empd_Empdd_Song *soi = elm_object_item_data_get(iti);
t += soi->duration;
}
snprintf(buf, sizeof(buf), "%.2ld:%.2ld", t / 60, t % 60);
return strdup(buf);
}
static void
queue_list_header_content_del(void *data, Evas *e EINA_UNUSED, Evas_Object *obj, void *event_info EINA_UNUSED)
{
evas_object_event_callback_del(obj, EVAS_CALLBACK_DEL, queue_list_header_content_del);
metadata_fetch_cancel(data, NULL, queue_list_header_image, obj);
}
static void
queue_list_header_image(void *data, Empc_Fetch_Request *req, Evas_Object *obj)
{
Evas_Object *o;
evas_object_event_callback_del_full(data, EVAS_CALLBACK_DEL, queue_list_header_content_del, req);
if (!obj) return;
o = ee_image_add();
ee_image_copy(obj, o, 64);
EXPAND(o);
FILL(o);
evas_object_show(o);
evas_object_box_append(data, o);
evas_object_event_callback_add(data, EVAS_CALLBACK_DEL, item_box_del, o);
evas_object_del(obj);
}
static Evas_Object *
queue_list_header_content_get(Empd_Empdd_Song *so, Evas_Object *obj, const char *part EINA_UNUSED)
{
Evas_Object *o, *cur;
if ((so->album != empd_song_album) || (so->artist != empd_song_artist))
{
Empc_Fetch_Request *req;
cur = evas_object_box_add(evas_object_evas_get(obj));
EXPAND(cur);
FILL(cur);
req = metadata_fetch_begin(EMPC_METADATA_TYPE_IMAGE, obj, so->artist, so->album, so->uri, EINA_FALSE, EINA_FALSE, queue_list_header_image, cur);
evas_object_event_callback_add(cur, EVAS_CALLBACK_DEL, queue_list_header_content_del, req);
return cur;
}
o = elm_object_part_content_get(layout, EMPC_SWALLOW_BACKGROUND);
if ((bgselector_artist_get(o) != empd_song_artist) ||
(bgselector_album_get(o) != empd_song_album))
goto error;
cur = bgselector_get(o);
if (!cur) goto error;
o = ee_image_add();
ee_image_copy(cur, o, 64);
evas_object_size_hint_aspect_set(o, EVAS_ASPECT_CONTROL_NONE, 0, 0);
return o;
error:
bgheader_dirty = EINA_TRUE;
return NULL;
}
static char *
queue_list_item_text_get(Empd_Empdd_Song *so, Evas_Object *obj EINA_UNUSED, const char *part)
{
char buf[1024];
if (!strcmp(part, EMPC_TEXT_TITLE))
return strdup(so->title ?: so->uri);
if (!strcmp(part, EMPC_TEXT_TRACK))
{
if (!so->track) return NULL;
snprintf(buf, sizeof(buf), "%.2d", so->track);
return strdup(buf);
}
//if (empd_songid == so->songid) return NULL;
//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_header_del(Empd_Empdd_Song *so, Evas_Object *obj EINA_UNUSED)
{
Empd_Empdd_Song_free(so);
}
static void
queue_list_item_del(Empd_Empdd_Song *so, Evas_Object *obj EINA_UNUSED)
{
Elm_Object_Item *it, *itg;
Empd_Empdd_Song *sog = NULL;
if (empd_song_item && (elm_object_item_data_get(empd_song_item) == so))
empd_song_item = NULL;
it = eina_hash_set(empd_current_queue, &so->songid, NULL);
itg = elm_genlist_item_parent_get(it);
if (itg)
sog = elm_object_item_data_get(itg);
if (empd_songid == so->songid)
{
elm_object_item_signal_emit(itg, "empc,state,not_playing", "empc");
elm_genlist_item_fields_update(itg, EMPC_TEXT_TIME, ELM_GENLIST_ITEM_FIELD_TEXT);
}
if (sog && (sog->songid == so->songid))
{
it = elm_genlist_item_next_get(it);
if (it && (elm_genlist_item_parent_get(it) == itg))
{
Empd_Empdd_Song_free(sog);
elm_object_item_data_set(itg, Empd_Empdd_Song_copy(elm_object_item_data_get(it)));
elm_genlist_item_fields_update(itg, EMPC_TEXT_TIME, ELM_GENLIST_ITEM_FIELD_TEXT);
}
else if (!elm_genlist_item_subitems_count(itg))
{
char buf[1024];
snprintf(buf, sizeof(buf), "%s:::%s", so->artist, so->album);
//INF("DEL HEADER(%p): %s", itg, buf);
eina_hash_list_remove(empd_current_queue_headers, buf, itg);
if (itg == queue_list_scroll_item)
queue_list_scroll_item = NULL;
elm_object_item_del(itg);
}
else
elm_genlist_item_fields_update(itg, EMPC_TEXT_TIME, ELM_GENLIST_ITEM_FIELD_TEXT);
}
Empd_Empdd_Song_free(so);
}
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_Empdd_Song *so;
Evas_Event_Key_Down *ev = event_info;
if ((!strcmp(ev->key, "KP_Enter")) || (!strcmp(ev->key, "Return")))
{
it = elm_genlist_selected_item_get(obj);
if (!it) return;
so = elm_object_item_data_get(it);
empd_empdd_play_id_call(empd_proxy, so->songid);
}
else if (!strcmp(ev->key, "Delete"))
queue_list_delete_selected();
else if (!strcmp(ev->key, "Home"))
{
it = elm_genlist_first_item_get(queue_list);
elm_genlist_item_selected_set(it, EINA_TRUE);
elm_genlist_item_show(it, ELM_GENLIST_ITEM_SCROLLTO_MIDDLE);
}
else if (!strcmp(ev->key, "End"))
{
it = elm_genlist_last_item_get(queue_list);
if (elm_genlist_item_subitems_count(it))
it = eina_list_last_data_get(elm_genlist_item_subitems_get(it));
elm_genlist_item_selected_set(it, EINA_TRUE);
elm_genlist_item_show(it, ELM_GENLIST_ITEM_SCROLLTO_MIDDLE);
}
}
static Elm_Object_Item *
queue_list_find_insert_point(Empd_Empdd_Song *so)
{
Elm_Object_Item *it, *itp;
Empd_Empdd_Song *soi;
if (!elm_genlist_items_count(queue_list)) return NULL;
if ((unsigned int)so->song_pos > (elm_genlist_items_count(queue_list) / 2))
{
it = elm_genlist_last_item_get(queue_list);
do
{
soi = elm_object_item_data_get(it);
if (so->song_pos >= soi->song_pos) return it;
it = elm_genlist_item_prev_get(it);
} while (it);
return NULL;
}
itp = it = elm_genlist_first_item_get(queue_list);
do
{
soi = elm_object_item_data_get(it);
if (so->song_pos <= soi->song_pos) return itp;
itp = it;
it = elm_genlist_item_next_get(it);
} while (it);
return NULL;
}
static void
queue_list_item_select(void *data EINA_UNUSED, Evas_Object *obj, void *event_info)
{
Elm_Object_Item *i, *itp, *it = event_info;
const Eina_List *items;
Elm_Object_Item *(*fn)(const Elm_Object_Item*) = elm_genlist_item_prev_get;
if (selecting || unselecting) return;
if (!evas_key_modifier_is_set(evas_key_modifier_get(evas_object_evas_get(obj)), "Shift"))
{
const Eina_List *li, *lli;
if (evas_key_modifier_is_set(evas_key_modifier_get(evas_object_evas_get(obj)), "Control")) return;
selecting = EINA_TRUE;
items = elm_genlist_selected_items_get(obj);
EINA_LIST_FOREACH_SAFE(items, li, lli, i)
elm_genlist_item_selected_set(i, (i == it));
selecting = EINA_FALSE;
return;
}
items = elm_genlist_selected_items_get(obj);
if (eina_list_count(items) == 1) return;
selecting = EINA_TRUE;
itp = eina_list_data_get(items);
if (queue_list_sort(itp, it) >= 0)
fn = elm_genlist_item_next_get;
for (i = fn(it); i != itp; i = fn(i))
{
if (!elm_genlist_item_subitems_count(i))
elm_genlist_item_selected_set(i, EINA_TRUE);
}
selecting = EINA_FALSE;
}
static void
queue_list_item_unselect(void *data EINA_UNUSED, Evas_Object *obj, void *event_info)
{
Elm_Object_Item *i, *itp, *it = event_info;
const Eina_List *items, *l, *ll;
if (selecting || unselecting) return;
if (!evas_key_modifier_is_set(evas_key_modifier_get(evas_object_evas_get(obj)), "Shift"))
{
const Eina_List *li, *lli;
if (evas_key_modifier_is_set(evas_key_modifier_get(evas_object_evas_get(obj)), "Control")) return;
unselecting = EINA_TRUE;
items = elm_genlist_selected_items_get(obj);
EINA_LIST_FOREACH_SAFE(items, li, lli, i)
elm_genlist_item_selected_set(i, EINA_FALSE);
elm_genlist_item_selected_set(it, EINA_TRUE);
unselecting = EINA_FALSE;
return;
}
items = elm_genlist_selected_items_get(obj);
if (!items) return;
itp = eina_list_data_get(items);
unselecting = EINA_TRUE;
EINA_LIST_FOREACH_SAFE(items, l, ll, i)
{
if (((queue_list_sort(itp, i) < 0) && (queue_list_sort(it, i) < 0)) ||
((queue_list_sort(itp, i) >= 0) && (queue_list_sort(it, i) >= 0)))
elm_genlist_item_selected_set(i, EINA_FALSE);
}
elm_genlist_item_selected_set(itp, EINA_TRUE);
unselecting = EINA_FALSE;
elm_genlist_item_selected_set(it, EINA_TRUE);
}
static void
queue_list_handler(Eina_Value *value, Eina_Bool update)
{
Empd_Array_Songs *songs = NULL;
Empd_Empdd_Song *so;
const char *album = NULL, *artist = NULL;
Elm_Object_Item *itl = NULL, *ith = NULL;
static Elm_Genlist_Item_Class queue_itc = {
.item_style = "default",
.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
};
static Elm_Genlist_Item_Class header_itc = {
.item_style = "header",
.func = {
.content_get = (Elm_Genlist_Item_Content_Get_Cb)queue_list_header_content_get,
.text_get = (Elm_Genlist_Item_Text_Get_Cb)queue_list_header_text_get,
.del = (Elm_Genlist_Item_Del_Cb)queue_list_header_del
},
.version = ELM_GENLIST_ITEM_CLASS_VERSION
};
if (!azy_value_to_Empd_Array_Songs(value, &songs))
{
EINA_LOG_ERR("conversion failure");
return;
}
if (update && songs->songs)
{
Elm_Object_Item *insert;
Empd_Empdd_Song *exist;
so = eina_list_data_get(songs->songs);
/* find existing song with first updated song's id */
insert = eina_hash_find(empd_current_queue, &so->songid);
if (insert)
{
exist = elm_object_item_data_get(insert);
if (exist->song_pos > so->song_pos)
{
/* songs removed before existing item:
* - remove items until exist has target position
*/
int target = so->song_pos;
Elm_Object_Item *prev, *next = insert;
do
{
insert = elm_genlist_item_prev_get(next);
if (elm_genlist_item_subitems_count(insert))
insert = elm_genlist_item_prev_get(insert);
if (!insert) break;
exist = elm_object_item_data_get(insert);
if (exist->song_pos < target) break;
//fprintf(stderr, "DEL %s\n", exist->title);
elm_object_item_del(insert);
} while (insert);
prev = elm_genlist_item_prev_get(next);
if (prev)
{
Elm_Object_Item *parent;
Empd_Empdd_Song *a, *b;
parent = elm_genlist_item_parent_get(next);
if (!parent) parent = next;
a = elm_object_item_data_get(prev);
b = elm_object_item_data_get(parent);
/* check whether the previous album can be merged with the next one */
if ((a->artist == b->artist) && (a->album == b->album) &&
(parent != elm_genlist_item_parent_get(prev)))
elm_object_item_del(parent);
}
}
}
/* songs being inserted before end */
else if (so->song_pos < eina_hash_population(empd_current_queue))
{
int i, num;
/* delete #items until insert point reached */
num = eina_list_count(songs->songs) -
(empd_queue_length - eina_hash_population(empd_current_queue));
for (i = 0; i < num; i++)
{
Elm_Object_Item *it;
/* skip header item... */
it = elm_genlist_item_prev_get(elm_genlist_last_item_get(queue_list));
//Empd_Empdd_Song *ss = elm_object_item_data_get(it);
//fprintf(stderr, "2863 DEL %s\n", ss->title);
elm_object_item_del(it);
}
}
}
else if (update)
{
while ((unsigned int)eina_hash_population(empd_current_queue) > empd_queue_length)
{
Elm_Object_Item *it;
/* skip header item... */
it = elm_genlist_item_prev_get(elm_genlist_last_item_get(queue_list));
//Empd_Empdd_Song *ss = elm_object_item_data_get(it);
//fprintf(stderr, "2863 DEL %s\n", ss->title);
elm_object_item_del(it);
}
}
EINA_LIST_FREE(songs->songs, so)
{
Elm_Object_Item *it = NULL;
Empd_Empdd_Song *sop;
it = eina_hash_find(empd_current_queue, &so->songid);
if (it)
{
Empd_Empdd_Song *ss = elm_object_item_data_get(it);
if (Empd_Empdd_Song_eq(so, ss))
{
Empd_Empdd_Song_free(so);
so = ss;
}
else
{
Elm_Object_Item *parent;
parent = elm_genlist_item_parent_get(it);
sop = elm_object_item_data_get(parent);
if (Empd_Empdd_Song_eq(sop, ss))
{
Empd_Empdd_Song_free(sop);
elm_object_item_data_set(parent, Empd_Empdd_Song_copy(so));
elm_genlist_item_update(parent);
}
Empd_Empdd_Song_free(ss);
elm_object_item_data_set(it, so);
elm_genlist_item_update(it);
if (so->songid == empd_songid)
{
if ((so->track != empd_song_track) || (empd_song_title != so->title))
{
empd_song_track = so->track;
eina_stringshare_refplace(&empd_song_title, so->title);
title_text_set();
elm_object_tooltip_hide(bg[background_num]);
}
}
}
ith = elm_genlist_item_parent_get(it);
}
if (!it)
{
Elm_Object_Item *itp = NULL;
Eina_Bool end = EINA_FALSE;
if (((!album) && (!artist)) || (album != so->album) || (artist != so->artist) || (!ith))
{
Eina_Bool use = EINA_FALSE;
if ((!ith) || ((!album) && (!artist)))
{
itp = queue_list_find_insert_point(so);
if (itp)
{
sop = elm_object_item_data_get(itp);
if ((sop->album == so->album) && (sop->artist == so->artist))
{
use = EINA_TRUE;
ith = elm_genlist_item_parent_get(itp);
if (!ith) ith = itp;
}
if (itp && (itp == elm_genlist_last_item_get(queue_list)))
end = EINA_TRUE;
}
}
if (!use)
{
char buf[1024];
if (end || (!itp))
ith = elm_genlist_item_append(queue_list, &header_itc, Empd_Empdd_Song_copy(so), NULL, ELM_GENLIST_ITEM_GROUP, NULL, NULL);
else
{
ith = elm_genlist_item_parent_get(itp);
if (!ith) ith = itp;
ith = elm_genlist_item_insert_after(queue_list, &header_itc,
Empd_Empdd_Song_copy(so), NULL, ith, ELM_GENLIST_ITEM_GROUP, NULL, NULL);
}
snprintf(buf, sizeof(buf), "%s:::%s", so->artist, so->album);
//INF("NEW HEADER(%p): %s", ith, buf);
eina_hash_list_append(empd_current_queue_headers, buf, ith);
elm_genlist_item_select_mode_set(ith, ELM_OBJECT_SELECT_MODE_DISPLAY_ONLY);
itp = NULL;
}
}
if (!ith)
{
CRI("NO HEADER ITEM FOUND!!! BUG!!");
abort();
}
if (end || (!itp))
it = elm_genlist_item_append(queue_list, &queue_itc, so, ith, ELM_GENLIST_ITEM_NONE, queue_list_item_select, NULL);
else if (itp)
it = elm_genlist_item_insert_after(queue_list, &queue_itc, so, ith, itp, ELM_GENLIST_ITEM_NONE, queue_list_item_select, NULL);
else
it = elm_genlist_item_sorted_insert(queue_list, &queue_itc, so, ith, ELM_GENLIST_ITEM_NONE, (Eina_Compare_Cb)queue_list_sort, queue_list_item_select, NULL);
eina_hash_add(empd_current_queue, &so->songid, it);
}
if (so->songid == empd_songid)
{
Eina_Bool title;
empd_song_item = it;
/* force updates in case song info has changed */
if ((so->artist != empd_song_artist) || (so->album != empd_song_album))
bg_update(bg_next_get(), so->artist, so->album, so->uri);
eina_stringshare_refplace(&empd_song_album, so->album);
title = eina_stringshare_refplace(&empd_song_title, so->title);
if (title || (empd_song_track != so->track))
elm_object_signal_emit(layout, "empc,title,change,next", "empc");
empd_song_track = so->track;
if (eina_stringshare_refplace(&empd_song_artist, so->artist) || title)
title_update();
}
if ((album != so->album) || (artist != so->artist))
{
if (itl)
elm_genlist_item_fields_update(elm_genlist_item_parent_get(itl), EMPC_TEXT_TIME, ELM_GENLIST_ITEM_FIELD_TEXT);
}
album = so->album;
artist = so->artist;
itl = it;
}
free(songs);
}
static Eina_Bool
empc_queue_list(void *d EINA_UNUSED, int t EINA_UNUSED, Empd_Empdd_QueueList_Data *ev)
{
Elm_Object_Item *it;
it = empd_song_item;
queue_list_handler(ev->value, EINA_FALSE);
if ((!it) || (it != empd_song_item))
elm_genlist_item_show(empd_song_item, ELM_GENLIST_ITEM_SCROLLTO_MIDDLE);
return ECORE_CALLBACK_RENEW;
}
static Eina_Bool
empc_queue_list_changes(void *d EINA_UNUSED, int t EINA_UNUSED, Empd_Empdd_QueueList_Data *ev)
{
Elm_Object_Item *it;
it = empd_song_item;
queue_list_handler(ev->value, EINA_TRUE);
if (empd_song_item && ((!it) || (it != empd_song_item)))
elm_genlist_item_show(empd_song_item, ELM_GENLIST_ITEM_SCROLLTO_MIDDLE);
return ECORE_CALLBACK_RENEW;
}
static Evas_Object *
button_add(const char *icon, const char *text, const char *style, Evas_Smart_Cb cb)
{
Evas_Object *o, *ic;
o = elm_button_add(win);
if (style)
elm_object_style_set(o, style);
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_order_lookup_set(ic, ELM_ICON_LOOKUP_THEME_FDO);
elm_icon_standard_set(ic, icon);
elm_object_part_content_set(o, "icon", ic);
if (text)
elm_object_text_set(o, _(text));
evas_object_show(ic);
evas_object_show(o);
evas_object_smart_callback_add(o, "clicked", cb, NULL);
return o;
}
static void
control_skip_back()
{
empd_empdd_previous_call(empd_proxy);
}
static void
control_skip_back_album()
{
Empd_Empdd_Song *so;
Elm_Object_Item *pick;
if (!empd_song_item) return;
pick = queue_list_header_prev_get(elm_genlist_item_parent_get(empd_song_item));
if ((!pick) || (pick == elm_genlist_item_parent_get(empd_song_item)))
pick = elm_genlist_item_parent_get(elm_genlist_last_item_get(queue_list));
if (!pick)
pick = elm_genlist_last_item_get(queue_list);
so = elm_object_item_data_get(pick);
empd_empdd_play_id_call(empd_proxy, so->songid);
}
static void
control_stop()
{
empd_empdd_stop_call(empd_proxy);
}
static void
control_toggle()
{
if (empd_state == MPD_STATE_PLAY)
empd_empdd_pause_call(empd_proxy, EINA_TRUE);
else
empd_empdd_play_call(empd_proxy);
}
static void
control_skip_forward()
{
empd_empdd_next_call(empd_proxy);
}
static void
control_skip_forward_album()
{
Empd_Empdd_Song *so;
Elm_Object_Item *pick;
if (!empd_song_item) return;
pick = queue_list_header_next_get(elm_genlist_item_parent_get(empd_song_item));
if (!pick)
pick = elm_genlist_item_parent_get(elm_genlist_first_item_get(queue_list));
so = elm_object_item_data_get(pick);
empd_empdd_play_id_call(empd_proxy, so->songid);
}
static void
controls_hiding()
{
elm_layout_signal_emit(evas_object_data_get(win, "slider"), "empc,controls,hiding", "empc");
}
static void
controls_showing()
{
elm_layout_signal_emit(evas_object_data_get(win, "slider"), "empc,controls,showing", "empc");
}
static void
slider_fmt(void *d EINA_UNUSED, Evas_Object *obj, const char *sig, const char *src EINA_UNUSED)
{
const char *num = sig + sizeof("guide,changed,") - 1;
char buf[1024];
double pct;
unsigned int t;
pct = strtof(num, NULL);
t = lround(pct * empd_song_length);
snprintf(buf, sizeof(buf), "%.2d:%.2d", t / 60, t % 60);
elm_slider_indicator_format_set(obj, buf);
}
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_empdd_seek_call(empd_proxy, empd_songid, lround(val * empd_song_length));
}
static int
mouse_wheel(void *data EINA_UNUSED, int t EINA_UNUSED, Ecore_Event_Mouse_Wheel *ev)
{
Elm_Object_Item *it, *pit, *pick = NULL;
int x, y, w;
if (filesystem_state) return ECORE_CALLBACK_RENEW;
if (!(ev->modifiers & ECORE_EVENT_MODIFIER_CTRL)) return ECORE_CALLBACK_RENEW;
elm_layout_signal_emit(layout, "empc,mouse,wheel", "empc");
if (!queue_list_state)
{
if (!empd_song_item) return ECORE_CALLBACK_CANCEL;
if (ev->z < 0) //up
elm_layout_signal_emit(layout, "empc,mouse,wheel,0,-1,ctrl", "empc");
else if (ev->z > 0) //down
elm_layout_signal_emit(layout, "empc,mouse,wheel,0,1,ctrl", "empc");
return ECORE_CALLBACK_CANCEL;
}
if (queue_list_scroll_item)
{
if (ev->z < 0) //up
pick = queue_list_header_prev_get(queue_list_scroll_item);
else if (ev->z > 0) //down
pick = queue_list_header_next_get(queue_list_scroll_item);
elm_genlist_item_bring_in(pick, ELM_GENLIST_ITEM_SCROLLTO_TOP);
queue_list_scroll_item = pick;
return ECORE_CALLBACK_CANCEL;
}
elm_scroller_region_get(queue_list, NULL, NULL, &w, NULL);
evas_object_geometry_get(queue_list, &x, &y, NULL, NULL);
/* FIXME: this should actually calc the height of an item for y */
it = elm_genlist_at_xy_item_get(queue_list, x + (w / 2), y + 2, NULL);
if (!it) return ECORE_CALLBACK_RENEW;
pit = elm_genlist_item_parent_get(it);
if (!pit) pit = it; //already parent
if (!ev->z) return ECORE_CALLBACK_RENEW;
if (ev->z < 0) //up
{
if (pit != it) pick = pit;
else
pick = queue_list_header_prev_get(pit);
}
else if (ev->z > 0)
{
if (pit != it)
{
pick = elm_genlist_item_next_get(pit);
if (pick)
pick = elm_genlist_item_parent_get(pick);
}
else
pick = queue_list_header_next_get(pit);
if (!pick)
pick = elm_genlist_last_item_get(queue_list);
}
elm_genlist_item_bring_in(pick, ELM_GENLIST_ITEM_SCROLLTO_TOP);
queue_list_scroll_item = pick;
return ECORE_CALLBACK_CANCEL;
}
static int
mouse_down(void *data EINA_UNUSED, int t EINA_UNUSED, Ecore_Event_Key *ev EINA_UNUSED)
{
if (evas_object_visible_get(filesystem_entry))
{
Evas_Object *ly;
ly = elm_object_part_content_get(layout, EMPC_SWALLOW_FILESYSTEM);
filesystem_entry_hide(ly);
}
return ECORE_CALLBACK_RENEW;
}
static int
key_down(void *data EINA_UNUSED, int t EINA_UNUSED, Ecore_Event_Key *ev)
{
if (ctxpopup)
{
unsigned int n;
errno = 0;
n = strtoul(ev->key, NULL, 10);
if (!errno)
{
const Eina_List *items;
items = elm_list_items_get(elm_object_content_get(ctxpopup));
if (n && (n <= eina_list_count(items)))
{
Elm_Object_Item *it;
it = eina_list_nth(items, n - 1);
elm_list_item_selected_set(it, 1);
return ECORE_CALLBACK_DONE;
}
}
}
if ((!strcmp(ev->key, "q")) && (ev->modifiers & ECORE_EVENT_MODIFIER_CTRL))
ecore_main_loop_quit();
else if ((!(ev->modifiers & ECORE_EVENT_MODIFIER_CTRL)) && (!ctxpopup) &&
(!queue_list_state) && (!filesystem_state) && (!strcmp(ev->key, "Delete")))
{
if (empd_song_item)
{
Empd_Empdd_Song *so = elm_object_item_data_get(empd_song_item);
empd_empdd_delete_list_range_call(empd_proxy, so->song_pos, 1);
}
}
else if ((!(ev->modifiers & ECORE_EVENT_MODIFIER_CTRL)) && (!ctxpopup) &&
(!queue_list_state) && (!filesystem_state) && (!strcmp(ev->key, "space")))
{
control_toggle();
}
else if (!strcmp(ev->key, "Escape"))
{
if (ctxpopup)
elm_ctxpopup_dismiss(ctxpopup);
else if (bgchooser)
{
bgselector_cancel(elm_object_part_content_get(layout, EMPC_SWALLOW_BACKGROUND));
elm_layout_signal_emit(layout, "empc,bg_chooser,cancel", "empc");
}
return (!ctxpopup) && (!bgchooser);
}
else if (!strcmp(ev->key, "F1"))
{
if (login_visible || ctxpopup) return ECORE_CALLBACK_DONE;
if (filesystem_state)
elm_object_signal_emit(layout, "empc,filesystem,hide", "empc");
elm_object_signal_emit(layout, "empc,overlay,toggle", "empc");
}
else if (!strcmp(ev->key, "F2"))
{
if (login_visible || ctxpopup) return ECORE_CALLBACK_DONE;
if (filesystem_state)
{
if (overlay_locked_state)
elm_object_signal_emit(layout, "empc,overlay,toggle", "empc");
else
elm_object_signal_emit(layout, "empc,filesystem,hide", "empc");
}
else
{
if (!overlay_locked_state)
elm_object_signal_emit(layout, "empc,overlay,toggle", "empc");
elm_object_signal_emit(layout, "empc,filesystem,show", "empc");
}
}
else if (bgchooser && (!strcmp(ev->key, "Down")))
bgselector_next(elm_object_part_content_get(layout, EMPC_SWALLOW_BACKGROUND));
else if (bgchooser && (!strcmp(ev->key, "Up")))
bgselector_prev(elm_object_part_content_get(layout, EMPC_SWALLOW_BACKGROUND));
else if (filesystem_state && evas_object_visible_get(filesystem_entry) && (!strcmp(ev->key, "Down")))
filesystem_entry_key_select(1, 0, 1, ev->modifiers & ECORE_EVENT_MODIFIER_SHIFT);
else if (filesystem_state && evas_object_visible_get(filesystem_entry) && (!strcmp(ev->key, "Up")))
filesystem_entry_key_select(0, 0, -1, ev->modifiers & ECORE_EVENT_MODIFIER_SHIFT);
else if (filesystem_state && evas_object_visible_get(filesystem_entry) && (!strcmp(ev->key, "Left")))
filesystem_entry_key_select(0, -1, 0, ev->modifiers & ECORE_EVENT_MODIFIER_SHIFT);
else if (filesystem_state && evas_object_visible_get(filesystem_entry) && (!strcmp(ev->key, "Right")))
filesystem_entry_key_select(1, 1, 0, ev->modifiers & ECORE_EVENT_MODIFIER_SHIFT);
else if (bgchooser && ((!strcmp(ev->key, "Return")) || (!strcmp(ev->key, "KP_Enter"))))
elm_layout_signal_emit(layout, "empc,bg_chooser,stop", "empc");
else if ((!filesystem_state) && (!queue_list_state) && elm_genlist_selected_item_get(queue_list) &&
((!strcmp(ev->key, "Return")) || (!strcmp(ev->key, "KP_Enter"))))
{
Empd_Empdd_Song *so;
so = elm_object_item_data_get(elm_genlist_selected_item_get(queue_list));
empd_empdd_play_id_call(empd_proxy, so->songid);
}
else if ((!(ev->modifiers & ECORE_EVENT_MODIFIER_CTRL)) && (!(ev->modifiers & ECORE_EVENT_MODIFIER_ALT)) &&
(!(ev->modifiers & ECORE_EVENT_MODIFIER_ALTGR)) && (!(ev->modifiers & ECORE_EVENT_MODIFIER_WIN)))
return ECORE_CALLBACK_RENEW;
if (login_visible) return ECORE_CALLBACK_RENEW;
while (ev->modifiers & ECORE_EVENT_MODIFIER_CTRL)
{
if ((!ctxpopup) && empd_song_item &&
(!queue_list_state) && (!filesystem_state) && (!strcmp(ev->key, "Delete")))
{
Elm_Object_Item *it;
Empd_Empdd_Song *so;
Eina_List *l = NULL;
it = elm_genlist_item_parent_get(empd_song_item);
so = elm_object_item_data_get(it);
it = eina_hash_find(empd_current_queue, &so->songid);
do
{
l = eina_list_append(l, it);
it = elm_genlist_item_next_get(it);
} while (elm_genlist_item_parent_get(it));
queue_list_delete_list(l);
}
else if ((!strcmp(ev->key, "Return")) || (!strcmp(ev->key, "KP_Enter")))
{
if (filesystem_state && evas_object_visible_get(filesystem_entry)) return ECORE_CALLBACK_RENEW;
if (filesystem_state)
filesystem_ctxpopup_show(eina_list_last_data_get(filesystems));
else if (queue_list_state && elm_genlist_selected_items_get(queue_list))
queue_list_ctxpopup_show(queue_list);
}
else if (filesystem_state && evas_object_visible_get(filesystem_entry)) return ECORE_CALLBACK_RENEW;
else if (!strcmp(ev->key, "a"))
{
if (filesystem_state)
{
Elm_Object_Item *it;
for (it = elm_gengrid_first_item_get(eina_list_last_data_get(filesystems)); it; it = elm_gengrid_item_next_get(it))
elm_gengrid_item_selected_set(it, EINA_TRUE);
}
else if (queue_list_state)
{
Elm_Object_Item *it;
selecting = EINA_TRUE;
for (it = elm_genlist_first_item_get(queue_list); it; it = elm_genlist_item_next_get(it))
{
if (!elm_genlist_item_parent_get(it)) continue; //header
elm_genlist_item_selected_set(it, EINA_TRUE);
}
selecting = EINA_FALSE;
}
}
else if (!strcmp(ev->key, "x"))
{
if (!clipboard_copy())
return ECORE_CALLBACK_RENEW;
queue_list_delete_selected();
}
else if (!strcmp(ev->key, "c"))
{
if (!clipboard_copy())
return ECORE_CALLBACK_RENEW;
}
else if (!strcmp(ev->key, "v"))
{
if (queue_list_state && (!filesystem_state))
{
Elm_Object_Item *it;
const Eina_List *l;
Empd_Empdd_Song *soi, *so = NULL;
EINA_LIST_FOREACH(elm_genlist_selected_items_get(queue_list), l, it)
{
soi = elm_object_item_data_get(it);
if ((!so) || (soi->song_pos > so->song_pos))
so = soi;
}
if (so && ((unsigned int)so->song_pos == empd_queue_length - 1))
so = NULL;
if (!clipboard_paste(so ? so->song_pos + 1 : (long long)empd_queue_length))
return ECORE_CALLBACK_RENEW;
break;
}
if ((!lyrics_visible) && (!bg_pasting) &&
((!filesystem_state) || (eina_list_count(elm_gengrid_selected_items_get(eina_list_last_data_get(filesystems))) == 1)))
elm_cnp_selection_get(win, ELM_SEL_TYPE_CLIPBOARD, ELM_SEL_FORMAT_IMAGE | ELM_SEL_FORMAT_TEXT, (Elm_Drop_Cb)bg_paste, NULL);
}
break;
}
return ECORE_CALLBACK_DONE;
}
static int
module_sort_cb(Empc_Module *a, Empc_Module *b)
{
return a->priority - b->priority;
}
static Eina_Bool
module_check(Eina_Module *m, void *d EINA_UNUSED)
{
const char *filename;
Empc_Module *mod;
Empc_Module_Type type = EMPC_MODULE_TYPE_LAST;
Empc_Module_Type_Cb type_cb;
Empc_Module_Remote_Cb remote_cb;
Empc_Module_Priority_Cb prio_cb;
filename = eina_module_file_get(m);
filename = strrchr(filename, '/') + 1;
if (strcmp(filename + (strlen(filename) - 3), SHARED_LIB_SUFFIX))
return EINA_FALSE;
if (!eina_module_load(m))
{
ERR("Could not verify module named '%s'. Error: '%s'", filename, eina_error_msg_get(eina_error_get()));
return EINA_FALSE;
}
type_cb = eina_module_symbol_get(m, "empc_module_type");
if (!type_cb) goto error;
type = type_cb();
if (type >= EMPC_MODULE_TYPE_LAST)
{
ERR("Unimplemented module type!");
goto error;
}
prio_cb = eina_module_symbol_get(m, "empc_module_priority");
remote_cb = eina_module_symbol_get(m, "empc_module_remote");
mod = calloc(1, empc_module_size[type]);
mod->type = type;
if (prio_cb)
mod->priority = prio_cb();
if (remote_cb)
mod->remote = remote_cb();
mod->module = m;
empc_modules[type] = eina_inlist_sorted_insert(empc_modules[type], EINA_INLIST_GET(mod), (Eina_Compare_Cb)module_sort_cb);
switch (type)
{
case EMPC_MODULE_TYPE_METADATA_FETCH:
{
Empc_Module_Metadata_Fetch *em = (Empc_Module_Metadata_Fetch*)mod;
em->fetch = eina_module_symbol_get(m, "empc_module_metadata_fetch");
em->cancel = eina_module_symbol_get(m, "empc_module_metadata_cancel");
break;
}
case EMPC_MODULE_TYPE_METADATA_SAVER:
{
Empc_Module_Metadata_Save *es = (Empc_Module_Metadata_Save*)mod;
es->save_image = eina_module_symbol_get(m, "empc_module_metadata_save_image");
es->save_text = eina_module_symbol_get(m, "empc_module_metadata_save_text");
break;
}
case EMPC_MODULE_TYPE_MISC:
{
//Empc_Module_Misc *ems = (Empc_Module_Misc*)mod;
break;
}
default: break;
}
INF("MODULE LOAD(%s)", strrchr(eina_module_file_get(mod->module), '/') + 1);
return EINA_TRUE;
error:
eina_module_unload(m);
return EINA_FALSE;
}
static void
lyrics_request()
{
if (elm_object_part_content_get(layout, EMPC_SWALLOW_LYRICS))
elm_object_signal_emit(layout, "empc,lyrics,show", "empc");
else
{
Empd_Empdd_Song *so;
const char *uri = NULL;
if (empd_song_item)
{
so = elm_object_item_data_get(empd_song_item);
uri = so->uri;
}
metadata_fetch_begin(EMPC_METADATA_TYPE_TEXT, layout, empd_song_artist, empd_song_title, uri, EINA_FALSE, EINA_FALSE, lyrics_set, NULL);
}
}
static void
lyrics_show(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED, const char *sig EINA_UNUSED, const char *src EINA_UNUSED)
{
lyrics_visible = EINA_TRUE;
}
static void
lyrics_hide(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED, const char *sig EINA_UNUSED, const char *src EINA_UNUSED)
{
lyrics_visible = EINA_FALSE;
}
static void
mode_toggle(void *data EINA_UNUSED, Evas_Object *obj, const char *sig EINA_UNUSED, const char *src EINA_UNUSED)
{
if (obj == repeat)
empd_empdd_repeat_call(empd_proxy, !elm_check_state_get(obj));
else if (obj == shuffle)
empd_empdd_shuffle_call(empd_proxy, !elm_check_state_get(obj));
else if (obj == single)
empd_empdd_single_call(empd_proxy, !elm_check_state_get(obj));
else
empd_empdd_consume_call(empd_proxy, !elm_check_state_get(obj));
}
static void
bg_chooser_next(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED, const char *sig EINA_UNUSED, const char *src EINA_UNUSED)
{
bgselector_next(elm_object_part_content_get(layout, EMPC_SWALLOW_BACKGROUND));
}
static void
bg_chooser_prev(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED, const char *sig EINA_UNUSED, const char *src EINA_UNUSED)
{
bgselector_prev(elm_object_part_content_get(layout, EMPC_SWALLOW_BACKGROUND));
}
static void
bg_chooser_show(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED, const char *sig EINA_UNUSED, const char *src EINA_UNUSED)
{
Evas_Object *bgs;
Empd_Empdd_Song *so;
const char *uri = NULL;
if (empd_song_item)
{
so = elm_object_item_data_get(empd_song_item);
uri = so->uri;
}
bgchooser = EINA_TRUE;
bgs = elm_object_part_content_get(layout, EMPC_SWALLOW_BACKGROUND);
bgfetch = metadata_fetch_begin(EMPC_METADATA_TYPE_IMAGE, bgs, empd_song_artist, empd_song_album, uri, EINA_TRUE, EINA_FALSE, bg_add, NULL);
bgselector_active_set(bgs, EINA_TRUE);
elm_object_tooltip_hide(bgs);
}
static void
bg_chooser_hide(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED, const char *sig, const char *src EINA_UNUSED)
{
Evas_Object *bgs, *img;
Eina_Stringshare *artist, *album;
if (!bgchooser) return;
bgs = elm_object_part_content_get(layout, EMPC_SWALLOW_BACKGROUND);
bgselector_prune(bgs);
bgselector_active_set(bgs, EINA_FALSE);
img = bgselector_get(bgs);
artist = bgselector_artist_get(bgs);
album = bgselector_album_get(bgs);
metadata_fetch_cancel(bgfetch, bgs, bg_add, NULL);
bgchooser = EINA_FALSE;
evas_event_feed_mouse_out(evas_object_evas_get(win), 0, NULL);
evas_event_feed_mouse_in(evas_object_evas_get(win), 0, NULL);
if (!img)
elm_object_signal_emit(layout, "empc,info,show", "empc");
if (!strcmp(sig + sizeof("empc,bg_chooser,") - 1, "canceled")) return;
save_image(EINA_TRUE, img, NULL, artist, album, bg_update_signal);
bg_update_propogate(artist, album);
}
static void
queue_list_show(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED, const char *sig EINA_UNUSED, const char *src EINA_UNUSED)
{
queue_list_state = EINA_TRUE;
elm_object_focus_set(queue_list, !login_visible);
}
static void
queue_list_hide(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED, const char *sig EINA_UNUSED, const char *src EINA_UNUSED)
{
Elm_Object_Item *it;
Eina_List *l;
queue_list_state = EINA_FALSE;
EINA_LIST_FOREACH(queue_list_realized, l, it)
elm_object_item_signal_emit(it, "empc,state,hidden", "empc");
}
static void
queue_list_showing(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED, const char *sig EINA_UNUSED, const char *src EINA_UNUSED)
{
Elm_Object_Item *it;
Eina_List *l;
if (empd_song_item)
elm_genlist_item_fields_update(empd_song_item, EMPC_TEXT_TIME, ELM_GENLIST_ITEM_FIELD_TEXT);
EINA_LIST_FOREACH(queue_list_realized, l, it)
elm_object_item_signal_emit(it, "empc,state,visible", "empc");
}
static void
queue_list_hiding(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED, const char *sig EINA_UNUSED, const char *src EINA_UNUSED)
{
evas_object_del(ctxpopup);
ctxpopup = NULL;
}
static void
overlay_locked(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED, const char *sig EINA_UNUSED, const char *src EINA_UNUSED)
{
overlay_locked_state = EINA_TRUE;
}
static void
overlay_unlocked(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED, const char *sig EINA_UNUSED, const char *src EINA_UNUSED)
{
overlay_locked_state = EINA_FALSE;
}
static void
theme_load(void)
{
const char *themepath;
char buf[PATH_MAX];
themepath = getenv("EMPC_THEME");
if (!themepath)
snprintf(buf, sizeof(buf), "%s/empc.edj", PACKAGE_DATA_DIR);
elm_theme_overlay_add(NULL, themepath ?: buf);
}
static void
login_port_filter(void *d EINA_UNUSED, Evas_Object *obj EINA_UNUSED, char **text)
{
char *p;
Eina_Bool done = EINA_FALSE;
if (eina_strlen_bounded(*text, 6) == 6)
*text[5] = 0;
for (p = *text; p[0]; p++)
{
if ((p[0] < '0') || (p[0] > '9'))
done = EINA_TRUE;
if (done)
p[0] = 0;
}
}
static void
dbus_name_changed(void *data EINA_UNUSED, const char *bus EINA_UNUSED, const char *old_id EINA_UNUSED, const char *new_id)
{
master = !strcmp(new_id, eldbus_connection_unique_name_get(dbus_conn));
}
static void
dbus_request_name(void *data EINA_UNUSED, const Eldbus_Message *msg, Eldbus_Pending *pending EINA_UNUSED)
{
unsigned int reply;
if (eldbus_message_error_get(msg, NULL, NULL))
return;
if (!eldbus_message_arguments_get(msg, "u", &reply))
return;
master = reply == ELDBUS_NAME_REQUEST_REPLY_PRIMARY_OWNER;
}
static void
dbus_getbg_fetch_cb(void *data, Empc_Fetch_Request *req EINA_UNUSED, Evas_Object *obj)
{
Eldbus_Message *ret = data;
Eina_Stringshare *f = NULL, *g = NULL;
elm_image_file_get(obj, &f, &g);
eldbus_message_arguments_append(ret, "ss", f ?: "", g ?: "");
eldbus_connection_send(dbus_conn, ret, NULL, NULL, -1);
evas_object_del(obj);
}
static Eldbus_Message *
dbus_getbg(const Eldbus_Service_Interface *iface EINA_UNUSED, const Eldbus_Message *msg)
{
Eldbus_Message *ret;
Evas_Object *cur, *o;
Eina_Stringshare *f = NULL, *g = NULL;
Empd_Empdd_Song *so;
o = elm_object_part_content_get(layout, EMPC_SWALLOW_BACKGROUND);
cur = bgselector_get(o);
elm_image_file_get(cur, &f, &g);
ret = eldbus_message_method_return_new(msg);
if (f)
{
eldbus_message_arguments_append(ret, "ss", f ?: "", g ?: "");
return ret;
}
so = elm_object_item_data_get(empd_song_item);
metadata_fetch_begin(EMPC_METADATA_TYPE_IMAGE, win, empd_song_artist, empd_song_title, so->uri, EINA_FALSE, EINA_TRUE, dbus_getbg_fetch_cb, ret);
return NULL;
}
static Eldbus_Message *
dbus_setbgfile(const Eldbus_Service_Interface *iface EINA_UNUSED, const Eldbus_Message *msg)
{
const char *artist, *album, *file, *key;
Evas_Object *img;
if (!eldbus_message_arguments_get(msg, "ssss", &artist, &album, &file, &key))
return eldbus_message_method_return_new(msg);
img = elm_image_add(win);
elm_image_fill_outside_set(img, EINA_FALSE);
elm_image_smooth_set(img, EINA_FALSE);
elm_image_file_set(img, file, key);
save_image(EINA_TRUE, img, NULL, artist, album, bg_update_signal);
if (eina_streq(artist, empd_song_artist) && eina_streq(album, empd_song_album))
{
background_num = bg_next_get();
bgselector_clear(bg[background_num]);
bgselector_info_set(bg[background_num], empd_song_artist, empd_song_album);
bgselector_image_add(bg[background_num], img);
elm_object_signal_emit(layout, "empc,bg,next", "empc");
}
bg_update_propogate(artist, album);
return eldbus_message_method_return_new(msg);
}
static Eldbus_Message *
dbus_setbgdata(const Eldbus_Service_Interface *iface EINA_UNUSED, const Eldbus_Message *msg)
{
const char *artist, *album, *uri;
Eldbus_Message_Iter *array;
Evas_Object *img;
void *px;
int size;
if (!eldbus_message_arguments_get(msg, "sssay", &artist, &album, &uri, &array))
return eldbus_message_method_return_new(msg);
if (!eldbus_message_iter_fixed_array_get(array, 'y', &px, &size))
return eldbus_message_method_return_new(msg);
img = elm_image_add(win);
elm_image_fill_outside_set(img, EINA_FALSE);
elm_image_smooth_set(img, EINA_FALSE);
elm_image_memfile_set(img, px, size, NULL, NULL);
save_image(EINA_TRUE, img, uri, artist, album, bg_update_signal);
if (eina_streq(artist, empd_song_artist) && eina_streq(album, empd_song_album))
{
background_num = bg_next_get();
bgselector_clear(bg[background_num]);
bgselector_info_set(bg[background_num], empd_song_artist, empd_song_album);
bgselector_image_add(bg[background_num], img);
elm_object_signal_emit(layout, "empc,bg,next", "empc");
}
bg_update_propogate(artist, album);
return eldbus_message_method_return_new(msg);
}
static const Eldbus_Signal empc_signals[] =
{
[EMPC_SIGNAL_BACKGROUND_CHANGED] = {"BackgroundChanged", ELDBUS_ARGS({"s", "file"}, {"s", "key"}), 0},
{NULL, NULL, 0}
};
static const Eldbus_Method empc_methods[] =
{
{ "SetBackgroundFile", ELDBUS_ARGS({"s", "artist"}, {"s", "album"}, {"s", "file"}, {"s", "key"}), NULL, dbus_setbgfile, 0},
{ "SetBackgroundData", ELDBUS_ARGS({"s", "artist"}, {"s", "album"}, {"s", "uri"}, {"ay", "bytes"}), NULL, dbus_setbgdata, 0},
{ "GetBackground", NULL, ELDBUS_ARGS({"s", "file"}, {"s", "key"}), dbus_getbg, 0},
{NULL, NULL, NULL, NULL, 0}
};
static const Eldbus_Service_Interface_Desc base_desc =
{
EMPC_METHOD_BASE, empc_methods, empc_signals, NULL, NULL, NULL
};
static void
empd_send_connect(void)
{
const char *h, *pass = NULL, *p = NULL;
char host[PATH_MAX] = {0};
int port = DEFAULT_PORT;
pass = getenv("MPD_PASSWORD");
p = getenv("MPD_PORT");
h = getenv("MPD_HOST");
if (h)
{
if (!p)
p = strchr(h, ':');
if (p)
{
if (p - h > PATH_MAX - 1)
{
fprintf(stderr, "MPD_HOST longer than 4096 chars? I don't believe you.\n");
empd_empdd_is_connected_call(empd_proxy, empc_isconnected, NULL);
return;
}
port = strtol(p + 1, NULL, 10);
memcpy(host, h, p - h);
h = host;
}
}
else
{
struct stat st;
if (!stat("/var/lib/mpd/socket", &st))
h = "/var/lib/mpd/socket";
else if (!stat("/run/mpd/socket", &st))
h = "/run/mpd/socket";
}
if (h)
empd_empdd_connect_call(empd_proxy, h ?: "", port, pass ?: "");
else
empd_empdd_is_connected_call(empd_proxy, empc_isconnected, NULL);
}
static void
empd_name_start(void *data EINA_UNUSED, const Eldbus_Message *msg, Eldbus_Pending *pending EINA_UNUSED)
{
unsigned flag = 0;
if ((!eldbus_message_arguments_get(msg, "u", &flag)) || (!flag))
{
error_o_doom();
return;
}
if (flag == ELDBUS_NAME_START_REPLY_SUCCESS)
empd_send_connect();
else
empd_empdd_is_connected_call(empd_proxy, empc_isconnected, NULL);
}
int
main(int argc, char *argv[])
{
Evas_Object *o, *hbox;
int i;
const char *modpath;
Eina_Array *mods;
Eina_Free_Cb free_cbs[] =
{
[EMPC_METADATA_TYPE_IMAGE] = (Eina_Free_Cb)fetch_req_free,
[EMPC_METADATA_TYPE_TEXT] = (Eina_Free_Cb)fetch_req_free,
};
eina_init();
ecore_app_no_system_modules();
eldbus_init();
efreet_init();
ecore_event_init();
E_LIST_HANDLER_APPEND(handlers, ECORE_EVENT_KEY_DOWN, key_down, NULL);
E_LIST_HANDLER_APPEND(handlers, ECORE_EVENT_MOUSE_BUTTON_DOWN, mouse_down, NULL);
E_LIST_HANDLER_APPEND(handlers, ECORE_EVENT_MOUSE_WHEEL, mouse_wheel, NULL);
elm_init(argc, argv);
elm_config_scale_set(1.3);
elm_config_focus_highlight_enabled_set(0);
elm_config_focus_highlight_animate_set(0);
eina_log_domain_level_set("evas_main", EINA_LOG_LEVEL_CRITICAL);
eina_log_domain_level_set("edje", EINA_LOG_LEVEL_CRITICAL);
empc_log_dom = eina_log_domain_register("empc", EINA_COLOR_YELLOW);
eina_log_domain_level_set("empc", EINA_LOG_LEVEL_DBG);
{
char buf[PATH_MAX];
snprintf(buf, sizeof(buf), "%s/empc/metadata", efreet_cache_home_get());
ecore_file_mkpath(buf);
}
theme_load();
clipboard = eina_array_new(10);
empd_current_queue = eina_hash_int32_new(NULL);
empd_current_queue_headers = eina_hash_string_superfast_new(NULL);
for (i = 0; i < EMPC_METADATA_TYPE_LAST; i++)
empc_metadata_fetch_reqs[i] = eina_hash_string_superfast_new(free_cbs[i]);
elm_policy_set(ELM_POLICY_QUIT, ELM_POLICY_QUIT_LAST_WINDOW_CLOSED);
dbus_conn = eldbus_connection_get(ELDBUS_CONNECTION_TYPE_SESSION);
eldbus_name_start(dbus_conn, EMPDD_METHOD_BASE, 0, empd_name_start, NULL);
empc_proxy = empd_empc_proxy_get(dbus_conn, EMPC_METHOD_BASE, NULL);
empd_proxy = empd_empdd_proxy_get(dbus_conn, EMPDD_METHOD_BASE, NULL);
eldbus_name_request(dbus_conn, EMPC_METHOD_BASE, 0, dbus_request_name, NULL);
eldbus_name_owner_changed_callback_add(dbus_conn, EMPC_METHOD_BASE, dbus_name_changed, NULL, EINA_FALSE);
empc_iface = eldbus_service_interface_register(dbus_conn, "/", &base_desc);
modpath = getenv("EMPC_MODULE_DIR");
mods = eina_module_list_get(NULL, modpath ?: EMPC_MODULE_PATH, EINA_FALSE, (Eina_Module_Cb)module_check, NULL);
eina_array_free(mods);
{
char buf[PATH_MAX];
snprintf(buf, sizeof(buf), "%s/empc/modules", efreet_config_home_get());
mods = eina_module_list_get(NULL, buf, EINA_FALSE, (Eina_Module_Cb)module_check, NULL);
eina_array_free(mods);
}
E_LIST_HANDLER_APPEND(handlers, EMPD_EMPDD_CONNECTED_EVENT, empc_connected, NULL);
E_LIST_HANDLER_APPEND(handlers, EMPD_EMPDD_DISCONNECTED_EVENT, empc_disconnected, NULL);
E_LIST_HANDLER_APPEND(handlers, EMPD_EMPDD_LOGIN_FAILED_EVENT, empc_login_fail, NULL);
E_LIST_HANDLER_APPEND(handlers, EMPD_EMPDD_PERMISSION_FAILED_EVENT, empc_permission_fail, NULL);
E_LIST_HANDLER_APPEND(handlers, EMPD_EMPDD_STATUS_EVENT, empc_status, NULL);
E_LIST_HANDLER_APPEND(handlers, EMPD_EMPDD_QUEUE_LIST_EVENT, empc_queue_list, NULL);
E_LIST_HANDLER_APPEND(handlers, EMPD_EMPDD_QUEUE_CHANGES_META_EVENT, empc_queue_list_changes, NULL);
E_LIST_HANDLER_APPEND(handlers, EMPD_EMPDD_DATABASE_UPDATE_END_EVENT, empc_database_end, NULL);
E_LIST_HANDLER_APPEND(handlers, EMPD_EMPC_BACKGROUND_CHANGED_EVENT, empc_bg_changed, NULL);
win = elm_win_add(NULL, "empc", ELM_WIN_BASIC);
elm_object_style_set(win, "empc");
elm_win_title_set(win, "empc");
elm_win_autodel_set(win, 1);
layout = elm_layout_add(win);
elm_object_focus_allow_set(layout, 0);
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,artist,changed,1", "empc", artist_changed, NULL);
elm_object_signal_callback_add(layout, "empc,album,changed,1", "empc", album_changed, NULL);
elm_object_signal_callback_add(layout, "empc,title,changed,1", "empc", title_changed, NULL);
elm_object_signal_callback_add(layout, "empc,play,toggle", "empc", control_toggle, NULL);
elm_object_signal_callback_add(layout, "empc,play,stop", "empc", control_stop, NULL);
elm_object_signal_callback_add(layout, "empc,play,prev", "empc", control_skip_back, NULL);
elm_object_signal_callback_add(layout, "empc,play,prev_album", "empc", control_skip_back_album, NULL);
elm_object_signal_callback_add(layout, "empc,play,next", "empc", control_skip_forward, NULL);
elm_object_signal_callback_add(layout, "empc,play,next_album", "empc", control_skip_forward_album, NULL);
elm_object_signal_callback_add(layout, "empc,lyrics,request", "empc", lyrics_request, NULL);
elm_object_signal_callback_add(layout, "empc,lyrics,visible", "empc", lyrics_show, NULL);
elm_object_signal_callback_add(layout, "empc,lyrics,hidden", "empc", lyrics_hide, NULL);
elm_object_signal_callback_add(layout, "empc,playlist,visible", "empc", queue_list_show, NULL);
elm_object_signal_callback_add(layout, "empc,playlist,hidden", "empc", queue_list_hide, NULL);
elm_object_signal_callback_add(layout, "empc,playlist,hiding", "empc", queue_list_hiding, NULL);
elm_object_signal_callback_add(layout, "empc,playlist,showing", "empc", queue_list_showing, NULL);
elm_object_signal_callback_add(layout, "empc,controls,hiding", "empc", controls_hiding, NULL);
elm_object_signal_callback_add(layout, "empc,controls,showing", "empc", controls_showing, NULL);
elm_object_signal_callback_add(layout, "empc,filesystem,showing", "empc", filesystem_showing, NULL);
elm_object_signal_callback_add(layout, "empc,filesystem,visible", "empc", filesystem_show, NULL);
elm_object_signal_callback_add(layout, "empc,filesystem,hidden", "empc", filesystem_hide, NULL);
elm_object_signal_callback_add(layout, "empc,filesystem,hiding", "empc", filesystem_hiding, NULL);
elm_object_signal_callback_add(layout, "empc,bg_chooser,active", "empc", bg_chooser_show, NULL);
elm_object_signal_callback_add(layout, "empc,bg_chooser,inactive", "empc", bg_chooser_hide, NULL);
elm_object_signal_callback_add(layout, "empc,bg_chooser,canceled", "empc", bg_chooser_hide, NULL);
elm_object_signal_callback_add(layout, "empc,bg_chooser,next", "empc", bg_chooser_next, NULL);
elm_object_signal_callback_add(layout, "empc,bg_chooser,prev", "empc", bg_chooser_prev, NULL);
elm_object_signal_callback_add(layout, "empc,overlay,locked", "empc", overlay_locked, NULL);
elm_object_signal_callback_add(layout, "empc,overlay,unlocked", "empc", overlay_unlocked, NULL);
evas_object_show(layout);
{
const char *toggles[] =
{
EMPC_SWALLOW_REPEAT,
EMPC_SWALLOW_SHUFFLE,
EMPC_SWALLOW_SINGLE,
EMPC_SWALLOW_CONSUME
};
const char *icons[] =
{
"repeat",
"shuffle",
"single",
"consume"
};
Evas_Object **objs[] =
{
&repeat,
&shuffle,
&single,
&consume,
};
const char *tooltips[] =
{
"Toggle Repeat play mode",
"Toggle Random play mode",
"Toggle Repeat-Single mode",
"Toggle Consume-On-Play mode",
};
for (i = 0; i < 4; i++)
{
Evas_Object *img;
o = elm_check_add(win);
elm_object_tooltip_text_set(o, tooltips[i]);
elm_object_tooltip_style_set(o, "empc");
elm_object_style_set(o, "mode_toggle");
img = elm_icon_add(win);
elm_icon_order_lookup_set(img, ELM_ICON_LOOKUP_THEME);
elm_icon_standard_set(img, icons[i]);
elm_object_content_set(o, img);
elm_object_part_content_set(layout, toggles[i], o);
elm_object_signal_callback_add(o, "empc,check,toggle", "empc", mode_toggle, NULL);
*objs[i] = o;
}
}
for (i = 0; i < 2; i++)
{
bg[i] = bgselector_add(win);
elm_object_tooltip_content_cb_set(bg[i], bg_tooltip_cb, NULL, NULL);
elm_object_tooltip_style_set(bg[i], "empc");
elm_object_tooltip_window_mode_set(bg[i], EINA_TRUE);
}
elm_object_part_content_set(layout, EMPC_SWALLOW_BACKGROUND, bg[0]);
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", NULL, "empc", control_skip_back);
elm_object_tooltip_text_set(o, _("Previous song"));
elm_object_tooltip_style_set(o, "empc");
elm_box_pack_end(hbox, o);
o = button_add("media_player/stop", NULL, "empc", control_stop);
elm_object_tooltip_text_set(o, _("Stop"));
elm_object_tooltip_style_set(o, "empc");
elm_box_pack_end(hbox, o);
o = button_add("media_player/play", NULL, "empc", control_toggle);
elm_object_tooltip_text_set(o, _("Play/Pause"));
elm_object_tooltip_style_set(o, "empc");
evas_object_data_set(win, "play_button", o);
elm_box_pack_end(hbox, o);
o = button_add("media_player/next", NULL, "empc", control_skip_forward);
elm_object_tooltip_text_set(o, _("Next song"));
elm_object_tooltip_style_set(o, "empc");
elm_box_pack_end(hbox, o);
elm_object_part_content_set(layout, EMPC_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_object_signal_callback_add(o, "guide,changed,*", "empc", slider_fmt, NULL);
elm_slider_min_max_set(o, 0.0, 1.0);
elm_object_part_content_set(layout, EMPC_SWALLOW_POSITION, o);
evas_object_show(o);
queue_list = o = elm_genlist_add(win);
elm_object_style_set(o, "playlist");
evas_object_smart_callback_add(o, "longpressed", queue_list_item_longpress, NULL);
evas_object_event_callback_add(o, EVAS_CALLBACK_MOUSE_DOWN, queue_list_item_click, NULL);
evas_object_smart_callback_add(o, "realized", queue_list_item_realize, NULL);
evas_object_smart_callback_add(o, "unrealized", queue_list_item_unrealize, NULL);
evas_object_smart_callback_add(o, "unselected", queue_list_item_unselect, NULL);
evas_object_smart_callback_add(o, "clicked,double", queue_list_double_click, NULL);
evas_object_smart_callback_add(o, "scroll,anim,stop", queue_list_scroll_stop, 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_DEFAULT);
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_SWALLOW_PLAYLIST, o);
evas_object_show(o);
evas_object_focus_set(o, EINA_TRUE);
{
const char *parts[] =
{
EMPC_LOGIN_SWALLOW_PORT,
EMPC_LOGIN_SWALLOW_HOST,
EMPC_LOGIN_SWALLOW_PASSWORD
};
Evas_Object **objs[] =
{
&login_port,
&login_host,
&login_password,
};
for (i = 0; i < 3; i++)
{
*objs[i] = o = elm_entry_add(win);
elm_entry_single_line_set(o, 1);
elm_entry_scrollable_set(o, 0);
elm_entry_password_set(o, i == 2);
if (!i)
elm_entry_markup_filter_append(o, login_port_filter, NULL);
elm_object_style_set(o, "login");
evas_object_smart_callback_add(o, "activated", login_connect, NULL);
elm_object_part_content_set(layout, parts[i], o);
}
elm_layout_signal_callback_add(layout, "empc,login,close,request", "empc", login_close_request, NULL);
}
{
Evas_Object *ly;
layout_filesystem = ly = elm_layout_add(win);
elm_object_focus_allow_set(ly, 0);
elm_layout_theme_set(ly, "layout", "empc", "filesystem");
elm_layout_signal_emit(ly, "empc,back,hide", "empc");
elm_layout_signal_callback_add(ly, "empc,search,hidden", "empc", filesystem_search_hidden, NULL);
elm_layout_signal_callback_add(ly, "empc,search,visible", "empc", filesystem_search_visible, NULL);
elm_object_part_content_set(layout, EMPC_SWALLOW_FILESYSTEM, ly);
filesystem_entry = o = elm_entry_add(win);
elm_object_style_set(o, "filesystem");
evas_object_event_callback_add(o, EVAS_CALLBACK_KEY_DOWN, filesystem_entry_key, NULL);
elm_entry_single_line_set(o, 1);
elm_entry_scrollable_set(o, 0);
elm_object_part_content_set(ly, "empc.swallow.search", o);
o = button_add("fs-back", NULL, "empc", filesystem_button_back);
elm_object_tooltip_text_set(o, _("Go to parent directory"));
WEIGHT(o, EVAS_HINT_EXPAND, 0);
FILL(o);
elm_object_part_content_set(ly, "empc.swallow.back", o);
hbox = elm_box_add(win);
WEIGHT(hbox, EVAS_HINT_EXPAND, 0);
FILL(hbox);
elm_box_horizontal_set(hbox, 1);
elm_box_homogeneous_set(hbox, 1);
o = button_add("add", NULL, "empc", filesystem_button_add);
elm_object_tooltip_text_set(o, _("Add to play queue"));
elm_object_tooltip_style_set(o, "empc");
elm_box_pack_end(hbox, o);
o = button_add("refresh", NULL, "empc", filesystem_button_update);
elm_object_tooltip_text_set(o, _("Rescan"));
elm_object_tooltip_style_set(o, "empc");
elm_box_pack_end(hbox, o);
elm_object_part_content_set(ly, "empc.swallow.buttons", hbox);
evas_object_data_set(ly, "hbox", hbox);
}
elm_win_icon_name_set(win, "empc");
evas_object_resize(win, 357, 362);
evas_object_show(win);
elm_run();
/* crashing wooooooooo
metadata_shutdown();
empd_empdd_proxy_unref(empd_proxy);
empd_empdd_proxy_unref(empc_proxy);
E_FREE_LIST(handlers, ecore_event_handler_del);
eldbus_connection_unref(dbus_conn);
eldbus_shutdown();
efreet_shutdown();
elm_shutdown();
{
Empc_Module_Type t;
Empc_Module *mod;
Eina_Inlist *l;
for (t = 0; t < EMPC_MODULE_TYPE_LAST; t++)
EINA_INLIST_FOREACH_SAFE(empc_modules[t], l, mod)
{
eina_module_free(mod->module);
free(mod);
}
}
eina_list_free(filesystems);
eina_shutdown();
*/
return 0;
}
EAPI const Eina_List *
empc_modapi_queue_list_header_items_find(const char *artist, const char *album)
{
char buf[4096];
snprintf(buf, sizeof(buf), "%s:::%s", artist, album);
return eina_hash_find(empd_current_queue_headers, buf);
}
EAPI Eina_Bool
empc_modapi_queue_list_song_find(const Empd_Empdd_File *f)
{
const Eina_List *l, *ll;
Elm_Object_Item *it, *sit;
EINA_LIST_FOREACH(empc_modapi_queue_list_header_items_find(f->artist, f->album), l, it)
EINA_LIST_FOREACH(elm_genlist_item_subitems_get(it), ll, sit)
{
Empd_Empdd_Song *so = elm_object_item_data_get(sit);
if (so->uri == f->uri) return EINA_TRUE;
}
return EINA_FALSE;
}