#ifdef HAVE_CONFIG_H # include "config.h" #endif #include #include #include "e_mod_main.h" #include "e_mod_places.h" #ifdef HAVE_EEZE # include "e_mod_eeze.h" #endif #ifdef HAVE_ELDBUS # include "e_mod_udisks_eldbus.h" #endif #ifdef HAVE_MOUNT # include "e_mod_mount.h" #endif /* Local Function Prototypes */ static Eina_Bool _places_poller(void *data); static const char *_places_human_size_get(unsigned long long size); static void _places_volume_object_update(Volume *vol, Evas_Object *obj); static void _places_run_fm_external(const char *fm, const char *directory); /* Edje callbacks */ void _places_icon_activated_cb(void *data, Evas_Object *o, const char *emission, const char *source); void _places_custom_icon_activated_cb(void *data, Evas_Object *o, const char *emission, const char *source); void _places_eject_activated_cb(void *data, Evas_Object *o, const char *emission, const char *source); void _places_header_activated_cb(void *data, Evas_Object *o, const char *emission, const char *source); /* Local Variables */ static Ecore_Timer *poller = NULL; static char theme_file[PATH_MAX]; Eina_List *volumes = NULL; /* Implementation */ void places_init(void) { volumes = NULL; printf("PLACES: Init\n"); #ifdef HAVE_EEZE places_eeze_init(); #endif #ifdef HAVE_ELDBUS places_udisks_eldbus_init(); #endif #ifdef HAVE_MOUNT places_mount_init(); #endif snprintf(theme_file, PATH_MAX, "%s/e-module-places.edj", places_conf->module->dir); poller = ecore_timer_add(3.0, _places_poller, NULL); } void places_shutdown(void) { if (poller) ecore_timer_del(poller); while (volumes) places_volume_del((Volume*)volumes->data); #ifdef HAVE_EEZE places_eeze_shutdown(); #endif #ifdef HAVE_ELDBUS places_udisks_eldbus_shutdown(); #endif #ifdef HAVE_MOUNT places_mount_shutdown(); #endif } Evas_Object * places_main_obj_create(Evas *canvas) { Evas_Object *o; o = edje_object_add(canvas); edje_object_file_set(o, theme_file, "modules/places/main"); return o; } Eina_List * places_volume_list_get(void) { return volumes; } Volume * places_volume_add(const char *id, Eina_Bool first_time) { Volume *v; if (!id) return NULL; v = E_NEW(Volume, 1); if (!v) return NULL; // safe defaults v->id = eina_stringshare_add(id); v->valid = EINA_FALSE; v->objs = NULL; v->icon = eina_stringshare_add(""); v->device = eina_stringshare_add(""); v->label = eina_stringshare_add(""); v->mount_point = eina_stringshare_add(""); v->fstype = eina_stringshare_add(""); v->drive_type = eina_stringshare_add(""); v->model = eina_stringshare_add(""); v->serial = eina_stringshare_add(""); v->vendor = eina_stringshare_add(""); v->bus = eina_stringshare_add(""); v->to_mount = ((places_conf->auto_mount && !first_time) || (first_time && places_conf->boot_mount)); v->force_open = (places_conf->auto_open && !first_time); volumes = eina_list_append(volumes, v); return v; } void places_volume_del(Volume *v) { Evas_Object *o; Evas_Object *swal; Eina_List *l; Instance *inst; if (v->free_func) v->free_func(v); volumes = eina_list_remove(volumes, v); EINA_LIST_FREE(v->objs, o) { swal = edje_object_part_swallow_get(o, "icon"); if (swal) { edje_object_part_unswallow(o, swal); evas_object_del(swal); } EINA_LIST_FOREACH(instances, l, inst) edje_object_part_box_remove(inst->o_main, "box", o); evas_object_del(o); } if (v->id) eina_stringshare_del(v->id); if (v->label) eina_stringshare_del(v->label); if (v->icon) eina_stringshare_del(v->icon); if (v->mount_point) eina_stringshare_del(v->mount_point); if (v->device) eina_stringshare_del(v->device); if (v->fstype) eina_stringshare_del(v->fstype); if (v->bus) eina_stringshare_del(v->bus); if (v->drive_type) eina_stringshare_del(v->drive_type); if (v->model) eina_stringshare_del(v->model); if (v->vendor) eina_stringshare_del(v->vendor); if (v->serial) eina_stringshare_del(v->serial); E_FREE(v); } Volume * places_volume_by_id_get(const char *id) { Volume *v; Eina_List *l; EINA_LIST_FOREACH(volumes, l, v) if (!strcmp(v->id, id)) return v; return NULL; } static int _places_volume_sort_cb(const void *d1, const void *d2) { const Volume *v1 = d1; const Volume *v2 = d2; // removable after interal if (v1->removable && !v2->removable) return(1); if (v2->removable && !v1->removable) return(-1); // filesystem root on top if (v1->mount_point && !strcmp(v1->mount_point, "/")) return -1; if (v2->mount_point && !strcmp(v2->mount_point, "/")) return 1; // order by label if(!v1 || !v1->label) return(1); if(!v2 || !v2->label) return(-1); return strcmp(v1->label, v2->label); } void places_update_all_gadgets(void) { Eina_List *l; Instance *inst; volumes = eina_list_sort(volumes, 0, _places_volume_sort_cb); EINA_LIST_FOREACH(instances, l, inst) places_fill_box(inst->o_main, inst->horiz); } void places_volume_update(Volume *vol) { Evas_Object *obj; Eina_List *l; EINA_LIST_FOREACH(vol->objs, l, obj) _places_volume_object_update(vol, obj); // mount the volume if needed if (vol->to_mount && !vol->mounted) { places_volume_mount(vol); vol->to_mount = EINA_FALSE; } // the volume has been mounted as requested, open the fm if (vol->force_open && vol->mounted && vol->mount_point) { places_run_fm(vol->mount_point); vol->force_open = EINA_FALSE; } // debug: // places_print_volume(vol); } void places_fill_box(Evas_Object *main, Eina_Bool horiz) { Eina_List *l; int min_w, min_h, max_w, max_h, found; Evas_Object *o, *icon; char *f1, *f2, *f3; char buf[128]; if (!main) return; places_empty_box(main); // orient the edje box if (horiz) edje_object_signal_emit(main, "box,set,horiz", "places"); else edje_object_signal_emit(main, "box,set,vert", "places"); // header (or just a separator if header is not wanted) o = edje_object_add(evas_object_evas_get(main)); if (places_conf->hide_header) edje_object_file_set(o, theme_file, "modules/places/separator"); else edje_object_file_set(o, theme_file, "modules/places/header"); edje_object_part_text_set(o, "label", D_("Places")); if (horiz) edje_object_signal_emit(o, "separator,set,vert", "places"); else edje_object_signal_emit(o, "separator,set,horiz", "places"); edje_object_size_min_get(o, &min_w, &min_h); edje_object_size_max_get(o, &max_w, &max_h); evas_object_size_hint_min_set(o, min_w, min_h); evas_object_size_hint_max_set(o, max_w, max_h); // evas_object_size_hint_align_set(o, EVAS_HINT_FILL, 0.0); edje_object_part_box_append(main, "box", o); evas_object_show(o); edje_object_signal_callback_add(o, "header,activated", "places", _places_header_activated_cb, NULL); // volume objects for (l = volumes; l; l = l->next) { Volume *vol = l->data; if (!vol->valid) continue; //volume object o = edje_object_add(evas_object_evas_get(main)); edje_object_file_set(o, theme_file, "modules/places/volume"); vol->objs = eina_list_append(vol->objs, o); //choose the right icon icon = e_icon_add(evas_object_evas_get(main)); f1 = f2 = f3 = NULL; /* optical discs */ if (!strcmp(vol->drive_type, "cdrom") || !strcmp(vol->drive_type, "optical_cd")) { f1 = "media"; f2 = "optical"; // OR media-optical ?? } /* flash cards */ else if (!strcmp(vol->drive_type, "sd_mmc") || !strcmp(vol->model, "SD/MMC")) { f1 = "media"; f2 = "flash"; f3 = "sdmmc"; // NOTE sd-mmc in Oxigen :( } else if (!strcmp(vol->drive_type, "memory_stick") || !strcmp(vol->model, "MS/MS-Pro")) { f1 = "media"; f2 = "flash"; f3 = "ms"; // NOTE memory-stick in Oxigen :( } /* iPods */ else if (!strcmp(vol->model, "iPod")) { f1 = "multimedia-player"; f2 = "apple"; f3 = "ipod"; } /* generic usb drives */ else if (!strcmp(vol->bus, "usb")) { f1 = "drive"; f2 = "removable-media"; f3 = "usb"; } /* network filesystem */ else if (!strcmp(vol->fstype, "nfs") || !strcmp(vol->fstype, "cifs")) { f1 = "folder"; f2 = "remote"; } // search the icon, following freedesktop fallback system found = 0; if (f1 && f2 && f3) { snprintf(buf, sizeof(buf), "%s-%s-%s", f1, f2, f3); found = e_util_icon_theme_set(icon, buf); } if (!found && f1 && f2) { snprintf(buf, sizeof(buf), "%s-%s", f1, f2); found = e_util_icon_theme_set(icon, buf); } if (!found) { snprintf(buf, sizeof(buf), "drive-harddisk"); found = e_util_icon_theme_set(icon, buf); } if (found) { edje_object_part_swallow(o, "icon", icon); vol->icon = eina_stringshare_add(buf); } else evas_object_del(icon); //set partition type tag if (!strcmp(vol->fstype, "ext2") || !strcmp(vol->fstype, "ext3") || !strcmp(vol->fstype, "ext4") || !strcmp(vol->fstype, "reiserfs") || !strcmp(vol->fstype, "nfs")) edje_object_signal_emit(o, "icon,tag,ext3", "places"); else if (!strcmp(vol->fstype, "ufs") || !strcmp(vol->fstype, "zfs")) edje_object_signal_emit(o, "icon,tag,ufs", "places"); else if (!strcmp(vol->fstype, "vfat") || !strcmp(vol->fstype, "ntfs") || !strcmp(vol->fstype, "ntfs-3g") || !strcmp(vol->fstype, "cifs")) edje_object_signal_emit(o, "icon,tag,fat", "places"); else if (!strcmp(vol->fstype, "hfs") || !strcmp(vol->fstype, "hfsplus")) edje_object_signal_emit(o, "icon,tag,hfs", "places"); else if (!strcmp(vol->fstype, "udf")) edje_object_signal_emit(o, "icon,tag,dvd", "places"); // update labels, gauge and button _places_volume_object_update(vol, o); // orient the separator if (horiz) edje_object_signal_emit(o, "separator,set,vert", "places"); else edje_object_signal_emit(o, "separator,set,horiz", "places"); // connect signals from edje edje_object_signal_callback_add(o, "icon,activated", "places", _places_icon_activated_cb, vol); edje_object_signal_callback_add(o, "eject,activated", "places", _places_eject_activated_cb, vol); // pack the volume in the box edje_object_size_min_get(o, &min_w, &min_h); edje_object_size_max_get(o, &max_w, &max_h); evas_object_size_hint_min_set(o, min_w, min_h); evas_object_size_hint_max_set(o, max_w, max_h); // evas_object_size_hint_align_set(o, EVAS_HINT_FILL, 0.0); // evas_object_size_hint_weight_set(o, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); edje_object_part_box_append(main, "box", o); evas_object_show(o); } edje_object_calc_force(main); edje_object_size_min_restricted_calc(main, &min_w, &min_h, 99, 1); // printf("PLACES: SIZE: %d %d\n", min_w, min_h); evas_object_size_hint_min_set(main, min_w, min_h); } void places_empty_box(Evas_Object *main) { Evas_Object *o; while ((o = edje_object_part_box_remove_at(main, "box", 0))) { Volume *vol; Evas_Object *swal; Eina_List *l; swal = edje_object_part_swallow_get(o, "icon"); if (swal) { edje_object_part_unswallow(o, swal); evas_object_del(swal); } EINA_LIST_FOREACH(volumes, l, vol) vol->objs = eina_list_remove(vol->objs, o); evas_object_del(o); } } void places_volume_mount(Volume *vol) { Eina_List *opts = NULL; char buf[256]; if (!vol || !vol->mount_func || vol->mounted) return; if ((!strcmp(vol->fstype, "vfat")) || (!strcmp(vol->fstype, "ntfs"))) { snprintf(buf, sizeof(buf), "uid=%i", (int)getuid()); opts = eina_list_append(opts, buf); } vol->mount_func(vol, opts); vol->to_mount = EINA_FALSE; eina_list_free(opts); } void places_volume_unmount(Volume *vol) { if (vol && vol->unmount_func) vol->unmount_func(vol, NULL); } void places_volume_eject(Volume *vol) { if (vol && vol->eject_func) vol->eject_func(vol, NULL); } void places_print_volume(Volume *v) { const char *size, *free; printf("Got volume %s (totals: %d)\n", v->id, eina_list_count(volumes)); printf(" label: %s\n",v->label); printf(" mounted: %d\n", v->mounted); printf(" m_point: %s\n", v->mount_point); printf(" device: %s\n", v->device); printf(" fstype: %s\n", v->fstype); printf(" bus: %s\n", v->bus); printf(" drive_type: %s\n", v->drive_type); printf(" model: %s\n", v->model); printf(" vendor: %s\n", v->vendor); printf(" serial: %s\n", v->serial); printf(" removable: %d\n", v->removable); printf(" requires eject: %d\n", v->requires_eject); size = _places_human_size_get(v->size); free = _places_human_size_get(v->free_space); printf(" size: %s\n", size); printf(" free_space: %s\n", free); eina_stringshare_del(size); eina_stringshare_del(free); printf("\n"); } void places_run_fm(const char *directory) { if (places_conf->fm && places_conf->fm[0]) { _places_run_fm_external(places_conf->fm, directory); } else { E_Action *act = e_action_find("fileman"); Eina_List *managers = e_manager_list(); if (act && act->func.go && managers && managers->data) act->func.go(E_OBJECT(managers->data), directory); else e_util_dialog_internal(D_("Warning"), D_("Cannot run the Enlightenment FileManager.
" "Please choose a custom file manager in
" "the gadget configuration.")); } if (places_conf->autoclose_popup) places_popups_close(); } /* Internals */ static unsigned long long _places_free_space_get(const char *mount, Volume *vol) { struct statvfs s; if (!mount) return 0; if (statvfs(mount, &s) != 0) return 0; if ((vol->size == 0) && (s.f_blocks)) vol->size = (unsigned long long)s.f_blocks * (unsigned long long)s.f_frsize; return (unsigned long long)s.f_bavail * (unsigned long long)s.f_frsize; } static Eina_Bool _places_poller(void *data) { Volume *vol; Eina_List *l; long long new; EINA_LIST_FOREACH(volumes, l, vol) if (vol->valid && vol->mounted) { new = _places_free_space_get(vol->mount_point, vol); // redraw only if the size has changed more that 1Mb if (abs(new - vol->free_space) > 1024 * 1024) { vol->free_space = new; places_volume_update(vol); } } return EINA_TRUE; } static const char * _places_human_size_get(unsigned long long size) { double dsize; char hum[32], *suffix; dsize = (double)size; if (dsize < 1024) snprintf(hum, sizeof(hum), "%.0f%s", dsize, D_("b")); else { dsize /= 1024.0; if (dsize < 1024) suffix = N_("KB"); else { dsize /= 1024.0; if (dsize < 1024) suffix = N_("MB"); else { dsize /= 1024.0; if(dsize < 1024) suffix = N_("GB"); else { dsize /= 1024.0; suffix = N_("TB"); } } } snprintf(hum, sizeof(hum), "%.1f%s", dsize, D_(suffix)); } return eina_stringshare_add(hum); } static void _places_run_fm_external(const char *fm, const char *directory) { char exec[PATH_MAX]; snprintf(exec, PATH_MAX, "%s \"%s\"", (char*)fm, (char*)directory); e_exec(NULL, NULL, exec, NULL, NULL); } static void _places_volume_object_update(Volume *vol, Evas_Object *obj) { const char *tot_h; const char *free_h; char buf[256]; char buf2[16]; // printf("PLACES: Object update for vol %s\n", vol->id); // the volume label if (vol->mount_point && !strcmp(vol->mount_point, "/")) edje_object_part_text_set(obj, "volume_label", D_("Filesystem")); else if (vol->label && vol->label[0]) edje_object_part_text_set(obj, "volume_label", vol->label); else edje_object_part_text_set(obj, "volume_label", D_("No Name")); // the free label tot_h = _places_human_size_get(vol->size); if (vol->mounted) { free_h = _places_human_size_get(vol->free_space); snprintf(buf, sizeof(buf), "%s %s %s", free_h, D_("free of"), tot_h); edje_object_part_text_set(obj, "size_label", buf); eina_stringshare_del(free_h); } else { snprintf(buf, sizeof(buf), D_("%s Not Mounted"), tot_h); edje_object_part_text_set(obj, "size_label", buf); } eina_stringshare_del(tot_h); // the gauge int percent; Edje_Message_Float msg_float; if (vol->mounted) { percent = 100 - (((long double)vol->free_space / (long double)vol->size) * 100); snprintf(buf2, sizeof(buf2), "%d%%", percent); edje_object_part_text_set(obj, "percent_label", buf2); msg_float.val = (float)percent / 100; edje_object_message_send(obj, EDJE_MESSAGE_FLOAT, 1, &msg_float); edje_object_signal_emit(obj, "gauge,show", "places"); } else { edje_object_signal_emit(obj, "gauge,hide", "places"); edje_object_part_text_set(obj, "percent_label", ""); } // the mount/eject icon if (vol->mounted && vol->mount_point && vol->unmount_func && strcmp(vol->mount_point, "/")) { edje_object_signal_emit(obj, "icon,eject,show", "places"); edje_object_part_text_set(obj, "eject_label", D_("unmount")); } else if (!vol->mounted && vol->eject_func && (vol->requires_eject || vol->removable)) { edje_object_signal_emit(obj, "icon,eject,show", "places"); edje_object_part_text_set(obj, "eject_label", D_("eject")); } else edje_object_signal_emit(obj, "icon,eject,hide", "places"); } /* EDJE Callbacks */ void _places_icon_activated_cb(void *data, Evas_Object *o, const char *emission, const char *source) { Volume *vol = data; if (vol->mounted) places_run_fm(vol->mount_point); else if (vol->mount_func) { vol->force_open = EINA_TRUE; places_volume_mount(vol); } } void _places_eject_activated_cb(void *data, Evas_Object *o, const char *emission, const char *source) { Volume *vol = data; if (vol->mounted) places_volume_unmount(vol); else places_volume_eject(vol); } void _places_header_activated_cb(void *data, Evas_Object *o, const char *emission, const char *source) { places_run_fm(e_user_homedir_get()); } /* E17 menu augmentation */ void _places_menu_cb(void *data, E_Menu *m, E_Menu_Item *mi) { places_run_fm(data); } static void _places_bookmarks_parse(E_Menu *em) { char line[PATH_MAX]; char buf[PATH_MAX]; E_Menu_Item *mi; Efreet_Uri *uri; char *alias; FILE* fp; snprintf(buf, sizeof(buf), "%s/.gtk-bookmarks", e_user_homedir_get()); fp = fopen(buf, "r"); if (fp) { while(fgets(line, sizeof(line), fp)) { alias = NULL; line[strlen(line) - 1] = '\0'; alias = strchr(line, ' '); if (alias) { line[alias-line] = '\0'; alias++; } uri = efreet_uri_decode(line); if (uri && uri->path && ecore_file_exists(uri->path)) { mi = e_menu_item_new(em); e_menu_item_label_set(mi, alias ? alias : ecore_file_file_get(uri->path)); e_util_menu_item_theme_icon_set(mi, "folder"); e_menu_item_callback_set(mi, _places_menu_cb, strdup(uri->path)); //TODO free somewhere } if (uri) efreet_uri_free(uri); } fclose(fp); } } void places_generate_menu(void *data, E_Menu *em) { E_Menu_Item *mi; // Home if (places_conf->show_home) { mi = e_menu_item_new(em); e_menu_item_label_set(mi, D_("Home")); e_util_menu_item_theme_icon_set(mi, "user-home"); e_menu_item_callback_set(mi, _places_menu_cb, e_user_homedir_get()); } // Desktop if (places_conf->show_desk) { mi = e_menu_item_new(em); e_menu_item_label_set(mi, D_("Desktop")); e_util_menu_item_theme_icon_set(mi, "user-desktop"); e_menu_item_callback_set(mi, _places_menu_cb, efreet_desktop_dir_get()); } // Trash if (places_conf->show_trash) { mi = e_menu_item_new(em); e_menu_item_label_set(mi, D_("Trash")); e_util_menu_item_theme_icon_set(mi, "user-trash"); e_menu_item_callback_set(mi, _places_menu_cb, "trash:///"); } // File System if (places_conf->show_root) { mi = e_menu_item_new(em); e_menu_item_label_set(mi, D_("Filesystem")); e_util_menu_item_theme_icon_set(mi, "drive-harddisk"); e_menu_item_callback_set(mi, _places_menu_cb, "/"); } // Temp if (places_conf->show_temp) { mi = e_menu_item_new(em); e_menu_item_label_set(mi, D_("Temp")); e_util_menu_item_theme_icon_set(mi, "user-temp"); e_menu_item_callback_set(mi, _places_menu_cb, "/tmp"); } // Separator if (places_conf->show_home || places_conf->show_desk || places_conf->show_trash || places_conf->show_root || places_conf->show_temp) { mi = e_menu_item_new(em); e_menu_item_separator_set(mi, 1); } // Volumes Eina_Bool volumes_visible = 0; const Eina_List *l; Volume *vol; EINA_LIST_FOREACH(volumes, l, vol) { if (!vol->valid) continue; if (vol->mount_point && !strcmp(vol->mount_point, "/")) continue; mi = e_menu_item_new(em); if ((vol->label) && (vol->label[0] != '\0')) e_menu_item_label_set(mi, vol->label); else e_menu_item_label_set(mi, ecore_file_file_get(vol->mount_point)); if (vol->icon) e_util_menu_item_theme_icon_set(mi, vol->icon); e_menu_item_callback_set(mi, _places_menu_cb, vol->mount_point); volumes_visible = 1; } // Favorites if (places_conf->show_bookm) { if (volumes_visible) { mi = e_menu_item_new(em); e_menu_item_separator_set(mi, 1); } _places_bookmarks_parse(em); } e_menu_pre_activate_callback_set(em, NULL, NULL); } void places_augmentation(void *data, E_Menu *em) { E_Menu_Item *mi; E_Menu *m; mi = e_menu_item_new(em); e_menu_item_label_set(mi, D_("Places")); e_util_menu_item_theme_icon_set(mi, "system-file-manager"); m = e_menu_new(); e_menu_item_submenu_set(mi, m); e_menu_pre_activate_callback_set(m, places_generate_menu, NULL); }