efm finally does something other than flail around helplessly when you drag stuff onto the icon of another device

ticket #2000, fuck DND


SVN revision: 81162
This commit is contained in:
Mike Blumenkrantz 2012-12-17 15:59:43 +00:00
parent 373bd3ce00
commit 46f630f103
4 changed files with 303 additions and 39 deletions

View File

@ -146,6 +146,7 @@ struct _E_Fm2_Smart_Data
E_Fm2_Icon *drop_icon;
Ecore_Animator *dnd_scroller;
Evas_Point dnd_current;
Eina_List *mount_ops;
E_Fm2_Mount *mount;
signed char drop_after;
Eina_Bool drop_show : 1;
@ -192,6 +193,8 @@ struct _E_Fm2_Icon
E_Dialog *dialog;
E_Fm2_Icon_Info info;
E_Fm2_Mount *mount; // for dnd into unmounted dirs
Ecore_Timer *mount_timer; // autounmount in 15s
struct
{
@ -4715,6 +4718,9 @@ _e_fm2_icon_free(E_Fm2_Icon *ic)
e_object_del(E_OBJECT(ic->prop_dialog));
ic->prop_dialog = NULL;
}
if (ic->mount)
e_fm2_device_unmount(ic->mount);
if (ic->mount_timer) ecore_timer_del(ic->mount_timer);
if (ic->selected)
ic->sd->selected_icons = eina_list_remove(ic->sd->selected_icons, ic);
if (ic->drag.dnd_end_timer)
@ -6446,12 +6452,56 @@ _e_fm_icon_save_position(const char *file, Evas_Coord x, Evas_Coord y, Evas_Coor
e_fm2_custom_file_flush();
}
static Eina_Bool
_e_fm_drop_menu_queue(Evas_Object *e_fm, void *args, int op)
{
E_Volume *vol;
E_Fm2_Device_Mount_Op *mop = args;
vol = evas_object_data_del(e_fm, "dnd_queue");
if (!vol) return EINA_FALSE;
if (!vol->mounted)
{
/* this should get picked up by the post-mount callback */
switch (op)
{
case 0: //copy
mop->action = ECORE_X_ATOM_XDND_ACTION_COPY;
break;
case 1: //move
mop->action = ECORE_X_ATOM_XDND_ACTION_MOVE;
break;
case 2: //link
mop->action = ECORE_X_ATOM_XDND_ACTION_LINK;
break;
}
return EINA_TRUE;
}
switch (op)
{
case 0: //copy
e_fm2_client_file_copy(e_fm, mop->args);
break;
case 1: //move
e_fm2_client_file_move(e_fm, mop->args);
break;
case 2: //link
e_fm2_client_file_symlink(e_fm, mop->args);
break;
}
vol->mount_ops = eina_inlist_remove(vol->mount_ops, EINA_INLIST_GET(mop));
free(mop->args);
free(mop);
return EINA_TRUE;
}
static void
_e_fm_drop_menu_copy_cb(void *data, E_Menu *m __UNUSED__, E_Menu_Item *mi __UNUSED__)
{
char *args;
args = evas_object_data_get(data, "drop_menu_data");
args = evas_object_data_del(data, "drop_menu_data");
if (_e_fm_drop_menu_queue(data, args, 0)) return;
e_fm2_client_file_copy(data, args);
free(args);
}
@ -6461,7 +6511,8 @@ _e_fm_drop_menu_move_cb(void *data, E_Menu *m __UNUSED__, E_Menu_Item *mi __UNUS
{
char *args;
args = evas_object_data_get(data, "drop_menu_data");
args = evas_object_data_del(data, "drop_menu_data");
if (_e_fm_drop_menu_queue(data, args, 1)) return;
e_fm2_client_file_move(data, args);
free(args);
}
@ -6471,7 +6522,8 @@ _e_fm_drop_menu_symlink_cb(void *data, E_Menu *m __UNUSED__, E_Menu_Item *mi __U
{
char *args;
args = evas_object_data_get(data, "drop_menu_data");
args = evas_object_data_del(data, "drop_menu_data");
if (_e_fm_drop_menu_queue(data, args, 2)) return;
e_fm2_client_file_symlink(data, args);
free(args);
}
@ -6479,7 +6531,7 @@ _e_fm_drop_menu_symlink_cb(void *data, E_Menu *m __UNUSED__, E_Menu_Item *mi __U
static void
_e_fm_drop_menu_abort_cb(void *data, E_Menu *m __UNUSED__, E_Menu_Item *mi __UNUSED__)
{
free(evas_object_data_get(data, "drop_menu_data"));
free(evas_object_data_del(data, "drop_menu_data"));
}
static void
@ -6492,6 +6544,87 @@ _e_fm_drop_menu_free(void *data)
evas_object_data_del(e_fm, "drop_menu_data");
}
static void
_e_fm2_cb_dnd_selection_notify_post_mount_fail(E_Volume *vol)
{
E_Fm2_Device_Mount_Op *mop;
while (vol->mount_ops)
{
E_Fm2_Icon *ic;
mop = (E_Fm2_Device_Mount_Op*) vol->mount_ops;
ic = mop->ic;
vol->mount_ops = eina_inlist_remove(vol->mount_ops, EINA_INLIST_GET(mop));
/* FIXME: this can be made more clear */
e_util_dialog_show(_("Error"), _("The recent DND operation requested for '%s' has failed."), vol->label ?: vol->udi);
evas_object_data_del(ic->sd->obj, "dnd_queue");
free(mop->args);
ic->sd->mount_ops = eina_list_remove(ic->sd->mount_ops, mop);
free(mop);
}
}
static void
_e_fm2_cb_dnd_selection_notify_post_mount(E_Volume *vol)
{
E_Fm2_Device_Mount_Op *mop;
const char *mp;
Eina_Inlist *l;
mp = e_fm2_device_volume_mountpoint_get(vol);
EINA_INLIST_FOREACH_SAFE(vol->mount_ops, l, mop)
{
E_Fm2_Icon *ic = mop->ic;
if (mp)
{
mop->args = e_util_string_append_quoted(mop->args, &mop->size, &mop->length, mp);
if (mop->action == ECORE_X_ATOM_XDND_ACTION_ASK)
continue;
else if (mop->action == ECORE_X_ATOM_XDND_ACTION_MOVE)
e_fm2_client_file_move(ic->sd->obj, mop->args);
else if (mop->action == ECORE_X_ATOM_XDND_ACTION_COPY)
e_fm2_client_file_copy(ic->sd->obj, mop->args);
else if (mop->action == ECORE_X_ATOM_XDND_ACTION_LINK)
e_fm2_client_file_symlink(ic->sd->obj, mop->args);
}
else
e_util_dialog_show(_("Error"), _("The recent DND operation requested for '%s' has failed."), vol->label ?: vol->udi);
free(mop->args);
vol->mount_ops = eina_inlist_remove(vol->mount_ops, EINA_INLIST_GET(mop));
ic->sd->mount_ops = eina_list_remove(ic->sd->mount_ops, mop);
free(mop);
}
eina_stringshare_del(mp);
}
static void
_e_fm2_cb_dnd_selection_notify_post_umount(E_Volume *vol)
{
E_Fm2_Device_Mount_Op *mop;
EINA_INLIST_FOREACH(vol->mount_ops, mop)
{
E_Fm2_Icon *ic = mop->ic;
if (!ic) continue;
if (ic->mount_timer) ecore_timer_del(ic->mount_timer);
ic->mount_timer = NULL;
ic->mount = NULL;
ic->sd->mount_ops = eina_list_remove(ic->sd->mount_ops, mop);
}
}
static Eina_Bool
_e_fm2_cb_dnd_selection_notify_post_mount_timer(E_Fm2_Icon *ic)
{
e_fm2_device_unmount(ic->mount);
ic->mount = NULL;
ic->mount_timer = NULL;
return EINA_FALSE;
}
static void
_e_fm2_cb_dnd_selection_notify(void *data, const char *type, void *event)
{
@ -6508,7 +6641,8 @@ _e_fm2_cb_dnd_selection_notify(void *data, const char *type, void *event)
char *args = NULL;
size_t size = 0;
size_t length = 0;
Eina_Bool lnk = EINA_FALSE, memerr = EINA_FALSE;
Eina_Bool lnk = EINA_FALSE, memerr = EINA_FALSE, mnt = EINA_FALSE;
E_Fm2_Device_Mount_Op *mop = NULL;
sd = data;
ev = event;
@ -6652,18 +6786,68 @@ _e_fm2_cb_dnd_selection_notify(void *data, const char *type, void *event)
if (!memerr)
{
if (S_ISDIR(sd->drop_icon->info.statinfo.st_mode))
while (sd->drop_icon->info.removable)
{
if (sd->drop_icon->info.link)
snprintf(dirpath, sizeof(dirpath), "%s", sd->drop_icon->info.link);
else
snprintf(dirpath, sizeof(dirpath), "%s/%s", sd->realpath, sd->drop_icon->info.file);
}
else
snprintf(dirpath, sizeof(dirpath), "%s", sd->realpath);
/* we're dropping onto a device
* cross your fingers and hope for good luck
*/
E_Volume *vol;
const char *mp;
args = e_util_string_append_quoted(args, &size, &length, dirpath);
if (!args) memerr = EINA_TRUE;
vol = e_fm2_device_volume_find_fast(sd->drop_icon->info.link);
if (!vol) break;
if (vol->mounted)
{
mp = e_fm2_device_volume_mountpoint_get(vol);
if (mp)
{
/* luuuuuuckkyyyyyyyyy */
args = e_util_string_append_quoted(args, &size, &length, mp);
if (!args) memerr = EINA_TRUE;
eina_stringshare_del(mp);
mnt = EINA_TRUE;
break;
}
}
else if (!sd->drop_icon->mount)
sd->drop_icon->mount = e_fm2_device_mount(vol, (Ecore_Cb)_e_fm2_cb_dnd_selection_notify_post_mount,
(Ecore_Cb)_e_fm2_cb_dnd_selection_notify_post_mount_fail, (Ecore_Cb)_e_fm2_cb_dnd_selection_notify_post_umount,
NULL, vol);
if (sd->drop_icon->mount_timer) ecore_timer_reset(sd->drop_icon->mount_timer);
else sd->drop_icon->mount_timer = ecore_timer_add(15., (Ecore_Task_Cb)_e_fm2_cb_dnd_selection_notify_post_mount_timer, sd->drop_icon);
if ((e_drop_handler_action_get() == ECORE_X_ATOM_XDND_ACTION_ASK) ||
((sd->config->view.link_drop) || (!sd->drop_icon)))
/* this here's some buuuullshit */
evas_object_data_set(sd->obj, "dnd_queue", vol);
else if (e_drop_handler_action_get() == ECORE_X_ATOM_XDND_ACTION_MOVE)
/* set copy if we're over a device */
e_drop_handler_action_set(ECORE_X_ATOM_XDND_ACTION_COPY);
mop = e_fm2_device_mount_op_add(sd->drop_icon->mount, args, size, length);
mop->ic = sd->drop_icon;
mop->mnt = sd->drop_icon->mount;
sd->mount_ops = eina_list_append(sd->mount_ops, mop);
/*
* set lnk here to prevent deleting the show timer
*/
mnt = lnk = EINA_TRUE;
break;
}
if (!mnt)
{
if (S_ISDIR(sd->drop_icon->info.statinfo.st_mode))
{
if (sd->drop_icon->info.link)
snprintf(dirpath, sizeof(dirpath), "%s", sd->drop_icon->info.link);
else
snprintf(dirpath, sizeof(dirpath), "%s/%s", sd->realpath, sd->drop_icon->info.file);
}
else
snprintf(dirpath, sizeof(dirpath), "%s", sd->realpath);
args = e_util_string_append_quoted(args, &size, &length, dirpath);
if (!args) memerr = EINA_TRUE;
}
}
}
else
@ -6729,33 +6913,46 @@ _e_fm2_cb_dnd_selection_notify(void *data, const char *type, void *event)
if (args)
{
Eina_Bool do_lnk = EINA_FALSE, do_move = EINA_FALSE, do_copy = EINA_FALSE;
if (e_drop_handler_action_get() == ECORE_X_ATOM_XDND_ACTION_COPY)
{
lnk = EINA_TRUE;
if (sd->config->view.link_drop && (!sd->drop_icon))
e_fm2_client_file_symlink(sd->obj, args);
do_lnk = EINA_TRUE;
else
e_fm2_client_file_copy(sd->obj, args);
free(args);
do_copy = EINA_TRUE;
}
else if (e_drop_handler_action_get() == ECORE_X_ATOM_XDND_ACTION_MOVE)
{
if (sd->config->view.link_drop && (!sd->drop_icon))
lnk = EINA_TRUE, e_fm2_client_file_symlink(sd->obj, args);
lnk = do_lnk = EINA_TRUE;
else
e_fm2_client_file_move(sd->obj, args);
free(args);
do_move = EINA_TRUE;
}
else if (e_drop_handler_action_get() == ECORE_X_ATOM_XDND_ACTION_ASK)
{
if (sd->config->view.link_drop && (!sd->drop_icon))
{
lnk = EINA_TRUE, e_fm2_client_file_symlink(sd->obj, args);
free(args);
}
else
e_fm2_drop_menu(sd->obj, args);
do_lnk = lnk = EINA_TRUE;
}
if (mnt && mop)
mop->action = (do_lnk * ECORE_X_ATOM_XDND_ACTION_LINK) +
(do_copy * ECORE_X_ATOM_XDND_ACTION_COPY) + (do_move * ECORE_X_ATOM_XDND_ACTION_MOVE) +
(((!do_copy) && (!do_move) && (!do_lnk)) * ECORE_X_ATOM_XDND_ACTION_ASK);
else if (do_lnk)
e_fm2_client_file_symlink(sd->obj, args);
else if (do_copy)
e_fm2_client_file_copy(sd->obj, args);
else if (do_move)
e_fm2_client_file_move(sd->obj, args);
if ((!do_lnk) && (!do_copy) && (!do_move))
{
e_fm2_drop_menu(sd->obj, args);
if (mnt && mop)
evas_object_data_set(sd->obj, "drop_menu_data", mop);
}
if (((!mnt) && (!mop)) && (do_lnk || do_copy || do_move))
free(args);
}
end:
_e_fm2_dnd_drop_hide(sd->obj);
@ -8246,6 +8443,7 @@ _e_fm2_smart_del(Evas_Object *obj)
E_FREE(sd->typebuf.buf);
if (sd->typebuf.timer) ecore_timer_del(sd->typebuf.timer);
sd->typebuf.timer = NULL;
eina_list_free(sd->mount_ops);
evas_object_del(sd->underlay);
evas_object_del(sd->overlay);
@ -11278,7 +11476,7 @@ e_fm2_desktop_get(Evas_Object *obj)
}
EAPI void
e_fm2_drop_menu(Evas_Object *e_fm, char *args)
e_fm2_drop_menu(Evas_Object *obj, char *args)
{
E_Menu *menu;
E_Menu_Item *item;
@ -11287,21 +11485,26 @@ e_fm2_drop_menu(Evas_Object *e_fm, char *args)
E_Zone *zone;
int x, y;
menu = e_menu_new();
EFM_SMART_CHECK();
EINA_SAFETY_ON_TRUE_RETURN(!!sd->menu);
sd->menu = menu = e_menu_new();
if (!menu) return;
evas_object_data_set(e_fm, "drop_menu_data", args);
e_object_data_set(E_OBJECT(menu), e_fm);
e_menu_post_deactivate_callback_set(menu, _e_fm2_menu_post_cb, sd);
evas_object_data_set(obj, "drop_menu_data", args);
e_object_data_set(E_OBJECT(menu), obj);
e_object_free_attach_func_set(E_OBJECT(menu), _e_fm_drop_menu_free);
item = e_menu_item_new(menu);
e_menu_item_label_set(item, _("Copy"));
e_menu_item_callback_set(item, _e_fm_drop_menu_copy_cb, e_fm);
e_menu_item_callback_set(item, _e_fm_drop_menu_copy_cb, obj);
e_util_menu_item_theme_icon_set(item, "edit-copy");
item = e_menu_item_new(menu);
e_menu_item_label_set(item, _("Move"));
e_menu_item_callback_set(item, _e_fm_drop_menu_move_cb, e_fm);
e_menu_item_callback_set(item, _e_fm_drop_menu_move_cb, obj);
e_menu_item_icon_edje_set(item,
e_theme_edje_file_get("base/theme/fileman",
"e/fileman/default/button/move"),
@ -11309,7 +11512,7 @@ e_fm2_drop_menu(Evas_Object *e_fm, char *args)
item = e_menu_item_new(menu);
e_menu_item_label_set(item, _("Link"));
e_menu_item_callback_set(item, _e_fm_drop_menu_symlink_cb, e_fm);
e_menu_item_callback_set(item, _e_fm_drop_menu_symlink_cb, obj);
e_util_menu_item_theme_icon_set(item, "emblem-symbolic-link");
item = e_menu_item_new(menu);
@ -11317,7 +11520,7 @@ e_fm2_drop_menu(Evas_Object *e_fm, char *args)
item = e_menu_item_new(menu);
e_menu_item_label_set(item, _("Abort"));
e_menu_item_callback_set(item, _e_fm_drop_menu_abort_cb, e_fm);
e_menu_item_callback_set(item, _e_fm_drop_menu_abort_cb, obj);
e_menu_item_icon_edje_set(item,
e_theme_edje_file_get("base/theme/fileman",
"e/fileman/default/button/abort"),
@ -11331,7 +11534,8 @@ e_fm2_drop_menu(Evas_Object *e_fm, char *args)
zone = e_util_zone_current_get(man);
if (!zone) goto error;
e_menu_activate_mouse(menu, zone, x, y, 1, 1, E_MENU_POP_DIRECTION_DOWN, 0);
return;
error:
e_object_del(E_OBJECT(menu));
sd->menu = NULL;
}

View File

@ -16,6 +16,26 @@ static Eina_Bool _check_run_show = EINA_FALSE;
static Eina_Bool _check_run_hide = EINA_FALSE;
static Ecore_Thread *_check_vols = NULL;
static inline E_Fm2_Device_Mount_Op *
_e_fm2_device_mount_op_new(char *args, size_t size, size_t length)
{
E_Fm2_Device_Mount_Op *mop;
mop = E_NEW(E_Fm2_Device_Mount_Op, 1);
mop->args = args;
mop->size = size;
mop->length = length;
return mop;
}
static inline void
_e_fm2_device_mount_op_free(E_Fm2_Device_Mount_Op *mop)
{
if (!mop) return;
free(mop->args);
free(mop);
}
static void
_e_fm2_device_volume_setup(E_Volume *v)
{
@ -281,6 +301,14 @@ e_fm2_device_volume_del(E_Volume *v)
_e_fm2_device_unmount_ok(m);
e_fm2_device_mount_free(m);
}
while (v->mount_ops)
{
E_Fm2_Device_Mount_Op *mop;
mop = (E_Fm2_Device_Mount_Op*)v->mount_ops;
v->mount_ops = eina_inlist_remove(v->mount_ops, v->mount_ops);
_e_fm2_device_mount_op_free(mop);
}
_e_fm_shared_device_volume_free(v);
}
@ -411,19 +439,32 @@ e_fm2_device_volume_mountpoint_get(E_Volume *v)
return eina_stringshare_add(buf);
}
EAPI E_Fm2_Device_Mount_Op *
e_fm2_device_mount_op_add(E_Fm2_Mount *m, char *args, size_t size, size_t length)
{
E_Fm2_Device_Mount_Op *mop;
mop = _e_fm2_device_mount_op_new(args, size, length);
m->volume->mount_ops = eina_inlist_append(m->volume->mount_ops, EINA_INLIST_GET(mop));
return mop;
}
EAPI void
e_fm2_device_mount_add(E_Volume *v,
const char *mountpoint)
{
Eina_List *l;
Eina_List *l, *ll;
E_Fm2_Mount *m;
v->mounted = EINA_TRUE;
if (mountpoint && (mountpoint[0]))
eina_stringshare_replace(&v->mount_point, mountpoint);
EINA_LIST_FOREACH(v->mounts, l, m)
_e_fm2_device_mount_ok(m);
EINA_LIST_FOREACH_SAFE(v->mounts, l, ll, m)
{
_e_fm2_device_mount_ok(m);
if (m->deleted) v->mounts = eina_list_remove_list(v->mounts, l);
}
// printf("MOUNT %s %s\n", v->udi, v->mount_point);
}
@ -543,6 +584,11 @@ e_fm2_device_unmount(E_Fm2_Mount *m)
E_Volume *v;
if (!(v = m->volume)) return;
if (v->mount_ops)
{
m->deleted = EINA_TRUE;
return;
}
v->mounts = eina_list_remove(v->mounts, m);
e_fm2_device_mount_free(m);

View File

@ -15,6 +15,7 @@ EAPI E_Volume *e_fm2_device_volume_find_fast(const char *udi);
EAPI const char *e_fm2_device_volume_mountpoint_get(E_Volume *v);
EAPI void e_fm2_device_mount_add(E_Volume *v, const char *mountpoint);
EAPI E_Fm2_Device_Mount_Op *e_fm2_device_mount_op_add(E_Fm2_Mount *m, char *args, size_t size, size_t length);
EAPI void e_fm2_device_mount_free(E_Fm2_Mount *m) EINA_ARG_NONNULL(1);
EAPI void e_fm2_device_mount_del(E_Volume *v);
EAPI E_Fm2_Mount *e_fm2_device_mount_find(const char *path);

View File

@ -34,6 +34,16 @@ typedef enum
E_VOLUME_OP_TYPE_EJECT
} E_Volume_Op_Type;
typedef struct E_Fm2_Device_Mount_Op
{
EINA_INLIST;
unsigned int action;
char *args;
void *ic;
E_Fm2_Mount *mnt;
size_t size, length;
} E_Fm2_Device_Mount_Op;
struct _E_Storage
{
int type;
@ -91,6 +101,8 @@ struct _E_Volume
E_Volume_Op_Type optype;
Efm_Mode efm_mode;
Eina_Inlist *mount_ops; // E_Fm2_Device_Mount_Op
Eina_Bool encrypted;
Eina_Bool unlocked;
@ -117,6 +129,7 @@ struct _E_Fm2_Mount
E_Volume *volume;
Eina_Bool mounted : 1;
Eina_Bool deleted : 1;
};
#endif