diff --git a/gral.h b/gral.h index acc2b8f..4bcf42c 100644 --- a/gral.h +++ b/gral.h @@ -181,6 +181,7 @@ void gral_file_remove(char const *path); void gral_directory_create(char const *path); void gral_directory_iterate(char const *path, void (*callback)(char const *name, void *user_data), void *user_data); void gral_directory_remove(char const *path); +void gral_directory_monitor(char const *path, void (*callback)(void *user_data), void *user_data); /*========= diff --git a/gral_linux.c b/gral_linux.c index e5d9648..d7a81f2 100644 --- a/gral_linux.c +++ b/gral_linux.c @@ -768,6 +768,10 @@ void gral_directory_remove(char const *path) { rmdir(path); } +void gral_directory_monitor(char const *path, void (*callback)(void *user_data), void *user_data) { + // TODO: implement +} + /*========= TIME diff --git a/gral_macos.m b/gral_macos.m index 47a8a8f..c14f9e7 100644 --- a/gral_macos.m +++ b/gral_macos.m @@ -803,6 +803,10 @@ void gral_directory_remove(char const *path) { rmdir(path); } +void gral_directory_monitor(char const *path, void (*callback)(void *user_data), void *user_data) { + // TODO: implement +} + /*========= TIME diff --git a/gral_windows.cpp b/gral_windows.cpp index f38f0dc..44cb418 100644 --- a/gral_windows.cpp +++ b/gral_windows.cpp @@ -563,12 +563,17 @@ int gral_application_run(gral_application *application, int argc_, char **argv_) } LocalFree(argv); MSG message; - while (GetMessage(&message, NULL, 0, 0)) { - TranslateMessage(&message); - DispatchMessage(&message); + while (TRUE) { + while (PeekMessage(&message, NULL, 0, 0, PM_REMOVE)) { + if (message.message == WM_QUIT) { + application->iface.quit(application->user_data); + return 0; + } + TranslateMessage(&message); + DispatchMessage(&message); + } + MsgWaitForMultipleObjectsEx(0, NULL, INFINITE, QS_ALLINPUT, MWMO_ALERTABLE); } - application->iface.quit(application->user_data); - return 0; } @@ -1171,6 +1176,49 @@ void gral_directory_remove(char const *path) { RemoveDirectory(utf8_to_utf16(path)); } +class gral_directory_watcher { + HANDLE directory; + OVERLAPPED overlapped; + void (*callback)(void *user_data); + void *user_data + char buffer[4096]; + static void completion_routine(DWORD dwErrorCode, DWORD dwNumberOfBytesTransfered, LPOVERLAPPED lpOverlapped) { + gral_directory_watcher *watcher = (gral_directory_watcher *)lpOverlapped->hEvent; + DWORD offset = 0; + while (TRUE) { + PFILE_NOTIFY_INFORMATION information = (PFILE_NOTIFY_INFORMATION)(watcher->buffer + offset); + if (information->Action != FILE_ACTION_RENAMED_OLD_NAME) { + watcher->callback(watcher->user_data); + } + if (information->NextEntryOffset == 0) { + break; + } + offset += information->NextEntryOffset; + } + watcher->watch(); + } +public: + gral_directory_watcher(char const *path, void (*callback)(void *user_data), void *user_data) { + directory = CreateFile(utf8_to_utf16(path), FILE_LIST_DIRECTORY, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED, NULL); + ZeroMemory(&overlapped, sizeof(overlapped)); + overlapped.hEvent = this; + this->callback = callback; + this->user_data = user_data; + } + ~gral_directory_watcher() { + CloseHandle(directory); + } + void watch() { + const DWORD notify_filter = FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME | 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(directory, buffer, sizeof(buffer), FALSE, notify_filter, NULL, &overlapped, completion_routine); + } +}; + +void gral_directory_monitor(char const *path, void (*callback)(void *user_data), void *user_data) { + gral_directory_watcher *watcher = new gral_directory_watcher(path, callback, user_data); + watcher->watch(); +} + /*========= TIME