From 46f630f103e0cc885ebdc48937269d86e8df6646 Mon Sep 17 00:00:00 2001 From: Mike Blumenkrantz Date: Mon, 17 Dec 2012 15:59:43 +0000 Subject: [PATCH] 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 --- src/bin/e_fm.c | 276 ++++++++++++++++++++++++++++----- src/bin/e_fm_device.c | 52 ++++++- src/bin/e_fm_device.h | 1 + src/bin/e_fm_shared_types.h.in | 13 ++ 4 files changed, 303 insertions(+), 39 deletions(-) diff --git a/src/bin/e_fm.c b/src/bin/e_fm.c index cf6dbec97..50e48321c 100644 --- a/src/bin/e_fm.c +++ b/src/bin/e_fm.c @@ -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; } diff --git a/src/bin/e_fm_device.c b/src/bin/e_fm_device.c index 1b9d58975..a55e89597 100644 --- a/src/bin/e_fm_device.c +++ b/src/bin/e_fm_device.c @@ -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); diff --git a/src/bin/e_fm_device.h b/src/bin/e_fm_device.h index 1e76f7961..56aa29b93 100644 --- a/src/bin/e_fm_device.h +++ b/src/bin/e_fm_device.h @@ -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); diff --git a/src/bin/e_fm_shared_types.h.in b/src/bin/e_fm_shared_types.h.in index 52f131a67..4f7446a5f 100644 --- a/src/bin/e_fm_shared_types.h.in +++ b/src/bin/e_fm_shared_types.h.in @@ -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