Threaded gtk+ example
Sept 23, 2011 5:09:15 GMT 1
Post by 2lss on Sept 23, 2011 5:09:15 GMT 1
Hi everyone,
I want to use pthreads with a Bacon/gtk+ project I am working on so I made this example.
I used the example program "thread1.bac" as a base and added the gui.
It was slightly difficult since gtk won't play nice with pthreads without changing things around a bit.
I have yet to test with Hug but I can't imagine why it wouldn't work.
Have fun!
Last updated: 9/26/11
I want to use pthreads with a Bacon/gtk+ project I am working on so I made this example.
I used the example program "thread1.bac" as a base and added the gui.
It was slightly difficult since gtk won't play nice with pthreads without changing things around a bit.
I have yet to test with Hug but I can't imagine why it wouldn't work.
Have fun!
Last updated: 9/26/11
' An example program showing how to use pthreads with Gtk+ in BaCon
INCLUDE "pthread.bac"
gdk$ = "libgdk-x11-2.0.so"
gob$ = "libgobject-2.0.so"
gtk$ = "libgtk-x11-2.0.so"
IMPORT "gdk_threads_enter" FROM gdk$ TYPE void
IMPORT "gdk_threads_init" FROM gdk$ TYPE void
IMPORT "gdk_threads_leave" FROM gdk$ TYPE void
IMPORT "g_signal_connect_data(long,char*,void*,long,long,int)" FROM gob$ TYPE void
IMPORT "g_thread_init(char*)" FROM gob$ TYPE void
IMPORT "gtk_button_new_with_mnemonic(char*)" FROM gtk$ TYPE long
IMPORT "gtk_container_add(long,long)" FROM gtk$ TYPE void
IMPORT "gtk_editable_set_editable(long,int)" FROM gtk$ TYPE void
IMPORT "gtk_entry_get_text(long)" FROM gtk$ TYPE char*
IMPORT "gtk_entry_new" FROM gtk$ TYPE long
IMPORT "gtk_entry_set_text(long,char*)" FROM gtk$ TYPE void
IMPORT "gtk_init(int*,void*)" FROM gtk$ TYPE void
IMPORT "gtk_label_new(char*)" FROM gtk$ TYPE long
IMPORT "gtk_main" FROM gtk$ TYPE void
IMPORT "gtk_message_dialog_new(long,int,int,int,char*,...)" FROM gtk$ TYPE long
IMPORT "gtk_table_attach_defaults(long,long,int,int,int,int)" FROM gtk$ TYPE void
IMPORT "gtk_table_new(int,int,int)" FROM gtk$ TYPE long
IMPORT "gtk_widget_hide(long)" FROM gtk$ TYPE void
IMPORT "gtk_widget_hide_on_delete(long)" FROM gtk$ TYPE int
IMPORT "gtk_widget_set_size_request(long,int,int)" FROM gtk$ TYPE void
IMPORT "gtk_widget_show(long)" FROM gtk$ TYPE void
IMPORT "gtk_widget_show_all(long)" FROM gtk$ TYPE void
IMPORT "gtk_window_new(int)" FROM gtk$ TYPE long
IMPORT "gtk_window_set_position(long,int)" FROM gtk$ TYPE void
IMPORT "gtk_window_set_title(long,char*)" FROM gtk$ TYPE void
GLOBAL STOP_BUTTON
CONST NUM_THREADS = 3
CONST SLEEP_INT = 500
CONST GTK_WINDOW_TOPLEVEL = 0
CONST GTK_WIN_POS_CENTER = 1
DECLARE entries[NUM_THREADS]
DECLARE threads[NUM_THREADS]
DECLARE NUL TYPE STRING
DECLARE mutex TYPE pthread_mutex_t
DECLARE attr TYPE pthread_attr_t
pthread_attr_init(ADDRESS(attr))
pthread_attr_setdetachstate(ADDRESS(attr), PTHREAD_CREATE_JOINABLE)
pthread_mutex_init(ADDRESS(mutex), 0)
'-------------------------------------------------------------------------------
SUB dostuff(NUMBER val)
LOCAL num
num = VAL(gtk_entry_get_text(entries[val]))
' Not Sure if gdk takes care of mutex. Seems to work well with mutex lines disabled
' pthread_mutex_lock(ADDRESS(mutex))
WHILE TRUE DO
' Note: When using pthreads with gtk, you MUST encapsulate gtk calls with "gdk_threads_enter" and "gdk_threads_leave."
' This only applies to gtk calls that are outside of the main thread.
gdk_threads_enter
gtk_entry_set_text(entries[val], STR$(num))
gdk_threads_leave
INCR num
SLEEP (val+1)*SLEEP_INT
IF STOP_BUTTON THEN BREAK
WEND
PRINT "Thread ", val, " exit!"
' Leaving these commented out for now as well.
' pthread_mutex_unlock(ADDRESS(mutex))
' pthread_mutex_destroy(ADDRESS(mutex))
pthread_exit(0)
END SUB
'-------------------------------------------------------------------------------
SUB ok_handle
gtk_widget_hide(button1)
gtk_widget_show(button2)
STOP_BUTTON = 0
FOR x = 0 TO NUM_THREADS-1
pthread_mutex_lock(ADDRESS(mutex))
PRINT "In main: creating thread ", x
pthread_mutex_unlock(ADDRESS(mutex))
rc = pthread_create(ADDRESS(threads[x]), ADDRESS(attr), dostuff, x)
NEXT
IF rc THEN
PRINT "ERROR: return code from pthread_create() is ", rc
END -1
END IF
END SUB
'-------------------------------------------------------------------------------
SUB stop_handle
STOP_BUTTON = 1
' Give time for threads to exit
SLEEP 1000
gtk_widget_hide(button2)
gtk_widget_show(button1)
END SUB
'-------------------------------------------------------------------------------
'TRAP LOCAL
' Note: for gtk you MUST call "g_thread_init" followed by "gdk_threads_init."
' The calls to "gdk_threads_enter" and "gdk_threads_leave" may be overkill at this point.
g_thread_init(NUL)
gdk_threads_init
gdk_threads_enter
gtk_init(0, 0)
win = gtk_window_new(GTK_WINDOW_TOPLEVEL)
gtk_window_set_title(win, "pthreads with GTK+ !!!!")
layer = gtk_table_new(11, 11, 1)
gtk_container_add(win, layer)
gtk_widget_set_size_request(win, 400, 200)
g_signal_connect_data(win, "delete-event", exit, 0, 0, 0)
button1 = gtk_button_new_with_mnemonic("Start!")
gtk_table_attach_defaults(layer, button1, 4, 7, 8, 10)
g_signal_connect_data(button1, "clicked", ok_handle, 0, 0, 0)
button2 = gtk_button_new_with_mnemonic("Stop!")
gtk_table_attach_defaults(layer, button2, 4, 7, 8, 10)
gtk_widget_hide(button2)
g_signal_connect_data(button2, "clicked", stop_handle, 0, 0, 0)
label1 = gtk_label_new("First Thread")
gtk_table_attach_defaults(layer, label1, 0, 3, 1, 2)
label2 = gtk_label_new("Second Thread")
gtk_table_attach_defaults(layer, label2, 3, 8, 1, 2)
label3 = gtk_label_new("Third Thread")
gtk_table_attach_defaults(layer, label3, 8, 11, 1, 2)
entries[0] = gtk_entry_new()
gtk_editable_set_editable(entries[0], 0)
gtk_table_attach_defaults(layer, entries[0], 1, 2, 4, 6)
entries[1] = gtk_entry_new()
gtk_editable_set_editable(entries[1], 0)
gtk_table_attach_defaults(layer, entries[1], 5, 6, 4, 6)
entries[2] = gtk_entry_new()
gtk_editable_set_editable(entries[2], 0)
gtk_table_attach_defaults(layer, entries[2], 9, 10, 4, 6)
gtk_widget_show_all(win)
gtk_main
gdk_threads_leave