Yes, file modifications are detected with dnotify …
#define _GNU_SOURCE
#include <fcntl.h>
#include <sys/stat.h>
#include <stdio.h>
#include <errno.h>
#include <signal.h>
#include <stdlib.h>
#include <string.h>
int fd=0;
char *dir=NULL;
char *slashPtr=NULL;
struct stat statBuf;
struct sigaction action;
int directorychanged=0;
char splitFilename[128];
char filechecked[127];
time_t modifiedTime;
int isrunning=0;
int filechanged=0;
void EventHandlerFunc( int sig )
{
// printf("This is the event Handler when the ./ directory is modified
" /* , filechecked */ );
directorychanged = 1;
}
void DelayedActionToFileChange()
{
printf("Delayed action after a modification to %s
", filechecked);
filechanged = 0;
}
int InitDetectChange( int argc, char *argv[] )
{
/* Find directory the file is in, or assume the current directory */
strncpy( splitFilename, argv[1], 127 );
strncpy( filechecked, argv[1], 127 );
if( (slashPtr = rindex( splitFilename, '/' )) == NULL )
{
dir = ".";
}
else
{
*slashPtr = 0;
dir = splitFilename;
}
/* Set up the signal handler */
action.sa_handler = EventHandlerFunc;
sigemptyset( &action.sa_mask );
action.sa_flags = SA_RESTART;
sigaction( SIGRTMIN, &action, NULL );
/* Open the directory the file is in */
if( (fd = open( dir, O_RDONLY )) < 0 )
{
printf( "Cannot open %s for reading : %s
", dir, strerror(errno) );
exit( -1 );
}
/* Choose the signal I want to receive when the directory content changes */
if( fcntl( fd, F_SETSIG, SIGRTMIN) < 0 )
{
printf( "Cannot set signal : %s
", strerror(errno) );
exit( -1 );
}
/* Ask for notification when a modification is made in the directory */
if( fcntl( fd, F_NOTIFY, DN_MODIFY|DN_MULTISHOT ) < 0 )
{
printf( "Cannot fcntl %s : %s
", dir, strerror(errno) );
exit( -1 );
}
if( lstat( filechecked, &statBuf ) < 0 )
{
printf( "Cannot lstat %s : %s
", filechecked, strerror(errno) );
exit( -1 );
}
modifiedTime = statBuf.st_mtime;
return fd;
}
int DetectChange(char *filename)
{
if( lstat( filename, &statBuf ) < 0 )
{
printf( "Cannot lstat %s : %s
", filename, strerror(errno) );
exit( -1 );
}
// If the modification time has changed, the file has been altered
if( modifiedTime != statBuf.st_mtime )
{
directorychanged = 1;
filechanged = 1;
modifiedTime = statBuf.st_mtime;
// printf( "File %s has really been modified since the lastest call
", filename );
}else{
// directorychanged = 0;
filechanged = 0;
// printf( "File %s hasn\'t been modified since the later call
", filename );
}
return filechanged;
}
void PrintUsage(int argc, char **argv)
{
if( argc != 2 )
{
printf( "Usage: %s filename", argv[0] );
exit( -1 );
}
if( lstat( argv[1], &statBuf ) < 0 )
{
printf( "Cannot lstat %s : %s
", argv[1], strerror(errno) );
exit( -1 );
}
if( ! S_ISREG( statBuf.st_mode ) )
{
printf( "%s is not a regular file
", argv[1] );
exit( -1 );
}
}
int main( int argc, char *argv[] )
{
PrintUsage(argc, argv);
isrunning = InitDetectChange(argc, argv);
while( isrunning )
{
/* This demo has nothing to do, so just wait for a signal */
sleep(10);
/* Check the flag which indicates the right signal has been received */
if( directorychanged )
{
if( DetectChange(argv[1]) )
{
sleep(1);
DelayedActionToFileChange();
}
}
}
return 0;
}
But this use lstat( filechecked, &statBuf ) vs modifiedTime too
=> if necessary the dnotify part can to be canceled …
(but perhaps with a %CPU increase because it limit really the number of calls to the DetectChange() func …)
This is not OpenGL code, this produce only a little executable that detect when the file in argument is modified.
I think to use separates (but linked) tasks for
-
edition of shaders
-
detection of changes in a vertex/fragment shader file
-
[re]compilation of shaders [that are changed]
-
execution of a OpenGL task that show edited shaders in action
The previous code can already be used for to implement the part 2) and the part 3) is’t too difficult to make
But Ok, if the part 4) can certainly to be make without too difficulties, I think that the really hard task is to make the editor …