Search code examples
gtkprogram-entry-point

GTK Main blocking Others threads.How to solve


I have 2 threads

1)Holds the GTK main and gtk screen display codes (code is explained below) 2)generates key events according to user rquirement

if() block i ported into my code. but result is same. Once the signal is generated .after that its not coming to 2nd thread(signal generation thread). Have put debug prints ,but its not happening Seems its waiting on gtk_main on first thread.

What my code is :

void S1(void)
{
 GtkWidget *Win_1;
 GtkBuilder *builder;        
 builder = gtk_builder_new ();
 gtk_builder_add_from_file (builder, "/home/glade/glade1.glade", NULL);
 window = GTK_WIDGET (gtk_builder_get_object (builder, "Win_1"));        
 g_signal_connect_swapped(G_OBJECT(window), "destroy",   G_CALLBACK(gtk_main_quit), G_OBJECT(window));
 g_signal_connect (G_OBJECT (window), "key_press_event", G_CALLBACK(kp_event), NULL);
 gtk_widget_show_all(window);
 gtk_main(); 

}

kp_event()
{
    gtk_widget_destroy (window);            
    S2();
}

S2 is same as S1,only screen item difference.Am calling S2() from keypress handler of S1 & vice versa. Since i have no keyboards attached,need to change two screens base on some user input via sockets or something.


Solution

  • You may need to call gtk_main() just one time, and use gtk_widget_hide() and gtk_window_present(), instead of gtk_widget_destroy(), declaring window1 and window2 as global variables, and creating the two windows at startup. A sample code:

    GtkWidget * window1;
    GtkWidget * window2;
    
    void S1() {
      // create the window
    
      window1 = GTK_WIDGET (gtk_builder_get_object (builder, "Win_1"));  
    
      // do not call gtk_main()
    }
    
    void S2() {
      // create the window
    
      window2 = GTK_WIDGET (gtk_builder_get_object (builder, "Win_2"));  
    
      // do not call gtk_main()
    }
    
    kp_event_S1() {
        gtk_widget_hide(window1);
        gtk_window_present(GTK_WINDOW(window2));            
    }
    
    kp_event_S2() {
        gtk_widget_hide(window2);
        gtk_window_present(GTK_WINDOW(window1));            
    }
    
    int main() {
      gtk_init();
    
      S1();
      S2();
      gtk_widget_hide(window2);
      gtk_main();
    }
    

    If you don't want to use global variables, you can do:

    GtkWidget * S1() {
      // create the window
    
      GtkWidget * window1 = GTK_WIDGET (gtk_builder_get_object (builder, "Win_1"));  
    
      return window1;
    }
    
    GtkWidget * S2() {
      // create the window
    
      GtkWidget * window2 = GTK_WIDGET (gtk_builder_get_object (builder, "Win_2"));  
    
      return window2;
    }
    
    gboolean kp_event_S1(GtkWidget * window, GdkEvent e, gpointer user_data) {
      gtk_widget_hide(window);
      gtk_window_present(GTK_WINDOW(user_data));            
    }
    
    gboolean kp_event_S2(GtkWidget * window, GdkEvent e, gpointer user_data) {
      gtk_widget_hide(window);
      gtk_window_present(GTK_WINDOW(user_data));            
    }
    
    int main() {
      gtk_init();
    
      GtkWidget * w1 = S1();
      GtkWidget * w2 = S2();
      gtk_widget_hide(w2);
    
      g_signal_connect (G_OBJECT (w1), "key-press-event", G_CALLBACK(kp_event_S1), (gpointer)w2);
      g_signal_connect (G_OBJECT (w2), "key-press-event", G_CALLBACK(kp_event_S2), (gpointer)w1);
      gtk_main();
    }