GTK+ Forums

Discussion forum for GTK+ and Programming. Ask questions, troubleshoot problems, view and post example code, or express your opinions.
It is currently Sat Nov 01, 2014 3:26 am

All times are UTC




Post new topic Reply to topic  [ 3 posts ] 
Author Message
 Post subject: GTK+ with pthread
PostPosted: Thu Apr 19, 2012 5:57 pm 
Offline
GTK+ Geek

Joined: Sun Apr 03, 2011 11:12 am
Posts: 63
Hello everyone, I am creating an IDE in C using GTK+. In my IDE, i want to determine whenever the file accessed by another program. For that I used inotify() for POSIX. To determine whether the file is accessed or not, an infinite loop has to executed, which will continuously check whether file has been accessed or not. But, we know running an infinite loop in the main thread will block it. So, I decide to run the loop in another thread and whenever the file will be accessed a message box will be displayed. For that what I did is, I created a struct WatchFile which will watch the file whether it has been accessed or not. Here's the code.
watchfile.h
Code:
#include<sys/inotify.h>
#include<limits.h>
#include<stdio.h>
#include<pthread.h>
#include<stdlib.h>

struct _WatchFile
{
    int inotifyFd;
    int *wd_array;
    char **filename_array;
    int files_count;
    struct inotify_event *event;
    pthread_t begin_watching_thread;
    void (*callback_function)(void *watch_file,char *filename);
    };

typedef struct _WatchFile WatchFile;

void watch_file_init(WatchFile *watch_file_object);
void watch_file_add_file(WatchFile *watch_file_object, char *filename);
int watch_file_remove_file(WatchFile *watch_file_object, char *filename);
void watch_file_add_callback(WatchFile *watch_file_object, void (*func)(void *watch_file,char *filename));
void watch_file_begin(WatchFile *watch_file_object);
void watch_file_stop(WatchFile *watch_file_object);

watchfile.c
Code:
#include"watchfileobject.h"

void watch_file_init(WatchFile *watch_file_object)
{       
    watch_file_object->inotifyFd = inotify_init();   
    watch_file_object->files_count = 0;
    watch_file_object->filename_array = malloc(1*sizeof(char *));
    watch_file_object->wd_array = malloc(1*sizeof(int));
    }

void watch_file_add_file(WatchFile *watch_file_object, char *filename) //Remember to add Events to Arguments also
{   
    if(watch_file_object->files_count>0)
    {
        watch_file_object->filename_array = realloc(watch_file_object->filename_array,(watch_file_object->files_count+1)*sizeof(char *));
        watch_file_object->wd_array = realloc(watch_file_object->wd_array,(watch_file_object->files_count+1)*sizeof(int));
        }
    asprintf(&watch_file_object->filename_array[watch_file_object->files_count],"%s",filename);
    watch_file_object->wd_array[watch_file_object->files_count] = inotify_add_watch(watch_file_object->inotifyFd,filename,IN_ALL_EVENTS);
    watch_file_object->files_count++;
    }

int watch_file_remove_file(WatchFile *watch_file_object, char *filename)
{   
    if(watch_file_object->files_count==0)
        return -1;
    int index,i;
    for(index=0;index<watch_file_object->files_count;index++)
        if(strcmp(watch_file_object->filename_array[index],filename)==0)
            break;
    if(index==watch_file_object->files_count+1)
        return -1;
   
    int retval = inotify_rm_watch(watch_file_object->inotifyFd,watch_file_object->wd_array[index]);

    for(i=index;i<watch_file_object->files_count;i++)
    {
        watch_file_object->filename_array[i]= watch_file_object->filename_array[i+1];
        watch_file_object->wd_array[i] = watch_file_object->wd_array[i+1];
        }
    watch_file_object->files_count--;
    return retval;
    }

void watch_file_add_callback(WatchFile *watch_file_object, void (*func)(void *watch_file,char *filename))
{
    watch_file_object->callback_function = func;   
    }

void *watch_file_thread_begin(void *watch_file)
{
    WatchFile *watch_file_object = (WatchFile *)watch_file;
    char buf[1000];
    char *p;
    while(1)
    {
        int n = read(watch_file_object->inotifyFd,buf,1000);
        for(p=buf;p<buf+n;)
        {
            watch_file_object->event = (struct inotify_event *)p;
            if(watch_file_object->event->mask & IN_ACCESS)
            {
                int wd =watch_file_object->event->wd, index;
                for(index=0;index<watch_file_object->files_count;index++)
                    if(watch_file_object->wd_array[index]==wd)
                        break;                   
                watch_file_object->callback_function((void *)watch_file_object,watch_file_object->filename_array[index]);
                }
            p +=sizeof(struct inotify_event)+watch_file_object->event->len;
            }       
        }
    return NULL;
    }

void watch_file_begin(WatchFile *watch_file_object)
{   
    int s;   
    s = pthread_create(&watch_file_object->begin_watching_thread,NULL,watch_file_thread_begin,watch_file_object);   
    }

void watch_file_stop(WatchFile *watch_file_object)
{
    pthread_cancel(watch_file_object->begin_watching_thread);
    }

Here, we have different functions. watch_file_add_callback will add a callback function, and will be called whenever the file has been accessed. watch_file_begin will create a new thread and will run watch_file_thread_begin function in the newly created thread using pthread_t in POSIX and whenever the file will be accessed it will execute the callback_function.
As I will use it in my IDE, so I created a new watch_file object, initializes it, starts it and add or remove files whenever a file is opened or saved or a tab is removed. But whenever the file is accessed it calls the callback_function and if I try to create a GtkDialog inside that function and run it using gtk_dialog_run() then program hangs. Here's the callback function
Code:
void watch_file_file_modified(void *watch_file, char *filepath)
{
    ///Just implement a message dialog
    //I think the problem is with threads
   
    watch_file_stop(&watch_file_object);
    GtkWidget *dialog,*label,*hbox;
    char *message, *filename;
    filename = strrchr(filepath,'/');
    filename++;
    asprintf(&message,"File %s has been modified. Do you want to reload it?",filename);
    dialog  = gtk_dialog_new();
    label = gtk_label_new(message);
    gtk_box_pack_start_defaults(GTK_BOX(GTK_DIALOG(dialog)->vbox),label);
    gtk_widget_show_all(dialog);
    gtk_dialog_run(GTK_DIALOG(dialog));
    free(message);   
    }

I think the problem is that the GtkDialog must run inside a main thread but it is running in another thread, so can you tell me how to solve this problem. I know we have GFileMonitor, but I want to solve this problem.


Top
 Profile  
 
 Post subject: Re: GTK+ with pthread
PostPosted: Fri Apr 20, 2012 6:37 am 
Offline
Never Seen the Sunlight

Joined: Mon Apr 28, 2008 5:52 am
Posts: 768
Location: UK
Hi,

What I assume you are trying to do is make calls to GTK/GDK from different threads. This you can not do as GTK/GDK is not thread safe. You could use gdk_threads_enter()/gdk_threads_leave() calls, but these are soon to be deprecated so I would avoid these.

The best method is to use an inter process communication of some sorts. Such as g_idle_add() to add to a queue of signals that would be called in the main thread. Note that Glib is thread safe.

Other notes are

- I would prefer to use the GIO functions to monitor file changes, as I would then not be re-inventing the wheel. It would then be portable from system to system. It is much easier to use and the signals can be added to the main loop. The actual file monitoring is done in another thread with GIO, but you do not need to use threads directly.

- You do not say what versions of the libraries you are using, but you are using features that were deprecated many years ago and now have been removed in GTK+ 3
Code:
GTK_DIALOG(dialog)->vbox
is no longer valid use
Code:
GtkWidget *         gtk_dialog_get_content_area         (GtkDialog *dialog);
instead.

- Since you have included the Glib library (you always will if you use GTK) prefer functions from Glib rather than extension to libraries so use g_strdup_printf() rather than asprintf()

_________________
E.


Top
 Profile  
 
 Post subject: Re: GTK+ with pthread
PostPosted: Fri Apr 20, 2012 11:49 am 
Offline
GTK+ Geek

Joined: Sun Apr 03, 2011 11:12 am
Posts: 63
I'm using GTK+ 2 and will shift to GTK+ 3 in some time. And once again Thnx for the help errol!! :)


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 3 posts ] 

All times are UTC


Who is online

Users browsing this forum: No registered users and 1 guest


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group