Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Calling GTK_MAIN under Pthread(secondary thread) in C code

Tags:

c

gtk

glib

This is in my continuation of GTK understanding::

Is it right to call GTK_MAIN() under pthread from Main?? sample code ::

from main i call dispInit(argc, argv); from which i call g_thread_create(main_callback, NULL, FALSE, NULL);

** also i have not included g_idle_add in this code..this is just a reference code.

Please guide

#include <stdio.h>
#include <glib.h>
#include <gtk/gtk.h>
//#include "dispimage.h"
#include <windows.h>
#define sleep(n) Sleep(1000 * n)
GtkWidget* window;
void dispInit(int argc, char* argv[]);
void dispInfoPage(char* fileName, int duration);


gpointer main_callback(gpointer data)
{
    gtk_main();
    return 0;
}

void dispInit(int argc, char* argv[])
{
    gdk_threads_init();
    gdk_threads_enter();
    printf("Initializing the display library\n");
    gtk_init(&argc, &argv);
    window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
    gtk_window_resize(GTK_WINDOW(window), 640, 480);
    gtk_window_set_default_size(GTK_WINDOW(window), 640, 480);
    gtk_widget_realize( window );
    gtk_window_set_decorated(GTK_WINDOW(window), FALSE);
    g_thread_create(main_callback, NULL, FALSE, NULL);
    gdk_threads_leave();
}

void dispInfoPage(char* fileName, int duration)
{
    int index;
    gdk_threads_enter();
    printf("Initializing dispInfoPage\n");
    destroyWidget();
    printf("Initializing dispInfoPage1\n");
    GtkWidget *image;
    image = gtk_image_new_from_file(fileName);
    printf("Initializing dispInfoPage2\n");
    gtk_container_add(GTK_CONTAINER(window), image);
    gtk_widget_show(image);
    gtk_widget_show(window);
    printf("Initializing dispInfoPage4\n");
    printf("Initializing dispInfoPage5\n");
    gdk_threads_leave();
    printf("Initializing dispInfoPage6\n");
}

void destroyWidget()
{
    GList *children, *iter;
    struct WidgetsAlive *temp, *prev, *next, *depTemp;
    children = gtk_container_get_children(GTK_CONTAINER(window));
    for(iter = children; iter != NULL; iter = g_list_next(iter)){
        gtk_container_remove(GTK_CONTAINER(window),GTK_WIDGET(iter->data));
        printf("Deleting Widget\n");
    }
    g_list_free(iter);
    g_list_free(children);

}


int dispTextPage(char* fileName, int isJustifyCenter)
{
    int index;
    GtkWidget *textv;
    GdkWindow *textv_window;
    GdkPixmap *pixmap = NULL;
    GtkTextBuffer *textBuffer;
    gdk_threads_enter();
    GdkColor color;
    char debugBuf[128] = { '\0' };
    char newfName[100]={'\0'};
    char ext[4]={'\0'};
    char temp[100]={'\0'};
    int i;
    FILE * fd;
    destroyWidget();
    textBuffer = gtk_text_buffer_new(NULL);
    textv = gtk_text_view_new_with_buffer(textBuffer);
    gtk_text_view_set_left_margin(GTK_TEXT_VIEW(textv), 22);
    gtk_text_view_set_right_margin(GTK_TEXT_VIEW(textv), 20);
    gtk_text_view_set_pixels_above_lines(GTK_TEXT_VIEW(textv),1);
    gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(textv), GTK_WRAP_CHAR);
    if (isJustifyCenter == 1)
    {
        gtk_text_view_set_justification(GTK_TEXT_VIEW(textv), GTK_JUSTIFY_CENTER);
    }
    else
    {
        gtk_text_view_set_justification(GTK_TEXT_VIEW(textv), GTK_JUSTIFY_LEFT);
    }
    gtk_text_view_set_editable(GTK_TEXT_VIEW(textv), FALSE);
    gtk_text_view_set_cursor_visible(GTK_TEXT_VIEW(textv), FALSE);
    printf("tttt0");
    gtk_container_add(GTK_CONTAINER(window), textv);
    printf("tttt1");
    textv_window = gtk_text_view_get_window (GTK_TEXT_VIEW (textv),
                                           GTK_TEXT_WINDOW_TEXT);
    gdk_color_parse ("#68604d", &color);
    pixmap = gdk_pixmap_create_from_xpm ((GdkDrawable *) textv_window, NULL,
                                       &color, fileName);
    gdk_window_set_back_pixmap (textv_window, pixmap, FALSE);
    g_object_unref(pixmap);

    textBuffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(textv));

    gtk_text_buffer_create_tag (textBuffer, "Red", "foreground", "Red", NULL);
    gtk_text_buffer_create_tag (textBuffer, "RedBold","foreground", "Red",NULL);
      gtk_text_buffer_create_tag(textBuffer, "gray_bg", "background", "gray", NULL);
      gtk_text_buffer_create_tag(textBuffer, "italic",  "style", PANGO_STYLE_ITALIC, NULL);
      gtk_text_buffer_create_tag(textBuffer, "bold","weight", PANGO_WEIGHT_BOLD, NULL);
    gtk_text_buffer_create_tag (textBuffer, "RedFontWeight", "weight", 1000,NULL);
    gtk_text_buffer_create_tag (textBuffer, "RedBoldFontWeight","weight", 1000,NULL);
    gtk_widget_show(textv);
    gtk_widget_show(window);
    gdk_threads_leave();
    return index;
}

void *fsmThread_RunFunction()
{
    int pollMsgRetVal = -1;
    printf("Now enter into for image");
    dispInfoPage("../images/givefp.gif",1);
    sleep(5);
    dispInfoPage("../images/bootup.gif",1);
    sleep(5);
    dispInfoPage("../images/givefp.gif",1);
    sleep(5);
    dispInfoPage("../images/bootup.gif",1);
    sleep(5);
    printf("Now enter into for disptext");
    dispTextPage("",0);
    printf("Now exit for disptext");
}

int main(int argc, char *argv[])
{
    GThread *fsmThreadId;
    GError *error = NULL;
    g_thread_init(NULL);
    dispInit(argc, argv);
    dispInfoPage("../images/bootup.gif",1);
    sleep(5);
    printf("Now creat ethread ");
    fsmThreadId = g_thread_create(fsmThread_RunFunction,NULL,TRUE,&error);
    if (error) {
      fflush(stderr);
      exit(1);
    }
    g_thread_join(fsmThreadId);
    sleep(2);

    printf("ENd of main");
    return 0;
}
like image 960
Ragav Avatar asked May 12 '26 23:05

Ragav


1 Answers

The short answer: yes, you can call gtk_main() from a thread other than the main C thread, as long as you consistently call all GTK API functions from the same thread throughout the lifetime of the process. More details follow.

According to the documentation, GTK and GDK are not thread-safe (they cannot be concurrently called from multiple threads), but they are thread-aware — they provide locking functions such as gdk_threads_enter and gdk_threads_leave that can be used to synchronize GTK calls accross multiple threads. However, the documentation goes on to say that "with the Win32 backend, GDK and GTK+ calls should not be attempted from multiple threads at all." So, if you care about portability to Windows, you will want to avoid attempting to call GTK API calls from multiple threads. Additionally, GTK 3 completely deprecated the use of the threading locks.

There is, however, one way to safely call into GTK from multiple threads that works on all architectures: place the GTK calls in a function and pass it as callback to g_idle_add (without any special locking) — from any thread. It will schedule the callback to be invoked by the GTK main loop, in whatever thread is running it. This is documented at the end of the description section of the documentation, above the start of the details section.

A word on terminology: the word "main thread" in C normally refers to the thread that runs the C main() function. In a GTK context, the "main thread" often confusingly refers to the thread running the GTK main loop. While the two can be (and typically are) one and the same, GTK doesn't really care what thread you call the main loop from, as long as you call all GTK functions (including gtk_main) from the same one. To avoid confusion, it is best to refer to this thread as the GTK thread, the main loop thread, or the GUI thread.

like image 123
user4815162342 Avatar answered May 15 '26 17:05

user4815162342



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!