Fixes to .desktop parsing.
Add language/locale support for .desktop files.
Fixes to inotify watching, change what information is passed through the notify handler.
Add linkbase.h to the public obt headers.
obtpubinclude_HEADERS = \
obt/link.h \
+ obt/linkbase.h \
obt/display.h \
obt/keyboard.h \
obt/xml.h \
Return TRUE if it is added to the hash table, and FALSE if not.
*/
typedef gboolean (*ObtDDParseValueFunc)(gchar *key, const gchar *val,
+ ObtDDParseLangMatch match,
ObtDDParse *parse, gboolean *error);
struct _ObtDDParse {
const gchar *filename;
+ const gchar *language;
+ const gchar *country;
+ const gchar *modifier;
gulong lineno;
gulong flags;
ObtDDParseGroup *group;
}
else if (*i == '\\')
backslash = TRUE;
- else if ((guchar)*i >= 127 || (guchar)*i < 32) {
+ else if ((!locale && (guchar)*i >= 127) || (guchar)*i < 32) {
/* avoid ascii control characters */
parse_error("Found control character in string", parse, error);
break;
}
else {
/* read more */
- size += BUFMUL;
+ *size += BUFMUL;
*buf = g_renew(char, *buf, *size);
}
}
g->seen = TRUE;
parse->group = g;
- g_print("Found group %s\n", g->name);
+ /* g_print("Found group %s\n", g->name); */
}
}
ObtDDParse *parse, gboolean *error)
{
gulong i, keyend, valstart, eq;
+ gulong langstart, langend, countrystart, countryend, modstart, modend;
char *key;
+ ObtDDParseValue *val;
+ ObtDDParseLangMatch match;
/* find the end of the key */
for (i = 0; i < len; ++i)
parse_error("Empty key", parse, error);
return;
}
+
+ /* is there a language specifier? */
+ langstart = langend = countrystart = countryend = modstart = modend = 0;
+ if ((guchar)buf[i] == '[') {
+ langstart = i+1;
+ for (i = langstart; i < len; ++i)
+ if ((guchar)buf[i] == '.' || (guchar)buf[i] == '_' ||
+ (guchar)buf[i] == '@' || (guchar)buf[i] == ']')
+ {
+ langend = i-1;
+ break;
+ }
+ else if (!(((guchar)buf[i] >= 'A' && (guchar)buf[i] <= 'Z') ||
+ ((guchar)buf[i] >= 'a' && (guchar)buf[i] <= 'z'))) {
+ parse_error("Invalid character in language", parse, error);
+ return;
+ }
+ if ((guchar)buf[i] == '_') {
+ countrystart = i+1;
+ for (i = i+1; i < len; ++i)
+ if ((guchar)buf[i] == '.' ||
+ (guchar)buf[i] == '@' || (guchar)buf[i] == ']')
+ {
+ langend = i-1;
+ break;
+ }
+ else if (!(((guchar)buf[i] >= 'A' && (guchar)buf[i] <= 'Z') ||
+ ((guchar)buf[i] >= 'a' && (guchar)buf[i] <= 'z'))) {
+ parse_error("Invalid character in country", parse, error);
+ return;
+ }
+ }
+ if ((guchar)buf[i] == '.') {
+ for (i = i+1; i < len; ++i)
+ if ((guchar)buf[i] == '@' || (guchar)buf[i] == ']')
+ break;
+ else if (!(((guchar)buf[i] >= 'A' && (guchar)buf[i] <= 'Z') ||
+ ((guchar)buf[i] >= 'a' && (guchar)buf[i] <= 'z'))) {
+ parse_error("Invalid character in encoding", parse, error);
+ return;
+ }
+ }
+ if ((guchar)buf[i] == '@') {
+ modstart = i+1;
+ for (i = i+1; i < len; ++i)
+ if ((guchar)buf[i] == ']') {
+ modend = i-1;
+ break;
+ }
+ else if (!(((guchar)buf[i] >= 'A' && (guchar)buf[i] <= 'Z') ||
+ ((guchar)buf[i] >= 'a' && (guchar)buf[i] <= 'z'))) {
+ parse_error("Invalid character in locale modifier",
+ parse, error);
+ return;
+ }
+ }
+ ++i;
+ }
+
/* find the = character */
- for (i = keyend; i < len; ++i) {
+ for (; i < len; ++i) {
if (buf[i] == '=') {
eq = i;
break;
}
else if (buf[i] != ' ') {
parse_error("Invalid character in key name", parse, error);
- return ;
+ return;
}
}
if (i == len) {
return;
}
+ if (langend < langstart)
+ match = OBT_DDPARSE_MATCH_FAIL;
+ else
+ match = OBT_DDPARSE_MATCH_NONE;
+ if (parse->language && langend >= langstart &&
+ strncmp(parse->language, buf+langstart, langend-langstart+1) == 0)
+ {
+ match = OBT_DDPARSE_MATCH_LANG;
+ if (parse->country && countryend >= countrystart &&
+ strncmp(parse->country, buf+countrystart,
+ countryend-countrystart+1) == 0)
+ match = OBT_DDPARSE_MATCH_LANG_COUNTRY;
+
+ if (parse->modifier && modend >= modstart &&
+ strncmp(parse->modifier, buf+modstart,
+ modend-modstart+1) == 0)
+ match += 1; /* its one up for LANG and for LANG_COUNTY */
+ }
+
key = g_strndup(buf, keyend);
- if (g_hash_table_lookup(parse->group->key_hash, key)) {
- parse_error("Duplicate key found", parse, error);
- g_free(key);
- return;
+ if ((val = g_hash_table_lookup(parse->group->key_hash, key))) {
+ if (val->language_match >= match) {
+ /* found a better match already */
+ g_free(key);
+ return;
+ }
}
- g_print("Found key/value %s=%s.\n", key, buf+valstart);
+ /* g_print("Found key/value %s=%s\n", key, buf+valstart); */
if (parse->group->value_func)
- if (!parse->group->value_func(key, buf+valstart, parse, error)) {
- parse_error("Unknown key", parse, error);
+ if (!parse->group->value_func(key, buf+valstart, match, parse, error))
+ {
+ /*parse_error("Unknown key", parse, error);*/
g_free(key);
}
}
}
static gboolean parse_desktop_entry_value(gchar *key, const gchar *val,
+ ObtDDParseLangMatch match,
ObtDDParse *parse, gboolean *error)
{
ObtDDParseValue v, *pv;
+ v.language_match = match;
+
switch (key[0]) {
case 'C':
switch (key[1]) {
return FALSE;
}
+ if (v.language_match && !(v.type == OBT_DDPARSE_LOCALESTRING ||
+ v.type == OBT_DDPARSE_LOCALESTRINGS))
+ {
+ parse_error("Invalid localization on key", parse, error);
+ return FALSE;
+ }
+
/* parse the value */
switch (v.type) {
case OBT_DDPARSE_EXEC: {
return TRUE;
}
-GHashTable* obt_ddparse_file(const gchar *filename)
+GHashTable* obt_ddparse_file(const gchar *filename,
+ const gchar *language,
+ const gchar *country,
+ const gchar *modifier)
{
ObtDDParse parse;
ObtDDParseGroup *desktop_entry;
}
parse.filename = filename;
+ parse.language = language;
+ parse.country = country;
+ parse.modifier = modifier;
parse.lineno = 0;
parse.group = NULL;
parse.group_hash = g_hash_table_new_full(g_str_hash,
{
gint len;
const gchar *in;
- gchar *out;
+ gchar *out, *out_start;
gboolean sep;
if (!g_utf8_validate(filename, -1, NULL)) {
len = strlen(filename) - 8; /* 8 = strlen(".desktop") */
g_assert(strcmp(filename+len, ".desktop") == 0);
- out = g_new(char, len+1);
+ out_start = out = g_new(char, len+1);
sep = TRUE;
- for (in = filename; *in; ++in) {
+ for (in = filename; in < filename + len; ) {
gchar *next;
if (*in == '/') {
++out;
}
sep = TRUE;
+ ++in;
}
else {
/* everything else is copied as is */
++out;
++in;
}
+ sep = FALSE;
}
}
- return out;
+ *out = '\0';
+ return out_start;
}
OBT_DDPARSE_NUM_VALUE_TYPES
} ObtDDParseValueType;
+typedef enum {
+ OBT_DDPARSE_MATCH_NONE = 0,
+ OBT_DDPARSE_MATCH_FAIL,
+ OBT_DDPARSE_MATCH_LANG,
+ OBT_DDPARSE_MATCH_LANG_MODIFIER,
+ OBT_DDPARSE_MATCH_LANG_COUNTRY,
+ OBT_DDPARSE_MATCH_LANG_COUNTRY_MODIFIER
+} ObtDDParseLangMatch;
+
typedef struct _ObtDDParseValue {
ObtDDParseValueType type;
union _ObtDDParseValueValue {
guint enumerable;
guint environments; /*!< A mask of flags from ObtLinkEnvMask */
} value;
+ ObtDDParseLangMatch language_match;
} ObtDDParseValue;
/*! Parse a .desktop file.
@param filename The full path to the .desktop file to be read.
@return Returns a hash table where the keys are groups, and the values are
ObtDDParseGroups */
-GHashTable* obt_ddparse_file(const gchar *filename);
+GHashTable* obt_ddparse_file(const gchar *filename,
+ const gchar *language,
+ const gchar *country,
+ const gchar *modifier);
/*! Get the keys in a group from a .desktop file.
The group comes from the hash table returned by obt_ddparse_file.
struct _ObtLink {
guint ref;
+ gchar *path; /*!< The path to the file where the link came from */
+
ObtLinkType type;
gchar *name; /*!< Specific name for the object (eg Firefox) */
gboolean display; /*<! When false, do not display this link in menus or
} d;
};
-ObtLink* obt_link_from_ddfile(const gchar *basepath, const gchar *filename,
- ObtPaths *p)
+ObtLink* obt_link_from_ddfile(const gchar *path, ObtPaths *p,
+ const gchar *language,
+ const gchar *country,
+ const gchar *modifier)
{
ObtLink *link;
GHashTable *groups, *keys;
ObtDDParseGroup *g;
ObtDDParseValue *v;
- gchar *path;
/* parse the file, and get a hash table of the groups */
- path = g_strconcat(basepath, filename, NULL);
- groups = obt_ddparse_file(path);
- g_free(path);
+ groups = obt_ddparse_file(path, language, country, modifier);
if (!groups) return NULL; /* parsing failed */
/* grab the Desktop Entry group */
/* build the ObtLink (we steal all strings from the parser) */
link = g_slice_new0(ObtLink);
link->ref = 1;
+ link->path = g_strdup(path);
link->display = TRUE;
v = g_hash_table_lookup(keys, "Type");
*n = e->d.app.n_categories;
return e->d.app.categories;
}
+
+const gchar *obt_link_source_file(ObtLink *e)
+{
+ return e->path;
+}
+
+gchar* obt_link_id_from_ddfile(const gchar *filename)
+{
+ return obt_ddparse_file_to_id(filename);
+}
typedef struct _ObtLink ObtLink;
/*! Parse a .desktop (dd) file.
- @param basepath The base directory in which to read the file.
- @param filename The full path to the .desktop file _relative to_ basepath.
- It must be in basepath or a subdirectory of it.
+ @param path The full path to the .desktop file.
@param o An ObtPaths structure, which contains the executable paths.
*/
-ObtLink* obt_link_from_ddfile(const gchar *basepath, const gchar *filename,
- struct _ObtPaths *p);
+ObtLink* obt_link_from_ddfile(const gchar *path,
+ struct _ObtPaths *p,
+ const gchar *language,
+ const gchar *country,
+ const gchar *modifier);
+
+/*! Determine the identifier for a .desktop (dd) file.
+ @param filename The full path to the .desktop file _relative to_ some
+ basepath. For instance, if the desktop file is
+ /usr/share/applications/foo/bar.desktop, and the basepath is
+ /usr/share/applications, then the filename would be 'foo/bar.desktop'.
+ The filename must end with ".desktop" and be encoded in utf8.
+*/
+gchar* obt_link_id_from_ddfile(const gchar *filename);
void obt_link_ref(ObtLink *e);
void obt_link_unref(ObtLink *e);
+const gchar *obt_link_source_file(ObtLink *e);
+
/*! Returns TRUE if the file exists but says it should be ignored, with
the Hidden flag. No other functions can be used for the ObtLink
in this case. */
#include "obt/paths.h"
#include "obt/watch.h"
+#ifdef HAVE_STRING_H
+# include <string.h>
+#endif
+
+typedef struct _ObtLinkBaseEntry ObtLinkBaseEntry;
+
+struct _ObtLinkBaseEntry {
+ /*! Links come from a set of paths. Links found in earlier paths get lower
+ priority values (higher precedence). This is the index in that set of
+ paths of the base directory under which the link was found. */
+ gint priority;
+ ObtLink *link;
+};
+
struct _ObtLinkBase {
gint ref;
+ const gchar *language;
+ const gchar *country;
+ const gchar *modifier;
+
+ ObtPaths *paths;
ObtWatch *watch;
+ /*! This holds a GSList of ObtLinkBaseEntrys sorted by priority in
+ increasing order (by precedence in decreasing order). */
GHashTable *base;
+ /*! This holds the paths in which we look for links, and the data is an
+ integer that is the priority of that directory. */
+ GHashTable *path_to_priority;
};
-static void func(ObtWatch *w, const gchar *subpath, ObtWatchNotifyType type,
- gpointer data)
+static void base_entry_free(ObtLinkBaseEntry *e)
+{
+ obt_link_unref(e->link);
+ g_slice_free(ObtLinkBaseEntry, e);
+}
+
+static void base_entry_list_free(GSList *list)
+{
+ GSList *it;
+ for (it = list; it; it = g_slist_next(it))
+ base_entry_free(it->data);
+ g_slist_free(list);
+}
+
+static GSList* find_base_entry_path(GSList *list, const gchar *full_path)
{
+ GSList *it;
+ for (it = list; it; it = g_slist_next(it)) {
+ ObtLinkBaseEntry *e = it->data;
+ if (strcmp(obt_link_source_file(e->link), full_path) == 0)
+ break;
+ }
+ return it;
}
-ObtLinkBase* obt_linkbase_new(ObtPaths *paths)
+/*! Finds the first entry in the list with a priority number >= @priority. */
+static GSList* find_base_entry_priority(GSList *list, gint priority)
{
- ObtLinkBase *b;
GSList *it;
+ for (it = list; it; it = g_slist_next(it)) {
+ ObtLinkBaseEntry *e = it->data;
+ if (e->priority >= priority)
+ break;
+ }
+ return it;
+}
+
+static void update(ObtWatch *w, const gchar *base_path,
+ const gchar *sub_path,
+ const gchar *full_path,
+ ObtWatchNotifyType type,
+ gpointer data)
+{
+ ObtLinkBase *self = data;
+ gchar *id;
+ GSList *list, *it;
+ gint *priority;
+ gboolean add = FALSE;
+
+ if (!g_str_has_suffix(sub_path, ".desktop"))
+ return; /* ignore non-.desktop files */
+
+ id = obt_link_id_from_ddfile(sub_path);
+ list = g_hash_table_lookup(self->base, id);
+
+ switch (type) {
+ case OBT_WATCH_SELF_REMOVED:
+ break;
+ case OBT_WATCH_REMOVED:
+ it = find_base_entry_path(list, full_path);
+ list = g_slist_delete_link(list, it);
+ base_entry_free(it->data);
+
+ /* this will free 'id' */
+ g_hash_table_insert(self->base, id, list);
+ id = NULL;
+ break;
+ case OBT_WATCH_MODIFIED:
+ it = find_base_entry_path(list, full_path);
+ list = g_slist_delete_link(list, it);
+ base_entry_free(it->data);
+ add = TRUE; /* this will put the modified list into the hash table */
+ break;
+ case OBT_WATCH_ADDED:
+ priority = g_hash_table_lookup(self->path_to_priority, base_path);
+ add = TRUE;
+
+ /* find the first position in the list with a higher priority value */
+ if ((it = find_base_entry_priority(list, *priority))) {
+ const ObtLinkBaseEntry *e = it->data;
+ if (e->priority == *priority) {
+ /* already exists */
+ add = FALSE;
+ }
+ }
+ break;
+ }
+
+ if (add) {
+ ObtLinkBaseEntry *e = g_slice_new(ObtLinkBaseEntry);
+ e->priority = *priority;
+ e->link = obt_link_from_ddfile(full_path, self->paths,
+ self->language, self->country,
+ self->modifier);
+ list = g_slist_insert_before(list, it, e);
+
+ /* this will free 'id' */
+ g_hash_table_insert(self->base, id, list);
+ id = NULL;
+ }
+
+ g_free(id);
+}
+
+ObtLinkBase* obt_linkbase_new(ObtPaths *paths, const gchar *locale)
+{
+ ObtLinkBase *self;
+ GSList *it;
+ gint priority;
+ gint i;
- b = g_slice_new(ObtLinkBase);
- b->watch = obt_watch_new();
- b->base = g_hash_table_new_full(g_str_hash, g_str_equal, g_free,
- (GDestroyNotify)obt_link_unref);
+ self = g_slice_new0(ObtLinkBase);
+ self->watch = obt_watch_new();
+ self->base = g_hash_table_new_full(g_str_hash, g_str_equal, g_free,
+ (GDestroyNotify)base_entry_list_free);
+ self->path_to_priority = g_hash_table_new_full(g_str_hash, g_str_equal,
+ g_free, g_free);
+ self->paths = paths;
+ obt_paths_ref(paths);
+
+ for (i = 0; ; ++i)
+ if (!locale[i] || locale[i] == '_' || locale[i] == '.' ||
+ locale[i] == '@')
+ {
+ self->language = g_strndup(locale, i);
+ break;
+ }
+ else if (((guchar)locale[i] < 'A' || (guchar)locale[i] > 'Z') &&
+ ((guchar)locale[i] < 'a' || (guchar)locale[i] > 'z'))
+ break;
+ if (self->language && locale[i] == '_') {
+ locale += i+1;
+ for (i = 0; ; ++i)
+ if (!locale[i] || locale[i] == '.' || locale[i] == '@') {
+ self->country = g_strndup(locale, i);
+ break;
+ }
+ else if (((guchar)locale[i] < 'A' || (guchar)locale[i] > 'Z') &&
+ ((guchar)locale[i] < 'a' || (guchar)locale[i] > 'z'))
+ break;
+ }
+ if (self->country && locale[i] == '.')
+ for (; ; ++i)
+ if (!locale[i] || locale[i] == '@')
+ break;
+ else if (((guchar)locale[i] < 'A' || (guchar)locale[i] > 'Z') &&
+ ((guchar)locale[i] < 'a' || (guchar)locale[i] > 'z'))
+ break;
+ if (self->country && locale[i] == '@') {
+ locale += i+1;
+ for (i = 0; ; ++i)
+ if (!locale[i]) {
+ self->modifier = g_strndup(locale, i);
+ break;
+ }
+ else if (((guchar)locale[i] < 'A' || (guchar)locale[i] > 'Z') &&
+ ((guchar)locale[i] < 'a' || (guchar)locale[i] > 'z'))
+ break;
+ }
+ priority = 0;
for (it = obt_paths_data_dirs(paths); it; it = g_slist_next(it)) {
- gchar *p;
- p = g_strconcat(it->data, "/applications", NULL);
- obt_watch_add(b->watch, p, FALSE, func, b);
+ if (!g_hash_table_lookup(self->path_to_priority, it->data)) {
+ gchar *base_path;
+ gint *pri;
+
+ base_path = g_build_filename(it->data, "applications", NULL);
+
+ /* add to the hash table before adding the watch. the new watch
+ will be calling our update handler, immediately with any
+ files present in the directory */
+ pri = g_new(gint, 1);
+ *pri = priority;
+ g_hash_table_insert(self->path_to_priority,
+ g_strdup(base_path), pri);
+
+ obt_watch_add(self->watch, base_path, FALSE, update, self);
+
+ ++priority;
+ }
}
- return b;
+ return self;
}
-void obt_linkbase_ref(ObtLinkBase *lb)
+void obt_linkbase_ref(ObtLinkBase *self)
{
- ++lb->ref;
+ ++self->ref;
}
-void obt_linkbase_unref(ObtLinkBase *lb)
+void obt_linkbase_unref(ObtLinkBase *self)
{
- if (--lb->ref < 1) {
- obt_watch_unref(lb->watch);
- g_hash_table_unref(lb->base);
- g_slice_free(ObtLinkBase, lb);
+ if (--self->ref < 1) {
+ obt_watch_unref(self->watch);
+ g_hash_table_unref(self->path_to_priority);
+ g_hash_table_unref(self->base);
+ obt_paths_unref(self->paths);
+ g_slice_free(ObtLinkBase, self);
}
}
typedef struct _ObtLinkBase ObtLinkBase;
-/*! Create a new database of ObtLinks. */
-ObtLinkBase* obt_linkbase_new(struct _ObtPaths *paths);
+/*! Create a new database of ObtLinks.
+ @param paths An ObtPaths structure.
+ @param locale The value of LC_MESSAGES.
+*/
+ObtLinkBase* obt_linkbase_new(struct _ObtPaths *paths, const gchar *locale);
void obt_linkbase_ref(ObtLinkBase *lb);
void obt_linkbase_unref(ObtLinkBase *lb);
/*! Callback function for the system-specific GSource to alert us to changes.
*/
-typedef void (*ObtWatchNotifyFunc)(const gchar *path, gpointer target,
+typedef void (*ObtWatchNotifyFunc)(const gchar *sub_path,
+ const gchar *full_path, gpointer target,
ObtWatchNotifyType type);
};
static void target_free(ObtWatchTarget *t);
-static void target_notify(const gchar *const path, gpointer target,
- ObtWatchNotifyType type);
+static void target_notify(const gchar *sub_path, const gchar *full_path,
+ gpointer target, ObtWatchNotifyType type);
ObtWatch* obt_watch_new()
{
g_hash_table_remove(w->targets_by_path, path);
}
-static void target_notify(const gchar *const path, gpointer target,
- ObtWatchNotifyType type)
+static void target_notify(const gchar *sub_path, const gchar *full_path,
+ gpointer target, ObtWatchNotifyType type)
{
ObtWatchTarget *t = target;
if (type == OBT_WATCH_SELF_REMOVED) {
/* this also calls target_free */
g_hash_table_remove(t->w->targets_by_path, t->base_path);
}
- t->func(t->w, path, type, t->data);
+ t->func(t->w, t->base_path, sub_path, full_path, type, t->data);
}
typedef struct _ObtWatch ObtWatch;
typedef enum _ObtWatchNotifyType ObtWatchNotifyType;
-typedef void (*ObtWatchFunc)(ObtWatch *w, const gchar *subpath,
+/*! Notification function for changes in a watch file/directory.
+ @param base_path is the path to the watch target (file or directory).
+ @param sub_path is a path relative to the watched directory. If the
+ notification is about the watch target itself, the subpath will be
+ an empty string.
+*/
+typedef void (*ObtWatchFunc)(ObtWatch *w, const gchar *base_path,
+ const gchar *sub_path, const gchar *full_path,
ObtWatchNotifyType type, gpointer data);
enum _ObtWatchNotifyType {
/*! Callback function in the watch general system.
Matches definition in watch.c
*/
-typedef void (*ObtWatchNotifyFunc)(const gchar *path, gpointer target,
+typedef void (*ObtWatchNotifyFunc)(const gchar *sub_path,
+ const gchar *full_path, gpointer target,
ObtWatchNotifyType type);
struct _InoSource {
struct _InoTarget {
gint key;
gchar *path;
+ guint base_len; /* the length of the prefix of path which is the
+ target's path */
gpointer watch_target;
gboolean is_dir;
gboolean watch_hidden;
gpointer target);
static void remove_target(GSource *source, InoTarget *target);
static void target_free(InoTarget *target);
+static void notify_target(GSource *source, InoTarget *ino_target,
+ const gchar *path, ObtWatchNotifyType type);
static GSourceFuncs source_funcs = {
source_prepare,
if (cb) cb(data);
/* call the WatchNotify callback */
- ino_source->notify(full_path, t->watch_target, type);
+ notify_target(source, t, full_path, type);
}
g_free(full_path);
}
static gint add_target(GSource *source, InoTarget *parent,
- const gchar *path, gboolean watch_hidden,
- gpointer target)
+ const gchar *path,
+ gboolean watch_hidden, gpointer target)
{
InoSource *ino_source;
InoTarget *ino_target;
ino_target = g_slice_new(InoTarget);
ino_target->key = key;
ino_target->path = g_strdup(path);
+ ino_target->base_len = (parent ? parent->base_len : strlen(path));
ino_target->is_dir = is_dir;
ino_target->watch_hidden = watch_hidden;
ino_target->watch_target = target;
subpath = g_build_filename(path, name, NULL);
if (g_file_test(subpath, G_FILE_TEST_IS_DIR))
- add_target(source, ino_target, subpath, watch_hidden,
- target);
+ add_target(source, ino_target, subpath,
+ watch_hidden, target);
else
/* notify for each file in the directory on startup */
- ino_source->notify(subpath, ino_target->watch_target,
- OBT_WATCH_ADDED);
+ notify_target(source, ino_target, subpath,
+ OBT_WATCH_ADDED);
g_free(subpath);
}
}
g_slice_free(InoTarget, target);
}
+static void notify_target(GSource *source, InoTarget *ino_target,
+ const gchar *path, ObtWatchNotifyType type)
+{
+ InoSource *ino_source = (InoSource*)source;
+ ino_source->notify(path + ino_target->base_len,
+ path,
+ ino_target->watch_target,
+ type);
+}
+
#endif