É normal minha console ficar travada quando eu fecho um programa? Claro que não.
Se você abrir outro terminal e usar um ps, vai ver que o aplicativo continua em execução. Quando fechamos a janela, não quer dizer que encerramos o aplicativo, pelo menos não se não definirmos que é dessa forma que o programa deve se comportar.
Lembra do main loop? Ele continua esperando eventos, apesar de fecharmos a janela.
Se queremos que o programa seja encerrado quando fechamos a janela, precisamos encerrar o main loop, daí então ele vai executar tudo que está depois do gtk_main(); o que no nosso caso é o return 0;.
Edite o arquivo teste.c e acrescente mais uma linha:
#include <stdio.h>
#include <gtk/gtk.h>
int main(int argc, char **argv) {
GtkWidget *janela;
gtk_init(&argc, &argv);
janela=gtk_window_new(GTK_WINDOW_TOPLEVEL);
g_signal_connect(G_OBJECT(janela), "destroy", G_CALLBACK(gtk_main_quit), NULL);
gtk_widget_show_all(janela);
gtk_main();
return 0;
}
A linha que acrescentamos conecta um sinal ao objeto janela. Esse sinal espera que o objeto janela emita um evento do tipo "destroy" e quando isso acontece chama a função gtk_main_quit, e não passa nenhum argumento para essa função(NULL).
Recompile o programa e tente executá-lo novamente.
Agora o programa deve se encerrar quando a janela é fechada. Isso ocorre porque quando a janela é fechada ela emite um sinal "destroy", que faz com que a função gtk_main_quit() seja executada, e essa função encerra o main loop.
Conectar eventos é a maneira que usamos para fazer qualquer coisa em GTK+ (e na maioria das bibliotecas gráficas). Quando um evento ocorre, ele entra na fila do loop de eventos (main loop), que vai executando as funções conectadas a cada evento (se houver alguma função 'conectada' ao evento).