GUI signals from a thread (GTK+-3.10)



Greetings gtk-app-devel-list.

I'm a newbie GTK+ developer and I have encountered with a problem.

I tried to create a DC Motor Transient process calculation as a
practice programm for learning.
I've wanted to have a feedback of the calculation process on a progress bar.
Documentation say that "the threading support has been deprecated in
GTK+ 3.6. Instead of calling GTK+ directly from multiple threads, it
is recommended to use g_idle_add(), g_main_context_invoke() and
similar functions to make these calls from the main thread instead".

I have no idea how g_main_context_invoke() could be usefull for that
and g_idle_add() is totally wrong: because if something heavy in the
function happens, then the GUI hangs anyway.

I don't adequate way to transfer status report from a thread, that
blocks a lot, for example very laggy socket connections.

Here's a minimal programm. Somehow GTK+ calls from thread are working.
How sinfull is that?

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

struct CallbackObject
{
    GtkWidget *win;
    GtkWidget *button;
    GtkWidget *progress;
};

gpointer thread_func( struct CallbackObject *callobj );
static void startstop_thread (GtkWidget *wid, struct CallbackObject *callobj);

GThread *pthread = NULL;
gboolean thread_run = FALSE;

const gchar *label_start = "Start thread";
const gchar *label_stop = "Stop thread";

gpointer thread_func( struct CallbackObject *callobj )
{
  gdouble x = 0.0;
  while (x < 1.0 && thread_run == TRUE)
  {
    usleep (20*1000);
    x += 1.0 / 50;

    gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR (callobj->progress), x);
  }

  thread_run = FALSE;
  pthread = NULL;
  gtk_button_set_label (GTK_BUTTON (callobj->button), label_start);

  return NULL;
}

static void startstop_thread (GtkWidget *wid, struct CallbackObject *callobj)
{
  gpointer user_data = callobj;

  if (thread_run == FALSE)
  {
    thread_run = TRUE;
    pthread = g_thread_new ("thread", (GThreadFunc) thread_func, user_data);
    gtk_button_set_label (GTK_BUTTON (callobj->button), label_stop);
  }
  else
  {
    thread_run = FALSE;
    g_thread_join (pthread);
    pthread = NULL;
    gtk_button_set_label (GTK_BUTTON (callobj->button), label_start);
  }
}

int main (int argc, char *argv[])
{
  GtkWidget *button = NULL;
  GtkWidget *vbox = NULL;
  struct CallbackObject *callobj = NULL;

  /* Initialize GTK+ */
  g_log_set_handler ("Gtk", G_LOG_LEVEL_WARNING, (GLogFunc) gtk_false, NULL);
  gtk_init (&argc, &argv);
  g_log_set_handler ("Gtk", G_LOG_LEVEL_WARNING, g_log_default_handler, NULL);

  callobj = g_malloc (sizeof(struct CallbackObject));

  /* Create the main window */
  callobj->win = gtk_window_new (GTK_WINDOW_TOPLEVEL);
  gtk_container_set_border_width (GTK_CONTAINER (callobj->win), 8);
  gtk_window_set_title (GTK_WINDOW (callobj->win), "GTK+-3.10.7-1 Threads");
  gtk_window_set_position (GTK_WINDOW (callobj->win), GTK_WIN_POS_CENTER);
  gtk_widget_realize (callobj->win);
  g_signal_connect (callobj->win, "destroy", gtk_main_quit, NULL);

  /* Create a vertical box with buttons */
  vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 8);
  gtk_container_add (GTK_CONTAINER (callobj->win), vbox);

  callobj->progress = gtk_progress_bar_new ();
  gtk_progress_bar_set_show_text (GTK_PROGRESS_BAR (callobj->progress), TRUE);
  gtk_box_pack_start (GTK_BOX (vbox), callobj->progress, TRUE, TRUE, 0);

  callobj->button = gtk_button_new_with_label ("Start thread");
  g_signal_connect (G_OBJECT (callobj->button), "clicked", G_CALLBACK
(startstop_thread), (gpointer) callobj);
  gtk_box_pack_start (GTK_BOX (vbox), callobj->button, TRUE, TRUE, 0);

  button = gtk_button_new_with_label ("Close");
  g_signal_connect (button, "clicked", gtk_main_quit, NULL);
  gtk_box_pack_start (GTK_BOX (vbox), button, TRUE, TRUE, 0);

  /* Enter the main loop */
  gtk_widget_show_all (callobj->win);
  gtk_main ();

  g_free (callobj);

  return 0;
}


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]