Freedesktop.org desktop, icon, and menu support as per the discussion in

the mailing list.  It's not ready yet.  It needs documentation, EFL
conformant naming, and a good whipping into shape by indent.  The ecore
integration needs a reveiw, see if I got that right.

Consider this a preview, it's mostly there, just needs some tweking.


SVN revision: 24560
This commit is contained in:
David Walter Seikel 2006-08-11 13:45:39 +00:00
parent f864ccd8e6
commit ae95df23ab
18 changed files with 3293 additions and 7 deletions

View File

@ -28,6 +28,7 @@ EXTRA_DIST = AUTHORS COPYING COPYING-PLAIN ecore.c.in gendoc ecore.supp ecore.m4
debian/libecore0-con.install \
debian/libecore0-config.install \
debian/libecore0-dbus.install \
debian/libecore0-desktop.install \
debian/libecore0-dev.install \
debian/libecore0-evas.install \
debian/libecore0-fb.install \

View File

@ -921,7 +921,6 @@ fi
AC_SUBST(ecore_ipc_cflags)
AC_SUBST(ecore_ipc_libs)
AC_MSG_CHECKING(whether ecore_dbus module is to be built)
want_ecore_dbus="yes";
have_ecore_dbus="no";
@ -968,7 +967,6 @@ AC_SUBST(dbus_libs)
AC_SUBST(ecore_dbus_cflags)
AC_SUBST(ecore_dbus_libs)
AC_MSG_CHECKING(whether ecore_config module is to be built)
want_ecore_config="yes";
@ -1155,6 +1153,45 @@ fi
AC_SUBST(fam_libs)
AC_SUBST(ecore_file_libs)
if test "x$have_ecore_file" = "xyes"; then
AC_MSG_CHECKING(whether ecore_desktop module is to be built)
want_ecore_desktop="yes";
have_ecore_desktop="no";
ecore_desktop_cflags="";
ecore_desktop_libs="";
AC_ARG_ENABLE(ecore-desktop,
[ --disable-ecore-desktop disable the ecore_desktop module],
[
if test x"$enableval" = x"yes" ; then
AC_MSG_RESULT(yes)
else
AC_MSG_RESULT(no)
want_ecore_desktop="no"
fi
], [
AC_MSG_RESULT(yes)
]
)
if test "x$want_ecore_desktop" = "xyes"; then
AM_CONDITIONAL(BUILD_ECORE_DESKTOP, true)
AC_DEFINE(BUILD_ECORE_DESKTOP, 1, [Build Ecore_Desktop Module])
have_ecore_desktop="yes"
ecore_desktop_libs="-lecore_desktop";
else
AM_CONDITIONAL(BUILD_ECORE_DESKTOP, false)
fi
AC_SUBST(ecore_desktop_cflags)
AC_SUBST(ecore_desktop_libs)
else
AC_MSG_RESULT(ecore_file not enabled so ecore_desktop will not be enabled)
want_ecore_desktop="no"
fi
AC_ARG_ENABLE(pthreads,
[ --disable-pthreads disable building with pthread support],
[
@ -1224,6 +1261,7 @@ src/lib/ecore_txt/Makefile
src/lib/ecore_config/Makefile
src/lib/ecore_file/Makefile
src/lib/ecore_dbus/Makefile
src/lib/ecore_desktop/Makefile
src/lib/ecore_directfb/Makefile
examples/Makefile
ecore-config
@ -1254,6 +1292,7 @@ echo " Ecore_Buffer.................: $have_ecore_evas_buffer"
echo " Ecore_Ipc....................: $have_ecore_ipc (OpenSSL: $use_openssl)"
echo " Ecore_Config.................: $have_ecore_config"
echo " Ecore_DBUS...................: $have_ecore_dbus"
echo " Ecore_Desktop................: $have_ecore_desktop"
#echo " Ecore_File...................: $have_ecore_file (Inotify: $use_inotify) (FAM: $use_fam) (Poll: $use_poll)"
echo " Ecore_File...................: $have_ecore_file (Inotify: $use_inotify) (Poll: $use_poll) (CURL: $use_curl)"
echo

View File

@ -56,6 +56,19 @@ Description: Ecore DBus Library
applications.
This package contains the Ecore DBus Library.
Package: libecore0-desktop
Architecture: any
Section: libs
Depends: ${shlibs:Depends}, libecore0 (= ${Source-Version}), libecore-file
Provides: libecore-desktop
Description: Ecore freedesktop.org .desktop, icon, menu parsing Library
This is the core event abstraction layer and X abstraction layer that makes
doing selections, Xdnd, general X stuff, and event loops, timeouts and idle
handlers fast, optimized, and convenient. It's a separate library so anyone
can make use of the work put into Ecore to make this job easy for
applications.
This package contains the Ecore freedesktop.org .desktop, icon, menu parsing Library.
Package: libecore0-evas
Architecture: any
Section: libs
@ -152,7 +165,7 @@ Package: libecore0-all
Architecture: any
Section: libdevel
Architecture: any
Depends: libecore0 (= ${Source-Version}), libecore-config, libecore-con, libecore-dbus, libecore-evas, libecore-fb, libecore-file, libecore-ipc, libecore-job, libecore-txt, libecore-x
Depends: libecore0 (= ${Source-Version}), libecore-config, libecore-con, libecore-dbus, libecore-desktop, libecore-evas, libecore-fb, libecore-file, libecore-ipc, libecore-job, libecore-txt, libecore-x
Provides: libecore-all
Description: Virtual package providing all available Ecore modules.
This is the core event abstraction layer and X abstraction layer that makes

View File

@ -0,0 +1 @@
debian/tmp/usr/lib/libecore_desktop.so.*

View File

@ -2,6 +2,7 @@ debian/tmp/usr/include/Ecore_Config.h
debian/tmp/usr/include/Ecore_Con.h
debian/tmp/usr/include/Ecore_Data.h
debian/tmp/usr/include/Ecore_DBus.h
debian/tmp/usr/include/Ecore_Desktop.h
debian/tmp/usr/include/Ecore_Evas.h
debian/tmp/usr/include/Ecore_Fb.h
debian/tmp/usr/include/Ecore_File.h
@ -24,6 +25,9 @@ debian/tmp/usr/lib/libecore_config.so
debian/tmp/usr/lib/libecore_dbus.a
debian/tmp/usr/lib/libecore_dbus.la
debian/tmp/usr/lib/libecore_dbus.so
debian/tmp/usr/lib/libecore_desktop.a
debian/tmp/usr/lib/libecore_desktop.la
debian/tmp/usr/lib/libecore_desktop.so
debian/tmp/usr/lib/libecore_evas.a
debian/tmp/usr/lib/libecore_evas.la
debian/tmp/usr/lib/libecore_evas.so

View File

@ -6,8 +6,8 @@ exec_prefix_set=no
usage() {
echo "Usage: ecore-config [--prefix[=DIR]] [--exec-prefix[=DIR]] [--version] [--libs] [--cflags]" 1>&2
echo " [--libs-con] [--libs-config] [--libs-dbus] [--libs-evas] [--libs-fb]" 1>&2
echo " [--libs-file] [--libs-ipc] [--libs-job] [--libs-txt] [--libs-x]" 1>&2
echo " [--libs-con] [--libs-config] [--libs-dbus] [--libs-desktop] [--libs-evas]" 1>&2
echo " [--libs-fb] [--libs-file] [--libs-ipc] [--libs-job] [--libs-txt] [--libs-x]" 1>&2
}
if test $# -eq 0; then
@ -49,7 +49,7 @@ while test $# -gt 0; do
;;
--libs)
libdirs=-L@libdir@
echo $libdirs -lecore @ecore_job_libs@ @ecore_x_libs@ @ecore_evas_libs@ @ecore_con_libs@ @ecore_ipc_libs@ @ecore_txt_libs@ @ecore_fb_libs@ @ecore_config_libs@ @ecore_file_libs@ @ecore_dbus_libs@ @SSL_LIBS@ @winsock_libs@ @CURL_LIBS@ @EET_LIBS@ @EVAS_LIBS@ @x_libs@ @Xcursor_libs@ @Xrender_libs@ @Xprint_libs@ @Xinerama_libs@ @Xrandr_libs@ @Xfixes_libs@ @Xdamage_libs@ @Xss_libs@ @iconv_libs@ @tslib_libs@ @fam_libs@ -lm
echo $libdirs -lecore @ecore_job_libs@ @ecore_x_libs@ @ecore_evas_libs@ @ecore_con_libs@ @ecore_ipc_libs@ @ecore_txt_libs@ @ecore_fb_libs@ @ecore_config_libs@ @ecore_file_libs@ @ecore_desktop_libs@ @ecore_dbus_libs@ @SSL_LIBS@ @winsock_libs@ @CURL_LIBS@ @EET_LIBS@ @EVAS_LIBS@ @x_libs@ @Xcursor_libs@ @Xrender_libs@ @Xprint_libs@ @Xinerama_libs@ @Xrandr_libs@ @Xfixes_libs@ @Xdamage_libs@ @Xss_libs@ @iconv_libs@ @tslib_libs@ @fam_libs@ -lm
;;
--libs-con)
libdirs=-L@libdir@
@ -63,6 +63,10 @@ while test $# -gt 0; do
libdirs=-L@libdir@
echo $libdirs -lecore @ecore_dbus_libs@ @SSL_LIBS@ -lm
;;
--libs-desktop)
libdirs=-L@libdir@
echo $libdirs -lecore @ecore_desktop_libs@ @ecore_file_libs@ -lm
;;
--libs-evas)
libdirs=-L@libdir@
echo $libdirs -lecore @ecore_evas_libs@ @EVAS_LIBS@ @ecore_x_libs@ @x_libs@ @Xcursor_libs@ @Xrender_libs@ @Xprint_libs@ @Xinerama_libs@ @Xrandr_libs@ @Xfixes_libs@ @Xdamage_libs@ @Xss_libs@ @ecore_txt_libs@ @iconv_libs@ @ecore_job_libs@ @ecore_fb_libs@ @tslib_libs@ -lm

View File

@ -27,7 +27,7 @@ Summary: Ecore headers and development libraries.
Group: Development/Libraries
Requires: %{name} = %{version}
Requires: openssl-devel, evas-devel, eet-devel
Requires: ecore-con, ecore-config, ecore-dbus, ecore-evas, ecore-fb, ecore-file, ecore-ipc, ecore-job, ecore-txt, ecore-x
Requires: ecore-con, ecore-config, ecore-dbus, ecore-desktop, ecore-evas, ecore-fb, ecore-file, ecore-ipc, ecore-job, ecore-txt, ecore-x
%description devel
Ecore development files
@ -69,6 +69,11 @@ Summary: Ecore DBus Library
Group: Development/Libraries
Requires: %{name} = %{version}
%package desktop
Summary: Ecore freedesktop.org .desktop, icon, menu parsing Library
Group: Development/Libraries
Requires: %{name} = %{version}
%description dbus
Ecore DBus Library
@ -189,6 +194,10 @@ test "x$RPM_BUILD_ROOT" != "x/" && rm -rf $RPM_BUILD_ROOT
%defattr(-, root, root)
%{_libdir}/libecore_dbus.so.*
%files desktop
%defattr(-, root, root)
%{_libdir}/libecore_desktop.so.*
%files evas
%defattr(-, root, root)
%{_libdir}/libecore_evas.so.*

View File

@ -11,4 +11,5 @@ ecore_ipc \
ecore_evas \
ecore_config \
ecore_file \
ecore_desktop \
ecore_dbus

View File

@ -0,0 +1,6 @@
.deps
.libs
Makefile
Makefile.in
*.lo
*.la

View File

@ -0,0 +1,122 @@
#ifndef _ECORE_DESKTOP_H
# define _ECORE_DESKTOP_H
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <Ecore_Data.h>
#define MAX_PATH 4096
#define E_FN_DEL(_fn, _h) if (_h) { _fn(_h); _h = NULL; }
#define E_REALLOC(p, s, n) p = (s *)realloc(p, sizeof(s) * n)
#define E_NEW(s, n) (s *)calloc(n, sizeof(s))
#define E_NEW_BIG(s, n) (s *)malloc(n * sizeof(s))
#define E_FREE(p) { if (p) {free(p); p = NULL;} }
Ecore_List *ecore_desktop_paths_config;
Ecore_List *ecore_desktop_paths_menus;
Ecore_List *ecore_desktop_paths_directories;
Ecore_List *ecore_desktop_paths_desktops;
Ecore_List *ecore_desktop_paths_icons;
Ecore_List *ecore_desktop_paths_kde_legacy;
struct _Ecore_Desktop
{
Ecore_Hash *data, *group, *Categories, *OnlyShowIn, *NotShowIn;
char *name;
char *generic;
char *comment;
char *type;
char *categories;
char *exec;
char *icon;
char *icon_path;
char *startup;
char *window_class;
int allocated; /* FIXME: NoDisplay, Hidden */
};
typedef struct _Ecore_Desktop Ecore_Desktop;
enum _Ecore_Desktop_Tree_Element_Type
{
ECORE_DESKTOP_TREE_ELEMENT_TYPE_NULL = 0,
ECORE_DESKTOP_TREE_ELEMENT_TYPE_STRING = 1,
ECORE_DESKTOP_TREE_ELEMENT_TYPE_TREE = 2,
ECORE_DESKTOP_TREE_ELEMENT_TYPE_HASH = 3,
};
typedef enum _Ecore_Desktop_Tree_Element_Type Ecore_Desktop_Tree_Element_Type;
struct _Ecore_Desktop_Tree_Element
{
void *element; /* A pointer to the element. */
Ecore_Desktop_Tree_Element_Type type; /* The type of the element. */
};
typedef struct _Ecore_Desktop_Tree_Element Ecore_Desktop_Tree_Element;
typedef struct _Ecore_Desktop_Tree Ecore_Desktop_Tree;
struct _Ecore_Desktop_Tree
{
Ecore_Desktop_Tree_Element *elements; /* An array of elements. */
int size; /* The size of the array. */
char **buffers; /* An array of pointers to the bits of data. */
int buffers_size; /* The size of the array. */
Ecore_Desktop_Tree *parent; /* Parent if this is a child. */
};
# ifdef __cplusplus
extern "C"
{
# endif
/* Function Prototypes */
void ecore_desktop_paths_init(void);
char *ecore_desktop_paths_search_for_file(Ecore_List *paths, char *file, int sub, int (*func) (const void *data, char *path), const void *data);
char *ecore_desktop_paths_recursive_search(char *path, char *d, int (*dir_func) (const void *data, char *path), int (*func) (const void *data, char *path), const void *data);
void ecore_desktop_paths_shutdown(void);
Ecore_Hash *ecore_desktop_hash_from_paths(char *paths);
Ecore_List *ecore_desktop_list_from_paths(char *paths);
void ecore_desktop_init(void);
void ecore_desktop_shutdown(void);
Ecore_Hash *ecore_desktop_parse_ini_file(char *file);
Ecore_Desktop *ecore_desktop_parse_file(char *file);
void ecore_desktop_destroy(Ecore_Desktop * desktop);
char *ecore_desktop_find_icon(char *icon, char *icon_size, char *icon_theme);
Ecore_Desktop_Tree *ecore_desktop_menus_get(char *file, Ecore_Desktop_Tree * merge_stack, int level);
Ecore_Desktop_Tree *ecore_desktop_tree_new(char *buffer);
Ecore_Desktop_Tree *ecore_desktop_tree_add(Ecore_Desktop_Tree * tree, char *element);
void ecore_desktop_tree_track(Ecore_Desktop_Tree * tree, void *element);
Ecore_Desktop_Tree *ecore_desktop_tree_extend(Ecore_Desktop_Tree * tree, char *element);
Ecore_Desktop_Tree *ecore_desktop_tree_insert(Ecore_Desktop_Tree * tree, int before, void *element, Ecore_Desktop_Tree_Element_Type type);
Ecore_Desktop_Tree *ecore_desktop_tree_merge(Ecore_Desktop_Tree * tree, int before, Ecore_Desktop_Tree * element);
Ecore_Desktop_Tree *ecore_desktop_tree_add_child(Ecore_Desktop_Tree * tree, Ecore_Desktop_Tree * element);
Ecore_Desktop_Tree *ecore_desktop_tree_add_hash(Ecore_Desktop_Tree * tree, Ecore_Hash * element);
void ecore_desktop_tree_remove(Ecore_Desktop_Tree * tree, int element);
int ecore_desktop_tree_exist(Ecore_Desktop_Tree * tree, char *element);
int ecore_desktop_tree_foreach(Ecore_Desktop_Tree * tree, int level, int (*func) (const void *data, Ecore_Desktop_Tree * tree, int element, int level), const void *data);
void ecore_esktop_tree_dump(Ecore_Desktop_Tree * tree, int level);
void ecore_desktop_tree_del(Ecore_Desktop_Tree * tree);
Ecore_Desktop_Tree *ecore_desktop_xmlame_new(char *buffer);
Ecore_Desktop_Tree *ecore_desktop_xmlame_get(char *file);
char *ecore_desktop_get_home(void);
# ifdef __cplusplus
}
# endif
#endif

View File

@ -0,0 +1,48 @@
MAINTAINERCLEANFILES = Makefile.in
INCLUDES = \
-I$(top_srcdir)/src/lib/ecore \
-I$(top_builddir)/src/lib/ecore_file \
-I$(top_builddir)/src/lib/ecore_desktop \
-I$(top_builddir)/src/lib/ecore \
-I$(top_srcdir)/src/lib/ecore_file \
-I$(top_srcdir)/src/lib/ecore_desktop
libecore_desktop_la_LDFLAGS = -version-info 1:0:0 \
-L$(top_builddir)/src/lib/ecore/.libs \
-L$(top_builddir)/src/lib/ecore_file/.libs
if BUILD_ECORE_DESKTOP
lib_LTLIBRARIES = libecore_desktop.la
include_HEADERS = \
Ecore_Desktop.h
libecore_desktop_la_SOURCES = \
ecore_desktop.c \
ecore_desktop_tree.c \
ecore_desktop_icon.c \
ecore_desktop_menu.c \
ecore_desktop_paths.c \
ecore_desktop_xmlame.c \
ecore_desktop_private.h
libecore_desktop_la_LIBADD = \
$(top_builddir)/src/lib/ecore/libecore.la \
$(top_builddir)/src/lib/ecore_file/libecore_file.la
libecore_desktop_la_DEPENDENCIES = \
$(top_builddir)/src/lib/ecore/libecore.la \
$(top_builddir)/src/lib/ecore_file/libecore_file.la
endif
EXTRA_DIST = \
Ecore_Desktop.h \
ecore_desktop.c \
ecore_desktop_tree.c \
ecore_desktop_icon.c \
ecore_desktop_menu.c \
ecore_desktop_paths.c \
ecore_desktop_xmlame.c \
ecore_desktop_private.h

View File

@ -0,0 +1,237 @@
#include "Ecore_Desktop.h"
#include "ecore_desktop_private.h"
extern int reject_count, not_over_count;
static Ecore_Hash *ini_file_cache;
static Ecore_Hash *desktop_cache;
Ecore_Hash *
ecore_desktop_parse_ini_file(char *file)
{
Ecore_Hash *result;
/* FIXME: should probably look in ini_file_cache first. */
result = ecore_hash_new(ecore_str_hash, ecore_str_compare);
if (result)
{
FILE *f;
char buffer[MAX_PATH];
Ecore_Hash *current = NULL;
f = fopen(file, "r");
if (!f)
{
fprintf(stderr, "ERROR: Cannot Open File %s\n", file);
ecore_hash_destroy(result);
return NULL;
}
ecore_hash_set_free_key(result, free);
ecore_hash_set_free_value(result, (Ecore_Free_Cb) ecore_hash_destroy);
*buffer = '\0';
#ifdef DEBUG
fprintf(stdout, "PARSING INI %s\n", file);
#endif
while (fgets(buffer, sizeof(buffer), f) != NULL)
{
char *c;
char *key;
char *value;
c = buffer;
/* Strip preceeding blanks. */
while (((*c == ' ') || (*c == '\t')) && (*c != '\n') && (*c != '\0'))
c++;
/* Skip blank lines and comments */
if ((*c == '\0') || (*c == '\n') || (*c == '#'))
continue;
if (*c == '[') /* New group. */
{
key = c + 1;
while ((*c != ']') && (*c != '\n') && (*c != '\0'))
c++;
*c++ = '\0';
current = ecore_hash_new(ecore_str_hash, ecore_str_compare);
if (current)
{
ecore_hash_set_free_key(current, free);
ecore_hash_set_free_value(current, free);
ecore_hash_set(result, strdup(key), current);
#ifdef DEBUG
fprintf(stdout, " GROUP [%s]\n", key);
#endif
}
}
else if (current) /* key=value pair of current group. */
{
key = c;
/* Find trailing blanks or =. */
while ((*c != '=') && (*c != ' ') && (*c != '\t') && (*c != '\n') && (*c != '\0'))
c++;
if (*c != '=') /* Find equals. */
{
*c++ = '\0';
while ((*c != '=') && (*c != '\n') && (*c != '\0'))
c++;
}
if (*c == '=') /* Equals found. */
{
*c++ = '\0';
/* Strip preceeding blanks. */
while (((*c == ' ') || (*c == '\t')) && (*c != '\n') && (*c != '\0'))
c++;
value = c;
/* Find end. */
while ((*c != '\n') && (*c != '\0'))
c++;
*c++ = '\0';
/* FIXME: should strip space at end, then unescape value. */
ecore_hash_set(current, strdup(key), strdup(value));
#ifdef DEBUG
fprintf(stdout, " %s=%s\n", key, value);
#endif
}
}
}
buffer[0] = (char)0;
fclose(f);
ecore_hash_set(ini_file_cache, strdup(file), result);
}
return result;
}
Ecore_Desktop *
ecore_desktop_parse_file(char *file)
{
Ecore_Desktop *result;
result = (Ecore_Desktop *) ecore_hash_get(desktop_cache, file);
if (!result)
{
result = calloc(1, sizeof(Ecore_Desktop));
if (result)
{
result->data = ecore_desktop_parse_ini_file(file);
if (result->data)
{
result->group = (Ecore_Hash *) ecore_hash_get(result->data, "Desktop Entry");
if (!result->group)
result->group = (Ecore_Hash *) ecore_hash_get(result->data, "KDE Desktop Entry");
if (result->group)
{
char *value;
result->name = (char *)ecore_hash_get(result->group, "Name");
result->generic = (char *)ecore_hash_get(result->group, "GenericName");
result->comment = (char *)ecore_hash_get(result->group, "Comment");
result->type = (char *)ecore_hash_get(result->group, "Type");
result->exec = (char *)ecore_hash_get(result->group, "Exec");
result->window_class = (char *)ecore_hash_get(result->group, "StartupWMClass");
result->icon = (char *)ecore_hash_get(result->group, "Icon");
result->categories = (char *)ecore_hash_get(result->group, "Categories");
if (result->categories)
result->Categories = ecore_desktop_hash_from_paths(result->categories);
value = (char *)ecore_hash_get(result->group, "OnlyShowIn");
if (value)
result->OnlyShowIn = ecore_desktop_hash_from_paths(value);
value = (char *)ecore_hash_get(result->group, "NotShowIn");
if (value)
result->NotShowIn = ecore_desktop_hash_from_paths(value);
value = (char *)ecore_hash_get(result->group, "X-KDE-StartupNotify");
if (value)
result->startup = (!strcmp(value, "true")) ? "1" : "0";
value = (char *)ecore_hash_get(result->group, "StartupNotify");
if (value)
result->startup = (!strcmp(value, "true")) ? "1" : "0";
}
ecore_hash_set(desktop_cache, strdup(file), result);
}
else
{
free(result);
result = NULL;
}
}
}
return result;
}
void
ecore_desktop_init()
{
if (!ini_file_cache)
{
ini_file_cache = ecore_hash_new(ecore_str_hash, ecore_str_compare);
if (ini_file_cache)
{
ecore_hash_set_free_key(ini_file_cache, free);
ecore_hash_set_free_value(ini_file_cache, (Ecore_Free_Cb) ecore_hash_destroy);
}
}
if (!desktop_cache)
{
desktop_cache = ecore_hash_new(ecore_str_hash, ecore_str_compare);
if (desktop_cache)
{
ecore_hash_set_free_key(desktop_cache, free);
ecore_hash_set_free_value(desktop_cache, (Ecore_Free_Cb) ecore_desktop_destroy);
}
}
}
void
ecore_desktop_shutdown()
{
if (ini_file_cache)
{
ecore_hash_destroy(ini_file_cache);
ini_file_cache = NULL;
}
if (desktop_cache)
{
ecore_hash_destroy(desktop_cache);
desktop_cache = NULL;
}
}
void
ecore_desktop_destroy(Ecore_Desktop * desktop)
{
if (desktop->NotShowIn)
ecore_hash_destroy(desktop->NotShowIn);
if (desktop->OnlyShowIn)
ecore_hash_destroy(desktop->OnlyShowIn);
if (desktop->Categories)
ecore_hash_destroy(desktop->Categories);
free(desktop);
}
char *
ecore_desktop_get_home()
{
char *d;
int length;
char home[MAX_PATH];
/* Get Home Dir, check for trailing '/', strip it */
snprintf(home, sizeof(home), "%s", getenv("HOME"));
d = strrchr(home, '/');
if (d)
{
if (strlen(d) == 1)
{
if (home[(length = strlen(home) - 1)] == '/')
home[length] = '\0';
}
}
return strdup(home);
}

View File

@ -0,0 +1,288 @@
#include <limits.h>
#include "Ecore_Desktop.h"
#include "ecore_desktop_private.h"
//#define DEBUG 1
static char * _ecore_desktop_find_icon0(char *icon, char *icon_size, char *icon_theme);
/* FIXME: Ideally this should be -
* {".png", ".svg", ".xpm", "", NULL}
* Add them in when they are supported in .eaps.
*/
static const char *ext[] = { ".png", ".svg", ".xpm", "", NULL };
char *
ecore_desktop_find_icon(char *icon, char *icon_size, char *icon_theme)
{
char icn[MAX_PATH], path[MAX_PATH];
char *dir, *home;
if (icon == NULL)
return NULL;
/* Easy check first, was a full path supplied? */
if ((icon[0] == '/') && (ecore_file_exists(icon)))
return strdup(icon);
home = ecore_desktop_get_home();
snprintf(icn, sizeof(icn), "%s", icon);
#ifdef DEBUG
fprintf(stderr, "\tTrying To Find Icon %s\n", icn);
#endif
/* Check For Unsupported Extension */
// if ((!strcmp(icon + strlen(icon) - 4, ".svg")) || (!strcmp(icon + strlen(icon) - 4, ".ico"))
// || (!strcmp(icon + strlen(icon) - 4, ".xpm")))
if (!strcmp(icon + strlen(icon) - 4, ".ico"))
return NULL;
if (!icon_theme)
{
/* Check If Dir Supplied In Desktop File */
dir = ecore_file_get_dir(icn);
if (!strcmp(dir, icn) == 0)
{
snprintf(path, MAX_PATH, "%s", icn);
/* Check Supplied Dir For Icon */
if (ecore_file_exists(path))
return strdup(icn);
}
}
dir = _ecore_desktop_find_icon0(icon, icon_size, icon_theme);
if (dir)
dir = strdup(dir);
return dir;
}
/** Search for an icon the fdo way.
*
* This complies with the freedesktop.org Icon Theme Specification version 0.7
*
* @param icon The icon to search for.
* @param icon_size The icon size to search for.
* @param icon_theme The icon theme to search in.
* @return The full path to the found icon.
*/
static char *
_ecore_desktop_find_icon0(char *icon, char *icon_size, char *icon_theme)
{
/* NOTES ON OPTIMIZATIONS
*
* The spec has this to say -
*
* "The algorithm as described in this document works by always looking up
* filenames in directories (a stat in unix terminology). A good
* implementation is expected to read the directories once, and do all
* lookups in memory using that information.
*
* "This caching can make it impossible for users to add icons without having
* to restart applications. In order to handle this, any implementation that
* does caching is required to look at the mtime of the toplevel icon
* directories when doing a cache lookup, unless it already did so less than
* 5 seconds ago. This means that any icon editor or theme installation
* program need only to change the mtime of the the toplevel directory where
* it changed the theme to make sure that the new icons will eventually get
* used."
*
* On the other hand, OS caching (at least in linux) seems to do a reasonable
* job here.
*
* We could also precalculate and cache all the information extracted from
* the .theme files.
*/
char icn[MAX_PATH], path[MAX_PATH];
char *theme_path, *found;
if ((icon == NULL) || (icon[0] == '\0'))
return NULL;
#ifdef DEBUG
fprintf(stderr, "\tTrying To Find Icon %s (%s) in theme %s\n", icon, icon_size, icon_theme);
#endif
/* Get the theme description file. */
snprintf(icn, MAX_PATH, "%s/index.theme", icon_theme);
#ifdef DEBUG
printf("SEARCHING FOR %s\n", icn);
#endif
theme_path = ecore_desktop_paths_search_for_file(ecore_desktop_paths_icons, icn, 1, NULL, NULL);
if (theme_path)
{
Ecore_Hash *theme;
/* Parse the theme description file. */
#ifdef DEBUG
printf("Path to %s is %s\n", icn, theme_path);
#endif
theme = ecore_desktop_parse_ini_file(theme_path);
if (theme)
{
Ecore_Hash *icon_group;
/* Grab the themes directory list, and what it inherits. */
icon_group = (Ecore_Hash *) ecore_hash_get(theme, "Icon Theme");
if (icon_group)
{
char *directories, *inherits;
directories = (char *)ecore_hash_get(icon_group, "Directories");
inherits = (char *)ecore_hash_get(icon_group, "Inherits");
if (directories)
{
Ecore_List *directory_paths;
/* Split the directory list. */
#ifdef DEBUG
printf("Inherits %s Directories %s\n", inherits, directories);
#endif
directory_paths = ecore_desktop_list_from_paths(directories);
if (directory_paths)
{
int wanted_size;
int minimal_size = INT_MAX;
int i;
char *closest = NULL;
char *directory;
wanted_size = atoi(icon_size);
/* Loop through the themes directories. */
ecore_list_goto_first(directory_paths);
while ((directory = ecore_list_next(directory_paths)) != NULL)
{
Ecore_Hash *sub_group;
#ifdef DEBUG
printf("FDO icon path = %s\n", directory_paths);
#endif
/* Get the details for this theme directory. */
sub_group = (Ecore_Hash *) ecore_hash_get(theme, directory);
if (sub_group)
{
char *size, *type, *minsize, *maxsize, *threshold;
int j;
size = (char *)ecore_hash_get(sub_group, "Size");
type = (char *)ecore_hash_get(sub_group, "Type");
minsize = (char *)ecore_hash_get(sub_group, "MinSize");
maxsize = (char *)ecore_hash_get(sub_group, "MaxSize");
threshold = (char *)ecore_hash_get(sub_group, "Threshold");
if (size)
{
int match = 0;
int this_size, result_size = 0, min_size, max_size, thresh_size;
if (!minsize)
minsize = size;
if (!maxsize)
maxsize = size;
if (!threshold)
threshold = "2";
min_size = atoi(minsize);
max_size = atoi(maxsize);
thresh_size = atoi(threshold);
/* Does this theme directory match the required icon size? */
this_size = atoi(size);
if (!type)
type = "Threshold";
switch (type[0])
{
case 'F': /* Fixed. */
{
match = (wanted_size == this_size);
result_size = abs(this_size - wanted_size);
break;
}
case 'S': /* Scaled. */
{
match = ((min_size <= wanted_size) && (wanted_size <= max_size));
if (wanted_size < min_size)
result_size = min_size - wanted_size;
if (wanted_size > max_size)
result_size = wanted_size - max_size;
break;
}
default: /* Threshold. */
{
match = (((this_size - thresh_size) <= wanted_size)
&& (wanted_size <= (this_size + thresh_size)));
if (wanted_size < (this_size - thresh_size))
result_size = min_size - wanted_size;
if (wanted_size > (this_size + thresh_size))
result_size = wanted_size - max_size;
break;
}
}
/* Look for icon with all extensions. */
for (j = 0; ext[j] != NULL; j++)
{
snprintf(path, MAX_PATH, "%s/%s/%s%s", icon_theme, directory, icon, ext[j]);
#ifdef DEBUG
printf("FDO icon = %s\n", path);
#endif
found = ecore_desktop_paths_search_for_file(ecore_desktop_paths_icons, path, 0, NULL, NULL);
if (found)
{
if (match) /* If there is a match in sizes, return the icon. */
return found;
if (result_size < minimal_size) /* While we are here, figure out our next fallback strategy. */
{
minimal_size = result_size;
closest = found;
}
}
}
}
}
} /* while ((directory = ecore_list_next(directory_paths)) != NULL) */
/* Fall back strategy #1, look for closest size in this theme. */
if (closest)
return closest;
/* Fall back strategy #2, Try again with the parent theme. */
if ((inherits) && (inherits[0] != '\0') && (strcmp(icon_theme, "hicolor") != 0))
{
found = _ecore_desktop_find_icon0(icon, icon_size, inherits);
if (found != NULL)
return found;
}
/* Fall back strategy #3, Try the default hicolor theme. */
if ((!((inherits) && (inherits[0] != '\0'))) && (strcmp(icon_theme, "hicolor") != 0))
{
found = _ecore_desktop_find_icon0(icon, icon_size, "hicolor");
if (found != NULL)
return found;
}
/* Fall back strategy #4, Just search in the base of the icon directories. */
for (i = 0; ext[i] != NULL; i++)
{
snprintf(path, MAX_PATH, "%s%s", icon, ext[i]);
#ifdef DEBUG
printf("FDO icon = %s\n", path);
#endif
found = ecore_desktop_paths_search_for_file(ecore_desktop_paths_icons, path, 0, NULL, NULL);
if (found)
return found;
}
}
}
}
}
free(theme_path);
}
return NULL;
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,657 @@
/*
* This conforms with the freedesktop.org XDG Base Directory Specification version 0.6
*/
#include <dirent.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <libgen.h>
#include <Ecore.h>
#include "Ecore_Desktop.h"
#include "ecore_desktop_private.h"
struct _config_exe_data
{
char *home;
Ecore_List *paths, *types;
int done;
};
static Ecore_List *_ecore_desktop_paths_get(char *before, char *env_home, char *env, char *env_home_default, char *env_default, char *type,
char *gnome_extra, char *kde);
static void _ecore_desktop_paths_massage_path(char *path, char *home, char *first, char *second);
static void _ecore_desktop_paths_check_and_add(Ecore_List * paths, char *path);
static void _ecore_desktop_paths_exec_config(Ecore_List * paths, char *home, Ecore_List * extras, char *cmd);
static int _ecore_desktop_paths_cb_exe_exit(void *data, int type, void *event);
Ecore_Event_Handler *exit_handler = NULL;
Ecore_List *gnome_data = NULL;
char *home;
void
ecore_desktop_paths_init()
{
/* FIXME: Keep track of any loose strdups in a list, so that we can free them at shutdown time. */
exit_handler = ecore_event_handler_add(ECORE_EXE_EVENT_DEL, _ecore_desktop_paths_cb_exe_exit, NULL);
gnome_data = ecore_list_new();
home = ecore_desktop_get_home();
if (home)
{
int last;
/* Strip trailing slash of home. */
last = strlen(home) - 1;
if ((last >= 0) && (home[last] == '/'))
home[last] = '\0';
}
if (exit_handler && gnome_data)
{
ecore_list_set_free_cb(gnome_data, free);
_ecore_desktop_paths_exec_config(gnome_data, home, NULL, "gnome-config --datadir");
}
if (!ecore_desktop_paths_desktops)
{
ecore_desktop_paths_desktops =
_ecore_desktop_paths_get(NULL, "XDG_DATA_HOME", "XDG_DATA_DIRS",
"~/.local/share", "/usr/local/share:/usr/share", "applications",
"dist/desktop-files:dist/short-menu:gnome/apps", "xdgdata-apps:apps");
_ecore_desktop_paths_check_and_add(ecore_desktop_paths_desktops, "/usr/local/share/update-desktop-files/templates");
_ecore_desktop_paths_check_and_add(ecore_desktop_paths_desktops, "/usr/share/update-desktop-files/templates");
}
if (!ecore_desktop_paths_kde_legacy)
{
char temp[MAX_PATH], *path;
Ecore_List *temp_list;
ecore_desktop_paths_kde_legacy = _ecore_desktop_paths_get(NULL, NULL, NULL, NULL, NULL, NULL, NULL, "apps");
if (ecore_desktop_paths_kde_legacy)
{
/* Copy it, cause Ecore_List walks can not be nested. */
temp_list = ecore_list_new();
if (temp_list)
{
ecore_list_goto_first(ecore_desktop_paths_kde_legacy);
while ((path = ecore_list_next(ecore_desktop_paths_kde_legacy)) != NULL)
ecore_list_append(temp_list, path);
ecore_list_goto_first(temp_list);
while ((path = ecore_list_next(temp_list)) != NULL)
{
char *t1, *t2;
t1 = rindex(path, '/');
*t1 = '\0';
t2 = rindex(path, '/');
*t2 = '\0';
sprintf(temp, "%s/apps/kappfinder/apps/", path);
*t2 = '/';
*t1 = '/';
_ecore_desktop_paths_check_and_add(ecore_desktop_paths_kde_legacy, temp);
}
}
}
}
if (!ecore_desktop_paths_icons)
{
char *gnome;
ecore_desktop_paths_icons =
_ecore_desktop_paths_get("~/.icons", "XDG_DATA_HOME", "XDG_DATA_DIRS", "~/.local/share", "/usr/local/share:/usr/share", "icons",
"dist/icons", "icon:pixmap");
_ecore_desktop_paths_check_and_add(ecore_desktop_paths_icons, "/usr/local/share/pixmaps/");
_ecore_desktop_paths_check_and_add(ecore_desktop_paths_icons, "/usr/share/pixmaps/");
gnome = getenv("GNOME_ICON_PATH");
if (gnome)
_ecore_desktop_paths_check_and_add(ecore_desktop_paths_icons, gnome);
}
if (!ecore_desktop_paths_menus)
ecore_desktop_paths_menus =
_ecore_desktop_paths_get(NULL, "XDG_CONFIG_HOME", "XDG_CONFIG_DIRS", "~/.config", "/etc/xdg", "menus", NULL, "xdgconf-menu");
if (!ecore_desktop_paths_directories)
ecore_desktop_paths_directories =
_ecore_desktop_paths_get(NULL, "XDG_DATA_HOME", "XDG_DATA_DIRS",
"~/.local/share", "/usr/local/share:/usr/share", "desktop-directories", "gnome/vfolders", "xdgdata-dirs");
if (!ecore_desktop_paths_config)
ecore_desktop_paths_config = _ecore_desktop_paths_get(NULL, "XDG_CONFIG_HOME", "XDG_CONFIG_DIRS", "~/.config", "/etc/xdg", "", NULL, NULL);
if (exit_handler) ecore_event_handler_del(exit_handler);
}
void
ecore_desktop_paths_shutdown()
{
E_FN_DEL(ecore_list_destroy, ecore_desktop_paths_menus);
E_FN_DEL(ecore_list_destroy, ecore_desktop_paths_directories);
E_FN_DEL(ecore_list_destroy, ecore_desktop_paths_desktops);
E_FN_DEL(ecore_list_destroy, ecore_desktop_paths_icons);
}
/** Search for a file in fdo compatible locations.
*
* This will search through all the diretories of a particular type, looking
* for the file. It will recurse into subdirectories. If func is NULL, then
* only the first file found will be returned. If func is defined, then each
* file found will be passed to func, until func returns 1.
*
* @param type The type of directories to search.
* @param file The file to search for.
* @param sub Should we search sub directories.
* @param func A function to call for each file found.
* @param data A pointer to pass on to func.
*/
char *
ecore_desktop_paths_search_for_file(Ecore_List *paths, char *file, int sub, int (*func) (const void *data, char *path), const void *data)
{
char *path = NULL, *this_path;
char temp[MAX_PATH];
struct stat path_stat;
if (paths)
{
ecore_list_goto_first(paths);
while ((this_path = ecore_list_next(paths)) != NULL)
{
sprintf(temp, "%s%s", this_path, file);
if (stat(temp, &path_stat) == 0)
{
path = strdup(temp);
if (func)
if (func(data, path))
break;
}
else if (sub)
path = ecore_desktop_paths_recursive_search(this_path, file, NULL, func, data);
if (path && (!func))
break;
}
}
return path;
}
/* We need -
config file full of paths
menus=pathlist
desktops=pathlist
directories=pathlist
icons=pathlist
*/
static Ecore_List *
_ecore_desktop_paths_get(char *before, char *env_home, char *env, char *env_home_default, char *env_default, char *type, char *gnome_extra,
char *kde)
{
Ecore_List *paths = NULL;
Ecore_List *types = NULL;
Ecore_List *gnome_extras = NULL;
Ecore_List *kdes = NULL;
/* Don't sort them, as they are in preferred order from each source. */
/* Merge the results, there are probably some duplicates. */
if (type) types = ecore_desktop_list_from_paths(strdup(type));
if (gnome_extra) gnome_extras = ecore_desktop_list_from_paths(strdup(gnome_extra));
if (kde) kdes = ecore_desktop_list_from_paths(strdup(kde));
paths = ecore_list_new();
if (paths)
{
char path[MAX_PATH];
Ecore_List *env_list;
ecore_list_set_free_cb(paths, free);
if (before)
{
Ecore_List *befores;
befores = ecore_desktop_list_from_paths(strdup(before));
if (befores)
{
char *this_before;
ecore_list_goto_first(befores);
while ((this_before = ecore_list_next(befores)) != NULL)
{
_ecore_desktop_paths_massage_path(path, home, this_before, NULL);
_ecore_desktop_paths_check_and_add(paths, path);
}
E_FN_DEL(ecore_list_destroy, befores);
}
}
if (env_home)
{
char *value;
value = getenv(env_home);
if ((value == NULL) || (value[0] == '\0'))
value = env_home_default;
env_list = ecore_desktop_list_from_paths(strdup(value));
if (env_list && types)
{
char *this_env, *this_type;
ecore_list_goto_first(env_list);
while ((this_env = ecore_list_next(env_list)) != NULL)
{
ecore_list_goto_first(types);
while ((this_type = ecore_list_next(types)) != NULL)
{
_ecore_desktop_paths_massage_path(path, home, this_env, this_type);
_ecore_desktop_paths_check_and_add(paths, path);
}
}
E_FN_DEL(ecore_list_destroy, env_list);
}
}
if (env)
{
char *value;
value = getenv(env);
if ((value == NULL) || (value[0] == '\0'))
value = env_default;
env_list = ecore_desktop_list_from_paths(value);
if (env_list && types)
{
char *this_env, *this_type;
ecore_list_goto_first(env_list);
while ((this_env = ecore_list_next(env_list)) != NULL)
{
ecore_list_goto_first(types);
while ((this_type = ecore_list_next(types)) != NULL)
{
_ecore_desktop_paths_massage_path(path, home, this_env, this_type);
_ecore_desktop_paths_check_and_add(paths, path);
}
}
E_FN_DEL(ecore_list_destroy, env_list);
}
}
/*
* Get the pathlist from the config file - type=pathlist
* for each path in config
* if it is already in paths, skip it
* if it exists, add it to end of paths
*/
if (gnome_data && types)
{
char *this_gnome, *this_type;
ecore_list_goto_first(gnome_data);
while ((this_gnome = ecore_list_next(gnome_data)) != NULL)
{
ecore_list_goto_first(types);
while ((this_type = ecore_list_next(types)) != NULL)
{
_ecore_desktop_paths_massage_path(path, home, this_gnome, this_type);
_ecore_desktop_paths_check_and_add(paths, path);
}
}
}
if (gnome_data && gnome_extras)
{
char *this_gnome, *this_type;
ecore_list_goto_first(gnome_data);
while ((this_gnome = ecore_list_next(gnome_data)) != NULL)
{
ecore_list_goto_first(gnome_extras);
while ((this_type = ecore_list_next(gnome_extras)) != NULL)
{
_ecore_desktop_paths_massage_path(path, home, this_gnome, this_type);
_ecore_desktop_paths_check_and_add(paths, path);
}
}
}
if ((exit_handler != NULL) && (kdes != NULL))
{
char *this_kde;
ecore_list_goto_first(kdes);
while ((this_kde = ecore_list_next(kdes)) != NULL)
{
char cmd[128];
sprintf(cmd, "kde-config --path %s", this_kde);
_ecore_desktop_paths_exec_config(paths, home, NULL, cmd);
}
}
}
E_FN_DEL(ecore_list_destroy, kdes);
E_FN_DEL(ecore_list_destroy, gnome_extras);
E_FN_DEL(ecore_list_destroy, types);
return paths;
}
static void
_ecore_desktop_paths_massage_path(char *path, char *home, char *first, char *second)
{
int last;
/* Strip traling slash of first. */
last = strlen(first) - 1;
if ((last >= 0) && (first[last] == '/'))
first[last] = '\0';
if (second)
{
/* Strip traling slash of second. */
last = strlen(second) - 1;
if ((last >= 0) && (second[last] == '/'))
second[last] = '\0';
}
if ((second) && (second[0] != '\0'))
{
if (first[0] == '~')
sprintf(path, "%s%s/%s/", home, &first[1], &second[(second[0] == '/') ? 1 : 0]);
else
sprintf(path, "%s/%s/", first, &second[(second[0] == '/') ? 1 : 0]);
}
else
{
if (first[0] == '~')
sprintf(path, "%s%s/", home, &first[1]);
else
sprintf(path, "%s/", first);
}
}
static void
_ecore_desktop_paths_check_and_add(Ecore_List * paths, char *path)
{
struct stat path_stat;
char *this_path;
if (paths == NULL)
{
paths = ecore_list_new();
if (paths == NULL)
return;
ecore_list_set_free_cb(paths, free);
}
/* Check if we have it already. */
ecore_list_goto_first(paths);
while ((this_path = ecore_list_next(paths)) != NULL)
{
if (strcmp(path, this_path) == 0)
return;
}
/* Check if the path exists. */
if ((stat(path, &path_stat) == 0) && (S_ISDIR(path_stat.st_mode)))
ecore_list_append(paths, strdup(path));
}
static void
_ecore_desktop_paths_exec_config(Ecore_List *paths, char *home, Ecore_List * extras, char *cmd)
{
Ecore_Exe *exe;
struct _config_exe_data ced;
ced.home = home;
ced.paths = paths;
ced.types = extras;
ced.done = 0;
exe = ecore_exe_pipe_run(cmd, ECORE_EXE_PIPE_AUTO | ECORE_EXE_PIPE_READ | ECORE_EXE_PIPE_READ_LINE_BUFFERED, &ced);
if (exe)
{
ecore_exe_tag_set(exe, "genmenu/fdo");
while (ced.done == 0)
{
/* FIXME: raster is paranoid. If too much time passes, give up.
* Or find a way to let the usual event loop shit do this without spinning our wheels.
* On the other hand, these are quick commands, and we NEED this data before we can continue.
*/
ecore_main_loop_iterate();
usleep(10);
}
}
}
char *
ecore_desktop_paths_recursive_search(char *path, char *file, int (*dir_func) (const void *data, char *path),
int (*func) (const void *data, char *path), const void *data)
{
char *fpath = NULL;
DIR *dir = NULL;
dir = opendir(path);
if (dir != NULL)
{
struct dirent *script;
while ((script = readdir(dir)) != NULL)
{
struct stat script_stat;
char info_text[4096];
sprintf(info_text, "%s%s", path, script->d_name);
if ((stat(info_text, &script_stat) == 0))
{
if (S_ISDIR(script_stat.st_mode))
{
if ((strcmp(basename(info_text), ".") != 0) && (strcmp(basename(info_text), "..") != 0))
{
sprintf(info_text, "%s%s/", path, script->d_name);
if (dir_func)
if (dir_func(data, info_text))
break;
fpath = ecore_desktop_paths_recursive_search(info_text, file, dir_func, func, data);
}
}
else
{
if (file)
{
if (strcmp(basename(info_text), file) == 0)
{
fpath = strdup(info_text);
if (func)
if (func(data, path))
break;
}
}
else
{
if (func)
if (func(data, info_text))
break;
}
}
if (fpath && (!func))
break;
}
}
closedir(dir);
}
return fpath;
}
static int
_ecore_desktop_paths_cb_exe_exit(void *data, int type, void *event)
{
Ecore_Exe_Event_Del *ev;
Ecore_List *paths;
Ecore_List *config_list;
Ecore_Exe_Event_Data *read;
struct _config_exe_data *ced;
char *value;
char path[MAX_PATH];
ev = event;
if (!ev->exe)
return 1;
value = ecore_exe_tag_get(ev->exe);
if ((!value) || (strcmp(value, "genmenu/fdo")) != 0)
return 1;
ced = ecore_exe_data_get(ev->exe);
if (!ced)
return 1;
paths = ced->paths;
if (!paths)
return 1;
read = ecore_exe_event_data_get(ev->exe, ECORE_EXE_PIPE_READ);
if ((read) && (read->lines[0].line))
{
value = read->lines[0].line;
if (value)
{
config_list = ecore_desktop_list_from_paths(value);
if (config_list)
{
char *this_config, *this_type;
ecore_list_goto_first(config_list);
while ((this_config = ecore_list_next(config_list)) != NULL)
{
if (ced->types)
{
ecore_list_goto_first(ced->types);
while ((this_type = ecore_list_next(ced->types)) != NULL)
{
_ecore_desktop_paths_massage_path(path, ced->home, this_config, this_type);
_ecore_desktop_paths_check_and_add(paths, path);
}
}
else
{
_ecore_desktop_paths_massage_path(path, ced->home, this_config, NULL);
_ecore_desktop_paths_check_and_add(paths, path);
}
}
E_FN_DEL(ecore_list_destroy, config_list);
}
}
}
ced->done = 1;
return 1;
}
/** Split a list of paths into an Ecore_Hash.
*
* The list of paths can use any one of ;:, to seperate the paths.
* You can also escape the :;, with \.
*
* FIXME: The concept here is still buggy, but it should do for now.
* Also, it writes to the input string, this may be bad.
*
* @param paths A list of paths.
*/
Ecore_Hash *
ecore_desktop_hash_from_paths(char *paths)
{
Ecore_Hash *result;
result = ecore_hash_new(ecore_str_hash, ecore_str_compare);
if (result)
{
ecore_hash_set_free_key(result, free);
ecore_hash_set_free_value(result, free);
if (paths)
{
char *start, *end, temp;
int finished = 0;
end = paths;
while (!finished)
{
start = end;
do /* FIXME: There is probably a better way to do this. */
{
while ((*end != ';') && (*end != ':') && (*end != ',') && (*end != '\0'))
end++;
}
while ((end != paths) && (*(end - 1) == '\\') && (*end != '\0')); /* Ignore any escaped ;:, */
/* FIXME: We still need to unescape it now. */
temp = *end;
if (*end == '\0')
finished = 1;
else
*end = '\0';
ecore_hash_set(result, strdup(start), strdup(start));
if ((*end) != temp)
*end = temp;
end++;
}
}
}
return result;
}
/** Split a list of paths into an Ecore_Hash.
*
* The list of paths can use any one of ;:, to seperate the paths.
* You can also escape the :;, with \.
*
* FIXME: The concept here is still buggy, but it should do for now.
* Also, it writes to the input string, this may be bad.
*
* @param paths A list of paths.
*/
Ecore_List *
ecore_desktop_list_from_paths(char *paths)
{
Ecore_List *result;
result = ecore_list_new();
if (result)
{
ecore_list_set_free_cb(result, free);
if (paths)
{
char *start, *end, temp;
int finished = 0;
end = paths;
while (!finished)
{
start = end;
do /* FIXME: There is probably a better way to do this. */
{
while ((*end != ';') && (*end != ':') && (*end != ',') && (*end != '\0'))
end++;
}
while ((end != paths) && (*(end - 1) == '\\') && (*end != '\0')); /* Ignore any escaped ;:, */
/* FIXME: We still need to unescape it now. */
temp = *end;
if (*end == '\0')
finished = 1;
else
*end = '\0';
ecore_list_append(result, strdup(start));
if ((*end) != temp)
*end = temp;
end++;
}
}
}
return result;
}

View File

@ -0,0 +1,15 @@
#ifndef _ECORE_DESKTOP_PRIVATE_H
# define _ECORE_DESKTOP_PRIVATE_H
#include <Ecore_File.h>
# ifdef __cplusplus
extern "C"
{
# endif
# ifdef __cplusplus
}
# endif
#endif

View File

@ -0,0 +1,313 @@
#include <sys/types.h>
#include "Ecore_Desktop.h"
#include "ecore_desktop_private.h"
static void ecore_desktop_tree_dump_each_hash_node(void *value, void *user_data);
/* Just a quick and dirty tree implemtation that will likely get replaced by
* something much saner at a later date. I wrote most of this while falling
* asleep. It will probably scare me when I wake up. B-)
*
* Devilhorns said to make it portable, so we can't rely on any external tree
* implementation. So this tree is designed specifically for this task. Then
* we finally found a place for the genmenu code, and Ecore was back on the
* menu. However, speed could be an issue later, so it might be worth it to
* stick with a custom tree implementation, so that we can optimize it for this
* task.
*
* The trees will be tiny.
* They only store strings.
* There is no insertion or deletion, only append.
* Append order must be maintained.
* The trees will only ever be accessed sequentially, from begining to end.
* The tree data will come in two ways, all in one big string, or a bunch of
* seperate strings, one per element. Any particular tree might have both.
*
* No duplicates in the tree,
* This is the nasty part of this tree implementation.
* Insertions involve a linear search for dupes, most of the
* time there won't be any dupes, so the tree is searched in
* it's entirety. These trees will be really small, and only created at
* the begining, so no big drama there.
* The tree may allow duplicates.
*/
Ecore_Desktop_Tree *
ecore_desktop_tree_new(char *buffer)
{
Ecore_Desktop_Tree *tree;
tree = E_NEW(Ecore_Desktop_Tree, 1);
if ((tree) && (buffer))
{
tree->buffers = (char **)realloc(tree->buffers, (tree->buffers_size + 1) * sizeof(char *));
tree->buffers[tree->buffers_size++] = strdup(buffer);
}
return tree;
}
Ecore_Desktop_Tree *
ecore_desktop_tree_add(Ecore_Desktop_Tree * tree, char *element)
{
tree->elements = (Ecore_Desktop_Tree_Element *) realloc(tree->elements, (tree->size + 1) * sizeof(Ecore_Desktop_Tree_Element));
tree->elements[tree->size].element = element;
tree->elements[tree->size++].type = ECORE_DESKTOP_TREE_ELEMENT_TYPE_STRING;
return tree;
}
Ecore_Desktop_Tree *
ecore_desktop_tree_extend(Ecore_Desktop_Tree * tree, char *element)
{
tree->buffers = (char **)realloc(tree->buffers, (tree->buffers_size + 1) * sizeof(char *));
tree->buffers[tree->buffers_size++] = strdup(element);
tree = ecore_desktop_tree_add(tree, tree->buffers[tree->buffers_size - 1]);
return tree;
}
void
ecore_desktop_tree_track(Ecore_Desktop_Tree * tree, void *element)
{
tree->buffers = (char **)realloc(tree->buffers, (tree->buffers_size + 1) * sizeof(char *));
tree->buffers[tree->buffers_size++] = element;
}
/* OK, so we need an insert after all, and it falls into the dumb category. */
Ecore_Desktop_Tree *
ecore_desktop_tree_insert(Ecore_Desktop_Tree * tree, int before, void *element, Ecore_Desktop_Tree_Element_Type type)
{
int i;
tree->elements = (Ecore_Desktop_Tree_Element *) realloc(tree->elements, (tree->size + 1) * sizeof(Ecore_Desktop_Tree_Element));
tree->size++;
for (i = tree->size - 1; i > before; i--)
{
tree->elements[i].element = tree->elements[i - 1].element;
tree->elements[i].type = tree->elements[i - 1].type;
}
tree->elements[before].element = element;
tree->elements[before].type = type;
return tree;
}
/* OK, so we need a tree merge after all, and it falls into the dumb category. */
Ecore_Desktop_Tree *
ecore_desktop_tree_merge(Ecore_Desktop_Tree * tree, int before, Ecore_Desktop_Tree * element)
{
int i, size;
size = element->size;
if (size)
{
tree->elements = (Ecore_Desktop_Tree_Element *) realloc(tree->elements, (tree->size + size) * sizeof(Ecore_Desktop_Tree_Element));
tree->size += size;
for (i = tree->size - 1; i > before; i--)
{
tree->elements[i].element = tree->elements[i - size].element;
tree->elements[i].type = tree->elements[i - size].type;
}
for (i = 0; i < size; i++)
{
tree->elements[before + i].element = element->elements[i].element;
tree->elements[before + i].type = element->elements[i].type;
}
}
/* Careful, this might screw up the freeing order if that is important. */
size = element->buffers_size;
if (size)
{
/*
tree->buffers = (char **) realloc(tree->buffers, (tree->buffers_size + size) * sizeof(char *));
tree->buffers_size += size;
for (i = 0; i < size; i++)
{
tree->buffers[tree->buffers_size + i] = element->buffers[i];
element->buffers[i] = NULL;
}
*/
}
return tree;
}
Ecore_Desktop_Tree *
ecore_desktop_tree_add_child(Ecore_Desktop_Tree * tree, Ecore_Desktop_Tree * element)
{
tree->elements = (Ecore_Desktop_Tree_Element *) realloc(tree->elements, (tree->size + 1) * sizeof(Ecore_Desktop_Tree_Element));
tree->elements[tree->size].element = element;
tree->elements[tree->size++].type = ECORE_DESKTOP_TREE_ELEMENT_TYPE_TREE;
element->parent = tree;
return tree;
}
Ecore_Desktop_Tree *
ecore_desktop_tree_add_hash(Ecore_Desktop_Tree * tree, Ecore_Hash * element)
{
tree->elements = (Ecore_Desktop_Tree_Element *) realloc(tree->elements, (tree->size + 1) * sizeof(Ecore_Desktop_Tree_Element));
tree->elements[tree->size].element = element;
tree->elements[tree->size++].type = ECORE_DESKTOP_TREE_ELEMENT_TYPE_HASH;
return tree;
}
void
ecore_desktop_tree_remove(Ecore_Desktop_Tree * tree, int element)
{
if (tree->size > element)
{
tree->elements[element].type = ECORE_DESKTOP_TREE_ELEMENT_TYPE_NULL;
tree->elements[element].element = NULL;
}
}
int
ecore_desktop_tree_exist(Ecore_Desktop_Tree * tree, char *element)
{
int exist = 0;
int i;
/* This is the dumb part of the tree, a linear search. */
for (i = 0; i < tree->size; i++)
{
if ((tree->elements[i].type == ECORE_DESKTOP_TREE_ELEMENT_TYPE_STRING) && (strcmp((char *)tree->elements[i].element, element) == 0))
{
exist = 1;
break;
}
}
return exist;
}
int
ecore_desktop_tree_foreach(Ecore_Desktop_Tree * tree, int level, int (*func) (const void *data, Ecore_Desktop_Tree * tree, int element, int level),
const void *data)
{
int result = 0;
int i;
for (i = 0; i < tree->size; i++)
{
if (tree->elements[i].type == ECORE_DESKTOP_TREE_ELEMENT_TYPE_TREE)
{
if (ecore_desktop_tree_foreach((Ecore_Desktop_Tree *) tree->elements[i].element, level + 1, func, data))
result = 1;
}
else if (tree->elements[i].type == ECORE_DESKTOP_TREE_ELEMENT_TYPE_NULL)
{
/* This falls into the dumb category. */
int j = i;
int k = i;
int moved = 0;
/* Find the next non NULL element. */
while ((j < tree->size) && (tree->elements[j].type == ECORE_DESKTOP_TREE_ELEMENT_TYPE_NULL))
j++;
/* Move the next batch of non NULL up. */
while ((j < tree->size) && (tree->elements[j].type != ECORE_DESKTOP_TREE_ELEMENT_TYPE_NULL))
{
moved = 1;
tree->elements[k].type = tree->elements[j].type;
tree->elements[k].element = tree->elements[j].element;
tree->elements[j].type = ECORE_DESKTOP_TREE_ELEMENT_TYPE_NULL;
tree->elements[j].element = NULL;
j++;
k++;
}
if (moved)
i--;
else
tree->size = i;
}
else
{
if (func(data, tree, i, level))
result = 1;
}
}
return result;
}
void
ecore_desktop_tree_dump(Ecore_Desktop_Tree * tree, int level)
{
int i;
for (i = 0; i < tree->size; i++)
{
int j;
for (j = 0; j < level; j++)
printf(".");
switch (tree->elements[i].type)
{
case ECORE_DESKTOP_TREE_ELEMENT_TYPE_NULL:
{
printf("NULL\n");
}
break;
case ECORE_DESKTOP_TREE_ELEMENT_TYPE_STRING:
{
printf("%s\n", (char *)tree->elements[i].element);
}
break;
case ECORE_DESKTOP_TREE_ELEMENT_TYPE_TREE:
{
printf("TREE ELEMENT TYPE\n");
ecore_desktop_tree_dump((Ecore_Desktop_Tree *) tree->elements[i].element, level + 1);
}
break;
case ECORE_DESKTOP_TREE_ELEMENT_TYPE_HASH:
{
int lev;
lev = level + 1;
printf("HASH ELEMENT TYPE\n");
ecore_hash_for_each_node((Ecore_Hash *) tree->elements[i].element, ecore_desktop_tree_dump_each_hash_node, &lev);
}
break;
default:
{
printf("UNKNOWN ELEMENT TYPE!\n");
}
break;
}
}
}
static void
ecore_desktop_tree_dump_each_hash_node(void *value, void *user_data)
{
Ecore_Hash_Node *node;
int level;
int j;
node = (Ecore_Hash_Node *) value;
level = *((int *)user_data);
for (j = 0; j < level; j++)
printf(".");
printf("%s = %s\n", (char *)node->key, (char *)node->value);
}
void
ecore_desktop_tree_del(Ecore_Desktop_Tree * tree)
{
int i;
for (i = tree->size - 1; i >= 0; i--)
{
if (tree->elements[i].type == ECORE_DESKTOP_TREE_ELEMENT_TYPE_TREE)
ecore_desktop_tree_del((Ecore_Desktop_Tree *) tree->elements[i].element);
else if (tree->elements[i].type == ECORE_DESKTOP_TREE_ELEMENT_TYPE_HASH)
ecore_hash_destroy((Ecore_Hash *) tree->elements[i].element);
}
E_FREE(tree->elements);
for (i = tree->buffers_size - 1; i >= 0; i--)
E_FREE(tree->buffers[i]);
E_FREE(tree);
}

View File

@ -0,0 +1,131 @@
#include <fcntl.h>
#include <ctype.h>
#include <sys/types.h>
#include <sys/stat.h>
#include "Ecore_Desktop.h"
#include "ecore_desktop_private.h"
/** xmlame.c Extensively Mocked Language Approximately Mangled for Enlightenment.
*
* This is NOT a real XML parser. There were a few ways we could go when it came
* to parsing the freedesktop.org (fdo) XML menu files. Whatever way we went, we
* needed some sort of XML parser if we wanted to fully support fdo menu files.
* Nothing we can do about that, fdo set the standard and they choose XML to do it.
*
* After a discussion with raster, three things led to the decision to do it this
* way. It is likely that this will get included as a core part of the E17 window
* manager (E17) coz E17 needs this functionality. E17 is in a dependency freeze
* and there is no XML parser in it's current dependencies. The fdo XML menu files
* look to be simple enough to parse that this sort of fake, brain dead, XML parser
* may get away with it. Much testing on lots of systems is highly recommended.
*
* The final '>' of a tag is replaced with a '\0', but it's existance can be implied.
*/
static char *_ecore_desktop_xmlame_parse(Ecore_Desktop_Tree * tree, char *buffer);
Ecore_Desktop_Tree *
ecore_desktop_xmlame_new(char *buffer)
{
Ecore_Desktop_Tree *tree;
tree = ecore_desktop_tree_new(buffer);
return tree;
}
Ecore_Desktop_Tree *
ecore_desktop_xmlame_get(char *file)
{
int size;
char *buffer;
Ecore_Desktop_Tree *tree = NULL;
size = ecore_file_size(file);
buffer = (char *)malloc(size + 1);
if (buffer)
{
int fd;
buffer[0] = '\0';
fd = open(file, O_RDONLY);
if (fd != -1)
{
if (read(fd, buffer, size) == size)
buffer[size] = '\0';
}
tree = ecore_desktop_xmlame_new(buffer);
if (tree)
{
/* Have the file name as the first item on the tree, for later reference. */
ecore_desktop_tree_extend(tree, file);
_ecore_desktop_xmlame_parse(tree, buffer);
}
}
return tree;
}
static char *
_ecore_desktop_xmlame_parse(Ecore_Desktop_Tree * tree, char *buffer)
{
do
{
char *text;
/* Skip any white space at the beginning. */
while ((*buffer != '\0') && (isspace(*buffer)))
buffer++;
text = buffer;
/* Find the beginning of a tag. */
while ((*buffer != '<') && (*buffer != '\0'))
buffer++;
/* Check for data between tags. */
if (buffer != text)
{
char t;
t = *buffer;
*buffer = '\0';
ecore_desktop_tree_extend(tree, strdup(text));
*buffer = t;
}
if (*buffer != '\0')
{
char *begin;
begin = buffer++;
/* Find the end of the tag. */
while ((*buffer != '>') && (*buffer != '\0'))
buffer++;
/* We have our tag, do something with it. */
if (*buffer != '\0')
{
*buffer++ = '\0';
if (begin[1] == '/')
{ /* The end of an element. */
ecore_desktop_tree_add(tree, begin);
break;
}
else if ((begin[1] == '!') || (begin[1] == '-') || (*(buffer - 2) == '/'))
{ /* This is a script, a comment, or a stand alone tag. */
ecore_desktop_tree_add(tree, begin);
}
else
{ /* The beginning of an element. */
Ecore_Desktop_Tree *new_tree;
new_tree = ecore_desktop_xmlame_new(NULL);
if (new_tree)
{
ecore_desktop_tree_add_child(tree, new_tree);
ecore_desktop_tree_add(new_tree, begin);
buffer = _ecore_desktop_xmlame_parse(new_tree, buffer);
}
}
}
}
}
while (*buffer != '\0');
return buffer;
}