Add Windows directory monitoring to ecore_file. It was tough.
authorcaro <caro@7cbeb6ba-43b4-40fd-8cce-4c39aea84d33>
Wed, 11 Nov 2009 17:45:55 +0000 (17:45 +0000)
committercaro <caro@7cbeb6ba-43b4-40fd-8cce-4c39aea84d33>
Wed, 11 Nov 2009 17:45:55 +0000 (17:45 +0000)
A lot of thanks to Lars Munch for his great help

git-svn-id: svn+ssh://svn.enlightenment.org/var/svn/e/trunk/ecore@43617 7cbeb6ba-43b4-40fd-8cce-4c39aea84d33

configure.ac
m4/ecore_check_options.m4
src/lib/ecore_file/Makefile.am
src/lib/ecore_file/ecore_file_monitor.c
src/lib/ecore_file/ecore_file_monitor_win32.c [new file with mode: 0644]
src/lib/ecore_file/ecore_file_private.h

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