#include "e.h" #include "e_fm_device.h" #include "e_fm_op.h" #define OVERCLIP 128 #define ICON_BOTTOM_SPACE 100 /* in order to check files (ie: extensions) use simpler and faster * strcasecmp version that instead of checking case for each * character, check just the first and if it's upper, assume * everything is uppercase, otherwise assume everything is lowercase. */ //#define E_FM2_SIMPLE_STRCASE_FILES 1 /* FIXME: this is NOT complete. in icon view dnd needs to be much better about placement of icons and * being able to save/load icon placement. it doesn't support custom frames or icons yet */ #define EFM_SMART_CHECK(args ...) \ E_Fm2_Smart_Data * sd; \ \ if (evas_object_smart_smart_get(obj) != _e_fm2_smart) SMARTERRNR() args; \ sd = evas_object_smart_data_get(obj); \ if ((!sd) || (e_util_strcmp(evas_object_type_get(obj), "e_fm"))) \ return args typedef enum _E_Fm2_Action_Type { FILE_ADD, FILE_DEL, FILE_CHANGE } E_Fm2_Action_Type; typedef struct _E_Fm2_Smart_Data E_Fm2_Smart_Data; typedef struct _E_Fm2_Region E_Fm2_Region; typedef struct _E_Fm2_Finfo E_Fm2_Finfo; typedef struct _E_Fm2_Action E_Fm2_Action; typedef struct _E_Fm2_Client E_Fm2_Client; typedef struct _E_Fm2_Uri E_Fm2_Uri; typedef struct _E_Fm2_Context_Menu_Data E_Fm2_Context_Menu_Data; struct _E_Fm2_Smart_Data { int id; Evas_Coord x, y, w, h, pw, ph; Eina_List *icons; Evas_Object *obj; Evas_Object *clip; Evas_Object *underlay; unsigned int overlay_count; Evas_Object *overlay; Evas_Object *overlay_clip; Evas_Object *drop; Evas_Object *drop_in; Evas_Object *sel_rect; const char *dev; const char *path; const char *realpath; struct { Evas_Coord w, h; } max, pmax, min; /* min is actually the size of the largest icon, updated each placement */ struct { Evas_Coord x, y; } pos; struct { Eina_List *list; int member_max; } regions; struct { struct { E_Fm_Cb func; void *data; } start, end, replace; E_Fm2_Menu_Flags flags; } icon_menu; struct { Ecore_Thread *thread; const char *filename; Eina_Bool done E_BITFIELD; } new_file; E_Fm2_Icon *last_selected; E_Fm2_Icon *range_selected; E_Fm2_Icon *range_select_anchor; Eina_List *selected_icons; Eina_List *icons_place; Eina_List *queue; Ecore_Timer *scan_timer; Ecore_Idler *sort_idler; Ecore_Job *scroll_job; Ecore_Job *resize_job; Ecore_Job *refresh_job; E_Menu *menu; Eina_List *rename_dialogs; E_Entry_Dialog *entry_dialog; E_Dialog *image_dialog; Eina_Bool iconlist_changed E_BITFIELD; Eina_Bool order_file E_BITFIELD; Eina_Bool typebuf_visible E_BITFIELD; Eina_Bool show_hidden_files E_BITFIELD; Eina_Bool listing E_BITFIELD; Eina_Bool inherited_dir_props E_BITFIELD; signed char view_mode; /* -1 = unset */ signed short icon_size; /* -1 = unset */ E_Fm2_View_Flags view_flags; E_Fm2_Icon *last_placed; E_Fm2_Config *config; const char *custom_theme; const char *custom_theme_content; struct { Evas_Object *obj, *obj2; Eina_List *last_insert; Eina_List **list_index; int iter; } tmp; struct { Eina_List *actions; Ecore_Idler *idler; Ecore_Timer *timer; Eina_Bool deletions E_BITFIELD; } live; struct { char *buf; const char *start; Ecore_Timer *timer; unsigned int wildcard; Eina_Bool setting E_BITFIELD; Eina_Bool disabled E_BITFIELD; } typebuf; int busy_count; E_Object *eobj; Evas_Object *win; E_Drop_Handler *drop_handler; 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 E_BITFIELD; Eina_Bool drop_in_show E_BITFIELD; Eina_Bool drop_all E_BITFIELD; Eina_Bool drag E_BITFIELD; Eina_Bool selecting E_BITFIELD; Eina_Bool toomany E_BITFIELD; struct { int ox, oy; int x, y, w, h; } selrect; E_Fm2_Icon *iop_icon; Eina_List *handlers; Efreet_Desktop *desktop; }; struct _E_Fm2_Region { E_Fm2_Smart_Data *sd; Evas_Coord x, y, w, h; Eina_List *list; Eina_Bool realized E_BITFIELD; }; struct _E_Fm2_Icon { int saved_x, saved_y; double selected_time; E_Fm2_Smart_Data *sd; E_Fm2_Region *region; Evas_Coord x, y, w, h, min_w, min_h; Evas_Object *obj, *obj_icon; E_Menu *menu; E_Entry_Dialog *entry_dialog; Evas_Object *entry_widget; E_Client_Hook *focus_hook; Eio_File *eio; Ecore_X_Window keygrab; E_Config_Dialog *prop_dialog; 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 { Evas_Coord x, y; Ecore_Timer *dnd_end_timer; //we need this for XDirectSave drops so we don't lose the icon Eina_Bool start E_BITFIELD; Eina_Bool dnd E_BITFIELD; // currently dragging Eina_Bool src E_BITFIELD; // drag source Eina_Bool hidden E_BITFIELD; // dropped into different dir } drag; int saved_rel; Eina_Bool realized E_BITFIELD; Eina_Bool selected E_BITFIELD; Eina_Bool last_selected E_BITFIELD; Eina_Bool saved_pos E_BITFIELD; Eina_Bool odd E_BITFIELD; Eina_Bool down_sel E_BITFIELD; Eina_Bool removable_state_change E_BITFIELD; Eina_Bool thumb_failed E_BITFIELD; Eina_Bool queued E_BITFIELD; Eina_Bool inserted E_BITFIELD; }; struct _E_Fm2_Finfo { struct stat st; int broken_link; const char *lnk; const char *rlnk; }; struct _E_Fm2_Action { E_Fm2_Action_Type type; const char *file; const char *file2; int flags; E_Fm2_Finfo finf; }; struct _E_Fm2_Client { Ecore_Ipc_Client *cl; int req; }; struct _E_Fm2_Uri { const char *hostname; const char *path; }; struct _E_Fm2_Context_Menu_Data { E_Fm2_Icon *icon; E_Fm2_Smart_Data *sd; E_Fm2_Mime_Handler *handler; }; static Eina_Bool _e_fm2_cb_drag_finished_show(E_Fm2_Icon *ic); static const char *_e_fm2_dev_path_map(E_Fm2_Smart_Data *sd, const char *dev, const char *path); static void _e_fm2_file_add(Evas_Object *obj, const char *file, int unique, Eina_Stringshare *file_rel, int after, E_Fm2_Finfo *finf); static void _e_fm2_file_del(Evas_Object *obj, const char *file); static void _e_fm2_queue_process(Evas_Object *obj); static void _e_fm2_queue_free(Evas_Object *obj); static void _e_fm2_regions_free(Evas_Object *obj); static void _e_fm2_regions_populate(Evas_Object *obj); static void _e_fm2_icons_place(Evas_Object *obj); static void _e_fm2_icons_free(Evas_Object *obj); static void _e_fm2_regions_eval(Evas_Object *obj); static void _e_fm2_config_free(E_Fm2_Config *cfg); static void _e_fm2_dir_load_props(E_Fm2_Smart_Data *sd); static void _e_fm2_dir_save_props(E_Fm2_Smart_Data *sd); static Eina_List *_e_fm2_file_fm2_find(const char *file); static E_Fm2_Icon *_e_fm2_icon_find(Evas_Object *obj, const char *file); static const char *_e_fm2_uri_escape(const char *path); static Eina_List *_e_fm2_uri_selected_icon_list_get(Eina_List *uri); static E_Fm2_Icon *_e_fm2_icon_new(E_Fm2_Smart_Data *sd, const char *file, E_Fm2_Finfo *finf); static void _e_fm2_icon_unfill(E_Fm2_Icon *ic); static int _e_fm2_icon_fill(E_Fm2_Icon *ic, E_Fm2_Finfo *finf); static void _e_fm2_icon_free(E_Fm2_Icon *ic); static void _e_fm2_icon_realize(E_Fm2_Icon *ic); static void _e_fm2_icon_unrealize(E_Fm2_Icon *ic); static Eina_Bool _e_fm2_icon_visible(const E_Fm2_Icon *ic); static void _e_fm2_icon_label_set(E_Fm2_Icon *ic, Evas_Object *obj); static Evas_Object *_e_fm2_icon_icon_direct_set(E_Fm2_Icon *ic, Evas_Object *o, Evas_Smart_Cb gen_func, void *data, int force_gen); static void _e_fm2_icon_icon_set(E_Fm2_Icon *ic); static void _e_fm2_icon_thumb(const E_Fm2_Icon *ic, Evas_Object *oic, int force); static void _e_fm2_icon_select(E_Fm2_Icon *ic); static void _e_fm2_icon_deselect(E_Fm2_Icon *ic); static int _e_fm2_icon_desktop_load(E_Fm2_Icon *ic); static E_Fm2_Region *_e_fm2_region_new(E_Fm2_Smart_Data *sd); static void _e_fm2_region_free(E_Fm2_Region *rg); static void _e_fm2_region_realize(E_Fm2_Region *rg); static void _e_fm2_region_unrealize(E_Fm2_Region *rg); static int _e_fm2_region_visible(E_Fm2_Region *rg); static void _e_fm2_icon_make_visible(E_Fm2_Icon *ic); static void _e_fm2_icon_desel_any(Evas_Object *obj); static E_Fm2_Icon *_e_fm2_icon_first_selected_find(Evas_Object *obj); static E_Fm2_Icon *_e_fm2_icon_next_find(Evas_Object *obj, int next, int (*match_func)(E_Fm2_Icon *ic, void *data), void *data); static void _e_fm2_icon_sel_any(Evas_Object *obj); static void _e_fm2_icon_sel_first(Evas_Object *obj, Eina_Bool add); static void _e_fm2_icon_sel_last(Evas_Object *obj, Eina_Bool add); static void _e_fm2_icon_sel_prev(Evas_Object *obj, Eina_Bool add); static void _e_fm2_icon_sel_next(Evas_Object *obj, Eina_Bool add); static void _e_fm2_icon_sel_down(Evas_Object *obj, Eina_Bool add); static void _e_fm2_icon_sel_up(Evas_Object *obj, Eina_Bool add); static void _e_fm2_icon_range_select(E_Fm2_Icon *ic); static void _e_fm2_typebuf_show(Evas_Object *obj); static void _e_fm2_typebuf_hide(Evas_Object *obj); //static void _e_fm2_typebuf_history_prev(Evas_Object *obj); //static void _e_fm2_typebuf_history_next(Evas_Object *obj); static void _e_fm2_typebuf_run(Evas_Object *obj); static E_Fm2_Icon *_e_fm2_typebuf_match(Evas_Object *obj, int next); static void _e_fm2_typebuf_complete(Evas_Object *obj); static void _e_fm2_typebuf_char_append(Evas_Object *obj, const char *ch); static void _e_fm2_typebuf_char_backspace(Evas_Object *obj); static void _e_fm2_cb_dnd_enter(void *data, const char *type, void *event); static void _e_fm2_cb_dnd_move(void *data, const char *type, void *event); static void _e_fm2_cb_dnd_leave(void *data, const char *type, void *event); static void _e_fm2_cb_dnd_selection_notify(void *data, const char *type, void *event); static void _e_fm2_cb_icon_mouse_down(void *data, Evas *e, Evas_Object *obj, void *event_info); static void _e_fm2_cb_icon_mouse_up(void *data, Evas *e, Evas_Object *obj, void *event_info); static void _e_fm2_cb_icon_mouse_move(void *data, Evas *e, Evas_Object *obj, void *event_info); static void _e_fm2_cb_icon_mouse_in(void *data, Evas *e, Evas_Object *obj, void *event_info); static void _e_fm2_cb_icon_mouse_out(void *data, Evas *e, Evas_Object *obj, void *event_info); static void _e_fm2_cb_icon_thumb_dnd_gen(void *data, Evas_Object *obj, void *event_info); static void _e_fm2_cb_icon_thumb_gen(void *data, Evas_Object *obj, void *event_info); static void _e_fm2_cb_key_down(void *data, Evas *e, Evas_Object *obj, void *event_info); static void _e_fm2_cb_mouse_down(void *data, Evas *e, Evas_Object *obj, void *event_info); static void _e_fm2_cb_mouse_up(void *data, Evas *e, Evas_Object *obj, void *event_info); static void _e_fm2_cb_mouse_move(void *data, Evas *e, Evas_Object *obj, void *event_info); static void _e_fm2_cb_scroll_job(void *data); static void _e_fm2_cb_resize_job(void *data); static int _e_fm2_cb_icon_sort(const void *data1, const void *data2); static Eina_Bool _e_fm2_cb_scan_timer(void *data); static Eina_Bool _e_fm2_cb_sort_idler(void *data); static Eina_Bool _e_fm2_cb_theme(void *data, int type EINA_UNUSED, void *event EINA_UNUSED); static void _e_fm2_obj_icons_place(E_Fm2_Smart_Data *sd); static void _e_fm2_smart_add(Evas_Object *object); static void _e_fm2_smart_del(Evas_Object *object); static void _e_fm2_smart_move(Evas_Object *object, Evas_Coord x, Evas_Coord y); static void _e_fm2_smart_resize(Evas_Object *object, Evas_Coord w, Evas_Coord h); static void _e_fm2_smart_show(Evas_Object *object); static void _e_fm2_smart_hide(Evas_Object *object); static void _e_fm2_smart_color_set(Evas_Object *obj, int r, int g, int b, int a); static void _e_fm2_smart_clip_set(Evas_Object *obj, Evas_Object *clip); static void _e_fm2_smart_clip_unset(Evas_Object *obj); static void _e_fm2_menu(Evas_Object *obj, unsigned int timestamp); static void _e_fm2_menu_post_cb(void *data, E_Menu *m); static void _e_fm2_icon_menu(E_Fm2_Icon *ic, Evas_Object *obj, unsigned int timestamp); static void _e_fm2_icon_menu_post_cb(void *data, E_Menu *m); static void _e_fm2_icon_menu_item_cb(void *data, E_Menu *m, E_Menu_Item *mi); static void _e_fm2_icon_view_menu_pre(void *data, E_Menu *m); static void _e_fm2_options_menu_pre(void *data, E_Menu *m); static void _e_fm2_add_menu_pre(void *data, E_Menu *m); static void _e_fm2_toggle_inherit_dir_props(void *data, E_Menu *m, E_Menu_Item *mi); static void _e_fm2_view_menu_pre(void *data, E_Menu *m); static void _e_fm2_view_menu_grid_icons_cb(void *data, E_Menu *m, E_Menu_Item *mi); static void _e_fm2_view_menu_custom_icons_cb(void *data, E_Menu *m, E_Menu_Item *mi); static void _e_fm2_view_menu_list_cb(void *data, E_Menu *m, E_Menu_Item *mi); static void _e_fm2_view_menu_use_default_cb(void *data, E_Menu *m, E_Menu_Item *mi); static void _e_fm2_view_menu_set_background_cb(void *data, E_Menu *m, E_Menu_Item *mi); static void _e_fm2_view_menu_set_overlay_cb(void *data, E_Menu *m, E_Menu_Item *mi); static void _e_fm2_view_image_sel(E_Fm2_Smart_Data *sd, const char *title, void (*ok_cb)(void *data, E_Dialog *dia)); static void _e_fm2_view_image_sel_close(void *data, E_Dialog *dia); static void _e_fm2_refresh(void *data, E_Menu *m, E_Menu_Item *mi); static void _e_fm2_toggle_hidden_files(void *data, E_Menu *m, E_Menu_Item *mi); static void _e_fm2_toggle_single_click(void *data, E_Menu *m, E_Menu_Item *mi); static void _e_fm2_toggle_secure_rm(void *data, E_Menu *m, E_Menu_Item *mi); static void _e_fm2_toggle_ordering(void *data, E_Menu *m, E_Menu_Item *mi); static void _e_fm2_sort(void *data, E_Menu *m, E_Menu_Item *mi); static void _e_fm2_new_directory(void *data, E_Menu *m, E_Menu_Item *mi); static void _e_fm2_file_rename(void *data, E_Menu *m, E_Menu_Item *mi); static void _e_fm2_file_rename_delete_cb(void *obj); static void _e_fm2_file_rename_yes_cb(void *data, char *text); static void _e_fm2_file_rename_no_cb(void *data); static void _e_fm2_file_application_properties(void *data, E_Menu *m EINA_UNUSED, E_Menu_Item *mi EINA_UNUSED); static void _e_fm2_file_properties(void *data, E_Menu *m, E_Menu_Item *mi); static void _e_fm2_file_properties_delete_cb(void *obj); static int _e_fm2_file_do_rename(const char *text, E_Fm2_Icon *ic); static Evas_Object *_e_fm2_icon_entry_widget_add(E_Fm2_Icon *ic); static void _e_fm2_icon_entry_widget_del(E_Fm2_Icon *ic); static void _e_fm2_icon_entry_widget_cb_key_down(void *data, Evas *e, Evas_Object *obj, void *event_info); static void _e_fm2_icon_entry_widget_accept(E_Fm2_Icon *ic); static E_Dialog *_e_fm_retry_abort_dialog(int pid, const char *str); static void _e_fm_retry_abort_retry_cb(void *data, E_Dialog *dialog); static void _e_fm_retry_abort_abort_cb(void *data, E_Dialog *dialog); static E_Dialog *_e_fm_overwrite_dialog(int pid, const char *str); static void _e_fm_overwrite_no_cb(void *data, E_Dialog *dialog); static void _e_fm_overwrite_no_all_cb(void *data, E_Dialog *dialog); static void _e_fm_overwrite_rename(void *data, E_Dialog *dialog); static void _e_fm_overwrite_yes_cb(void *data, E_Dialog *dialog); static void _e_fm_overwrite_yes_all_cb(void *data, E_Dialog *dialog); static E_Dialog *_e_fm_error_dialog(int pid, const char *str); static void _e_fm_error_retry_cb(void *data, E_Dialog *dialog); static void _e_fm_error_abort_cb(void *data, E_Dialog *dialog); static void _e_fm_error_link_source(void *data, E_Dialog *dialog); static void _e_fm_error_ignore_this_cb(void *data, E_Dialog *dialog); static void _e_fm_error_ignore_all_cb(void *data, E_Dialog *dialog); static void _e_fm_device_error_dialog(const char *title, const char *msg, const char *pstr); static void _e_fm2_file_delete(Evas_Object *obj); static void _e_fm2_file_delete_menu(void *data, E_Menu *m, E_Menu_Item *mi); static void _e_fm2_file_delete_delete_cb(void *obj); static void _e_fm2_file_delete_yes_cb(void *data, E_Dialog *dialog); static void _e_fm2_file_delete_no_cb(void *data, E_Dialog *dialog); static void _e_fm2_refresh_job_cb(void *data); static void _e_fm_file_buffer_clear(void); static void _e_fm2_file_cut(Evas_Object *obj); static void _e_fm2_file_copy(Evas_Object *obj); static void _e_fm2_file_paste(Evas_Object *obj); static void _e_fm2_file_symlink(Evas_Object *obj); static void _e_fm2_file_cut_menu(void *data, E_Menu *m, E_Menu_Item *mi); static void _e_fm2_file_copy_menu(void *data, E_Menu *m, E_Menu_Item *mi); static void _e_fm2_file_paste_menu(void *data, E_Menu *m, E_Menu_Item *mi); static void _e_fm2_file_symlink_menu(void *data, E_Menu *m, E_Menu_Item *mi); static void _e_fm2_live_file_add(Evas_Object *obj, const char *file, const char *file_rel, int after, E_Fm2_Finfo *finf); static void _e_fm2_live_file_del(Evas_Object *obj, const char *file); static void _e_fm2_live_file_changed(Evas_Object *obj, const char *file, E_Fm2_Finfo *finf); static void _e_fm2_live_process_begin(Evas_Object *obj); static void _e_fm2_live_process_end(Evas_Object *obj); static void _e_fm2_live_process(Evas_Object *obj); static Eina_Bool _e_fm2_cb_live_idler(void *data); static Eina_Bool _e_fm2_cb_live_timer(void *data); static int _e_fm2_theme_edje_object_set(E_Fm2_Smart_Data *sd, Evas_Object *o, const char *category, const char *group); static int _e_fm2_theme_edje_icon_object_set(E_Fm2_Smart_Data *sd, Evas_Object *o, const char *category, const char *group); static void _e_fm2_mouse_2_handler(E_Fm2_Icon *ic, void *evas_event); static void _e_fm2_client_spawn(void); static E_Fm2_Client *_e_fm2_client_get(void); static int _e_fm2_client_monitor_add(const char *path); static void _e_fm2_client_monitor_del(int id, const char *path); static int _e_fm_client_file_del(const char *files, Eina_Bool secure, Evas_Object *e_fm); //static int _e_fm2_client_file_trash(const char *path, Evas_Object *e_fm); //static int _e_fm2_client_file_mkdir(const char *path, const char *rel, int rel_to, int x, int y, int res_w, int res_h, Evas_Object *e_fm); static void _e_fm2_sel_rect_update(void *data); static void _e_fm2_context_menu_append(E_Fm2_Smart_Data *sd, const char *path, const Eina_List *l, E_Menu *mn, E_Fm2_Icon *ic); static int _e_fm2_context_list_sort(const void *data1, const void *data2); void _e_fm2_path_parent_set(Evas_Object *obj, const char *path); static void _e_fm2_volume_mount(void *data, E_Menu *m, E_Menu_Item *mi); static void _e_fm2_volume_unmount(void *data, E_Menu *m, E_Menu_Item *mi); static void _e_fm2_volume_eject(void *data, E_Menu *m, E_Menu_Item *mi); static void _e_fm2_icon_removable_update(E_Fm2_Icon *ic); static void _e_fm2_volume_icon_update(E_Volume *v); static int _e_fm2_desktop_open(E_Fm2_Smart_Data *sd); static void _e_fm2_operation_abort_internal(E_Fm2_Op_Registry_Entry *ere); static Eina_Bool _e_fm2_sys_suspend_hibernate(void *, int, void *); static void _e_fm2_favorites_thread_cb(void *d, Ecore_Thread *et); static void _e_fm2_thread_cleanup_cb(void *d, Ecore_Thread *et); static void _e_fm2_new_file(void *data, E_Menu *m, E_Menu_Item *mi); static Ecore_Exe *_e_fm2_exe = NULL; static char *_e_fm2_meta_path = NULL; static Evas_Smart *_e_fm2_smart = NULL; static Eina_List *_e_fm2_list = NULL; static Eina_List *_e_fm2_list_remove = NULL; static int _e_fm2_list_walking = 0; static Eina_List *_e_fm2_client_list = NULL; static Eina_List *_e_fm2_menu_contexts = NULL; static Eina_List *_e_fm_file_buffer = NULL; /* Files for copy&paste are saved here. */ static int _e_fm_file_buffer_copying = 0; static const char *_e_fm2_icon_desktop_str = NULL; static const char *_e_fm2_icon_thumb_str = NULL; static const char *_e_fm2_mime_inode_directory = NULL; static const char *_e_fm2_mime_app_desktop = NULL; static const char *_e_fm2_mime_app_edje = NULL; static const char *_e_fm2_mime_text_uri_list = NULL; static const char *_e_fm2_mime_xmozurl = NULL; static const char *_e_fm2_xds = NULL; static Eina_List *_e_fm_handlers = NULL; static const char **_e_fm2_dnd_types[] = { &_e_fm2_mime_text_uri_list, &_e_fm2_xds, &_e_fm2_mime_xmozurl, NULL }; static Ecore_Timer *_e_fm2_mime_flush = NULL; static Ecore_Timer *_e_fm2_mime_clear = NULL; static Ecore_Thread *_e_fm2_favorites_thread = NULL; /* contains: * _e_volume_edd * _e_storage_edd * _e_volume_free() * _e_storage_free() * _e_volume_edd_new() * _e_storage_edd_new() * _e_storage_volume_edd_init() * _e_storage_volume_edd_shutdown() */ #include "e_fm_shared_codec.h" static inline Eina_Bool _e_fm2_icon_realpath(const E_Fm2_Icon *ic, char *buf, int buflen) { int r = snprintf(buf, buflen, "%s/%s", ic->sd->realpath, ic->info.file); return r < buflen; } static inline Eina_Bool _e_fm2_icon_path(const E_Fm2_Icon *ic, char *buf, int buflen) { int r; if (ic->info.real_link) r = snprintf(buf, buflen, "%s", ic->info.real_link); else r = snprintf(buf, buflen, "%s/%s", ic->sd->path, ic->info.file); return r < buflen; } static inline Eina_Bool _e_fm2_ext_is_edje(const char *ext) { #ifdef E_FM2_SIMPLE_STRCASE_FILES if ((ext[0] == 'e') && (ext[1] == 'd') && (ext[2] == 'j')) return 1; else if ((ext[0] == 'E') && (ext[1] == 'D') && (ext[2] == 'J')) return 1; else return 0; #else return strcasecmp(ext, "edj") == 0; #endif } static inline Eina_Bool _e_fm2_ext_is_desktop(const char *ext) { #ifdef E_FM2_SIMPLE_STRCASE_FILES if ((ext[0] == 'd') && ((strcmp(ext + 1, "esktop") == 0) || (strcmp(ext + 1, "irectory") == 0))) return 1; else if ((ext[0] == 'D') && ((strcmp(ext + 1, "ESKTOP") == 0) || (strcmp(ext + 1, "IRECTORY") == 0))) return 1; else return 0; #else if ((ext[0] != 'd') && (ext[0] != 'D')) return 0; ext++; return (strcasecmp(ext, "esktop") == 0) || (strcasecmp(ext, "irectory") == 0); #endif } static inline Eina_Bool _e_fm2_ext_is_imc(const char *ext) { #ifdef E_FM2_SIMPLE_STRCASE_FILES if ((ext[0] == 'i') && (ext[1] == 'm') && (ext[2] == 'c')) return 1; else if ((ext[0] == 'I') && (ext[1] == 'M') && (ext[2] == 'C')) return 1; else return 0; #else return strcasecmp(ext, "imc") == 0; #endif } static inline Eina_Bool _e_fm2_file_is_edje(const char *file) { const char *p = strrchr(file, '.'); return (p) && (_e_fm2_ext_is_edje(p + 1)); } static inline Eina_Bool _e_fm2_file_is_desktop(const char *file) { const char *p = strrchr(file, '.'); return (p) && (_e_fm2_ext_is_desktop(p + 1)); } static inline Eina_Bool _e_fm2_toomany_get(const E_Fm2_Smart_Data *sd) { char mode; mode = sd->config->view.mode; if (sd->view_mode > -1) mode = sd->view_mode; if (((mode >= E_FM2_VIEW_MODE_CUSTOM_ICONS) && (mode <= E_FM2_VIEW_MODE_CUSTOM_SMART_GRID_ICONS)) && (eina_list_count(sd->icons) >= 500)) return EINA_TRUE; return EINA_FALSE; } static inline char _e_fm2_view_mode_get(const E_Fm2_Smart_Data *sd) { char mode; mode = sd->config->view.mode; if (sd->view_mode > -1) mode = sd->view_mode; if ((sd->toomany) && ((mode >= E_FM2_VIEW_MODE_CUSTOM_ICONS) && (mode <= E_FM2_VIEW_MODE_CUSTOM_SMART_GRID_ICONS))) return E_FM2_VIEW_MODE_GRID_ICONS; return mode; } static inline Evas_Coord _e_fm2_icon_w_get(const E_Fm2_Smart_Data *sd) { if (sd->icon_size > -1) return sd->icon_size * e_scale; if (sd->config->icon.icon.w) return sd->config->icon.icon.w; return sd->config->icon.list.w; } static inline Evas_Coord _e_fm2_icon_h_get(const E_Fm2_Smart_Data *sd) { if (sd->icon_size > -1) return sd->icon_size * e_scale; if (sd->config->icon.icon.h) return sd->config->icon.icon.h; return sd->config->icon.list.h; } static inline unsigned int _e_fm2_icon_mime_size_normalize(const E_Fm2_Icon *ic) { return e_util_icon_size_normalize(_e_fm2_icon_w_get(ic->sd)); } static Eina_Bool _e_fm2_mime_flush_cb(void *data EINA_UNUSED) { efreet_mime_type_cache_flush(); return ECORE_CALLBACK_RENEW; } static Eina_Bool _e_fm2_mime_clear_cb(void *data EINA_UNUSED) { efreet_mime_type_cache_clear(); return ECORE_CALLBACK_RENEW; } static void _e_fm2_op_registry_go_on(int id) { E_Fm2_Op_Registry_Entry *ere = e_fm2_op_registry_entry_get(id); if (!ere) return; ere->status = E_FM2_OP_STATUS_IN_PROGRESS; ere->needs_attention = 0; ere->dialog = NULL; e_fm2_op_registry_entry_changed(ere); } static void _e_fm2_op_registry_aborted(int id) { E_Fm2_Op_Registry_Entry *ere = e_fm2_op_registry_entry_get(id); if (!ere) return; ere->status = E_FM2_OP_STATUS_ABORTED; ere->needs_attention = 0; ere->dialog = NULL; ere->finished = 1; e_fm2_op_registry_entry_changed(ere); // XXX e_fm2_op_registry_entry_del(id); } static void _e_fm2_op_registry_error(int id, E_Dialog *dlg) { E_Fm2_Op_Registry_Entry *ere = e_fm2_op_registry_entry_get(id); if (!ere) return; ere->status = E_FM2_OP_STATUS_ERROR; ere->needs_attention = 1; ere->dialog = dlg; e_fm2_op_registry_entry_changed(ere); } static void _e_fm2_op_registry_needs_attention(int id, E_Dialog *dlg) { E_Fm2_Op_Registry_Entry *ere = e_fm2_op_registry_entry_get(id); if (!ere) return; ere->needs_attention = 1; ere->dialog = dlg; e_fm2_op_registry_entry_changed(ere); } /////////////// DBG: static void _e_fm2_op_registry_entry_print(const E_Fm2_Op_Registry_Entry *ere) { const char *status_strings[] = { "UNKNOWN", "IN_PROGRESS", "SUCCESSFUL", "ABORTED", "ERROR" }; const char *status; if (ere->status <= E_FM2_OP_STATUS_ERROR) status = status_strings[ere->status]; else status = status_strings[0]; DBG("id: %8d, op: %2d [%s] finished: %hhu, needs_attention: %hhu\n" " %3d%% (%" PRIi64 "/%" PRIi64 "), start_time: %10.0f, eta: %5ds, xwin: %#x\n" " src=[%s]\n" " dst=[%s]", ere->id, ere->op, status, ere->finished, ere->needs_attention, ere->percent, ere->done, ere->total, ere->start_time, ere->eta, e_fm2_op_registry_entry_xwin_get(ere), ere->src, ere->dst); } static Eina_Bool _e_fm2_exe_del(void *data EINA_UNUSED, int type EINA_UNUSED, void *event) { Ecore_Exe_Event_Del *ev = event; if (ev->exe == _e_fm2_exe) _e_fm2_exe = NULL; return ECORE_CALLBACK_RENEW; } static Eina_Bool _e_fm2_op_registry_entry_add_cb(void *data EINA_UNUSED, int type EINA_UNUSED, void *event) { const E_Fm2_Op_Registry_Entry *ere = event; DBG("E FM OPERATION STARTED: id=%d, op=%d", ere->id, ere->op); return ECORE_CALLBACK_RENEW; } static Eina_Bool _e_fm2_op_registry_entry_del_cb(void *data EINA_UNUSED, int type EINA_UNUSED, void *event) { const E_Fm2_Op_Registry_Entry *ere = event; puts("E FM OPERATION FINISHED:"); _e_fm2_op_registry_entry_print(ere); puts("---"); return ECORE_CALLBACK_RENEW; } static Eina_Bool _e_fm2_op_registry_entry_changed_cb(void *data EINA_UNUSED, int type EINA_UNUSED, void *event) { const E_Fm2_Op_Registry_Entry *ere = event; puts("E FM OPERATION CHANGED:"); _e_fm2_op_registry_entry_print(ere); puts("---"); return ECORE_CALLBACK_RENEW; } /////////////// DBG: /***/ EINTERN int e_fm2_init(void) { char path[PATH_MAX]; eina_init(); ecore_init(); _e_storage_volume_edd_init(); e_user_dir_concat_static(path, "fileman/metadata"); ecore_file_mkpath(path); _e_fm2_meta_path = strdup(path); { static const Evas_Smart_Class sc = { "e_fm", EVAS_SMART_CLASS_VERSION, _e_fm2_smart_add, /* add */ _e_fm2_smart_del, /* del */ _e_fm2_smart_move, /* move */ _e_fm2_smart_resize, /* resize */ _e_fm2_smart_show, /* show */ _e_fm2_smart_hide, /* hide */ _e_fm2_smart_color_set, /* color_set */ _e_fm2_smart_clip_set, /* clip_set */ _e_fm2_smart_clip_unset, /* clip_unset */ NULL, NULL, NULL, NULL, NULL, NULL, NULL }; _e_fm2_smart = evas_smart_class_new(&sc); } // _e_fm2_client_spawn(); e_fm2_custom_file_init(); e_fm2_op_registry_init(); efreet_mime_init(); /* XXX: move this to a central/global place? */ _e_fm2_mime_flush = ecore_timer_loop_add(60.0, _e_fm2_mime_flush_cb, NULL); _e_fm2_mime_clear = ecore_timer_loop_add(600.0, _e_fm2_mime_clear_cb, NULL); _e_fm2_icon_desktop_str = eina_stringshare_add("DESKTOP"); _e_fm2_icon_thumb_str = eina_stringshare_add("THUMB"); _e_fm2_mime_inode_directory = eina_stringshare_add("inode/directory"); _e_fm2_mime_app_desktop = eina_stringshare_add("application/x-desktop"); _e_fm2_mime_app_edje = eina_stringshare_add("application/x-extension-edj"); _e_fm2_mime_text_uri_list = eina_stringshare_add("text/uri-list"); _e_fm2_xds = eina_stringshare_add("XdndDirectSave0"); _e_fm2_mime_xmozurl = eina_stringshare_add("text/x-moz-url"); _e_fm2_favorites_thread = ecore_thread_run(_e_fm2_favorites_thread_cb, _e_fm2_thread_cleanup_cb, _e_fm2_thread_cleanup_cb, NULL); E_LIST_HANDLER_APPEND(_e_fm_handlers, ECORE_EXE_EVENT_DEL, _e_fm2_exe_del, NULL); /// DBG E_LIST_HANDLER_APPEND(_e_fm_handlers, E_EVENT_FM_OP_REGISTRY_ADD, _e_fm2_op_registry_entry_add_cb, NULL); E_LIST_HANDLER_APPEND(_e_fm_handlers, E_EVENT_FM_OP_REGISTRY_DEL, _e_fm2_op_registry_entry_del_cb, NULL); E_LIST_HANDLER_APPEND(_e_fm_handlers, E_EVENT_FM_OP_REGISTRY_CHANGED, _e_fm2_op_registry_entry_changed_cb, NULL); /// DBG E_LIST_HANDLER_APPEND(_e_fm_handlers, E_EVENT_SYS_HIBERNATE, _e_fm2_sys_suspend_hibernate, NULL); E_LIST_HANDLER_APPEND(_e_fm_handlers, E_EVENT_SYS_RESUME, _e_fm2_sys_suspend_hibernate, NULL); return 1; } EINTERN int e_fm2_shutdown(void) { e_fm2_die(); E_FREE_LIST(_e_fm2_list, evas_object_del); eina_stringshare_replace(&_e_fm2_icon_desktop_str, NULL); eina_stringshare_replace(&_e_fm2_icon_thumb_str, NULL); eina_stringshare_replace(&_e_fm2_mime_inode_directory, NULL); eina_stringshare_replace(&_e_fm2_mime_app_desktop, NULL); eina_stringshare_replace(&_e_fm2_mime_app_edje, NULL); eina_stringshare_replace(&_e_fm2_mime_text_uri_list, NULL); eina_stringshare_replace(&_e_fm2_xds, NULL); eina_stringshare_replace(&_e_fm2_mime_xmozurl, NULL); E_FREE_LIST(_e_fm_handlers, ecore_event_handler_del); ecore_timer_del(_e_fm2_mime_flush); _e_fm2_mime_flush = NULL; ecore_timer_del(_e_fm2_mime_clear); _e_fm2_mime_clear = NULL; if (_e_fm2_favorites_thread) ecore_thread_cancel(_e_fm2_favorites_thread); _e_fm2_favorites_thread = NULL; evas_smart_free(_e_fm2_smart); _e_fm2_smart = NULL; E_FREE(_e_fm2_meta_path); e_fm2_custom_file_shutdown(); _e_storage_volume_edd_shutdown(); e_fm2_op_registry_shutdown(); efreet_mime_shutdown(); ecore_shutdown(); eina_shutdown(); return 1; } E_API void e_fm2_die(void) { if (_e_fm2_exe) { ecore_exe_kill(_e_fm2_exe); ecore_exe_free(_e_fm2_exe); _e_fm2_exe = NULL; } } E_API Evas_Object * e_fm2_add(Evas *evas) { return evas_object_smart_add(evas, _e_fm2_smart); } static Eina_Bool _e_fm2_cb_dnd_drop(void *data, const char *type) { E_Fm2_Smart_Data *sd = data; Eina_Bool allow; char buf[PATH_MAX]; if (sd->config->view.link_drop && (type == _e_fm2_xds)) allow = EINA_FALSE; else { if (sd->drop_icon) { snprintf(buf, sizeof(buf), "%s/%s", sd->realpath, sd->drop_icon->info.file); allow = ecore_file_can_write(buf); } else allow = (sd->realpath && ecore_file_can_write(sd->realpath)); } e_drop_xds_update(allow, sd->drop_icon ? buf : sd->realpath); if (sd->dnd_scroller) ecore_animator_del(sd->dnd_scroller); sd->dnd_scroller = NULL; sd->dnd_current.x = sd->dnd_current.y = 0; return allow; } static void _e_fm2_cb_mount_ok(void *data) { E_Fm2_Smart_Data *sd; sd = evas_object_smart_data_get(data); if (!sd) return; // safety if (sd->mount->volume->efm_mode != EFM_MODE_USING_HAL_MOUNT) { /* Clean up typebuf. */ _e_fm2_typebuf_hide(data); /* we only just now have the mount point so we should do stuff we couldn't do before */ eina_stringshare_replace(&sd->realpath, sd->mount->volume->mount_point); eina_stringshare_replace(&sd->mount->mount_point, sd->mount->volume->mount_point); _e_fm2_dir_load_props(sd); } if ((sd->realpath) && (strcmp(sd->mount->mount_point, sd->realpath))) { e_fm2_path_set(sd->obj, "/", sd->mount->mount_point); } else { sd->id = _e_fm2_client_monitor_add(sd->mount->mount_point); sd->listing = EINA_TRUE; evas_object_smart_callback_call(data, "dir_changed", NULL); sd->tmp.iter = EINA_FALSE; } } static void _e_fm2_cb_mount_fail(void *data) { E_Fm2_Smart_Data *sd; sd = evas_object_smart_data_get(data); if (!sd) return; // safety if (sd->mount) { // At this moment E_Fm2_Mount object already deleted in e_fm_device.c sd->mount = NULL; if (sd->config->view.open_dirs_in_place) e_fm2_path_set(data, "favorites", "/"); else evas_object_smart_callback_call(data, "dir_deleted", NULL); } } static void _e_fm2_cb_unmount_ok(void *data) { E_Fm2_Smart_Data *sd; sd = evas_object_smart_data_get(data); if (!sd) return; if (sd->mount) { sd->mount = NULL; if (sd->config->view.open_dirs_in_place && sd->realpath) _e_fm2_path_parent_set(data, sd->realpath); else evas_object_smart_callback_call(data, "dir_deleted", NULL); } } void _e_fm2_path_parent_set(Evas_Object *obj, const char *path) { char buf[PATH_MAX], *p; int idx; p = strrchr(path, '/'); if (!p || (p == path)) e_fm2_path_set(obj, "/", "/"); else { idx = p - path; if (idx < PATH_MAX) { strncpy(buf, path, idx); buf[idx] = '\0'; e_fm2_path_set(obj, "/", buf); } else e_fm2_path_set(obj, "/", "/"); } } static void _e_fm2_favorites_thread_cb(void *d EINA_UNUSED, Ecore_Thread *et EINA_UNUSED) { e_fm2_favorites_init(); } static void _e_fm2_thread_cleanup_cb(void *d EINA_UNUSED, Ecore_Thread *et EINA_UNUSED) { _e_fm2_favorites_thread = NULL; } E_API void e_fm2_path_set(Evas_Object *obj, const char *dev, const char *path) { const char *real_path; EFM_SMART_CHECK(); /* internal config for now - don't see a point making this configurable */ sd->regions.member_max = 64; if (!sd->config) { sd->config = E_NEW(E_Fm2_Config, 1); if (!sd->config) return; // sd->config->view.mode = E_FM2_VIEW_MODE_ICONS; sd->config->view.mode = E_FM2_VIEW_MODE_LIST; sd->config->view.open_dirs_in_place = EINA_TRUE; sd->config->view.selector = EINA_TRUE; sd->config->view.single_click = e_config->filemanager_single_click; sd->config->view.single_click_delay = EINA_FALSE; sd->config->view.no_subdir_jump = EINA_FALSE; sd->config->icon.max_thumb_size = 5; sd->config->icon.icon.w = 128; sd->config->icon.icon.h = 128; sd->config->icon.list.w = 24; sd->config->icon.list.h = 24; sd->config->icon.fixed.w = EINA_TRUE; sd->config->icon.fixed.h = EINA_TRUE; sd->config->icon.extension.show = EINA_FALSE; sd->config->list.sort.no_case = EINA_TRUE; sd->config->list.sort.dirs.first = EINA_TRUE; sd->config->list.sort.dirs.last = EINA_FALSE; sd->config->selection.single = EINA_FALSE; sd->config->selection.windows_modifiers = EINA_FALSE; sd->config->theme.background = NULL; sd->config->theme.frame = NULL; sd->config->theme.icons = NULL; sd->config->theme.fixed = EINA_FALSE; } real_path = _e_fm2_dev_path_map(sd, dev, path); /* If the path doesn't exist, popup a dialog */ if (dev && strncmp(dev, "removable:", 10) && !ecore_file_exists(real_path)) { E_Dialog *dialog; char text[4096 + 256]; dialog = e_dialog_new(NULL, "E", "_fm_file_unexisting_path_dialog"); e_dialog_button_add(dialog, _("Close"), NULL, NULL, dialog); e_dialog_button_focus_num(dialog, 0); e_dialog_title_set(dialog, _("Nonexistent path")); e_dialog_icon_set(dialog, "dialog-error", 64); snprintf(text, sizeof(text), _("%s doesn't exist."), real_path); e_dialog_text_set(dialog, text); elm_win_center(dialog->win, 1, 1); e_dialog_show(dialog); return; } if (real_path && (sd->realpath == real_path)) return; E_FREE_FUNC(sd->scan_timer, ecore_timer_del); E_FREE_FUNC(sd->sort_idler, ecore_idler_del); if (sd->busy_count) sd->busy_count--; if (sd->busy_count == 0) { edje_object_signal_emit(sd->overlay, "e,state,busy,stop", "e"); e_fm2_custom_file_flush(); } if (sd->realpath) _e_fm2_client_monitor_del(sd->id, sd->realpath); sd->listing = EINA_FALSE; if (sd->new_file.thread) ecore_thread_cancel(sd->new_file.thread); sd->new_file.thread = NULL; eina_stringshare_replace(&sd->new_file.filename, NULL); eina_stringshare_replace(&sd->dev, dev); eina_stringshare_replace(&sd->path, path); eina_stringshare_del(sd->realpath); sd->realpath = real_path; _e_fm2_queue_free(obj); _e_fm2_regions_free(obj); _e_fm2_icons_free(obj); sd->overlay_count = 0; edje_object_part_text_set(sd->overlay, "e.text.busy_label", ""); _e_fm2_dir_load_props(sd); /* If the path change from a mountpoint to something else, we fake-unmount */ if (sd->mount && sd->mount->mount_point && real_path && strncmp(sd->mount->mount_point, sd->realpath, strlen(sd->mount->mount_point))) { e_fm2_device_unmount(sd->mount); sd->mount = NULL; } /* Clean up typebuf. */ _e_fm2_typebuf_hide(obj); /* If the path is of type removable: we add a new mountpoint */ if (sd->dev && !sd->mount && !strncmp(sd->dev, "removable:", 10)) { E_Volume *v = NULL; v = e_fm2_device_volume_find(sd->dev + sizeof("removable:") - 1); if (v) { sd->mount = e_fm2_device_mount(v, _e_fm2_cb_mount_ok, _e_fm2_cb_mount_fail, _e_fm2_cb_unmount_ok, NULL, obj); if ((v->efm_mode == EFM_MODE_USING_HAL_MOUNT) && (!sd->mount->mounted)) return; } } else if (sd->config->view.open_dirs_in_place == 0) { E_Fm2_Mount *m; m = e_fm2_device_mount_find(sd->realpath); if (m) { sd->mount = e_fm2_device_mount(m->volume, _e_fm2_cb_mount_ok, _e_fm2_cb_mount_fail, _e_fm2_cb_unmount_ok, NULL, obj); if ((m->volume->efm_mode != EFM_MODE_USING_HAL_MOUNT) && (!sd->mount->mounted)) return; } } if (!sd->realpath) return; if (!sd->mount || sd->mount->mounted) { if (sd->dev && (!strcmp(sd->dev, "favorites")) && (!_e_fm2_favorites_thread)) _e_fm2_favorites_thread = ecore_thread_run(_e_fm2_favorites_thread_cb, _e_fm2_thread_cleanup_cb, _e_fm2_thread_cleanup_cb, NULL); sd->id = _e_fm2_client_monitor_add(sd->realpath); sd->listing = EINA_TRUE; } evas_object_smart_callback_call(obj, "dir_changed", NULL); sd->tmp.iter = EINA_FALSE; } E_API void e_fm2_underlay_show(Evas_Object *obj) { EFM_SMART_CHECK(); evas_object_show(sd->underlay); } E_API void e_fm2_underlay_hide(Evas_Object *obj) { EFM_SMART_CHECK(); evas_object_hide(sd->underlay); } E_API void e_fm2_all_unsel(Evas_Object *obj) { EFM_SMART_CHECK(); _e_fm2_icon_desel_any(obj); } E_API void e_fm2_all_sel(Evas_Object *obj) { EFM_SMART_CHECK(); _e_fm2_icon_sel_any(obj); } E_API void e_fm2_first_sel(Evas_Object *obj) { EFM_SMART_CHECK(); _e_fm2_icon_sel_first(obj, EINA_FALSE); } E_API void e_fm2_last_sel(Evas_Object *obj) { EFM_SMART_CHECK(); _e_fm2_icon_sel_last(obj, EINA_FALSE); } E_API void e_fm2_custom_theme_set(Evas_Object *obj, const char *path) { EFM_SMART_CHECK(); eina_stringshare_replace(&sd->custom_theme, path); _e_fm2_theme_edje_object_set(sd, sd->drop, "base/theme/fileman", "list/drop_between"); _e_fm2_theme_edje_object_set(sd, sd->drop_in, "base/theme/fileman", "list/drop_in"); _e_fm2_theme_edje_object_set(sd, sd->overlay, "base/theme/fileman", "overlay"); _e_fm2_theme_edje_object_set(sd, sd->sel_rect, "base/theme/fileman", "rubberband"); } E_API void e_fm2_custom_theme_content_set(Evas_Object *obj, const char *content) { EFM_SMART_CHECK(); eina_stringshare_replace(&sd->custom_theme_content, content); _e_fm2_theme_edje_object_set(sd, sd->drop, "base/theme/fileman", "list/drop_between"); _e_fm2_theme_edje_object_set(sd, sd->drop_in, "base/theme/fileman", "list/drop_in"); _e_fm2_theme_edje_object_set(sd, sd->overlay, "base/theme/fileman", "overlay"); } E_API void e_fm2_path_get(Evas_Object *obj, const char **dev, const char **path) { if (dev) *dev = NULL; if (path) *path = NULL; EFM_SMART_CHECK(); if (dev) *dev = sd->dev; if (path) *path = sd->path; } static E_Fm2_Custom_File * _e_fm2_dir_load_props_from_parent(const char *path) { E_Fm2_Custom_File *cf; char *parent; if ((!path) || (path[0] == '\0') || (strcmp(path, "/") == 0)) return NULL; parent = ecore_file_dir_get(path); cf = e_fm2_custom_file_get(parent); if (((cf) && (cf->dir) && (cf->dir->prop.in_use)) || (!strcmp(parent, path))) { free(parent); return cf; } cf = _e_fm2_dir_load_props_from_parent(parent); free(parent); return cf; } static void _e_fm2_dir_load_props(E_Fm2_Smart_Data *sd) { E_Fm2_Custom_File *cf; if (!sd->realpath) return; /* come back later */ if (!(sd->view_flags & E_FM2_VIEW_LOAD_DIR_CUSTOM)) return; cf = e_fm2_custom_file_get(sd->realpath); if ((cf) && (cf->dir)) { Evas_Coord x, y; if (sd->max.w - sd->w > 0) x = (sd->max.w - sd->w) * cf->dir->pos.x; else x = 0; if (sd->max.h - sd->h > 0) y = (sd->max.h - sd->h) * cf->dir->pos.y; else y = 0; e_fm2_pan_set(sd->obj, x, y); if (cf->dir->prop.in_use) { sd->view_mode = cf->dir->prop.view_mode; sd->icon_size = cf->dir->prop.icon_size; sd->order_file = !!cf->dir->prop.order_file; sd->show_hidden_files = !!cf->dir->prop.show_hidden_files; sd->inherited_dir_props = EINA_FALSE; sd->config->list.sort.no_case = cf->dir->prop.sort.no_case; sd->config->list.sort.size = cf->dir->prop.sort.size; sd->config->list.sort.extension = cf->dir->prop.sort.extension; sd->config->list.sort.mtime = cf->dir->prop.sort.mtime; sd->config->list.sort.dirs.first = cf->dir->prop.sort.dirs.first; sd->config->list.sort.dirs.last = cf->dir->prop.sort.dirs.last; return; } } else { sd->pos.x = 0; sd->pos.y = 0; } if (!(sd->view_flags & E_FM2_VIEW_INHERIT_DIR_CUSTOM)) { sd->view_mode = -1; sd->icon_size = -1; sd->order_file = EINA_FALSE; sd->show_hidden_files = EINA_FALSE; sd->inherited_dir_props = EINA_FALSE; return; } sd->inherited_dir_props = EINA_TRUE; cf = _e_fm2_dir_load_props_from_parent(sd->realpath); if ((cf) && (cf->dir) && (cf->dir->prop.in_use)) { sd->view_mode = cf->dir->prop.view_mode; sd->icon_size = cf->dir->prop.icon_size; sd->order_file = !!cf->dir->prop.order_file; sd->show_hidden_files = !!cf->dir->prop.show_hidden_files; sd->config->list.sort.no_case = cf->dir->prop.sort.no_case; sd->config->list.sort.size = cf->dir->prop.sort.size; sd->config->list.sort.extension = cf->dir->prop.sort.extension; sd->config->list.sort.mtime = cf->dir->prop.sort.mtime; sd->config->list.sort.dirs.first = cf->dir->prop.sort.dirs.first; sd->config->list.sort.dirs.last = cf->dir->prop.sort.dirs.last; } else { sd->view_mode = -1; sd->icon_size = -1; sd->order_file = EINA_FALSE; sd->show_hidden_files = EINA_FALSE; } } static void _e_fm2_dir_save_props(E_Fm2_Smart_Data *sd) { E_Fm2_Custom_File *cf, cf0; E_Fm2_Custom_Dir dir0; if (!(sd->view_flags & E_FM2_VIEW_SAVE_DIR_CUSTOM)) return; cf = e_fm2_custom_file_get(sd->realpath); if (!cf) { cf = &cf0; memset(cf, 0, sizeof(*cf)); cf->dir = &dir0; } else if (!cf->dir) { E_Fm2_Custom_File *cf2 = cf; cf = &cf0; memcpy(cf, cf2, sizeof(*cf2)); cf->dir = &dir0; } if (sd->max.w - sd->w > 0) cf->dir->pos.x = sd->pos.x / (double)(sd->max.w - sd->w); else cf->dir->pos.x = 0.0; if (sd->max.h - sd->h) cf->dir->pos.y = sd->pos.y / (double)(sd->max.h - sd->h); else cf->dir->pos.y = 0.0; cf->dir->prop.icon_size = sd->icon_size; cf->dir->prop.view_mode = sd->view_mode; cf->dir->prop.order_file = sd->order_file; cf->dir->prop.show_hidden_files = sd->show_hidden_files; cf->dir->prop.in_use = !sd->inherited_dir_props; if (sd->config) { cf->dir->prop.sort.no_case = sd->config->list.sort.no_case; cf->dir->prop.sort.size = sd->config->list.sort.size; cf->dir->prop.sort.extension = sd->config->list.sort.extension; cf->dir->prop.sort.mtime = sd->config->list.sort.mtime; cf->dir->prop.sort.dirs.first = sd->config->list.sort.dirs.first; cf->dir->prop.sort.dirs.last = sd->config->list.sort.dirs.last; } e_fm2_custom_file_set(sd->realpath, cf); e_fm2_custom_file_flush(); } E_API void e_fm2_refresh(Evas_Object *obj) { EFM_SMART_CHECK(); evas_object_smart_callback_call(sd->obj, "changed", NULL); _e_fm2_dir_save_props(sd); _e_fm2_queue_free(obj); _e_fm2_regions_free(obj); _e_fm2_icons_free(obj); sd->order_file = EINA_FALSE; if (sd->realpath) { sd->listing = EINA_FALSE; _e_fm2_client_monitor_del(sd->id, sd->realpath); sd->id = _e_fm2_client_monitor_add(sd->realpath); sd->listing = EINA_TRUE; } sd->tmp.iter = EINA_FALSE; } E_API int e_fm2_has_parent_get(Evas_Object *obj) { EFM_SMART_CHECK(0); if (!sd->path) return 0; if (strcmp(sd->path, "/")) return 1; if (!sd->realpath) return 0; if ((sd->realpath[0] == 0) || (!strcmp(sd->realpath, "/"))) return 0; return 1; } E_API const char * e_fm2_real_path_get(Evas_Object *obj) { EFM_SMART_CHECK(NULL); return sd->realpath; } E_API void e_fm2_parent_go(Evas_Object *obj) { char *p, *path; char buf[PATH_MAX]; EFM_SMART_CHECK(); if (!sd->path) return; path = memcpy(buf, sd->path, strlen(sd->path) + 1); if ((p = strrchr(path, '/'))) *p = 0; if (*path) e_fm2_path_set(obj, sd->dev, path); else if (sd->realpath) { path = ecore_file_dir_get(sd->realpath); e_fm2_path_set(obj, "/", path); free(path); } } E_API void e_fm2_config_set(Evas_Object *obj, E_Fm2_Config *cfg) { EFM_SMART_CHECK(); if (sd->config == cfg) return; if (sd->config) _e_fm2_config_free(sd->config); sd->config = NULL; if (!cfg) return; sd->config = E_NEW(E_Fm2_Config, 1); if (!sd->config) return; memcpy(sd->config, cfg, sizeof(E_Fm2_Config)); sd->config->icon.key_hint = eina_stringshare_add(cfg->icon.key_hint); sd->config->theme.background = eina_stringshare_add(cfg->theme.background); sd->config->theme.frame = eina_stringshare_add(cfg->theme.frame); sd->config->theme.icons = eina_stringshare_add(cfg->theme.icons); } E_API E_Fm2_Config * e_fm2_config_get(Evas_Object *obj) { EFM_SMART_CHECK(NULL); return sd->config; } E_API Eina_List * e_fm2_selected_list_get(Evas_Object *obj) { Eina_List *list = NULL, *l; E_Fm2_Icon *ic; EFM_SMART_CHECK(NULL); EINA_LIST_FOREACH(sd->selected_icons, l, ic) list = eina_list_append(list, &(ic->info)); return list; } E_API Eina_List * e_fm2_all_list_get(Evas_Object *obj) { Eina_List *list = NULL, *l; E_Fm2_Icon *ic; EFM_SMART_CHECK(NULL); EINA_LIST_FOREACH(sd->icons, l, ic) { list = eina_list_append(list, &(ic->info)); } return list; } E_API E_Fm2_Icon_Info * e_fm2_icon_file_get(Evas_Object *obj, const char *file) { Eina_List *l; E_Fm2_Icon *ic; EFM_SMART_CHECK(NULL); if (!file) return NULL; EINA_LIST_FOREACH(sd->icons, l, ic) { if ((ic->info.file) && (!strcmp(ic->info.file, file))) return &(ic->info); } return NULL; } E_API void e_fm2_deselect_all(Evas_Object *obj) { EFM_SMART_CHECK(); _e_fm2_icon_desel_any(obj); } E_API void e_fm2_select_set(Evas_Object *obj, const char *file, int select_) { Eina_List *l; E_Fm2_Icon *ic; EFM_SMART_CHECK(); EINA_LIST_FOREACH(sd->icons, l, ic) { if ((file) && (!strcmp(ic->info.file, file))) { if (select_) _e_fm2_icon_select(ic); else _e_fm2_icon_deselect(ic); } else { if (ic->sd->config->selection.single) _e_fm2_icon_deselect(ic); ic->last_selected = EINA_FALSE; } } } E_API void e_fm2_file_show(Evas_Object *obj, const char *file) { Eina_List *l; E_Fm2_Icon *ic; EFM_SMART_CHECK(); EINA_LIST_FOREACH(sd->icons, l, ic) { if (!strcmp(ic->info.file, file)) { _e_fm2_icon_make_visible(ic); return; } } } E_API void e_fm2_icon_menu_replace_callback_set(Evas_Object *obj, E_Fm_Cb func, void *data) { EFM_SMART_CHECK(); sd->icon_menu.replace.func = func; sd->icon_menu.replace.data = data; } E_API void e_fm2_icon_menu_start_extend_callback_set(Evas_Object *obj, E_Fm_Cb func, void *data) { EFM_SMART_CHECK(); sd->icon_menu.start.func = func; sd->icon_menu.start.data = data; } E_API void e_fm2_icon_menu_end_extend_callback_set(Evas_Object *obj, E_Fm_Cb func, void *data) { EFM_SMART_CHECK(); sd->icon_menu.end.func = func; sd->icon_menu.end.data = data; } E_API void e_fm2_icon_menu_flags_set(Evas_Object *obj, E_Fm2_Menu_Flags flags) { EFM_SMART_CHECK(); sd->icon_menu.flags = flags; } E_API E_Fm2_Menu_Flags e_fm2_icon_menu_flags_get(Evas_Object *obj) { EFM_SMART_CHECK(0); return sd->icon_menu.flags; } E_API void e_fm2_view_flags_set(Evas_Object *obj, E_Fm2_View_Flags flags) { EFM_SMART_CHECK(); sd->view_flags = flags; } E_API E_Fm2_View_Flags e_fm2_view_flags_get(Evas_Object *obj) { EFM_SMART_CHECK(0); return sd->view_flags; } E_API E_Object * e_fm2_window_object_get(Evas_Object *obj) { EFM_SMART_CHECK(NULL); return sd->eobj; } E_API void e_fm2_window_object_set(Evas_Object *obj, E_Object *eobj) { const char *drop[] = {"text/uri-list", "text/x-moz-url", "XdndDirectSave0"}; EFM_SMART_CHECK(); sd->eobj = eobj; sd->win = NULL; if (sd->drop_handler) e_drop_handler_del(sd->drop_handler); sd->drop_handler = e_drop_handler_add(sd->eobj, NULL, sd, _e_fm2_cb_dnd_enter, _e_fm2_cb_dnd_move, _e_fm2_cb_dnd_leave, _e_fm2_cb_dnd_selection_notify, drop, 3, sd->x, sd->y, sd->w, sd->h); e_drop_handler_responsive_set(sd->drop_handler); e_drop_handler_xds_set(sd->drop_handler, _e_fm2_cb_dnd_drop); } E_API void e_fm2_window_set(Evas_Object *obj, Evas_Object *win) { const char *drop[] = {"text/uri-list", "text/x-moz-url", "XdndDirectSave0"}; EFM_SMART_CHECK(); sd->win = win; sd->eobj = NULL; if (sd->drop_handler) e_drop_handler_del(sd->drop_handler); sd->drop_handler = e_drop_handler_add(NULL, win, sd, _e_fm2_cb_dnd_enter, _e_fm2_cb_dnd_move, _e_fm2_cb_dnd_leave, _e_fm2_cb_dnd_selection_notify, drop, 3, sd->x, sd->y, sd->w, sd->h); e_drop_handler_responsive_set(sd->drop_handler); e_drop_handler_xds_set(sd->drop_handler, _e_fm2_cb_dnd_drop); } static void _e_fm2_icons_update_helper(E_Fm2_Smart_Data *sd, Eina_Bool icon_only) { Eina_List *l; E_Fm2_Icon *ic; char buf[PATH_MAX], *pfile; int bufused, buffree; if ((!sd->realpath) || (!sd->icons)) return; bufused = eina_strlcpy(buf, sd->realpath, sizeof(buf)); if (bufused >= (int)(sizeof(buf) - 2)) return; if ((bufused > 0) && (buf[bufused - 1] != '/')) { buf[bufused] = '/'; bufused++; } pfile = buf + bufused; buffree = sizeof(buf) - bufused; EINA_LIST_FOREACH(sd->icons, l, ic) { E_Fm2_Custom_File *cf; eina_stringshare_del(ic->info.icon); ic->info.icon = NULL; ic->info.icon_type = EINA_FALSE; if (_e_fm2_file_is_desktop(ic->info.file)) _e_fm2_icon_desktop_load(ic); if ((int)eina_strlcpy(pfile, ic->info.file, buffree) >= buffree) continue; cf = e_fm2_custom_file_get(buf); if (cf) { if (cf->icon.valid) { eina_stringshare_replace(&ic->info.icon, cf->icon.icon); ic->info.icon_type = cf->icon.type; } } if (!ic->realized) continue; if (icon_only) { E_FREE_FUNC(ic->obj_icon, evas_object_del); _e_fm2_icon_icon_set(ic); } else { _e_fm2_icon_unrealize(ic); _e_fm2_icon_realize(ic); } } e_fm2_custom_file_flush(); } E_API void e_fm2_icons_update(Evas_Object *obj) { EFM_SMART_CHECK(); _e_fm2_icons_update_helper(sd, EINA_FALSE); } E_API void e_fm2_pan_set(Evas_Object *obj, Evas_Coord x, Evas_Coord y) { EFM_SMART_CHECK(); x = MIN(x, sd->max.w - sd->w); if (x < 0) x = 0; y = MIN(y, sd->max.h - sd->h); if (y < 0) y = 0; if ((sd->pos.x == x) && (sd->pos.y == y)) return; sd->pos.x = x; sd->pos.y = y; if (sd->scroll_job) ecore_job_del(sd->scroll_job); sd->scroll_job = ecore_job_add(_e_fm2_cb_scroll_job, obj); } E_API void e_fm2_pan_get(Evas_Object *obj, Evas_Coord *x, Evas_Coord *y) { EFM_SMART_CHECK(); if (x) *x = sd->pos.x; if (y) *y = sd->pos.y; } E_API void e_fm2_pan_max_get(Evas_Object *obj, Evas_Coord *x, Evas_Coord *y) { Evas_Coord mx, my; EFM_SMART_CHECK(); mx = sd->max.w - sd->w; if (mx < 0) mx = 0; my = sd->max.h - sd->h; if (my < 0) my = 0; if (x) *x = mx; if (y) *y = my; } E_API void e_fm2_pan_child_size_get(Evas_Object *obj, Evas_Coord *w, Evas_Coord *h) { EFM_SMART_CHECK(); if (w) *w = sd->max.w; if (h) *h = sd->max.h; } E_API void e_fm2_all_icons_update(void) { Evas_Object *o; const Eina_List *l; _e_fm2_list_walking++; EINA_LIST_FOREACH(_e_fm2_list, l, o) { if ((_e_fm2_list_walking > 0) && (eina_list_data_find(_e_fm2_list_remove, o))) continue; e_fm2_icons_update(o); } _e_fm2_list_walking--; if (_e_fm2_list_walking == 0) { EINA_LIST_FREE(_e_fm2_list_remove, o) { _e_fm2_list = eina_list_remove(_e_fm2_list, o); } } } static const char * _e_fm2_path_join(char *buf, int buflen, const char *base, const char *component) { if ((!buf) || (!component)) return NULL; if (component[0] == '/') return component; else if (component[0] == '\0') return base; else if (component[0] == '.') { if (component[1] == '/') { component += 2; if (!base) return component; if (snprintf(buf, buflen, "%s/%s", base, component) < buflen) return buf; else return NULL; } else if ((component[1] == '.') && (component[2] == '/')) { const char *p; int len; component += 3; if (!base) return component; p = strrchr(base, '/'); if (!p) return component; len = p - base; if (snprintf(buf, buflen, "%.*s/%s", len, base, component) < buflen) return buf; else return NULL; } } if (snprintf(buf, buflen, "%s/%s", base, component) < buflen) return buf; else return NULL; } /** * Explicitly set an Edje icon from the given icon path. * * @param iconpath path to edje file that contains 'icon' group. * * @see _e_fm2_icon_explicit_get() */ static Evas_Object * _e_fm2_icon_explicit_edje_get(Evas *evas, const E_Fm2_Icon *ic EINA_UNUSED, const char *iconpath, const char **type_ret) { Evas_Object *o = edje_object_add(evas); if (!o) return NULL; if (!edje_object_file_set(o, iconpath, "icon")) { evas_object_del(o); return NULL; } if (type_ret) *type_ret = "CUSTOM"; return o; } /** * Explicitly set icon from theme using its name. * * @param name will be prefixed by 'e/icons/' to form the group name in theme. * * @see e_util_edje_icon_set() * @see _e_fm2_icon_explicit_get() */ static Evas_Object * _e_fm2_icon_explicit_theme_icon_get(Evas *evas, const E_Fm2_Icon *ic EINA_UNUSED, const char *name, const char **type_ret) { Evas_Object *o = e_icon_add(evas); if (!o) return NULL; e_icon_scale_size_set(o, _e_fm2_icon_mime_size_normalize(ic)); if (!e_util_icon_theme_set(o, name)) { evas_object_del(o); return NULL; } if (type_ret) *type_ret = "THEME_ICON"; return o; } /** * Explicitly set icon from file manager theem using its name. * * @param name will be prefixed with 'base/theme/fileman' to form the * group name in theme. * * @see _e_fm2_theme_edje_icon_object_set() * @see _e_fm2_icon_explicit_get() */ static Evas_Object * _e_fm2_icon_explicit_theme_get(Evas *evas, const E_Fm2_Icon *ic, const char *name, const char **type_ret) { Evas_Object *o = edje_object_add(evas); if (!o) return NULL; if (!_e_fm2_theme_edje_icon_object_set(ic->sd, o, "base/theme/fileman", name)) { evas_object_del(o); return NULL; } if (type_ret) *type_ret = "THEME"; return o; } /** * Explicitly set icon to given value. * * This will try to identify if icon is an edje or regular file or even * an icon name to get from icon set. * * @param icon might be an absolute or relative path, or icon name or edje path. */ static Evas_Object * _e_fm2_icon_explicit_get(Evas *evas, const E_Fm2_Icon *ic, const char *icon, const char **type_ret) { char buf[PATH_MAX]; const char *iconpath; iconpath = _e_fm2_path_join(buf, sizeof(buf), ic->sd->realpath, icon); if (!iconpath) { ERR("could not create icon \"%s\".", icon); return NULL; } if (_e_fm2_file_is_edje(iconpath)) return _e_fm2_icon_explicit_edje_get(evas, ic, iconpath, type_ret); else { Evas_Object *o = e_icon_add(evas); if (!o) return NULL; e_icon_scale_size_set(o, _e_fm2_icon_mime_size_normalize(ic)); e_icon_file_set(o, iconpath); e_icon_fill_inside_set(o, 1); if (type_ret) *type_ret = "CUSTOM"; return o; } return NULL; } /** * Creates an icon that generates a thumbnail if required. * * @param group if given, will be used in e_thumb_icon_file_set() * @param cb function to callback when thumbnail generation is over. * @param data extra data to give to @p cb * @param force_gen whenever to force generation of thumbnails, even it exists. */ static Evas_Object * _e_fm2_icon_thumb_get(Evas *evas, const E_Fm2_Icon *ic, const char *group, Evas_Smart_Cb cb, void *data, int force_gen, const char **type_ret) { Evas_Object *o; char buf[PATH_MAX]; if (ic->thumb_failed) return NULL; if (!_e_fm2_icon_realpath(ic, buf, sizeof(buf))) return NULL; o = e_thumb_icon_add(evas); if (!o) return NULL; if (cb) evas_object_smart_callback_add(o, "e_thumb_gen", cb, data); e_thumb_icon_size_set(o, 256, 256); e_thumb_icon_file_set(o, buf, group); _e_fm2_icon_thumb(ic, o, force_gen); if (type_ret) *type_ret = "THUMB"; return o; } /** * Generates the thumbnail of the given edje file. * * It will use 'icon.key_hint' from config if set and then try some well * known groups like 'icon', 'e/desktop/background' and 'e/init/splash'. */ static Evas_Object * _e_fm2_icon_thumb_edje_get(Evas *evas, const E_Fm2_Icon *ic, Evas_Smart_Cb cb, void *data, int force_gen, const char **type_ret) { char buf[PATH_MAX]; const char **itr = NULL, *group = NULL; const char *known_groups[] = { NULL, "e/desktop/background", "icon", "e/init/splash", /* XXX TODO: add more? example 'screenshot', 'preview' */ NULL }; Evas_Object *o; if (!_e_fm2_icon_realpath(ic, buf, sizeof(buf))) return NULL; known_groups[0] = ic->sd->config->icon.key_hint; if (known_groups[0]) itr = known_groups; else itr = known_groups + 1; for (; *itr; itr++) { if (edje_file_group_exists(buf, *itr)) break; } if (*itr) group = eina_stringshare_add(*itr); else { Eina_List *l; l = edje_file_collection_list(buf); group = eina_stringshare_ref(eina_list_data_get(l)); edje_file_collection_list_free(l); } if (!group) return NULL; o = _e_fm2_icon_thumb_get(evas, ic, group, cb, data, force_gen, type_ret); eina_stringshare_del(group); return o; } static Eina_Bool _e_fm2_icon_cache_update(void *data, int type EINA_UNUSED, void *event EINA_UNUSED) { _e_fm2_icons_update_helper(data, EINA_TRUE); return ECORE_CALLBACK_RENEW; } /** * Machinery for _e_fm2_icon_desktop_get() and others with instances of desktop. */ static Evas_Object * _e_fm2_icon_desktop_get_internal(Evas *evas, const E_Fm2_Icon *ic, Efreet_Desktop *desktop, const char **type_ret) { Evas_Object *o; if (!desktop->icon) return NULL; if (_e_fm2_file_is_edje(desktop->icon)) return _e_fm2_icon_explicit_edje_get(evas, ic, desktop->icon, type_ret); o = _e_fm2_icon_explicit_theme_icon_get(evas, ic, desktop->icon, type_ret); if (o) return o; o = e_util_desktop_icon_add(desktop, 48, evas); // o = e_util_icon_theme_icon_add(desktop->icon, 48, evas); if (o && type_ret) *type_ret = "DESKTOP"; return o; } /** * Use freedesktop.org '.desktop' files to set icon. */ static Evas_Object * _e_fm2_icon_desktop_get(Evas *evas, const E_Fm2_Icon *ic, const char **type_ret) { Efreet_Desktop *ef; Evas_Object *o; char buf[PATH_MAX]; if (!ic->info.file) return NULL; if (!_e_fm2_icon_realpath(ic, buf, sizeof(buf))) return NULL; ef = efreet_desktop_new(buf); if (!ef) return NULL; o = _e_fm2_icon_desktop_get_internal(evas, ic, ef, type_ret); efreet_desktop_free(ef); return o; } static inline const char * _e_fm2_icon_mime_type_special_match(const E_Fm2_Icon *ic) { const Eina_List *l; const E_Config_Mime_Icon *mi; const char *mime = ic->info.mime; EINA_LIST_FOREACH(e_config->mime_icons, l, mi) if (mi->mime == mime) /* both in the same stringshare pool */ return mi->icon; return NULL; } static Evas_Object * _e_fm2_icon_mime_fdo_get(Evas *evas, const E_Fm2_Icon *ic, const char **type_ret) { const char *icon; unsigned int size; size = _e_fm2_icon_mime_size_normalize(ic); icon = efreet_mime_type_icon_get(ic->info.mime, e_config->icon_theme, size); if (icon) return _e_fm2_icon_explicit_get(evas, ic, icon, type_ret); return NULL; } static Evas_Object * _e_fm2_icon_mime_theme_get(Evas *evas, const E_Fm2_Icon *ic, const char **type_ret EINA_UNUSED) { char buf[1024]; const char *file; if (snprintf(buf, sizeof(buf), "e/icons/fileman/mime/%s", ic->info.mime) >= (int)sizeof(buf)) return NULL; file = e_theme_edje_file_get("base/theme/icons", buf); if (file && file[0]) { Evas_Object *o = edje_object_add(evas); if (!o) return NULL; if (!edje_object_file_set(o, file, buf)) { evas_object_del(o); return NULL; } return o; } return NULL; } /** * Use mime type information to set icon. */ static Evas_Object * _e_fm2_icon_mime_get(Evas *evas, const E_Fm2_Icon *ic, Evas_Smart_Cb gen_func EINA_UNUSED, void *data EINA_UNUSED, int force_gen EINA_UNUSED, const char **type_ret) { Evas_Object *o = NULL; if (e_config->icon_theme_overrides) o = _e_fm2_icon_mime_fdo_get(evas, ic, type_ret); else o = _e_fm2_icon_mime_theme_get(evas, ic, type_ret); if (o) return o; if (!e_config->icon_theme_overrides) o = _e_fm2_icon_mime_fdo_get(evas, ic, type_ret); else o = _e_fm2_icon_mime_theme_get(evas, ic, type_ret); return o; } /** * Discovers the executable of Input Method Config file and set icon. */ static Evas_Object * _e_fm2_icon_imc_get(Evas *evas, const E_Fm2_Icon *ic, const char **type_ret) { E_Input_Method_Config *imc; Efreet_Desktop *desktop; Eet_File *imc_ef; Evas_Object *o = NULL; char buf[PATH_MAX]; if (!ic->info.file) return NULL; if (!_e_fm2_icon_realpath(ic, buf, sizeof(buf))) return NULL; imc_ef = eet_open(buf, EET_FILE_MODE_READ); if (!imc_ef) return NULL; imc = e_intl_input_method_config_read(imc_ef); eet_close(imc_ef); if (!imc->e_im_setup_exec) { e_intl_input_method_config_free(imc); return NULL; } desktop = efreet_util_desktop_exec_find(imc->e_im_setup_exec); if (desktop) { o = _e_fm2_icon_desktop_get_internal(evas, ic, desktop, type_ret); efreet_desktop_free(desktop); } e_intl_input_method_config_free(imc); if ((o) && (type_ret)) *type_ret = "IMC"; return o; } /** * Use heuristics to discover and set icon. */ static Evas_Object * _e_fm2_icon_discover_get(Evas *evas, const E_Fm2_Icon *ic, Evas_Smart_Cb gen_func, void *data, int force_gen, const char **type_ret) { const char *p; p = strrchr(ic->info.file, '.'); if (!p) return NULL; p++; if (_e_fm2_ext_is_edje(p)) return _e_fm2_icon_thumb_edje_get(evas, ic, gen_func, data, force_gen, type_ret); if (_e_fm2_ext_is_desktop(p)) return _e_fm2_icon_desktop_get(evas, ic, type_ret); if (_e_fm2_ext_is_imc(p)) return _e_fm2_icon_imc_get(evas, ic, type_ret); if (evas_object_image_extension_can_load_get(p - 1)) return _e_fm2_icon_thumb_get(evas, ic, NULL, gen_func, data, force_gen, type_ret); return NULL; } /** * Get the object representing the icon. * * @param evas canvas instance to use to store the icon. * @param ic icon to get information in order to find the icon. * @param gen_func if thumbnails need to be generated, call this function * when it's over. * @param data extra data to give to @p gen_func. * @param force_gen force thumbnail generation. * @param type_ret string that identifies type of icon. */ E_API Evas_Object * e_fm2_icon_get(Evas *evas, E_Fm2_Icon *ic, Evas_Smart_Cb gen_func, void *data, int force_gen, const char **type_ret) { const char *icon; Evas_Object *o = NULL; if (ic->info.icon) { if ((ic->info.icon[0] == '/') || ((ic->info.icon[0] == '.') && ((ic->info.icon[1] == '/') || ((ic->info.icon[1] == '.') && (ic->info.icon[2] == '/'))))) { o = _e_fm2_icon_explicit_get(evas, ic, ic->info.icon, type_ret); if (o) return o; } o = _e_fm2_icon_explicit_theme_icon_get(evas, ic, ic->info.icon, type_ret); if (o) return o; } if (ic->sd->config->icon.max_thumb_size && (ic->info.statinfo.st_size > ic->sd->config->icon.max_thumb_size * 1024 * 1024)) ic->thumb_failed = EINA_TRUE; /* create thumbnails for edje files */ if ((ic->info.file) && (_e_fm2_file_is_edje(ic->info.file))) { o = _e_fm2_icon_thumb_edje_get (evas, ic, gen_func, data, force_gen, type_ret); if (o) return o; } /* disabled until everyone has edje in mime.types: * use mimetype to identify edje. * if (ic->info.mime == _e_fm2_mime_app_edje) * return _e_fm2_icon_thumb_edje_get * (evas, ic, gen_func, data, force_gen, type_ret); */ /* check user preferences */ icon = _e_fm2_icon_mime_type_special_match(ic); if (icon) { if (icon == _e_fm2_icon_desktop_str) o = _e_fm2_icon_desktop_get(evas, ic, type_ret); else if (icon == _e_fm2_icon_thumb_str) { if (!ic->thumb_failed) o = _e_fm2_icon_thumb_get (evas, ic, NULL, gen_func, data, force_gen, type_ret); } else if (strncmp(icon, "e/icons/fileman/", 16) == 0) o = _e_fm2_icon_explicit_theme_get(evas, ic, icon + 16, type_ret); else o = _e_fm2_icon_explicit_get(evas, ic, icon, type_ret); if (o) return o; } if ((!ic->thumb_failed) && (ic->info.icon_type == 1)) { o = _e_fm2_icon_thumb_get(evas, ic, NULL, gen_func, data, force_gen, type_ret); if (o) return o; } if (ic->info.file) { o = _e_fm2_icon_discover_get(evas, ic, gen_func, data, force_gen, type_ret); if (o) return o; } if (ic->info.mime) { o = _e_fm2_icon_mime_get(evas, ic, gen_func, data, force_gen, type_ret); if (o) return o; } //fallback: o = _e_fm2_icon_explicit_theme_icon_get(evas, ic, "unknown", type_ret); if (o) return o; return _e_fm2_icon_explicit_theme_get(evas, ic, "text/plain", type_ret); } E_API E_Fm2_Icon_Info * e_fm2_icon_file_info_get(E_Fm2_Icon *ic) { if (!ic) return NULL; return &(ic->info); } E_API void e_fm2_icon_geometry_get(E_Fm2_Icon *ic, int *x, int *y, int *w, int *h) { int xx, yy, ww, hh; if (x) *x = 0; if (y) *y = 0; if (w) *w = 0; if (h) *h = 0; if (ic) { evas_object_geometry_get(ic->obj, &xx, &yy, &ww, &hh); if (x) *x = xx; if (y) *y = yy; if (w) *w = ww; if (h) *h = hh; } } /* FIXME: track real exe with exe del events etc. */ static int _e_fm2_client_spawning = 0; static void _e_fm2_client_spawn(void) { char buf[4096]; if (_e_fm2_client_spawning) return; if (e_sys_on_the_way_out_get()) return; snprintf(buf, sizeof(buf), "%s/enlightenment/utils/enlightenment_fm", e_prefix_lib_get()); if (_e_fm2_exe) e_fm2_die(); _e_fm2_exe = ecore_exe_pipe_run(buf, ECORE_EXE_NOT_LEADER | ECORE_EXE_TERM_WITH_PARENT, NULL); _e_fm2_client_spawning = 1; } static E_Fm2_Client * _e_fm2_client_get(void) { Eina_List *l; E_Fm2_Client *cl, *cl_chosen = NULL; int min_req = 0x7fffffff; /* if we don't have a slave - spawn one */ if (!_e_fm2_client_list) { _e_fm2_client_spawn(); return NULL; } EINA_LIST_FOREACH(_e_fm2_client_list, l, cl) { if (cl->req < min_req) { min_req = cl->req; cl_chosen = cl; } } return cl_chosen; } typedef struct _E_Fm2_Message E_Fm2_Message; struct _E_Fm2_Message { int major, minor, ref, ref_to, response; void *data; int size; }; static Eina_List *_e_fm2_messages = NULL; static void _e_fm2_client_message_queue(int major, int minor, int ref, int ref_to, int response, const void *data, int size) { E_Fm2_Message *msg; msg = E_NEW(E_Fm2_Message, 1); if (!msg) return; msg->major = major; msg->minor = minor; msg->ref = ref; msg->ref_to = ref_to; msg->response = response; if (data) { msg->size = size; msg->data = malloc(size); if (msg->data) memcpy(msg->data, data, size); else { free(msg); return; } } _e_fm2_messages = eina_list_append(_e_fm2_messages, msg); } static void _e_fm2_client_message_flush(E_Fm2_Client *cl, E_Fm2_Message *msg) { _e_fm2_messages = eina_list_remove(_e_fm2_messages, msg); ecore_ipc_client_send(cl->cl, msg->major, msg->minor, msg->ref, msg->ref_to, msg->response, msg->data, msg->size); cl->req++; free(msg->data); free(msg); } static void _e_fm2_client_messages_flush(void) { while (_e_fm2_messages) { E_Fm2_Client *cl; cl = _e_fm2_client_get(); if (!cl) break; _e_fm2_client_message_flush(cl, eina_list_data_get(_e_fm2_messages)); } } static int _e_fm_client_send_new(int minor, void *data, int size) { static int id = 0; E_Fm2_Client *cl; id++; cl = _e_fm2_client_get(); if (!cl) { _e_fm2_client_message_queue(E_IPC_DOMAIN_FM, minor, id, 0, 0, data, size); } else { ecore_ipc_client_send(cl->cl, E_IPC_DOMAIN_FM, minor, id, 0, 0, data, size); cl->req++; } return id; } static int _e_fm_client_send(int minor, int id, void *data, int size) { E_Fm2_Client *cl; cl = _e_fm2_client_get(); if (!cl) { _e_fm2_client_message_queue(E_IPC_DOMAIN_FM, minor, id, 0, 0, data, size); } else { ecore_ipc_client_send(cl->cl, E_IPC_DOMAIN_FM, minor, id, 0, 0, data, size); cl->req++; } return id; } static int _e_fm2_client_monitor_add(const char *path) { return _e_fm_client_send_new(E_FM_OP_MONITOR_START, (void *)path, strlen(path) + 1); } static void _e_fm2_client_monitor_del(int id, const char *path) { _e_fm_client_send(E_FM_OP_MONITOR_END, id, (void *)path, strlen(path) + 1); } static int _e_fm_client_file_del(const char *files, Eina_Bool secure, Evas_Object *e_fm) { int id, op = E_FM_OP_REMOVE; if (secure) op = E_FM_OP_SECURE_REMOVE; id = _e_fm_client_send_new(op, (void *)files, strlen(files) + 1); e_fm2_op_registry_entry_add(id, e_fm, op, _e_fm2_operation_abort_internal); return id; } #if 0 static int _e_fm2_client_file_trash(const char *path, Evas_Object *e_fm) { int id = _e_fm_client_send_new(E_FM_OP_TRASH, (void *)path, strlen(path) + 1); e_fm2_op_registry_entry_add(id, e_fm, E_FM_OP_TRASH, _e_fm2_operation_abort_internal); return id; } static int _e_fm2_client_file_mkdir(const char *path, const char *rel, int rel_to, int x, int y, int res_w EINA_UNUSED, int res_h EINA_UNUSED, Evas_Object *e_fm) { char *d; int l1, l2, l, id; l1 = strlen(path); l2 = strlen(rel); l = l1 + 1 + l2 + 1 + (sizeof(int) * 3); d = alloca(l); strcpy(d, path); strcpy(d + l1 + 1, rel); memcpy(d + l1 + 1 + l2 + 1, &rel_to, sizeof(int)); memcpy(d + l1 + 1 + l2 + 1 + sizeof(int), &x, sizeof(int)); memcpy(d + l1 + 1 + l2 + 1 + (2 * sizeof(int)), &y, sizeof(int)); id = _e_fm_client_send_new(E_FM_OP_MKDIR, (void *)d, l); e_fm2_op_registry_entry_add(id, e_fm, E_FM_OP_MKDIR, _e_fm2_operation_abort_internal); return id; } #endif E_API int e_fm2_client_file_move(Evas_Object *e_fm, const char *args) { int id; E_Fm_Op_Type op = e_config->filemanager_copy ? E_FM_OP_MOVE : E_FM_OP_RENAME; id = _e_fm_client_send_new(op, (void *)args, strlen(args) + 1); e_fm2_op_registry_entry_add(id, e_fm, op, _e_fm2_operation_abort_internal); return id; } E_API int e_fm2_client_file_copy(Evas_Object *e_fm, const char *args) { int id = _e_fm_client_send_new(E_FM_OP_COPY, (void *)args, strlen(args) + 1); e_fm2_op_registry_entry_add(id, e_fm, E_FM_OP_COPY, _e_fm2_operation_abort_internal); return id; } E_API int e_fm2_client_file_symlink(Evas_Object *e_fm, const char *args) { int id = _e_fm_client_send_new(E_FM_OP_SYMLINK, (void *)args, strlen(args) + 1); e_fm2_op_registry_entry_add(id, e_fm, E_FM_OP_SYMLINK, _e_fm2_operation_abort_internal); return id; } E_API int _e_fm2_client_mount(const char *udi, const char *mountpoint) { char *d; int l, l1, l2 = 0; if (!udi) return 0; l1 = strlen(udi); if (mountpoint) { l2 = strlen(mountpoint); l = l1 + 1 + l2 + 1; } else l = l1 + 1; d = alloca(l); strcpy(d, udi); if (mountpoint) strcpy(d + l1 + 1, mountpoint); return _e_fm_client_send_new(E_FM_OP_MOUNT, (void *)d, l); } E_API int _e_fm2_client_unmount(const char *udi) { char *d; int l, l1; if (!udi) return 0; l1 = strlen(udi); l = l1 + 1; d = alloca(l); strcpy(d, udi); _e_fm2_client_get(); elm_cache_all_flush(); edje_file_cache_flush(); edje_collection_cache_flush(); if (e_comp) { evas_image_cache_flush(e_comp->evas); evas_font_cache_flush(e_comp->evas); } return _e_fm_client_send_new(E_FM_OP_UNMOUNT, (void *)d, l); } E_API int _e_fm2_client_eject(const char *udi) { char *data; int size; if (!udi) return 0; size = strlen(udi) + 1; data = alloca(size); strcpy(data, udi); fprintf(stderr, "EJECT [%s]\n", udi); // udi == /dev/sdd1 :) return _e_fm_client_send_new(E_FM_OP_EJECT, data, size); } static void _e_fm2_client_monitor_list_end(Evas_Object *obj) { E_Fm2_Smart_Data *sd; sd = evas_object_smart_data_get(obj); sd->busy_count--; if (sd->busy_count == 0) { edje_object_signal_emit(sd->overlay, "e,state,busy,stop", "e"); e_fm2_custom_file_flush(); } if (sd->tmp.obj) { evas_object_del(sd->tmp.obj); sd->tmp.obj = NULL; } if (sd->tmp.obj2) { evas_object_del(sd->tmp.obj2); sd->tmp.obj2 = NULL; } if (sd->scan_timer) { ecore_timer_del(sd->scan_timer); sd->scan_timer = NULL; } if (sd->sort_idler) { ecore_idler_del(sd->sort_idler); sd->sort_idler = NULL; } E_FREE(sd->tmp.list_index); _e_fm2_queue_free(obj); _e_fm2_obj_icons_place(sd); _e_fm2_live_process_begin(obj); } E_API void _e_fm2_file_force_update(const char *path) { Evas_Object *o; char *dir; Eina_List *l; dir = ecore_file_dir_get(path); if (!dir) return; EINA_LIST_FOREACH(_e_fm2_list, l, o) { const char *rp; if ((_e_fm2_list_walking > 0) && (eina_list_data_find(_e_fm2_list_remove, o))) continue; rp = e_fm2_real_path_get(o); if (!rp) continue; if (!strcmp(rp, dir)) { E_Fm2_Icon *ic; ic = _e_fm2_icon_find(o, ecore_file_file_get(path)); if (ic) { E_Fm2_Finfo finf; memset(&finf, 0, sizeof(E_Fm2_Finfo)); memcpy(&(finf.st), &(ic->info.statinfo), sizeof(struct stat)); finf.broken_link = ic->info.broken_link; finf.lnk = ic->info.link; finf.rlnk = ic->info.real_link; ic->removable_state_change = EINA_TRUE; _e_fm2_live_file_changed(o, ecore_file_file_get(path), &finf); } } } free(dir); } E_API void e_fm2_client_data(Ecore_Ipc_Event_Client_Data *e) { Evas_Object *obj; Eina_List *l, *dels = NULL; E_Fm2_Client *cl; if (e->major != 6 /*E_IPC_DOMAIN_FM*/) return; EINA_LIST_FOREACH(_e_fm2_client_list, l, cl) { if (cl->cl == e->client) break; } if (!l) { cl = E_NEW(E_Fm2_Client, 1); cl->cl = e->client; _e_fm2_client_list = eina_list_prepend(_e_fm2_client_list, cl); /* FIXME: new client - send queued msgs */ _e_fm2_client_spawning = 0; _e_fm2_client_messages_flush(); } _e_fm2_list_walking++; EINA_LIST_FOREACH(_e_fm2_list, l, obj) { unsigned char *p; char *evdir; const char *dir, *path, *lnk, *rlnk, *file; struct stat st; int broken_link; E_Fm2_Smart_Data *sd; if ((_e_fm2_list_walking > 0) && (eina_list_data_find(_e_fm2_list_remove, obj))) continue; dir = e_fm2_real_path_get(obj); sd = evas_object_smart_data_get(obj); switch (e->minor) { case E_FM_OP_HELLO: /*hello*/ // printf("E_FM_OP_HELLO\n"); break; case E_FM_OP_OK: /*req ok*/ // printf("E_FM_OP_OK\n"); cl->req--; break; case E_FM_OP_FILE_ADD: /*file add*/ // printf("E_FM_OP_FILE_ADD\n"); case E_FM_OP_FILE_CHANGE: /*file change*/ // printf("E_FM_OP_FILE_CHANGE\n"); { E_Fm2_Finfo finf; p = e->data; /* NOTE: i am NOT converting this data to portable arch/os independent * format. i am ASSUMING e_fm_main and e are local and built together * and thus this will work. if this ever changes this here needs to * change */ memcpy(&st, p, sizeof(struct stat)); p += sizeof(struct stat); broken_link = p[0]; p += 1; path = (char *)p; p += strlen(path) + 1; lnk = (char *)p; p += strlen(lnk) + 1; rlnk = (char *)p; memcpy(&(finf.st), &st, sizeof(struct stat)); finf.broken_link = broken_link; finf.lnk = lnk; finf.rlnk = rlnk; evdir = ecore_file_dir_get(path); if ((evdir) && (sd->id == e->ref_to) && ((!strcmp(evdir, "") || ((dir) && (!strcmp(dir, evdir)))))) { // printf(" ch/add response = %i\n", e->response); free(evdir); if (e->response == 0) /*live changes*/ { if (e->minor == E_FM_OP_FILE_ADD) /*file add*/ { _e_fm2_live_file_add (obj, ecore_file_file_get(path), NULL, 0, &finf); break; } if (e->minor == E_FM_OP_FILE_CHANGE) /*file change*/ { _e_fm2_live_file_changed (obj, (char *)ecore_file_file_get(path), &finf); } break; } /*file add - listing*/ if (e->minor == E_FM_OP_FILE_ADD) /*file add*/ { if (!sd->scan_timer) { sd->scan_timer = ecore_timer_loop_add(0.5, _e_fm2_cb_scan_timer, sd->obj); sd->busy_count++; if (sd->busy_count == 1) edje_object_signal_emit(sd->overlay, "e,state,busy,start", "e"); } else { if ((eina_list_count(sd->icons) > 50) && (ecore_timer_interval_get(sd->scan_timer) < 1.5)) { /* increase timer interval when loading large directories to * dramatically improve load times */ ecore_timer_interval_set(sd->scan_timer, 1.5); ecore_timer_loop_reset(sd->scan_timer); } } if (path[0] != 0) { file = ecore_file_file_get(path); if ((!strcmp(file, ".order"))) sd->order_file = EINA_TRUE; else { unsigned int n; n = eina_list_count(sd->queue) + eina_list_count(sd->icons); if (!((file[0] == '.') && (!sd->show_hidden_files))) { char buf[1024]; _e_fm2_file_add(obj, file, sd->order_file, NULL, 0, &finf); if (n - sd->overlay_count > 150) { sd->overlay_count = n + 1; snprintf(buf, sizeof(buf), P_("%u file", "%u files", sd->overlay_count), sd->overlay_count); edje_object_part_text_set(sd->overlay, "e.text.busy_label", buf); } } } } if (e->response == 2) /* end of scan */ { sd->listing = EINA_FALSE; if (sd->scan_timer) { ecore_timer_interval_set(sd->scan_timer, 0.0001); ecore_timer_loop_reset(sd->scan_timer); } else { _e_fm2_client_monitor_list_end(obj); } } } break; } free(evdir); // printf(" ...\n"); if ((sd->id != e->ref_to) || (path[0] != 0)) break; // printf(" end response = %i\n", e->response); if (e->response == 2) /* end of scan */ { sd->listing = EINA_FALSE; if (sd->scan_timer) { ecore_timer_del(sd->scan_timer); sd->scan_timer = ecore_timer_loop_add(0.0001, _e_fm2_cb_scan_timer, sd->obj); } else { _e_fm2_client_monitor_list_end(obj); } } } break; case E_FM_OP_FILE_DEL: /*file del*/ // printf("E_FM_OP_FILE_DEL\n"); path = e->data; evdir = ecore_file_dir_get(path); if ((dir) && (evdir) && (sd->id == e->ref_to) && (!strcmp(dir, evdir))) { _e_fm2_live_file_del (obj, ecore_file_file_get(path)); } free(evdir); break; case E_FM_OP_MONITOR_END: /*mon dir del*/ // printf("E_FM_OP_MONITOR_END\n"); path = e->data; /* FIXME dir should not be null but can. fix segv when mounting cdrom with udisk here btw monitor end seems to be a strange event for mounting disks. */ if ((dir) && (path) && (sd->id == e->ref_to) && (!strcmp(dir, path))) { dels = eina_list_append(dels, obj); } break; default: break; } } EINA_LIST_FREE(dels, obj) { E_Fm2_Smart_Data *sd; sd = evas_object_smart_data_get(obj); if ((_e_fm2_list_walking > 0) && (eina_list_data_find(_e_fm2_list_remove, obj))) continue; if (sd->config->view.open_dirs_in_place) _e_fm2_path_parent_set(obj, sd->realpath); else evas_object_smart_callback_call(obj, "dir_deleted", NULL); } _e_fm2_list_walking--; if (_e_fm2_list_walking == 0) { EINA_LIST_FREE(_e_fm2_list_remove, obj) { _e_fm2_list = eina_list_remove(_e_fm2_list, obj); } } switch (e->minor) { case E_FM_OP_INIT: e_config->device_detect_mode = strtoul((char*)e->data, NULL, 10); break; case E_FM_OP_MONITOR_SYNC: /*mon list sync*/ ecore_ipc_client_send(cl->cl, E_IPC_DOMAIN_FM, E_FM_OP_MONITOR_SYNC, 0, 0, e->response, NULL, 0); break; case E_FM_OP_STORAGE_ADD: /*storage add*/ if ((e->data) && (e->size > 0)) { E_Storage *s; s = _e_fm_shared_codec_storage_decode(e->data, e->size); if (s) e_fm2_device_storage_add(s); } break; case E_FM_OP_STORAGE_DEL: /*storage del*/ if ((e->data) && (e->size > 0)) { char *udi; E_Storage *s; udi = e->data; s = e_fm2_device_storage_find(udi); if (s) e_fm2_device_storage_del(s); } break; case E_FM_OP_VOLUME_LIST_DONE: e_fm2_device_check_desktop_icons(); break; case E_FM_OP_VOLUME_ADD: /*volume add*/ if ((e->data) && (e->size > 0)) { E_Volume *v; v = _e_fm_shared_codec_volume_decode(e->data, e->size); if (!v) break; e_config->device_detect_mode = v->efm_mode; e_fm2_device_volume_add(v); if (v->mounted) e_fm2_device_mount(v, NULL, NULL, NULL, NULL, NULL); else if ((!starting) && e_config->device_auto_mount && v->first_time) { v->auto_unmount = !v->mounted; _e_fm2_client_mount(v->udi, v->mount_point); } if (e_config->device_desktop) e_fm2_device_show_desktop_icons(); else e_fm2_device_hide_desktop_icons(); v->first_time = 0; } break; case E_FM_OP_VOLUME_DEL: /*volume del*/ if ((e->data) && (e->size > 0)) { char *udi; E_Volume *v; udi = e->data; v = e_fm2_device_volume_find(udi); if (v) e_fm2_device_volume_del(v); } break; case E_FM_OP_MOUNT_DONE: /*mount done*/ if ((e->data) && (e->size > 1)) { E_Volume *v; char *udi, *mountpoint = NULL; udi = e->data; if ((unsigned int)e->size != (strlen(udi) + 1)) mountpoint = udi + strlen(udi) + 1; v = e_fm2_device_volume_find(udi); if (v) { e_fm2_device_mount_add(v, mountpoint); _e_fm2_volume_icon_update(v); if (e_config->device_auto_open && !eina_list_count(v->mounts)) { E_Action *a; unsigned int count; a = e_action_find("fileman"); count = eina_list_count(_e_fm2_list); if (a && a->func.go && mountpoint) { Evas_Object *fm; Eina_List *m; Eina_Bool auto_unmount = v->auto_unmount; a->func.go(E_OBJECT(e_comp), mountpoint); if (count == eina_list_count(_e_fm2_list)) break; EINA_LIST_REVERSE_FOREACH(_e_fm2_list, m, fm) { E_Fm2_Smart_Data *sd = evas_object_smart_data_get(fm); if (e_util_strcmp(sd->realpath, mountpoint)) continue; if (sd->mount) break; sd->mount = e_fm2_device_mount(v, _e_fm2_cb_mount_ok, _e_fm2_cb_mount_fail, _e_fm2_cb_unmount_ok, NULL, fm); v->auto_unmount = auto_unmount; break; } } } } } break; case E_FM_OP_UNMOUNT_DONE: /*unmount done*/ if ((e->data) && (e->size > 1)) { E_Volume *v; char *udi; udi = e->data; v = e_fm2_device_volume_find(udi); if (v) { e_fm2_device_mount_del(v); _e_fm2_volume_icon_update(v); } } break; case E_FM_OP_EJECT_DONE: break; case E_FM_OP_MOUNT_ERROR: /*mount error*/ if (e->data && (e->size > 1)) { E_Volume *v; char *udi; udi = e->data; v = e_fm2_device_volume_find(udi); if (v) { _e_fm_device_error_dialog(_("Mount Error"), _("Can't mount device"), e->data); e_fm2_device_mount_fail(v); } } break; case E_FM_OP_UNMOUNT_ERROR: /*unmount error*/ if (e->data && (e->size > 1)) { E_Volume *v; char *udi; udi = e->data; v = e_fm2_device_volume_find(udi); if (v) { _e_fm_device_error_dialog(_("Unmount Error"), _("Can't unmount device"), e->data); e_fm2_device_unmount_fail(v); } } break; case E_FM_OP_EJECT_ERROR: if (e->data && (e->size > 1)) { E_Volume *v; char *udi; udi = e->data; v = e_fm2_device_volume_find(udi); if (v) _e_fm_device_error_dialog(_("Eject Error"), _("Can't eject device"), e->data); } break; case E_FM_OP_ERROR: /*error*/ { E_Dialog *dlg; ERR("Error from slave #%d: %s", e->ref, (char *)e->data); dlg = _e_fm_error_dialog(e->ref, e->data); _e_fm2_op_registry_error(e->ref, dlg); } break; case E_FM_OP_ERROR_RETRY_ABORT: /*error*/ { E_Dialog *dlg; ERR("Error from slave #%d: %s", e->ref, (char *)e->data); dlg = _e_fm_retry_abort_dialog(e->ref, (char *)e->data); _e_fm2_op_registry_error(e->ref, dlg); } break; case E_FM_OP_OVERWRITE: /*overwrite*/ { E_Dialog *dlg; ERR("Overwrite from slave #%d: %s", e->ref, (char *)e->data); dlg = _e_fm_overwrite_dialog(e->ref, (char *)e->data); _e_fm2_op_registry_needs_attention(e->ref, dlg); } break; case E_FM_OP_PROGRESS: /*progress*/ { int percent, seconds; off_t done, total; char *src = NULL; char *dst = NULL; char *p = e->data; E_Fm2_Op_Registry_Entry *ere; if (!e->data) return; #define UP(value, type) (value) = *(type *)(void *)p; p += sizeof(type) UP(percent, int); UP(seconds, int); UP(done, off_t); UP(total, off_t); #undef UP src = p; dst = p + strlen(src) + 1; // printf("%s:%s(%d) Progress from slave #%d:\n\t%d%% done,\n\t%d seconds left,\n\t%zd done,\n\t%zd total,\n\tsrc = %s,\n\tdst = %s.\n", __FILE__, __FUNCTION__, __LINE__, e->ref, percent, seconds, done, total, src, dst); ere = e_fm2_op_registry_entry_get(e->ref); if (!ere) return; ere->percent = percent; ere->done = done; ere->total = total; ere->eta = seconds; e_fm2_op_registry_entry_files_set(ere, src, dst); if (ere->percent == 100) { ere->status = E_FM2_OP_STATUS_SUCCESSFUL; ere->finished = 1; } e_fm2_op_registry_entry_changed(ere); } break; case E_FM_OP_QUIT: /*finished*/ { E_Fm2_Op_Registry_Entry *ere = e_fm2_op_registry_entry_get(e->ref); if (ere) { ere->finished = 1; ere->eta = 0; e_fm2_op_registry_entry_changed(ere); } e_fm2_op_registry_entry_del(e->ref); } break; default: break; } } E_API void e_fm2_client_del(Ecore_Ipc_Event_Client_Del *e) { Eina_List *l; E_Fm2_Client *cl; EINA_LIST_FOREACH(_e_fm2_client_list, l, cl) { if (cl->cl == e->client) { _e_fm2_client_list = eina_list_remove_list(_e_fm2_client_list, l); free(cl); break; } } } /* local subsystem functions */ static const char * _e_fm2_dev_path_map(E_Fm2_Smart_Data *sd, const char *dev, const char *path) { char buf[PATH_MAX] = "", *s, *ss; int len; /* map a device name to a mount point/path on the os (and append path) */ /* FIXME: load mappings from config and use them first - maybe device * discovery should be done through config and not the below (except * maybe for home directory and root fs and other simple thngs */ /* FIXME: also add other virtualized dirs like "backgrounds", "themes", * "favorites" */ #define CMP(x) ((dev) && (e_util_glob_case_match(dev, x))) #define PRT(args ...) snprintf(buf, sizeof(buf), ##args) if (dev) { if (dev[0] == '/') { if (dev[1] == '\0') { if (eina_strlcpy(buf, path, sizeof(buf)) >= (int)sizeof(buf)) return NULL; } else { if (PRT("%s/%s", dev, path) >= (int)sizeof(buf)) return NULL; } } else if ((dev[0] == '~') && (dev[1] == '/') && (dev[2] == '\0')) { s = (char *)e_user_homedir_get(); if (PRT("%s/%s", s, path) >= (int)sizeof(buf)) return NULL; } else if (strcmp(dev, "favorites") == 0) { /* this is a virtual device - it's where your favorites list is * stored - a dir with .desktop files or symlinks (in fact anything * you like). */ if (e_user_dir_concat_static(buf, "fileman/favorites") >= sizeof(buf)) return NULL; if (sd && sd->config) sd->config->view.no_typebuf_set = EINA_TRUE; ecore_file_mkpath(buf); } else if (strcmp(dev, "desktop") == 0) { /* this is a virtual device - it's where your favorites list is * stored - a dir with .desktop files or symlinks (in fact anything * you like). */ if ((!path) || (!path[0]) || (!strcmp(path, "/"))) { snprintf(buf, sizeof(buf), "%s", efreet_desktop_dir_get()); ecore_file_mkpath(buf); } else if (path[0] == '/') snprintf(buf, sizeof(buf), "%s/%s", efreet_desktop_dir_get(), path); else { snprintf(buf, sizeof(buf), "%s-%s", efreet_desktop_dir_get(), path); ecore_file_mkpath(buf); } } else if (strcmp(dev, "temp") == 0) PRT("/tmp"); /* FIXME: replace all this removable, dvd and like with hal */ else if (!strncmp(dev, "removable:", sizeof("removable:") - 1)) { E_Volume *v; v = e_fm2_device_volume_find(dev + strlen("removable:")); if (v) { if ((!v->mount_point) && (v->efm_mode == EFM_MODE_USING_HAL_MOUNT)) v->mount_point = e_fm2_device_volume_mountpoint_get(v); else if (!v->mount_point) return NULL; if (PRT("%s/%s", v->mount_point, path) >= (int)sizeof(buf)) return NULL; } } /* else if (CMP("dvd") || CMP("dvd-*")) */ /* { */ /* /\* FIXME: find dvd mountpoint optionally for dvd no. X *\/ */ /* /\* maybe make part of the device mappings config? *\/ */ /* } */ /* else if (CMP("cd") || CMP("cd-*") || CMP("cdrom") || CMP("cdrom-*") || */ /* CMP("dvd") || CMP("dvd-*")) */ /* { */ /* /\* FIXME: find cdrom or dvd mountpoint optionally for cd/dvd no. X *\/ */ /* /\* maybe make part of the device mappings config? *\/ */ /* } */ } /* FIXME: add code to find USB devices (multi-card readers or single, * usb thumb drives, other usb storage devices (usb hd's etc.) */ /* maybe make part of the device mappings config? */ /* FIXME: add code for finding nfs shares, smb shares etc. */ /* maybe make part of the device mappings config? */ if (buf[0] == '\0') { if (eina_strlcpy(buf, path, sizeof(buf)) >= sizeof(buf)) return NULL; } /* strip out excess multiple slashes */ s = buf; while (*s) { while ((s[0] == '/') && (s[1] == '/')) { ss = s; do { ss[0] = ss[1]; ss++; } while (*ss); } s++; } /* strip out slashes at the end - unless its just "/" */ len = s - buf; while ((len > 1) && (buf[len - 1] == '/')) { buf[len - 1] = 0; len--; } return eina_stringshare_add(buf); } static void _e_fm2_file_add(Evas_Object *obj, const char *file, int unique, Eina_Stringshare *file_rel, int after, E_Fm2_Finfo *finf) { E_Fm2_Smart_Data *sd; E_Fm2_Icon *ic, *ic2; Eina_List *l; sd = evas_object_smart_data_get(obj); if (!sd) return; /* if we only want unique icon names - if it's there - ignore */ if (unique) { EINA_LIST_FOREACH(sd->icons, l, ic) { if (!strcmp(ic->info.file, file)) { sd->tmp.last_insert = NULL; return; } } EINA_LIST_FOREACH(sd->queue, l, ic) { if (!strcmp(ic->info.file, file)) { sd->tmp.last_insert = NULL; return; } } } /* create icon obj and append to unsorted list */ ic = _e_fm2_icon_new(sd, file, finf); if (ic) { if (!file_rel) { if (ic->queued) abort(); if (ic->inserted) abort(); /* respekt da ordah! */ if (sd->order_file) sd->queue = eina_list_append(sd->queue, ic); else { /* insertion sort it here to spread the sort load into idle time */ sd->queue = eina_list_sorted_insert(sd->queue, _e_fm2_cb_icon_sort, ic); } ic->queued = EINA_TRUE; } else { if (ic->queued) abort(); if (ic->inserted) abort(); EINA_LIST_FOREACH(sd->icons, l, ic2) { if (ic2->info.file == file_rel) { if (after) sd->icons = eina_list_append_relative(sd->icons, ic, ic2); else sd->icons = eina_list_prepend_relative(sd->icons, ic, ic2); ic->inserted = EINA_TRUE; break; } } if (ic->inserted) { sd->icons = eina_list_append(sd->icons, ic); ic->inserted = EINA_TRUE; } sd->icons_place = eina_list_append(sd->icons_place, ic); } sd->tmp.last_insert = NULL; sd->iconlist_changed = EINA_TRUE; } } static void _e_fm2_file_del(Evas_Object *obj, const char *file) { E_Fm2_Smart_Data *sd; E_Fm2_Icon *ic; Eina_List *l; sd = evas_object_smart_data_get(obj); if (!sd) return; EINA_LIST_FOREACH(sd->icons, l, ic) { if (!strcmp(ic->info.file, file)) { if (!ic->inserted) abort(); sd->icons = eina_list_remove_list(sd->icons, l); ic->inserted = EINA_FALSE; sd->icons_place = eina_list_remove(sd->icons_place, ic); if (ic->region) { ic->region->list = eina_list_remove(ic->region->list, ic); ic->region = NULL; } _e_fm2_icon_free(ic); return; } } EINA_LIST_FOREACH(sd->queue, l, ic) { if (!strcmp(ic->info.file, file)) { INF("MATCH!"); sd->queue = eina_list_remove_list(sd->queue, l); ic->queued = EINA_FALSE; _e_fm2_icon_free(ic); return; } } } static void _e_fm_file_buffer_clear(void) { const char *s; EINA_LIST_FREE(_e_fm_file_buffer, s) eina_stringshare_del(s); _e_fm_file_buffer_copying = 0; } static Eina_Bool _e_fm2_buffer_fill(Evas_Object *obj) { Eina_List *sel; char buf[PATH_MAX], *pfile; int bufused, buffree; const char *real_path; const E_Fm2_Icon_Info *ici; sel = e_fm2_selected_list_get(obj); if (!sel) return EINA_FALSE; real_path = e_fm2_real_path_get(obj); if (!real_path) return EINA_FALSE; bufused = eina_strlcpy(buf, real_path, sizeof(buf)); if (bufused >= (int)sizeof(buf) - 2) return EINA_FALSE; if ((bufused > 0) && (buf[bufused - 1] != '/')) { buf[bufused] = '/'; bufused++; } pfile = buf + bufused; buffree = sizeof(buf) - bufused; EINA_LIST_FREE(sel, ici) { if (!ici) continue; if ((int)eina_strlcpy(pfile, ici->file, buffree) >= buffree) continue; _e_fm_file_buffer = eina_list_append(_e_fm_file_buffer, _e_fm2_uri_escape(buf)); } return EINA_TRUE; } static void _e_fm2_file_cut(Evas_Object *obj) { _e_fm_file_buffer_clear(); _e_fm2_buffer_fill(obj); } static void _e_fm2_file_copy(Evas_Object *obj) { _e_fm_file_buffer_clear(); _e_fm_file_buffer_copying = _e_fm2_buffer_fill(obj); } static void _e_fm2_file_paste(Evas_Object *obj) { E_Fm2_Smart_Data *sd; Eina_List *paths; const char *filepath; size_t length = 0; size_t size = 0; char *args = NULL; Eina_Bool memerr = EINA_FALSE; sd = evas_object_smart_data_get(obj); if (!sd) return; /* Convert URI list to a list of real paths. */ paths = e_fm2_uri_path_list_get(_e_fm_file_buffer); if (!paths) return; EINA_LIST_FREE(paths, filepath) { /* Get file's full path. */ if (!filepath) continue; /* Check if file is protected. */ if (e_filereg_file_protected(filepath)) { eina_stringshare_del(filepath); continue; } /* Put filepath into a string of args. * If there are more files, put an additional space. */ if (!memerr) { args = e_util_string_append_quoted(args, &size, &length, filepath); if (!args) memerr = EINA_TRUE; else { args = e_util_string_append_char(args, &size, &length, ' '); if (!args) memerr = EINA_TRUE; } } eina_stringshare_del(filepath); } if (memerr) return; /* Add destination to the arguments. */ { E_Fm2_Icon *ic = NULL; if (eina_list_count(sd->selected_icons) == 1) { ic = eina_list_data_get(sd->selected_icons); if (ic->info.link || (!S_ISDIR(ic->info.statinfo.st_mode))) ic = NULL; } if (ic) { args = e_util_string_append_quoted(args, &size, &length, sd->realpath); if (!args) return; args = e_util_string_append_char(args, &size, &length, '/'); if (!args) return; args = e_util_string_append_quoted(args, &size, &length, ic->info.file); if (!args) return; } else { args = e_util_string_append_quoted(args, &size, &length, sd->realpath); if (!args) return; } } /* Roll the operation! */ if (_e_fm_file_buffer_copying) { if (sd->config->view.link_drop) e_fm2_client_file_symlink(sd->obj, args); else e_fm2_client_file_copy(sd->obj, args); } else { if (sd->config->view.link_drop) e_fm2_client_file_symlink(sd->obj, args); else e_fm2_client_file_move(sd->obj, args); _e_fm_file_buffer_clear(); } free(args); } static void _e_fm2_file_symlink(Evas_Object *obj) { E_Fm2_Smart_Data *sd; Eina_List *paths; const char *filepath; size_t length = 0; size_t size = 0; char *args = NULL; Eina_Bool memerr = EINA_FALSE; sd = evas_object_smart_data_get(obj); if (!sd) return; /* Convert URI list to a list of real paths. */ paths = e_fm2_uri_path_list_get(_e_fm_file_buffer); EINA_LIST_FREE(paths, filepath) { /* Get file's full path. */ if (!filepath) continue; /* Check if file is protected. */ if (e_filereg_file_protected(filepath)) { eina_stringshare_del(filepath); continue; } /* Put filepath into a string of args. * If there are more files, put an additional space. */ if (!memerr) { args = e_util_string_append_quoted(args, &size, &length, filepath); if (!args) memerr = EINA_TRUE; else { args = e_util_string_append_char(args, &size, &length, ' '); if (!args) memerr = EINA_TRUE; } } eina_stringshare_del(filepath); } if (memerr) return; /* Add destination to the arguments. */ args = e_util_string_append_quoted(args, &size, &length, sd->realpath); if (!args) return; /* Roll the operation! */ if (_e_fm_file_buffer_copying) e_fm2_client_file_symlink(sd->obj, args); free(args); } static void _e_fm2_file_cut_menu(void *data, E_Menu *m EINA_UNUSED, E_Menu_Item *mi EINA_UNUSED) { E_Fm2_Smart_Data *sd = data; if (!sd) return; _e_fm2_file_cut(sd->obj); } static void _e_fm2_file_copy_menu(void *data, E_Menu *m EINA_UNUSED, E_Menu_Item *mi EINA_UNUSED) { E_Fm2_Smart_Data *sd = data; if (!sd) return; _e_fm2_file_copy(sd->obj); } static void _e_fm2_file_paste_menu(void *data, E_Menu *m EINA_UNUSED, E_Menu_Item *mi EINA_UNUSED) { E_Fm2_Smart_Data *sd = data; if (!sd) return; _e_fm2_file_paste(sd->obj); } static void _e_fm2_file_symlink_menu(void *data, E_Menu *m EINA_UNUSED, E_Menu_Item *mi EINA_UNUSED) { E_Fm2_Smart_Data *sd = data; if (!sd) return; _e_fm2_file_symlink(sd->obj); } static void _e_fm2_queue_process(Evas_Object *obj) { E_Fm2_Smart_Data *sd; E_Fm2_Icon *ic, *ic2; Eina_List *l, **ll; int added = 0, i, p0, p1, n, v; double t; char buf[4096]; sd = evas_object_smart_data_get(obj); if (!sd) return; if (!sd->queue) { if (sd->resize_job) ecore_job_del(sd->resize_job); sd->resize_job = ecore_job_add(_e_fm2_cb_resize_job, obj); evas_object_smart_callback_call(sd->obj, "changed", NULL); sd->tmp.last_insert = NULL; return; } // double tt = ecore_time_get(); // int queued = eina_list_count(sd->queue); /* take unsorted and insert into the icon list - reprocess regions */ t = ecore_time_get(); if (!sd->tmp.last_insert) { #if 1 n = eina_list_count(sd->icons); E_FREE(sd->tmp.list_index); if (n > 0) sd->tmp.list_index = calloc(n, sizeof(Eina_List *)); if (sd->tmp.list_index) { ll = sd->tmp.list_index; for (l = sd->icons; l; l = eina_list_next(l)) { *ll = l; ll++; } /* binary search first queue */ ic = eina_list_data_get(sd->queue); p0 = 0; p1 = n; i = (p0 + p1) / 2; ll = sd->tmp.list_index; if (ll[i]) do /* avoid garbage deref */ { ic2 = eina_list_data_get(ll[i]); v = _e_fm2_cb_icon_sort(ic, ic2); if (v < 0) /* ic should go before ic2 */ p1 = i; else /* ic should go at or after ic2 */ p0 = i; i = (p0 + p1) / 2; l = ll[i]; } while ((p1 - p0) > 1); } else #endif l = sd->icons; } else l = sd->tmp.last_insert; while (sd->queue) { ic = sd->queue->data; sd->queue = eina_list_remove_list(sd->queue, sd->queue); /* insertion sort - better than qsort for the way we are doing * things - incrimentally scan and sort as we go as we now know * that the queue files are in order, we speed up insertions to * a worst case of O(n) where n is the # of files in the list * so far */ if (sd->order_file) { l = NULL; } else { EINA_LIST_FOREACH(l, l, ic2) { if (_e_fm2_cb_icon_sort(ic, ic2) < 0) { if (!ic->queued) abort(); if (ic->inserted) abort(); ic->queued = EINA_FALSE; ic->inserted = EINA_TRUE; if (l == sd->icons) sd->icons = eina_list_prepend(sd->icons, ic); else sd->icons = eina_list_prepend_relative_list(sd->icons, ic, l); sd->tmp.last_insert = l; break; } } } if (!l) { if (!ic->queued) abort(); if (ic->inserted) abort(); ic->queued = EINA_FALSE; ic->inserted = EINA_TRUE; sd->icons = eina_list_append(sd->icons, ic); sd->tmp.last_insert = eina_list_last(sd->icons); } sd->icons_place = eina_list_append(sd->icons_place, ic); added++; /* if we spent more than 1/20th of a second inserting - give up * for now */ if ((_e_fm2_toomany_get(sd)) && (!sd->toomany)) { sd->toomany = EINA_TRUE; break; } if ((ecore_time_get() - t) > 0.01) break; } // printf("FM: SORT %1.3f (%i files) (%i queued, %i added) [%i iter]\n", // ecore_time_get() - tt, eina_list_count(sd->icons), queued, // added, sd->tmp.iter); sd->overlay_count = eina_list_count(sd->icons); snprintf(buf, sizeof(buf), P_("%u file", "%u files", sd->overlay_count), sd->overlay_count); edje_object_part_text_set(sd->overlay, "e.text.busy_label", buf); if (sd->resize_job) ecore_job_del(sd->resize_job); // this will handle a relayout if we have too many icons sd->resize_job = ecore_job_add(_e_fm2_cb_resize_job, obj); evas_object_smart_callback_call(sd->obj, "changed", NULL); sd->tmp.iter++; } static void _e_fm2_queue_free(Evas_Object *obj) { E_Fm2_Smart_Data *sd; E_Fm2_Icon *ic; sd = evas_object_smart_data_get(obj); if (!sd) return; /* just free the icons in the queue and the queue itself */ EINA_LIST_FREE(sd->queue, ic) { if (!ic->queued) abort(); if (ic->inserted) abort(); ic->queued = EINA_FALSE; _e_fm2_icon_free(ic); } } static void _e_fm2_regions_free(Evas_Object *obj) { E_Fm2_Smart_Data *sd; E_Fm2_Region *rg; sd = evas_object_smart_data_get(obj); if (!sd) return; /* free up all regions */ EINA_LIST_FREE(sd->regions.list, rg) _e_fm2_region_free(rg); } static void _e_fm2_regions_populate(Evas_Object *obj) { E_Fm2_Smart_Data *sd; Eina_List *l; E_Fm2_Region *rg; E_Fm2_Icon *ic; sd = evas_object_smart_data_get(obj); if (!sd) return; /* take the icon list and split into regions */ rg = NULL; evas_event_freeze(evas_object_evas_get(obj)); edje_freeze(); EINA_LIST_FOREACH(sd->icons, l, ic) { if (!rg) { rg = _e_fm2_region_new(sd); sd->regions.list = eina_list_append(sd->regions.list, rg); } ic->region = rg; rg->list = eina_list_append(rg->list, ic); if (rg->w == 0) { rg->x = ic->x; rg->y = ic->y; rg->w = ic->w; rg->h = ic->h; } else { if (ic->x < rg->x) { rg->w += rg->x - ic->x; rg->x = ic->x; } if ((ic->x + ic->w) > (rg->x + rg->w)) { rg->w += (ic->x + ic->w) - (rg->x + rg->w); } if (ic->y < rg->y) { rg->h += rg->y - ic->y; rg->y = ic->y; } if ((ic->y + ic->h) > (rg->y + rg->h)) { rg->h += (ic->y + ic->h) - (rg->y + rg->h); } } if ((int)eina_list_count(rg->list) > sd->regions.member_max) rg = NULL; } _e_fm2_regions_eval(obj); EINA_LIST_FOREACH(sd->icons, l, ic) { if ((!ic->region->realized) && (ic->realized)) _e_fm2_icon_unrealize(ic); } _e_fm2_obj_icons_place(sd); edje_thaw(); evas_event_thaw(evas_object_evas_get(obj)); } static void _e_fm2_icons_place_icons(E_Fm2_Smart_Data *sd) { Eina_List *l; E_Fm2_Icon *ic; Evas_Coord x, y, rh; x = 0; y = 0; rh = 0; EINA_LIST_FOREACH(sd->icons, l, ic) { if ((x > 0) && ((x + ic->w) > sd->w)) { x = 0; y += rh; rh = 0; } ic->x = x; ic->y = y; x += ic->w; sd->min.w = MAX(ic->min_w, sd->min.w); sd->min.h = MAX(ic->min_h, sd->min.h); if (ic->h > rh) rh = ic->h; if ((ic->x + ic->w) > sd->max.w) sd->max.w = ic->x + ic->w; if ((ic->y + ic->h) > sd->max.h) sd->max.h = ic->y + ic->h; } } static void _e_fm2_icons_place_grid_icons(E_Fm2_Smart_Data *sd) { Eina_List *l; E_Fm2_Icon *ic; Evas_Coord x, y, gw, gh; int cols = 1, col; gw = 0; gh = 0; EINA_LIST_FOREACH(sd->icons, l, ic) { if (ic->w > gw) gw = ic->w; if (ic->h > gh) gh = ic->h; } if (gw > 0) cols = sd->w / gw; if (cols < 1) cols = 1; x = 0; y = 0; col = 0; EINA_LIST_FOREACH(sd->icons, l, ic) { ic->x = x + ((gw - ic->w) / 2); ic->y = y + (gh - ic->h); x += gw; col++; if (col >= cols) { col = 0; x = 0; y += gh; } if ((ic->x + ic->w) > sd->max.w) sd->max.w = ic->x + ic->w; if ((ic->y + ic->h) > sd->max.h) sd->max.h = ic->y + ic->h; sd->min.w = MAX(ic->min_w, sd->min.w); sd->min.h = MAX(ic->min_h, sd->min.h); } } static int _e_fm2_icons_icon_overlaps(E_Fm2_Icon *ic) { Eina_List *l; E_Fm2_Icon *ic2; /* this is really slow... when we have a lot of icons */ EINA_LIST_FOREACH(ic->sd->icons, l, ic2) { if ((ic2 != ic) && (ic2->saved_pos)) { if (E_INTERSECTS(ic2->x, ic2->y, ic2->w, ic2->h, ic->x, ic->y, ic->w, ic->h)) return 1; } } return 0; } static int _e_fm2_icons_icon_row_ok(E_Fm2_Icon *ic) { if (ic->x + ic->w > ic->sd->w) return 0; if (ic->x < 0) return 0; if (ic->y < 0) return 0; return 1; } static void _e_fm2_icon_place_relative(E_Fm2_Icon *ic, E_Fm2_Icon *icr, int xrel, int yrel, int xa, int ya) { ic->x = icr->x; ic->y = icr->y; if (xrel > 0) ic->x += icr->w; else if (xrel < 0) ic->x -= ic->w; else if (xa == 1) ic->x += (icr->w - ic->w) / 2; else if (xa == 2) ic->x += icr->w - ic->w; if (yrel > 0) ic->y += icr->h; else if (yrel < 0) ic->y -= ic->h; else if (ya == 1) ic->y += (icr->h - ic->h) / 2; else if (ya == 2) ic->y += icr->h - ic->h; } static void _e_fm2_icons_place_icon(E_Fm2_Icon *ic) { Eina_List *l; E_Fm2_Icon *ic2; ic->x = 0; ic->y = 0; ic->saved_pos = EINA_TRUE; /* ### BLAH ### */ // if (!_e_fm2_icons_icon_overlaps(ic)) return; /* _e_fm2_icon_place_relative(ic, ic2, 1, 0, 0, 2); if (_e_fm2_icons_icon_row_ok(ic) && !_e_fm2_icons_icon_overlaps(ic)) return; _e_fm2_icon_place_relative(ic, ic2, 0, -1, 0, 0); if (_e_fm2_icons_icon_row_ok(ic) && !_e_fm2_icons_icon_overlaps(ic)) return; _e_fm2_icon_place_relative(ic, ic2, 0, -1, 1, 0); if (_e_fm2_icons_icon_row_ok(ic) && !_e_fm2_icons_icon_overlaps(ic)) return; _e_fm2_icon_place_relative(ic, ic2, 1, 0, 0, 0); if (_e_fm2_icons_icon_row_ok(ic) && !_e_fm2_icons_icon_overlaps(ic)) return; _e_fm2_icon_place_relative(ic, ic2, 1, 0, 0, 1); if (_e_fm2_icons_icon_row_ok(ic) && !_e_fm2_icons_icon_overlaps(ic)) return; _e_fm2_icon_place_relative(ic, ic2, 0, 1, 0, 0); if (_e_fm2_icons_icon_row_ok(ic) && !_e_fm2_icons_icon_overlaps(ic)) return; _e_fm2_icon_place_relative(ic, ic2, 0, 1, 1, 0); if (_e_fm2_icons_icon_row_ok(ic) && !_e_fm2_icons_icon_overlaps(ic)) return; */ if ((ic->sd->last_placed) && (ic->sd->toomany)) { ic2 = ic->sd->last_placed; // ###_ _e_fm2_icon_place_relative(ic, ic2, 1, 0, 0, 2); if (_e_fm2_icons_icon_row_ok(ic) && !_e_fm2_icons_icon_overlaps(ic)) goto done; // _### _e_fm2_icon_place_relative(ic, ic2, -1, 0, 0, 2); if (_e_fm2_icons_icon_row_ok(ic) && !_e_fm2_icons_icon_overlaps(ic)) goto done; // ### // | _e_fm2_icon_place_relative(ic, ic2, 0, 1, 1, 0); if (_e_fm2_icons_icon_row_ok(ic) && !_e_fm2_icons_icon_overlaps(ic)) goto done; // | // ### _e_fm2_icon_place_relative(ic, ic2, 0, -1, 1, 0); if (_e_fm2_icons_icon_row_ok(ic) && !_e_fm2_icons_icon_overlaps(ic)) goto done; // do this anyway - dont care. // ### // | _e_fm2_icon_place_relative(ic, ic2, 0, 1, 1, 0); ic->x = 0; goto done; } EINA_LIST_FOREACH(ic->sd->icons, l, ic2) { if ((ic2 != ic) && (ic2->saved_pos)) { // ###_ _e_fm2_icon_place_relative(ic, ic2, 1, 0, 0, 2); if (_e_fm2_icons_icon_row_ok(ic) && !_e_fm2_icons_icon_overlaps(ic)) goto done; // _### _e_fm2_icon_place_relative(ic, ic2, -1, 0, 0, 2); if (_e_fm2_icons_icon_row_ok(ic) && !_e_fm2_icons_icon_overlaps(ic)) goto done; } } EINA_LIST_FOREACH(ic->sd->icons, l, ic2) { if ((ic2 != ic) && (ic2->saved_pos)) { // ### // | _e_fm2_icon_place_relative(ic, ic2, 0, 1, 1, 0); if (_e_fm2_icons_icon_row_ok(ic) && !_e_fm2_icons_icon_overlaps(ic)) goto done; // | // ### _e_fm2_icon_place_relative(ic, ic2, 0, -1, 1, 0); if (_e_fm2_icons_icon_row_ok(ic) && !_e_fm2_icons_icon_overlaps(ic)) goto done; } if ((ic2 != ic) && (ic2->saved_pos)) { // TODO: if uncomment this, change EINA_LIST_FOREACH to EINA_LIST_FOREACH_SAFE! // ic->sd->icons_place = eina_list_remove_list(ic->sd->icons_place, pl); } } done: ic->sd->last_placed = ic; return; } static void _e_fm2_icons_place_custom_icons(E_Fm2_Smart_Data *sd) { Eina_List *l; E_Fm2_Icon *ic; EINA_LIST_FOREACH(sd->icons, l, ic) { if (!ic->saved_pos) { /* FIXME: place using smart place fn */ _e_fm2_icons_place_icon(ic); } if ((ic->x + ic->w) > sd->max.w) sd->max.w = ic->x + ic->w; if ((ic->y + ic->h) > sd->max.h) sd->max.h = ic->y + ic->h; sd->min.w = MAX(ic->min_w, sd->min.w); sd->min.h = MAX(ic->min_h, sd->min.h); } } static void _e_fm2_icons_place_custom_grid_icons(E_Fm2_Smart_Data *sd) { /* FIXME: not going to implement this at this stage */ Eina_List *l; E_Fm2_Icon *ic; EINA_LIST_FOREACH(sd->icons, l, ic) { if (!ic->saved_pos) { /* FIXME: place using grid fn */ } if ((ic->x + ic->w) > sd->max.w) sd->max.w = ic->x + ic->w; if ((ic->y + ic->h) > sd->max.h) sd->max.h = ic->y + ic->h; sd->min.w = MAX(ic->min_w, sd->min.w); sd->min.h = MAX(ic->min_h, sd->min.h); } } static void _e_fm2_icons_place_custom_smart_grid_icons(E_Fm2_Smart_Data *sd) { /* FIXME: not going to implement this at this stage */ Eina_List *l; E_Fm2_Icon *ic; EINA_LIST_FOREACH(sd->icons, l, ic) { if (!ic->saved_pos) { /* FIXME: place using smart grid fn */ } if ((ic->x + ic->w) > sd->max.w) sd->max.w = ic->x + ic->w; if ((ic->y + ic->h) > sd->max.h) sd->max.h = ic->y + ic->h; sd->min.w = MAX(ic->min_w, sd->min.w); sd->min.h = MAX(ic->min_h, sd->min.h); } } static void _e_fm2_icons_place_list(E_Fm2_Smart_Data *sd) { Eina_List *l; E_Fm2_Icon *ic; Evas_Coord x, y; int w, i; w = i = x = y = 0; EINA_LIST_FOREACH(sd->icons, l, ic) { ic->x = x; ic->y = y; sd->min.w = MAX(ic->min_w, sd->min.w); sd->min.h = MAX(ic->min_h, sd->min.h); if (sd->w > ic->min_w) ic->w = sd->w; else ic->w = ic->min_w; y += ic->h; ic->odd = (i & 0x01); if ((ic->w != sd->w) && ((ic->x + ic->w) > sd->max.w)) sd->max.w = ic->x + ic->w; else if (ic->min_w > sd->max.w) sd->max.w = ic->min_w; if ((ic->y + ic->h) > sd->max.h) sd->max.h = ic->y + ic->h; w = MAX(w, ic->min_w); w = MAX(w, sd->w); i++; } EINA_LIST_FOREACH(sd->icons, l, ic) ic->w = w; } static void _e_fm2_icons_place(Evas_Object *obj) { E_Fm2_Smart_Data *sd; sd = evas_object_smart_data_get(obj); if (!sd) return; /* take the icon list and find a location for them */ sd->max.w = 0; sd->max.h = 0; switch (_e_fm2_view_mode_get(sd)) { case E_FM2_VIEW_MODE_ICONS: _e_fm2_icons_place_icons(sd); // sd->max.h += ICON_BOTTOM_SPACE; break; case E_FM2_VIEW_MODE_GRID_ICONS: _e_fm2_icons_place_grid_icons(sd); // sd->max.h += ICON_BOTTOM_SPACE; break; case E_FM2_VIEW_MODE_CUSTOM_ICONS: _e_fm2_icons_place_custom_icons(sd); // sd->max.h += ICON_BOTTOM_SPACE; break; case E_FM2_VIEW_MODE_CUSTOM_GRID_ICONS: /* FIXME: not going to implement this at this stage */ _e_fm2_icons_place_custom_grid_icons(sd); // sd->max.h += ICON_BOTTOM_SPACE; break; case E_FM2_VIEW_MODE_CUSTOM_SMART_GRID_ICONS: /* FIXME: not going to implement this at this stage */ _e_fm2_icons_place_custom_smart_grid_icons(sd); // sd->max.h += ICON_BOTTOM_SPACE; break; case E_FM2_VIEW_MODE_LIST: _e_fm2_icons_place_list(sd); break; default: break; } /* tell our parent scrollview - if any, that we have changed */ evas_object_smart_callback_call(sd->obj, "changed", NULL); } static void _e_fm2_icons_free(Evas_Object *obj) { E_Fm2_Smart_Data *sd; E_Fm2_Icon *ic; sd = evas_object_smart_data_get(obj); if (!sd) return; _e_fm2_queue_free(obj); /* free all icons */ EINA_LIST_FREE(sd->icons, ic) { if (ic->queued) abort(); if (!ic->inserted) abort(); ic->inserted = EINA_FALSE; _e_fm2_icon_free(ic); } sd->last_selected = NULL; sd->range_selected = NULL; eina_list_free(sd->icons_place); sd->icons_place = NULL; sd->tmp.last_insert = NULL; E_FREE(sd->tmp.list_index); } static void _e_fm2_regions_eval(Evas_Object *obj) { E_Fm2_Smart_Data *sd; Eina_List *l; E_Fm2_Region *rg; sd = evas_object_smart_data_get(obj); if (!sd) return; EINA_LIST_FOREACH(sd->regions.list, l, rg) { if (_e_fm2_region_visible(rg)) _e_fm2_region_realize(rg); else _e_fm2_region_unrealize(rg); } } static void _e_fm2_config_free(E_Fm2_Config *cfg) { if (cfg->icon.key_hint) eina_stringshare_del(cfg->icon.key_hint); if (cfg->theme.background) eina_stringshare_del(cfg->theme.background); if (cfg->theme.frame) eina_stringshare_del(cfg->theme.frame); if (cfg->theme.icons) eina_stringshare_del(cfg->theme.icons); free(cfg); } static Eina_List * _e_fm2_file_fm2_find(const char *file) { char *dir; Eina_List *l, *ret = NULL; Evas_Object *obj; dir = ecore_file_dir_get(file); if (!dir) return NULL; EINA_LIST_FOREACH(_e_fm2_list, l, obj) { if ((_e_fm2_list_walking > 0) && (eina_list_data_find(_e_fm2_list_remove, obj))) continue; if (!strcmp(e_fm2_real_path_get(obj), dir)) ret = eina_list_append(ret, obj); } free(dir); return ret; } static E_Fm2_Icon * _e_fm2_icon_find(Evas_Object *obj, const char *file) { E_Fm2_Smart_Data *sd; Eina_List *l; E_Fm2_Icon *ic; sd = evas_object_smart_data_get(obj); if (!sd) return NULL; EINA_LIST_FOREACH(sd->icons, l, ic) { if (!strcmp(ic->info.file, file)) return ic; } return NULL; } /* Escape illegal caracters within an uri and return an eina_stringshare */ static const char * _e_fm2_uri_escape(const char *path) { char dest[PATH_MAX * 3 + 7]; const char *p; int i; if (!path) return NULL; memset(dest, 0, PATH_MAX * 3 + 7); snprintf(dest, 8, "file://"); /* Most app doesn't handle the hostname in the uri so it's put to NULL */ for (i = 7, p = path; *p != '\0'; p++, i++) { if (isalnum(*p) || strchr("/$-_.+!*'()", *p)) dest[i] = *p; else { snprintf(&(dest[i]), 4, "%%%02X", (unsigned char)*p); i += 2; } } return eina_stringshare_add(dest); } /* Parse a single uri and return an E_Fm2_Uri struct. * If the parsing have failed it return NULL. * The E_Fm2_Uri may have hostname parameter and always a path. * If there's no hostname in the uri then the hostname parameter is NULL */ static E_Fm2_Uri * _e_fm2_uri_parse(const char *val) { E_Fm2_Uri *uri; const char *p; char hostname[PATH_MAX], path[PATH_MAX]; int i = 0; /* if value is a raw path: /path/to/blah just return it */ if (val[0] == '/') { uri = E_NEW(E_Fm2_Uri, 1); uri->hostname = NULL; uri->path = eina_stringshare_add(val); return uri; } /* The shortest possible path is file:/// * anything smaller than that can't be a valid uri */ if (strlen(val) <= 7 && strncmp(val, "file://", 7)) return NULL; memset(path, 0, PATH_MAX); /* An uri should be in a form file:/// */ p = val + 7; if (*p != '/') { for (i = 0; *p != '/' && *p != '\0' && i < _POSIX_HOST_NAME_MAX; p++, i++) hostname[i] = *p; } hostname[i] = '\0'; /* See http://www.faqs.org/rfcs/rfc1738.html for the escaped chars */ for (i = 0; (*p != '\0') && (i < (PATH_MAX - 1)); i++, p++) { if (*p == '%') { path[i] = *(++p); path[i + 1] = *(++p); path[i] = (char)strtol(&(path[i]), NULL, 16); path[i + 1] = '\0'; } else path[i] = *p; } uri = E_NEW(E_Fm2_Uri, 1); if (hostname[0]) uri->hostname = eina_stringshare_add(hostname); else uri->hostname = NULL; uri->path = eina_stringshare_add(path); return uri; } /* Takes an Eina_List of uri and return an Eina_List of real paths */ static Eina_List * _e_fm2_uri_selected_icon_list_get(Eina_List *uri) { Eina_List *icons = NULL; Eina_List *l; const char *path; EINA_LIST_FOREACH(uri, l, path) { Eina_List *fms; Evas_Object *fm; E_Fm2_Icon *ic; fms = _e_fm2_file_fm2_find(path); if (!fms) continue; ic = NULL; EINA_LIST_FREE(fms, fm) { ic = _e_fm2_icon_find(fm, ecore_file_file_get(path)); if (!ic) continue; if (eina_list_data_find(ic->sd->selected_icons, ic)) break; ic = NULL; } if (ic) icons = eina_list_append(icons, ic); } return icons; } /**************************/ static E_Fm2_Icon * _e_fm2_icon_new(E_Fm2_Smart_Data *sd, const char *file, E_Fm2_Finfo *finf) { E_Fm2_Icon *ic; /* create icon */ ic = E_NEW(E_Fm2_Icon, 1); ic->info.fm = sd->obj; ic->info.ic = ic; ic->info.file = eina_stringshare_add(file); ic->sd = sd; if (!_e_fm2_icon_fill(ic, finf)) { eina_stringshare_del(ic->info.file); free(ic); return NULL; } return ic; } static void _e_fm2_icon_unfill(E_Fm2_Icon *ic) { eina_stringshare_del(ic->info.mime); eina_stringshare_del(ic->info.label); eina_stringshare_del(ic->info.comment); eina_stringshare_del(ic->info.generic); eina_stringshare_del(ic->info.icon); eina_stringshare_del(ic->info.link); eina_stringshare_del(ic->info.real_link); eina_stringshare_del(ic->info.category); ic->info.mime = NULL; ic->info.label = NULL; ic->info.comment = NULL; ic->info.generic = NULL; ic->info.icon = NULL; ic->info.link = NULL; ic->info.real_link = NULL; ic->info.mount = EINA_FALSE; ic->info.removable = EINA_FALSE; ic->info.removable_full = EINA_FALSE; ic->info.deleted = EINA_FALSE; ic->info.broken_link = EINA_FALSE; } static void _e_fm2_icon_geom_adjust(E_Fm2_Icon *ic, int saved_x, int saved_y, int saved_w EINA_UNUSED, int saved_h EINA_UNUSED, int saved_res_w, int saved_res_h) { int qx, qy, rx, ry, x, y; if (!((_e_fm2_view_mode_get(ic->sd) == E_FM2_VIEW_MODE_CUSTOM_ICONS) && (ic->sd->config->view.fit_custom_pos) && (saved_res_w > 0) && (saved_res_h > 0))) return; if (saved_res_w >= 3) qx = saved_x / (saved_res_w / 3); else qx = 0; rx = saved_x - ((saved_res_w / 2) * qx); x = ((ic->sd->w / 2) * qx) + rx; ic->x = x; if (saved_res_h >= 3) qy = saved_y / (saved_res_h / 3); else qy = 0; ry = saved_y - ((saved_res_h / 2) * qy); y = ((ic->sd->h / 2) * qy) + ry; ic->y = y; } static const char * _mime_get(const char *path) { const char *mime = efreet_mime_special_type_get(path); if (!mime) mime = efreet_mime_globs_type_get(path); if (!mime) mime = efreet_mime_fallback_type_get(path); return mime; } static int _e_fm2_icon_fill(E_Fm2_Icon *ic, E_Fm2_Finfo *finf) { Evas_Coord mw = 0, mh = 0; Evas_Object *obj, *obj2; char buf[PATH_MAX]; const char *mime; E_Fm2_Custom_File *cf; if (!finf) return 0; if (!_e_fm2_icon_realpath(ic, buf, sizeof(buf))) return 0; cf = e_fm2_custom_file_get(buf); memcpy(&(ic->info.statinfo), &(finf->st), sizeof(struct stat)); if ((finf->lnk) && (finf->lnk[0])) ic->info.link = eina_stringshare_add(finf->lnk); else ic->info.link = NULL; if ((finf->rlnk) && (finf->rlnk[0])) ic->info.real_link = eina_stringshare_add(finf->rlnk); else ic->info.real_link = NULL; ic->info.broken_link = finf->broken_link; if ((!ic->info.link) && (S_ISDIR(ic->info.statinfo.st_mode))) { ic->info.mime = eina_stringshare_ref(_e_fm2_mime_inode_directory); } else if (ic->info.real_link) { mime = _mime_get(ic->info.real_link); if (!mime) /* XXX REMOVE/DEPRECATE ME LATER */ mime = e_fm_mime_filename_get(ic->info.file); if (mime) ic->info.mime = eina_stringshare_add(mime); } if (!ic->info.mime) { mime = _mime_get(buf); if (!mime) /* XXX REMOVE/DEPRECATE ME LATER */ mime = e_fm_mime_filename_get(ic->info.file); if (mime) ic->info.mime = eina_stringshare_add(mime); } if (_e_fm2_file_is_desktop(ic->info.file)) _e_fm2_icon_desktop_load(ic); if (cf) { if (cf->icon.valid) { if (cf->icon.icon) { eina_stringshare_replace(&ic->info.icon, cf->icon.icon); } ic->info.icon_type = cf->icon.type; } if (cf->geom.valid) { ic->saved_pos = EINA_TRUE; ic->x = cf->geom.x; ic->y = cf->geom.y; if (cf->geom.w > 0) ic->w = cf->geom.w; if (cf->geom.h > 0) ic->h = cf->geom.h; _e_fm2_icon_geom_adjust(ic, cf->geom.x, cf->geom.y, cf->geom.w, cf->geom.h, cf->geom.res_w, cf->geom.res_h); } } evas_event_freeze(evas_object_evas_get(ic->sd->obj)); edje_freeze(); switch (_e_fm2_view_mode_get(ic->sd)) { case E_FM2_VIEW_MODE_ICONS: case E_FM2_VIEW_MODE_GRID_ICONS: case E_FM2_VIEW_MODE_CUSTOM_ICONS: case E_FM2_VIEW_MODE_CUSTOM_GRID_ICONS: case E_FM2_VIEW_MODE_CUSTOM_SMART_GRID_ICONS: /* FIXME: need to define icon edjes. here goes: * * fileman/icon/fixed * fileman/icon/variable * fileman/list/fixed * fileman/list/variable * fileman/list_odd/fixed * fileman/list_odd/variable * */ if ((!ic->sd->config->icon.fixed.w) || (!ic->sd->config->icon.fixed.h)) { obj = ic->sd->tmp.obj; if (!obj) { obj = edje_object_add(evas_object_evas_get(ic->sd->obj)); if ((ic->sd->config->icon.fixed.w) && (ic->sd->config->icon.fixed.h)) _e_fm2_theme_edje_object_set(ic->sd, obj, "base/theme/fileman", "icon/fixed"); else _e_fm2_theme_edje_object_set(ic->sd, obj, "base/theme/fileman", "icon/variable"); ic->sd->tmp.obj = obj; } _e_fm2_icon_label_set(ic, obj); obj2 = ic->sd->tmp.obj2; if (!obj2) { obj2 = evas_object_rectangle_add(evas_object_evas_get(ic->sd->obj)); ic->sd->tmp.obj2 = obj2; } /* FIXME: if icons are allowed to have their own size - use it */ evas_object_size_hint_min_set(obj2, _e_fm2_icon_w_get(ic->sd), _e_fm2_icon_h_get(ic->sd)); evas_object_size_hint_max_set(obj2, _e_fm2_icon_w_get(ic->sd), _e_fm2_icon_h_get(ic->sd)); edje_object_part_swallow(obj, "e.swallow.icon", obj2); edje_object_size_min_calc(obj, &mw, &mh); } ic->w = mw; ic->h = mh; if (ic->sd->config->icon.fixed.w) ic->w = _e_fm2_icon_w_get(ic->sd); if (ic->sd->config->icon.fixed.h) ic->h = _e_fm2_icon_h_get(ic->sd); ic->min_w = mw; ic->min_h = mh; break; case E_FM2_VIEW_MODE_LIST: obj = ic->sd->tmp.obj; if (!obj) { obj = edje_object_add(evas_object_evas_get(ic->sd->obj)); // vairable sized list items are pretty usless - ignore. // if (ic->sd->config->icon.fixed.w) _e_fm2_theme_edje_object_set(ic->sd, obj, "base/theme/fileman", "list/fixed"); // else // _e_fm2_theme_edje_object_set(ic->sd, obj, "base/theme/fileman", // "list/variable"); ic->sd->tmp.obj = obj; } _e_fm2_icon_label_set(ic, obj); obj2 = ic->sd->tmp.obj2; if (!obj2) { obj2 = evas_object_rectangle_add(evas_object_evas_get(ic->sd->obj)); ic->sd->tmp.obj2 = obj2; } evas_object_size_hint_min_set(obj2, ic->sd->config->icon.list.w, ic->sd->config->icon.list.h); evas_object_size_hint_max_set(obj2, ic->sd->config->icon.list.w, ic->sd->config->icon.list.h); edje_object_part_swallow(obj, "e.swallow.icon", obj2); edje_object_size_min_calc(obj, &mw, &mh); ic->w = MAX(mw, ic->sd->w); ic->h = mh; ic->min_w = mw; ic->min_h = mh; break; default: break; } edje_thaw(); evas_event_thaw(evas_object_evas_get(ic->sd->obj)); return 1; } static void _e_fm2_icon_free(E_Fm2_Icon *ic) { if (ic->queued) abort(); if (ic->inserted) abort(); if (ic->eio) { eio_file_cancel(ic->eio); ic->eio = NULL; } /* free icon, object data etc. etc. */ if (ic->sd->last_placed == ic) { ic->sd->last_placed = NULL; } if (ic->sd->drop_icon == ic) { /* FIXME: call hide call */ ic->sd->drop_icon = NULL; } _e_fm2_icon_unrealize(ic); if (ic->menu) { e_menu_post_deactivate_callback_set(ic->menu, NULL, NULL); e_object_del(E_OBJECT(ic->menu)); ic->menu = NULL; } if (ic->dialog) { e_object_del(E_OBJECT(ic->dialog)); ic->dialog = NULL; } if (ic->entry_dialog) { e_object_del(E_OBJECT(ic->entry_dialog)); ic->entry_dialog = NULL; } if (ic->entry_widget) _e_fm2_icon_entry_widget_del(ic); if (ic->prop_dialog) { 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) ecore_timer_del(ic->drag.dnd_end_timer); eina_stringshare_del(ic->info.file); eina_stringshare_del(ic->info.mime); eina_stringshare_del(ic->info.label); eina_stringshare_del(ic->info.comment); eina_stringshare_del(ic->info.generic); eina_stringshare_del(ic->info.icon); eina_stringshare_del(ic->info.link); eina_stringshare_del(ic->info.real_link); eina_stringshare_del(ic->info.category); memset(ic, 0xff, sizeof(*ic)); free(ic); } static void _e_fm2_icon_label_click(void *data, Evas_Object *obj EINA_UNUSED, const char *emission EINA_UNUSED, const char *source EINA_UNUSED) { E_Fm2_Icon *ic = data; if (ic->entry_widget || ic->entry_dialog) return; if (!ic->selected) return; if (ecore_loop_time_get() - ic->selected_time < 0.2) return; if (ic->sd->config->view.no_click_rename) return; if (eina_list_count(ic->sd->selected_icons) != 1) return; if (eina_list_data_get(ic->sd->selected_icons) != ic) return; _e_fm2_file_rename(ic, NULL, NULL); } static void _e_fm2_icon_realize(E_Fm2_Icon *ic) { if (ic->realized) goto new_file; /* actually create evas objects etc. */ ic->realized = EINA_TRUE; evas_event_freeze(evas_object_evas_get(ic->sd->obj)); ic->obj = edje_object_add(evas_object_evas_get(ic->sd->obj)); edje_object_freeze(ic->obj); evas_object_smart_member_add(ic->obj, ic->sd->obj); evas_object_stack_below(ic->obj, ic->sd->drop); if (_e_fm2_view_mode_get(ic->sd) == E_FM2_VIEW_MODE_LIST) { const char *stacking; // if (ic->sd->config->icon.fixed.w) // { if (ic->odd) _e_fm2_theme_edje_object_set(ic->sd, ic->obj, "base/theme/widgets", "list_odd/fixed"); else _e_fm2_theme_edje_object_set(ic->sd, ic->obj, "base/theme/widgets", "list/fixed"); stacking = edje_object_data_get(ic->obj, "stacking"); if (stacking) { if (!strcmp(stacking, "below")) evas_object_stack_above(ic->obj, ic->sd->underlay); else if (!strcmp(stacking, "above")) evas_object_stack_below(ic->obj, ic->sd->drop); } // } // else // { // if (ic->odd) // _e_fm2_theme_edje_object_set(ic->sd, ic->obj, "base/theme/widgets", // "list_odd/variable"); // else // _e_fm2_theme_edje_object_set(ic->sd, ic->obj, "base/theme/widgets", // "list/variable"); // } } else { if (ic->sd->config->icon.fixed.w) _e_fm2_theme_edje_object_set(ic->sd, ic->obj, "base/theme/fileman", "icon/fixed"); else _e_fm2_theme_edje_object_set(ic->sd, ic->obj, "base/theme/fileman", "icon/variable"); } _e_fm2_icon_label_set(ic, ic->obj); evas_object_clip_set(ic->obj, ic->sd->clip); evas_object_move(ic->obj, ic->sd->x + ic->x - ic->sd->pos.x, ic->sd->y + ic->y - ic->sd->pos.y); evas_object_resize(ic->obj, ic->w, ic->h); evas_object_event_callback_add(ic->obj, EVAS_CALLBACK_MOUSE_DOWN, _e_fm2_cb_icon_mouse_down, ic); evas_object_event_callback_add(ic->obj, EVAS_CALLBACK_MOUSE_UP, _e_fm2_cb_icon_mouse_up, ic); evas_object_event_callback_add(ic->obj, EVAS_CALLBACK_MOUSE_MOVE, _e_fm2_cb_icon_mouse_move, ic); evas_object_event_callback_add(ic->obj, EVAS_CALLBACK_MOUSE_IN, _e_fm2_cb_icon_mouse_in, ic); evas_object_event_callback_add(ic->obj, EVAS_CALLBACK_MOUSE_OUT, _e_fm2_cb_icon_mouse_out, ic); edje_object_signal_callback_add(ic->obj, "e,action,label,click", "e", _e_fm2_icon_label_click, ic); _e_fm2_icon_icon_set(ic); edje_object_thaw(ic->obj); evas_event_thaw(evas_object_evas_get(ic->sd->obj)); evas_object_show(ic->obj); if (ic->selected) { const char *selectraise; /* FIXME: need new signal to INSTANTLY activate - no anim */ /* FIXME: while listing dirs need to use icons in-place and not * unrealize and re-realize */ edje_object_signal_emit(ic->obj, "e,state,selected", "e"); selectraise = edje_object_data_get(ic->obj, "selectraise"); if ((selectraise) && (!strcmp(selectraise, "on"))) evas_object_stack_below(ic->obj, ic->sd->drop); } if (ic->info.removable) _e_fm2_icon_removable_update(ic); new_file: if (ic->sd->new_file.thread && (!ic->sd->new_file.filename)) { /* we got the file through the scanner :/ */ const char *file = ecore_thread_global_data_find("efm_pending_filename"); if (!e_util_strcmp(ic->info.file, file)) { _e_fm2_file_rename(ic, NULL, NULL); ic->sd->new_file.done = 1; } if (file) ecore_thread_global_data_del("efm_pending_filename"); } if (ic->sd->new_file.filename) { if (ic->info.file == ic->sd->new_file.filename) { _e_fm2_file_rename(ic, NULL, NULL); eina_stringshare_replace(&ic->sd->new_file.filename, NULL); } } } static void _e_fm2_icon_unrealize(E_Fm2_Icon *ic) { if (!ic->realized) return; /* delete evas objects */ ic->realized = EINA_FALSE; evas_object_event_callback_del_full(ic->obj, EVAS_CALLBACK_MOUSE_DOWN, _e_fm2_cb_icon_mouse_down, ic); evas_object_event_callback_del_full(ic->obj, EVAS_CALLBACK_MOUSE_UP, _e_fm2_cb_icon_mouse_up, ic); evas_object_event_callback_del_full(ic->obj, EVAS_CALLBACK_MOUSE_MOVE, _e_fm2_cb_icon_mouse_move, ic); evas_object_event_callback_del_full(ic->obj, EVAS_CALLBACK_MOUSE_IN, _e_fm2_cb_icon_mouse_in, ic); evas_object_event_callback_del_full(ic->obj, EVAS_CALLBACK_MOUSE_OUT, _e_fm2_cb_icon_mouse_out, ic); evas_object_del(ic->obj); ic->obj = NULL; evas_object_del(ic->obj_icon); ic->obj_icon = NULL; } static Eina_Bool _e_fm2_icon_visible(const E_Fm2_Icon *ic) { /* return if the icon is visible */ if ( ((ic->x - ic->sd->pos.x) < (ic->sd->w + OVERCLIP)) && ((ic->x + ic->w - ic->sd->pos.x) > (-OVERCLIP)) && ((ic->y - ic->sd->pos.y) < (ic->sd->h + OVERCLIP)) && ((ic->y + ic->h - ic->sd->pos.y) > (-OVERCLIP)) ) return 1; return 0; } static void _e_fm2_icon_label_set(E_Fm2_Icon *ic, Evas_Object *obj) { char buf[4096], *p; int len; const char *lbl, *type; if (ic->info.label) lbl = ic->info.label; else if ((ic->sd->config->icon.extension.show) || ((!ic->info.link) && (S_ISDIR(ic->info.statinfo.st_mode)))) lbl = ic->info.file; else { /* remove extension. handle double extensions like .tar.gz too * also be fuzzy - up to 4 chars of extn is ok - eg .html but 5 or * more is considered part of the name */ eina_strlcpy(buf, ic->info.file, sizeof(buf)); len = strlen(buf); p = strrchr(buf, '.'); if ((p) && ((len - (p - buf)) < 6)) { *p = 0; len = strlen(buf); p = strrchr(buf, '.'); if ((p) && ((len - (p - buf)) < 6)) *p = 0; } lbl = buf; } type = evas_object_type_get(edje_object_part_object_get(obj, "e.text.label")); if (!e_util_strcmp(type, "textblock")) { p = evas_textblock_text_utf8_to_markup(NULL, lbl); edje_object_part_text_set(obj, "e.text.label", p); free(p); } else edje_object_part_text_set(obj, "e.text.label", lbl); } static Evas_Object * _e_fm2_icon_icon_direct_set(E_Fm2_Icon *ic, Evas_Object *o, Evas_Smart_Cb gen_func, void *data, int force_gen) { Evas_Object *oic; oic = e_fm2_icon_get(evas_object_evas_get(o), ic, gen_func, data, force_gen, NULL); if (oic) { edje_object_part_swallow(o, "e.swallow.icon", oic); evas_object_show(oic); } return oic; } static void _e_fm2_icon_icon_set(E_Fm2_Icon *ic) { if (!ic->realized) return; ic->obj_icon = _e_fm2_icon_icon_direct_set(ic, ic->obj, _e_fm2_cb_icon_thumb_gen, ic, 0); } static void _e_fm2_icon_thumb(const E_Fm2_Icon *ic, Evas_Object *oic, int force) { if ((force) || ((_e_fm2_icon_visible(ic)) && (!ic->sd->queue) && (!ic->sd->sort_idler) && (!ic->sd->listing))) e_thumb_icon_begin(oic); } static void _e_fm2_icon_select(E_Fm2_Icon *ic) { E_Fm2_Icon *prev; if (ic->selected) return; prev = eina_list_last_data_get(ic->sd->selected_icons); if (prev) prev->last_selected = EINA_FALSE; ic->selected = EINA_TRUE; ic->sd->range_selected = NULL; ic->sd->last_selected = ic; ic->sd->selected_icons = eina_list_append(ic->sd->selected_icons, ic); ic->last_selected = EINA_TRUE; ic->selected_time = ecore_loop_time_get(); if (ic->realized) { const char *selectraise; if (ic->sd->iop_icon) _e_fm2_icon_entry_widget_accept(ic->sd->iop_icon); edje_object_signal_emit(ic->obj, "e,state,selected", "e"); evas_object_stack_below(ic->obj, ic->sd->drop); selectraise = edje_object_data_get(ic->obj, "selectraise"); if ((selectraise) && (!strcmp(selectraise, "on"))) evas_object_stack_below(ic->obj, ic->sd->drop); } } static void _e_fm2_icon_deselect(E_Fm2_Icon *ic) { if (!ic->selected) return; ic->selected = EINA_FALSE; ic->last_selected = EINA_FALSE; ic->sd->range_selected = NULL; if (ic->sd->last_selected == ic) ic->sd->last_selected = NULL; ic->sd->selected_icons = eina_list_remove(ic->sd->selected_icons, ic); ic->selected_time = 0.0; if (ic->realized) { const char *stacking, *selectraise; if (ic->entry_widget) _e_fm2_icon_entry_widget_del(ic); edje_object_signal_emit(ic->obj, "e,state,unselected", "e"); stacking = edje_object_data_get(ic->obj, "stacking"); selectraise = edje_object_data_get(ic->obj, "selectraise"); if ((selectraise) && (!strcmp(selectraise, "on"))) { if ((stacking) && (!strcmp(stacking, "below"))) evas_object_stack_above(ic->obj, ic->sd->underlay); } } } static const char * _e_fm2_icon_desktop_url_eval(const char *val) { const char *s; char *path, *p; if (strlen(val) < 6) return NULL; if (strncmp(val, "file:", 5)) return NULL; path = (char *)val + 5; p = e_util_shell_env_path_eval(path); if (!p) return NULL; path = p; while (*path == '/') path++; path--; s = eina_stringshare_add(path); free(p); return s; } E_API const char * e_fm2_desktop_url_eval(const char *val) { return _e_fm2_icon_desktop_url_eval(val); } static void _e_fm2_cb_eio_stat(void *data, Eio_File *handler EINA_UNUSED, const Eina_Stat *st) { E_Fm2_Icon *ic = data; ic->eio = NULL; #define FUCK_EINA_STAT_WHY_IS_IT_NOT_THE_SAME_AS_STAT(member) \ ic->info.statinfo.st_##member = st->member FUCK_EINA_STAT_WHY_IS_IT_NOT_THE_SAME_AS_STAT(dev); FUCK_EINA_STAT_WHY_IS_IT_NOT_THE_SAME_AS_STAT(ino); FUCK_EINA_STAT_WHY_IS_IT_NOT_THE_SAME_AS_STAT(mode); FUCK_EINA_STAT_WHY_IS_IT_NOT_THE_SAME_AS_STAT(nlink); FUCK_EINA_STAT_WHY_IS_IT_NOT_THE_SAME_AS_STAT(uid); FUCK_EINA_STAT_WHY_IS_IT_NOT_THE_SAME_AS_STAT(gid); FUCK_EINA_STAT_WHY_IS_IT_NOT_THE_SAME_AS_STAT(rdev); FUCK_EINA_STAT_WHY_IS_IT_NOT_THE_SAME_AS_STAT(size); FUCK_EINA_STAT_WHY_IS_IT_NOT_THE_SAME_AS_STAT(blksize); FUCK_EINA_STAT_WHY_IS_IT_NOT_THE_SAME_AS_STAT(blocks); FUCK_EINA_STAT_WHY_IS_IT_NOT_THE_SAME_AS_STAT(atime); FUCK_EINA_STAT_WHY_IS_IT_NOT_THE_SAME_AS_STAT(mtime); FUCK_EINA_STAT_WHY_IS_IT_NOT_THE_SAME_AS_STAT(ctime); } static void _e_fm2_cb_eio_err(void *data, Eio_File *handler EINA_UNUSED, int error EINA_UNUSED) { E_Fm2_Icon *ic = data; ic->eio = NULL; } static int _e_fm2_icon_desktop_load(E_Fm2_Icon *ic) { char buf[PATH_MAX]; Efreet_Desktop *desktop; if (!_e_fm2_icon_realpath(ic, buf, sizeof(buf))) return 0; desktop = efreet_desktop_new(buf); // printf("efreet_desktop_new(%s) = %p\n", buf, desktop); if (!desktop) goto error; // if (desktop->type != EFREET_DESKTOP_TYPE_LINK) goto error; ic->info.removable = EINA_FALSE; ic->info.removable_full = EINA_FALSE; ic->info.label = eina_stringshare_add(desktop->name); ic->info.generic = eina_stringshare_add(desktop->generic_name); ic->info.comment = eina_stringshare_add(desktop->comment); ic->info.icon = eina_stringshare_add(desktop->icon); if (desktop->url) ic->info.link = _e_fm2_icon_desktop_url_eval(desktop->url); if (ic->info.link) { if (!ic->eio) ic->eio = eio_file_direct_stat(ic->info.link, _e_fm2_cb_eio_stat, _e_fm2_cb_eio_err, ic); } if (desktop->x) { const char *type; type = eina_hash_find(desktop->x, "X-Enlightenment-Type"); if (type) { if (!strcmp(type, "Mount")) ic->info.mount = EINA_TRUE; else if (!strcmp(type, "Removable")) { ic->info.removable = EINA_TRUE; if ((!e_fm2_device_storage_find(ic->info.link)) && (!e_fm2_device_volume_find(ic->info.link))) { /* delete .desktop for non existing device */ if (ecore_file_remove(buf)) _e_fm2_live_file_del(ic->sd->obj, ic->info.file); else /* ignore */ _e_fm2_file_del(ic->sd->obj, ic->info.file); efreet_desktop_free(desktop); goto error; } } type = eina_hash_find(desktop->x, "X-Enlightenment-Removable-State"); if (type) { if (!strcmp(type, "Full")) ic->info.removable_full = EINA_TRUE; } } } /* FIXME: get category */ ic->info.category = NULL; efreet_desktop_free(desktop); return 1; error: eina_stringshare_del(ic->info.label); eina_stringshare_del(ic->info.comment); eina_stringshare_del(ic->info.generic); eina_stringshare_del(ic->info.icon); eina_stringshare_del(ic->info.link); eina_stringshare_del(ic->info.category); ic->info.label = NULL; ic->info.comment = NULL; ic->info.generic = NULL; ic->info.icon = NULL; ic->info.link = NULL; ic->info.category = NULL; //Hack if (!strncmp(ic->info.file, "|storage_", 9)) ecore_file_unlink(buf); return 0; } /**************************/ static E_Fm2_Region * _e_fm2_region_new(E_Fm2_Smart_Data *sd) { E_Fm2_Region *rg; rg = E_NEW(E_Fm2_Region, 1); rg->sd = sd; return rg; } static void _e_fm2_region_free(E_Fm2_Region *rg) { E_Fm2_Icon *ic; EINA_LIST_FREE(rg->list, ic) ic->region = NULL; free(rg); } static void _e_fm2_region_realize(E_Fm2_Region *rg) { const Eina_List *l; E_Fm2_Icon *ic; if (rg->realized) return; /* actually create evas objects etc. */ rg->realized = 1; edje_freeze(); EINA_LIST_FOREACH(rg->list, l, ic) _e_fm2_icon_realize(ic); EINA_LIST_FOREACH(rg->list, l, ic) { if (ic->selected) evas_object_stack_below(ic->obj, ic->sd->drop); } edje_thaw(); } static void _e_fm2_region_unrealize(E_Fm2_Region *rg) { Eina_List *l; E_Fm2_Icon *ic; if (!rg->realized) return; /* delete evas objects */ rg->realized = 0; edje_freeze(); EINA_LIST_FOREACH(rg->list, l, ic) _e_fm2_icon_unrealize(ic); edje_thaw(); } static int _e_fm2_region_visible(E_Fm2_Region *rg) { /* return if the icon is visible */ if ( ((rg->x - rg->sd->pos.x) < (rg->sd->w + OVERCLIP)) && ((rg->x + rg->w - rg->sd->pos.x) > (-OVERCLIP)) && ((rg->y - rg->sd->pos.y) < (rg->sd->h + OVERCLIP)) && ((rg->y + rg->h - rg->sd->pos.y) > (-OVERCLIP)) ) return 1; return 0; } static void _e_fm2_icon_make_visible(E_Fm2_Icon *ic) { if (_e_fm2_view_mode_get(ic->sd) == E_FM2_VIEW_MODE_LIST) { if ( ((ic->y - ic->sd->pos.y) >= 0) && ((ic->y + ic->h - ic->sd->pos.y) <= (ic->sd->h)) ) return; if ((ic->y - ic->sd->pos.y) < 0) e_fm2_pan_set(ic->sd->obj, ic->sd->pos.x, ic->y); else e_fm2_pan_set(ic->sd->obj, ic->sd->pos.x, ic->y - ic->sd->h + ic->h); } else { Evas_Coord x, y; if ( ((ic->y - ic->sd->pos.y) >= 0) && ((ic->y + ic->h /* + ICON_BOTTOM_SPACE*/ - ic->sd->pos.y) <= (ic->sd->h)) && ((ic->x - ic->sd->pos.x) >= 0) && ((ic->x + ic->w - ic->sd->pos.x) <= (ic->sd->w)) ) return; x = ic->sd->pos.x; if ((ic->x - ic->sd->pos.x) < 0) x = ic->x; else if ((ic->x + ic->w - ic->sd->pos.x) > (ic->sd->w)) x = ic->x + ic->w - ic->sd->w; y = ic->sd->pos.y; if ((ic->y - ic->sd->pos.y) < 0) y = ic->y; else if ((ic->y + ic->h /* + ICON_BOTTOM_SPACE*/ - ic->sd->pos.y) > (ic->sd->h)) y = ic->y + ic->h /* + ICON_BOTTOM_SPACE*/ - ic->sd->h; e_fm2_pan_set(ic->sd->obj, x, y); } evas_object_smart_callback_call(ic->sd->obj, "pan_changed", NULL); } static void _e_fm2_icon_desel_any(Evas_Object *obj) { E_Fm2_Smart_Data *sd; Eina_List *l, *ll; E_Fm2_Icon *ic; sd = evas_object_smart_data_get(obj); if (!sd) return; EINA_LIST_FOREACH_SAFE(sd->selected_icons, l, ll, ic) _e_fm2_icon_deselect(ic); } static E_Fm2_Icon * _e_fm2_icon_first_selected_find(Evas_Object *obj) { E_Fm2_Smart_Data *sd; sd = evas_object_smart_data_get(obj); if (!sd) return NULL; return eina_list_data_get(sd->selected_icons); } static void _e_fm2_icon_sel_first(Evas_Object *obj, Eina_Bool add) { E_Fm2_Smart_Data *sd; E_Fm2_Icon *ic; sd = evas_object_smart_data_get(obj); if (!sd) return; if (!sd->icons) return; if ((!add) || sd->config->selection.single) _e_fm2_icon_desel_any(obj); ic = eina_list_data_get(sd->icons); _e_fm2_icon_select(ic); evas_object_smart_callback_call(sd->obj, "selection_change", NULL); _e_fm2_icon_make_visible(ic); } static void _e_fm2_icon_sel_last(Evas_Object *obj, Eina_Bool add) { E_Fm2_Smart_Data *sd; E_Fm2_Icon *ic; sd = evas_object_smart_data_get(obj); if (!sd) return; if (!sd->icons) return; if ((!add) || sd->config->selection.single) _e_fm2_icon_desel_any(obj); ic = eina_list_last_data_get(sd->icons); _e_fm2_icon_select(ic); evas_object_smart_callback_call(sd->obj, "selection_change", NULL); _e_fm2_icon_make_visible(ic); } static void _e_fm2_icon_sel_any(Evas_Object *obj) { E_Fm2_Smart_Data *sd; E_Fm2_Icon *ic; Eina_List *l; sd = evas_object_smart_data_get(obj); if (!sd) return; if (!sd->icons) return; EINA_LIST_FOREACH(sd->icons, l, ic) if (!ic->selected) _e_fm2_icon_select(ic); } static E_Fm2_Icon * _e_fm2_icon_next_find(Evas_Object *obj, int next, int (*match_func)(E_Fm2_Icon *ic, void *data), void *data) { E_Fm2_Smart_Data *sd; Eina_List *l; E_Fm2_Icon *ic, *ic_next; char view_mode; int x = 0, y = 0, custom = 0; int dist = 0, min = 65535; sd = evas_object_smart_data_get(obj); if (!sd) return NULL; if (!sd->icons) return NULL; l = eina_list_data_find_list(sd->icons, (sd->range_selected) ? sd->range_selected : sd->last_selected); if (!next) return eina_list_data_get(l); if (!l) return (next == 1) ? eina_list_data_get(sd->icons) : eina_list_last_data_get(sd->icons); view_mode = _e_fm2_view_mode_get(sd); if ((view_mode == E_FM2_VIEW_MODE_CUSTOM_SMART_GRID_ICONS) || (view_mode == E_FM2_VIEW_MODE_CUSTOM_GRID_ICONS) || (view_mode == E_FM2_VIEW_MODE_CUSTOM_ICONS)) custom = 1; ic_next = NULL; if (custom || match_func) { ic = eina_list_data_get(l); x = ic->x; y = ic->y; EINA_LIST_FOREACH(sd->icons, l, ic) { if (match_func && !match_func(ic, data)) continue; int dx = (ic->x - x); int dy = (ic->y - y); int sgnx = (dx) ? dx / abs(dx) : 0; if ((next == sgnx) && (abs(dx) >= abs(dy))) { dist = abs(dy) + abs(dx); if (dist < min) { min = dist; ic_next = ic; } } } } else { ic_next = eina_list_data_get((next == 1) ? eina_list_next(l) : eina_list_prev(l)); } return ic_next; } static void _e_fm2_icon_sel_prev(Evas_Object *obj, Eina_Bool add) { E_Fm2_Icon *ic_prev; ic_prev = _e_fm2_icon_next_find(obj, -1, NULL, NULL); if (!ic_prev) return; if ((!add) || ic_prev->sd->config->selection.single) { _e_fm2_icon_desel_any(obj); _e_fm2_icon_select(ic_prev); } else { _e_fm2_icon_range_select(ic_prev); } evas_object_smart_callback_call(obj, "selection_change", NULL); _e_fm2_icon_make_visible(ic_prev); } static void _e_fm2_icon_sel_next(Evas_Object *obj, Eina_Bool add) { E_Fm2_Icon *ic_next; ic_next = _e_fm2_icon_next_find(obj, 1, NULL, NULL); if (!ic_next) return; if ((!add) || ic_next->sd->config->selection.single) { _e_fm2_icon_desel_any(obj); _e_fm2_icon_select(ic_next); } else { _e_fm2_icon_range_select(ic_next); } evas_object_smart_callback_call(obj, "selection_change", NULL); _e_fm2_icon_make_visible(ic_next); } static void _e_fm2_icon_sel_down(Evas_Object *obj, Eina_Bool add) { E_Fm2_Smart_Data *sd; Eina_List *l; E_Fm2_Icon *ic, *ic2, *ic_down; int dist, min = 65535; sd = evas_object_smart_data_get(obj); if (!sd) return; if (!sd->icons) return; ic = (sd->range_selected) ? sd->range_selected : sd->last_selected; if (ic) { ic_down = ic; EINA_LIST_FOREACH(sd->icons, l, ic2) { int dx = (ic2->x - ic->x); int dy = (ic2->y - ic->y); if ((dy > 0) && (abs(dy) > abs(dx))) { dist = abs(dx)+abs(dy); if (dist < min) { min = dist; ic_down = ic2; } } } } else { ic_down = eina_list_data_get(sd->icons); } if ((!add) || ic_down->sd->config->selection.single) { _e_fm2_icon_desel_any(obj); _e_fm2_icon_select(ic_down); } else { _e_fm2_icon_range_select(ic_down); } evas_object_smart_callback_call(sd->obj, "selection_change", NULL); _e_fm2_icon_make_visible(ic_down); } static void _e_fm2_icon_sel_up(Evas_Object *obj, Eina_Bool add) { E_Fm2_Smart_Data *sd; Eina_List *l; E_Fm2_Icon *ic, *ic2, *ic_down; int dist, min = 65535; sd = evas_object_smart_data_get(obj); if (!sd) return; if (!sd->icons) return; ic = (sd->range_selected) ? sd->range_selected : sd->last_selected; if (ic) { ic_down = ic; EINA_LIST_FOREACH(sd->icons, l, ic2) { int dx = (ic2->x - ic->x); int dy = (ic2->y - ic->y); if ((dy < 0) && (abs(dy) > abs(dx))) { dist = abs(dx) + abs(dy); if (dist < min) { min = dist; ic_down = ic2; } } } } else { ic_down = eina_list_last_data_get(sd->icons); } if ((!add) || ic_down->sd->config->selection.single) { _e_fm2_icon_desel_any(obj); _e_fm2_icon_select(ic_down); } else { _e_fm2_icon_range_select(ic_down); } evas_object_smart_callback_call(sd->obj, "selection_change", NULL); _e_fm2_icon_make_visible(ic_down); } static void _e_fm2_icon_range_select(E_Fm2_Icon *ic) { const Eina_List *l; E_Fm2_Icon *ic2; E_Fm2_Icon *last; char view_mode = _e_fm2_view_mode_get(ic->sd); if (!ic->sd->range_selected) { last = ic->sd->last_selected; ic->sd->range_select_anchor = last; } else { last = ic->sd->range_select_anchor; } _e_fm2_icon_desel_any(ic->sd->obj); if ((!last) || (last == ic)) { _e_fm2_icon_select(ic); ic->sd->range_select_anchor = ic; } else if ((view_mode == E_FM2_VIEW_MODE_CUSTOM_SMART_GRID_ICONS) || (view_mode == E_FM2_VIEW_MODE_CUSTOM_GRID_ICONS) || (view_mode == E_FM2_VIEW_MODE_CUSTOM_ICONS)) { int topx = (ic->x <= last->x) ? ic->x : last->x; int boundx = (ic->x < last->x) ? (last->x + last->w) : (ic->x + ic->w); int topy = (ic->y <= last->y) ? ic->y : last->y; int boundy = (ic->y < last->y) ? (last->y + last->h) : (ic->y + ic->h); EINA_LIST_FOREACH(ic->sd->icons, l, ic2) { if ((ic2->x >= topx) && (ic2->x < boundx) && (ic2->y >= topy) && (ic2->y < boundy)) _e_fm2_icon_select(ic2); } } else { int trig = 2; EINA_LIST_FOREACH(ic->sd->icons, l, ic2) { if ((ic2 == last) || (ic2 == ic)) trig--; if ((trig < 2)) _e_fm2_icon_select(ic2); if (!trig) break; } } ic->sd->range_selected = ic; } /* FIXME: prototype */ static void _e_fm2_typebuf_show(Evas_Object *obj) { E_Fm2_Smart_Data *sd; sd = evas_object_smart_data_get(obj); if (!sd) return; if (sd->typebuf.disabled) return; E_FREE(sd->typebuf.buf); sd->typebuf.buf = strdup(""); edje_object_part_text_set(sd->overlay, "e.text.typebuf_label", sd->typebuf.buf); edje_object_signal_emit(sd->overlay, "e,state,typebuf,start", "e"); sd->typebuf_visible = EINA_TRUE; } static void _e_fm2_typebuf_hide(Evas_Object *obj) { E_Fm2_Smart_Data *sd; sd = evas_object_smart_data_get(obj); if (!sd) return; if (!sd->typebuf_visible) return; if (sd->typebuf.setting) return; E_FREE(sd->typebuf.buf); edje_object_signal_emit(sd->overlay, "e,state,typebuf,stop", "e"); eina_stringshare_replace(&sd->typebuf.start, NULL); sd->typebuf_visible = EINA_FALSE; sd->typebuf.wildcard = 0; if (sd->typebuf.timer) ecore_timer_del(sd->typebuf.timer); sd->typebuf.timer = NULL; } #if 0 static void _e_fm2_typebuf_history_prev(Evas_Object *obj) { E_Fm2_Smart_Data *sd; sd = evas_object_smart_data_get(obj); if (!sd) return; /* FIXME: do */ } static void _e_fm2_typebuf_history_next(Evas_Object *obj) { E_Fm2_Smart_Data *sd; sd = evas_object_smart_data_get(obj); if (!sd) return; /* FIXME: do */ } #endif static int _e_fm2_inplace_open(const E_Fm2_Icon *ic) { char buf[PATH_MAX]; if (((!S_ISDIR(ic->info.statinfo.st_mode)) || (ic->info.link && (!S_ISDIR(ic->info.statinfo.st_mode))) || (!ic->sd->config->view.open_dirs_in_place) || (ic->sd->config->view.no_subdir_jump))) return 0; if (!_e_fm2_icon_path(ic, buf, sizeof(buf))) return -1; e_fm2_path_set(ic->sd->obj, ic->info.real_link ? "/" : ic->sd->dev, buf); return 1; } static void _e_fm2_typebuf_run(Evas_Object *obj) { E_Fm2_Icon *ic; _e_fm2_typebuf_hide(obj); ic = _e_fm2_icon_first_selected_find(obj); if (ic) { if (_e_fm2_inplace_open(ic) == 0) evas_object_smart_callback_call(ic->sd->obj, "selected", NULL); } } static int _e_fm2_typebuf_match_func(E_Fm2_Icon *ic, void *data) { char *s, *tb = data; s = strrchr(tb, '/'); if (s) tb = s + 1; return ((ic->info.label) && (e_util_glob_case_match(ic->info.label, tb))) || ((ic->info.file) && (e_util_glob_case_match(ic->info.file, tb))); } static Eina_Bool _e_fm_typebuf_timer_cb(void *data) { E_Fm2_Smart_Data *sd = data; if (!sd) return ECORE_CALLBACK_CANCEL; sd->typebuf.timer = NULL; if (!sd->typebuf_visible) return ECORE_CALLBACK_CANCEL; _e_fm2_typebuf_hide(sd->obj); return ECORE_CALLBACK_CANCEL; } static E_Fm2_Icon * _e_fm2_typebuf_match(Evas_Object *obj, int next) { E_Fm2_Smart_Data *sd; E_Fm2_Icon *ic, *ic_match = NULL; Eina_List *l, *sel = NULL; char *tb; int tblen, x; sd = evas_object_smart_data_get(obj); if (!sd) return NULL; if (sd->typebuf.disabled) return NULL; if (!sd->typebuf.buf) return NULL; if (!sd->icons) return NULL; tblen = strlen(sd->typebuf.buf); if (sd->typebuf.buf[tblen - 1] != '*') { tb = alloca(tblen + 2); memcpy(tb, sd->typebuf.buf, tblen); tb[tblen] = '*'; tb[tblen + 1] = '\0'; } else { size_t blen = strlen(sd->typebuf.buf); tb = memcpy(alloca(blen + 1), sd->typebuf.buf, blen + 1); } if (!next) { EINA_LIST_FOREACH(sd->icons, l, ic) { if (_e_fm2_typebuf_match_func(ic, tb)) { sel = eina_list_append(sel, ic); if (!sd->typebuf.wildcard) break; } } if (eina_list_count(sel) == 1) ic_match = eina_list_data_get(sel); } else { ic_match = _e_fm2_icon_next_find(obj, next, &_e_fm2_typebuf_match_func, tb); } for (x = 0; x < 2; x++) { switch (x) { case 0: if (!sd->selected_icons) continue; if (eina_list_count(sel) != eina_list_count(sd->selected_icons)) continue; EINA_LIST_FOREACH(sd->selected_icons, l, ic) if (!eina_list_data_find(sel, ic)) { x++; break; } if (!x) { /* selections are identical, don't change */ _e_fm2_icon_make_visible(eina_list_data_get(sel)); sel = eina_list_free(sel); x++; break; } EINA_FALLTHROUGH; /* no break */ case 1: _e_fm2_icon_desel_any(obj); if (sel) { if (!ic_match) ic_match = eina_list_data_get(sel); _e_fm2_icon_make_visible(eina_list_data_get(sel)); EINA_LIST_FREE(sel, ic) _e_fm2_icon_select(ic); } evas_object_smart_callback_call(obj, "selection_change", NULL); } } while (0) ; if (sd->typebuf.timer) ecore_timer_loop_reset(sd->typebuf.timer); else sd->typebuf.timer = ecore_timer_loop_add(3.5, _e_fm_typebuf_timer_cb, sd); return ic_match; } static void _e_fm2_typebuf_complete(Evas_Object *obj) { E_Fm2_Smart_Data *sd; E_Fm2_Icon *ic; sd = evas_object_smart_data_get(obj); if (!sd) return; if (sd->typebuf.disabled) return; if ((!sd->typebuf.buf) || (!sd->typebuf.buf[0])) return; ic = _e_fm2_typebuf_match(obj, 0); if (!ic) return; if ((sd->typebuf.buf[0] == '/') || (!memcmp(sd->typebuf.buf, "~/", 2))) { char *buf, *s; size_t size; s = strrchr(sd->typebuf.buf, '/'); if (!s) return; s++; s[0] = 0; size = s - sd->typebuf.buf + strlen(ic->info.file) + 1; buf = malloc(size); if (!buf) return; snprintf(buf, size, "%s%s", sd->typebuf.buf, ic->info.file); free(sd->typebuf.buf); sd->typebuf.buf = buf; edje_object_part_text_set(sd->overlay, "e.text.typebuf_label", sd->typebuf.buf); evas_object_smart_callback_call(sd->obj, "typebuf_changed", sd->typebuf.buf); } else { free(sd->typebuf.buf); sd->typebuf.buf = strdup(ic->info.file); if (!sd->typebuf.buf) { edje_object_part_text_set(sd->overlay, "e.text.typebuf_label", ""); return; } eina_stringshare_replace(&sd->typebuf.start, sd->realpath); edje_object_part_text_set(sd->overlay, "e.text.typebuf_label", sd->typebuf.buf); evas_object_smart_callback_call(sd->obj, "typebuf_changed", sd->typebuf.buf); } } static void _e_fm2_typebuf_char_append(Evas_Object *obj, const char *ch) { E_Fm2_Smart_Data *sd; char *ts; size_t len; if ((!ch) || (!ch[0])) return; sd = evas_object_smart_data_get(obj); if (!sd) return; if (sd->typebuf.disabled) return; if (!sd->typebuf.buf) return; len = strlen(sd->typebuf.buf) + strlen(ch); ts = malloc(len + 1); if (!ts) return; strcpy(ts, sd->typebuf.buf); strcat(ts, ch); free(sd->typebuf.buf); sd->typebuf.buf = ts; if (ch[0] == '*') sd->typebuf.wildcard++; _e_fm2_typebuf_match(obj, 0); if ((!sd->config->view.no_typebuf_set) && (ch[0] == '/')) { if (sd->typebuf.buf[0] == '/') { if (ecore_file_is_dir(sd->typebuf.buf)) { sd->typebuf.setting = EINA_TRUE; e_fm2_path_set(obj, "/", sd->typebuf.buf); sd->typebuf.setting = EINA_FALSE; } } else if (sd->typebuf.buf[0] != '~') { char buf[PATH_MAX]; if (!sd->typebuf.start) sd->typebuf.start = eina_stringshare_ref(sd->realpath); snprintf(buf, sizeof(buf), "%s/%s", sd->typebuf.start, sd->typebuf.buf); if (ecore_file_is_dir(buf)) { sd->typebuf.setting = EINA_TRUE; e_fm2_path_set(obj, "/", buf); sd->typebuf.setting = EINA_FALSE; } } else if (!memcmp(sd->typebuf.buf, "~/", 2)) { char buf[PATH_MAX]; snprintf(buf, sizeof(buf), "%s/%s", getenv("HOME"), sd->typebuf.buf + 2); if (ecore_file_is_dir(buf)) { sd->typebuf.setting = EINA_TRUE; e_fm2_path_set(obj, "~/", sd->typebuf.buf + 1); sd->typebuf.setting = EINA_FALSE; } } } edje_object_part_text_set(sd->overlay, "e.text.typebuf_label", sd->typebuf.buf); evas_object_smart_callback_call(sd->obj, "typebuf_changed", sd->typebuf.buf); } static void _e_fm2_typebuf_char_backspace(Evas_Object *obj) { E_Fm2_Smart_Data *sd; int len, p, dec; sd = evas_object_smart_data_get(obj); if (!sd) return; if (sd->typebuf.disabled) return; if (!sd->typebuf.buf) return; len = strlen(sd->typebuf.buf); if (len == 0) { _e_fm2_typebuf_hide(obj); return; } p = evas_string_char_prev_get(sd->typebuf.buf, len, &dec); if (p < 0) return; sd->typebuf.buf[p] = 0; len--; if (dec == '*') sd->typebuf.wildcard--; if (len) _e_fm2_typebuf_match(obj, 0); if ((!sd->config->view.no_typebuf_set) && (dec == '/')) { if ((len > 1) || (sd->typebuf.buf[0] == '/')) { if (ecore_file_is_dir(sd->typebuf.buf)) { sd->typebuf.setting = EINA_TRUE; e_fm2_path_set(obj, "/", sd->typebuf.buf); sd->typebuf.setting = EINA_FALSE; } } else if ((len > 1) || (sd->typebuf.buf[0] != '~')) { char buf[PATH_MAX]; if (!sd->typebuf.start) sd->typebuf.start = eina_stringshare_ref(sd->realpath); snprintf(buf, sizeof(buf), "%s/%s", sd->typebuf.start, sd->typebuf.buf); if (ecore_file_is_dir(buf)) { sd->typebuf.setting = EINA_TRUE; e_fm2_path_set(obj, "/", buf); sd->typebuf.setting = EINA_FALSE; } } else if (!memcmp(sd->typebuf.buf, "~/", 2)) { char buf[PATH_MAX]; snprintf(buf, sizeof(buf), "%s/%s", getenv("HOME"), sd->typebuf.buf + 2); if (ecore_file_is_dir(buf)) { sd->typebuf.setting = EINA_TRUE; e_fm2_path_set(obj, "~/", sd->typebuf.buf + 1); sd->typebuf.setting = EINA_FALSE; } } } edje_object_part_text_set(sd->overlay, "e.text.typebuf_label", sd->typebuf.buf); evas_object_smart_callback_call(sd->obj, "typebuf_changed", sd->typebuf.buf); } /**************************/ /* FIXME: prototype + reposition + implement */ static void _e_fm2_dnd_drop_configure(Evas_Object *obj) { E_Fm2_Smart_Data *sd; sd = evas_object_smart_data_get(obj); if (!sd) return; if (!sd->drop_icon) return; if (sd->drop_after == -1) { evas_object_move(sd->drop_in, sd->x + sd->drop_icon->x - sd->pos.x, sd->y + sd->drop_icon->y - sd->pos.y); evas_object_resize(sd->drop_in, sd->drop_icon->w, sd->drop_icon->h); } else if (sd->drop_after) { evas_object_move(sd->drop, sd->x + sd->drop_icon->x - sd->pos.x, sd->y + sd->drop_icon->y - sd->pos.y + sd->drop_icon->h - 1); evas_object_resize(sd->drop, sd->drop_icon->w, 2); } else { evas_object_move(sd->drop, sd->x + sd->drop_icon->x - sd->pos.x, sd->y + sd->drop_icon->y - sd->pos.y - 1); evas_object_resize(sd->drop, sd->drop_icon->w, 2); } } /* FIXME: prototype + reposition + implement */ static void _e_fm2_dnd_drop_all_show(Evas_Object *obj) { E_Fm2_Smart_Data *sd; sd = evas_object_smart_data_get(obj); if (!sd) return; if (sd->drop_show) { edje_object_signal_emit(sd->drop, "e,state,unselected", "e"); sd->drop_show = EINA_FALSE; } if (sd->drop_in_show) { edje_object_signal_emit(sd->drop_in, "e,state,unselected", "e"); sd->drop_in_show = EINA_FALSE; } if (!sd->drop_all) { edje_object_signal_emit(sd->overlay, "e,state,drop,start", "e"); sd->drop_all = EINA_TRUE; } sd->drop_icon = NULL; sd->drop_after = EINA_FALSE; } /* FIXME: prototype + reposition + implement */ static void _e_fm2_dnd_drop_all_hide(Evas_Object *obj) { E_Fm2_Smart_Data *sd; sd = evas_object_smart_data_get(obj); if (!sd) return; if (sd->drop_all) { edje_object_signal_emit(sd->overlay, "e,state,drop,stop", "e"); sd->drop_all = EINA_FALSE; } } /* FIXME: prototype + reposition + implement */ static void _e_fm2_dnd_drop_show(E_Fm2_Icon *ic, int after) { int emit = 0; if ((ic->sd->drop_icon == ic) && (ic->sd->drop_after == after)) return; if (((!ic->sd->drop_icon)) || ((after < 0) && (ic->sd->drop_after >= 0)) || ((after >= 0) && (ic->sd->drop_after < 0))) emit = 1; evas_object_smart_callback_call(ic->sd->obj, "dnd_changed", &ic->info); ic->sd->drop_icon = ic; ic->sd->drop_after = after; if (emit) { if (ic->sd->drop_after != -1) { edje_object_signal_emit(ic->sd->drop_in, "e,state,unselected", "e"); edje_object_signal_emit(ic->sd->drop, "e,state,selected", "e"); ic->sd->drop_in_show = EINA_FALSE; ic->sd->drop_show = EINA_TRUE; } else { edje_object_signal_emit(ic->sd->drop, "e,state,unselected", "e"); edje_object_signal_emit(ic->sd->drop_in, "e,state,selected", "e"); ic->sd->drop_in_show = EINA_TRUE; ic->sd->drop_show = EINA_FALSE; } } _e_fm2_dnd_drop_all_hide(ic->sd->obj); _e_fm2_dnd_drop_configure(ic->sd->obj); } /* FIXME: prototype + reposition + implement */ static void _e_fm2_dnd_drop_hide(Evas_Object *obj) { E_Fm2_Smart_Data *sd; sd = evas_object_smart_data_get(obj); if (!sd) return; if (sd->drop_show) { edje_object_signal_emit(sd->drop, "e,state,unselected", "e"); sd->drop_show = EINA_FALSE; } if (sd->drop_in_show) { edje_object_signal_emit(sd->drop_in, "e,state,unselected", "e"); sd->drop_in_show = EINA_FALSE; } sd->drop_icon = NULL; sd->drop_after = EINA_FALSE; } /* FIXME: prototype + reposition + implement */ static Eina_Bool _e_fm2_dnd_type_implemented(const char *type) { const char ***t; for (t = _e_fm2_dnd_types; *t; t++) { if (type == **t) return EINA_TRUE; } return EINA_FALSE; } static void _e_fm2_dnd_finish(Evas_Object *obj, int refresh) { E_Fm2_Smart_Data *sd; E_Fm2_Icon *ic; const Eina_List *l; sd = evas_object_smart_data_get(obj); if (!sd) return; if (!sd->drag) return; sd->drag = EINA_FALSE; EINA_LIST_FOREACH(sd->icons, l, ic) { ic->drag.src = EINA_FALSE; if (ic->drag.hidden) continue; if (ic->obj) evas_object_show(ic->obj); if (ic->obj_icon) evas_object_show(ic->obj_icon); } if (refresh) e_fm2_refresh(obj); } static Eina_Bool _e_fm2_cb_dnd_scroller(E_Fm2_Smart_Data *sd) { int cx = 0, cy = 0; int x = 0, y = 0, w = 0, h = 0; int mx = 0, my = 0; double px = 0.0; #undef EFM_MAX_PIXEL_DRAG #define EFM_MAX_PIXEL_DRAG 25 px = EFM_MAX_PIXEL_DRAG * ecore_animator_frametime_get(); x = y = 500; if (sd->w < 100) w = sd->w / 5; else if (sd->w < 500) w = sd->w / 8; else w = sd->w / 10; if (sd->h < 100) h = sd->h / 5; else if (sd->h < 500) h = sd->h / 8; else h = sd->h / 10; if (sd->dnd_current.x < w) { /* left scroll */ x = lround((-px) * (double)(w - sd->dnd_current.x)); } else if (sd->dnd_current.x > sd->w - w) { /* right scroll */ x = lround((px) * (double)(sd->dnd_current.x - (sd->w - w))); } if (sd->dnd_current.y < h) { /* up scroll */ y = lround((-px) * (double)(h - sd->dnd_current.y)); } else if (sd->dnd_current.y > sd->h - h) { /* down scroll */ y = lround((px) * (double)(sd->dnd_current.y - (sd->h - h))); } if ((x == 500) && (y == 500)) return EINA_TRUE; e_fm2_pan_get(sd->obj, &cx, &cy); e_fm2_pan_max_get(sd->obj, &mx, &my); x = MIN(cx + x, mx); y = MIN(cy + y, my); x = MAX(0, x); y = MAX(0, y); e_fm2_pan_set(sd->obj, x, y); if ((sd->drop_icon) && (!E_INSIDE(sd->dnd_current.x, sd->dnd_current.y, sd->drop_icon->x - sd->drop_icon->sd->pos.x, sd->drop_icon->y - sd->drop_icon->sd->pos.y, sd->drop_icon->w, sd->drop_icon->h))) _e_fm2_dnd_drop_hide(sd->obj); /* * FIXME: this is slow and doesn't do much, need a better way... if (!sd->drop_icon) _e_fm2_cb_dnd_move(sd, NULL, NULL); */ #undef EFM_MAX_PIXEL_DRAG return EINA_TRUE; } static void _e_fm2_cb_dnd_enter(void *data, const char *type, void *event) { E_Event_Dnd_Enter *ev; E_Fm2_Smart_Data *sd = data; if (!_e_fm2_dnd_type_implemented(type)) return; ev = (E_Event_Dnd_Enter *)event; e_drop_handler_action_set(ev->action); if (!sd->dnd_scroller) sd->dnd_scroller = ecore_animator_add((Ecore_Task_Cb)_e_fm2_cb_dnd_scroller, sd); evas_object_smart_callback_call(sd->obj, "dnd_enter", NULL); } static Eina_Bool _e_fm2_cb_dnd_move_helper(E_Fm2_Smart_Data *sd, E_Fm2_Icon *ic, int dx, int dy) { if (!E_INSIDE(dx, dy, ic->x - ic->sd->pos.x, ic->y - ic->sd->pos.y, ic->w, ic->h)) return EINA_FALSE; if (ic->drag.dnd) return EINA_FALSE; if (!S_ISDIR(ic->info.statinfo.st_mode)) { if (ic->sd->drop_icon) _e_fm2_dnd_drop_hide(sd->obj); _e_fm2_dnd_drop_all_show(sd->obj); return EINA_TRUE; } /* if list view */ if (_e_fm2_view_mode_get(ic->sd) == E_FM2_VIEW_MODE_LIST) { /* if there is a .order file - we can re-order files */ if (ic->sd->order_file) { /* if dir: */ if (!ic->sd->config->view.no_subdir_drop) { /* if bottom 25% or top 25% then insert between prev or next */ /* if in middle 50% then put in dir */ if (dy <= (ic->y - ic->sd->pos.y + (ic->h / 4))) _e_fm2_dnd_drop_show(ic, 0); else if (dy > (ic->y - ic->sd->pos.y + ((ic->h * 3) / 4))) _e_fm2_dnd_drop_show(ic, 1); else _e_fm2_dnd_drop_show(ic, -1); } else { /* if top 50% or bottom 50% then insert between prev or next */ if (dy <= (ic->y - ic->sd->pos.y + (ic->h / 2))) _e_fm2_dnd_drop_show(ic, 0); else _e_fm2_dnd_drop_show(ic, 1); } } /* if we are over subdirs or files */ else { /* * if it's over a dir - hilight as it will be dropped info * FIXME: should there be a separate highlighting function for files? * */ if (!ic->sd->config->view.no_subdir_drop) _e_fm2_dnd_drop_show(ic, -1); } } else { /* if it's over a dir - hilight as it will be dropped in */ if (!ic->sd->config->view.no_subdir_drop) _e_fm2_dnd_drop_show(ic, -1); } return EINA_TRUE; } static void _e_fm2_cb_dnd_move(void *data, const char *type, void *event) { E_Fm2_Smart_Data *sd; E_Event_Dnd_Move *ev; E_Fm2_Icon *ic; Eina_List *l; int dx, dy; sd = data; /* also called from the scroll animator with only the first param */ if (type && (!_e_fm2_dnd_type_implemented(type))) return; ev = (E_Event_Dnd_Move *)event; if (ev) { dx = ev->x - sd->x; dy = ev->y - sd->y; sd->dnd_current.x = dx, sd->dnd_current.y = dy; e_drop_handler_action_set(ev->action); } else dx = sd->dnd_current.x, dy = sd->dnd_current.y; EINA_LIST_FOREACH(sd->icons, l, ic) if (_e_fm2_cb_dnd_move_helper(sd, ic, dx, dy)) return; /* FIXME: not over icon - is it within the fm view? if so drop there */ if (E_INSIDE(dx, dy, 0, 0, sd->w, sd->h)) { #if 0 //this is broken since we don't allow custom list sorting /* if listview - it is now after last file */ if (_e_fm2_view_mode_get(sd) == E_FM2_VIEW_MODE_LIST) { /* if there is a .order file - we can re-order files */ if (sd->order_file) { ic = eina_list_last_data_get(sd->icons); if (ic) { if (!ic->drag.dnd) _e_fm2_dnd_drop_show(ic, 1); else _e_fm2_dnd_drop_all_show(sd->obj); } else _e_fm2_dnd_drop_all_show(sd->obj); } else _e_fm2_dnd_drop_all_show(sd->obj); } else #endif _e_fm2_dnd_drop_all_show(sd->obj); return; } /* outside fm view */ _e_fm2_dnd_drop_hide(sd->obj); } static void _e_fm2_cb_dnd_leave(void *data, const char *type, void *event EINA_UNUSED) { E_Fm2_Smart_Data *sd; sd = data; if (!_e_fm2_dnd_type_implemented(type)) return; _e_fm2_dnd_drop_hide(sd->obj); _e_fm2_dnd_drop_all_hide(sd->obj); if (sd->dnd_scroller) ecore_animator_del(sd->dnd_scroller); sd->dnd_scroller = NULL; sd->dnd_current.x = sd->dnd_current.y = 0; evas_object_smart_callback_call(sd->obj, "dnd_leave", NULL); /* NOTE: DO NOT PERFORM ANY OPERATIONS USING sd AT THIS POINT! * things use this callback to delete the efm object */ } static void _e_fm_file_reorder(const char *file, const char *dst, const char *relative, int after) { unsigned int length = strlen(file) + 1 + strlen(dst) + 1 + strlen(relative) + 1 + sizeof(after); char *data, *p; data = alloca(length); if (!data) return; p = data; #define P(s) memcpy(p, s, strlen(s) + 1); p += strlen(s) + 1 P(file); P(dst); P(relative); #undef P memcpy(p, &after, sizeof(int)); _e_fm_client_send_new(E_FM_OP_REORDER, data, length); } static void _e_fm_icon_save_position(const char *file, Evas_Coord x, Evas_Coord y, Evas_Coord w, Evas_Coord h) { E_Fm2_Custom_File *cf, new; if (!file) return; cf = e_fm2_custom_file_get(file); if (!cf) { memset(&new, 0, sizeof(E_Fm2_Custom_File)); cf = &new; } cf->geom.x = x; cf->geom.y = y; cf->geom.res_w = w; cf->geom.res_h = h; cf->geom.valid = 1; e_fm2_custom_file_set(file, cf); 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 */ #ifndef HAVE_WAYLAND_ONLY 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; } #endif 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 EINA_UNUSED, E_Menu_Item *mi EINA_UNUSED) { char *args; 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); } static void _e_fm_drop_menu_move_cb(void *data, E_Menu *m EINA_UNUSED, E_Menu_Item *mi EINA_UNUSED) { char *args; 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); } static void _e_fm_drop_menu_symlink_cb(void *data, E_Menu *m EINA_UNUSED, E_Menu_Item *mi EINA_UNUSED) { char *args; 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); } static void _e_fm_drop_menu_abort_cb(void *data, E_Menu *m EINA_UNUSED, E_Menu_Item *mi EINA_UNUSED) { free(evas_object_data_del(data, "drop_menu_data")); } static void _e_fm_drop_menu_free(void *data) { Evas_Object *e_fm; e_fm = e_object_data_get(data); if (!e_fm) return; 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 = NULL; 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); #ifndef HAVE_WAYLAND_ONLY 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); #endif } 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) { E_Fm2_Smart_Data *sd = data; E_Event_Dnd_Drop *ev = event; E_Fm2_Icon *ic = NULL; Eina_List *fsel, *l, *ll, *il, *isel = NULL; char buf[PATH_MAX]; const char *fp; Evas_Coord ox, oy; Evas_Object *obj; int adjust_icons = 0; char dirpath[PATH_MAX]; char *args = NULL; size_t size = 0; size_t length = 0; Eina_Bool lnk = EINA_FALSE, memerr = EINA_FALSE, mnt = EINA_FALSE; E_Fm2_Device_Mount_Op *mop = NULL; if (!_e_fm2_dnd_type_implemented(type)) return; if (type == _e_fm2_mime_xmozurl) { const char **name, *s; Efreet_Desktop *desktop; E_Dnd_X_Moz_Url *moz = ev->data; unsigned int x = 0; EINA_INARRAY_FOREACH(moz->link_names, name) { int p; s = *name; for (p = 0; p < 7; p++) { Eina_Bool done = EINA_FALSE; if (!s[p]) break; if ((s[p] == ':') && (s[p + 1] == '/')) { s = ecore_file_file_get(s); done = EINA_TRUE; } if (done) break; } if (!s[0]) s = ecore_file_file_get(*name); if (!s) { s = *(char**)eina_inarray_nth(moz->links, x); s = ecore_file_file_get(s); } /* FIXME: should this filename be sanitized somehow? */ if (sd->drop_icon && sd->drop_after == -1) { //into drop_icon if (S_ISDIR(sd->drop_icon->info.statinfo.st_mode)) { if (sd->drop_icon->info.link) snprintf(dirpath, sizeof(dirpath), "%s/Link to %s.desktop", sd->drop_icon->info.link, s); else snprintf(dirpath, sizeof(dirpath), "%s/%s/Link to %s.desktop", sd->realpath, sd->drop_icon->info.file, s); } else snprintf(buf, sizeof(buf), "%s/Link to %s.desktop", sd->realpath, s); } else snprintf(buf, sizeof(buf), "%s/Link to %s.desktop", sd->realpath, s); if (ecore_file_exists(buf)) { e_util_dialog_show(_("Error"), _("A link to the requested URL already exists!")); continue; } desktop = efreet_desktop_empty_new(buf); desktop->type = EFREET_DESKTOP_TYPE_LINK; snprintf(buf, sizeof(buf), "Link to %s", *name); desktop->name = strdup(buf); desktop->icon = strdup("text-html"); desktop->url = strdup(*(char**)eina_inarray_nth(moz->links, x)); efreet_desktop_save(desktop); efreet_desktop_free(desktop); x++; } return; } fsel = e_fm2_uri_path_list_get(ev->data); fp = eina_list_data_get(fsel); if (fp && sd->realpath && ((sd->drop_all) || (!sd->drop_icon))) { const char *f; /* if we're dropping into a link_drop view, we need to stop here so we * don't accidentally replace an original file with a link! */ f = ecore_file_file_get(fp); if ((((f - fp - 1 == 0) && (!strcmp(sd->realpath, "/"))) || ((f - fp - 1 > 0) && (!strncmp(sd->realpath, fp, f - fp - 1)))) && ((size_t)(f - fp - 1) == strlen(sd->realpath))) { #ifndef HAVE_WAYLAND_ONLY if ((e_drop_handler_action_get() == ECORE_X_ATOM_XDND_ACTION_MOVE) || (sd->config->view.link_drop)) { lnk = EINA_TRUE; if (_e_fm2_view_mode_get(sd) != E_FM2_VIEW_MODE_CUSTOM_ICONS) goto end; memerr = EINA_TRUE; // prevent actual file move op } #endif } } if (!fsel) { #ifndef HAVE_WAYLAND_ONLY if (e_drop_handler_action_get() == ECORE_X_ATOM_XDND_ACTION_COPY) { /* most likely someone is trying to dnd some text to us */ _e_fm2_new_file(sd, NULL, NULL); EINA_LIST_FOREACH(ev->data, l, fp) isel = eina_list_append(isel, strdup(fp)); ecore_thread_global_data_add("efm_text_uri_list", isel, (Eina_Free_Cb)e_util_string_list_free, 0); } #endif /* no files, abort! */ return; } isel = _e_fm2_uri_selected_icon_list_get(fsel); ox = 0; oy = 0; EINA_LIST_FOREACH(isel, l, ic) { if (!ic) continue; if (ic->drag.src) { ox = ic->x; oy = ic->y; break; } } /* note - logic. * if drop file prefix path matches extra_file_source then it can be * and indirect link - dont MOVE the file just add filename to list. * if not literally move the file in. if move can't work - try a copy. * on a literal move find any fm views for the dir of the dropped file * and refresh those, as well as refresh current target fm dir */ if (sd->drop_all) /* drop arbitrarily into the dir */ { Evas_Coord x, y; /* move file into this fm dir */ for (ll = fsel, il = isel; ll; ll = eina_list_next(ll), il = eina_list_next(il)) { ic = eina_list_data_get(il); fp = eina_list_data_get(ll); if (!fp) continue; if ((ic) && (_e_fm2_view_mode_get(sd) == E_FM2_VIEW_MODE_CUSTOM_ICONS)) { /* dnd doesn't tell me all the co-ords of the icons being dragged so i can't place them accurately. * need to fix this. ev->data probably needs to become more compelx than a list of url's */ x = ev->x + (ic->x - ox) - ic->drag.x + sd->pos.x - sd->x; y = ev->y + (ic->y - oy) - ic->drag.y + sd->pos.y - sd->y; if (x < 0) x = 0; if (y < 0) y = 0; if (sd->config->view.fit_custom_pos) { if ((x + ic->w) > sd->w) x = (sd->w - ic->w); if ((y + ic->h) > sd->h) y = (sd->h - ic->h); } if (ic->sd == sd) { ic->x = x; ic->y = y; ic->saved_pos = EINA_TRUE; adjust_icons = 1; } snprintf(buf, sizeof(buf), "%s/%s", sd->realpath, ecore_file_file_get(fp)); _e_fm_icon_save_position(buf, x, y, sd->w, sd->h); } if (!memerr) { args = e_util_string_append_quoted(args, &size, &length, fp); if (!args) memerr = EINA_TRUE; else { args = e_util_string_append_char(args, &size, &length, ' '); if (!args) memerr = EINA_TRUE; else if (ic) ic->drag.hidden = EINA_TRUE; } } eina_stringshare_del(fp); } if (adjust_icons) { sd->max.w = 0; sd->max.h = 0; EINA_LIST_FOREACH(sd->icons, l, ic) { if ((ic->x + ic->w) > sd->max.w) sd->max.w = ic->x + ic->w; if ((ic->y + ic->h) > sd->max.h) sd->max.h = ic->y + ic->h; } _e_fm2_obj_icons_place(sd); evas_object_smart_callback_call(sd->obj, "changed", NULL); } if (!memerr) args = e_util_string_append_quoted(args, &size, &length, sd->realpath); } else if (sd->drop_icon) /* into or before/after an icon */ { if (sd->drop_after == -1) /* put into subdir/file in icon */ { /* move file into dir that this icon is for */ for (ll = fsel, il = isel; ll && il; ll = eina_list_next(ll), il = eina_list_next(il)) { fp = eina_list_data_get(ll); if (!fp) continue; if (!memerr) { args = e_util_string_append_quoted(args, &size, &length, fp); if (!args) memerr = EINA_TRUE; else { args = e_util_string_append_char(args, &size, &length, ' '); if (!args) memerr = EINA_TRUE; else ic->drag.hidden = EINA_TRUE; } } eina_stringshare_del(fp); } if (!memerr) { while (sd->drop_icon->info.removable) { /* we're dropping onto a device * cross your fingers and hope for good luck */ E_Volume *vol; const char *mp; 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_loop_reset(sd->drop_icon->mount_timer); else sd->drop_icon->mount_timer = ecore_timer_loop_add(15., (Ecore_Task_Cb)_e_fm2_cb_dnd_selection_notify_post_mount_timer, sd->drop_icon); #ifndef HAVE_WAYLAND_ONLY 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); #endif 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 if (sd->realpath) { if (_e_fm2_view_mode_get(sd) == E_FM2_VIEW_MODE_LIST && sd->order_file) /* list */ { for (ll = fsel, il = isel; ll && il; ll = eina_list_next(ll), il = eina_list_next(il)) { fp = eina_list_data_get(ll); if (!fp) continue; if (!memerr) { snprintf(buf, sizeof(buf), "%s/%s", sd->realpath, ecore_file_file_get(fp)); args = e_util_string_append_quoted(args, &size, &length, fp); if (!args) memerr = EINA_TRUE; else { args = e_util_string_append_char(args, &size, &length, ' '); if (!args) memerr = EINA_TRUE; else ic->drag.hidden = EINA_TRUE; } } _e_fm_file_reorder(ecore_file_file_get(fp), sd->realpath, sd->drop_icon->info.file, sd->drop_after); eina_stringshare_del(fp); } if (!memerr) { args = e_util_string_append_quoted(args, &size, &length, sd->realpath); if (!args) memerr = EINA_TRUE; } } else { for (ll = fsel, il = isel; ll && il; ll = eina_list_next(ll), il = eina_list_next(il)) { fp = eina_list_data_get(ll); if (!fp) continue; if (!memerr) { args = e_util_string_append_quoted(args, &size, &length, fp); if (!args) memerr = EINA_TRUE; else { args = e_util_string_append_char(args, &size, &length, ' '); if (!args) memerr = EINA_TRUE; else ic->drag.hidden = EINA_TRUE; } } eina_stringshare_del(fp); } if (!memerr) { args = e_util_string_append_quoted(args, &size, &length, sd->realpath); if (!args) memerr = EINA_TRUE; } } } } if (args) { Eina_Bool do_lnk = EINA_FALSE, do_move = EINA_FALSE, do_copy = EINA_FALSE; #ifndef HAVE_WAYLAND_ONLY if (e_drop_handler_action_get() == ECORE_X_ATOM_XDND_ACTION_COPY) { lnk = EINA_TRUE; if (sd->config->view.link_drop && (!sd->drop_icon)) do_lnk = EINA_TRUE; else do_copy = EINA_TRUE; } else if (e_drop_handler_action_get() == ECORE_X_ATOM_XDND_ACTION_MOVE) { if (sd->config->view.link_drop) lnk = do_lnk = EINA_TRUE; else 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)) 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); #endif 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); E_LIST_FOREACH(isel, _e_fm2_cb_drag_finished_show); } if (((!mnt) || (!mop)) && (do_lnk || do_copy || do_move)) free(args); } end: _e_fm2_dnd_drop_hide(sd->obj); _e_fm2_dnd_drop_all_hide(sd->obj); _e_fm2_list_walking++; EINA_LIST_FOREACH(_e_fm2_list, l, obj) { if ((_e_fm2_list_walking > 0) && (eina_list_data_find(_e_fm2_list_remove, obj))) continue; _e_fm2_dnd_finish(obj, 0); } _e_fm2_list_walking--; if (_e_fm2_list_walking == 0) { EINA_LIST_FREE(_e_fm2_list_remove, obj) { _e_fm2_list = eina_list_remove(_e_fm2_list, obj); } } eina_list_free(fsel); EINA_LIST_FREE(isel, ic) if (ic->drag.dnd_end_timer && (!lnk)) { ecore_timer_del(ic->drag.dnd_end_timer); ic->drag.dnd_end_timer = NULL; } } static void _e_fm2_mouse_2_handler(E_Fm2_Icon *ic, void *evas_event) { int multi_sel = 1; Eina_List *l; E_Fm2_Icon *ic2; if (!evas_event) return; if (ic->sd->config->selection.single) multi_sel = 0; EINA_LIST_FOREACH(ic->sd->icons, l, ic2) ic2->last_selected = 0; if (ic->selected) _e_fm2_icon_deselect(ic); else { if (!multi_sel) { ic2 = eina_list_data_get(ic->sd->selected_icons); if (ic2) _e_fm2_icon_deselect(ic2); } _e_fm2_icon_select(ic); _e_fm2_icon_make_visible(ic); ic->last_selected = EINA_TRUE; } evas_object_smart_callback_call(ic->sd->obj, "selection_change", NULL); } /* FIXME: prototype */ static int _e_fm2_mouse_1_handler(E_Fm2_Icon *ic, int up, void *evas_event) { Evas_Event_Mouse_Down *ed = NULL; Evas_Event_Mouse_Up *eu = NULL; Evas_Modifier *modifiers; int multi_sel = 0, range_sel = 0, sel_change = 0; static unsigned int down_timestamp = 0; if (!evas_event) return 0; if (!up) { ed = evas_event; modifiers = ed->modifiers; } else { eu = evas_event; modifiers = eu->modifiers; } if (ed && ic->sd->config->view.single_click_delay) down_timestamp = ed->timestamp; if (!ic->sd->config->selection.windows_modifiers) { if (evas_key_modifier_is_set(modifiers, "Shift")) range_sel = 1; else if (evas_key_modifier_is_set(modifiers, "Control")) multi_sel = 1; } else { if (evas_key_modifier_is_set(modifiers, "Control")) range_sel = 1; else if (evas_key_modifier_is_set(modifiers, "Shift")) multi_sel = 1; } if (ic->sd->config->selection.single) { multi_sel = 0; range_sel = 0; } /* * On mouse up, check if we want to do in place open */ if ((eu) && (!multi_sel) && (!range_sel) && (ic->sd->config->view.single_click) && ((eu->timestamp - down_timestamp) > ic->sd->config->view.single_click_delay)) { if (_e_fm2_inplace_open(ic) == 1) return 1; } if (range_sel) { if (!up) _e_fm2_icon_range_select(ic); } else if ((!multi_sel) && ((up) || ((!up) && (!ic->selected)))) { const Eina_List *l; E_Fm2_Icon *ic2; /* desel others */ EINA_LIST_FOREACH(ic->sd->icons, l, ic2) { if (ic2 != ic) { if (ic2->selected) { _e_fm2_icon_deselect(ic2); sel_change = 1; } } } } else { if (!up) { const Eina_List *l; E_Fm2_Icon *ic2; EINA_LIST_FOREACH(ic->sd->icons, l, ic2) ic2->last_selected = 0; } } if ((multi_sel) && (ic->selected)) { if ((up) && (!ic->drag.dnd) && (!ic->down_sel)) { sel_change = 1; _e_fm2_icon_deselect(ic); } } else { if (!up) { if (!ic->selected) sel_change = EINA_TRUE; _e_fm2_icon_select(ic); _e_fm2_icon_make_visible(ic); ic->down_sel = EINA_TRUE; ic->last_selected = EINA_TRUE; } } if (sel_change) evas_object_smart_callback_call(ic->sd->obj, "selection_change", NULL); if (ic->sd->config->view.single_click && (!range_sel) && (!multi_sel)) { if (eu && (eu->timestamp - down_timestamp) > ic->sd->config->view.single_click_delay) { int icon_pos_x = ic->x + ic->sd->x - ic->sd->pos.x; int icon_pos_y = ic->y + ic->sd->y - ic->sd->pos.y; if (eu->output.x >= icon_pos_x && eu->output.x <= (icon_pos_x + ic->w) && eu->output.y >= icon_pos_y && eu->output.y <= (icon_pos_y + ic->h)) evas_object_smart_callback_call(ic->sd->obj, "selected", NULL); } } return 0; } static void _e_fm2_cb_icon_mouse_down(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info) { Evas_Event_Mouse_Down *ev; E_Fm2_Icon *ic; ic = data; ev = event_info; if (ic->entry_widget) return; _e_fm2_typebuf_hide(ic->sd->obj); if ((ev->button == 1) && (ev->flags & EVAS_BUTTON_DOUBLE_CLICK)) { /* if its a directory && open dirs in-place is set then change the dir * to be the dir + file */ if (ic->sd->config->view.single_click) return; if (_e_fm2_inplace_open(ic) == 0) evas_object_smart_callback_call(ic->sd->obj, "selected", NULL); /* if its in file selector mode then signal that a selection has * taken place and dont do anything more */ /* do the below per selected file */ /* if its a directory and open dirs in-place is not set, then * signal owner that a new dir should be opened */ /* if its a normal file - do what the mime type says to do with * that file type */ } else if (ev->button < 3) { if (ev->button == 1) { if ((ic->sd->eobj || ic->sd->win)) { ic->drag.x = ev->output.x - ic->x - ic->sd->x + ic->sd->pos.x; ic->drag.y = ev->output.y - ic->y - ic->sd->y + ic->sd->pos.y; ic->drag.start = EINA_TRUE; ic->drag.dnd = EINA_FALSE; ic->drag.src = EINA_TRUE; } _e_fm2_mouse_1_handler(ic, 0, ev); } else _e_fm2_mouse_2_handler(ic, ev); } else if (ev->button == 3) { if (!ic->selected) { if (_e_fm2_mouse_1_handler(ic, 0, ev)) return; } _e_fm2_icon_menu(ic, ic->sd->obj, ev->timestamp); } } static void _e_fm2_cb_icon_mouse_up(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info) { Evas_Event_Mouse_Up *ev = event_info; E_Fm2_Icon *ic = data; if (ic->sd->selecting) return; edje_object_message_signal_process(ic->obj); edje_object_message_signal_process(ic->obj); _e_fm2_typebuf_hide(ic->sd->obj); if ((ev->button == 1) && (!ic->drag.dnd)) { if (!(ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD)) { if (!ic->entry_widget) { if (_e_fm2_mouse_1_handler(ic, 1, ev)) return; } } ic->drag.start = EINA_FALSE; ic->drag.dnd = EINA_FALSE; ic->drag.src = EINA_FALSE; ic->down_sel = EINA_FALSE; } } static Eina_Bool _e_fm2_cb_drag_finished_show(E_Fm2_Icon *ic) { ic->drag.dnd = ic->drag.src = EINA_FALSE; if (ic->obj) evas_object_show(ic->obj); if (ic->obj_icon) evas_object_show(ic->obj_icon); ic->drag.dnd_end_timer = NULL; return EINA_FALSE; } static void _e_fm2_cb_drag_finished(E_Drag *drag, int dropped EINA_UNUSED) { E_Fm2_Uri *uri; const char *p; char buf[PATH_MAX * 3 + 7]; Eina_List *fms; Evas_Object *fm; int i; memset(buf, 0, sizeof(buf)); for (p = drag->data, i = 0; p && *p != '\0'; p++, i++) { if (*p == '\r') { p++; i = -1; uri = _e_fm2_uri_parse(buf); memset(buf, 0, sizeof(buf)); if (!uri) continue; fms = _e_fm2_file_fm2_find(uri->path); if (fms) { const char *file; E_Fm2_Icon *ic; file = ecore_file_file_get(uri->path); if (file) { EINA_LIST_FREE(fms, fm) { ic = _e_fm2_icon_find(fm, file); if (ic && ic->drag.dnd) { ic->drag.dnd = EINA_FALSE; if (ic->sd->dnd_scroller) ecore_animator_del(ic->sd->dnd_scroller); ic->sd->dnd_scroller = NULL; if (ic->drag.dnd_end_timer) ecore_timer_loop_reset(ic->drag.dnd_end_timer); else ic->drag.dnd_end_timer = ecore_timer_loop_add(0.2, (Ecore_Task_Cb)_e_fm2_cb_drag_finished_show, ic); /* NOTE: * do not touch ic after this callback; it's possible that it may have been deleted */ evas_object_smart_callback_call(ic->sd->obj, "dnd_end", &ic->info); break; } } eina_list_free(fms); } } if (uri->hostname) eina_stringshare_del(uri->hostname); eina_stringshare_del(uri->path); E_FREE(uri); } else buf[i] = *p; } free(drag->data); } static void _e_fm_drag_key_down_cb(E_Drag *drag, Ecore_Event_Key *e) { #ifndef HAVE_WAYLAND_ONLY if (!strncmp(e->keyname, "Alt", 3)) { ecore_x_dnd_source_action_set(ECORE_X_ATOM_XDND_ACTION_ASK); e_drop_handler_action_set(ECORE_X_ATOM_XDND_ACTION_ASK); edje_object_signal_emit(drag->object, "e,state,ask", "e"); } else if (!strncmp(e->key, "Shift", 5)) { if (e->modifiers == ECORE_EVENT_MODIFIER_CTRL) { ecore_x_dnd_source_action_set(ECORE_X_ATOM_XDND_ACTION_ASK); e_drop_handler_action_set(ECORE_X_ATOM_XDND_ACTION_ASK); edje_object_signal_emit(drag->object, "e,state,ask", "e"); } else { ecore_x_dnd_source_action_set(ECORE_X_ATOM_XDND_ACTION_MOVE); e_drop_handler_action_set(ECORE_X_ATOM_XDND_ACTION_MOVE); edje_object_signal_emit(drag->object, "e,state,move", "e"); } } else if (!strncmp(e->key, "Control", 7)) { if (e->modifiers == ECORE_EVENT_MODIFIER_SHIFT) { ecore_x_dnd_source_action_set(ECORE_X_ATOM_XDND_ACTION_ASK); e_drop_handler_action_set(ECORE_X_ATOM_XDND_ACTION_ASK); edje_object_signal_emit(drag->object, "e,state,ask", "e"); } else { ecore_x_dnd_source_action_set(ECORE_X_ATOM_XDND_ACTION_COPY); e_drop_handler_action_set(ECORE_X_ATOM_XDND_ACTION_COPY); edje_object_signal_emit(drag->object, "e,state,copy", "e"); } } #endif } static void _e_fm_drag_key_up_cb(E_Drag *drag, Ecore_Event_Key *e) { #ifndef HAVE_WAYLAND_ONLY Ecore_X_Atom act = ECORE_X_ATOM_XDND_ACTION_MOVE; /* Default action would be move. ;) */ if (!strncmp(e->key, "Alt", 3)) act = ECORE_X_ATOM_XDND_ACTION_MOVE; else if (!strncmp(e->key, "Shift", 5)) act = ECORE_X_ATOM_XDND_ACTION_MOVE; else if (!strncmp(e->key, "Control", 7)) act = ECORE_X_ATOM_XDND_ACTION_MOVE; ecore_x_dnd_source_action_set(act); e_drop_handler_action_set(act); #endif edje_object_signal_emit(drag->object, "e,state,move", "e"); } static void _e_fm2_cb_icon_mouse_in(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info) { Evas_Event_Mouse_In *ev; E_Fm2_Icon *ic; ic = data; ev = event_info; if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) return; if (e_comp_util_mouse_grabbed()) return; evas_object_smart_callback_call(ic->sd->obj, "icon_mouse_in", &ic->info); } static void _e_fm2_cb_icon_mouse_out(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info) { Evas_Event_Mouse_Out *ev; E_Fm2_Icon *ic; ic = data; ev = event_info; if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) return; evas_object_smart_callback_call(ic->sd->obj, "icon_mouse_out", &ic->info); } static void _e_fm2_cb_icon_mouse_move(void *data, Evas *e, Evas_Object *obj EINA_UNUSED, void *event_info) { Evas_Event_Mouse_Move *ev; E_Fm2_Icon *ic; E_Fm2_Icon_Info *ici; ic = data; ev = event_info; if (ic->entry_widget) return; if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) return; if (ic->sd->selecting) { /* happens when clicking precisely between icons */ ic->drag.x = ic->drag.y = 0; ic->drag.start = ic->drag.dnd = ic->drag.src = EINA_FALSE; return; } if ((ic->drag.start) && (ic->sd->eobj || ic->sd->win)) { int dx, dy; dx = ev->cur.output.x - (ic->drag.x + ic->x + ic->sd->x - ic->sd->pos.x); dy = ev->cur.output.y - (ic->drag.y + ic->y + ic->sd->y - ic->sd->pos.y); if (((dx * dx) + (dy * dy)) > (e_config->drag_resist * e_config->drag_resist)) { E_Drag *d; Evas_Object *o = NULL, *o2 = NULL, *layout = NULL; const char *drag_types[] = { "text/uri-list" }, *real_path; char buf[PATH_MAX + 8], *p, *sel = NULL; Eina_Binbuf *sbuf; Eina_List *sl, *icons = NULL; size_t sel_length = 0, p_offset, p_length; int wx = 0, wy = 0; ic->sd->drag = EINA_TRUE; ic->drag.start = EINA_FALSE; real_path = e_fm2_real_path_get(ic->sd->obj); p_offset = eina_strlcpy(buf, real_path, sizeof(buf)); if ((p_offset < 1) || (p_offset >= (int)sizeof(buf) - 2)) return; if (buf[p_offset - 1] != '/') { buf[p_offset] = '/'; p_offset++; } p = buf + p_offset; p_length = sizeof(buf) - p_offset - 1; sl = e_fm2_selected_list_get(ic->sd->obj); if (eina_list_count(sl) > 1) { layout = e_layout_add(e_comp->evas); e_layout_freeze(layout); e_layout_virtual_size_set(layout, ic->sd->w, ic->sd->h); } sbuf = eina_binbuf_new(); EINA_LIST_FREE(sl, ici) { const char *s; size_t s_len; if (eina_strlcpy(p, ici->file, p_length) >= p_length) continue; s = _e_fm2_uri_escape(buf); if (!s) continue; s_len = strlen(s); eina_binbuf_append_length(sbuf, (void*)s, s_len); eina_binbuf_append_length(sbuf, (void*)"\r\n", 2); eina_stringshare_del(s); ici->ic->drag.dnd = EINA_TRUE; if (ici->ic->obj) evas_object_hide(ici->ic->obj); if (ici->ic->obj_icon) evas_object_hide(ici->ic->obj_icon); o = edje_object_add(e_comp->evas); if (_e_fm2_view_mode_get(ici->ic->sd) == E_FM2_VIEW_MODE_LIST) { if (ici->ic->sd->config->icon.fixed.w) { if (ici->ic->odd) _e_fm2_theme_edje_object_set(ici->ic->sd, o, "base/theme/widgets", "list_odd/fixed"); else _e_fm2_theme_edje_object_set(ici->ic->sd, o, "base/theme/widgets", "list/fixed"); } else { if (ici->ic->odd) _e_fm2_theme_edje_object_set(ici->ic->sd, o, "base/theme/widgets", "list_odd/variable"); else _e_fm2_theme_edje_object_set(ici->ic->sd, o, "base/theme/widgets", "list/variable"); } } else { if (ici->ic->sd->config->icon.fixed.w) _e_fm2_theme_edje_object_set(ici->ic->sd, o, "base/theme/fileman", "icon/fixed"); else _e_fm2_theme_edje_object_set(ici->ic->sd, o, "base/theme/fileman", "icon/variable"); } _e_fm2_icon_label_set(ici->ic, o); o2 = _e_fm2_icon_icon_direct_set(ici->ic, o, _e_fm2_cb_icon_thumb_dnd_gen, o, 1); edje_object_signal_emit(o, "e,state,selected", "e"); if (isedje(o2)) edje_object_signal_emit(o2, "e,state,selected", "e"); edje_object_signal_emit(o, "e,state,move", "e"); if (layout) { e_layout_pack(layout, o); e_layout_child_move(o, ici->ic->x, ici->ic->y); e_layout_child_resize(o, ici->ic->w, ici->ic->h); evas_object_show(o); icons = eina_list_append(icons, o); } icons = eina_list_append(icons, o2); } eina_binbuf_append_char(sbuf, 0); sel_length = eina_binbuf_length_get(sbuf) - 1; sel = (char*)eina_binbuf_string_steal(sbuf); eina_binbuf_free(sbuf); d = e_drag_new(0, 0, drag_types, 1, sel, sel_length, NULL, _e_fm2_cb_drag_finished); d->button_mask = evas_pointer_button_down_mask_get(e); if (ic->sd->win) evas_object_geometry_get(ic->sd->win, &wx, &wy, NULL, NULL); if (layout) d->x = ic->sd->x - ic->sd->pos.x, d->y = ic->sd->y - ic->sd->pos.y; else d->x = ic->x + ic->sd->x - ic->sd->pos.x, d->y = ic->y + ic->sd->y - ic->sd->pos.y; d->x += wx, d->y += wy; #ifndef HAVE_WAYLAND_ONLY e_drop_handler_action_set(ECORE_X_ATOM_XDND_ACTION_MOVE); #endif e_drag_object_set(d, layout ?: o); if (layout) { e_layout_thaw(layout); e_drag_resize(d, ic->sd->w, ic->sd->h); EINA_LIST_FREE(icons, o) e_comp_object_util_del_list_append(d->comp_object, o); } else { e_drag_resize(d, ic->w, ic->h); e_comp_object_util_del_list_append(d->comp_object, o2); } evas_object_smart_callback_call(ic->sd->obj, "dnd_begin", &ic->info); e_drag_key_down_cb_set(d, _e_fm_drag_key_down_cb); e_drag_key_up_cb_set(d, _e_fm_drag_key_up_cb); e_drag_xdnd_start(d, ic->drag.x + wx + ic->x + ic->sd->x - ic->sd->pos.x, ic->drag.y + wy + ic->y + ic->sd->y - ic->sd->pos.y); } } } static void _e_fm2_cb_icon_thumb_dnd_gen(void *data, Evas_Object *obj, void *event_info EINA_UNUSED) { Evas_Object *o; Evas_Coord w = 0, h = 0; int have_alpha; o = data; e_icon_size_get(obj, &w, &h); if (w + h == 0) return; have_alpha = e_icon_alpha_get(obj); // if (_e_fm2_view_mode_get(ic->sd) == E_FM2_VIEW_MODE_LIST) { evas_object_size_hint_aspect_set(obj, EVAS_ASPECT_CONTROL_BOTH, w, h); } edje_object_part_swallow(o, "e.swallow.icon", obj); if (have_alpha) edje_object_signal_emit(o, "e,action,thumb,gen,alpha", "e"); else edje_object_signal_emit(o, "e,action,thumb,gen", "e"); } static void _e_fm2_cb_icon_thumb_gen(void *data, Evas_Object *obj, void *event_info EINA_UNUSED) { E_Fm2_Icon *ic; const char *file; ic = data; if (e_icon_file_get(obj, &file, NULL)) { int w = 0, h = 0; if (!ic->realized) return; e_icon_size_get(obj, &w, &h); if (w && h) { Eina_Bool have_alpha; have_alpha = e_icon_alpha_get(obj); // if (_e_fm2_view_mode_get(ic->sd) == E_FM2_VIEW_MODE_LIST) { evas_object_size_hint_aspect_set(obj, EVAS_ASPECT_CONTROL_BOTH, w, h); } edje_object_part_swallow(ic->obj, "e.swallow.icon", obj); if (have_alpha) edje_object_signal_emit(ic->obj, "e,action,thumb,gen,alpha", "e"); else edje_object_signal_emit(ic->obj, "e,action,thumb,gen", "e"); return; } } ic->thumb_failed = EINA_TRUE; evas_object_del(obj); if (ic->realized) _e_fm2_icon_icon_set(ic); } #if 0 static void _e_fm2_cb_focus_in(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED) { E_Fm2_Smart_Data *sd = data; if (sd->iop_icon && sd->iop_icon->entry_widget) e_widget_focus_set(sd->iop_icon->entry_widget, 1); } #endif static void _e_fm2_cb_key_down(void *data, Evas *e EINA_UNUSED, Evas_Object *obj, void *event_info) { Evas_Event_Key_Down *ev = event_info; E_Fm2_Smart_Data *sd = data; E_Fm2_Icon *ic; if (e_comp_util_kbd_grabbed()) return; if (sd->iop_icon) return; if (evas_key_modifier_is_set(ev->modifiers, "Control")) { if (!strcmp(ev->key, "x")) { _e_fm2_file_cut(obj); return; } else if (!strcmp(ev->key, "c")) { _e_fm2_file_copy(obj); return; } else if (!strcmp(ev->key, "v")) { _e_fm2_file_paste(obj); return; } else if (!strcmp(ev->key, "h")) { if (sd->show_hidden_files) sd->show_hidden_files = EINA_FALSE; else sd->show_hidden_files = EINA_TRUE; sd->inherited_dir_props = EINA_FALSE; _e_fm2_refresh(data, NULL, NULL); return; } else if (!strcmp(ev->key, "1")) { if (_e_fm2_view_mode_get(sd) == E_FM2_VIEW_MODE_GRID_ICONS) return; sd->view_mode = E_FM2_VIEW_MODE_GRID_ICONS; sd->inherited_dir_props = EINA_FALSE; _e_fm2_refresh(sd, NULL, NULL); return; } else if (!strcmp(ev->key, "2")) { if (_e_fm2_view_mode_get(sd) == E_FM2_VIEW_MODE_LIST) return; sd->view_mode = E_FM2_VIEW_MODE_LIST; sd->inherited_dir_props = EINA_FALSE; _e_fm2_refresh(sd, NULL, NULL); return; } else if (!strcmp(ev->key, "3")) { if (_e_fm2_view_mode_get(sd) == E_FM2_VIEW_MODE_CUSTOM_ICONS) return; sd->view_mode = E_FM2_VIEW_MODE_CUSTOM_ICONS; sd->inherited_dir_props = EINA_FALSE; _e_fm2_refresh(sd, NULL, NULL); return; } } if (!strcmp(ev->key, "Left")) { /* FIXME: icon mode, typebuf extras */ /* list mode: scroll left n pix * icon mode: prev icon * typebuf mode: cursor left */ _e_fm2_icon_sel_prev(obj, evas_key_modifier_is_set(ev->modifiers, "Shift")); } else if (!strcmp(ev->key, "Right")) { /* FIXME: icon mode, typebuf extras */ /* list mode: scroll right n pix * icon mode: next icon * typebuf mode: cursor right */ _e_fm2_icon_sel_next(obj, evas_key_modifier_is_set(ev->modifiers, "Shift")); } else if (!strcmp(ev->key, "Up")) { if (_e_fm2_view_mode_get(sd) == E_FM2_VIEW_MODE_LIST) _e_fm2_icon_sel_prev(obj, evas_key_modifier_is_set(ev->modifiers, "Shift")); else _e_fm2_icon_sel_up(obj, evas_key_modifier_is_set(ev->modifiers, "Shift")); } else if (!strcmp(ev->key, "Down")) { if (_e_fm2_view_mode_get(sd) == E_FM2_VIEW_MODE_LIST) _e_fm2_icon_sel_next(obj, evas_key_modifier_is_set(ev->modifiers, "Shift")); else _e_fm2_icon_sel_down(obj, evas_key_modifier_is_set(ev->modifiers, "Shift")); } else if (!strcmp(ev->key, "Home")) { /* FIXME: typebuf extras */ /* go to first icon * typebuf mode: cursor to start */ _e_fm2_icon_sel_first(obj, EINA_FALSE); } else if (!strcmp(ev->key, "End")) { /* FIXME: typebuf extras */ /* go to last icon * typebuf mode: cursor to end */ _e_fm2_icon_sel_last(obj, EINA_FALSE); } else if (!strcmp(ev->key, "Prior")) { /* up h * n pixels */ e_fm2_pan_set(obj, sd->pos.x, sd->pos.y - sd->h); evas_object_smart_callback_call(sd->obj, "pan_changed", NULL); } else if (!strcmp(ev->key, "Next")) { /* down h * n pixels */ e_fm2_pan_set(obj, sd->pos.x, sd->pos.y + sd->h); evas_object_smart_callback_call(sd->obj, "pan_changed", NULL); } else if (!strcmp(ev->key, "Escape")) { /* typebuf mode: end typebuf mode */ if (sd->typebuf_visible) _e_fm2_typebuf_hide(obj); else if (sd->dev && (!strcmp(sd->dev, "desktop"))) return; else { ic = _e_fm2_icon_first_selected_find(obj); if (ic) _e_fm2_icon_desel_any(obj); else { if (e_fm2_has_parent_get(obj)) e_fm2_parent_go(obj); } } } else if ((!strcmp(ev->key, "Return")) || (!strcmp(ev->key, "KP_Enter"))) { /* if selected - select callback. * typebuf mode: if nothing selected - run cmd */ if (sd->typebuf_visible) _e_fm2_typebuf_run(obj); else { ic = _e_fm2_icon_first_selected_find(obj); if (ic) { if (_e_fm2_inplace_open(ic) == 0) evas_object_smart_callback_call(ic->sd->obj, "selected", NULL); } } } else if (!strcmp(ev->key, "F5")) e_fm2_refresh(obj); else if (!strcmp(ev->key, "F2")) { if (eina_list_count(sd->selected_icons) == 1) _e_fm2_file_rename(eina_list_data_get(sd->selected_icons), NULL, NULL); } else if (!strcmp(ev->key, "Insert")) { /* dunno what to do with this yet */ } else if (!strcmp(ev->key, "Tab")) { /* typebuf mode: tab complete */ if (sd->typebuf_visible) _e_fm2_typebuf_complete(obj); } else if (!strcmp(ev->key, "BackSpace")) { /* typebuf mode: backspace */ if (sd->typebuf_visible) _e_fm2_typebuf_char_backspace(obj); else if (!sd->config->view.no_typebuf_set) { /* only allow this action when typebuf navigation is allowed in config */ if (e_fm2_has_parent_get(obj)) e_fm2_parent_go(obj); } } else if (!strcmp(ev->key, "Delete")) _e_fm2_file_delete(obj); else if (!evas_key_modifier_is_set(ev->modifiers, "Control") && !evas_key_modifier_is_set(ev->modifiers, "Alt")) { if (ev->string) { if (!sd->typebuf_visible) _e_fm2_typebuf_show(obj); _e_fm2_typebuf_char_append(obj, ev->string); } } } static void _e_fm2_cb_mouse_down(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info) { Evas_Event_Mouse_Down *ev; E_Fm2_Smart_Data *sd; sd = data; ev = event_info; _e_fm2_typebuf_hide(sd->obj); if (sd->iop_icon) _e_fm2_icon_entry_widget_del(sd->iop_icon); if (ev->button == 1) { Eina_List *l; int multi_sel = 0, range_sel = 0, sel_change = 0; if (!sd->config->selection.windows_modifiers) { if (evas_key_modifier_is_set(ev->modifiers, "Shift")) range_sel = 1; else if (evas_key_modifier_is_set(ev->modifiers, "Control")) multi_sel = 1; } else { if (evas_key_modifier_is_set(ev->modifiers, "Control")) range_sel = 1; else if (evas_key_modifier_is_set(ev->modifiers, "Shift")) multi_sel = 1; } if (sd->config->selection.single) { multi_sel = 0; range_sel = 0; } if ((!multi_sel) && (!range_sel)) { E_Fm2_Icon *ic; EINA_LIST_FOREACH(sd->icons, l, ic) { if (ic->selected) { _e_fm2_icon_deselect(ic); sel_change = 1; } } } if (sel_change) evas_object_smart_callback_call(sd->obj, "selection_change", NULL); if (!(ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD)) { if (!sd->config->selection.single) { sd->selrect.ox = ev->canvas.x; sd->selrect.oy = ev->canvas.y; sd->selecting = EINA_TRUE; } } if (ev->flags & EVAS_BUTTON_DOUBLE_CLICK) evas_object_smart_callback_call(sd->obj, "double_clicked", NULL); } else if (ev->button == 3) { _e_fm2_menu(sd->obj, ev->timestamp); } } static void _e_fm2_cb_mouse_up(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED) { E_Fm2_Smart_Data *sd; sd = data; _e_fm2_typebuf_hide(sd->obj); sd->selecting = EINA_FALSE; sd->selrect.ox = 0; sd->selrect.oy = 0; evas_object_hide(sd->sel_rect); } static void _e_fm2_cb_mouse_move(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info) { Evas_Event_Mouse_Move *ev; E_Fm2_Smart_Data *sd; E_Fm2_Icon *ic; Eina_List *l = NULL; int x, y, w, h; int sel_change = 0; sd = data; ev = event_info; if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) { if (sd->selecting) { sd->selecting = EINA_FALSE; sd->selrect.ox = 0; sd->selrect.oy = 0; evas_object_hide(sd->sel_rect); } return; } if (!sd->selecting) return; if (ev->cur.canvas.x < sd->selrect.ox) { sd->selrect.x = ev->cur.canvas.x; sd->selrect.w = (sd->selrect.ox - sd->selrect.x); } else { sd->selrect.x = MIN(sd->selrect.ox, ev->cur.canvas.x); sd->selrect.w = abs(sd->selrect.x - ev->cur.canvas.x); } if (ev->cur.canvas.y < sd->selrect.oy) { sd->selrect.y = ev->cur.canvas.y; sd->selrect.h = (sd->selrect.oy - sd->selrect.y); } else { sd->selrect.y = MIN(sd->selrect.oy, ev->cur.canvas.y); sd->selrect.h = abs(sd->selrect.y - ev->cur.canvas.y); } _e_fm2_sel_rect_update(sd); evas_object_geometry_get(sd->sel_rect, &x, &y, &w, &h); /* * Leave commented for now. Start of scrolling the sel_rect * int nx, ny, nw, nh; nx = sd->pos.x; if ((x - sd->pos.x) < 0) nx = x; else if ((x + w - sd->pos.x) > (sd->w)) nx = x + w - sd->w; ny = sd->pos.y; if ((y - sd->pos.y) < 0) ny = y; else if ((y + h - sd->pos.y) > (sd->h)) ny = y + h - sd->h; e_fm2_pan_set(sd->obj, nx, ny); evas_object_smart_callback_call(sd->obj, "pan_changed", NULL); */ EINA_LIST_FOREACH(sd->icons, l, ic) { int ix, iy, iw, ih; int ix_t, iy_t, iw_t, ih_t; if (!ic) continue; evas_object_geometry_get(ic->obj_icon, &ix, &iy, &iw, &ih); evas_object_geometry_get(edje_object_part_object_get(ic->obj, "e.text.label"), &ix_t, &iy_t, &iw_t, &ih_t); if (E_INTERSECTS(x, y, w, h, ix, iy, iw, ih) || E_INTERSECTS(x, y, w, h, ix_t, iy_t, iw_t, ih_t)) { if (!ic->selected) { _e_fm2_icon_select(ic); sel_change = 1; } } else { if (ic->selected) { _e_fm2_icon_deselect(ic); sel_change = 1; } } } if (sel_change) evas_object_smart_callback_call(sd->obj, "selection_change", NULL); } static void _e_fm2_sel_rect_update(void *data) { E_Fm2_Smart_Data *sd; sd = data; evas_object_move(sd->sel_rect, sd->selrect.x, sd->selrect.y); evas_object_resize(sd->sel_rect, sd->selrect.w, sd->selrect.h); evas_object_show(sd->sel_rect); } static void _e_fm2_cb_scroll_job(void *data) { E_Fm2_Smart_Data *sd; sd = evas_object_smart_data_get(data); if (!sd) return; sd->scroll_job = NULL; evas_event_freeze(evas_object_evas_get(sd->obj)); edje_freeze(); _e_fm2_regions_eval(sd->obj); _e_fm2_obj_icons_place(sd); edje_thaw(); evas_event_thaw(evas_object_evas_get(sd->obj)); _e_fm2_dir_save_props(sd); } static void _e_fm2_cb_resize_job(void *data) { E_Fm2_Smart_Data *sd; Eina_List *l; sd = evas_object_smart_data_get(data); if (!sd) return; sd->resize_job = NULL; evas_event_freeze(evas_object_evas_get(sd->obj)); edje_freeze(); switch (_e_fm2_view_mode_get(sd)) { case E_FM2_VIEW_MODE_ICONS: _e_fm2_regions_free(sd->obj); _e_fm2_icons_place(sd->obj); _e_fm2_regions_populate(sd->obj); break; case E_FM2_VIEW_MODE_GRID_ICONS: _e_fm2_regions_free(sd->obj); _e_fm2_icons_place(sd->obj); _e_fm2_regions_populate(sd->obj); break; case E_FM2_VIEW_MODE_CUSTOM_ICONS: if (sd->config->view.fit_custom_pos) { E_Fm2_Icon *ic; EINA_LIST_FOREACH(sd->icons, l, ic) { ic->region = NULL; _e_fm2_icon_geom_adjust(ic, ic->x, ic->y, ic->w, ic->h, sd->pw, sd->ph); } } _e_fm2_regions_free(sd->obj); // _e_fm2_regions_eval(sd->obj); _e_fm2_icons_place(sd->obj); _e_fm2_regions_populate(sd->obj); break; case E_FM2_VIEW_MODE_CUSTOM_GRID_ICONS: /* FIXME: not going to implement this at this stage */ _e_fm2_regions_free(sd->obj); // _e_fm2_regions_eval(sd->obj); _e_fm2_icons_place(sd->obj); _e_fm2_regions_populate(sd->obj); break; case E_FM2_VIEW_MODE_CUSTOM_SMART_GRID_ICONS: /* FIXME: not going to implement this at this stage */ _e_fm2_regions_free(sd->obj); // _e_fm2_regions_eval(sd->obj); _e_fm2_icons_place(sd->obj); _e_fm2_regions_populate(sd->obj); break; case E_FM2_VIEW_MODE_LIST: if (sd->iconlist_changed) { E_Fm2_Icon *ic; EINA_LIST_FOREACH(sd->icons, l, ic) { ic->region = NULL; // _e_fm2_icon_unrealize(ic); } } _e_fm2_regions_free(sd->obj); _e_fm2_icons_place(sd->obj); _e_fm2_regions_populate(sd->obj); break; default: break; } edje_thaw(); evas_event_thaw(evas_object_evas_get(sd->obj)); sd->iconlist_changed = EINA_FALSE; sd->pw = sd->w; sd->ph = sd->h; if ((sd->max.w > 0) && (sd->max.h > 0) && (sd->w > 0) && (sd->h > 0) && (sd->view_flags & E_FM2_VIEW_SAVE_DIR_CUSTOM)) { E_Fm2_Custom_File *cf = e_fm2_custom_file_get(sd->realpath); if ((cf) && (cf->dir)) { sd->pos.x = cf->dir->pos.x * (sd->max.w - sd->w); sd->pos.y = cf->dir->pos.y * (sd->max.h - sd->h); evas_object_smart_callback_call(sd->obj, "pan_changed", NULL); } } } static int _e_fm2_cb_icon_sort(const void *data1, const void *data2) { const E_Fm2_Icon *ic1, *ic2; char *l1, *l2; ic1 = data1; ic2 = data2; l1 = (char *)ic1->info.file; if (ic1->info.label) l1 = (char *)ic1->info.label; l2 = (char *)ic2->info.file; if (ic2->info.label) l2 = (char *)ic2->info.label; if (ic1->sd->config->list.sort.dirs.first) { if ((S_ISDIR(ic1->info.statinfo.st_mode)) != (S_ISDIR(ic2->info.statinfo.st_mode))) { if (S_ISDIR(ic1->info.statinfo.st_mode)) return -1; return 1; } } else if (ic1->sd->config->list.sort.dirs.last) { if ((S_ISDIR(ic1->info.statinfo.st_mode)) != (S_ISDIR(ic2->info.statinfo.st_mode))) { if (S_ISDIR(ic1->info.statinfo.st_mode)) return 1; return -1; } } if (ic1->sd->config->list.sort.mtime) { if (ic1->info.statinfo.st_mtime > ic2->info.statinfo.st_mtime) return -1; if (ic1->info.statinfo.st_mtime < ic2->info.statinfo.st_mtime) return 1; } if (ic1->sd->config->list.sort.extension) { int cmp; const char *f1, *f2; f1 = ecore_file_file_get(l1); f1 = strrchr(f1, '.'); f2 = ecore_file_file_get(l2); f2 = strrchr(f2, '.'); if (f1 && f2) { cmp = strcasecmp(f1, f2); if (cmp) return cmp; } else if (f1) return 1; else if (f2) return -1; } if (ic1->sd->config->list.sort.size) { if (ic1->info.link) { if (!ic2->info.link) return 1; } else { if (ic2->info.link) return -1; if (ic1->info.statinfo.st_size > ic2->info.statinfo.st_size) return -1; else if (ic1->info.statinfo.st_size < ic2->info.statinfo.st_size) return 1; } } if (ic1->sd->config->list.sort.no_case) return strcasecmp(l1, l2); return strcmp(l1, l2); } static Eina_Bool _e_fm2_cb_scan_timer(void *data) { E_Fm2_Smart_Data *sd; sd = evas_object_smart_data_get(data); if (!sd) return ECORE_CALLBACK_CANCEL; _e_fm2_queue_process(data); sd->scan_timer = NULL; if (!sd->listing) { _e_fm2_client_monitor_list_end(data); return ECORE_CALLBACK_CANCEL; } if (sd->busy_count > 0) sd->scan_timer = ecore_timer_loop_add(0.2, _e_fm2_cb_scan_timer, sd->obj); else { if (!sd->sort_idler) sd->sort_idler = ecore_idler_add(_e_fm2_cb_sort_idler, data); } return ECORE_CALLBACK_CANCEL; } static Eina_Bool _e_fm2_cb_sort_idler(void *data) { E_Fm2_Smart_Data *sd; sd = evas_object_smart_data_get(data); if (!sd) return ECORE_CALLBACK_CANCEL; _e_fm2_queue_process(data); if (!sd->listing) { sd->sort_idler = NULL; _e_fm2_client_monitor_list_end(data); return ECORE_CALLBACK_CANCEL; } return ECORE_CALLBACK_RENEW; } static Eina_Bool _e_fm2_cb_theme(void *data, int type EINA_UNUSED, void *event EINA_UNUSED) { e_fm2_refresh(data); return ECORE_CALLBACK_RENEW; } /**************************/ static void _e_fm2_obj_icons_place(E_Fm2_Smart_Data *sd) { const Eina_List *l; E_Fm2_Region *rg; evas_event_freeze(evas_object_evas_get(sd->obj)); edje_freeze(); EINA_LIST_FOREACH(sd->regions.list, l, rg) { if (rg->realized) { const Eina_List *ll; E_Fm2_Icon *ic; EINA_LIST_FOREACH(rg->list, ll, ic) { const char *th[] = { "list/fixed", "list_odd/fixed", }; Evas_Object *prev; if (!ic->realized) continue; if (!_e_fm2_icon_visible(ic)) { e_thumb_icon_end(ic->obj_icon); } evas_object_move(ic->obj, sd->x + ic->x - sd->pos.x, sd->y + ic->y - sd->pos.y); evas_object_resize(ic->obj, ic->w, ic->h); _e_fm2_icon_thumb(ic, ic->obj_icon, 0); if (_e_fm2_view_mode_get(ic->sd) != E_FM2_VIEW_MODE_LIST) continue; /* FIXME: this is probably something that should be unnecessary, * but currently we add icons in semi-randomly and it messes up ordering. * current process is: * 1 receive file info from slave * 2 create icon struct * 3 either directly add icon or queue it (usually queue) * 4 process queue on timer, determining even/odd for all icons at this time * 4.5 icons are realized, theme is set here <-- where bug occurs * 5 goto 1 * 6 if icon is inserted into current viewport during 4.5, even/odd for surrounding items * will always be wrong (ticket #1579) */ prev = edje_object_part_swallow_get(ic->obj, "e.swallow.icon"); _e_fm2_theme_edje_object_set(ic->sd, ic->obj, "base/theme/widgets", th[ic->odd]); edje_object_part_swallow(ic->obj, "e.swallow.icon", prev); _e_fm2_icon_label_set(ic, ic->obj); if (ic->selected) edje_object_signal_emit(ic->obj, "e,state,selected", "e"); } } } edje_thaw(); evas_event_thaw(evas_object_evas_get(sd->obj)); } /**************************/ static void _e_fm2_smart_add(Evas_Object *obj) { E_Fm2_Smart_Data *sd; sd = E_NEW(E_Fm2_Smart_Data, 1); if (!sd) return; sd->view_mode = -1; /* unset */ sd->icon_size = -1; /* unset */ sd->obj = obj; sd->clip = evas_object_rectangle_add(evas_object_evas_get(obj)); evas_object_smart_member_add(sd->clip, obj); evas_object_color_set(sd->clip, 255, 255, 255, 255); sd->underlay = evas_object_rectangle_add(evas_object_evas_get(obj)); evas_object_clip_set(sd->underlay, sd->clip); evas_object_smart_member_add(sd->underlay, obj); evas_object_color_set(sd->underlay, 0, 0, 0, 0); evas_object_show(sd->underlay); evas_object_event_callback_add(obj, EVAS_CALLBACK_KEY_DOWN, _e_fm2_cb_key_down, sd); //evas_object_event_callback_add(obj, EVAS_CALLBACK_FOCUS_IN, _e_fm2_cb_focus_in, sd); evas_object_event_callback_add(sd->underlay, EVAS_CALLBACK_MOUSE_DOWN, _e_fm2_cb_mouse_down, sd); evas_object_event_callback_add(sd->underlay, EVAS_CALLBACK_MOUSE_UP, _e_fm2_cb_mouse_up, sd); evas_object_event_callback_add(sd->underlay, EVAS_CALLBACK_MOUSE_MOVE, _e_fm2_cb_mouse_move, sd); sd->drop = edje_object_add(evas_object_evas_get(obj)); evas_object_clip_set(sd->drop, sd->clip); _e_fm2_theme_edje_object_set(sd, sd->drop, "base/theme/fileman", "list/drop_between"); evas_object_smart_member_add(sd->drop, obj); evas_object_show(sd->drop); sd->drop_in = edje_object_add(evas_object_evas_get(obj)); evas_object_clip_set(sd->drop_in, sd->clip); _e_fm2_theme_edje_object_set(sd, sd->drop_in, "base/theme/fileman", "list/drop_in"); evas_object_smart_member_add(sd->drop_in, obj); evas_object_show(sd->drop_in); sd->overlay = edje_object_add(evas_object_evas_get(obj)); evas_object_clip_set(sd->overlay, sd->clip); _e_fm2_theme_edje_object_set(sd, sd->overlay, "base/theme/fileman", "overlay"); evas_object_smart_member_add(sd->overlay, obj); evas_object_show(sd->overlay); sd->sel_rect = edje_object_add(evas_object_evas_get(obj)); evas_object_clip_set(sd->sel_rect, sd->clip); _e_fm2_theme_edje_object_set(sd, sd->sel_rect, "base/theme/fileman", "rubberband"); evas_object_smart_member_add(sd->sel_rect, obj); evas_object_smart_data_set(obj, sd); evas_object_move(obj, 0, 0); evas_object_resize(obj, 0, 0); E_LIST_HANDLER_APPEND(sd->handlers, E_EVENT_CONFIG_ICON_THEME, _e_fm2_cb_theme, sd->obj); E_LIST_HANDLER_APPEND(sd->handlers, EFREET_EVENT_ICON_CACHE_UPDATE, _e_fm2_icon_cache_update, sd); _e_fm2_list = eina_list_append(_e_fm2_list, sd->obj); } static void _e_fm2_smart_del(Evas_Object *obj) { E_Fm2_Smart_Data *sd; sd = evas_object_smart_data_get(obj); if (!sd) return; E_FREE_LIST(sd->handlers, ecore_event_handler_del); _e_fm2_client_monitor_list_end(obj); if (sd->realpath) _e_fm2_client_monitor_del(sd->id, sd->realpath); _e_fm2_live_process_end(obj); _e_fm2_queue_free(obj); _e_fm2_regions_free(obj); _e_fm2_icons_free(obj); if (sd->selected_icons) eina_list_free(sd->selected_icons); if (sd->menu) { e_menu_post_deactivate_callback_set(sd->menu, NULL, NULL); e_object_del(E_OBJECT(sd->menu)); sd->menu = NULL; } if (sd->entry_dialog) { e_object_del(E_OBJECT(sd->entry_dialog)); sd->entry_dialog = NULL; } if (sd->image_dialog) { e_object_del(E_OBJECT(sd->image_dialog)); sd->image_dialog = NULL; } E_FREE_LIST(sd->rename_dialogs, e_object_del); if (sd->scroll_job) ecore_job_del(sd->scroll_job); if (sd->resize_job) ecore_job_del(sd->resize_job); if (sd->refresh_job) ecore_job_del(sd->refresh_job); eina_stringshare_del(sd->custom_theme); eina_stringshare_del(sd->custom_theme_content); sd->custom_theme = sd->custom_theme_content = NULL; eina_stringshare_del(sd->dev); eina_stringshare_del(sd->path); eina_stringshare_del(sd->realpath); eina_stringshare_del(sd->new_file.filename); sd->dev = sd->path = sd->realpath = NULL; if (sd->mount) { e_fm2_device_unmount(sd->mount); sd->mount = NULL; } if (sd->config) _e_fm2_config_free(sd->config); 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); evas_object_del(sd->drop); evas_object_del(sd->drop_in); evas_object_del(sd->sel_rect); evas_object_del(sd->clip); if (sd->drop_handler) e_drop_handler_del(sd->drop_handler); if (_e_fm2_list_walking == 0) _e_fm2_list = eina_list_remove(_e_fm2_list, sd->obj); else _e_fm2_list_remove = eina_list_append(_e_fm2_list_remove, sd->obj); if (sd->desktop) efreet_desktop_free(sd->desktop); sd->desktop = NULL; free(sd); e_fm2_custom_file_flush(); } static void _e_fm2_smart_move(Evas_Object *obj, Evas_Coord x, Evas_Coord y) { E_Fm2_Smart_Data *sd; sd = evas_object_smart_data_get(obj); if (!sd) return; if ((sd->x == x) && (sd->y == y)) return; sd->x = x; sd->y = y; evas_object_move(sd->underlay, sd->x, sd->y); if (!sd->overlay_clip) evas_object_move(sd->overlay, sd->x, sd->y); _e_fm2_dnd_drop_configure(sd->obj); evas_object_move(sd->clip, sd->x - OVERCLIP, sd->y - OVERCLIP); _e_fm2_obj_icons_place(sd); if (sd->drop_handler) e_drop_handler_geometry_set(sd->drop_handler, sd->x, sd->y, sd->w, sd->h); } static void _e_fm2_smart_resize(Evas_Object *obj, Evas_Coord w, Evas_Coord h) { E_Fm2_Smart_Data *sd; Eina_Bool wch = EINA_FALSE; sd = evas_object_smart_data_get(obj); if (!sd) return; if ((sd->w == w) && (sd->h == h)) return; if (w != sd->w) wch = EINA_TRUE; sd->w = w; sd->h = h; evas_object_resize(sd->underlay, sd->w, sd->h); if (!sd->overlay_clip) evas_object_resize(sd->overlay, sd->w, sd->h); _e_fm2_dnd_drop_configure(sd->obj); evas_object_resize(sd->clip, sd->w + (OVERCLIP * 2), sd->h + (OVERCLIP * 2)); /* for automatic layout - do this - NB; we could put this on a timer delay */ if ((_e_fm2_view_mode_get(sd) == E_FM2_VIEW_MODE_LIST) || (_e_fm2_view_mode_get(sd) == E_FM2_VIEW_MODE_GRID_ICONS)) { if (wch) { if (sd->resize_job) ecore_job_del(sd->resize_job); sd->resize_job = ecore_job_add(_e_fm2_cb_resize_job, obj); } else { if (sd->scroll_job) ecore_job_del(sd->scroll_job); sd->scroll_job = ecore_job_add(_e_fm2_cb_scroll_job, obj); } } else if (_e_fm2_view_mode_get(sd) == E_FM2_VIEW_MODE_CUSTOM_ICONS) { if (sd->config->view.fit_custom_pos) { if (sd->resize_job) ecore_job_del(sd->resize_job); sd->resize_job = ecore_job_add(_e_fm2_cb_resize_job, obj); } else { if (sd->scroll_job) ecore_job_del(sd->scroll_job); sd->scroll_job = ecore_job_add(_e_fm2_cb_scroll_job, obj); } } if (sd->drop_handler) e_drop_handler_geometry_set(sd->drop_handler, sd->x, sd->y, sd->w, sd->h); } static void _e_fm2_smart_show(Evas_Object *obj) { E_Fm2_Smart_Data *sd; sd = evas_object_smart_data_get(obj); if (!sd) return; evas_object_show(sd->clip); } static void _e_fm2_smart_hide(Evas_Object *obj) { E_Fm2_Smart_Data *sd; sd = evas_object_smart_data_get(obj); if (!sd) return; evas_object_hide(sd->clip); } static void _e_fm2_smart_color_set(Evas_Object *obj, int r, int g, int b, int a) { E_Fm2_Smart_Data *sd; sd = evas_object_smart_data_get(obj); if (!sd) return; evas_object_color_set(sd->clip, r, g, b, a); } static void _e_fm2_smart_clip_set(Evas_Object *obj, Evas_Object *clip) { E_Fm2_Smart_Data *sd; sd = evas_object_smart_data_get(obj); if (!sd) return; evas_object_clip_set(sd->clip, clip); } static void _e_fm2_smart_clip_unset(Evas_Object *obj) { E_Fm2_Smart_Data *sd; sd = evas_object_smart_data_get(obj); if (!sd) return; evas_object_clip_unset(sd->clip); } static void _e_fm2_overlay_clip_resize(void *data, Evas *e EINA_UNUSED, Evas_Object *obj, void *event_info EINA_UNUSED) { E_Fm2_Smart_Data *sd = data; int w, h; evas_object_geometry_get(obj, NULL, NULL, &w, &h); evas_object_resize(sd->overlay, w, h); } static void _e_fm2_overlay_clip_move(void *data, Evas *e EINA_UNUSED, Evas_Object *obj, void *event_info EINA_UNUSED) { E_Fm2_Smart_Data *sd = data; int x, y; evas_object_geometry_get(obj, &x, &y, NULL, NULL); evas_object_move(sd->overlay, x, y); } static void _e_fm2_view_menu_sorting_change_case(void *data, E_Menu *m EINA_UNUSED, E_Menu_Item *mi) { E_Fm2_Smart_Data *sd = data; sd->config->list.sort.no_case = !mi->toggle; _e_fm2_refresh(sd, NULL, NULL); } static void _e_fm2_view_menu_sorting_change_size(void *data, E_Menu *m EINA_UNUSED, E_Menu_Item *mi) { E_Fm2_Smart_Data *sd = data; sd->config->list.sort.size = mi->toggle; _e_fm2_refresh(sd, NULL, NULL); } static void _e_fm2_view_menu_sorting_change_mtime(void *data, E_Menu *m EINA_UNUSED, E_Menu_Item *mi) { E_Fm2_Smart_Data *sd = data; sd->config->list.sort.mtime = mi->toggle; _e_fm2_refresh(sd, NULL, NULL); } static void _e_fm2_view_menu_sorting_change_extension(void *data, E_Menu *m EINA_UNUSED, E_Menu_Item *mi) { E_Fm2_Smart_Data *sd = data; sd->config->list.sort.extension = mi->toggle; _e_fm2_refresh(sd, NULL, NULL); } static void _e_fm2_view_menu_sorting_change_dirs_first(void *data, E_Menu *m EINA_UNUSED, E_Menu_Item *mi) { E_Fm2_Smart_Data *sd = data; sd->config->list.sort.dirs.first = mi->toggle; if (mi->toggle && sd->config->list.sort.dirs.last) sd->config->list.sort.dirs.last = 0; _e_fm2_refresh(sd, NULL, NULL); } static void _e_fm2_view_menu_sorting_change_dirs_last(void *data, E_Menu *m EINA_UNUSED, E_Menu_Item *mi) { E_Fm2_Smart_Data *sd = data; sd->config->list.sort.dirs.last = mi->toggle; if (mi->toggle && sd->config->list.sort.dirs.first) sd->config->list.sort.dirs.first = 0; _e_fm2_refresh(sd, NULL, NULL); } static void _e_fm2_view_menu_sorting_pre(void *data, E_Menu *m EINA_UNUSED, E_Menu_Item *mi) { E_Fm2_Smart_Data *sd = data; E_Menu *subm; subm = e_menu_new(); e_menu_item_submenu_set(mi, subm); mi = e_menu_item_new(subm); e_menu_item_label_set(mi, _("Case Sensitive")); e_menu_item_check_set(mi, 1); e_menu_item_toggle_set(mi, !sd->config->list.sort.no_case); e_menu_item_callback_set(mi, _e_fm2_view_menu_sorting_change_case, sd); mi = e_menu_item_new(subm); e_menu_item_label_set(mi, _("Sort By Extension")); e_menu_item_check_set(mi, 1); e_menu_item_toggle_set(mi, sd->config->list.sort.extension); e_menu_item_callback_set(mi, _e_fm2_view_menu_sorting_change_extension, sd); mi = e_menu_item_new(subm); e_menu_item_label_set(mi, _("Sort By Modification Time")); e_menu_item_check_set(mi, 1); e_menu_item_toggle_set(mi, sd->config->list.sort.mtime); e_menu_item_callback_set(mi, _e_fm2_view_menu_sorting_change_mtime, sd); mi = e_menu_item_new(subm); e_menu_item_label_set(mi, _("Sort By Size")); e_menu_item_check_set(mi, 1); e_menu_item_toggle_set(mi, sd->config->list.sort.size); e_menu_item_callback_set(mi, _e_fm2_view_menu_sorting_change_size, sd); mi = e_menu_item_new(subm); e_menu_item_separator_set(mi, 1); mi = e_menu_item_new(subm); e_menu_item_label_set(mi, _("Directories First")); e_menu_item_check_set(mi, 1); e_menu_item_toggle_set(mi, sd->config->list.sort.dirs.first); e_menu_item_callback_set(mi, _e_fm2_view_menu_sorting_change_dirs_first, sd); mi = e_menu_item_new(subm); e_menu_item_label_set(mi, _("Directories Last")); e_menu_item_check_set(mi, 1); e_menu_item_toggle_set(mi, sd->config->list.sort.dirs.last); e_menu_item_callback_set(mi, _e_fm2_view_menu_sorting_change_dirs_last, sd); } static void _e_fm2_menu(Evas_Object *obj, unsigned int timestamp) { E_Fm2_Smart_Data *sd; E_Menu *mn, *sub; E_Menu_Item *mi; E_Zone *zone; int x, y; sd = evas_object_smart_data_get(obj); if (!sd) return; mn = e_menu_new(); e_object_data_set(E_OBJECT(mn), obj); e_menu_category_set(mn, "e/fileman/action"); if (sd->icon_menu.replace.func) sd->icon_menu.replace.func(sd->icon_menu.replace.data, sd->obj, mn, NULL); else { if (sd->icon_menu.start.func) sd->icon_menu.start.func(sd->icon_menu.start.data, sd->obj, mn, NULL); if (!(sd->icon_menu.flags & E_FM2_MENU_NO_VIEW_MENU)) { mi = e_menu_item_new(mn); e_menu_item_label_set(mi, _("View Mode")); e_util_menu_item_theme_icon_set(mi, "preferences-look"); sub = e_menu_new(); e_menu_item_submenu_set(mi, sub); e_object_unref(E_OBJECT(sub)); e_object_data_set(E_OBJECT(sub), sd); e_menu_pre_activate_callback_set(sub, _e_fm2_view_menu_pre, sd); mi = e_menu_item_new(mn); e_menu_item_label_set(mi, _("Sorting")); e_menu_item_submenu_pre_callback_set(mi, _e_fm2_view_menu_sorting_pre, sd); } if (!(sd->icon_menu.flags & (E_FM2_MENU_NO_SHOW_HIDDEN | E_FM2_MENU_NO_REMEMBER_ORDERING | E_FM2_MENU_NO_ACTIVATE_CHANGE))) { mi = e_menu_item_new(mn); e_menu_item_label_set(mi, _("Options")); e_util_menu_item_theme_icon_set(mi, "preferences-system"); sub = e_menu_new(); e_menu_item_submenu_set(mi, sub); e_object_unref(E_OBJECT(sub)); e_object_data_set(E_OBJECT(sub), sd); e_menu_pre_activate_callback_set(sub, _e_fm2_options_menu_pre, sd); } if (!(sd->icon_menu.flags & E_FM2_MENU_NO_REFRESH)) { mi = e_menu_item_new(mn); e_menu_item_label_set(mi, _("Refresh View")); e_util_menu_item_theme_icon_set(mi, "view-refresh"); e_menu_item_callback_set(mi, _e_fm2_refresh, sd); } if (!(sd->icon_menu.flags & E_FM2_MENU_NO_NEW)) { mi = e_menu_item_new(mn); e_menu_item_separator_set(mi, 1); mi = e_menu_item_new(mn); e_menu_item_label_set(mi, _("New...")); e_util_menu_item_theme_icon_set(mi, "add"); sub = e_menu_new(); e_menu_item_submenu_set(mi, sub); e_object_unref(E_OBJECT(sub)); e_object_data_set(E_OBJECT(sub), sd); e_menu_pre_activate_callback_set(sub, _e_fm2_add_menu_pre, sd); } if (sd->realpath) { const Eina_List *ll; /* see if we have any mime handlers registered for this file */ ll = e_fm2_mime_handler_mime_handlers_get("inode/directory"); if (ll) { mi = e_menu_item_new(mn); e_menu_item_separator_set(mi, 1); mi = e_menu_item_new(mn); e_menu_item_label_set(mi, _("Actions...")); e_util_menu_item_theme_icon_set(mi, "preferences-plugin"); sub = e_menu_new(); e_menu_item_submenu_set(mi, sub); _e_fm2_context_menu_append(sd, sd->realpath, ll, sub, NULL); } } if (((!(sd->icon_menu.flags & E_FM2_MENU_NO_PASTE)) || (!(sd->icon_menu.flags & E_FM2_MENU_NO_SYMLINK))) && (eina_list_count(_e_fm_file_buffer) > 0) && ecore_file_can_write(sd->realpath)) { mi = e_menu_item_new(mn); e_menu_item_separator_set(mi, 1); if (!(sd->icon_menu.flags & E_FM2_MENU_NO_PASTE)) { mi = e_menu_item_new(mn); e_menu_item_label_set(mi, _("Paste")); e_util_menu_item_theme_icon_set(mi, "edit-paste"); e_menu_item_callback_set(mi, _e_fm2_file_paste_menu, sd); } if (!(sd->icon_menu.flags & E_FM2_MENU_NO_SYMLINK)) { mi = e_menu_item_new(mn); e_menu_item_label_set(mi, _("Link")); e_util_menu_item_theme_icon_set(mi, "emblem-symbolic-link"); e_menu_item_callback_set(mi, _e_fm2_file_symlink_menu, sd); } } if (sd->icon_menu.end.func) sd->icon_menu.end.func(sd->icon_menu.end.data, sd->obj, mn, NULL); } ecore_evas_pointer_xy_get(e_comp->ee, &x, &y); zone = e_zone_current_get(); if (!zone) { e_object_del(E_OBJECT(mn)); return; } sd->menu = mn; e_menu_post_deactivate_callback_set(mn, _e_fm2_menu_post_cb, sd); e_menu_activate_mouse(mn, zone, x, y, 1, 1, E_MENU_POP_DIRECTION_DOWN, timestamp); } static void _e_fm2_menu_post_cb(void *data, E_Menu *m EINA_UNUSED) { E_Fm2_Smart_Data *sd; sd = data; sd->menu = NULL; } static void _e_fm2_icon_menu(E_Fm2_Icon *ic, Evas_Object *obj, unsigned int timestamp) { E_Fm2_Smart_Data *sd; E_Menu *mn, *sub; E_Menu_Item *mi; E_Zone *zone; Eina_List *sel; Eina_List *l = NULL; int x, y, can_w, can_w2, protect; char buf[PATH_MAX], *ext; Eina_Bool writable; sd = ic->sd; if (ic->menu) return; mn = e_menu_new(); e_object_data_set(E_OBJECT(mn), obj); e_menu_category_set(mn, "e/fileman/action"); if (sd->icon_menu.replace.func) sd->icon_menu.replace.func(sd->icon_menu.replace.data, sd->obj, mn, &ic->info); else { writable = ecore_file_can_write(sd->realpath); if (sd->icon_menu.start.func) sd->icon_menu.start.func(sd->icon_menu.start.data, sd->obj, mn, &ic->info); if (!(sd->icon_menu.flags & E_FM2_MENU_NO_VIEW_MENU)) { mi = e_menu_item_new(mn); e_menu_item_label_set(mi, _("View Mode")); e_util_menu_item_theme_icon_set(mi, "preferences-look"); sub = e_menu_new(); e_menu_item_submenu_set(mi, sub); e_object_data_set(E_OBJECT(sub), sd); e_object_unref(E_OBJECT(sub)); e_menu_pre_activate_callback_set(sub, _e_fm2_icon_view_menu_pre, sd); mi = e_menu_item_new(mn); e_menu_item_label_set(mi, _("Sorting")); e_menu_item_submenu_pre_callback_set(mi, _e_fm2_view_menu_sorting_pre, sd); } if (!(sd->icon_menu.flags & (E_FM2_MENU_NO_SHOW_HIDDEN | E_FM2_MENU_NO_REMEMBER_ORDERING | E_FM2_MENU_NO_ACTIVATE_CHANGE))) { mi = e_menu_item_new(mn); e_menu_item_label_set(mi, _("Options")); e_util_menu_item_theme_icon_set(mi, "preferences-system"); sub = e_menu_new(); e_menu_item_submenu_set(mi, sub); e_object_unref(E_OBJECT(sub)); e_object_data_set(E_OBJECT(sub), sd); e_menu_pre_activate_callback_set(sub, _e_fm2_options_menu_pre, sd); } if (!(sd->icon_menu.flags & E_FM2_MENU_NO_REFRESH)) { mi = e_menu_item_new(mn); e_menu_item_label_set(mi, _("Refresh View")); e_util_menu_item_theme_icon_set(mi, "view-refresh"); e_menu_item_callback_set(mi, _e_fm2_refresh, sd); } /* FIXME: stat the dir itself - move to e_fm_main */ if (writable && !(sd->icon_menu.flags & E_FM2_MENU_NO_NEW)) { mi = e_menu_item_new(mn); e_menu_item_separator_set(mi, 1); mi = e_menu_item_new(mn); e_menu_item_label_set(mi, _("New...")); e_util_menu_item_theme_icon_set(mi, "add"); sub = e_menu_new(); e_menu_item_submenu_set(mi, sub); e_object_unref(E_OBJECT(sub)); e_object_data_set(E_OBJECT(sub), sd); e_menu_pre_activate_callback_set(sub, _e_fm2_add_menu_pre, sd); } { const Eina_List *ll = NULL; E_Menu *subm = NULL; if (ic->info.mime) { /* see if we have any mime handlers registered for this file */ ll = e_fm2_mime_handler_mime_handlers_get(ic->info.mime); } if (ll || sd->realpath) { mi = e_menu_item_new(mn); e_menu_item_separator_set(mi, 1); mi = e_menu_item_new(mn); e_menu_item_label_set(mi, _("Actions...")); e_util_menu_item_theme_icon_set(mi, "preferences-plugin"); subm = e_menu_new(); e_menu_item_submenu_set(mi, subm); _e_fm2_icon_realpath(ic, buf, sizeof(buf)); } if (ll) _e_fm2_context_menu_append(sd, buf, ll, subm, ic); if (sd->realpath && (ic->info.mime != _e_fm2_mime_inode_directory)) { ll = e_fm2_mime_handler_mime_handlers_get("inode/directory"); _e_fm2_context_menu_append(sd, sd->realpath, ll, subm, ic); } /* see if we have any glob handlers registered for this file */ ext = strrchr(ic->info.file, '.'); if (ext) { snprintf(buf, sizeof(buf), "*%s", ext); l = e_fm2_mime_handler_glob_handlers_get(buf); if (l) { if (subm) { if (subm->items) { mi = e_menu_item_new(mn); e_menu_item_separator_set(mi, 1); } } else { mi = e_menu_item_new(mn); e_menu_item_separator_set(mi, 1); mi = e_menu_item_new(mn); e_menu_item_label_set(mi, _("Actions...")); e_util_menu_item_theme_icon_set(mi, "preferences-plugin"); subm = e_menu_new(); e_menu_item_submenu_set(mi, subm); } _e_fm2_icon_realpath(ic, buf, sizeof(buf)); _e_fm2_context_menu_append(sd, buf, l, subm, ic); eina_list_free(l); } } } if (!ic->info.removable) { if (!(sd->icon_menu.flags & E_FM2_MENU_NO_CUT)) { if (writable) { mi = e_menu_item_new(mn); e_menu_item_separator_set(mi, 1); mi = e_menu_item_new(mn); e_menu_item_label_set(mi, _("Cut")); e_util_menu_item_theme_icon_set(mi, "edit-cut"); e_menu_item_callback_set(mi, _e_fm2_file_cut_menu, sd); } } if (!(sd->icon_menu.flags & E_FM2_MENU_NO_COPY)) { if (!writable) { mi = e_menu_item_new(mn); e_menu_item_separator_set(mi, 1); } mi = e_menu_item_new(mn); e_menu_item_label_set(mi, _("Copy")); e_util_menu_item_theme_icon_set(mi, "edit-copy"); e_menu_item_callback_set(mi, _e_fm2_file_copy_menu, sd); } if (((!(sd->icon_menu.flags & E_FM2_MENU_NO_PASTE)) || (!(sd->icon_menu.flags & E_FM2_MENU_NO_SYMLINK))) && (eina_list_count(_e_fm_file_buffer) > 0) && writable) { if (!(sd->icon_menu.flags & E_FM2_MENU_NO_PASTE)) { mi = e_menu_item_new(mn); e_menu_item_label_set(mi, _("Paste")); e_util_menu_item_theme_icon_set(mi, "edit-paste"); e_menu_item_callback_set(mi, _e_fm2_file_paste_menu, sd); } if (!(sd->icon_menu.flags & E_FM2_MENU_NO_SYMLINK)) { mi = e_menu_item_new(mn); e_menu_item_label_set(mi, _("Link")); e_util_menu_item_theme_icon_set(mi, "emblem-symbolic-link"); e_menu_item_callback_set(mi, _e_fm2_file_symlink_menu, sd); } } } can_w2 = 1; if (ic->sd->order_file) { snprintf(buf, sizeof(buf), "%s/.order", sd->realpath); /* FIXME: stat the .order itself - move to e_fm_main */ // can_w2 = ecore_file_can_write(buf); } if (ic->info.link) { can_w = 1; /* struct stat st; if (_e_fm2_icon_realpath(ic, buf, sizeof(buf)) && (lstat(buf, &st) == 0)) { if (st.st_uid == getuid()) { if (st.st_mode & S_IWUSR) can_w = 1; } else if (st.st_gid == getgid()) { if (st.st_mode & S_IWGRP) can_w = 1; } else { if (st.st_mode & S_IWOTH) can_w = 1; } } */ } else can_w = 1; sel = e_fm2_selected_list_get(ic->sd->obj); if ((!sel) || eina_list_count(sel) == 1) { _e_fm2_icon_realpath(ic, buf, sizeof(buf)); protect = e_filereg_file_protected(buf); } else protect = 0; eina_list_free(sel); if ((can_w) && (can_w2) && !(protect) && !ic->info.removable) { if (!(sd->icon_menu.flags & E_FM2_MENU_NO_DELETE)) { mi = e_menu_item_new(mn); e_menu_item_label_set(mi, _("Delete")); e_util_menu_item_theme_icon_set(mi, "edit-delete"); e_menu_item_callback_set(mi, _e_fm2_file_delete_menu, ic); } if (!(sd->icon_menu.flags & E_FM2_MENU_NO_RENAME)) { mi = e_menu_item_new(mn); e_menu_item_label_set(mi, _("Rename")); e_util_menu_item_theme_icon_set(mi, "edit-rename"); e_menu_item_callback_set(mi, _e_fm2_file_rename, ic); } } if (ic->info.removable) { E_Volume *v; v = e_fm2_device_volume_find(ic->info.link); if (v) { mi = e_menu_item_new(mn); e_menu_item_separator_set(mi, 1); mi = e_menu_item_new(mn); if (v->mounted) { e_menu_item_label_set(mi, _("Unmount")); e_menu_item_callback_set(mi, _e_fm2_volume_unmount, v); } else { e_menu_item_label_set(mi, _("Mount")); e_menu_item_callback_set(mi, _e_fm2_volume_mount, v); } mi = e_menu_item_new(mn); e_menu_item_label_set(mi, _("Eject")); e_util_menu_item_theme_icon_set(mi, "media-eject"); e_menu_item_callback_set(mi, _e_fm2_volume_eject, v); mi = e_menu_item_new(mn); e_menu_item_separator_set(mi, 1); } } mi = e_menu_item_new(mn); e_menu_item_separator_set(mi, 1); if ((!ic->info.removable) && ic->info.file && (ic->info.file[0] != '|') && ic->info.mime && (!strcmp(ic->info.mime, "application/x-desktop"))) { mi = e_menu_item_new(mn); e_menu_item_label_set(mi, _("Properties")); e_util_menu_item_theme_icon_set(mi, "document-properties"); e_menu_item_callback_set(mi, _e_fm2_file_properties, ic); sub = e_menu_new(); e_menu_item_submenu_set(mi, sub); e_object_unref(E_OBJECT(sub)); mi = e_menu_item_new(sub); e_menu_item_label_set(mi, _("Application Properties")); e_util_menu_item_theme_icon_set(mi, "configure"); e_menu_item_callback_set(mi, _e_fm2_file_application_properties, ic); } else sub = NULL; mi = e_menu_item_new(sub ? : mn); e_menu_item_label_set(mi, _("File Properties")); e_util_menu_item_theme_icon_set(mi, "document-properties"); e_menu_item_callback_set(mi, _e_fm2_file_properties, ic); if (sd->icon_menu.end.func) sd->icon_menu.end.func(sd->icon_menu.end.data, sd->obj, mn, &(ic->info)); } ecore_evas_pointer_xy_get(e_comp->ee, &x, &y); zone = e_zone_current_get(); if (!zone) { e_object_del(E_OBJECT(mn)); return; } ic->menu = mn; e_menu_post_deactivate_callback_set(mn, _e_fm2_icon_menu_post_cb, ic); e_menu_activate_mouse(mn, zone, x, y, 1, 1, E_MENU_POP_DIRECTION_DOWN, timestamp); } static void _e_fm2_context_menu_append(E_Fm2_Smart_Data *sd, const char *path, const Eina_List *list, E_Menu *mn, E_Fm2_Icon *ic) { E_Fm2_Mime_Handler *handler; Eina_List *l; if (!list) return; l = eina_list_clone(list); l = eina_list_sort(l, -1, _e_fm2_context_list_sort); EINA_LIST_FREE(l, handler) { E_Fm2_Context_Menu_Data *md = NULL; E_Menu_Item *mi; if ((!handler) || (!handler->label) || (!e_fm2_mime_handler_test(handler, sd->obj, path))) continue; md = E_NEW(E_Fm2_Context_Menu_Data, 1); if (!md) continue; md->icon = ic; md->handler = handler; md->sd = sd; _e_fm2_menu_contexts = eina_list_append(_e_fm2_menu_contexts, md); mi = e_menu_item_new(mn); e_menu_item_label_set(mi, handler->label); if (handler->icon_group) { if (handler->icon_group[0] == '/') e_menu_item_icon_file_set(mi, handler->icon_group); else e_util_menu_item_theme_icon_set(mi, handler->icon_group); } e_menu_item_callback_set(mi, _e_fm2_icon_menu_item_cb, md); } } static int _e_fm2_context_list_sort(const void *data1, const void *data2) { const E_Fm2_Mime_Handler *d1, *d2; if (!data1) return 1; if (!data2) return -1; d1 = data1; if (!d1->label) return 1; d2 = data2; if (!d2->label) return -1; return strcmp(d1->label, d2->label); } static void _e_fm2_icon_menu_post_cb(void *data, E_Menu *m EINA_UNUSED) { E_Fm2_Context_Menu_Data *md; E_Fm2_Icon *ic; ic = data; ic->menu = NULL; EINA_LIST_FREE(_e_fm2_menu_contexts, md) E_FREE(md); } static void _e_fm2_icon_menu_item_cb(void *data, E_Menu *m EINA_UNUSED, E_Menu_Item *mi EINA_UNUSED) { E_Fm2_Context_Menu_Data *md = NULL; Evas_Object *obj = NULL; char buf[PATH_MAX]; md = data; if (!md) return; if (md->icon) { obj = md->icon->info.fm; if (!obj) return; snprintf(buf, sizeof(buf), "%s/%s", e_fm2_real_path_get(obj), md->icon->info.file); e_fm2_mime_handler_call(md->handler, obj, buf); } else e_fm2_mime_handler_call(md->handler, md->sd->obj, md->sd->realpath); } struct e_fm2_view_menu_icon_size_data { E_Fm2_Smart_Data *sd; short size; }; static void _e_fm2_view_menu_icon_size_data_free(void *obj) { struct e_fm2_view_menu_icon_size_data *d = e_object_data_get(obj); free(d); } static void _e_fm2_view_menu_icon_size_change(void *data, E_Menu *m, E_Menu_Item *mi) { struct e_fm2_view_menu_icon_size_data *d = data; short current_size = _e_fm2_icon_w_get(d->sd); d->sd->icon_size = d->size; d->sd->inherited_dir_props = EINA_FALSE; if (current_size == d->size) return; _e_fm2_refresh(d->sd, m, mi); } static void _e_fm2_view_menu_icon_size_use_default(void *data, E_Menu *m, E_Menu_Item *mi) { E_Fm2_Smart_Data *sd = data; short old, new; old = _e_fm2_icon_w_get(sd); if (sd->icon_size == -1) sd->icon_size = sd->config->icon.icon.w; else sd->icon_size = -1; new = _e_fm2_icon_w_get(sd); sd->inherited_dir_props = EINA_FALSE; if (new == old) return; _e_fm2_refresh(sd, m, mi); } static void _e_fm2_view_menu_icon_size_pre(void *data, E_Menu *m EINA_UNUSED, E_Menu_Item *mi) { E_Fm2_Smart_Data *sd = data; E_Menu *subm; const short *itr, sizes[] = { 22, 32, 48, 64, 96, 128, 256, -1 }; short current_size = _e_fm2_icon_w_get(sd); if (e_scale > 0.0) current_size /= e_scale; subm = e_menu_new(); e_menu_item_submenu_set(mi, subm); for (itr = sizes; *itr > -1; itr++) { char buf[32]; struct e_fm2_view_menu_icon_size_data *d; d = malloc(sizeof(*d)); if (!d) continue; d->sd = sd; d->size = *itr; snprintf(buf, sizeof(buf), "%hd", *itr); mi = e_menu_item_new(subm); e_object_data_set(E_OBJECT(mi), d); e_object_del_attach_func_set (E_OBJECT(mi), _e_fm2_view_menu_icon_size_data_free); e_menu_item_label_set(mi, buf); e_menu_item_radio_group_set(mi, 1); e_menu_item_radio_set(mi, 1); if (current_size == *itr) e_menu_item_toggle_set(mi, 1); e_menu_item_callback_set(mi, _e_fm2_view_menu_icon_size_change, d); } mi = e_menu_item_new(subm); e_menu_item_separator_set(mi, 1); mi = e_menu_item_new(subm); e_menu_item_label_set(mi, _("Use default")); e_menu_item_check_set(mi, 1); e_menu_item_toggle_set(mi, sd->icon_size == -1); e_menu_item_callback_set(mi, _e_fm2_view_menu_icon_size_use_default, sd); } static void _e_fm2_toggle_inherit_dir_props(void *data, E_Menu *m, E_Menu_Item *mi) { E_Fm2_Smart_Data *sd = data; sd->inherited_dir_props = !sd->inherited_dir_props; _e_fm2_dir_save_props(sd); _e_fm2_dir_load_props(sd); _e_fm2_refresh(sd, m, mi); } static void _e_fm2_view_menu_common(E_Menu *subm, E_Fm2_Smart_Data *sd) { char buf[64]; E_Menu_Item *mi; char view_mode; int icon_size; view_mode = _e_fm2_view_mode_get(sd); if (!(sd->icon_menu.flags & E_FM2_MENU_NO_VIEW_CHANGE)) { mi = e_menu_item_new(subm); e_menu_item_label_set(mi, _("Grid Icons")); e_menu_item_radio_group_set(mi, 1); e_menu_item_radio_set(mi, 1); if (view_mode == E_FM2_VIEW_MODE_GRID_ICONS) e_menu_item_toggle_set(mi, 1); e_menu_item_callback_set(mi, _e_fm2_view_menu_grid_icons_cb, sd); mi = e_menu_item_new(subm); e_menu_item_label_set(mi, _("Custom Icons")); e_menu_item_radio_group_set(mi, 1); e_menu_item_radio_set(mi, 1); if (view_mode == E_FM2_VIEW_MODE_CUSTOM_ICONS) e_menu_item_toggle_set(mi, 1); e_menu_item_callback_set(mi, _e_fm2_view_menu_custom_icons_cb, sd); mi = e_menu_item_new(subm); e_menu_item_label_set(mi, _("List")); e_menu_item_radio_group_set(mi, 1); e_menu_item_radio_set(mi, 1); if (view_mode == E_FM2_VIEW_MODE_LIST) e_menu_item_toggle_set(mi, 1); e_menu_item_callback_set(mi, _e_fm2_view_menu_list_cb, sd); mi = e_menu_item_new(subm); e_menu_item_label_set(mi, _("Default View")); e_menu_item_check_set(mi, 1); e_menu_item_toggle_set(mi, sd->view_mode == -1); e_menu_item_callback_set(mi, _e_fm2_view_menu_use_default_cb, sd); mi = e_menu_item_new(subm); e_menu_item_separator_set(mi, 1); } if (view_mode == E_FM2_VIEW_MODE_LIST) return; mi = e_menu_item_new(subm); e_menu_item_separator_set(mi, 1); icon_size = _e_fm2_icon_w_get(sd); // show the icon size as selected (even if it might be influnced by e_scale) /* if (e_scale > 0.0) * icon_size /= e_scale; */ snprintf(buf, sizeof(buf), _("Icon Size (%d)"), icon_size); mi = e_menu_item_new(subm); e_menu_item_label_set(mi, buf); e_menu_item_submenu_pre_callback_set(mi, _e_fm2_view_menu_icon_size_pre, sd); } static void _e_fm2_icon_view_menu_pre(void *data, E_Menu *subm) { E_Fm2_Smart_Data *sd; sd = data; if (subm->items) return; _e_fm2_view_menu_common(subm, sd); } static void _e_fm2_new_dir_notify(void *data, Ecore_Thread *eth EINA_UNUSED, char *filename) { E_Fm2_Smart_Data *sd = data; if (!sd->new_file.done) { if (filename) sd->new_file.filename = eina_stringshare_add(ecore_file_file_get(filename)); else e_util_dialog_internal(_("Error"), _("Could not create a directory!")); } free(filename); } static void _e_fm2_new_file_notify(void *data, Ecore_Thread *eth EINA_UNUSED, char *filename) { E_Fm2_Smart_Data *sd = data; if (!sd->new_file.done) { if (filename) sd->new_file.filename = eina_stringshare_add(ecore_file_file_get(filename)); else e_util_dialog_internal(_("Error"), _("Could not create a file!")); } free(filename); } static void _e_fm2_new_thread_helper(Ecore_Thread *eth, Eina_Bool dir) { char buf[PATH_MAX]; char *path; struct stat st; unsigned int x; int fd; Eina_List *texts, *l; path = ecore_thread_global_data_wait("path", 2.0); snprintf(buf, sizeof(buf), "%s/%s", path, dir ? _("New Directory") : _("New File")); errno = 0; if (stat(buf, &st) && (errno == ENOENT)) { if (dir) { if (ecore_file_mkdir(buf)) { ecore_thread_global_data_set("efm_pending_filename", strdup(buf), free); ecore_thread_feedback(eth, strdup(buf)); return; } } else { fd = open(buf, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR); if (fd) { texts = ecore_thread_global_data_wait("efm_text_uri_list", 0.01); EINA_LIST_FOREACH(texts, l, path) { if (write(fd, path, strlen(path)) < 0) perror("write"); if (write(fd, "\n", 1) < 0) perror("write"); } close(fd); ecore_thread_global_data_set("efm_pending_filename", strdup(buf), free); ecore_thread_feedback(eth, strdup(buf)); return; } } goto error; } else if (errno) goto error; for (x = 0; x < UINT_MAX; x++) { snprintf(buf, sizeof(buf), "%s/%s %u", path, dir ? _("New Directory") : _("New File"), x); errno = 0; if (stat(buf, &st) && (errno == ENOENT)) { if (dir) { if (ecore_file_mkdir(buf)) { ecore_thread_global_data_set("efm_pending_filename", strdup(buf), free); ecore_thread_feedback(eth, strdup(buf)); return; } } else { fd = open(buf, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR); if (fd) { texts = ecore_thread_global_data_wait("efm_text_uri_list", 0.01); EINA_LIST_FOREACH(texts, l, path) { if (write(fd, path, strlen(path)) < 0) perror("write"); if (write(fd, "\n", 1) < 0) perror("write"); } close(fd); ecore_thread_global_data_set("efm_pending_filename", strdup(buf), free); ecore_thread_feedback(eth, strdup(buf)); return; } } goto error; } else if (errno) goto error; } error: ecore_thread_feedback(eth, NULL); } static void _e_fm2_new_file_thread(void *data EINA_UNUSED, Ecore_Thread *eth) { _e_fm2_new_thread_helper(eth, EINA_FALSE); } static void _e_fm2_new_dir_thread(void *data EINA_UNUSED, Ecore_Thread *eth) { _e_fm2_new_thread_helper(eth, EINA_TRUE); } static void _e_fm2_new_file_end(void *data, Ecore_Thread *eth EINA_UNUSED) { E_Fm2_Smart_Data *sd = data; sd->new_file.thread = NULL; ecore_thread_global_data_del("path"); ecore_thread_global_data_del("efm_text_uri_list"); evas_object_unref(sd->obj); e_fm2_refresh(sd->obj); } static void _e_fm2_new_file_cancel(void *data, Ecore_Thread *eth EINA_UNUSED) { E_Fm2_Smart_Data *sd = data; sd->new_file.thread = NULL; ecore_thread_global_data_del("path"); ecore_thread_global_data_del("efm_text_uri_list"); evas_object_unref(sd->obj); } static void _e_fm2_new_file(void *data, E_Menu *m EINA_UNUSED, E_Menu_Item *mi EINA_UNUSED) { E_Fm2_Smart_Data *sd = data; if (sd->new_file.thread || sd->new_file.filename) { e_util_dialog_internal(_("Error"), _("Already creating a new file for this directory!")); return; } if (!ecore_file_can_write(sd->realpath)) { e_util_dialog_show(_("Error"), _("%s can't be written to!"), sd->realpath); return; } sd->new_file.thread = ecore_thread_feedback_run(_e_fm2_new_file_thread, (Ecore_Thread_Notify_Cb)_e_fm2_new_file_notify, _e_fm2_new_file_end, _e_fm2_new_file_cancel, sd, EINA_FALSE); ecore_thread_global_data_add("path", (void *)eina_stringshare_ref(sd->realpath), (void *)eina_stringshare_del, EINA_FALSE); evas_object_ref(sd->obj); } static void _e_fm2_new_directory(void *data, E_Menu *m EINA_UNUSED, E_Menu_Item *mi EINA_UNUSED) { E_Fm2_Smart_Data *sd = data; if (sd->new_file.thread || sd->new_file.filename) { e_util_dialog_internal(_("Error"), _("Already creating a new file for this directory!")); return; } if (!ecore_file_can_write(sd->realpath)) { e_util_dialog_show(_("Error"), _("%s can't be written to!"), sd->realpath); return; } sd->new_file.thread = ecore_thread_feedback_run(_e_fm2_new_dir_thread, (Ecore_Thread_Notify_Cb)_e_fm2_new_dir_notify, _e_fm2_new_file_end, _e_fm2_new_file_cancel, sd, EINA_FALSE); ecore_thread_global_data_add("path", (void *)eina_stringshare_ref(sd->realpath), (void *)eina_stringshare_del, EINA_FALSE); evas_object_ref(sd->obj); } static void _e_fm2_add_menu_pre(void *data, E_Menu *subm) { E_Menu_Item *mi; E_Fm2_Smart_Data *sd; sd = data; if (subm->items) return; mi = e_menu_item_new(subm); e_menu_item_label_set(mi, _("Directory")); e_util_menu_item_theme_icon_set(mi, "folder-new"); e_menu_item_callback_set(mi, _e_fm2_new_directory, sd); mi = e_menu_item_new(subm); e_menu_item_label_set(mi, _("File")); e_util_menu_item_theme_icon_set(mi, "document-new"); e_menu_item_callback_set(mi, _e_fm2_new_file, sd); } static void _e_fm2_settings_icon_item(void *data EINA_UNUSED, E_Menu *m EINA_UNUSED, E_Menu_Item *mi EINA_UNUSED) { e_configure_registry_call("fileman/file_icons", NULL, NULL); } static void _e_fm2_settings_item(void *data EINA_UNUSED, E_Menu *m EINA_UNUSED, E_Menu_Item *mi EINA_UNUSED) { e_configure_registry_call("fileman/fileman", NULL, NULL); } static void _e_fm2_options_menu_pre(void *data, E_Menu *subm) { E_Fm2_Smart_Data *sd; E_Menu_Item *mi; sd = data; if (subm->items) return; if ((!(sd->icon_menu.flags & E_FM2_MENU_NO_INHERIT_PARENT)) && (sd->view_flags & E_FM2_VIEW_INHERIT_DIR_CUSTOM)) { mi = e_menu_item_new(subm); e_menu_item_label_set(mi, _("Inherit parent settings")); e_util_menu_item_theme_icon_set(mi, "view-inherit"); e_menu_item_check_set(mi, 1); e_menu_item_toggle_set(mi, sd->inherited_dir_props); e_menu_item_callback_set(mi, _e_fm2_toggle_inherit_dir_props, sd); } if (!(sd->icon_menu.flags & E_FM2_MENU_NO_SHOW_HIDDEN)) { mi = e_menu_item_new(subm); e_menu_item_label_set(mi, _("Show Hidden Files")); e_util_menu_item_theme_icon_set(mi, "view-refresh"); e_menu_item_check_set(mi, 1); e_menu_item_toggle_set(mi, sd->show_hidden_files); e_menu_item_callback_set(mi, _e_fm2_toggle_hidden_files, sd); } if (!(sd->icon_menu.flags & E_FM2_MENU_NO_REMEMBER_ORDERING)) { if (!sd->config->view.always_order) { mi = e_menu_item_new(subm); e_menu_item_label_set(mi, _("Remember Ordering")); e_util_menu_item_theme_icon_set(mi, "view-order"); e_menu_item_check_set(mi, 1); e_menu_item_toggle_set(mi, sd->order_file); e_menu_item_callback_set(mi, _e_fm2_toggle_ordering, sd); } if ((sd->order_file) || (sd->config->view.always_order)) { mi = e_menu_item_new(subm); e_menu_item_label_set(mi, _("Sort Now")); e_util_menu_item_theme_icon_set(mi, "view-sort"); e_menu_item_callback_set(mi, _e_fm2_sort, sd); } } if (!(sd->icon_menu.flags & E_FM2_MENU_NO_ACTIVATE_CHANGE)) { mi = e_menu_item_new(subm); e_menu_item_label_set(mi, _("Single Click Activation")); e_util_menu_item_theme_icon_set(mi, "access"); e_menu_item_check_set(mi, 1); e_menu_item_toggle_set(mi, sd->config->view.single_click); e_menu_item_callback_set(mi, _e_fm2_toggle_single_click, sd); } if (!e_config->filemanager_secure_rm) { /* can't disable this if it's globally enabled */ mi = e_menu_item_new(subm); e_menu_item_label_set(mi, _("Secure Deletion")); e_util_menu_item_theme_icon_set(mi, "security-high"); e_menu_item_check_set(mi, 1); e_menu_item_toggle_set(mi, e_config->filemanager_secure_rm | sd->config->secure_rm); e_menu_item_callback_set(mi, _e_fm2_toggle_secure_rm, sd); } if (!e_configure_registry_exists("fileman/fileman")) return; mi = e_menu_item_new(subm); e_menu_item_separator_set(mi, 1); mi = e_menu_item_new(subm); e_menu_item_label_set(mi, _("File Manager Settings")); e_util_menu_item_theme_icon_set(mi, "system-file-manager"); e_menu_item_callback_set(mi, _e_fm2_settings_item, sd); mi = e_menu_item_new(subm); e_menu_item_label_set(mi, _("File Icon Settings")); e_util_menu_item_theme_icon_set(mi, "preferences-file-icons"); e_menu_item_callback_set(mi, _e_fm2_settings_icon_item, sd); } static void _custom_file_key_del(E_Fm2_Smart_Data *sd, const char *key) { Efreet_Desktop *ef; char buf[PATH_MAX]; if (sd->desktop) ef = sd->desktop; else { snprintf(buf, sizeof(buf), "%s/.directory.desktop", sd->realpath); ef = efreet_desktop_new(buf); } if (!ef) return; if (efreet_desktop_x_field_del(ef, key)) efreet_desktop_save(ef); if (!sd->desktop) efreet_desktop_free(ef); } static void _e_fm2_view_menu_del(void *data) { E_Fm2_Smart_Data *sd = e_object_data_get(data); if (!sd) return; if (sd->image_dialog) return; if (!sd->desktop) return; efreet_desktop_free(sd->desktop); sd->desktop = NULL; } static void _clear_background_cb(void *data, E_Menu *m EINA_UNUSED, E_Menu_Item *mi EINA_UNUSED) { E_Fm2_Smart_Data *sd; sd = data; if (!sd) return; _custom_file_key_del(sd, "X-Enlightenment-Directory-Wallpaper"); evas_object_smart_callback_call(sd->obj, "dir_changed", NULL); } static void _clear_overlay_cb(void *data, E_Menu *m EINA_UNUSED, E_Menu_Item *mi EINA_UNUSED) { E_Fm2_Smart_Data *sd = data; if (!sd) return; _custom_file_key_del(sd, "X-Enlightenment-Directory-Overlay"); evas_object_smart_callback_call(sd->obj, "dir_changed", NULL); } static void _e_fm2_view_menu_pre(void *data, E_Menu *subm) { E_Fm2_Smart_Data *sd = data; E_Menu_Item *mi; if (subm->items) return; _e_fm2_view_menu_common(subm, sd); if (_e_fm2_desktop_open(sd) < 0) return; e_object_data_set(E_OBJECT(subm), sd); e_object_del_attach_func_set(E_OBJECT(subm), _e_fm2_view_menu_del); if (e_menu_item_nth(subm, 0) != NULL) { mi = e_menu_item_new(subm); e_menu_item_separator_set(mi, 1); } mi = e_menu_item_new(subm); e_menu_item_label_set(mi, _("Set background...")); e_util_menu_item_theme_icon_set(mi, "preferences-desktop-wallpaper"); e_menu_item_callback_set(mi, _e_fm2_view_menu_set_background_cb, sd); while (sd->desktop) { if (!eina_hash_find(sd->desktop->x, "X-Enlightenment-Directory-Wallpaper")) break; mi = e_menu_item_new(subm); e_menu_item_label_set(mi, _("Clear background")); e_util_menu_item_theme_icon_set(mi, "preferences-desktop-wallpaper"); e_menu_item_callback_set(mi, _clear_background_cb, sd); break; } mi = e_menu_item_new(subm); e_menu_item_label_set(mi, _("Set overlay...")); e_menu_item_callback_set(mi, _e_fm2_view_menu_set_overlay_cb, sd); if (!sd->desktop) return; if (!eina_hash_find(sd->desktop->x, "X-Enlightenment-Directory-Overlay")) return; mi = e_menu_item_new(subm); e_menu_item_label_set(mi, _("Clear overlay")); e_menu_item_callback_set(mi, _clear_overlay_cb, sd); } static void _e_fm2_view_menu_grid_icons_cb(void *data, E_Menu *m, E_Menu_Item *mi) { E_Fm2_Smart_Data *sd = data; char old; old = _e_fm2_view_mode_get(sd); sd->view_mode = E_FM2_VIEW_MODE_GRID_ICONS; sd->inherited_dir_props = EINA_FALSE; if (old == E_FM2_VIEW_MODE_GRID_ICONS) return; _e_fm2_refresh(sd, m, mi); } static void _e_fm2_view_menu_custom_icons_cb(void *data, E_Menu *m, E_Menu_Item *mi) { E_Fm2_Smart_Data *sd = data; char old; old = _e_fm2_view_mode_get(sd); sd->view_mode = E_FM2_VIEW_MODE_CUSTOM_ICONS; sd->inherited_dir_props = EINA_FALSE; if (old == E_FM2_VIEW_MODE_CUSTOM_ICONS) return; _e_fm2_refresh(sd, m, mi); } static void _e_fm2_view_menu_list_cb(void *data, E_Menu *m, E_Menu_Item *mi) { E_Fm2_Smart_Data *sd = data; char old; old = _e_fm2_view_mode_get(sd); sd->view_mode = E_FM2_VIEW_MODE_LIST; sd->inherited_dir_props = EINA_FALSE; if (old == E_FM2_VIEW_MODE_LIST) return; _e_fm2_refresh(sd, m, mi); } static void _e_fm2_view_menu_use_default_cb(void *data, E_Menu *m, E_Menu_Item *mi) { E_Fm2_Smart_Data *sd = data; char old, new; old = _e_fm2_view_mode_get(sd); if (sd->view_mode == -1) sd->view_mode = sd->config->view.mode; else sd->view_mode = -1; new = _e_fm2_view_mode_get(sd); sd->inherited_dir_props = EINA_FALSE; if (new == old) return; _e_fm2_refresh(sd, m, mi); } static void _image_sel_del(void *data) { E_Fm2_Smart_Data *sd; sd = e_object_data_get(data); if (!sd) return; sd->image_dialog = NULL; if (sd->desktop) efreet_desktop_free(sd->desktop); sd->desktop = NULL; } static void _e_fm2_view_image_sel(E_Fm2_Smart_Data *sd, const char *title, void (*ok_cb)(void *data, E_Dialog *dia)) { E_Dialog *dia; Evas_Object *o; Evas_Coord w, h; dia = e_dialog_new(NULL, "E", "_fm2_view_image_select_dialog"); if (!dia) return; e_dialog_resizable_set(dia, 1); e_dialog_title_set(dia, title); o = e_widget_fsel_add(evas_object_evas_get(dia->win), "/", sd->realpath, NULL, NULL, NULL, sd, NULL, sd, 1); evas_object_show(o); e_widget_size_min_get(o, &w, &h); e_dialog_content_set(dia, o, w, h); dia->data = o; e_dialog_button_add(dia, _("OK"), NULL, ok_cb, sd); e_dialog_button_add(dia, _("Cancel"), NULL, _e_fm2_view_image_sel_close, sd); elm_win_center(dia->win, 1, 1); e_object_data_set(E_OBJECT(dia), sd); e_object_del_attach_func_set(E_OBJECT(dia), _image_sel_del); e_dialog_show(dia); sd->image_dialog = dia; } static void _e_fm2_view_image_sel_close(void *data, E_Dialog *dia) { E_Fm2_Smart_Data *sd; sd = data; e_object_del(E_OBJECT(dia)); sd->image_dialog = NULL; } static int _e_fm2_desktop_open(E_Fm2_Smart_Data *sd) { Efreet_Desktop *ef; char buf[PATH_MAX]; Eina_Bool ret; snprintf(buf, sizeof(buf), "%s/.directory.desktop", sd->realpath); if (sd->desktop) { if (!e_util_strcmp(buf, sd->desktop->orig_path)) return 1; } ret = ecore_file_exists(buf) ? ecore_file_can_write(buf) : ecore_file_can_write(sd->realpath); if (!ret) return -1; ef = efreet_desktop_new(buf); if (!ef) return 0; efreet_desktop_free(sd->desktop); sd->desktop = ef; return 1; } static void _custom_file_key_set(E_Fm2_Smart_Data *sd, const char *key, const char *value) { Efreet_Desktop *ef; char buf[PATH_MAX]; int len; if (sd->desktop) ef = sd->desktop; else { snprintf(buf, sizeof(buf), "%s/.directory.desktop", sd->realpath); ef = efreet_desktop_new(buf); if (!ef) { ef = efreet_desktop_empty_new(buf); if (!ef) return; ef->type = EFREET_DESKTOP_TYPE_DIRECTORY; ef->name = strdup("Directory look and feel"); } } len = strlen(sd->realpath); if (!strncmp(value, sd->realpath, len)) efreet_desktop_x_field_set(ef, key, value + len + 1); else efreet_desktop_x_field_set(ef, key, value); efreet_desktop_save(ef); if (!sd->desktop) efreet_desktop_free(ef); } static void _set_background_cb(void *data, E_Dialog *dia) { E_Fm2_Smart_Data *sd; const char *file; sd = data; if (!sd) return; file = e_widget_fsel_selection_path_get(dia->data); if (file) _custom_file_key_set(sd, "X-Enlightenment-Directory-Wallpaper", file); _e_fm2_view_image_sel_close(data, dia); evas_object_smart_callback_call(sd->obj, "dir_changed", NULL); } static void _e_fm2_view_menu_set_background_cb(void *data, E_Menu *m EINA_UNUSED, E_Menu_Item *mi EINA_UNUSED) { E_Fm2_Smart_Data *sd = data; if (sd->image_dialog) return; _e_fm2_view_image_sel(sd, _("Set background..."), _set_background_cb); } static void _set_overlay_cb(void *data, E_Dialog *dia) { E_Fm2_Smart_Data *sd; const char *file; sd = data; if (!sd) return; file = e_widget_fsel_selection_path_get(dia->data); if (file) _custom_file_key_set(sd, "X-Enlightenment-Directory-Overlay", file); _e_fm2_view_image_sel_close(data, dia); evas_object_smart_callback_call(sd->obj, "dir_changed", NULL); } static void _e_fm2_view_menu_set_overlay_cb(void *data, E_Menu *m EINA_UNUSED, E_Menu_Item *mi EINA_UNUSED) { E_Fm2_Smart_Data *sd = data; if (sd->image_dialog) return; _e_fm2_view_image_sel(sd, _("Set overlay..."), _set_overlay_cb); } static void _e_fm2_refresh(void *data, E_Menu *m EINA_UNUSED, E_Menu_Item *mi EINA_UNUSED) { E_Fm2_Smart_Data *sd; sd = data; if (sd->refresh_job) ecore_job_del(sd->refresh_job); sd->refresh_job = ecore_job_add(_e_fm2_refresh_job_cb, sd->obj); } static void _e_fm2_toggle_hidden_files(void *data, E_Menu *m, E_Menu_Item *mi) { E_Fm2_Smart_Data *sd; sd = data; if (sd->show_hidden_files) sd->show_hidden_files = EINA_FALSE; else sd->show_hidden_files = EINA_TRUE; sd->inherited_dir_props = EINA_FALSE; _e_fm2_refresh(data, m, mi); } static void _e_fm2_toggle_secure_rm(void *data, E_Menu *m EINA_UNUSED, E_Menu_Item *mi EINA_UNUSED) { E_Fm2_Smart_Data *sd = data; sd->config->secure_rm = !sd->config->secure_rm; } static void _e_fm2_toggle_single_click(void *data, E_Menu *m EINA_UNUSED, E_Menu_Item *mi EINA_UNUSED) { E_Fm2_Smart_Data *sd; sd = data; sd->config->view.single_click = !sd->config->view.single_click; } static void _e_fm2_toggle_ordering(void *data, E_Menu *m, E_Menu_Item *mi) { E_Fm2_Smart_Data *sd; char buf[4096]; sd = data; if (sd->order_file) { snprintf(buf, sizeof(buf), "%s/.order", sd->realpath); /* FIXME: move to e_fm_main */ ecore_file_unlink(buf); } else { FILE *f; snprintf(buf, sizeof(buf), "%s/.order", sd->realpath); f = fopen(buf, "w"); if (f) fclose(f); } sd->inherited_dir_props = EINA_FALSE; _e_fm2_refresh(data, m, mi); } static void _e_fm2_sort(void *data, E_Menu *m, E_Menu_Item *mi) { E_Fm2_Smart_Data *sd; sd = data; sd->icons = eina_list_sort(sd->icons, eina_list_count(sd->icons), _e_fm2_cb_icon_sort); _e_fm2_refresh(data, m, mi); } static void _e_fm2_file_rename(void *data, E_Menu *m EINA_UNUSED, E_Menu_Item *mi EINA_UNUSED) { E_Fm2_Icon *ic; char text[PATH_MAX + 256]; ic = data; if ((ic->entry_dialog) || (ic->entry_widget)) return; if (ic->sd->icon_menu.flags & E_FM2_MENU_NO_RENAME) return; if (!_e_fm2_icon_entry_widget_add(ic)) { snprintf(text, PATH_MAX + 256, _("Rename %s to:"), ic->info.file); ic->entry_dialog = e_entry_dialog_show(_("Rename File"), "edit-rename", text, ic->info.file, NULL, NULL, _e_fm2_file_rename_yes_cb, _e_fm2_file_rename_no_cb, ic); E_OBJECT(ic->entry_dialog)->data = ic; e_object_del_attach_func_set(E_OBJECT(ic->entry_dialog), _e_fm2_file_rename_delete_cb); } } /* FIXME: this is a stupid hack because it's impossible to get a focus event * from e_widget_entry. */ static void _e_fm2_icon_entry_widget_focus_out(void *data, E_Client *ec) { E_Fm2_Icon *ic = data; Evas_Object *win; win = e_win_evas_win_get(evas_object_evas_get(ic->obj)); if ((win != e_comp->elm) && (ec == e_win_client_get(win))) return; if (ic->entry_widget) _e_fm2_icon_entry_widget_del(ic); } static Evas_Object * _e_fm2_icon_entry_widget_add(E_Fm2_Icon *ic) { Evas *e; if (ic->sd->iop_icon) _e_fm2_icon_entry_widget_accept(ic->sd->iop_icon); if (!edje_object_part_exists(ic->obj, "e.swallow.entry")) return NULL; e = evas_object_evas_get(ic->obj); ic->entry_widget = e_widget_entry_add(e_win_evas_win_get(e), NULL, NULL, NULL, NULL); evas_object_event_callback_add(ic->entry_widget, EVAS_CALLBACK_KEY_DOWN, _e_fm2_icon_entry_widget_cb_key_down, ic); if (e_comp->comp_type == E_PIXMAP_TYPE_X) evas_event_feed_mouse_out(evas_object_evas_get(ic->obj), 0, NULL); if (e_comp->evas == e) e_comp_grab_input(0, 1); ic->keygrab = (e_comp->evas == e); edje_object_part_swallow(ic->obj, "e.swallow.entry", ic->entry_widget); evas_object_show(ic->entry_widget); edje_object_signal_emit(ic->obj, "e,state,rename,on", "e"); e_widget_entry_text_set(ic->entry_widget, ic->info.file); e_widget_focus_set(ic->entry_widget, 1); ic->focus_hook = e_client_hook_add(E_CLIENT_HOOK_FOCUS_SET, _e_fm2_icon_entry_widget_focus_out, ic); e_widget_entry_select_all(ic->entry_widget); ic->sd->iop_icon = ic; ic->sd->typebuf.disabled = EINA_TRUE; if (e_comp->comp_type == E_PIXMAP_TYPE_X) evas_event_feed_mouse_in(e, 0, NULL); return ic->entry_widget; } static void _e_fm2_icon_entry_widget_del(E_Fm2_Icon *ic) { ic->sd->iop_icon = NULL; evas_object_focus_set(ic->sd->obj, 1); evas_object_del(ic->entry_widget); ic->entry_widget = NULL; E_FREE_FUNC(ic->focus_hook, e_client_hook_del); ic->sd->typebuf.disabled = EINA_FALSE; if (ic->keygrab) { if (evas_object_evas_get(ic->obj) == e_comp->evas) e_comp_ungrab_input(0, 1); } ic->keygrab = 0; _e_fm2_icon_select(ic); edje_object_signal_emit(ic->obj, "e,state,rename,off", "e"); } static void _e_fm2_icon_entry_widget_cb_key_down(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info) { Evas_Event_Key_Down *ev; E_Fm2_Icon *ic; ev = event_info; ic = data; if (!strcmp(ev->key, "Escape")) _e_fm2_icon_entry_widget_del(ic); else if ((!strcmp(ev->key, "Return")) || (!strcmp(ev->key, "KP_Enter"))) _e_fm2_icon_entry_widget_accept(ic); } static void _e_fm2_icon_entry_widget_accept(E_Fm2_Icon *ic) { const char *txt; txt = e_widget_entry_text_get(ic->entry_widget); switch (_e_fm2_file_do_rename(txt, ic)) { case -2: e_util_dialog_show(_("Error"), _("%s already exists!"), txt); return; case -1: e_util_dialog_show(_("Error"), _("%s could not be renamed because it is protected"), ic->info.file); break; case 0: e_util_dialog_show(_("Error"), _("Internal filemanager error :(")); default: /* success! */ break; } _e_fm2_icon_entry_widget_del(ic); } static void _e_fm2_file_rename_delete_cb(void *obj) { E_Fm2_Icon *ic; ic = E_OBJECT(obj)->data; ic->entry_dialog = NULL; } static void _e_fm2_file_rename_yes_cb(void *data, char *text) { E_Fm2_Icon *ic; ic = data; ic->entry_dialog = NULL; switch (_e_fm2_file_do_rename(text, ic)) { case -2: e_util_dialog_show(_("Error"), _("%s already exists!"), text); _e_fm2_file_rename(ic, NULL, NULL); break; case -1: e_util_dialog_show(_("Error"), _("%s could not be renamed because it is protected"), ic->info.file); break; case 0: e_util_dialog_show(_("Error"), _("Internal filemanager error :(")); default: /* success! */ break; } } static void _e_fm2_file_rename_no_cb(void *data) { E_Fm2_Icon *ic; ic = data; ic->entry_dialog = NULL; } static int _e_fm2_file_do_rename(const char *text, E_Fm2_Icon *ic) { char oldpath[PATH_MAX]; char newpath[PATH_MAX]; char *args = NULL; size_t size = 0; size_t length = 0; if (!text) return 0; if (!strcmp(text, ic->info.file)) return EINA_TRUE; _e_fm2_icon_realpath(ic, oldpath, sizeof(oldpath)); snprintf(newpath, sizeof(newpath), "%s/%s", ic->sd->realpath, text); if (e_filereg_file_protected(oldpath)) return -1; if (ecore_file_exists(newpath)) return -2; args = e_util_string_append_quoted(args, &size, &length, oldpath); if (!args) return 0; args = e_util_string_append_char(args, &size, &length, ' '); if (!args) return 0; args = e_util_string_append_quoted(args, &size, &length, newpath); if (!args) return 0; e_fm2_client_file_move(ic->sd->obj, args); free(args); return 1; } static E_Dialog * _e_fm_retry_abort_dialog(int pid, const char *str) { E_Dialog *dialog; void *id; char text[4096 + PATH_MAX]; id = (intptr_t *)(long)pid; dialog = e_dialog_new(NULL, "E", "_fm_overwrite_dialog"); E_OBJECT(dialog)->data = id; e_dialog_button_add(dialog, _("Retry"), NULL, _e_fm_retry_abort_retry_cb, NULL); e_dialog_button_add(dialog, _("Abort"), NULL, _e_fm_retry_abort_abort_cb, NULL); e_dialog_button_focus_num(dialog, 0); e_dialog_title_set(dialog, _("Error")); e_dialog_icon_set(dialog, "dialog-error", 64); snprintf(text, sizeof(text), "%s", str); e_dialog_text_set(dialog, text); elm_win_center(dialog->win, 1, 1); e_dialog_show(dialog); return dialog; } static void _e_fm_retry_abort_retry_cb(void *data EINA_UNUSED, E_Dialog *dialog) { int id = (int)(intptr_t)E_OBJECT(dialog)->data; _e_fm2_op_registry_go_on(id); _e_fm_client_send(E_FM_OP_ERROR_RESPONSE_RETRY, id, NULL, 0); e_object_del(E_OBJECT(dialog)); } static void _e_fm_retry_abort_abort_cb(void *data EINA_UNUSED, E_Dialog *dialog) { int id = (int)(intptr_t)E_OBJECT(dialog)->data; _e_fm2_op_registry_aborted(id); _e_fm_client_send(E_FM_OP_ERROR_RESPONSE_ABORT, id, NULL, 0); e_object_del(E_OBJECT(dialog)); } static E_Dialog * _e_fm_overwrite_dialog(int pid, const char *str) { E_Dialog *dialog; void *id; char text[4096 + PATH_MAX]; E_Fm2_Op_Registry_Entry *ere; id = (intptr_t *)(long)pid; ere = e_fm2_op_registry_entry_get(pid); if (ere) { E_Fm2_Smart_Data *sd; Eina_List *fms; Evas_Object *fm; fms = _e_fm2_file_fm2_find(ere->src); EINA_LIST_FREE(fms, fm) { sd = evas_object_smart_data_get(fm); E_LIST_FOREACH(sd->icons, _e_fm2_cb_drag_finished_show); } } dialog = e_dialog_new(NULL, "E", "_fm_overwrite_dialog"); E_OBJECT(dialog)->data = id; e_dialog_button_add(dialog, _("No"), NULL, _e_fm_overwrite_no_cb, NULL); e_dialog_button_add(dialog, _("No to all"), NULL, _e_fm_overwrite_no_all_cb, NULL); e_dialog_button_add(dialog, _("Rename"), NULL, _e_fm_overwrite_rename, NULL); e_dialog_button_add(dialog, _("Yes"), NULL, _e_fm_overwrite_yes_cb, NULL); e_dialog_button_add(dialog, _("Yes to all"), NULL, _e_fm_overwrite_yes_all_cb, NULL); e_dialog_button_focus_num(dialog, 0); e_dialog_title_set(dialog, _("Warning")); e_dialog_icon_set(dialog, "dialog-warning", 64); snprintf(text, sizeof(text), _("File already exists, overwrite?%s"), str); e_dialog_text_set(dialog, text); elm_win_center(dialog->win, 1, 1); e_dialog_show(dialog); return dialog; } static void _e_fm_overwrite_no_cb(void *data EINA_UNUSED, E_Dialog *dialog) { int id = (int)(intptr_t)E_OBJECT(dialog)->data; _e_fm2_op_registry_go_on(id); _e_fm_client_send(E_FM_OP_OVERWRITE_RESPONSE_NO, id, NULL, 0); e_object_del(E_OBJECT(dialog)); } static void _e_fm_overwrite_no_all_cb(void *data EINA_UNUSED, E_Dialog *dialog) { int id = (int)(intptr_t)E_OBJECT(dialog)->data; _e_fm2_op_registry_go_on(id); _e_fm_client_send(E_FM_OP_OVERWRITE_RESPONSE_NO_ALL, id, NULL, 0); e_object_del(E_OBJECT(dialog)); } static void _e_fm_overwrite_rename_del(void *data) { E_Fm2_Op_Registry_Entry *ere; E_Fm2_Smart_Data *sd; ere = e_object_data_get(data); if (!ere) return; sd = evas_object_smart_data_get(ere->e_fm); if (!sd) return; sd->rename_dialogs = eina_list_remove(sd->rename_dialogs, data); e_fm2_op_registry_entry_unref(ere); _e_fm_client_send(E_FM_OP_OVERWRITE_RESPONSE_NO, ere->id, NULL, 0); } static void _e_fm_overwrite_rename_yes_cb(void *data, char *text) { E_Fm2_Op_Registry_Entry *ere = data; char newpath[PATH_MAX]; char *args = NULL; const char *f; size_t size = 0; size_t length = 0; if ((!text) || (!text[0])) return; if ((!ere->src) || (!ere->dst)) return; f = ecore_file_file_get(ere->dst); if (!f) return; length = strlen(text); if (f - ere->dst + length >= PATH_MAX) return; newpath[0] = 0; strncat(newpath, ere->dst, f - ere->dst); strcat(newpath, text); if (e_filereg_file_protected(newpath)) return; length = 0; args = e_util_string_append_quoted(args, &size, &length, ere->src); if (!args) return; args = e_util_string_append_char(args, &size, &length, ' '); if (!args) return; args = e_util_string_append_quoted(args, &size, &length, newpath); if (!args) return; e_fm2_client_file_copy(ere->e_fm, args); free(args); } static void _e_fm_overwrite_rename(void *data EINA_UNUSED, E_Dialog *dialog) { char text[PATH_MAX + 256]; int id = (int)(intptr_t)E_OBJECT(dialog)->data; E_Fm2_Op_Registry_Entry *ere; E_Entry_Dialog *ed; E_Fm2_Smart_Data *sd; const char *file; ere = e_fm2_op_registry_entry_get(id); if (!ere) return; sd = evas_object_smart_data_get(ere->e_fm); e_object_del(E_OBJECT(dialog)); file = ecore_file_file_get(ere->src); snprintf(text, sizeof(text), _("Rename %s to:"), file); ed = e_entry_dialog_show(_("Rename File"), "edit-rename", text, file, NULL, NULL, _e_fm_overwrite_rename_yes_cb, NULL, ere); sd->rename_dialogs = eina_list_append(sd->rename_dialogs, ed); e_object_del_attach_func_set(E_OBJECT(ed), _e_fm_overwrite_rename_del); E_OBJECT(ed)->data = ere; e_fm2_op_registry_entry_ref(ere); _e_fm2_op_registry_go_on(id); } static void _e_fm_overwrite_yes_cb(void *data EINA_UNUSED, E_Dialog *dialog) { int id = (int)(intptr_t)E_OBJECT(dialog)->data; _e_fm2_op_registry_go_on(id); _e_fm_client_send(E_FM_OP_OVERWRITE_RESPONSE_YES, id, NULL, 0); e_object_del(E_OBJECT(dialog)); } static void _e_fm_overwrite_yes_all_cb(void *data EINA_UNUSED, E_Dialog *dialog) { int id = (int)(intptr_t)E_OBJECT(dialog)->data; _e_fm2_op_registry_go_on(id); _e_fm_client_send(E_FM_OP_OVERWRITE_RESPONSE_YES_ALL, id, NULL, 0); e_object_del(E_OBJECT(dialog)); } static E_Dialog * _e_fm_error_dialog(int pid, const char *str) { E_Dialog *dialog; void *id; char text[4096 + PATH_MAX]; E_Fm2_Op_Registry_Entry *ere; E_Fm2_Smart_Data *sd; E_Fm2_Mount *m; Eina_Bool devlink = EINA_FALSE; id = (intptr_t *)(long)pid; ere = e_fm2_op_registry_entry_get(pid); if (!ere) return NULL; sd = evas_object_smart_data_get(ere->e_fm); E_LIST_FOREACH(sd->icons, _e_fm2_cb_drag_finished_show); while (sd->realpath) { /* trying to make or move a link onto a device will fail, create button for * moving source at this point if this is what failed */ struct stat st; if (sd->config->view.link_drop) break; m = e_fm2_device_mount_find(sd->realpath); if (!m) break; if (ere->op == E_FM_OP_SYMLINK) { devlink = EINA_TRUE; break; } if (stat(ere->src, &st)) break; if (S_ISLNK(st.st_mode)) devlink = EINA_TRUE; break; } dialog = e_dialog_new(NULL, "E", "_fm_error_dialog"); E_OBJECT(dialog)->data = id; e_dialog_button_add(dialog, _("Retry"), NULL, _e_fm_error_retry_cb, NULL); e_dialog_button_add(dialog, _("Abort"), NULL, _e_fm_error_abort_cb, NULL); if (devlink) e_dialog_button_add(dialog, _("Move Source"), NULL, _e_fm_error_link_source, ere); e_dialog_button_add(dialog, _("Ignore this"), NULL, _e_fm_error_ignore_this_cb, NULL); e_dialog_button_add(dialog, _("Ignore all"), NULL, _e_fm_error_ignore_all_cb, NULL); e_dialog_button_focus_num(dialog, 0); e_dialog_title_set(dialog, _("Error")); snprintf(text, sizeof(text), _("An error occurred while performing an operation." "%s"), str); e_dialog_text_set(dialog, text); elm_win_center(dialog->win, 1, 1); e_dialog_show(dialog); return dialog; } static void _e_fm_error_retry_cb(void *data EINA_UNUSED, E_Dialog *dialog) { int id = (int)(intptr_t)E_OBJECT(dialog)->data; _e_fm2_op_registry_go_on(id); _e_fm_client_send(E_FM_OP_ERROR_RESPONSE_RETRY, id, NULL, 0); e_object_del(E_OBJECT(dialog)); } static void _e_fm_error_abort_cb(void *data EINA_UNUSED, E_Dialog *dialog) { int id = (int)(intptr_t)E_OBJECT(dialog)->data; _e_fm2_op_registry_aborted(id); _e_fm_client_send(E_FM_OP_ERROR_RESPONSE_ABORT, id, NULL, 0); e_object_del(E_OBJECT(dialog)); } static void _e_fm_error_link_source(void *data, E_Dialog *dialog) { E_Fm2_Op_Registry_Entry *ere = data; int id = (int)(intptr_t)E_OBJECT(dialog)->data; char *file; char newpath[PATH_MAX]; char *args = NULL; const char *f; size_t size = 0; size_t length = 0; file = ecore_file_readlink(ere->src); if (!file) file = (char *)ere->src; f = ecore_file_file_get(file); if (!f) return; length = strlen(f); if (strlen(ere->dst) + length >= PATH_MAX) return; newpath[0] = 0; strncat(newpath, ere->dst, f - ere->dst); strcat(newpath, f); if (e_filereg_file_protected(newpath)) return; length = 0; args = e_util_string_append_quoted(args, &size, &length, file); if (!args) return; args = e_util_string_append_char(args, &size, &length, ' '); if (!args) return; args = e_util_string_append_quoted(args, &size, &length, newpath); if (!args) return; e_fm2_client_file_move(ere->e_fm, args); free(args); if (file != ere->src) free(file); _e_fm2_op_registry_aborted(id); _e_fm_client_send(E_FM_OP_ERROR_RESPONSE_ABORT, id, NULL, 0); e_object_del(E_OBJECT(dialog)); } static void _e_fm_error_ignore_this_cb(void *data EINA_UNUSED, E_Dialog *dialog) { int id = (int)(intptr_t)E_OBJECT(dialog)->data; _e_fm2_op_registry_go_on(id); _e_fm_client_send(E_FM_OP_ERROR_RESPONSE_IGNORE_THIS, id, NULL, 0); e_object_del(E_OBJECT(dialog)); } static void _e_fm_error_ignore_all_cb(void *data EINA_UNUSED, E_Dialog *dialog) { int id = (int)(intptr_t)E_OBJECT(dialog)->data; _e_fm2_op_registry_go_on(id); _e_fm_client_send(E_FM_OP_ERROR_RESPONSE_IGNORE_ALL, id, NULL, 0); e_object_del(E_OBJECT(dialog)); } static void _e_fm_device_error_dialog(const char *title, const char *msg, const char *pstr) { E_Dialog *dialog; char text[PATH_MAX]; const char *u, *d, *n, *m; dialog = e_dialog_new(NULL, "E", "_fm_device_error_dialog"); e_dialog_title_set(dialog, title); e_dialog_icon_set(dialog, "drive-harddisk", 64); e_dialog_button_add(dialog, _("OK"), NULL, NULL, NULL); u = pstr; pstr += strlen(pstr) + 1; d = pstr; pstr += strlen(pstr) + 1; n = pstr; pstr += strlen(pstr) + 1; m = pstr; snprintf(text, sizeof(text), "%s%s%s%s%s", msg, u, d, n, m); e_dialog_text_set(dialog, text); elm_win_center(dialog->win, 1, 1); e_dialog_button_focus_num(dialog, 0); e_dialog_show(dialog); } static void _e_fm2_file_application_properties(void *data, E_Menu *m EINA_UNUSED, E_Menu_Item *mi EINA_UNUSED) { Efreet_Desktop *desktop; E_Fm2_Icon *ic; char buf[PATH_MAX]; ic = data; if (!_e_fm2_icon_realpath(ic, buf, sizeof(buf))) return; desktop = efreet_desktop_get(buf); e_desktop_edit(desktop); } static void _e_fm2_file_properties(void *data, E_Menu *m EINA_UNUSED, E_Menu_Item *mi EINA_UNUSED) { E_Fm2_Icon *ic; ic = data; if ((ic->entry_dialog) || (ic->entry_widget)) return; if (ic->prop_dialog) e_object_del(E_OBJECT(ic->prop_dialog)); ic->prop_dialog = e_fm_prop_file(ic); E_OBJECT(ic->prop_dialog)->data = ic; e_object_del_attach_func_set(E_OBJECT(ic->prop_dialog), _e_fm2_file_properties_delete_cb); } static void _e_fm2_file_properties_delete_cb(void *obj) { E_Fm2_Icon *ic; ic = E_OBJECT(obj)->data; ic->prop_dialog = NULL; } static void _e_fm2_file_delete_menu(void *data, E_Menu *m EINA_UNUSED, E_Menu_Item *mi EINA_UNUSED) { E_Fm2_Icon *ic = data; if ((!ic) || (!ic->sd)) return; _e_fm2_file_delete(ic->sd->obj); } static void _e_fm2_file_delete(Evas_Object *obj) { E_Dialog *dialog; E_Fm2_Icon *ic; char text[4096 + 256]; Eina_List *sel; int n = 0, folder_count = 0; ic = _e_fm2_icon_first_selected_find(obj); if (!ic) return; if (ic->dialog) return; dialog = e_dialog_new(NULL, "E", "_fm_file_delete_dialog"); ic->dialog = dialog; E_OBJECT(dialog)->data = ic; e_object_del_attach_func_set(E_OBJECT(dialog), _e_fm2_file_delete_delete_cb); e_dialog_button_add(dialog, _("Delete"), NULL, _e_fm2_file_delete_yes_cb, ic); e_dialog_button_add(dialog, _("No"), NULL, _e_fm2_file_delete_no_cb, ic); e_dialog_button_focus_num(dialog, 0); e_dialog_title_set(dialog, _("Confirm Delete")); e_dialog_icon_set(dialog, "dialog-warning", 64); sel = e_fm2_selected_list_get(obj); if (sel) { n = eina_list_count(sel); folder_count = eina_list_count(ic->sd->icons); } if ((!sel) || (n == 1)) snprintf(text, sizeof(text), _("Are you sure you want to delete" "%s?"), ic->info.file); else if (n == folder_count) snprintf(text, sizeof(text), _("Are you sure you want to delete" "all the %d files in" "%s?"), n, ic->sd->realpath); else { /* Here the singular version is not used in english, but plural support * is nonetheless needed for languages who have multiple plurals * depending on the number of files. */ snprintf(text, sizeof(text), P_("Are you sure you want to delete" "the %d selected file in" "%s?", "Are you sure you want to delete" "the %d selected files in" "%s?", n), n, ic->sd->realpath); } if (sel) eina_list_free(sel); e_dialog_text_set(dialog, text); elm_win_center(dialog->win, 1, 1); e_dialog_show(dialog); } static void _e_fm2_file_delete_delete_cb(void *obj) { E_Fm2_Icon *ic; ic = E_OBJECT(obj)->data; ic->dialog = NULL; } static void _e_fm2_file_delete_yes_cb(void *data, E_Dialog *dialog) { E_Fm2_Icon *ic, *ic_next; char buf[PATH_MAX]; char *files = NULL; size_t size = 0; size_t len = 0; Eina_List *sel, *l; E_Fm2_Icon_Info *ici; Eina_Bool memerr = EINA_FALSE; ic = data; ic->dialog = NULL; e_object_del(E_OBJECT(dialog)); ic_next = _e_fm2_icon_next_find(ic->sd->obj, 1, NULL, NULL); sel = e_fm2_selected_list_get(ic->sd->obj); if (sel && (eina_list_count(sel) != 1)) { EINA_LIST_FOREACH(sel, l, ici) { if (ic_next && (&(ic_next->info) == ici)) ic_next = NULL; snprintf(buf, sizeof(buf), "%s/%s", ic->sd->realpath, ici->file); if (e_filereg_file_protected(buf)) continue; if (!memerr) { files = e_util_string_append_quoted(files, &size, &len, buf); if (!files) memerr = EINA_TRUE; else { if (eina_list_next(l)) { files = e_util_string_append_char(files, &size, &len, ' '); if (!files) memerr = EINA_TRUE; } } } evas_object_pass_events_set(ici->ic->obj, 1); } eina_list_free(sel); } else { if (sel) eina_list_free(sel); _e_fm2_icon_realpath(ic, buf, sizeof(buf)); if (e_filereg_file_protected(buf)) return; evas_object_pass_events_set(ic->obj, 1); files = e_util_string_append_quoted(files, &size, &len, buf); } if (files) { _e_fm_client_file_del(files, e_config->filemanager_secure_rm | ic->sd->config->secure_rm, ic->sd->obj); free(files); } if (ic_next) { _e_fm2_icon_select(ic_next); evas_object_smart_callback_call(ic_next->sd->obj, "selection_change", NULL); _e_fm2_icon_make_visible(ic_next); } evas_object_smart_callback_call(ic->sd->obj, "files_deleted", NULL); } static void _e_fm2_file_delete_no_cb(void *data, E_Dialog *dialog) { E_Fm2_Icon *ic; ic = data; ic->dialog = NULL; e_object_del(E_OBJECT(dialog)); } static Eina_Bool _e_fm2_sys_suspend_hibernate(void *d EINA_UNUSED, int type EINA_UNUSED, void *ev EINA_UNUSED) { Eina_List *l, *ll, *lll; E_Volume *v; E_Fm2_Mount *m; EINA_LIST_FOREACH(e_fm2_device_volume_list_get(), l, v) { EINA_LIST_FOREACH_SAFE(v->mounts, ll, lll, m) e_fm2_device_unmount(m); } return ECORE_CALLBACK_RENEW; } static void _e_fm2_refresh_job_cb(void *data) { E_Fm2_Smart_Data *sd; sd = evas_object_smart_data_get(data); if (!sd) return; e_fm2_refresh(data); sd->refresh_job = NULL; } static void _e_fm2_live_file_add(Evas_Object *obj, const char *file, const char *file_rel, int after, E_Fm2_Finfo *finf) { E_Fm2_Smart_Data *sd; E_Fm2_Action *a; sd = evas_object_smart_data_get(obj); if (!sd) return; a = E_NEW(E_Fm2_Action, 1); if (!a) return; sd->live.actions = eina_list_append(sd->live.actions, a); a->type = FILE_ADD; a->file = eina_stringshare_add(file); a->file2 = eina_stringshare_add(file_rel); a->flags = after; if (finf) memcpy(&(a->finf), finf, sizeof(E_Fm2_Finfo)); a->finf.lnk = eina_stringshare_add(a->finf.lnk); a->finf.rlnk = eina_stringshare_add(a->finf.rlnk); _e_fm2_live_process_begin(obj); } static void _e_fm2_live_file_del(Evas_Object *obj, const char *file) { E_Fm2_Smart_Data *sd; E_Fm2_Action *a; sd = evas_object_smart_data_get(obj); if (!sd) return; a = E_NEW(E_Fm2_Action, 1); if (!a) return; sd->live.actions = eina_list_append(sd->live.actions, a); a->type = FILE_DEL; a->file = eina_stringshare_add(file); _e_fm2_live_process_begin(obj); } static void _e_fm2_live_file_changed(Evas_Object *obj, const char *file, E_Fm2_Finfo *finf) { E_Fm2_Smart_Data *sd; E_Fm2_Action *a; sd = evas_object_smart_data_get(obj); if (!sd) return; a = E_NEW(E_Fm2_Action, 1); if (!a) return; sd->live.actions = eina_list_append(sd->live.actions, a); a->type = FILE_CHANGE; a->file = eina_stringshare_add(file); if (finf) memcpy(&(a->finf), finf, sizeof(E_Fm2_Finfo)); a->finf.lnk = eina_stringshare_add(a->finf.lnk); a->finf.rlnk = eina_stringshare_add(a->finf.rlnk); _e_fm2_live_process_begin(obj); } static void _e_fm2_live_process_begin(Evas_Object *obj) { E_Fm2_Smart_Data *sd; sd = evas_object_smart_data_get(obj); if (!sd->live.actions) return; if ((sd->live.idler) || (sd->live.timer) || (sd->listing) || (sd->scan_timer)) return; sd->live.idler = ecore_idler_add(_e_fm2_cb_live_idler, obj); sd->live.timer = ecore_timer_loop_add(0.2, _e_fm2_cb_live_timer, obj); sd->tmp.last_insert = NULL; } static void _e_fm2_live_process_end(Evas_Object *obj) { E_Fm2_Smart_Data *sd; E_Fm2_Action *a; sd = evas_object_smart_data_get(obj); EINA_LIST_FREE(sd->live.actions, a) { eina_stringshare_del(a->file); eina_stringshare_del(a->file2); eina_stringshare_del(a->finf.lnk); eina_stringshare_del(a->finf.rlnk); free(a); } if (sd->live.idler) { ecore_idler_del(sd->live.idler); sd->live.idler = NULL; } if (sd->live.timer) { ecore_timer_del(sd->live.timer); sd->live.timer = NULL; } sd->tmp.last_insert = NULL; } static void _e_fm2_live_process(Evas_Object *obj) { E_Fm2_Smart_Data *sd; E_Fm2_Action *a; Eina_List *l; E_Fm2_Icon *ic; sd = evas_object_smart_data_get(obj); if (!sd->live.actions) return; a = eina_list_data_get(sd->live.actions); sd->live.actions = eina_list_remove_list(sd->live.actions, sd->live.actions); switch (a->type) { case FILE_ADD: /* new file to sort in place */ if (!strcmp(a->file, ".order")) { sd->order_file = EINA_TRUE; /* FIXME: reload fm view */ } else { if (!((a->file[0] == '.') && (!sd->show_hidden_files))) _e_fm2_file_add(obj, a->file, 1, a->file2, a->flags, &(a->finf)); } break; case FILE_DEL: if (!strcmp(a->file, ".order")) { sd->order_file = EINA_FALSE; /* FIXME: reload fm view */ } else { if (!((a->file[0] == '.') && (!sd->show_hidden_files))) _e_fm2_file_del(obj, a->file); sd->live.deletions = EINA_TRUE; } break; case FILE_CHANGE: if (!strcmp(a->file, ".order")) { /* FIXME: reload fm view - ignore for now */ } else { if (!((a->file[0] == '.') && (!sd->show_hidden_files))) { EINA_LIST_FOREACH(sd->icons, l, ic) { if (!strcmp(ic->info.file, a->file)) { if (ic->removable_state_change) { _e_fm2_icon_unfill(ic); _e_fm2_icon_fill(ic, &(a->finf)); ic->removable_state_change = EINA_FALSE; if ((ic->realized) && (ic->obj_icon)) { _e_fm2_icon_removable_update(ic); _e_fm2_icon_label_set(ic, ic->obj); } } else if (!eina_str_has_extension(ic->info.file, ".part")) { int realized; realized = ic->realized; if (realized) _e_fm2_icon_unrealize(ic); _e_fm2_icon_unfill(ic); _e_fm2_icon_fill(ic, &(a->finf)); if (realized) _e_fm2_icon_realize(ic); } break; } } } } break; default: break; } eina_stringshare_del(a->file); eina_stringshare_del(a->file2); eina_stringshare_del(a->finf.lnk); eina_stringshare_del(a->finf.rlnk); free(a); } static Eina_Bool _e_fm2_cb_live_idler(void *data) { E_Fm2_Smart_Data *sd; double t; sd = evas_object_smart_data_get(data); if (!sd) return ECORE_CALLBACK_CANCEL; t = ecore_time_get(); do { if (!sd->live.actions) break; _e_fm2_live_process(data); } while ((ecore_time_get() - t) > 0.02); if (sd->live.actions) return ECORE_CALLBACK_RENEW; _e_fm2_live_process_end(data); _e_fm2_cb_live_timer(data); if ((sd->order_file) || (sd->config->view.always_order)) { e_fm2_refresh(data); } sd->live.idler = NULL; return ECORE_CALLBACK_CANCEL; } static Eina_Bool _e_fm2_cb_live_timer(void *data) { E_Fm2_Smart_Data *sd; sd = evas_object_smart_data_get(data); if (!sd) return ECORE_CALLBACK_CANCEL; if (sd->queue) _e_fm2_queue_process(data); else if (sd->iconlist_changed) { if (sd->resize_job) ecore_job_del(sd->resize_job); sd->resize_job = ecore_job_add(_e_fm2_cb_resize_job, sd->obj); } else { if (sd->live.deletions) { sd->iconlist_changed = EINA_TRUE; if (sd->resize_job) ecore_job_del(sd->resize_job); sd->resize_job = ecore_job_add(_e_fm2_cb_resize_job, sd->obj); } } sd->live.deletions = EINA_FALSE; sd->live.timer = NULL; if ((!sd->queue) && (!sd->live.idler)) return ECORE_CALLBACK_CANCEL; sd->live.timer = ecore_timer_loop_add(0.2, _e_fm2_cb_live_timer, data); return ECORE_CALLBACK_CANCEL; } static int _e_fm2_theme_edje_object_set(E_Fm2_Smart_Data *sd, Evas_Object *o, const char *category, const char *group) { char buf[1024]; int ret; if (sd->custom_theme_content) snprintf(buf, sizeof(buf), "e/fileman/%s/%s", sd->custom_theme_content, group); else snprintf(buf, sizeof(buf), "e/fileman/default/%s", group); if (sd->custom_theme) { if (edje_object_file_set(o, sd->custom_theme, buf)) return 1; } if (sd->custom_theme) { if (!ecore_file_exists(sd->custom_theme)) { eina_stringshare_del(sd->custom_theme); sd->custom_theme = NULL; } } ret = e_theme_edje_object_set(o, category, buf); return ret; } static int _e_fm2_theme_edje_icon_object_set(E_Fm2_Smart_Data *sd, Evas_Object *o, const char *category, const char *group) { char buf[1024]; int ret; // if (sd->custom_theme_content) // snprintf(buf, sizeof(buf), "e/icons/fileman/%s/%s", sd->custom_theme_content, group); // else snprintf(buf, sizeof(buf), "e/icons/fileman/mime/%s", group); if (sd->custom_theme) { if (edje_object_file_set(o, sd->custom_theme, buf)) return 1; } if (sd->custom_theme) { if (!ecore_file_exists(sd->custom_theme)) { eina_stringshare_del(sd->custom_theme); sd->custom_theme = NULL; } } ret = e_theme_edje_object_set(o, category, buf); return ret; } static void _e_fm2_volume_mount(void *data, E_Menu *m EINA_UNUSED, E_Menu_Item *mi EINA_UNUSED) { E_Volume *v; const char *mp; v = data; if (!v) return; mp = e_fm2_device_volume_mountpoint_get(v); _e_fm2_client_mount(v->udi, mp); eina_stringshare_del(mp); } static void _e_fm2_volume_unmount(void *data, E_Menu *m EINA_UNUSED, E_Menu_Item *mi EINA_UNUSED) { E_Volume *v; v = data; if (!v) return; v->auto_unmount = EINA_FALSE; _e_fm2_client_unmount(v->udi); } static void _e_fm2_volume_eject(void *data, E_Menu *m EINA_UNUSED, E_Menu_Item *mi EINA_UNUSED) { E_Volume *v; v = data; if (!v) return; v->auto_unmount = EINA_FALSE; _e_fm2_client_eject(v->udi); } static void _update_volume_icon(E_Volume *v, E_Fm2_Icon *ic) { Evas_Object *e = e_icon_edje_get(ic->obj_icon); if (e) { if (ic->info.removable_full) e_icon_edje_emit(ic->obj_icon, "e,state,removable,full", "e"); else e_icon_edje_emit(ic->obj_icon, "e,state,removable,empty", "e"); } if (v) { if (v->mounted) edje_object_signal_emit(ic->obj, "e,state,volume,mounted", "e"); else edje_object_signal_emit(ic->obj, "e,state,volume,unmounted", "e"); } else edje_object_signal_emit(ic->obj, "e,state,volume,off", "e"); } static void _e_fm2_volume_icon_update(E_Volume *v) { Evas_Object *o; char file[PATH_MAX], fav[PATH_MAX]; const char *desk; Eina_List *l; E_Fm2_Icon *ic; if (!v || !v->storage) return; e_user_dir_snprintf(fav, sizeof(fav), "fileman/favorites"); desk = efreet_desktop_dir_get(); snprintf(file, sizeof(file), "|%s_%d.desktop", ecore_file_file_get(v->storage->udi), v->partition_number); EINA_LIST_FOREACH(_e_fm2_list, l, o) { const char *rp; if ((_e_fm2_list_walking > 0) && (eina_list_data_find(_e_fm2_list_remove, o))) continue; rp = e_fm2_real_path_get(o); if ((rp) && (strcmp(rp, fav)) && (strcmp(rp, desk))) continue; ic = _e_fm2_icon_find(o, file); if (ic) _update_volume_icon(v, ic); } } static void _e_fm2_icon_removable_update(E_Fm2_Icon *ic) { E_Volume *v; if (!ic) return; v = e_fm2_device_volume_find(ic->info.link); _update_volume_icon(v, ic); } static void _e_fm2_operation_abort_internal(E_Fm2_Op_Registry_Entry *ere) { ere->status = E_FM2_OP_STATUS_ABORTED; ere->finished = 1; ere->needs_attention = 0; ere->dialog = NULL; e_fm2_op_registry_entry_changed(ere); _e_fm_client_send(E_FM_OP_ABORT, ere->id, NULL, 0); } E_API void e_fm2_operation_abort(int id) { E_Fm2_Op_Registry_Entry *ere; ere = e_fm2_op_registry_entry_get(id); if (!ere) return; e_fm2_op_registry_entry_ref(ere); e_fm2_op_registry_entry_abort(ere); e_fm2_op_registry_entry_unref(ere); } E_API Eina_Bool e_fm2_optimal_size_calc(Evas_Object *obj, int minw, int maxw, int maxh, int *w, int *h) { int x, y, step_w, step_h; EFM_SMART_CHECK(EINA_FALSE); if ((!w) || (!h)) return EINA_FALSE; if (!sd->icons) return EINA_FALSE; if (maxw < 0) maxw = 0; if (maxh < 0) maxh = 0; step_w = sd->min.w + 5, step_h = sd->min.h + 5; switch (_e_fm2_view_mode_get(sd)) { case E_FM2_VIEW_MODE_LIST: *w = MIN(step_w, maxw); *h = MIN(step_h * eina_list_count(sd->icons), (unsigned int)maxh); return EINA_TRUE; default: break; } y = x = (int)sqrt(eina_list_count(sd->icons)); if (maxw && (x * step_w > maxw)) { x = maxw / step_w; y = (eina_list_count(sd->icons) / x) + ((maxw % step_w) ? 1 : 0); } if (minw && (x * step_w < minw)) { x = minw / step_w; y = (eina_list_count(sd->icons) / x) + ((minw % step_w) ? 1 : 0); } *w = step_w * x; *w = MIN(*w, maxw); *h = step_h * y; *h = MIN(*h, maxh); return EINA_TRUE; } E_API E_Fm2_View_Mode e_fm2_view_mode_get(Evas_Object *obj) { EFM_SMART_CHECK(0); return _e_fm2_view_mode_get(sd); } E_API Eina_Bool e_fm2_typebuf_visible_get(Evas_Object *obj) { EFM_SMART_CHECK(EINA_FALSE); return sd->typebuf_visible; } E_API void e_fm2_typebuf_clear(Evas_Object *obj) { EFM_SMART_CHECK(); _e_fm2_typebuf_hide(obj); } E_API void e_fm2_overlay_clip_to(Evas_Object *obj, Evas_Object *clip) { int x, y, w, h; EFM_SMART_CHECK(); if (sd->overlay_clip) { evas_object_event_callback_del_full(sd->overlay_clip, EVAS_CALLBACK_MOVE, _e_fm2_overlay_clip_move, sd); evas_object_event_callback_del_full(sd->overlay_clip, EVAS_CALLBACK_RESIZE, _e_fm2_overlay_clip_resize, sd); } sd->overlay_clip = clip; if (clip) { evas_object_clip_set(sd->overlay, clip); evas_object_geometry_get(clip, &x, &y, &w, &h); evas_object_move(sd->overlay, x, y); evas_object_resize(sd->overlay, w, h); evas_object_event_callback_add(clip, EVAS_CALLBACK_MOVE, _e_fm2_overlay_clip_move, sd); evas_object_event_callback_add(clip, EVAS_CALLBACK_RESIZE, _e_fm2_overlay_clip_resize, sd); } else { evas_object_clip_set(sd->overlay, sd->clip); evas_object_move(sd->overlay, sd->x, sd->y); evas_object_resize(sd->overlay, sd->w, sd->h); } } E_API const char * e_fm2_real_path_map(const char *dev, const char *path) { return _e_fm2_dev_path_map(NULL, dev, path); } E_API void e_fm2_favorites_init(void) { Eina_List *files; char buf[PATH_MAX], buf2[PATH_MAX], *file; // make dir for favorites and install ones shipped e_user_dir_concat_static(buf, "fileman/favorites"); ecore_file_mkpath(buf); if (!ecore_file_dir_is_empty(buf)) return; e_prefix_data_concat(buf, sizeof(buf), "data/favorites"); files = ecore_file_ls(buf); if (!files) return; EINA_LIST_FREE(files, file) { e_prefix_data_snprintf(buf, sizeof(buf), "data/favorites/%s", file); snprintf(buf2, sizeof(buf2), "%s/fileman/favorites/%s", e_user_dir_get(), file); ecore_file_cp(buf, buf2); free(file); } } E_API unsigned int e_fm2_selected_count(Evas_Object *obj) { EFM_SMART_CHECK(0); return eina_list_count(sd->selected_icons); } E_API E_Fm2_Icon_Info * e_fm2_drop_icon_get(Evas_Object *obj) { EFM_SMART_CHECK(NULL); return sd->drop_icon ? &sd->drop_icon->info : NULL; } E_API Eina_List * e_fm2_uri_path_list_get(const Eina_List *uri_list) { E_Fm2_Uri *uri; const Eina_List *l; Eina_List *path_list = NULL; char current_hostname[_POSIX_HOST_NAME_MAX]; const char *uri_str; if (gethostname(current_hostname, _POSIX_HOST_NAME_MAX) == -1) current_hostname[0] = '\0'; EINA_LIST_FOREACH(uri_list, l, uri_str) { if (!(uri = _e_fm2_uri_parse(uri_str))) continue; if (!uri->hostname || !strcmp(uri->hostname, "localhost") || !strcmp(uri->hostname, current_hostname)) { path_list = eina_list_append(path_list, uri->path); } else eina_stringshare_del(uri->path); eina_stringshare_del(uri->hostname); E_FREE(uri); } return path_list; } E_API Efreet_Desktop * e_fm2_desktop_get(Evas_Object *obj) { EFM_SMART_CHECK(NULL); if (_e_fm2_desktop_open(sd) != 1) return NULL; return sd->desktop; } E_API void e_fm2_drop_menu(Evas_Object *obj, char *args) { E_Menu *menu; E_Menu_Item *item; E_Zone *zone; int x, y; EFM_SMART_CHECK(); EINA_SAFETY_ON_TRUE_RETURN(!!sd->menu); sd->menu = menu = e_menu_new(); if (!menu) return; 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, 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, obj); e_menu_item_icon_edje_set(item, e_theme_edje_file_get("base/theme/fileman", "e/fileman/default/button/move"), "e/fileman/default/button/move"); 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, obj); e_util_menu_item_theme_icon_set(item, "emblem-symbolic-link"); item = e_menu_item_new(menu); e_menu_item_separator_set(item, 1); 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, obj); e_menu_item_icon_edje_set(item, e_theme_edje_file_get("base/theme/fileman", "e/fileman/default/button/abort"), "e/fileman/default/button/abort"); ecore_evas_pointer_xy_get(e_comp->ee, &x, &y); zone = e_zone_current_get(); 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; } E_API E_Fm2_Icon * e_fm2_icon_editing_get(Evas_Object *obj) { EFM_SMART_CHECK(NULL); return sd->iop_icon; }