enlightenment/src/e_dir.c

546 lines
12 KiB
C

#include "file.h"
#include "desktops.h"
#include "e_dir.h"
#include "e_view_machine.h"
#include "view.h"
#include "icons.h"
#include "util.h"
#include "libefsd.h"
#include "e_file.h"
#include "globals.h"
static void e_dir_handle_fs_restart(void *data);
static void e_dir_handle_fs(EfsdEvent * ev);
static void e_dir_handle_efsd_event_reply(EfsdEvent * ev);
static void e_dir_handle_efsd_event_reply_stat(EfsdEvent * ev);
static void e_dir_handle_efsd_event_reply_readlink(EfsdEvent * ev);
static void e_dir_handle_efsd_event_reply_getfiletype(EfsdEvent * ev);
static void e_dir_handle_efsd_event_reply_getmeta(EfsdEvent * ev);
static void e_dir_cleanup(E_Dir * d);
void
e_dir_init(void)
{
D_ENTER;
e_fs_add_event_handler(e_dir_handle_fs);
D_RETURN;
}
static void
e_dir_cleanup(E_Dir * d)
{
D_ENTER;
if (!d)
D_RETURN;
efsd_stop_monitor(e_fs_get_connection(), d->dir, TRUE);
if (d->restarter)
e_fs_del_restart_handler(d->restarter);
d->restarter = NULL;
e_view_machine_unregister_dir(d);
e_object_cleanup(E_OBJECT(d));
D_RETURN;
}
E_Dir *
e_dir_new(void)
{
E_Dir *d;
D_ENTER;
d = NEW(E_Dir, 1);
ZERO(d, E_Dir, 1);
d->dir = NULL;
e_observee_init(E_OBSERVEE(d),
(E_Cleanup_Func) e_dir_cleanup);
e_view_machine_register_dir(d);
D_RETURN_(d);
}
static void
e_dir_handle_fs_restart(void *data) {
E_Dir *d;
D_ENTER;
D("e_dir_handle_fs_restart\n");
if((d = data)) {
if(d->dir&&*(d->dir)) {
if (e_fs_get_connection()) {
EfsdOptions *ops;
/* FIXME restart with metadata pending for views */
ops = efsd_ops(3,
efsd_op_get_stat(),
efsd_op_get_filetype(), efsd_op_list_all());
if((d->monitor_id=efsd_start_monitor(e_fs_get_connection(), d->dir,
ops, TRUE))<0) {
D("could not restart monitor (connx %p) for \"%s\" => %i\n",
e_fs_get_connection(), d->dir, d->monitor_id); }
else {
D("restarted monitor (connx %p) for \"%s\" => ID %i...\n",
e_fs_get_connection(), d->dir, d->monitor_id); }}
else {
D("could not restart, connection refused\n"); }}
else {
D("could not restart, no dir given!?\n"); }}
else {
D("could not restart, no data\n"); }
D_RETURN; }
void
e_dir_set_dir(E_Dir * d, char *dir)
{
D_ENTER;
if (!d) {
D("e_dir_set_dir -- no E_Dir!\n");
D_RETURN; }
/* stop monitoring old dir */
if ((d->dir) && (d->monitor_id))
{
efsd_stop_monitor(e_fs_get_connection(), d->dir, TRUE);
d->monitor_id = 0;
}
IF_FREE(d->dir);
if(!dir||!*dir) {
D("e_dir_set_dir -- no dir!\n");
D_RETURN; }
d->dir = e_file_realpath(dir);
if(!d->dir||!*(d->dir)) {
/* realpath failed. this would mean that we tried to set a monitor
on a non-existent (or inacessible) file. this may mean that the
programmer really meant "...and if it doesn't exist YET, tell me
if and when it is created", so rather than failing right here and
now, we'll forget about the realpath, stick in the path they
requested in the first place, and hope the backend actually supports
watching something it cannot determine an inode for... we'll still
throw a warning though, just for good measure. Azundris 2003/01/11 */
D("e_dir_set_dir -- e_file_realpath(\"%s\") failed...\n",dir);
if(d->dir)
free(d->dir);
if(!(d->dir=strdup(dir))) {
D("e_dir_set_dir: OOM\n");
D_RETURN; }}
/* start monitoring new dir */
d->restarter = e_fs_add_restart_handler(e_dir_handle_fs_restart, d);
if (e_fs_get_connection())
{
EfsdOptions *ops;
ops = efsd_ops(3,
efsd_op_get_stat(),
efsd_op_get_filetype(), efsd_op_list_all());
d->monitor_id = efsd_start_monitor(e_fs_get_connection(), d->dir,
ops, TRUE);
D("monitor id for \"%s\" = %i\n", d->dir, d->monitor_id);
}
D_RETURN;
}
static void
e_dir_handle_fs(EfsdEvent * ev)
{
D_ENTER;
if (!ev)
D_RETURN;
switch (ev->type)
{
case EFSD_EVENT_FILECHANGE:
switch (ev->efsd_filechange_event.changetype)
{
case EFSD_FILE_CREATED:
e_dir_file_added(ev->efsd_filechange_event.id,
ev->efsd_filechange_event.file);
break;
case EFSD_FILE_EXISTS:
e_dir_file_added(ev->efsd_filechange_event.id,
ev->efsd_filechange_event.file);
break;
case EFSD_FILE_DELETED:
e_dir_file_deleted(ev->efsd_filechange_event.id,
ev->efsd_filechange_event.file);
break;
case EFSD_FILE_CHANGED:
e_dir_file_changed(ev->efsd_filechange_event.id,
ev->efsd_filechange_event.file);
break;
case EFSD_FILE_MOVED:
e_dir_file_moved(ev->efsd_filechange_event.id,
ev->efsd_filechange_event.file);
break;
case EFSD_FILE_END_EXISTS:
break;
default:
break;
}
break;
case EFSD_EVENT_REPLY:
e_dir_handle_efsd_event_reply(ev);
break;
default:
break;
}
D_RETURN;
}
static void
e_dir_handle_efsd_event_reply_getfiletype(EfsdEvent * ev)
{
E_File *f;
char *file = NULL;
E_Dir *dir;
char *m, *p;
char mime[PATH_MAX], base[PATH_MAX];
D_ENTER;
if (!ev)
D_RETURN;
if (!ev->efsd_reply_event.errorcode == 0)
D_RETURN;
if ((file = efsd_event_filename(ev)))
{
file = e_file_get_file(file);
}
dir = e_dir_find_by_monitor_id(efsd_event_id(ev));
f = e_file_get_by_name(dir->files, file);
/* if its not in the list we care about, its filetype is meaningless */
if (!f)
D_RETURN;
m = ev->efsd_reply_event.data;
p = strchr(m, '/');
if (p)
{
STRNCPY(base, m, PATH_MAX);
STRNCPY(mime, p + 1, PATH_MAX);
p = strchr(base, '/');
*p = 0;
}
else
{
STRNCPY(base, m, PATH_MAX);
strcpy(mime, "unknown");
}
e_file_set_mime(f, base, mime);
/* Try to update the GUI.
* It's just a try because we need to have the file's stat
* info as well. --cK.
*/
e_observee_notify_observers(E_OBSERVEE(dir), E_EVENT_FILE_INFO, f);
D_RETURN;
}
static void
e_dir_handle_efsd_event_reply_stat(EfsdEvent * ev)
{
E_Dir *d;
E_File *f;
D_ENTER;
if (!ev)
D_RETURN;
if (!ev->efsd_reply_event.errorcode == 0)
D_RETURN;
d = e_dir_find_by_monitor_id(efsd_event_id(ev));
f = e_file_get_by_name(d->files, e_file_get_file(efsd_event_filename(ev)));
/* if its not in the list we care about, return */
if (!f)
D_RETURN;
/* When everything went okay and we can find a dir,
* set the file stat data for the file and try to update the gui.
* It's just a try because we need to have received the filetype
* info too. --cK. */
f->stat = *((struct stat *)efsd_event_data(ev));
e_observee_notify_observers(E_OBSERVEE(d), E_EVENT_FILE_INFO, f);
D_RETURN;
}
static void
e_dir_handle_efsd_event_reply_readlink(EfsdEvent * ev)
{
E_Dir *d;
E_File *f;
D_ENTER;
if (!ev)
D_RETURN;
if (!ev->efsd_reply_event.errorcode == 0)
D_RETURN;
d = e_dir_find_by_monitor_id(efsd_event_id(ev));
f = e_file_get_by_name(d->files, e_file_get_file(efsd_event_filename(ev)));
if (f)
{
e_file_set_link(f, (char *)efsd_event_data(ev));
}
e_observee_notify_observers(E_OBSERVEE(d), E_EVENT_FILE_INFO, f);
D_RETURN;
}
static void
e_dir_handle_efsd_event_reply_getmeta(EfsdEvent * ev)
{
Evas_List * l;
EfsdCmdId cmd;
D_ENTER;
if (!ev)
D_RETURN;
cmd = efsd_event_id(ev);
for (l = VM->views; l; l = l->next)
{
E_View *v;
v = l->data;
/* ignore metadata for desktops */
if (v->is_desktop)
continue;
if (v->geom_get.x == cmd)
{
v->geom_get.x = 0;
if (efsd_metadata_get_type(ev) == EFSD_INT)
{
if (ev->efsd_reply_event.errorcode == 0)
efsd_metadata_get_int(ev, &(v->location.x));
else
v->location.x = 0;
}
}
else if (v->geom_get.y == cmd)
{
v->geom_get.y = 0;
if (efsd_metadata_get_type(ev) == EFSD_INT)
{
if (ev->efsd_reply_event.errorcode == 0)
efsd_metadata_get_int(ev, &(v->location.y));
else
v->location.y = 0;
}
}
else if (v->geom_get.w == cmd)
{
v->geom_get.w = 0;
if (efsd_metadata_get_type(ev) == EFSD_INT)
{
if (ev->efsd_reply_event.errorcode == 0)
efsd_metadata_get_int(ev, &(v->size.w));
else
v->size.w = 400;
}
}
else if (v->geom_get.h == cmd)
{
v->geom_get.h = 0;
if (ev->efsd_reply_event.errorcode == 0)
{
if (ev->efsd_reply_event.errorcode == 0)
efsd_metadata_get_int(ev, &(v->size.h));
else
v->size.h = 401;
}
}
/* We have received all metadata we need, display the view */
if ((!v->geom_get.x) &&
(!v->geom_get.y) &&
(!v->geom_get.w) && (!v->geom_get.h) && (v->geom_get.busy))
{
E_Border *b;
ecore_window_move_resize(v->win.base, v->location.x, v->location.y,
v->size.w, v->size.h);
ecore_window_set_xy_hints(v->win.base, v->location.x,
v->location.y);
v->size.force = 1;
v->geom_get.busy = 0;
if (v->bg)
e_bg_resize(v->bg, v->size.w, v->size.h);
if (v->options.back_pixmap)
e_view_update(v);
b = e_border_adopt(v->win.base, 1);
b->client.internal = 1;
e_border_remove_click_grab(b);
}
}
D_RETURN;
}
static void
e_dir_handle_efsd_event_reply(EfsdEvent * ev)
{
D_ENTER;
if (!ev)
D_RETURN;
switch (ev->efsd_reply_event.command.type)
{
case EFSD_CMD_REMOVE:
break;
case EFSD_CMD_MOVE:
break;
case EFSD_CMD_SYMLINK:
break;
case EFSD_CMD_LISTDIR:
break;
case EFSD_CMD_MAKEDIR:
break;
case EFSD_CMD_CHMOD:
break;
case EFSD_CMD_GETFILETYPE:
e_dir_handle_efsd_event_reply_getfiletype(ev);
break;
case EFSD_CMD_STAT:
e_dir_handle_efsd_event_reply_stat(ev);
break;
case EFSD_CMD_READLINK:
e_dir_handle_efsd_event_reply_readlink(ev);
break;
case EFSD_CMD_CLOSE:
break;
case EFSD_CMD_SETMETA:
break;
case EFSD_CMD_GETMETA:
e_dir_handle_efsd_event_reply_getmeta(ev);
break;
case EFSD_CMD_STARTMON_DIR:
break;
case EFSD_CMD_STARTMON_FILE:
break;
case EFSD_CMD_STOPMON_DIR:
break;
case EFSD_CMD_STOPMON_FILE:
break;
default:
break;
}
D_RETURN;
}
void
e_dir_file_added(int id, char *file)
{
E_Dir *d;
E_File *f;
D_ENTER;
/* if we get a path - ignore it - its not a file in the dir */
if (!file || file[0] == '/')
D_RETURN;
d = e_dir_find_by_monitor_id(id);
if (file[0] != '.')
{
f = e_file_new(file);
d->files = evas_list_append(d->files, f);
/* tell all views for this dir about the new file */
e_observee_notify_observers(E_OBSERVEE(d), E_EVENT_FILE_ADD, f);
}
D_RETURN;
}
void
e_dir_file_deleted(int id, char *file)
{
E_File *f;
E_Dir *d;
D_ENTER;
if (!file || file[0] == '/')
D_RETURN;
d = e_dir_find_by_monitor_id(id);
f = e_file_get_by_name(d->files, file);
d->files = evas_list_remove(d->files, f);
if (file[0] != '.')
{
e_observee_notify_observers(E_OBSERVEE(d), E_EVENT_FILE_DELETE, f);
}
D_RETURN;
}
void
e_dir_file_changed(int id, char *file)
{
E_Dir *d;
E_File *f;
D_ENTER;
if (!file || file[0] == '/')
D_RETURN;
d = e_dir_find_by_monitor_id(id);
f = e_file_get_by_name(d->files, file);
if (file[0] != '.')
{
e_observee_notify_observers(E_OBSERVEE(d), E_EVENT_FILE_CHANGE, f);
}
D_RETURN;
}
void
e_dir_file_moved(int id, char *file)
{
E_Dir *d;
D_ENTER;
if (!file || file[0] == '/')
D_RETURN;
d = e_dir_find_by_monitor_id(id);
D_RETURN;
}
E_Dir *
e_dir_find_by_monitor_id(int id)
{
E_Dir *d;
Evas_List * l;
D_ENTER;
for (l = VM->dirs; l; l = l->next)
{
d = l->data;
if (d->monitor_id == id)
D_RETURN_(d);
}
D_RETURN_(NULL);
}