You are not logged in.

#1 2007-11-16 18:29:43

icrave
Member
Registered: 2006-04-11
Posts: 193

Burn project in C/GTK

I was tired of looking for a burn-program that works and is lightweight. So I decided to create my own program, it only depends of cdrkit/dvd+rw-tools/gtk2.

It works, but i have a problem with the GTK interface. In the "dvd" function i want to popup before every "system" start, but all messages popups when "dvd" function has finished.

I know that probably this isnt the best way to do it, but the "system" calls and the "forks" works.

If anyone knows how i can start every message in the correct time...

Here is the code:

DVD function:

static void dvd( GtkWidget *widget, gpointer   data )
{
  
     int result=0;
    char* mes;
    if (!fork())
            {
                mes = "Making image...";
                message(mes);
                system("mkisofs -R -J -T -o /home/alex/burn.iso /home/alex/tmp/*");
                if (!fork())
                {
                    mes = "Deleting temporaly files...";
                    message(mes);
                    system("rm -R /home/alex/tmp");
                    if (!fork())
                    {
                            mes = "Burning DVD...";
                            message(mes);
                            system("dvdrecord -v dev=/dev/hdb speed=8 -sao -eject -data /home/alex/burn.iso");
                            if (!fork())

                            {
                                mes = "Process completed.";
                                message(mes);
                                system("rm /home/alex/burn.iso");
                            }
                            wait (&result);
                    }
                    wait (&result);
                }
                wait (&result);
            }
            wait (&result);
}

Message function:

void message (gchar *message) {

   GtkWidget *dialog, *label;
   
   dialog = gtk_dialog_new_with_buttons ("Message",NULL,GTK_DIALOG_DESTROY_WITH_PARENT, NULL, GTK_RESPONSE_NONE, NULL);
   label = gtk_label_new (message);
   
   g_signal_connect_swapped (dialog,"response", G_CALLBACK (gtk_widget_destroy),dialog);

   gtk_container_add (GTK_CONTAINER (GTK_DIALOG(dialog)->vbox), label);
   gtk_widget_show_all (dialog);
}

Thanks.

PD: One comment, if it works i will change it for a label. Now i post a popup because it explains good my problem.

Last edited by icrave (2007-11-16 18:36:57)

Offline

#2 2007-11-18 01:09:14

e_tank
Member
Registered: 2006-12-21
Posts: 80

Re: Burn project in C/GTK

hmm i'll give a shot at a response here, i probably shouldn't though as i have little experience using threads and absolutely none using fork.
what i'm going to suggest is based off of what i've read from the faq and api documentation over at gtk.org (presuming i understood what i read correctly..). i have no idea if there are better ways to do this kind of stuff nor am i sure if the example code that is provided below will even work properly but after running a quick test it at least _seems_ to work.  i'm hoping someone with more experience using threads can read over it, verify, and correct anything that's wrong.

why not thread dvd() and have it communicate to the gtk main thread rather than forking? this probably is a cleaner approach and it's not too difficult to do. now if you don't care if the dialog box message() creates appears _exactly_ before your system() calls this will be easier as you can just add message() to the gtk main thread via g_idle_add() and then do the system() call.  otherwise you'll have to make dvd() wait for a signal which the dialog box can send to it once it's displayed, which you can do using a GMutex and a GCond.  so if you don't care about exact timing just ignore the stuff with the GMutex and GCond in the following example

declare the following variables in the scope of both dvd() and message()

GCond *data_cond = NULL;
GMutex *data_mutex = NULL;
gint iSignal = 0;

in your main function add the following

int main(int argc, char *argv[])
{
    ...
    
    /* add these two function before gtk_init */
    g_thread_init(NULL);
    gdk_threads_init();
    gtk_init(&argc,&argv);

    ...

    /* call a function to create the mutex and condition or do it here */
    data_cond = g_cond_new();
    data_mutex = g_mutex_new();

    ...

    /* add gdk_threads enter and leave around gtk_main */
    gdk_threads_enter();
    gtk_main();
    gdk_threads_leave();

    ...
}

have the function in the gtk_main thread that calls dvd() thread it

void on_some_button_click(GtkWidget *widget, gpointer data)
{
    GError *error = NULL;

    ...
    
    if(!g_thread_create(dvd,NULL,FALSE,&error))
    {
        p_printerr("Failed to create thread: %s\n",error->message);
        /* exit or something here */
    }

    ...
}

in dvd do the following each time you want to display a dialog box.

static gboolean dvd()
{
    ...

    g_mutex_lock(data_mutex);
        /* clear signal flag for dialog box to set */
        iSignal = 0;
    /* create message box in gtk main thread */
    g_idle_add(message,"your message here");
    /* wait for signal from dialog box */
    while(iSignal == 0)
        g_cond_wait(data_cond,data_mutex);
    g_mutex_unlock(data_mutex);
    /* do your system call here, the dialog box has already been displayed at this point */
    system("command");

    ...
}

make sure message returns FALSE!

gboolean message(gchar *message)
{
    ...

    /* connect a function to the show signal that will signal back to the dvd() thread */
    g_signal_connect(G_OBJECT(dialog),"show",G_CALLBACK(signal_dvd_function),NULL);
    gtk_widget_show_all(dialog);
    return FALSE;
}

add the show function for the dialog window which signals dvd() that it has been displayed

void signal_thread_test(GtkWidget *widget, gpointer data)
{
    g_mutex_lock(data_mutex);
    iSignal = 1;
    g_cond_signal(data_cond);
    g_mutex_unlock(data_mutex);
}

that should do it, you also probably should make sure that if the dvd thread is running that it can't be called again, which you could do by adding another variable like the iSignal above using the same mutex to access it to see if it's running or not, or use the glib atomic operations to do this.

also don't forget to add gthread-2.0 to the arguments given to pkg-config when compiling

Offline

Board footer

Powered by FluxBB