efl: vpath subsystem

this adds a core vpath subsystem to efl that allows paths like:

  ~/file.jpg
  ~user/file.jpg
  (:tmp/file.jpg
  (:config/file.jpg
  (:videos/file.mp4
  (:pictures/file.jpg
  (:app.config/mycfg.cfg

etc. to be translated/looked up. it is desitgned to be async and call
event callbacks when ready. the reason for this complexity is fo in
future also handle:

  file:///whatever/file.jpg
  http://blah.com/file.jpg
  https://blah.com/file.jpg
  ssh://blah.com:~/file.jpg

etc.

@feature
This commit is contained in:
Carsten Haitzler 2016-04-01 10:45:07 +09:00
parent a7400abbf6
commit 6291c61556
12 changed files with 731 additions and 1 deletions

View File

@ -23,6 +23,11 @@ efl_eolian_files = \
lib/efl/interfaces/efl_gfx_filter.eo \
lib/efl/interfaces/efl_model_base.eo \
lib/efl/interfaces/efl_animator.eo \
lib/efl/interfaces/efl_vpath.eo \
lib/efl/interfaces/efl_vpath_manager.eo \
lib/efl/interfaces/efl_vpath_file.eo \
lib/efl/interfaces/efl_vpath_core.eo \
lib/efl/interfaces/efl_vpath_file_core.eo \
$(efl_eolian_legacy_files) \
$(NULL)
@ -55,7 +60,11 @@ lib_LTLIBRARIES += lib/efl/libefl.la
lib_efl_libefl_la_SOURCES = \
lib/efl/interfaces/efl_interfaces_main.c \
lib/efl/interfaces/efl_model_common.c \
lib/efl/interfaces/efl_gfx_shape.c
lib/efl/interfaces/efl_gfx_shape.c \
lib/efl/interfaces/efl_vpath_file.c \
lib/efl/interfaces/efl_vpath_manager.c \
lib/efl/interfaces/efl_vpath_core.c \
lib/efl/interfaces/efl_vpath_file_core.c
lib_efl_libefl_la_CPPFLAGS = -I$(top_builddir)/src/lib/efl -I$(top_srcdir)/src/lib/efl @EFL_CFLAGS@ -DEFL_GFX_FILTER_BETA
lib_efl_libefl_la_LIBADD = @EFL_LIBS@

View File

@ -50,6 +50,12 @@ typedef struct tm Efl_Time;
#include <Efl_Model_Common.h>
#include "interfaces/efl_vpath_file.eo.h"
#include "interfaces/efl_vpath.eo.h"
#include "interfaces/efl_vpath_core.eo.h"
#include "interfaces/efl_vpath_manager.eo.h"
#include "interfaces/efl_vpath_file_core.eo.h"
/* Data types */
#include "interfaces/efl_gfx_types.eot.h"
typedef Efl_Gfx_Path_Command_Type Efl_Gfx_Path_Command;

View File

@ -25,6 +25,8 @@
#include "interfaces/efl_gfx_filter.eo.c"
#include "interfaces/efl_vpath.eo.c"
EAPI const Eo_Event_Description _EFL_GFX_CHANGED =
EO_EVENT_DESCRIPTION("Graphics changed");

View File

@ -0,0 +1,29 @@
interface Efl.Vpath
{
[[ VPath is the EFL "Virtual Path" system that maps paths and downloads
You can provide virtual paths common in unix shells like:
"~/file.jpg"
"~username/file.png"
And also other extended paths like:
"(:cache/file.png"
"(:videos/file.mp4"
...
And in future:
"file:///blah.jpg"
"http://blah.com/file.jpg"
"https://blahblah.com/file.jpg"
"ssh://blahblah.com:~/file.jpg"
...
]]
legacy_prefix: null;
eo_prefix: efl_vpath;
methods {
fetch {
[[ Fetch a new Vpath File object from the Vpath system ]]
params {
path: const(char)*; [[ The input virtual file path to fetch ]]
}
return: own(Efl.Vpath_File *); [[ An object representing the file ]]
}
}
}

View File

@ -0,0 +1,351 @@
#include "config.h"
#include "Efl.h"
#ifdef HAVE_GETPWENT
# include <sys/types.h>
# include <pwd.h>
#endif
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <unistd.h>
#define MY_CLASS EFL_VPATH_CORE_CLASS
typedef struct _Efl_Vpath_Core_Data Efl_Vpath_Core_Data;
struct _Efl_Vpath_Core_Data
{
Eina_Spinlock lock;
Eina_Hash *meta;
};
static Efl_Vpath_Core *vpath_core = NULL;
EOLIAN static Eo_Base *
_efl_vpath_core_eo_base_constructor(Eo *obj, Efl_Vpath_Core_Data *pd)
{
char buf[PATH_MAX], bufhome[PATH_MAX], *s;
const char *home;
if (vpath_core) return NULL;
obj = eo_constructor(eo_super(obj, MY_CLASS));
pd->meta = eina_hash_string_superfast_new
((Eina_Free_Cb)eina_stringshare_del);
eina_spinlock_new(&(pd->lock));
vpath_core = obj;
// $HOME / ~/ etc.
home = eina_environment_home_get();
if (!home)
{
uid_t uid = getuid();
struct stat st;
snprintf(bufhome, sizeof(bufhome), "/tmp/%i", (int)uid);
mkdir(bufhome, S_IRUSR | S_IWUSR | S_IXUSR);
if (stat(bufhome, &st) == 0) home = bufhome;
else
{
if (stat("/tmp", &st) == 0) home = "/tmp";
else home = "/";
}
}
efl_vpath_core_meta_set(obj, "home", home);
// tmp dir - system wide
s = getenv("TMPDIR");
if (!s) s = getenv("TMP");
if (!s) s = getenv("TEMPDIR");
if (!s) s = getenv("TEMP");
if (!s) s = "/tmp";
efl_vpath_core_meta_set(obj, "tmp", s);
#define ENV_HOME_SET(_env, _dir, _meta) \
if (!(s = getenv(_env))) { \
snprintf(buf, sizeof(buf), "%s/"_dir, home); s = buf; \
} efl_vpath_core_meta_set(obj, _meta, s);
// $XDG_DATA_HOME defines the base directory relative to which user
// specific data files should be stored. If $XDG_DATA_HOME is either
// not set or empty, a default equal to $HOME/.local/share should be
// used.
ENV_HOME_SET("XDG_DATA_HOME", ".local/share", "data");
// $XDG_CONFIG_HOME defines the base directory relative to which user
// specific configuration files should be stored. If $XDG_CONFIG_HOME
// is either not set or empty, a default equal to $HOME/.config should
// be used.
ENV_HOME_SET("XDG_CONFIG_HOME", ".config", "config");
// $XDG_CACHE_HOME defines the base directory relative to which
// user specific non-essential data files should be stored. If
// $XDG_CACHE_HOME is either not set or empty, a default equal to
// $HOME/.cache should be used.
ENV_HOME_SET("XDG_CACHE_HOME", ".cache", "cache");
// $XDG_RUNTIME_DIR defines the base directory relative to which
// user-specific non-essential runtime files and other file objects
// (such as sockets, named pipes, ...) should be stored. The
// directory MUST be owned by the user, and he MUST be the only one
// having read and write access to it. Its Unix access mode MUST
// be 0700.
if (!(s = getenv("XDG_RUNTIME_DIR")))
{
struct stat st;
// fallback - make ~/.run
snprintf(buf, sizeof(buf), "%s/.run", home);
mkdir(buf, S_IRUSR | S_IWUSR | S_IXUSR);
// if mkdir worked - use, otherwse use /tmp
if (stat(bufhome, &st) == 0) s = buf;
else
{
uid_t uid;
// use /tmp/.run-UID if ~/ dir cant be made
s = (char *)efl_vpath_core_meta_get(obj, "tmp");
uid = getuid();
snprintf(buf, sizeof(buf), "%s/.run-%i", s, (int)uid);
mkdir(buf, S_IRUSR | S_IWUSR | S_IXUSR);
// if ok - use it or fall back to /tmp
if (stat(bufhome, &st) == 0) s = buf;
else s = (char *)efl_vpath_core_meta_get(obj, "tmp");
}
}
efl_vpath_core_meta_set(obj, "run", s);
// https://www.freedesktop.org/wiki/Software/xdg-user-dirs/
// https://wiki.archlinux.org/index.php/Xdg_user_directories
// ^^^^ we don't handle:
// /etc/xdg/user-dirs.conf
// /etc/xdg/user-dirs.defaults
// (:config/user-dirs.conf
// (:config/user-dirs.defaults
// $XDG_DESKTOP_DIR="$HOME/Desktop"
ENV_HOME_SET("XDG_DESKTOP_DIR", "Desktop", "desktop");
// $XDG_DOCUMENTS_DIR="$HOME/Documents"
ENV_HOME_SET("XDG_DOCUMENTS_DIR", "Documents", "documents");
// $XDG_DOWNLOAD_DIR="$HOME/Downloads"
ENV_HOME_SET("XDG_DOWNLOAD_DIR", "Downloads", "downloads");
// $XDG_MUSIC_DIR="$HOME/Music"
ENV_HOME_SET("XDG_MUSIC_DIR", "Music", "music");
// $XDG_PICTURES_DIR="$HOME/Pictures"
ENV_HOME_SET("XDG_PICTURES_DIR", "Pictures", "pictures");
// $XDG_PUBLICSHARE_DIR="$HOME/Public"
ENV_HOME_SET("XDG_PUBLIC_DIR", "Public", "public");
// $XDG_TEMPLATES_DIR="$HOME/.Templates"
ENV_HOME_SET("XDG_TEMPLATES_DIR", ".Templates", "templates");
// $XDG_VIDEOS_DIR="$HOME/Videos"
ENV_HOME_SET("XDG_VIDEOS_DIR", "Videos", "videos");
// Add ~/Applications for user-installed apps
ENV_HOME_SET("E_APPS_DIR", "Applications", "apps");
// XXX: do the below ... later
//
// FHS FOR APP:
// app.dir = PREFIX
// app.bin = PREFIX/bin
// app.lib = PREFIX/lib
// app.data = PREFIX/share/APPNAME
// app.locale = PREFIX/share/locale
//
// XXX: figure out how to merge these with XDG/FHS?
// Tizen:
// App Dir Structure:
// bin Executable binary pathOwner: Read
// lib Library pathOwner: Read
// data Used to store private data of an application.
// res Used to read resource files that are delivered with the application package.
// shared Parent directory of the data, res, and trusted sub-directories. Files in this directory cannot be delivered with the application package.Owner: Read
// shared/data Used to share data with other applications.
// shared/res Used to share resources with other applications. The resource files are delivered with the application package.
// shared/trusted Used to share data with family of trusted applications. The family applications signed with the same certificate can access data in the shared/trusted directory.
//
// XXX: figure out how to merge these with XDG?
// Media/...vvv
// Images Used for Image data.Read and Write
// Sounds Used for Sound data.
// Videos Used for Video data.
// Cameras Used for Camera pictures.
// Downloads Used for Downloaded data.
// Music Used for Music data.
// Documents Used for Documents.
// Others Used for other types.
// System Ringtones Used for System default ringtones.Read
//
// $TZ_SYS_HOME=/home
// $TZ_SYS_DB=/var/db
// $TZ_SYS_CONFIG=/var/kdb
// $TZ_SYS_CONFIG_VOLATILE=/run/kdb
// $TZ_SYS_APP=/usr/apps
// $TZ_SYS_DESKTOP_APP=/usr/share/applications
//
// $TS_USER_DB=<user_homeid>/.tizen/db
// $TZ_USER_CONFIG=<user_home_dir>/.tizen/kdb
// $TZ_USER_APP=<user_home_dir>/.tizen/apps
// $TZ_USER_DESKTOP_APP=<user_home_dir>/.tizen/desktop
// $TZ_USER_DOCUMENTS=<user_home_dir>/Documents
// $TZ_USER_PICTURES=<user_home_dir>/Pictures
// $TZ_USER_VIDEOS=<user_home_dir>/Videos
// $TZ_USER_MUSIC=<user_home_dir>/Music
// $TZ_USER_DOWNLOADS=<user_home_dir>/Downloads
// $TZ_USER_PUBLIC=<user_home_dir>/Public
return obj;
}
EOLIAN static void
_efl_vpath_core_eo_base_destructor(Eo *obj, Efl_Vpath_Core_Data *pd)
{
eina_hash_free(pd->meta);
pd->meta = NULL;
eina_spinlock_free(&(pd->lock));
if (vpath_core == obj) vpath_core = NULL;
eo_destructor(eo_super(obj, MY_CLASS));
}
EOLIAN static Efl_Vpath_Core *
_efl_vpath_core_get(Eo *obj EINA_UNUSED, void *pd EINA_UNUSED)
{
// no locks here as we expect efl to init this early in main "thread"
if (!vpath_core) vpath_core = eo_add(EFL_VPATH_CORE_CLASS, NULL);
return vpath_core;
}
EOLIAN static const char *
_efl_vpath_core_meta_get(Eo *obj EINA_UNUSED, Efl_Vpath_Core_Data *pd, const char *key)
{
const char *meta;
if (!key) return NULL;
eina_spinlock_take(&(pd->lock));
meta = eina_hash_find(pd->meta, key);
eina_spinlock_release(&(pd->lock));
return meta;
}
EOLIAN static void
_efl_vpath_core_meta_set(Eo *obj EINA_UNUSED, Efl_Vpath_Core_Data *pd, const char *key, const char *path)
{
if (!key) return;
eina_spinlock_take(&(pd->lock));
if (path) eina_hash_add(pd->meta, key, eina_stringshare_add(path));
else eina_hash_del(pd->meta, key, NULL);
eina_spinlock_release(&(pd->lock));
}
EOLIAN static Efl_Vpath_File *
_efl_vpath_core_efl_vpath_fetch(Eo *obj, Efl_Vpath_Core_Data *pd EINA_UNUSED, const char *path)
{
Efl_Vpath_File_Core *file;
file = eo_add(EFL_VPATH_FILE_CORE_CLASS, obj);
efl_vpath_file_path_set(file, path);
// XXX: implement parse of path then look up in hash if not just create
// object where path and result are the same and return that with
// path set and result set to resolved path - return obj handler calls
// "do" on object to get the result inside fetched or failed callback.
// if it's a url then we need a new classs that overrides the do and
// begins a fetch and on finish calls the event cb or when wait is called
if (path)
{
// /* <- full path
if (path[0] == '/')
{
efl_vpath_file_result_set(file, path);
return file;
}
// .*
if (path[0] == '.')
{
// .[/]* <- current dir relative
if ((path[1] == '/') || (path[1] == 0))
{
efl_vpath_file_result_set(file, path);
return file;
}
// ..[/]* <- parent dir relative
if ((path[1] == '.') && ((path[2] == '/') || (path[2] == 0)))
{
efl_vpath_file_result_set(file, path);
return file;
}
}
// ~* ...
if (path[0] == '~')
{
// ~/ <- home directory
if (path[1] == '/')
{
char buf[PATH_MAX];
const char *home = efl_vpath_core_meta_get(obj, "home");
if (home)
{
snprintf(buf, sizeof(buf), "%s%s", home, path + 1);
efl_vpath_file_result_set(file, buf);
return file;
}
}
#ifdef HAVE_GETPWENT
// ~username/ <- homedir of user "username"
else
{
const char *p;
struct passwd pwent, *pwent2 = NULL;
char *name, buf[PATH_MAX], pwbuf[8129];
for (p = path + 1; *p; p++)
{
if (*p =='/') break;
}
name = alloca(p - path);
strncpy(name, path + 1, p - path - 1);
name[p - path - 1] = 0;
if (!getpwnam_r(name, &pwent, pwbuf, sizeof(pwbuf), &pwent2))
{
if ((pwent2) && (pwent.pw_dir))
{
snprintf(buf, sizeof(buf), "%s%s", pwent.pw_dir, p);
efl_vpath_file_result_set(file, buf);
return file;
}
}
}
#endif /* HAVE_GETPWENT */
}
// (:xxx/* ... <- meta has table
if ((path[0] == '(') && (path[1] == ':'))
{
const char *p, *meta;
char *name, buf[PATH_MAX];
for (p = path + 2; *p; p++)
{
if (*p =='/') break;
}
name = alloca(p - path);
strncpy(name, path + 2, p - path - 2);
name[p - path - 2] = 0;
eina_spinlock_take(&(pd->lock));
meta = eina_hash_find(pd->meta, name);
eina_spinlock_release(&(pd->lock));
if (meta)
{
snprintf(buf, sizeof(buf), "%s%s", meta, p);
efl_vpath_file_result_set(file, buf);
return file;
}
}
// file:/// <- local file path uri
// file://localhost/ <- local file path uri
// file://hostname/ <- remove file path uri
// XXX: %c4,%17,%fe etc. are bytes escaped
// http://www.ietf.org/rfc/rfc2396.txt
// http://www.ietf.org/rfc/rfc1738.txt
// http://equinox-project.org/spec/file-uri-spec.txt
// http://en.wikipedia.org/wiki/File_URI_scheme
}
return file;
}
#include "interfaces/efl_vpath_core.eo.c"

View File

@ -0,0 +1,31 @@
class Efl.Vpath.Core (Eo.Base, Efl.Vpath)
{
[[ Core EFL implementation of a Vpath system ]]
legacy_prefix: null;
eo_prefix: efl_vpath_core;
methods {
get @class {
[[ This gets the global EFL Core Vpath class - only 1 - singleton ]]
return: Efl.Vpath.Core *; [[ Get the singleton core vpath ]]
}
meta_set {
[[ A Meta key is a mapping from a virtual path to a real one ]]
params {
key: const(char)*; [[ The magic path key being looked up ]]
path: const(char)*; [[ The real path the key maps to ]]
}
}
meta_get {
[[ This returns the real path set for a Meta key, or NULL if not ]]
params {
key: const(char)*; [[ The magic path key being looked up ]]
}
return: const(char)*;
}
}
implements {
Eo.Base.constructor;
Eo.Base.destructor;
Efl.Vpath.fetch;
}
}

View File

@ -0,0 +1,61 @@
#include "config.h"
#include "Efl.h"
#define MY_CLASS EFL_VPATH_FILE_CLASS
typedef struct _Efl_Vpath_File_Data Efl_Vpath_File_Data;
struct _Efl_Vpath_File_Data
{
const char *path;
const char *result;
Eina_Bool called : 1;
};
EOLIAN static void
_efl_vpath_file_path_set(Eo *obj EINA_UNUSED, Efl_Vpath_File_Data *pd, const char *path)
{
eina_stringshare_replace(&(pd->path), path);
}
EOLIAN static const char *
_efl_vpath_file_path_get(Eo *obj EINA_UNUSED, Efl_Vpath_File_Data *pd)
{
return pd->path;
}
EOLIAN static void
_efl_vpath_file_result_set(Eo *obj EINA_UNUSED, Efl_Vpath_File_Data *pd, const char *path)
{
eina_stringshare_replace(&(pd->result), path);
}
EOLIAN static const char *
_efl_vpath_file_result_get(Eo *obj EINA_UNUSED, Efl_Vpath_File_Data *pd)
{
return pd->result;
}
EOLIAN static Eina_Bool
_efl_vpath_file_do(Eo *obj EINA_UNUSED, Efl_Vpath_File_Data *pd)
{
if (pd->called) return EINA_FALSE;
pd->called = EINA_TRUE;
eo_event_callback_call(obj, EFL_VPATH_FILE_EVENT_FETCHED, NULL);
return EINA_TRUE;
}
EOLIAN static void
_efl_vpath_file_wait(Eo *obj EINA_UNUSED, Efl_Vpath_File_Data *pd EINA_UNUSED)
{
if (!pd->called)
{
pd->called = EINA_TRUE;
if (pd->result)
eo_event_callback_call(obj, EFL_VPATH_FILE_EVENT_FETCHED, NULL);
else
eo_event_callback_call(obj, EFL_VPATH_FILE_EVENT_FAILED, NULL);
}
}
#include "interfaces/efl_vpath_file.eo.c"

View File

@ -0,0 +1,46 @@
class Efl.Vpath_File (Eo.Base)
{
[[ VPath File is an actual representation of a downloaded/mapped vpath file
Keep this object around for as long as you need to use the file as it
may have been downloaded and kept as a local temporary file and
deletion may remove it.
When you have a Vpath File object for the first time, call the do()
method on it to actually begin/do the mapping. From here the
fetched or failed event callbacks will be called, inside of which or
afterwards you can fetch the resulting local file path by getting the
result property.
]]
legacy_prefix: null;
eo_prefix: efl_vpath_file;
methods {
@property path {
[[ The original source path provided to lookup/fetch from ]]
set {}
get {}
values {
path: const(char)*; [[ The input virtual path to a file ]]
}
}
@property result {
[[ The resulting real local file path to open/read ]]
set {}
get {}
values {
path: const(char)*; [[ The resulting destination file ]]
}
}
do {
[[ Actually begin the resolving here - emit event now or do later ]]
return: bool; [[ Result callback already called ]]
}
wait {
[[ If not fteched yet, wait until it is and call result cb ]]
}
}
events {
fetched; [[ File successfully mapped/fetched ]]
failed; [[ File fetch or mapping failed ]]
}
}

View File

@ -0,0 +1,66 @@
#include "config.h"
#include "Efl.h"
#define MY_CLASS EFL_VPATH_FILE_CORE_CLASS
typedef struct _Efl_Vpath_File_Core_Data Efl_Vpath_File_Core_Data;
struct _Efl_Vpath_File_Core_Data
{
int dummy;
};
EOLIAN static Eo_Base *
_efl_vpath_file_core_eo_base_constructor(Eo *obj, Efl_Vpath_File_Core_Data *pd)
{
obj = eo_constructor(eo_super(obj, MY_CLASS));
pd->dummy = 0;
return obj;
}
EOLIAN static void
_efl_vpath_file_core_eo_base_destructor(Eo *obj, Efl_Vpath_File_Core_Data *pd)
{
pd->dummy = 0;
eo_destructor(eo_super(obj, MY_CLASS));
}
EOLIAN static Eina_Bool
_efl_vpath_file_core_efl_vpath_file_do(Eo *obj, Efl_Vpath_File_Core_Data *pd)
{
const char *path;
if (efl_vpath_file_result_get(obj))
return efl_vpath_file_do(eo_super(obj, MY_CLASS));
// vpath core didn't find a match, so it'ss likely a protocol like
// http:// etc. etc. so deal with that here
path = efl_vpath_file_path_get(obj);
if (path)
{
if ((!strncasecmp(path, "http://", 7)) ||
(!strncasecmp(path, "https://", 8)))
{
// XXX: handle urls --- need a loop object
}
}
// ...
pd->dummy = 0;
// not a magic path - just set result to path
efl_vpath_file_result_set(obj, efl_vpath_file_path_get(obj));
return efl_vpath_file_do(eo_super(obj, MY_CLASS));
}
EOLIAN static void
_efl_vpath_file_core_efl_vpath_file_wait(Eo *obj, Efl_Vpath_File_Core_Data *pd)
{
if (efl_vpath_file_result_get(obj))
{
efl_vpath_file_do(eo_super(obj, MY_CLASS));
return;
}
pd->dummy = 0;
// XXX: not found yet, so do what is necessary
}
#include "interfaces/efl_vpath_file_core.eo.c"

View File

@ -0,0 +1,12 @@
class Efl.Vpath_File.Core (Efl.Vpath_File)
{
[[ Core EFL implementation of a Vpath File ]]
legacy_prefix: null;
eo_prefix: efl_vpath_file_core;
implements {
Eo.Base.constructor;
Eo.Base.destructor;
Efl.Vpath_File.do;
Efl.Vpath_File.wait;
}
}

View File

@ -0,0 +1,89 @@
#include "config.h"
#include "Efl.h"
#define MY_CLASS EFL_VPATH_MANAGER_CLASS
typedef struct _Efl_Vpath_Manager_Data Efl_Vpath_Manager_Data;
typedef struct _Efl_Vpath_Manager_Entry Efl_Vpath_Manager_Entry;
struct _Efl_Vpath_Manager_Data
{
Eina_List *list;
};
struct _Efl_Vpath_Manager_Entry
{
Efl_Vpath *vpath;
int priority;
};
static Efl_Vpath_Manager_Data vpath_manager =
{
NULL
};
EOLIAN static Efl_Vpath_File *
_efl_vpath_manager_fetch(Eo *obj EINA_UNUSED, void *pd EINA_UNUSED, const char *path)
{
Efl_Vpath_Manager_Entry *entry;
Eina_List *l;
Efl_Vpath_File *file;
EINA_LIST_FOREACH(vpath_manager.list, l, entry)
{
file = efl_vpath_fetch(entry->vpath, path);
if (file) return file;
}
file = eo_add(EFL_VPATH_FILE_CLASS, NULL);
if (file)
{
efl_vpath_file_path_set(file, path);
efl_vpath_file_result_set(file, path);
}
return file;
}
static int
_register_sort_cb(Efl_Vpath_Manager_Entry *e1, Efl_Vpath_Manager_Entry *e2)
{
// sort higher numbers first in list
return (e2->priority - e1->priority);
}
static Eina_Bool
_cb_vpath_del(void *data, const Eo_Event *event)
{
efl_vpath_manager_unregister(data, event->obj);
eo_event_callback_del(event->obj, EO_BASE_EVENT_DEL, _cb_vpath_del, data);
return EINA_TRUE;
}
EOLIAN static void
_efl_vpath_manager_register(Eo *obj, void *pd EINA_UNUSED, int priority, Efl_Vpath *vpath)
{
Efl_Vpath_Manager_Entry *entry = malloc(sizeof(Efl_Vpath_Manager_Entry));
entry->vpath = vpath;
entry->priority = priority;
eo_event_callback_add(vpath, EO_BASE_EVENT_DEL, _cb_vpath_del, obj);
vpath_manager.list = eina_list_sorted_insert
(vpath_manager.list, EINA_COMPARE_CB(_register_sort_cb), entry);
}
EOLIAN static void
_efl_vpath_manager_unregister(Eo *obj EINA_UNUSED, void *pd EINA_UNUSED, Efl_Vpath *vpath)
{
Efl_Vpath_Manager_Entry *entry;
Eina_List *l;
EINA_LIST_FOREACH(vpath_manager.list, l, entry)
{
if (entry->vpath == vpath)
{
vpath_manager.list = eina_list_remove_list(vpath_manager.list, l);
free(entry);
return;
}
}
}
#include "interfaces/efl_vpath_manager.eo.c"

View File

@ -0,0 +1,28 @@
class Efl.Vpath_Manager (Eo.Base)
{
[[ Vpath Manager manages multiple VPath objects that remap/download ]]
legacy_prefix: null;
eo_prefix: efl_vpath_manager;
methods {
fetch @class {
[[ This class function fetches a Vpath File given an input path ]]
params {
path: const(char)*; [[ The input virtual file path to fetch ]]
}
return: own(Efl.Vpath_File *); [[ An object representing the file ]]
}
register @class {
[[ ]]
params {
priority: int; [[ Search order - higher values tired first ]]
vpath: Efl.Vpath * @nonull; [[ A Vpath implementation object ]]
}
}
unregister @class {
[[ ]]
params {
vpath: Efl.Vpath * @nonull; [[ A Vpath implementation object ]]
}
}
}
}