Add Windows directory monitoring to ecore_file. It was tough.

A lot of thanks to Lars Munch for his great help

SVN revision: 43617
This commit is contained in:
Vincent Torri 2009-11-11 17:45:55 +00:00
parent 9f839063c8
commit a2f8b6a526
6 changed files with 386 additions and 4 deletions

View File

@ -86,6 +86,7 @@ want_cipher="no"
want_signature="no"
want_poll="yes"
want_inotify="no"
want_notify_win32="no"
want_tslib="no"
want_glib="no"
@ -136,6 +137,7 @@ case "$host_os" in
want_ecore_evas_software_16_wince="yes"
;;
mingw*)
want_notify_win32="yes"
want_curl="yes"
want_glib="auto"
want_ecore_imf="yes"
@ -837,9 +839,11 @@ ECORE_CHECK_MODULE([File], [${want_ecore_file}])
have_poll="no"
have_inotify="no"
have_notify_win32="no"
if test "x${have_ecore_file}" = "xyes" ; then
ECORE_CHECK_POLL([${want_poll}], [have_poll="yes"], [have_poll="no"])
ECORE_CHECK_INOTIFY([${want_inotify}], [have_inotify="yes"], [have_inotify="no"])
ECORE_CHECK_NOTIFY_WIN32([${want_notify_win32}], [have_notify_win32="yes"], [have_notify_win32="no"])
if test "x${have_ecore_con}" = "xyes" ; then
requirements_ecore_file="ecore-con ${requirements_ecore_file}"
@ -1205,6 +1209,7 @@ fi
echo " Ecore_File...................: $have_ecore_file"
if test "x$have_ecore_file" = "xyes" ; then
echo " Inotify....................: $have_inotify"
echo " Windows notification.......: $have_notify_win32"
echo " Poll.......................: $have_poll"
echo " CURL.......................: $have_curl"
fi

View File

@ -84,6 +84,37 @@ else
m4_default([$3], [:])
fi
])
dnl use: ECORE_CHECK_NOTIFY_WIN32(default-enabled[, ACTION-IF-FOUND[, ACTION-IF-NOT-FOUND]])
AC_DEFUN([ECORE_CHECK_NOTIFY_WIN32],
[
_ecore_want_notify_win32=$1
_ecore_have_notify_win32="no"
AC_ARG_ENABLE(notify-win32,
[AC_HELP_STRING([--disable-notify-win32], [disable Windows notification in the ecore_file module])],
[
if test "x${enableval}" = "xyes" ; then
_ecore_want_notify_win32="yes"
else
_ecore_want_notify_win32="no"
fi
])
AC_MSG_CHECKING(whether Windows notification is to be used for filemonitoring)
AC_MSG_RESULT(${_ecore_want_notify_win32})
if test "x${_ecore_want_notify_win32}" = "xyes" ; then
AC_DEFINE([HAVE_NOTIFY_WIN32], [1], [ File monitoring with Windows notification ])
_ecore_have_notify_win32="yes"
fi
if test "x${_ecore_have_notify_win32}" = "xyes" ; then
m4_default([$2], [:])
else
m4_default([$3], [:])
fi
])
dnl use: ECORE_CHECK_CURL(default-enabled[, ACTION-IF-FOUND[, ACTION-IF-NOT-FOUND]])
AC_DEFUN([ECORE_CHECK_CURL],

View File

@ -25,6 +25,7 @@ libecore_file_la_SOURCES = \
ecore_file.c \
ecore_file_monitor.c \
ecore_file_monitor_inotify.c \
ecore_file_monitor_win32.c \
ecore_file_monitor_poll.c \
ecore_file_path.c \
ecore_file_download.c

View File

@ -13,6 +13,9 @@ typedef enum {
#ifdef HAVE_INOTIFY
ECORE_FILE_MONITOR_TYPE_INOTIFY,
#endif
#ifdef HAVE_NOTIFY_WIN32
ECORE_FILE_MONITOR_TYPE_NOTIFY_WIN32,
#endif
#ifdef HAVE_POLL
ECORE_FILE_MONITOR_TYPE_POLL
#endif
@ -28,6 +31,11 @@ ecore_file_monitor_init(void)
if (ecore_file_monitor_inotify_init())
return 1;
#endif
#ifdef HAVE_NOTIFY_WIN32
monitor_type = ECORE_FILE_MONITOR_TYPE_NOTIFY_WIN32;
if (ecore_file_monitor_win32_init())
return 1;
#endif
#ifdef HAVE_POLL
monitor_type = ECORE_FILE_MONITOR_TYPE_POLL;
if (ecore_file_monitor_poll_init())
@ -49,6 +57,11 @@ ecore_file_monitor_shutdown(void)
ecore_file_monitor_inotify_shutdown();
break;
#endif
#ifdef HAVE_NOTIFY_WIN32
case ECORE_FILE_MONITOR_TYPE_NOTIFY_WIN32:
ecore_file_monitor_win32_shutdown();
break;
#endif
#ifdef HAVE_POLL
case ECORE_FILE_MONITOR_TYPE_POLL:
ecore_file_monitor_poll_shutdown();
@ -66,10 +79,11 @@ ecore_file_monitor_shutdown(void)
*/
EAPI Ecore_File_Monitor *
ecore_file_monitor_add(const char *path,
void (*func) (void *data, Ecore_File_Monitor *em,
Ecore_File_Event event,
const char *path),
void *data)
void (*func) (void *data,
Ecore_File_Monitor *em,
Ecore_File_Event event,
const char *path),
void *data)
{
switch (monitor_type)
{
@ -79,6 +93,10 @@ ecore_file_monitor_add(const char *path,
case ECORE_FILE_MONITOR_TYPE_INOTIFY:
return ecore_file_monitor_inotify_add(path, func, data);
#endif
#ifdef HAVE_NOTIFY_WIN32
case ECORE_FILE_MONITOR_TYPE_NOTIFY_WIN32:
return ecore_file_monitor_win32_add(path, func, data);
#endif
#ifdef HAVE_POLL
case ECORE_FILE_MONITOR_TYPE_POLL:
return ecore_file_monitor_poll_add(path, func, data);
@ -103,6 +121,11 @@ ecore_file_monitor_del(Ecore_File_Monitor *em)
ecore_file_monitor_inotify_del(em);
break;
#endif
#ifdef HAVE_NOTIFY_WIN32
case ECORE_FILE_MONITOR_TYPE_NOTIFY_WIN32:
ecore_file_monitor_win32_del(em);
break;
#endif
#ifdef HAVE_POLL
case ECORE_FILE_MONITOR_TYPE_POLL:
ecore_file_monitor_poll_del(em);

View File

@ -0,0 +1,310 @@
/*
* vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2
*/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#ifdef HAVE_NOTIFY_WIN32
# define WIN32_LEAN_AND_MEAN
# include <windows.h>
# undef WIN32_LEAN_AND_MEAN
# include <process.h>
# include "ecore_file_private.h"
typedef struct _Ecore_File_Monitor_Win32 Ecore_File_Monitor_Win32;
typedef struct _Ecore_File_Monitor_Win32_Data Ecore_File_Monitor_Win32_Data;
/* 4096 = 256 * sizeof(FILE_NOTIFY_INFORMATION) */
# define ECORE_FILE_MONITOR_WIN32_BUFFER_SIZE 4096
# define ECORE_FILE_MONITOR_WIN32(x) ((Ecore_File_Monitor_Win32 *)(x))
struct _Ecore_File_Monitor_Win32_Data
{
char buffer[ECORE_FILE_MONITOR_WIN32_BUFFER_SIZE];
OVERLAPPED overlapped;
HANDLE handle;
HANDLE event;
Ecore_File_Monitor *monitor;
Ecore_Win32_Handler *h;
DWORD buf_length;
int is_dir;
};
struct _Ecore_File_Monitor_Win32
{
Ecore_File_Monitor monitor;
Ecore_File_Monitor_Win32_Data *file;
Ecore_File_Monitor_Win32_Data *dir;
};
static Ecore_File_Monitor *_monitors = NULL;
static int _ecore_file_monitor_win32_cb(void *data, Ecore_Win32_Handler *wh);
static Ecore_File_Monitor_Win32_Data *
_ecore_file_monitor_win32_data_new(Ecore_File_Monitor *monitor, int type)
{
Ecore_File_Monitor_Win32_Data *md;
DWORD filter;
md = (Ecore_File_Monitor_Win32_Data *)calloc(1, sizeof(Ecore_File_Monitor_Win32_Data));
if (!md) return NULL;
md->handle = CreateFile(monitor->path,
FILE_LIST_DIRECTORY,
FILE_SHARE_READ |
FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
FILE_FLAG_BACKUP_SEMANTICS |
FILE_FLAG_OVERLAPPED,
NULL);
if (md->handle == INVALID_HANDLE_VALUE)
goto free_md;
md->event = CreateEvent(NULL, FALSE, FALSE, NULL);
if (!md->event)
goto close_handle;
ZeroMemory (&md->overlapped, sizeof(md->overlapped));
md->overlapped.hEvent = md->event;
filter = (type == 0) ? FILE_NOTIFY_CHANGE_FILE_NAME : FILE_NOTIFY_CHANGE_DIR_NAME;
filter |=
FILE_NOTIFY_CHANGE_ATTRIBUTES |
FILE_NOTIFY_CHANGE_SIZE |
FILE_NOTIFY_CHANGE_LAST_WRITE |
FILE_NOTIFY_CHANGE_LAST_ACCESS |
FILE_NOTIFY_CHANGE_CREATION |
FILE_NOTIFY_CHANGE_SECURITY;
if (!ReadDirectoryChangesW(md->handle,
md->buffer,
ECORE_FILE_MONITOR_WIN32_BUFFER_SIZE,
FALSE,
filter,
&md->buf_length,
&md->overlapped,
NULL))
goto close_event;
md->h = ecore_main_win32_handler_add(md->event,
_ecore_file_monitor_win32_cb,
md);
if (!md->h)
goto close_event;
md->monitor = monitor;
md->is_dir = type;
return md;
close_event:
CloseHandle(md->event);
close_handle:
CloseHandle(md->handle);
free_md:
free(md);
return NULL;
}
static void
_ecore_file_monitor_win32_data_free(Ecore_File_Monitor_Win32_Data *md)
{
if (!md) return;
CloseHandle(md->event);
CloseHandle (md->handle);
free (md);
}
static int
_ecore_file_monitor_win32_cb(void *data, Ecore_Win32_Handler *wh)
{
char filename[PATH_MAX];
PFILE_NOTIFY_INFORMATION fni;
Ecore_File_Monitor_Win32_Data *md;
wchar_t *wname;
char *name;
DWORD filter;
DWORD offset;
DWORD buf_length;
Ecore_File_Event event = ECORE_FILE_EVENT_NONE;
md = (Ecore_File_Monitor_Win32_Data *)data;
if (!GetOverlappedResult (md->handle, &md->overlapped, &buf_length, TRUE))
return 1;
fni = (PFILE_NOTIFY_INFORMATION)md->buffer;
do {
if (!fni)
break;
offset = fni->NextEntryOffset;
wname = (wchar_t *)malloc(sizeof(wchar_t) * (fni->FileNameLength + 1));
if (!wname)
return 0;
memcpy(wname, fni->FileName, fni->FileNameLength);
wname[fni->FileNameLength]='\0';
name = evil_wchar_to_char(wname);
free(wname);
if (!name)
return 0;
_snprintf(filename, PATH_MAX, "%s\\%s", md->monitor->path, name);
free(name);
switch (fni->Action)
{
case FILE_ACTION_ADDED:
if (md->is_dir)
event = ECORE_FILE_EVENT_CREATED_DIRECTORY;
else
event = ECORE_FILE_EVENT_CREATED_FILE;
break;
case FILE_ACTION_REMOVED:
if (md->is_dir)
event = ECORE_FILE_EVENT_DELETED_DIRECTORY;
else
event = ECORE_FILE_EVENT_DELETED_FILE;
break;
case FILE_ACTION_MODIFIED:
if (!md->is_dir)
event = ECORE_FILE_EVENT_MODIFIED;
break;
case FILE_ACTION_RENAMED_OLD_NAME:
if (md->is_dir)
event = ECORE_FILE_EVENT_DELETED_DIRECTORY;
else
event = ECORE_FILE_EVENT_DELETED_FILE;
break;
case FILE_ACTION_RENAMED_NEW_NAME:
if (md->is_dir)
event = ECORE_FILE_EVENT_CREATED_DIRECTORY;
else
event = ECORE_FILE_EVENT_CREATED_FILE;
break;
default:
fprintf(stderr, "unknown event\n");
event = ECORE_FILE_EVENT_NONE;
break;
}
if (event != ECORE_FILE_EVENT_NONE)
md->monitor->func(md->monitor->data, md->monitor, event, filename);
fni = (PFILE_NOTIFY_INFORMATION)((LPBYTE)fni + offset);
} while (offset);
filter = (md->is_dir == 0) ? FILE_NOTIFY_CHANGE_FILE_NAME : FILE_NOTIFY_CHANGE_DIR_NAME;
filter |=
FILE_NOTIFY_CHANGE_ATTRIBUTES |
FILE_NOTIFY_CHANGE_SIZE |
FILE_NOTIFY_CHANGE_LAST_WRITE |
FILE_NOTIFY_CHANGE_LAST_ACCESS |
FILE_NOTIFY_CHANGE_CREATION |
FILE_NOTIFY_CHANGE_SECURITY;
ReadDirectoryChangesW(md->handle,
md->buffer,
ECORE_FILE_MONITOR_WIN32_BUFFER_SIZE,
FALSE,
filter,
&md->buf_length,
&md->overlapped,
NULL);
return 0;
}
int
ecore_file_monitor_win32_init(void)
{
return 1;
}
int
ecore_file_monitor_win32_shutdown(void)
{
return 1;
}
Ecore_File_Monitor *
ecore_file_monitor_win32_add(const char *path,
void (*func) (void *data, Ecore_File_Monitor *em,
Ecore_File_Event event,
const char *path),
void *data)
{
Ecore_File_Monitor_Win32 *m;
Ecore_File_Monitor *em;
size_t len;
if (!path || (*path == '\0')) return NULL;
if (!ecore_file_exists(path) || !ecore_file_is_dir(path))
return NULL;
if (!func) return NULL;
em = (Ecore_File_Monitor *)calloc(1, sizeof(Ecore_File_Monitor_Win32));
if (!em) return NULL;
em->func = func;
em->data = data;
em->path = strdup(path);
if (!em->path)
{
free(em);
return NULL;
}
len = strlen(em->path);
if (em->path[len - 1] == '/' || em->path[len - 1] == '\\')
em->path[len - 1] = '\0';
m = ECORE_FILE_MONITOR_WIN32(em);
m->file = _ecore_file_monitor_win32_data_new(em, 0);
if (!m->file)
{
free(em->path);
free(em);
return NULL;
}
m->dir = _ecore_file_monitor_win32_data_new(em, 1);
if (!m->dir)
{
_ecore_file_monitor_win32_data_free(m->file);
free(em->path);
free(em);
return NULL;
}
_monitors = ECORE_FILE_MONITOR(eina_inlist_append(EINA_INLIST_GET(_monitors), EINA_INLIST_GET(em)));
return em;
}
void
ecore_file_monitor_win32_del(Ecore_File_Monitor *em)
{
Ecore_File_Monitor_Win32 *m;
if (!em)
return;
m = ECORE_FILE_MONITOR_WIN32(em);
_ecore_file_monitor_win32_data_free(m->dir);
_ecore_file_monitor_win32_data_free(m->file);
free(em->path);
free(em);
}
#endif

View File

@ -57,6 +57,18 @@ Ecore_File_Monitor *ecore_file_monitor_inotify_add(const char *path,
void *data);
void ecore_file_monitor_inotify_del(Ecore_File_Monitor *ecore_file_monitor);
#endif
#ifdef HAVE_NOTIFY_WIN32
int ecore_file_monitor_win32_init(void);
int ecore_file_monitor_win32_shutdown(void);
Ecore_File_Monitor *ecore_file_monitor_win32_add(const char *path,
void (*func) (void *data,
Ecore_File_Monitor *ecore_file_monitor,
Ecore_File_Event event,
const char *path),
void *data);
void ecore_file_monitor_win32_del(Ecore_File_Monitor *ecore_file_monitor);
#endif
#ifdef HAVE_POLL
int ecore_file_monitor_poll_init(void);