609 lines
22 KiB
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);
|
|
}
|