Indice

Creazione automatica dello scheletro per applicazioni gtkbuilder

Autore: Fabio Di Matteo
Ultima revisione: 19/02/2018 - 15:34

Sviluppare con le librerie gtk puo' risultare tedioso nel caso in cui ogni volta ci si deve creare a mano il sorgente base, i vari script per la generazione del makefile e la struttura delle directory del progetto. Vedremo in questo articolo di creare uno script che possa automatizzare il tutto.
Utilizzeremo il tool CMake per generare il makefile multipiattaforma.

Utilizzo dello script

L'utilizzo dello script e' immediato, basta infatti impartire da console i seguenti comandi:

./auto-gtk <nome-progetto> 

Versione con Meson , file delle risorse e supporto all'installazione

#!/bin/sh
 
AUTHOR="Fabio Di Matteo"
VERSION="0.1.2"
 
 
#Controllo se e' stato fornito il nome del progetto
if [ "$1" = "" ];then
	echo "E' necessario fornire il nome del progetto come parametro."
	exit 1 ;
fi
 
#Se la directory del progetto esiste gia' esco.
mkdir $1 2>/dev/null
if [ "$?" != 0 ];then
	echo "Il progetto esiste."
	exit 1 ;
fi
 
cd $1
 
 
echo "Genero il main.c ..."
echo "#include <gtk/gtk.h>                                      
 
GtkBuilder *xml;                                              
int c=0;
 
 
static void count_clicks (GtkWidget *widget,gpointer data)
{
 
  c++;
  char* txt=g_strdup_printf(\" %d clicked!\", c);
  gtk_label_set_text(GTK_LABEL(data),txt);
}
 
 
 
int
main (int argc, char *argv[])
{
 
 
 
	gtk_init (&argc, &argv);
	GError* error = NULL;
	xml = gtk_builder_new ();
	if (!gtk_builder_add_from_resource  (xml, \"/org/myapp/res/gui.ui\", &error))
	  {
		g_warning (\"Error on  load builder file: %s\", error->message);
		g_error_free (error);
	  }
	GObject* window1=gtk_builder_get_object (xml,\"window1\");
	GObject* button1=gtk_builder_get_object (xml,\"button1\");
	GObject* label1=gtk_builder_get_object (xml,\"label1\");
	g_signal_connect (button1, \"clicked\", G_CALLBACK (count_clicks), label1);
	g_signal_connect (window1, \"destroy\", G_CALLBACK (gtk_main_quit), NULL);
 
	gtk_window_present(GTK_WINDOW(window1));
	gtk_main ();
 
  return 0;
 
}
 
 
" > main.c
 
echo "Genero il file delle risorse..."
echo "<?xml version=\"1.0\" encoding=\"UTF-8\"?>
		<gresources>
		  <gresource prefix=\"/org/myapp/res\">
			<file>gui.ui</file>
		  </gresource>
		</gresources>" >resource.xml
 
echo "Genero il file dell'interfaccia Glade..."
echo '<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.40.0 -->
<interface>
  <requires lib="gtk+" version="3.20"/>
  <object class="GtkWindow" id="window1">
    <property name="name">window1</property>
    <property name="visible">True</property>
    <property name="can-focus">False</property>
    <property name="title" translatable="yes">Test</property>
    <child>
      <!-- n-columns=1 n-rows=2 -->
      <object class="GtkGrid" id="grid1">
        <property name="visible">True</property>
        <property name="can-focus">False</property>
        <property name="column-homogeneous">True</property>
        <child>
          <object class="GtkLabel" id="label1">
            <property name="visible">True</property>
            <property name="can-focus">False</property>
            <property name="label" translatable="yes">label1</property>
            <attributes>
              <attribute name="scale" value="4"/>
            </attributes>
          </object>
          <packing>
            <property name="left-attach">0</property>
            <property name="top-attach">0</property>
          </packing>
        </child>
        <child>
          <object class="GtkButton" id="button1">
            <property name="label" translatable="yes">button</property>
            <property name="visible">True</property>
            <property name="can-focus">False</property>
            <property name="receives-default">True</property>
          </object>
          <packing>
            <property name="left-attach">0</property>
            <property name="top-attach">1</property>
          </packing>
        </child>
      </object>
    </child>
  </object>
</interface> ' >gui.ui		
 
echo "Genero il meson.build"
 
 
echo "
 
project('main', 'c')
 
gnome = import('gnome')
myresources = gnome.compile_resources(
    'my-resource', 'resource.xml',
     source_dir: '.',
    c_name: 'myresource'
)
 
 
extra_args= ['-rdynamic']
gtkdep = dependency('gtk+-3.0')
gthread = dependency('gthread-2.0')
gmodule = dependency('gmodule-2.0')
 
executable('main', myresources,'main.c', 
			dependencies :[gtkdep, gthread, gmodule ],
			c_args : extra_args, 
			install : false, 
			install_dir : '/usr/bin')
 
 
 
 
">meson.build
 
echo "Per configurare il progetto : meson setup <builddir>"
echo "Per compilare il progetto: cd <builddir> ; ninja"
echo "Per installare il progetto: sudo ninja install"

Versione CMake (senza file risorse)

per creare la directory del progetto con dentro tutte le sottodirectory e il file CMakeLists.txt .

drwxr-xr-x 2 fabio fabio 4096 2009-12-22 15:32 bin
-rw-r--r-- 1 fabio fabio 1050 2009-12-22 15:32 CMakeLists.txt
-rwxr-xr-x 1 fabio fabio   18 2009-12-22 15:32 configure
drwxr-xr-x 3 fabio fabio 4096 2009-12-22 15:32 share
drwxr-xr-x 2 fabio fabio 4096 2009-12-22 15:32 src

dentro bin verra posizionato l'eseguibile ;
in src sta il sorgente;
mentre in share c'e' una directory con lo stesso nome del progetto che verra copiata in fase di installazione in $PREFIX/share/<nome progetto>. In questa directory e' contenuto il file xml di Glade ;

Compilazione e installazione del progetto

Quando vorremo compilare e installare il progetto basteranno i seguenti comandi:

cmake . 
make
sudo make install

oppure

./configure 
make
sudo make install

Qualora si vogliano cambiare le opzioni di configurazione e' sufficente lanciare il comando

ccmake .

se il comando ccmake non e' installato lo si puo' installare in ubuntu con sudo apt-get install cmake-curses-gui

Lo script

#!/bin/sh
 
AUTHOR="Fabio Di Matteo"
VERSION="0.1.0"
 
#Controllo se e' stato fornito il nome del progetto
if [ "$1" = "" ];then
	echo "E' necessario fornire il nome del progetto come parametro."
	exit 1 ;
fi
 
#Se la directory del progetto esiste gia' esco.
mkdir $1 2>/dev/null
if [ "$?" != 0 ];then
	echo "Il progetto esiste."
	exit 1 ;
fi
 
cd $1
mkdir bin 
mkdir share && mkdir share/$1
 
echo "Genero il CMakeLists.txt ...\n"
 
echo "cmake_minimum_required(VERSION 2.6)" > CMakeLists.txt
 
echo "PROJECT($1)" >> CMakeLists.txt
echo "SET (AUTHOR \"$AUTHOR\" INTERNAL \"Author\")" >> CMakeLists.txt
echo "SET (VERSION \"$VERSION\")" >> CMakeLists.txt
 
echo "INCLUDE (FindPkgConfig)" >> CMakeLists.txt
 
echo "IF (NOT PKG_CONFIG_FOUND)" >> CMakeLists.txt
echo "	MESSAGE (FATAL_ERROR \"pkg-config not found...\") " >> CMakeLists.txt
echo "ENDIF (NOT PKG_CONFIG_FOUND)" >> CMakeLists.txt
 
echo "pkg_check_modules (GTK REQUIRED gtk+-2.0>=2.6)" >> CMakeLists.txt
 
echo "IF (NOT GTK_FOUND)" >> CMakeLists.txt
echo "	MESSAGE(FATAL_ERROR \"You don't seem to have gtk >= 2.6 development libraries installed...\")" >> CMakeLists.txt
echo "ENDIF (NOT GTK_FOUND)" >> CMakeLists.txt
 
echo "ADD_DEFINITIONS()" >> CMakeLists.txt
 
echo "INCLUDE_DIRECTORIES (. \${GTK_INCLUDE_DIRS})" >> CMakeLists.txt
 
echo "LINK_DIRECTORIES (\${GTK_LIBRARY_DIRS} )" >> CMakeLists.txt
echo "LINK_LIBRARIES (\${GTK_LIBRARIES} )" >> CMakeLists.txt
 
echo "#Indichiamo dove sara' messo l'eseguibile" >>CMakeLists.txt
echo "ADD_EXECUTABLE( bin/$1 src/main.c)" >> CMakeLists.txt
 
echo "#Se se si ha bisogno di eventuali dipendenze fornite da noi stessi" >> CMakeLists.txt
echo "#ADD_DEPENDENCIES ($1 src/main.c)" >> CMakeLists.txt
 
 
echo "#Variabili per le directory di installazione" >> CMakeLists.txt
echo "#ADD_DEFINITIONS (-DVERSION=\\\"\${VERSION}\\\")" >> CMakeLists.txt
echo "#ADD_DEFINITIONS (-DDATADIR=\\\"\${CMAKE_INSTALL_PREFIX}/share\\\")" >> CMakeLists.txt
 
 
echo "#Copia file per l'installazione" >> CMakeLists.txt
echo "#ADD_SUBDIRECTORY (src)" >> CMakeLists.txt
echo "INSTALL (TARGETS bin/$1 DESTINATION bin)" >> CMakeLists.txt
echo "INSTALL (DIRECTORY share/$1 DESTINATION share)" >> CMakeLists.txt
 
 
echo "#!/bin/sh" > configure
echo "cmake ." >> configure
chmod 755 configure
 
echo "Genero il main.c"
mkdir src && cd src
 
 
 
 
echo "#include <gtk/gtk.h>                                                //includo le librerie gtk e glade.
 
GtkBuilder *xml;                                                 //questo è il puntatore al file xml che contiene l'interfaccia  
GtkWidget  *widget;                                              //questa variabile serve per recuperare di volta in volta il  
                                                                //  widget (ovvero l'oggetto ) che vogliamo usare
 
 
 
void on_MainWindow_delete_event(GtkWidget *widget, gpointer user_data)        //altra callback associata alla chiusura della 
{                                                                         // finestra 
    gtk_main_quit();
}
 
 
 
int
main (int argc, char *argv[])
{
  	gtk_init (&argc, &argv);
	gchar* base;
	gchar* glade_file;
 
	if (g_find_program_in_path (\"$1\")==NULL){
		/*Ricava il percorso dell'eseguibile, senza il nome del file*/ 
		base = g_path_get_dirname(argv[0]);
 
		/*Concatena il percorso base al nome file gui.glade */
		glade_file = g_build_filename (base,\"../share/$1\", \"gui.glade\", NULL);
	}else{
		base = g_path_get_dirname(g_find_program_in_path (\"$1\"));
		glade_file = g_build_filename (base,\"../share/$1\", \"gui.glade\", NULL);
	}	
 
    /*Infine carica come disolito il file dell'interfaccia */
    GError* error = NULL;
	xml = gtk_builder_new ();
	if (!gtk_builder_add_from_file (xml, glade_file, &error))
	  {
		g_warning (\"Couldn't load builder file: %s\", error->message);
		g_error_free (error);
	  }
 
 
	 /* connette tutti gli eventi dei widget alle rispettive funzioni */
   	 gtk_builder_connect_signals (xml, NULL);
 
 
      	/* Avvia il ciclo principale delle gtAvvia il ciclo principale delle gtk*/ 
	gtk_main ();
 
  return 0;
 
}" > main.c
 
#scrivo il file della GUI
cd ../share/$1
 
echo "<?xml version=\"1.0\"?>
<interface>
  <requires lib=\"gtk+\" version=\"2.16\"/>
  <!-- interface-naming-policy project-wide -->
  <object class=\"GtkWindow\" id=\"MainWindow\">
	<property name=\"visible\">True</property>
    <signal name=\"delete_event\" handler=\"on_MainWindow_delete_event\"/>
    <child>
      <placeholder/>
    </child>
  </object>
</interface>
" > gui.glade

Creazione di uno scheletro per applicazioni che includono il file della gui dentro l'eseguibile

Versione GTK+2

#!/bin/sh
 
AUTHOR="Fabio Di Matteo"
VERSION="0.1.0"
 
 
#Controllo se e' stato fornito il nome del progetto
if [ "$1" = "" ];then
	echo "E' necessario fornire il nome del progetto come parametro."
	exit 1 ;
fi
 
#Se la directory del progetto esiste gia' esco.
mkdir $1 2>/dev/null
if [ "$?" != 0 ];then
	echo "Il progetto esiste."
	exit 1 ;
fi
 
cd $1
 
 
echo "Genero il main.c ..."
echo "#include <gtk/gtk.h>                                                //includo le librerie gtk e glade.
 
GtkBuilder *xml;                                                 //questo è il puntatore al file xml che contiene l'interfaccia  
GtkWidget  *widget;                                              //questa variabile serve per recuperare di volta in volta il  
                                                                //  widget (ovvero l'oggetto ) che vogliamo usare
 
 
 
void on_MainWindow_delete_event(GtkWidget *widget, gpointer user_data)        //altra callback associata alla chiusura della 
{                                                                         // finestra 
    gtk_main_quit();
}
 
 
 
int
main (int argc, char *argv[])
{
  	gtk_init (&argc, &argv);
  	GError* error = NULL;
	gchar* glade_file = g_build_filename(g_get_tmp_dir(),\"gui.xml\", NULL);;
 
	// Copio il file dalla gui dalle risorse a una cartella temporanea
	// (le gtk+2 non possono caricare direttamente il file).
	GFile*  mySRC =  g_file_new_for_uri(\"resource:///org/myapp/res/gui.xml\");
	GFile*  myDEST =  g_file_new_for_path(glade_file);
	g_file_copy (mySRC,  myDEST,  G_FILE_COPY_OVERWRITE, NULL, NULL,  NULL,    &error);
 
 
    /*Infine carica come disolito il file dell'interfaccia */
	xml = gtk_builder_new ();
	if (!gtk_builder_add_from_file (xml, glade_file, &error))
	  {
		g_warning (\"Couldn\'t load builder file: %s\", error->message);
		g_error_free (error);
	  }
 
 
	 /* connette tutti gli eventi dei widget alle rispettive funzioni */
   	 gtk_builder_connect_signals (xml, NULL);
 
 
      	/* Avvia il ciclo principale delle gtAvvia il ciclo principale delle gtk*/ 
	gtk_main ();
 
  return 0;
 
}
" > main.c
 
echo "Genero il file delle risorse..."
echo "<?xml version=\"1.0\" encoding=\"UTF-8\"?>
		<gresources>
		  <gresource prefix=\"/org/myapp/res\">
			<file>gui.xml</file>
		  </gresource>
		</gresources>" >resource.xml
 
echo "Genero il file dell'interfaccia Glade..."
echo "<?xml version=\"1.0\" encoding=\"UTF-8\"?>
		<interface>
		  <requires lib=\"gtk+\" version=\"2.24\"/>
		  <!-- interface-naming-policy project-wide -->
		  <object class=\"GtkWindow\" id=\"window1\">
			<property name=\"visible\">True</property>
			<property name=\"can_focus\">False</property>
			<property name=\"title\" translatable=\"yes\">Test</property>
			<signal name=\"destroy\" handler=\"gtk_main_quit\" swapped=\"no\"/>
			<signal name=\"delete-event\" handler=\"gtk_main_quit\" swapped=\"no\"/>
			<child>
			  <placeholder/>
			</child>
		  </object>
		</interface>" >gui.xml		
 
echo "Genero il makefile..."
echo "
CPP = gcc
OPTS = `pkg-config --cflags --libs gio-2.0 gtk+-2.0 gmodule-2.0` 
 
all:
	glib-compile-resources --generate-source resource.xml
	\$(CPP)  resource.c main.c -o main \$(OPTS)
 
clean:
	rm main" >makefile

Versione GTK+3

#!/bin/sh
 
AUTHOR="Fabio Di Matteo"
VERSION="0.1.0"
 
 
#Controllo se e' stato fornito il nome del progetto
if [ "$1" = "" ];then
	echo "E' necessario fornire il nome del progetto come parametro."
	exit 1 ;
fi
 
#Se la directory del progetto esiste gia' esco.
mkdir $1 2>/dev/null
if [ "$?" != 0 ];then
	echo "Il progetto esiste."
	exit 1 ;
fi
 
cd $1
 
 
echo "Genero il main.c ..."
echo "#include <gtk/gtk.h>                                                //includo le librerie gtk e glade.
 
GtkBuilder *xml;                                                 //questo è il puntatore al file xml che contiene l'interfaccia  
GtkWidget  *widget;                                              //questa variabile serve per recuperare di volta in volta il  
                                                                //  widget (ovvero l'oggetto ) che vogliamo usare
 
 
 
void on_MainWindow_delete_event(GtkWidget *widget, gpointer user_data)        //altra callback associata alla chiusura della 
{                                                                         // finestra 
    gtk_main_quit();
}
 
 
 
int
main (int argc, char *argv[])
{
  	gtk_init (&argc, &argv);
  	GError* error = NULL;
	gchar* glade_file = g_build_filename(g_get_tmp_dir(),\"gui.xml\", NULL);;
 
 
 
 
    /*Infine carica come disolito il file dell'interfaccia */
	xml = gtk_builder_new ();
	if (!gtk_builder_add_from_resource  (xml, \"/org/myapp/res/gui.xml\", &error))
	  {
		g_warning (\"Couldn\'t load builder file: %s\", error->message);
		g_error_free (error);
	  }
 
 
	 /* connette tutti gli eventi dei widget alle rispettive funzioni */
   	 gtk_builder_connect_signals (xml, NULL);
 
 
      	/* Avvia il ciclo principale delle gtAvvia il ciclo principale delle gtk*/ 
	gtk_main ();
 
  return 0;
 
}
" > main.c
 
echo "Genero il file delle risorse..."
echo "<?xml version=\"1.0\" encoding=\"UTF-8\"?>
		<gresources>
		  <gresource prefix=\"/org/myapp/res\">
			<file>gui.xml</file>
		  </gresource>
		</gresources>" >resource.xml
 
echo "Genero il file dell'interfaccia Glade..."
echo "<?xml version=\"1.0\" encoding=\"UTF-8\"?>
		<interface>
		  <requires lib=\"gtk+\" version=\"3.20\"/>
		  <!-- interface-naming-policy project-wide -->
		  <object class=\"GtkWindow\" id=\"window1\">
			<property name=\"visible\">True</property>
			<property name=\"can_focus\">False</property>
			<property name=\"title\" translatable=\"yes\">Test</property>
			<signal name=\"destroy\" handler=\"gtk_main_quit\" swapped=\"no\"/>
			<signal name=\"delete-event\" handler=\"gtk_main_quit\" swapped=\"no\"/>
			<child>
			  <placeholder/>
			</child>
		  </object>
		</interface>" >gui.xml		
 
echo "Genero il makefile..."
echo "
CPP = gcc
OPTS = \`pkg-config --cflags --libs gio-2.0 gtk+-3.0\` -rdynamic
 
all:
	glib-compile-resources --generate-source resource.xml
	\$(CPP)  resource.c main.c -o main \$(OPTS)
 
clean:
	rm main" >makefile

Versione Vala

#!/bin/bash
 
AUTHOR="Fabio Di Matteo"
VERSION="0.1.0"
 
 
#Controllo se e' stato fornito il nome del progetto
if [ "$1" = "" ];then
	echo "E' necessario fornire il nome del progetto come parametro."
	exit 1 ;
fi
 
#Se la directory del progetto esiste gia' esco.
mkdir $1 2>/dev/null
if [ "$?" != 0 ];then
	echo "Il progetto esiste."
	exit 1 ;
fi
 
cd $1
 
 
echo "Make resorces folder..."
mkdir res
 
 
echo "Make main.vala..."
echo "
using Gtk;
 
 
 
public class mainWindow : GLib.Object {
 
	public  Button btn;
	public  Window window;
	public  Label myLabel;
	int c=0;
 
	public void on_button1_clicked ()
    {
		c++;
		window.set_title(\"You have clicked \"+ c.to_string()+\" times\");
		myLabel.set_text(\"You have clicked \"+ c.to_string()+\" times\");
 
    }
 
    public mainWindow()
    {
 
    }
 
	public void show()
	{
		try { 
 
			var builder = new Builder ();
			builder.add_from_resource(\"/app/res/gui.ui\");
 
			btn=builder.get_object (\"button1\") as Button;
			myLabel=builder.get_object(\"label1\") as Label;
			btn.clicked.connect(on_button1_clicked);
 
			window = builder.get_object (\"window1\") as Window;
			window.destroy.connect(Gtk.main_quit);
			window.show_all ();
 
 
		} catch (Error e) {
			stderr.printf (\"Problem on gui loading: %s\n\", e.message);
 
		}
	}
 
 
 
}
 
int main (string[] args)
{
	Gtk.init (ref args);
	mainWindow myWin = new mainWindow();
	myWin.show();
 
	Gtk.main ();
	return 0;
}
 
" > main.vala ;
 
 
echo "Make meson.build"
echo "
project('$1', 'vala', 'c')
gtk_dep = dependency('gtk+-3.0')
 
 
r = run_command('compile_resources.sh')
if r.returncode() != 0
   error('Errors on compile resources')
endif
 
#check os 
os=build_machine.system()
 
if os == 'linux'
  executable('$1', 'main.vala', 'resources.c', dependencies : [gtk_dep])
endif
if os == 'windows'
  executable('$1', 'main.vala', 'resources.c', dependencies : [gtk_dep], link_args : ['-mwindows'])
endif
 
 
" > meson.build;
 
 
echo "Make resources"
echo "
<?xml version=\"1.0\" encoding=\"UTF-8\"?>
<gresources>
  <gresource prefix=\"/app/res\">
	<file>gui.ui</file>
  </gresource>
</gresources>
 
 
" > res/resources.xml;
 
 
echo  "
<?xml version=\"1.0\" encoding=\"UTF-8\"?>
<!-- Generated with glade 3.20.2 -->
<interface>
  <requires lib=\"gtk+\" version=\"3.20\"/>
  <object class=\"GtkWindow\" id=\"window1\">
    <property name=\"can_focus\">False</property>
    <child>
      <object class=\"GtkBox\">
        <property name=\"visible\">True</property>
        <property name=\"can_focus\">False</property>
        <property name=\"orientation\">vertical</property>
        <child>
          <object class=\"GtkLabel\" id=\"label1\">
            <property name=\"visible\">True</property>
            <property name=\"can_focus\">False</property>
            <property name=\"label\" translatable=\"yes\">You have clicked 0 times</property>
            <attributes>
              <attribute name=\"scale\" value=\"5\"/>
            </attributes>
          </object>
          <packing>
            <property name=\"expand\">False</property>
            <property name=\"fill\">True</property>
            <property name=\"position\">0</property>
          </packing>
        </child>
        <child>
          <object class=\"GtkButton\" id=\"button1\">
            <property name=\"label\" translatable=\"yes\">Cliccami</property>
            <property name=\"visible\">True</property>
            <property name=\"can_focus\">True</property>
            <property name=\"receives_default\">True</property>
          </object>
          <packing>
            <property name=\"expand\">False</property>
            <property name=\"fill\">True</property>
            <property name=\"position\">1</property>
          </packing>
        </child>
        <child>
          <placeholder/>
        </child>
      </object>
    </child>
    <child>
      <placeholder/>
    </child>
  </object>
</interface>
 
 
" > res/gui.ui ;
 
echo "#!/bin/bash
 
cd res
echo 'Building resources.c ...'
glib-compile-resources --generate-source resources.xml
mv resources.c ../
 
 
" > compile_resources.sh;
chmod +x compile_resources.sh

Gtkmm

auto-gtkmm

#!/bin/bash
 
AUTHOR="Fabio Di Matteo"
VERSION="0.1.0"
 
 
#Controllo se e' stato fornito il nome del progetto
if [ "$1" = "" ];then
	echo "E' necessario fornire il nome del progetto come parametro."
	exit 1 ;
fi
 
#Se la directory del progetto esiste gia' esco.
mkdir $1 2>/dev/null
if [ "$?" != 0 ];then
	echo "Il progetto esiste."
	exit 1 ;
fi
 
cd $1
 
 
echo "Make resorces folder..."
mkdir res
 
 
echo "Make main.cc..."
echo "
#include <gtkmm.h>
#include \"mainwindow.hpp\"
 
int main(int argc, char *argv[])
{
	auto app = Gtk::Application::create(argc, argv, \"org.gtkmm.example\");
	mainWindow mainw;
	return app->run(*mainw.window1);
}
 
" > main.cc ;
 
echo "Make mainwindow.hpp..."
echo "
#ifndef MAINWINDOW_HPP
#define MAINWINDOW_HPP
 
#include <gtkmm.h>
 
class mainWindow  
{
	public:
		Glib::RefPtr<Gtk::Builder> builder;
		Gtk::Window *window1;
		Gtk::Button *button1;
		Gtk::Label *label1;
 
		mainWindow();
 
	protected:	
		void on_button_clicked();
 
	private:
		/* add your private declarations */
};
 
#endif /* MAINWINDOW_HPP */ 
" > mainwindow.hpp ;
 
 
echo "Make mainwindow.cpp..."
echo "
#include \"mainwindow.hpp\"
#include <iostream>
 
 
mainWindow::mainWindow()
{
	auto builder = Gtk::Builder::create();
 
	try
	{
		builder->add_from_resource(\"/app/res/gui.ui\");
	}
	catch(const Glib::FileError& ex)
	{
		std::cerr << \"FileError: \" << ex.what() << std::endl;
	}
	catch(const Glib::MarkupError& ex)
	{
		std::cerr << \"MarkupError: \" << ex.what() << std::endl;
	}
	catch(const Gtk::BuilderError& ex)
	{
		std::cerr << \"BuilderError: \" << ex.what() << std::endl;
	}
 
 
 
 
	builder->get_widget(\"window1\", window1);
	builder->get_widget(\"button1\", button1);
	builder->get_widget(\"label1\", label1);
 
	button1->signal_clicked().connect( sigc::mem_fun(*this, &mainWindow::on_button_clicked) );
 
}
 
void mainWindow::on_button_clicked()
{
	static int c;
	c++;
	label1->set_text(\"You have clicked \"+std::to_string(c)+\" times!\");
}
 
 
 
" > mainwindow.cpp ;
 
 
 
 
echo "Make meson.build"
echo "
project('GTKmm', 'cpp')
gtkmm = dependency('gtkmm-3.0')
 
 
r = run_command('compile_resources.sh')
if r.returncode() != 0
   error('Errors on compile resources')
endif
 
 
os=build_machine.system()
if os == 'linux'
	executable('simple-meson', 'main.cc','resources.cpp','mainwindow.cpp', dependencies : gtkmm)
endif
if os == 'windows'
  executable('simple-meson', 'main.cc','resources.cpp','mainwindow.cpp', dependencies : gtkmm, link_args : ['-mwindows'])
endif
 
 
 
" > meson.build;
 
 
echo "Make resources"
echo "
<?xml version=\"1.0\" encoding=\"UTF-8\"?>
<gresources>
  <gresource prefix=\"/app/res\">
	<file>gui.ui</file>
  </gresource>
</gresources>
 
 
" > res/resources.xml;
 
 
echo  "
<?xml version=\"1.0\" encoding=\"UTF-8\"?>
<!-- Generated with glade 3.20.2 -->
<interface>
  <requires lib=\"gtk+\" version=\"3.20\"/>
  <object class=\"GtkWindow\" id=\"window1\">
    <property name=\"can_focus\">False</property>
    <child>
      <object class=\"GtkBox\">
        <property name=\"visible\">True</property>
        <property name=\"can_focus\">False</property>
        <property name=\"orientation\">vertical</property>
        <child>
          <object class=\"GtkLabel\" id=\"label1\">
            <property name=\"visible\">True</property>
            <property name=\"can_focus\">False</property>
            <property name=\"label\" translatable=\"yes\">You have clicked 0 times</property>
            <attributes>
              <attribute name=\"scale\" value=\"5\"/>
            </attributes>
          </object>
          <packing>
            <property name=\"expand\">False</property>
            <property name=\"fill\">True</property>
            <property name=\"position\">0</property>
          </packing>
        </child>
        <child>
          <object class=\"GtkButton\" id=\"button1\">
            <property name=\"label\" translatable=\"yes\">Cliccami</property>
            <property name=\"visible\">True</property>
            <property name=\"can_focus\">True</property>
            <property name=\"receives_default\">True</property>
          </object>
          <packing>
            <property name=\"expand\">False</property>
            <property name=\"fill\">True</property>
            <property name=\"position\">1</property>
          </packing>
        </child>
        <child>
          <placeholder/>
        </child>
      </object>
    </child>
    <child>
      <placeholder/>
    </child>
  </object>
</interface>
 
 
" > res/gui.ui ;
 
echo "#!/bin/bash
 
cd res
echo 'Building resources.c ...'
glib-compile-resources --generate-source resources.xml
mv resources.c ../resources.cpp
 
 
" > compile_resources.sh;
chmod +x compile_resources.sh