Look through the XDG directories to look for applications
This commit is contained in:
parent
f83a394f43
commit
e956dfcdce
320
src/desktop.c
320
src/desktop.c
@ -15,7 +15,8 @@
|
|||||||
/* TODO:
|
/* TODO:
|
||||||
* - let the user define the desktop folder (possibly default to FDO's)
|
* - let the user define the desktop folder (possibly default to FDO's)
|
||||||
* - set the font for the icons instantly
|
* - set the font for the icons instantly
|
||||||
* - track multiple selection on delete/properties */
|
* - track multiple selection on delete/properties
|
||||||
|
* - avoid code duplication with DeforaOS Panel ("main" applet) */
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -1114,6 +1115,9 @@ void desktop_refresh(Desktop * desktop)
|
|||||||
|
|
||||||
static void _refresh_applications(Desktop * desktop)
|
static void _refresh_applications(Desktop * desktop)
|
||||||
{
|
{
|
||||||
|
g_slist_foreach(desktop->apps, (GFunc)config_delete, NULL);
|
||||||
|
g_slist_free(desktop->apps);
|
||||||
|
desktop->apps = NULL;
|
||||||
desktop->refresh_source = g_idle_add(_desktop_on_refresh, desktop);
|
desktop->refresh_source = g_idle_add(_desktop_on_refresh, desktop);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1144,7 +1148,8 @@ static void _refresh_files(Desktop * desktop)
|
|||||||
|
|
||||||
static void _refresh_none(Desktop * desktop)
|
static void _refresh_none(Desktop * desktop)
|
||||||
{
|
{
|
||||||
desktop->refresh_source = 0;
|
/* for cleanup */
|
||||||
|
desktop->refresh_source = g_idle_add(_desktop_on_refresh, desktop);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -2326,17 +2331,26 @@ static void _preferences_set_color(Config * config, char const * section,
|
|||||||
/* callbacks */
|
/* callbacks */
|
||||||
/* desktop_on_refresh */
|
/* desktop_on_refresh */
|
||||||
static void _refresh_cleanup(Desktop * desktop);
|
static void _refresh_cleanup(Desktop * desktop);
|
||||||
|
static void _refresh_done_applications(Desktop * desktop);
|
||||||
static void _refresh_done_categories(Desktop * desktop);
|
static void _refresh_done_categories(Desktop * desktop);
|
||||||
static void _refresh_done_categories_open(Desktop * desktop, gpointer data);
|
static void _refresh_done_categories_open(Desktop * desktop, gpointer data);
|
||||||
static gboolean _refresh_done_timeout(gpointer data);
|
static gboolean _refresh_done_timeout(gpointer data);
|
||||||
static int _refresh_loop(Desktop * desktop);
|
static int _refresh_loop(Desktop * desktop);
|
||||||
static int _refresh_loop_applications(Desktop * desktop);
|
static int _refresh_loop_applications(Desktop * desktop);
|
||||||
static int _refresh_loop_applications_path(Desktop * desktop,
|
|
||||||
char const * path);
|
|
||||||
static int _refresh_loop_applications_do(Desktop * desktop);
|
|
||||||
static gint _categories_apps_compare(gconstpointer a, gconstpointer b);
|
static gint _categories_apps_compare(gconstpointer a, gconstpointer b);
|
||||||
static int _refresh_loop_categories(Desktop * desktop);
|
static int _refresh_loop_categories(Desktop * desktop);
|
||||||
static int _refresh_loop_categories_do(Desktop * desktop);
|
static int _refresh_loop_categories_dirs(Desktop * desktop);
|
||||||
|
static void _refresh_loop_categories_dirs_path(Desktop * desktop,
|
||||||
|
char const * path, char const * apppath);
|
||||||
|
static void _refresh_loop_categories_dirs_xdg(Desktop * desktop,
|
||||||
|
void (*callback)(Desktop * desktop, char const * path,
|
||||||
|
char const * apppath));
|
||||||
|
static void _refresh_loop_categories_dirs_xdg_home(Desktop * desktop,
|
||||||
|
void (*callback)(Desktop * desktop, char const * path,
|
||||||
|
char const * apppath));
|
||||||
|
static void _refresh_loop_categories_dirs_xdg_path(Desktop * desktop,
|
||||||
|
void (*callback)(Desktop * desktop, char const * path,
|
||||||
|
char const * apppath), char const * path);
|
||||||
static int _refresh_loop_files(Desktop * desktop);
|
static int _refresh_loop_files(Desktop * desktop);
|
||||||
static int _refresh_loop_lookup(Desktop * desktop, char const * name);
|
static int _refresh_loop_lookup(Desktop * desktop, char const * name);
|
||||||
static gboolean _refresh_done(Desktop * desktop);
|
static gboolean _refresh_done(Desktop * desktop);
|
||||||
@ -2369,6 +2383,9 @@ static gboolean _refresh_done(Desktop * desktop)
|
|||||||
{
|
{
|
||||||
switch(desktop->prefs.icons)
|
switch(desktop->prefs.icons)
|
||||||
{
|
{
|
||||||
|
case DESKTOP_ICONS_APPLICATIONS:
|
||||||
|
_refresh_done_applications(desktop);
|
||||||
|
break;
|
||||||
case DESKTOP_ICONS_CATEGORIES:
|
case DESKTOP_ICONS_CATEGORIES:
|
||||||
_refresh_done_categories(desktop);
|
_refresh_done_categories(desktop);
|
||||||
break;
|
break;
|
||||||
@ -2385,6 +2402,39 @@ static gboolean _refresh_done(Desktop * desktop)
|
|||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void _refresh_done_applications(Desktop * desktop)
|
||||||
|
{
|
||||||
|
GSList * p;
|
||||||
|
Config * config;
|
||||||
|
const char section[] = "Desktop Entry";
|
||||||
|
char const * q;
|
||||||
|
char const * r;
|
||||||
|
DesktopCategory * dc = desktop->category;
|
||||||
|
char const * path;
|
||||||
|
DesktopIcon * icon;
|
||||||
|
|
||||||
|
for(p = desktop->apps; p != NULL; p = p->next)
|
||||||
|
{
|
||||||
|
config = p->data;
|
||||||
|
path = config_get(config, NULL, "path");
|
||||||
|
if(dc != NULL)
|
||||||
|
{
|
||||||
|
if((q = config_get(config, section, "Categories"))
|
||||||
|
== NULL)
|
||||||
|
continue;
|
||||||
|
if((r = string_find(q, dc->category)) == NULL)
|
||||||
|
continue;
|
||||||
|
r += string_length(dc->category);
|
||||||
|
if(*r != '\0' && *r != ';')
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if((icon = desktopicon_new_application(desktop, path, NULL))
|
||||||
|
== NULL)
|
||||||
|
continue;
|
||||||
|
_desktop_icon_add(desktop, icon);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void _refresh_done_categories(Desktop * desktop)
|
static void _refresh_done_categories(Desktop * desktop)
|
||||||
{
|
{
|
||||||
GSList * p;
|
GSList * p;
|
||||||
@ -2475,135 +2525,62 @@ static int _refresh_loop(Desktop * desktop)
|
|||||||
return _refresh_loop_files(desktop);
|
return _refresh_loop_files(desktop);
|
||||||
case DESKTOP_ICONS_HOMESCREEN:
|
case DESKTOP_ICONS_HOMESCREEN:
|
||||||
case DESKTOP_ICONS_NONE:
|
case DESKTOP_ICONS_NONE:
|
||||||
break; /* nothing to do */
|
return 0; /* nothing to do */
|
||||||
}
|
}
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int _refresh_loop_applications(Desktop * desktop)
|
static int _refresh_loop_applications(Desktop * desktop)
|
||||||
{
|
{
|
||||||
int ret;
|
/* XXX */
|
||||||
char const * path;
|
return _refresh_loop_categories(desktop);
|
||||||
size_t len;
|
|
||||||
|
|
||||||
if(desktop->path == NULL)
|
|
||||||
return _refresh_loop_applications_path(desktop, DATADIR);
|
|
||||||
if((ret = _refresh_loop_applications_do(desktop)) == 0)
|
|
||||||
return 0;
|
|
||||||
/* XXX hack to also look at XDG_DATA_HOME */
|
|
||||||
if((path = getenv("XDG_DATA_HOME")) != NULL && (len = strlen(path)) > 0
|
|
||||||
&& strncmp(desktop->path, path, len) != 0)
|
|
||||||
return _refresh_loop_applications_path(desktop, path);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int _refresh_loop_applications_path(Desktop * desktop,
|
|
||||||
char const * path)
|
|
||||||
{
|
|
||||||
const char applications[] = "/applications";
|
|
||||||
char * p;
|
|
||||||
size_t len;
|
|
||||||
DIR * dir;
|
|
||||||
struct stat st;
|
|
||||||
|
|
||||||
len = strlen(path) + sizeof(applications);
|
|
||||||
if((p = malloc(len)) == NULL)
|
|
||||||
return -desktop_error(NULL, path, 1);
|
|
||||||
snprintf(p, len, "%s%s", path, applications);
|
|
||||||
if((dir = browser_vfs_opendir(p, &st)) == NULL)
|
|
||||||
{
|
|
||||||
free(p);
|
|
||||||
return -desktop_error(NULL, p, 1);
|
|
||||||
}
|
|
||||||
desktop->path = p;
|
|
||||||
desktop->path_cnt = len;
|
|
||||||
desktop->refresh_dir = dir;
|
|
||||||
desktop->refresh_mti = st.st_mtime;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int _refresh_loop_applications_do(Desktop * desktop)
|
|
||||||
{
|
|
||||||
struct dirent * de;
|
|
||||||
size_t len;
|
|
||||||
const char ext[] = ".desktop";
|
|
||||||
const char section[] = "Desktop Entry";
|
|
||||||
char * path = NULL;
|
|
||||||
char * p;
|
|
||||||
Config * config;
|
|
||||||
char const * q;
|
|
||||||
DesktopIcon * icon;
|
|
||||||
|
|
||||||
if(desktop->category == NULL)
|
|
||||||
return -1;
|
|
||||||
if((config = config_new()) == NULL)
|
|
||||||
return -_desktop_serror(desktop, NULL, 1);
|
|
||||||
while((de = browser_vfs_readdir(desktop->refresh_dir)) != NULL)
|
|
||||||
{
|
|
||||||
if(de->d_name[0] == '.')
|
|
||||||
if(de->d_name[1] == '\0' || (de->d_name[1] == '.'
|
|
||||||
&& de->d_name[2] == '\0'))
|
|
||||||
continue;
|
|
||||||
len = strlen(de->d_name);
|
|
||||||
if(len < sizeof(ext))
|
|
||||||
continue;
|
|
||||||
if(strncmp(&de->d_name[len - sizeof(ext) + 1], ext,
|
|
||||||
sizeof(ext)) != 0)
|
|
||||||
continue;
|
|
||||||
len = desktop->path_cnt + len + 1;
|
|
||||||
if((p = realloc(path, len)) == NULL)
|
|
||||||
{
|
|
||||||
error_set_print(PROGNAME, 1, "%s: %s", "realloc",
|
|
||||||
strerror(errno));
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
path = p;
|
|
||||||
snprintf(path, len, "%s/%s", desktop->path, de->d_name);
|
|
||||||
#ifdef DEBUG
|
|
||||||
fprintf(stderr, "DEBUG: %s() \"%s\"\n", __func__, path);
|
|
||||||
#endif
|
|
||||||
config_reset(config);
|
|
||||||
if(config_load(config, path) != 0)
|
|
||||||
continue;
|
|
||||||
if((q = config_get(config, section, "Categories")) == NULL)
|
|
||||||
continue;
|
|
||||||
if(string_find(q, desktop->category->category) == NULL)
|
|
||||||
continue;
|
|
||||||
/* FIXME forward the corresponding datadir */
|
|
||||||
if((icon = desktopicon_new_application(desktop, path, NULL))
|
|
||||||
== NULL)
|
|
||||||
continue;
|
|
||||||
_desktop_icon_add(desktop, icon);
|
|
||||||
free(path);
|
|
||||||
config_delete(config);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
free(path);
|
|
||||||
config_delete(config);
|
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int _refresh_loop_categories(Desktop * desktop)
|
static int _refresh_loop_categories(Desktop * desktop)
|
||||||
{
|
{
|
||||||
if(desktop->path == NULL)
|
return _refresh_loop_categories_dirs(desktop);
|
||||||
/* XXX hack */
|
|
||||||
return _refresh_loop_applications_path(desktop, DATADIR);
|
|
||||||
return _refresh_loop_categories_do(desktop);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int _refresh_loop_categories_do(Desktop * desktop)
|
static int _refresh_loop_categories_dirs(Desktop * desktop)
|
||||||
{
|
{
|
||||||
|
_refresh_loop_categories_dirs_xdg(desktop,
|
||||||
|
_refresh_loop_categories_dirs_path);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _refresh_loop_categories_dirs_path(Desktop * desktop,
|
||||||
|
char const * path, char const * apppath)
|
||||||
|
{
|
||||||
|
DIR * dir;
|
||||||
|
int fd;
|
||||||
|
struct stat st;
|
||||||
struct dirent * de;
|
struct dirent * de;
|
||||||
size_t len;
|
size_t len;
|
||||||
const char ext[] = ".desktop";
|
const char ext[] = ".desktop";
|
||||||
const char section[] = "Desktop Entry";
|
const char section[] = "Desktop Entry";
|
||||||
char * path = NULL;
|
char * name = NULL;
|
||||||
char * p;
|
char * p;
|
||||||
Config * config = NULL;
|
Config * config = NULL;
|
||||||
char const * q;
|
String const * q;
|
||||||
char const * r;
|
String const * r;
|
||||||
|
|
||||||
while((de = browser_vfs_readdir(desktop->refresh_dir)) != NULL)
|
#if defined(__sun__)
|
||||||
|
if((fd = open(apppath, O_RDONLY)) < 0
|
||||||
|
|| fstat(fd, &st) != 0
|
||||||
|
|| (dir = fdopendir(fd)) == NULL)
|
||||||
|
#else
|
||||||
|
if((dir = opendir(apppath)) == NULL
|
||||||
|
|| (fd = dirfd(dir)) < 0
|
||||||
|
|| fstat(fd, &st) != 0)
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
if(errno != ENOENT)
|
||||||
|
desktop_error(NULL, apppath, 1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(st.st_mtime > desktop->refresh_mti)
|
||||||
|
desktop->refresh_mti = st.st_mtime;
|
||||||
|
while((de = readdir(dir)) != NULL)
|
||||||
{
|
{
|
||||||
if(de->d_name[0] == '.')
|
if(de->d_name[0] == '.')
|
||||||
if(de->d_name[1] == '\0' || (de->d_name[1] == '.'
|
if(de->d_name[1] == '\0' || (de->d_name[1] == '.'
|
||||||
@ -2615,40 +2592,119 @@ static int _refresh_loop_categories_do(Desktop * desktop)
|
|||||||
if(strncmp(&de->d_name[len - sizeof(ext) + 1], ext,
|
if(strncmp(&de->d_name[len - sizeof(ext) + 1], ext,
|
||||||
sizeof(ext)) != 0)
|
sizeof(ext)) != 0)
|
||||||
continue;
|
continue;
|
||||||
len = desktop->path_cnt + len + 1;
|
if((p = realloc(name, strlen(apppath) + len + 2)) == NULL)
|
||||||
if((p = realloc(path, len)) == NULL)
|
|
||||||
{
|
{
|
||||||
error_set_print(PROGNAME, 1, "%s: %s", "realloc",
|
desktop_error(NULL, apppath, 1);
|
||||||
strerror(errno));
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
path = p;
|
name = p;
|
||||||
snprintf(path, len, "%s/%s", desktop->path, de->d_name);
|
snprintf(name, strlen(apppath) + len + 2, "%s/%s", apppath,
|
||||||
|
de->d_name);
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
fprintf(stderr, "DEBUG: %s() \"%s\"\n", __func__, path);
|
fprintf(stderr, "DEBUG: %s() name=\"%s\" path=\"%s\"\n",
|
||||||
|
__func__, name, path);
|
||||||
#endif
|
#endif
|
||||||
if(config == NULL && (config = config_new()) == NULL)
|
if(config == NULL)
|
||||||
continue; /* XXX report error */
|
config = config_new();
|
||||||
|
else
|
||||||
config_reset(config);
|
config_reset(config);
|
||||||
if(config_load(config, path) != 0)
|
if(config == NULL || config_load(config, name) != 0)
|
||||||
{
|
{
|
||||||
error_set_print(PROGNAME, 1, "%s: %s", path,
|
desktop_error(NULL, NULL, 1); /* XXX */
|
||||||
error_get());
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
q = config_get(config, section, "Name");
|
q = config_get(config, section, "Name");
|
||||||
r = config_get(config, section, "Exec");
|
r = config_get(config, section, "Exec");
|
||||||
if(q == NULL || r == NULL)
|
if(q == NULL || r == NULL)
|
||||||
continue;
|
continue;
|
||||||
config_set(config, NULL, "path", path);
|
/* remember the path */
|
||||||
|
config_set(config, NULL, "path", name);
|
||||||
desktop->apps = g_slist_insert_sorted(desktop->apps, config,
|
desktop->apps = g_slist_insert_sorted(desktop->apps, config,
|
||||||
_categories_apps_compare);
|
_categories_apps_compare);
|
||||||
free(path);
|
|
||||||
config = NULL;
|
config = NULL;
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
free(path);
|
free(name);
|
||||||
return -1;
|
closedir(dir);
|
||||||
|
if(config != NULL)
|
||||||
|
config_delete(config);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _refresh_loop_categories_dirs_xdg(Desktop * desktop,
|
||||||
|
void (*callback)(Desktop * desktop, char const * path,
|
||||||
|
char const * apppath))
|
||||||
|
{
|
||||||
|
char const * path;
|
||||||
|
char * p;
|
||||||
|
size_t i;
|
||||||
|
size_t j;
|
||||||
|
|
||||||
|
if((path = getenv("XDG_DATA_DIRS")) == NULL || strlen(path) == 0)
|
||||||
|
/* FIXME use DATADIR */
|
||||||
|
path = "/usr/local/share:/usr/share";
|
||||||
|
if((p = strdup(path)) == NULL)
|
||||||
|
{
|
||||||
|
desktop_error(NULL, "strdup", 1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for(i = 0, j = 0;; i++)
|
||||||
|
if(p[i] == '\0')
|
||||||
|
{
|
||||||
|
_refresh_loop_categories_dirs_xdg_path(desktop,
|
||||||
|
callback, &p[j]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else if(p[i] == ':')
|
||||||
|
{
|
||||||
|
p[i] = '\0';
|
||||||
|
_refresh_loop_categories_dirs_xdg_path(desktop,
|
||||||
|
callback, &p[j]);
|
||||||
|
j = i + 1;
|
||||||
|
}
|
||||||
|
free(p);
|
||||||
|
_refresh_loop_categories_dirs_xdg_home(desktop, callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _refresh_loop_categories_dirs_xdg_home(Desktop * desktop,
|
||||||
|
void (*callback)(Desktop * desktop, char const * path,
|
||||||
|
char const * apppath))
|
||||||
|
{
|
||||||
|
char const fallback[] = ".local/share";
|
||||||
|
char const * path;
|
||||||
|
char const * homedir;
|
||||||
|
size_t len;
|
||||||
|
char * p;
|
||||||
|
|
||||||
|
/* use $XDG_DATA_HOME if set and not empty */
|
||||||
|
if((path = getenv("XDG_DATA_HOME")) != NULL && strlen(path) > 0)
|
||||||
|
{
|
||||||
|
_refresh_loop_categories_dirs_xdg_path(desktop, callback, path);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
/* fallback to "$HOME/.local/share" */
|
||||||
|
if((homedir = getenv("HOME")) == NULL)
|
||||||
|
homedir = g_get_home_dir();
|
||||||
|
len = strlen(homedir) + 1 + sizeof(fallback);
|
||||||
|
if((p = malloc(len)) == NULL)
|
||||||
|
{
|
||||||
|
desktop_error(NULL, homedir, 1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
snprintf(p, len, "%s/%s", homedir, fallback);
|
||||||
|
_refresh_loop_categories_dirs_xdg_path(desktop, callback, p);
|
||||||
|
free(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _refresh_loop_categories_dirs_xdg_path(Desktop * desktop,
|
||||||
|
void (*callback)(Desktop * desktop, char const * path,
|
||||||
|
char const * apppath), char const * path)
|
||||||
|
{
|
||||||
|
const char applications[] = "/applications";
|
||||||
|
char * apppath;
|
||||||
|
|
||||||
|
if((apppath = string_new_append(path, applications, NULL)) == NULL)
|
||||||
|
desktop_error(NULL, path, 1);
|
||||||
|
callback(desktop, path, apppath);
|
||||||
|
string_delete(apppath);
|
||||||
}
|
}
|
||||||
|
|
||||||
static gint _categories_apps_compare(gconstpointer a, gconstpointer b)
|
static gint _categories_apps_compare(gconstpointer a, gconstpointer b)
|
||||||
|
Loading…
Reference in New Issue
Block a user