vitimiti
vitimiti

Reputation: 77

How can I make functions follow a proper order?

I have this code:

#include <stdlib.h>
#include <gtk/gtk.h>

#include "splash_screen.h"
#include "db.h"

/* Global declarations */
GtkWidget *splash_window, *splash_image, *vbox, *pbar;
int timer;

/* A timeout to make the progressbar be animated */
static gboolean progress_timeout (gpointer data)
{
    gtk_progress_bar_pulse (GTK_PROGRESS_BAR (data));

    /* Make this callback to be called again and again */
    return TRUE;
}

/* A function to destroy the splash screen */
static void destroy_splash_screen (GtkWidget *window, int timer)
{
    /* Finish the timer */
    gtk_timeout_remove (timer);
    timer = 0;

    /* Destroy the widget window and its children */
    gtk_widget_destroy (GTK_WIDGET (window));
}

/* Create the splash screen itself */
void splash_screen ()
{
    /* The screen */
    splash_window = gtk_window_new (GTK_WINDOW_TOPLEVEL);

    /* The properties */
    gtk_window_set_type_hint        (GTK_WINDOW (splash_window), GDK_WINDOW_TYPE_HINT_SPLASHSCREEN);
    gtk_window_set_decorated        (GTK_WINDOW (splash_window), FALSE);
    gtk_window_set_position         (GTK_WINDOW (splash_window), GTK_WIN_POS_CENTER_ALWAYS);
    gtk_window_set_default_size     (GTK_WINDOW (splash_window), 300, 300);
    gtk_window_set_resizable        (GTK_WINDOW (splash_window), FALSE);
    gtk_window_set_title            (GTK_WINDOW (splash_window), "VadeTux [Cargando...]");
    gtk_container_set_border_width  (GTK_CONTAINER (splash_window), 0);

    /* The splash image */
    splash_image = gtk_image_new_from_file ("./imgs/splashscreen/end-splash.png");

    /* The vertical box */
    vbox = gtk_vbox_new (FALSE, 0);

    /* Create the progress bar and make it pulse */
    pbar = gtk_progress_bar_new ();
    gtk_progress_bar_pulse (GTK_PROGRESS_BAR (pbar));
    /* The timer in charge of the animation */
    timer = g_timeout_add (100, progress_timeout, pbar);

    /* Start the packing */
    gtk_container_add (GTK_CONTAINER (splash_window), vbox);
    gtk_box_pack_start (GTK_BOX (vbox), splash_image, FALSE, FALSE, 0);
    gtk_box_pack_start (GTK_BOX (vbox), pbar, FALSE, FALSE, 0);

    /* Show everything */
    gtk_widget_show_all (splash_window);

    get_page ("http://listadomedicamentos.aemps.gob.es/prescripcion.zip", "DB/prescripcion.zip");

    destroy_splash_screen (splash_window, timer);
}

EDIT: (most includes are for when I add an unzip function)

#include <curl/curl.h>
#include <zip.h>
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <errno.h>
#include <stdlib.h>
#include <unistd.h>

#include "db.h"

void get_page (const char *url, const char *file_name)
{
    CURL *easyhandle = curl_easy_init ();
    curl_easy_setopt (easyhandle, CURLOPT_URL, url);

    FILE *file = fopen (file_name, "w");

    curl_easy_setopt (easyhandle, CURLOPT_WRITEDATA, file);
    curl_easy_perform (easyhandle);

    curl_easy_cleanup (easyhandle);
    fclose (file);
}

The timer and destroy_splash_screen are statics that work good, and the get_page () is a CURL function. The problem is that, instead of following that order of (definitions; create window; paint window; do get_page; destroy window;) it will do (definitions; create window; do get_page; paint window; destroy window;). This way, the screen is empty during the download, and the window is destroyed before you can see anything.

I've been looking around and haven't found anything about this, how can I fix it so it follows the order I want it to have?

Upvotes: 0

Views: 175

Answers (1)

Here is an almost minimal example of a Gtk+ program with a worker thread. The program displays a progress bar and prints numbers to input for 10 seconds. You could do something else when the worker is done. However, since GTK+ itself is not thread safe, you should not access the widgets from any thread other from the one running the main loop.

#include <stdio.h>
#include <gtk/gtk.h>

gboolean stop_program(gpointer unused)
{
    /* Idle function run in the main thread. */
    gtk_main_loop();
    return FALSE;
}

gpointer worker_func(gpointer unused)
{
    /* This code runs in the worker thread. */
    for (int i = 0; i < 10; ++i) {
        printf("%d\n", i);
        g_usleep(1000000);
    }

    g_idle_add(stop_program, NULL);
    gtk_main_quit();

    return NULL;
}

gboolean progress_cb(gpointer user_data)
{
    gtk_progress_bar_pulse(GTK_PROGRESS_BAR(user_data));
    return TRUE;
}

int main(int argc, char *argv[])
{
    gtk_init(&argc, &argv);

    GtkWidget *window = gtk_window_new(GTK_WINDOW_TOPLEVEL);

    g_signal_connect(window, "delete_event", G_CALLBACK(gtk_main_quit), NULL);

    GtkWidget *box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 6);

    GtkWidget *progress = gtk_progress_bar_new();
    gtk_progress_bar_pulse(GTK_PROGRESS_BAR(progress));
    guint timer = g_timeout_add (100, progress_cb, progress);

    gtk_box_pack_start(GTK_BOX(box), progress, TRUE, TRUE, 6);
    gtk_container_add(GTK_CONTAINER(window), box);

    gtk_widget_show_all(window);

    /* Start the worker thread before starting the main loop. */
    GThread *thread = g_thread_new("worker thread", worker_func, NULL);

    gtk_main();

    /* Wait for the thread to finish. */
    g_thread_join(thread);

    return 0;
}

Upvotes: 1

Related Questions