#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 teh 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;
} new_file;
E_Fm2_Icon *last_selected;
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 : 1;
Eina_Bool order_file : 1;
Eina_Bool typebuf_visible : 1;
Eina_Bool show_hidden_files : 1;
Eina_Bool listing : 1;
Eina_Bool inherited_dir_props : 1;
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 : 1;
} live;
struct
{
char *buf;
const char *start;
Ecore_Timer *timer;
unsigned int wildcard;
Eina_Bool setting : 1;
Eina_Bool disabled : 1;
} typebuf;
int busy_count;
E_Object *eobj;
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 : 1;
Eina_Bool drop_in_show : 1;
Eina_Bool drop_all : 1;
Eina_Bool drag : 1;
Eina_Bool selecting : 1;
Eina_Bool toomany : 1;
struct
{
int ox, oy;
int x, y, w, h;
} selrect;
E_Fm2_Icon *iop_icon;
Eina_List *handlers;
Ecore_Event_Handler *efreet_cache_update;
Efreet_Desktop *desktop;
};
struct _E_Fm2_Region
{
E_Fm2_Smart_Data *sd;
Evas_Coord x, y, w, h;
Eina_List *list;
Eina_Bool realized : 1;
};
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;
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 : 1;
Eina_Bool dnd : 1; // currently dragging
Eina_Bool src : 1; // drag source
Eina_Bool hidden : 1; // dropped into different dir
} drag;
int saved_rel;
Eina_Bool realized : 1;
Eina_Bool selected : 1;
Eina_Bool last_selected : 1;
Eina_Bool saved_pos : 1;
Eina_Bool odd : 1;
Eina_Bool down_sel : 1;
Eina_Bool removable_state_change : 1;
Eina_Bool thumb_failed : 1;
Eina_Bool queued : 1;
Eina_Bool inserted : 1;
};
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 Evas_Object *_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_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_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 __UNUSED__, void *event __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 __UNUSED__, E_Menu_Item *mi __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_1_handler(E_Fm2_Icon *ic, int up, void *evas_event);
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 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_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,
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.link)
r = snprintf(buf, buflen, "%s", ic->info.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)
{
#if 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)
{
#if 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)
{
#if 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 __UNUSED__)
{
efreet_mime_type_cache_flush();
return ECORE_CALLBACK_RENEW;
}
static Eina_Bool
_e_fm2_mime_clear_cb(void *data __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_op_registry_entry_add_cb(void *data __UNUSED__, int type __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 __UNUSED__, int type __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 __UNUSED__, int type __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_add(60.0, _e_fm2_mime_flush_cb, NULL);
_e_fm2_mime_clear = ecore_timer_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_favorites_thread = ecore_thread_run(_e_fm2_favorites_thread_cb,
_e_fm2_thread_cleanup_cb,
_e_fm2_thread_cleanup_cb, 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)
{
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);
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;
}
EAPI 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 __UNUSED__, Ecore_Thread *et __UNUSED__)
{
e_fm2_favorites_init();
}
static void
_e_fm2_thread_cleanup_cb(void *d __UNUSED__, Ecore_Thread *et __UNUSED__)
{
_e_fm2_favorites_thread = NULL;
}
EAPI 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 pont 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);
e_win_centered_set(dialog->win, 1);
e_dialog_show(dialog);
return;
}
if (real_path && (sd->realpath == real_path)) return;
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->efreet_cache_update)
ecore_event_handler_del(sd->efreet_cache_update);
sd->efreet_cache_update = NULL;
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;
}
EAPI void
e_fm2_underlay_show(Evas_Object *obj)
{
EFM_SMART_CHECK();
evas_object_show(sd->underlay);
}
EAPI void
e_fm2_underlay_hide(Evas_Object *obj)
{
EFM_SMART_CHECK();
evas_object_hide(sd->underlay);
}
EAPI void
e_fm2_all_unsel(Evas_Object *obj)
{
EFM_SMART_CHECK();
_e_fm2_icon_desel_any(obj);
}
EAPI void
e_fm2_all_sel(Evas_Object *obj)
{
EFM_SMART_CHECK();
_e_fm2_icon_sel_any(obj);
}
EAPI void
e_fm2_first_sel(Evas_Object *obj)
{
EFM_SMART_CHECK();
_e_fm2_icon_sel_first(obj, EINA_FALSE);
}
EAPI void
e_fm2_last_sel(Evas_Object *obj)
{
EFM_SMART_CHECK();
_e_fm2_icon_sel_last(obj, EINA_FALSE);
}
EAPI 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");
}
EAPI 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");
}
EAPI 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();
}
EAPI void
e_fm2_refresh(Evas_Object *obj)
{
EFM_SMART_CHECK();
_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;
}
EAPI 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;
}
EAPI const char *
e_fm2_real_path_get(Evas_Object *obj)
{
EFM_SMART_CHECK(NULL);
return sd->realpath;
}
EAPI void
e_fm2_parent_go(Evas_Object *obj)
{
char *p, *path;
EFM_SMART_CHECK();
if (!sd->path) return;
path = strdupa(sd->path);
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);
}
}
EAPI 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);
}
EAPI E_Fm2_Config *
e_fm2_config_get(Evas_Object *obj)
{
EFM_SMART_CHECK(NULL);
return sd->config;
}
EAPI 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;
}
EAPI 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;
}
EAPI void
e_fm2_deselect_all(Evas_Object *obj)
{
EFM_SMART_CHECK();
_e_fm2_icon_desel_any(obj);
}
EAPI 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;
}
}
}
EAPI 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;
}
}
}
EAPI 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;
}
EAPI 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;
}
EAPI 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;
}
EAPI void
e_fm2_icon_menu_flags_set(Evas_Object *obj, E_Fm2_Menu_Flags flags)
{
EFM_SMART_CHECK();
sd->icon_menu.flags = flags;
}
EAPI E_Fm2_Menu_Flags
e_fm2_icon_menu_flags_get(Evas_Object *obj)
{
EFM_SMART_CHECK(0);
return sd->icon_menu.flags;
}
EAPI void
e_fm2_view_flags_set(Evas_Object *obj, E_Fm2_View_Flags flags)
{
EFM_SMART_CHECK();
sd->view_flags = flags;
}
EAPI E_Fm2_View_Flags
e_fm2_view_flags_get(Evas_Object *obj)
{
EFM_SMART_CHECK(0);
return sd->view_flags;
}
EAPI E_Object *
e_fm2_window_object_get(Evas_Object *obj)
{
EFM_SMART_CHECK(NULL);
return sd->eobj;
}
EAPI void
e_fm2_window_object_set(Evas_Object *obj, E_Object *eobj)
{
const char *drop[] = {"text/uri-list", "XdndDirectSave0"};
EFM_SMART_CHECK();
sd->eobj = eobj;
if (sd->drop_handler) e_drop_handler_del(sd->drop_handler);
sd->drop_handler = e_drop_handler_add(sd->eobj,
sd,
_e_fm2_cb_dnd_enter,
_e_fm2_cb_dnd_move,
_e_fm2_cb_dnd_leave,
_e_fm2_cb_dnd_selection_notify,
drop, 2,
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);
}
EAPI void
e_fm2_icons_update(Evas_Object *obj)
{
Eina_List *l;
E_Fm2_Icon *ic;
char buf[PATH_MAX], *pfile;
int bufused, buffree;
EFM_SMART_CHECK();
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)
{
_e_fm2_icon_unrealize(ic);
_e_fm2_icon_realize(ic);
}
}
e_fm2_custom_file_flush();
}
EAPI 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);
}
EAPI 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;
}
EAPI 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;
}
EAPI 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;
}
EAPI 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 __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 __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;
e_thumb_icon_file_set(o, buf, group);
e_thumb_icon_size_set(o, 128, 128);
if (cb) evas_object_smart_callback_add(o, "e_thumb_gen", cb, data);
_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 = edje_file_collection_list(buf);
if (!l) return NULL;
group = eina_stringshare_add(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 __UNUSED__, void *event __UNUSED__)
{
e_fm2_icons_update(data);
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 __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 __UNUSED__, void *data __UNUSED__, int force_gen __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.
*/
EAPI 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);
}
EAPI E_Fm2_Icon_Info *
e_fm2_icon_file_info_get(E_Fm2_Icon *ic)
{
if (!ic) return NULL;
return &(ic->info);
}
EAPI 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;
snprintf(buf, sizeof(buf), "%s/enlightenment/utils/enlightenment_fm", e_prefix_lib_get());
ecore_exe_run(buf, 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 - spane 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 __UNUSED__, int res_h __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
EAPI 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;
}
EAPI 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;
}
EAPI 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;
}
EAPI 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);
}
EAPI 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();
return _e_fm_client_send_new(E_FM_OP_UNMOUNT, (void *)d, l);
}
EAPI 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);
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);
}
EAPI 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);
}
EAPI 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_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_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