efm2/src/efm/efm_back_end.c

609 lines
22 KiB
C

static void
_size_message(Evas_Object *o, double v)
{
Edje_Message_Float msg;
// display sqrt of 0.0-?1.0 so we don't have single huge files push every
// other bar out
if (v > 0.0) v = sqrt(v);
msg.val = v;
edje_object_message_send(o, EDJE_MESSAGE_FLOAT, 1, &msg);
edje_object_message_signal_process(o);
}
static void
_size_bars_update(Smart_Data *sd)
{
Eina_List *bl, *il;
Icon *icon;
Block *block;
const char *s;
if (sd->config.view_mode != EFM_VIEW_MODE_LIST_DETAILED) return;
EINA_LIST_FOREACH(sd->blocks, bl, block)
{
if (block->realized_num <= 0) continue;
EINA_LIST_FOREACH(block->icons, il, icon)
{
if (!icon->realized) continue;
s = cmd_key_find(icon->cmd, "size");
if (s)
{
unsigned long long size = atoll(s);
if (sd->file_max > 0)
_size_message(icon->o_list_detail_swallow2[0],
(double)size / (double)sd->file_max);
else
_size_message(icon->o_list_detail_swallow2[0], 0.0);
}
}
}
}
static void
_cb_size_bars_update_job(void *data)
{
Smart_Data *sd = data;
sd->size_bars_update_job = NULL;
_size_bars_update(sd);
}
static void
_size_bars_update_queue(Smart_Data *sd)
{
if (sd->size_bars_update_job) ecore_job_del(sd->size_bars_update_job);
sd->size_bars_update_job = ecore_job_add(_cb_size_bars_update_job, sd);
}
static void
_cb_size_max_update_job(void *data)
{
Smart_Data *sd = data;
Eina_List *il;
Icon *icon;
const char *s;
unsigned long long new_max = 0;
sd->size_max_update_job = NULL;
EINA_LIST_FOREACH(sd->icons, il, icon)
{
s = cmd_key_find(icon->cmd, "size");
if (s)
{
unsigned long long size = atoll(s);
if (size > new_max) new_max = size;
}
}
if (sd->file_max != new_max)
{
sd->file_max = new_max;
_size_bars_update_queue(sd);
}
}
static void
_size_bars_max_update_queue(Smart_Data *sd)
{
if (sd->size_max_update_job) ecore_job_del(sd->size_max_update_job);
sd->size_max_update_job = ecore_job_add(_cb_size_max_update_job, sd);
}
static void
_command(Smart_Data *sd, const char *cmd)
{
Cmd *c = cmd_parse(cmd);
Msg *msg;
void *ref;
if (!c) return;
// send the cmd to our thread to deal with
msg = eina_thread_queue_send(sd->thread_data->thq, sizeof(Msg), &ref);
msg->c = c;
eina_thread_queue_send_done(sd->thread_data->thq, ref);
}
static void
_process(Smart_Data_Thread *std, Ecore_Thread *th, Eina_List *batch)
{ // process a batch of commands that come from the back-end open process
Cmd *c, *c_tmp = NULL;
Eina_List *batch_new = NULL;
Eina_List *batch_tmp = NULL;
if (!batch) return;
// sort batch into batch_new where each set of things like add, mod, del
// if they are the same cmd then the files are sorted by path. we do this
// to speed up inserts in the main loop so we can assume a sorted list
// per batch. this speeds up file adds a lot as we can just do a walk of
// the batch (as long as commands stay the same like file-add) and then also
// walk the current file/icon list at the same time and skip to the insert
// spot which makes inserts very fast as both lists are known to be
// pre-sorted so at worst we walk N file icons in the current icon list
// per batch (and loading a dir is probably a series of batches of N
// file-add's where N is white reasonable
EINA_LIST_FREE(batch, c)
{
c->sort_mode = std->sd->config.sort_mode;
if (!batch_tmp)
{
batch_tmp = eina_list_append(batch_tmp, c);
c_tmp = c;
}
else if (!strcmp(c->command, c_tmp->command))
{
// works for file-add, file-del, file-mod
batch_tmp = eina_list_sorted_insert(batch_tmp, sort_cmd, c);
}
else
{
batch_new = eina_list_merge(batch_new, batch_tmp);
batch_tmp = NULL;
}
}
if (batch_tmp)
{
batch_new = eina_list_merge(batch_new, batch_tmp);
batch_tmp = NULL;
}
if (batch_new) ecore_thread_feedback(th, batch_new);
}
static Eina_Bool
_cb_exe_del(void *data, int ev_type EINA_UNUSED, void *event)
{
Smart_Data *sd = data;
Ecore_Exe_Event_Del *ev = event;
Eina_List *l;
Pending_Exe_Del *pend;
// remove this exited slave process from our pending exe deletions
// this list should be pretty small of pending deletions so we don't
// need to optimize this with a hash or whatever
EINA_LIST_FOREACH(_pending_exe_dels, l, pend)
{
if (pend->exe == ev->exe)
{
pend->exe = NULL;
if (pend->timer)
{
ecore_timer_del(pend->timer);
pend->timer = NULL;
}
free(pend);
_pending_exe_dels = eina_list_remove_list(_pending_exe_dels, l);
break;
}
}
if (ev->exe == sd->exe_open)
{ // this process exiting is the back-end open process for active view
printf("ERROR: back-end open process died unexpectedly\n");
return ECORE_CALLBACK_DONE;
}
return ECORE_CALLBACK_PASS_ON;
}
static Eina_Bool
_cb_exe_data(void *data, int ev_type EINA_UNUSED, void *event)
{
Smart_Data *sd = data;
Ecore_Exe_Event_Data *ev = event;
int i;
// if this exe doesn't match the view it is for - pass it on and skip
if (ev->exe != sd->exe_open) return ECORE_CALLBACK_PASS_ON;
// this exe data is for thijs view
for (i = 0; ev->lines[i].line; i++) _command(sd, ev->lines[i].line);
return ECORE_CALLBACK_DONE;
}
static Eina_Bool
_cb_exe_pending_timer(void *data)
{ // timeout trying to kill off back-end open process
Pending_Exe_Del *pend = data;
pend->timer = NULL;
_pending_exe_dels = eina_list_remove(_pending_exe_dels, pend);
if (pend->exe)
{ // forcibly kill the back-end process as it did not exit on its own
ecore_exe_kill(pend->exe);
pend->exe = NULL;
}
free(pend);
return EINA_FALSE;
}
static void
_cb_thread_main(void *data, Ecore_Thread *th)
{ // thread sits processing commands read from stdout from the back-end open
Smart_Data_Thread *std = data;
Msg *msg;
void *ref;
Cmd *c;
Eina_Bool block = EINA_FALSE;
const char *prev_cmd = NULL;
Eina_List *batch = NULL;
for (;;)
{ // sit in a loop soaking up commands on the input queue
if (ecore_thread_check(th)) break;
if (!block) msg = eina_thread_queue_poll(std->thq, &ref);
else
{
usleep(4000); // wait 4ms to collect more msg's
msg = eina_thread_queue_wait(std->thq, &ref);
block = EINA_FALSE;
}
if (msg)
{
if (!batch)
{
batch = eina_list_append(batch, msg->c);
eina_stringshare_replace(&(prev_cmd), msg->c->command);
}
else if ((prev_cmd) && (!strcmp(msg->c->command, prev_cmd)))
{
batch = eina_list_append(batch, msg->c);
}
else
{
_process(std, th, batch);
batch = NULL;
eina_stringshare_replace(&(prev_cmd), NULL);
batch = eina_list_append(batch, msg->c);
}
eina_thread_queue_wait_done(std->thq, ref);
}
else
{
block = EINA_TRUE;
_process(std, th, batch);
batch = NULL;
eina_stringshare_replace(&(prev_cmd), NULL);
}
}
EINA_LIST_FREE(batch, c)
{
cmd_free(c);
}
eina_stringshare_replace(&(prev_cmd), NULL);
}
static void
_cb_thread_notify(void *data, Ecore_Thread *th EINA_UNUSED, void *msg)
{ // handle data from the view thread to the UI - this will be a batch of cmds
Smart_Data_Thread *std = data;
Smart_Data *sd = std->sd;
Eina_List *batch = msg;
Cmd *c, *cprev = NULL;
Eina_List *l, *il2, *il = NULL;
Icon *icon, *icon2;
Block *block;
const char *file, *label, *s;
int file_adds = 0, file_dels = 0;
if (!sd)
{ // on cusp point - view gone but buffered thread feedback exists
EINA_LIST_FREE(batch, c) cmd_free(c);
return;
}
printf("XXXXX BATCH %i\n", eina_list_count(batch));
EINA_LIST_FOREACH(batch, l, c)
{
c->sort_mode = sd->config.sort_mode;
#define CMD_DONE cmd_free(c); continue
if (!strcmp(c->command, "list-begin"))
{
printf("XXXXX LIST BEGIN\n");
edje_object_part_text_set(sd->o_overlay_info,
"e.text.busy_label",
"Loading");
edje_object_signal_emit(sd->o_overlay_info,
"e,state,busy,start", "e");
CMD_DONE;
}
else if (!strcmp(c->command, "list-end"))
{
printf("XXXXX LIST END\n");
edje_object_signal_emit(sd->o_overlay_info,
"e,state,busy,stop", "e");
CMD_DONE;
}
file = cmd_key_find(c, "path");
printf("XXXXX [%s] [%s]\n", c->command, file);
if (file)
{
s = strrchr(file, '/');
if (s) file = s + 1;
if (file[0] == '.') // XXX filter dor files or not
{
CMD_DONE;
}
}
if ((!file) || (!file[0]))
{ // somehow we didn't get a sane filename from the back-end
CMD_DONE;
}
label = cmd_key_find(c, "link-label");
if (!label) label = cmd_key_find(c, "label");
if ((!cprev) || (!!strcmp(cprev->command, c->command)))
{ // we start a new batch of commands - these are sorted
il = sd->icons;
}
if (!strcmp(c->command, "file-add"))
{
icon = calloc(1, sizeof(Icon));
if (!icon) abort();
file_adds++;
icon->sd = sd;
icon->cmd = c;
icon->changed = EINA_TRUE;
icon->info.file = eina_stringshare_add(file);
eina_stringshare_replace(&(icon->info.label), label);
s = cmd_key_find(c, "label-clicked");
if (!s) s = cmd_key_find(c, "link-label-clicked");
eina_stringshare_replace(&(icon->info.label_clicked), s);
s = cmd_key_find(c, "label-selected");
if (!s) s = cmd_key_find(c, "link-label-selected");
eina_stringshare_replace(&(icon->info.label_selected), s);
s = cmd_key_find(c, "mime");
if (s) eina_stringshare_replace(&(icon->info.mime), s);
if (s) printf("XXXXX mime=%s\n", icon->info.mime);
s = cmd_key_find(c, "desktop-icon");
if (!s) s = cmd_key_find(c, "link-desktop-icon");
if (s) eina_stringshare_replace(&(icon->info.pre_lookup_icon), s);
s = cmd_key_find(c, "desktop-icon.lookup");
if (!s) s = cmd_key_find(c, "link-desktop-icon.lookup");
if (!s) s = cmd_key_find(c, "icon");
if ((s) && (s[0] == '/')) eina_stringshare_replace(&(icon->info.icon), s);
s = cmd_key_find(c, "link-desktop-icon-clicked");
if (!s) s = cmd_key_find(c, "desktop-icon-clicked");
if (s) eina_stringshare_replace(&(icon->info.icon_clicked), s);
s = cmd_key_find(c, "link-desktop-icon-selected");
if (!s) s = cmd_key_find(c, "desktop-icon-selected");
if (s) eina_stringshare_replace(&(icon->info.icon_selected), s);
s = cmd_key_find(c, "mime-icon");
if (s) eina_stringshare_replace(&(icon->info.mime_icon), s);
s = cmd_key_find(c, "thumb");
if (s) eina_stringshare_replace(&(icon->info.thumb), s);
s = cmd_key_find(c, "type");
if (s)
{
if (!strcmp(s, "link"))
{
icon->info.link = EINA_TRUE;
s = cmd_key_find(c, "broken-link");
if ((s) && (!strcmp(s, "true")))
icon->info.broken = EINA_TRUE;
s = cmd_key_find(c, "link-type");
}
if (s)
{
if (!strcmp(s, "dir"))
{
icon->info.dir = EINA_TRUE;
eina_stringshare_replace((&icon->info.mime),
"inode/directory");
}
else if (!strcmp(s, "block"))
{
icon->info.special = EINA_TRUE;
eina_stringshare_replace((&icon->info.mime),
"inode/blockdevice");
}
else if (!strcmp(s, "char"))
{
icon->info.special = EINA_TRUE;
eina_stringshare_replace((&icon->info.mime),
"inode/chardevice");
}
else if (!strcmp(s, "fifo"))
{
icon->info.special = EINA_TRUE;
eina_stringshare_replace((&icon->info.mime),
"inode/fifo");
}
else if (!strcmp(s, "socket"))
{
icon->info.special = EINA_TRUE;
eina_stringshare_replace((&icon->info.mime),
"inode/socket");
}
}
}
s = cmd_key_find(c, "size");
if (s)
{
unsigned long long size = atoll(s);
if (size > sd->file_max)
{
sd->file_max = size;
_size_bars_update_queue(sd);
}
}
if (!icon->info.mime)
eina_stringshare_replace((&icon->info.mime),
"inode/file");
for ( ; il; il = il->next)
{
icon2 = il->data;
if (!strcmp(file, icon2->info.file))
{ // handle the case we get an add for an existing file
file_dels++;
il2 = il->next;
sd->icons = eina_list_remove_list(sd->icons, il);
il = il2;
if (sd->last_focused)
{
// XXX: select prev or next icon
}
s = cmd_key_find(icon->cmd, "size");
if (s)
{
unsigned long long size = atoll(s);
if (size == sd->file_max)
{
_size_bars_max_update_queue(sd);
}
}
_icon_free(icon2);
if (il) icon2 = il->data;
else break;
}
if (sort_cmd(icon2->cmd, icon->cmd) > 0)
{
sd->icons = eina_list_prepend_relative_list
(sd->icons, icon, il);
break;
}
}
if (!il)
{
sd->icons = eina_list_append(sd->icons, icon);
}
}
else if (!strcmp(c->command, "file-del"))
{
for ( ; il; il = il->next)
{
icon = il->data;
if (!strcmp(file, icon->info.file))
{
file_dels++;
il2 = il->next;
sd->icons = eina_list_remove_list(sd->icons, il);
il = il2;
if (sd->last_focused)
{
// XXX: select prev or next icon
}
s = cmd_key_find(icon->cmd, "size");
if (s)
{
unsigned long long size = atoll(s);
if (size == sd->file_max)
{
_size_bars_max_update_queue(sd);
}
}
_icon_free(icon);
break;
}
}
cmd_free(c);
c = NULL;
}
else if (!strcmp(c->command, "file-mod"))
{
for ( ; il; il = il->next)
{
icon = il->data;
if (!strcmp(file, icon->info.file))
{
icon->changed = EINA_TRUE;
eina_stringshare_replace(&(icon->info.label), label);
s = cmd_key_find(c, "label-clicked");
if (!s) s = cmd_key_find(c, "link-label-clicked");
eina_stringshare_replace(&(icon->info.label_clicked), s);
s = cmd_key_find(c, "label-selected");
if (!s) s = cmd_key_find(c, "link-label-selected");
eina_stringshare_replace(&(icon->info.label_selected), s);
s = cmd_key_find(c, "mime");
if (s) eina_stringshare_replace(&(icon->info.mime), s);
if (!icon->info.mime)
eina_stringshare_replace((&icon->info.mime),
"inode/file");
s = cmd_key_find(c, "desktop-icon");
if (!s) s = cmd_key_find(c, "link-desktop-icon");
if (s) eina_stringshare_replace(&(icon->info.pre_lookup_icon), s);
s = cmd_key_find(c, "desktop-icon.lookup");
if (!s) s = cmd_key_find(c, "link-desktop-icon.lookup");
if (!s) s = cmd_key_find(c, "icon");
if ((s) && (s[0] == '/')) eina_stringshare_replace(&(icon->info.icon), s);
s = cmd_key_find(c, "link-desktop-icon-clicked");
if (!s) s = cmd_key_find(c, "desktop-icon-clicked");
if (s) eina_stringshare_replace(&(icon->info.icon_clicked), s);
s = cmd_key_find(c, "link-desktop-icon-selected");
if (!s) s = cmd_key_find(c, "desktop-icon-selected");
if (s) eina_stringshare_replace(&(icon->info.icon_selected), s);
s = cmd_key_find(c, "mime-icon");
if (s) eina_stringshare_replace(&(icon->info.mime_icon), s);
s = cmd_key_find(c, "thumb");
if (s) eina_stringshare_replace(&(icon->info.thumb), s);
s = cmd_key_find(c, "broken-link");
if ((s) && (!strcmp(s, "true")))
icon->info.broken = EINA_TRUE;
else
icon->info.broken = EINA_FALSE;
s = cmd_key_find(icon->cmd, "size");
if (s)
{
unsigned long long size = atoll(s);
if (size == sd->file_max)
{
_size_bars_max_update_queue(sd);
}
}
s = cmd_key_find(c, "size");
if (s)
{
unsigned long long size = atoll(s);
if (size > sd->file_max)
{
sd->file_max = size;
_size_bars_update_queue(sd);
}
}
cmd_free(icon->cmd);
icon->cmd = c;
break;
}
}
}
cprev = c;
}
eina_list_free(batch);
if ((sd->config.view_mode >= EFM_VIEW_MODE_LIST) &&
((file_adds > 0) || (file_dels > 0)))
{ // if it's one of the list modes, unrealize realized icons
EINA_LIST_FOREACH(sd->blocks, l, block)
{
if (block->realized_num <= 0) continue;
EINA_LIST_FOREACH(block->icons, il, icon)
{ // unrealize the icon - we odd/event forces this
if (!icon->realized) continue;
icon->realized = EINA_FALSE;
icon->block->realized_num--;
_icon_object_clear(icon);
}
}
}
if (sd->reblock_job) ecore_job_del(sd->reblock_job);
sd->reblock_job = ecore_job_add(_cb_reblock, sd);
}
static void
_cb_thread_done(void *data, Ecore_Thread *th EINA_UNUSED)
{
Smart_Data_Thread *std = data;
if (std->sd) std->sd->thread_data = NULL;
if (std->thq)
{
eina_thread_queue_free(std->thq);
std->thq = NULL;
}
free(std);
}