Queste sono le differenze tra la revisione selezionata e la versione attuale della pagina.
Prossima revisione Entrambe le parti successive la revisione | |||
programmazione:gtk:catturare_output_di_una_pipe [18/04/2018 - 15:48] 127.0.0.1 modifica esterna |
programmazione:gtk:catturare_output_di_una_pipe [29/12/2018 - 18:49] Fabio Di Matteo |
||
---|---|---|---|
Linea 2: | Linea 2: | ||
Autore: **//Fabio Di Matteo//** \\ Ultima revisione: **//24/02/2018 - 19:24//** \\ \\ | Autore: **//Fabio Di Matteo//** \\ Ultima revisione: **//24/02/2018 - 19:24//** \\ \\ | ||
+ | ===== Versione GLib ===== | ||
+ | |||
+ | **main.c** | ||
+ | <code c> | ||
+ | #include <gtk/gtk.h> | ||
+ | |||
+ | GObject *myEntry, *myButton, *myTextView, *myProgressBar; | ||
+ | GtkTextBuffer *buffer; | ||
+ | GtkTextMark *mark; | ||
+ | |||
+ | void on_mainWindow_delete_event(GtkWidget *widget, gpointer data) | ||
+ | { | ||
+ | g_print("Ciao ciao...\n"); | ||
+ | gtk_main_quit(); | ||
+ | } | ||
+ | |||
+ | |||
+ | void scrollToEnd() | ||
+ | { | ||
+ | //Per lo scrolling automatico della textView | ||
+ | GtkTextIter iter; | ||
+ | GtkTextMark *mark; | ||
+ | gtk_text_buffer_get_end_iter (buffer, &iter); //ricava la posizione finale del testo | ||
+ | gtk_text_buffer_create_mark (buffer, "end", &iter, FALSE); //la salva sul marcatore | ||
+ | mark = gtk_text_buffer_get_mark (buffer, "end"); //riprendo il marcatore "end" | ||
+ | gtk_text_buffer_get_iter_at_mark (buffer, &iter, mark); | ||
+ | gtk_text_view_scroll_mark_onscreen (GTK_TEXT_VIEW(myTextView), mark);//scorro la finestra fino al marcatore | ||
+ | |||
+ | } | ||
+ | |||
+ | //Semplice funzine che aggiorna la textview | ||
+ | gboolean appendTextView(gchar* out) | ||
+ | { | ||
+ | gtk_text_buffer_insert_at_cursor (buffer,out, -1); | ||
+ | gtk_text_view_set_buffer (GTK_TEXT_VIEW(myTextView),buffer); | ||
+ | |||
+ | //Scorre la textView alla fine | ||
+ | scrollToEnd(); | ||
+ | |||
+ | return FALSE; | ||
+ | } | ||
+ | |||
+ | |||
+ | //Callback che viene chiamata ogni qualvolta c'è dello standard output da mostrare | ||
+ | static gboolean | ||
+ | cb_out_watch( GIOChannel *channel, GIOCondition cond, gpointer user_data ) | ||
+ | { | ||
+ | gchar *string; | ||
+ | gsize size; | ||
+ | |||
+ | if( cond == G_IO_HUP ) | ||
+ | { | ||
+ | g_io_channel_unref( channel ); | ||
+ | return( FALSE ); | ||
+ | } | ||
+ | |||
+ | //Leggo la riga corrente dallo stdout e la salvo in "string" | ||
+ | g_io_channel_read_line( channel, &string, &size, NULL, NULL ); | ||
+ | |||
+ | //Formatto e stampo a video "string" e dopo libero string dalla memoria | ||
+ | gchar* s=g_strdup_printf("%s",string); | ||
+ | //g_idle_add ((GSourceFunc) appendTextView, s ); //mostro nel textview | ||
+ | g_idle_add_full (G_PRIORITY_HIGH_IDLE, (GSourceFunc) appendTextView, s, NULL); //mostro nel textview ad alta priorita' | ||
+ | printf("%s", s); | ||
+ | g_free( string ); | ||
+ | |||
+ | return( TRUE ); | ||
+ | } | ||
+ | |||
+ | //Callback che viene chiamata ogni qualvolta c'è dello standard error da mostrare | ||
+ | static gboolean | ||
+ | cb_err_watch( GIOChannel *channel, GIOCondition cond, gpointer user_data ) | ||
+ | { | ||
+ | gchar *string; | ||
+ | gsize size; | ||
+ | |||
+ | if( cond == G_IO_HUP ) | ||
+ | { | ||
+ | g_io_channel_unref( channel ); | ||
+ | return( FALSE ); | ||
+ | } | ||
+ | |||
+ | g_io_channel_read_line( channel, &string, &size, NULL, NULL ); | ||
+ | |||
+ | //Formatto e stampo a video "string" e dopo libero string dalla memoria | ||
+ | gchar* s=g_strdup_printf("Errore: %s",string); | ||
+ | g_idle_add ((GSourceFunc) appendTextView, s ); //mostro nel textview | ||
+ | printf("%s", s); | ||
+ | g_free( string ); | ||
+ | |||
+ | return( TRUE ); | ||
+ | } | ||
+ | |||
+ | |||
+ | void *runCommandPipe(gchar* cmd) | ||
+ | { | ||
+ | GPid pid; //il processid del processo figlio | ||
+ | gchar *workingDir ="/usr/bin/" ; //la directory corrente dove si trova l'eseguibile | ||
+ | gchar **launch = g_strsplit (cmd," ",0); //crea un array di stringhe a partire da una stringa di char | ||
+ | gint in, //file descriptor per l'input (non usato) | ||
+ | out, //file descriptor per l'stdoutput | ||
+ | err; //file descriptor per lo stderr | ||
+ | GIOChannel *out_ch, //canale per catturare l'output | ||
+ | *err_ch; //canale per catturare gli errori | ||
+ | gboolean ret; // se g_spawn_async_with_pipes ha successo è TRUE | ||
+ | GError **error; //array per catturare gli eventuali errori all'avvio di g_spawn_async_with_pipes | ||
+ | |||
+ | /* Avvia il processo figlio in background */ | ||
+ | ret = g_spawn_async_with_pipes( workingDir, launch, NULL, | ||
+ | G_SPAWN_DEFAULT, NULL, | ||
+ | NULL, &pid, &in, &out, &err, error ); | ||
+ | if( ! ret ) | ||
+ | { | ||
+ | g_error( "Pipe fallita." ); | ||
+ | } | ||
+ | |||
+ | //Creiamo i canali che servono per leggere i dati dalla pipe. | ||
+ | out_ch = g_io_channel_unix_new( out ); | ||
+ | err_ch = g_io_channel_unix_new( err ); | ||
+ | |||
+ | // Creiamo i watch per ogni canale creato | ||
+ | // in pratica ogni volta che la pipe restituisce dell'output dallo stdout | ||
+ | // oppure dallo stderr vengono esseguite le relative funzioni callbacks | ||
+ | g_io_add_watch( out_ch, G_IO_IN | G_IO_HUP, (GIOFunc)cb_out_watch, NULL ); | ||
+ | g_io_add_watch( err_ch, G_IO_IN | G_IO_HUP, (GIOFunc)cb_err_watch, NULL ); | ||
+ | |||
+ | |||
+ | if (error != NULL) | ||
+ | { | ||
+ | printf("Errore nella pipe\n"); | ||
+ | } | ||
+ | } | ||
+ | |||
+ | |||
+ | |||
+ | |||
+ | void myButton_clicked_cb(GtkWidget *widget, gpointer data) | ||
+ | { | ||
+ | //Pulisco tutto il textBuffer | ||
+ | gtk_text_buffer_set_text (GTK_TEXT_BUFFER(buffer),"",0); | ||
+ | |||
+ | gchar* cmd= g_strdup_printf("%s", gtk_entry_get_text(GTK_ENTRY(data))); | ||
+ | g_print("Comando-> %s\n",cmd); | ||
+ | |||
+ | //Un thread avvia la funzione che eseguira' la pipe | ||
+ | GThread *myThread; | ||
+ | myThread= g_thread_new(NULL,(GThreadFunc)runCommandPipe,cmd); | ||
+ | } | ||
+ | |||
+ | void mainWindowInit() | ||
+ | { | ||
+ | GError* error = NULL; | ||
+ | gchar* glade_file = g_build_filename("gui.glade", NULL); | ||
+ | GtkBuilder *xml; | ||
+ | GObject *mainWindow ; | ||
+ | buffer=gtk_text_buffer_new (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); | ||
+ | } | ||
+ | |||
+ | mainWindow=gtk_builder_get_object (xml,"mainWindow" ); | ||
+ | myButton=gtk_builder_get_object (xml,"myButton" ); | ||
+ | myEntry=gtk_builder_get_object(xml,"myEntry"); | ||
+ | myTextView=gtk_builder_get_object(xml,"myTextView"); | ||
+ | myProgressBar=gtk_builder_get_object(xml, "myProgressBar"); | ||
+ | gtk_entry_set_text(GTK_ENTRY(myEntry),"rsync -avz --info=progress2 --dry-run /usr/bin/ /home/fabio/Desktop/tt/"); | ||
+ | |||
+ | g_signal_connect(myButton,"clicked",G_CALLBACK(myButton_clicked_cb),myEntry); | ||
+ | g_signal_connect(mainWindow,"delete-event",G_CALLBACK(on_mainWindow_delete_event),NULL); | ||
+ | g_object_unref( G_OBJECT( xml ) ); | ||
+ | |||
+ | |||
+ | } | ||
+ | |||
+ | |||
+ | |||
+ | |||
+ | int main (int argc, char **argv) | ||
+ | { | ||
+ | |||
+ | gtk_init (&argc, &argv); | ||
+ | mainWindowInit(); | ||
+ | gtk_main (); | ||
+ | |||
+ | return 0; | ||
+ | } | ||
+ | |||
+ | |||
+ | </code> | ||
+ | |||
+ | **makefile** | ||
+ | <file> | ||
+ | all: | ||
+ | gcc main.c -o simple `pkg-config --cflags --libs gtk+-3.0 gthread-2.0 gmodule-2.0` | ||
+ | |||
+ | |||
+ | </file> | ||
+ | |||
+ | **gui.glade** | ||
+ | <code xml> | ||
+ | <?xml version="1.0" encoding="UTF-8"?> | ||
+ | <!-- Generated with glade 3.22.1 --> | ||
+ | <interface> | ||
+ | <requires lib="gtk+" version="3.20"/> | ||
+ | <object class="GtkWindow" id="mainWindow"> | ||
+ | <property name="width_request">500</property> | ||
+ | <property name="height_request">300</property> | ||
+ | <property name="visible">True</property> | ||
+ | <property name="can_focus">False</property> | ||
+ | <signal name="delete-event" handler="on_mainWindow_delete_event" swapped="no"/> | ||
+ | <child type="titlebar"> | ||
+ | <placeholder/> | ||
+ | </child> | ||
+ | <child> | ||
+ | <object class="GtkBox"> | ||
+ | <property name="visible">True</property> | ||
+ | <property name="can_focus">False</property> | ||
+ | <property name="orientation">vertical</property> | ||
+ | <child> | ||
+ | <object class="GtkBox"> | ||
+ | <property name="visible">True</property> | ||
+ | <property name="can_focus">False</property> | ||
+ | <child> | ||
+ | <object class="GtkEntry" id="myEntry"> | ||
+ | <property name="width_request">508</property> | ||
+ | <property name="visible">True</property> | ||
+ | <property name="can_focus">True</property> | ||
+ | </object> | ||
+ | <packing> | ||
+ | <property name="expand">False</property> | ||
+ | <property name="fill">True</property> | ||
+ | <property name="position">0</property> | ||
+ | </packing> | ||
+ | </child> | ||
+ | <child> | ||
+ | <object class="GtkButton" id="myButton"> | ||
+ | <property name="label">gtk-execute</property> | ||
+ | <property name="visible">True</property> | ||
+ | <property name="can_focus">True</property> | ||
+ | <property name="receives_default">True</property> | ||
+ | <property name="use_stock">True</property> | ||
+ | <property name="always_show_image">True</property> | ||
+ | <signal name="clicked" handler="myButton_clicked_cb" object="myEntry" swapped="no"/> | ||
+ | </object> | ||
+ | <packing> | ||
+ | <property name="expand">False</property> | ||
+ | <property name="fill">True</property> | ||
+ | <property name="position">1</property> | ||
+ | </packing> | ||
+ | </child> | ||
+ | </object> | ||
+ | <packing> | ||
+ | <property name="expand">False</property> | ||
+ | <property name="fill">True</property> | ||
+ | <property name="position">0</property> | ||
+ | </packing> | ||
+ | </child> | ||
+ | <child> | ||
+ | <object class="GtkScrolledWindow" id="myScrolledWindow"> | ||
+ | <property name="height_request">400</property> | ||
+ | <property name="visible">True</property> | ||
+ | <property name="can_focus">True</property> | ||
+ | <property name="shadow_type">in</property> | ||
+ | <child> | ||
+ | <object class="GtkTextView" id="myTextView"> | ||
+ | <property name="visible">True</property> | ||
+ | <property name="can_focus">True</property> | ||
+ | </object> | ||
+ | </child> | ||
+ | </object> | ||
+ | <packing> | ||
+ | <property name="expand">False</property> | ||
+ | <property name="fill">True</property> | ||
+ | <property name="position">1</property> | ||
+ | </packing> | ||
+ | </child> | ||
+ | <child> | ||
+ | <object class="GtkProgressBar" id="myProgressBar"> | ||
+ | <property name="height_request">15</property> | ||
+ | <property name="visible">True</property> | ||
+ | <property name="can_focus">False</property> | ||
+ | <property name="text" translatable="yes">Pronto.</property> | ||
+ | <property name="show_text">True</property> | ||
+ | </object> | ||
+ | <packing> | ||
+ | <property name="expand">False</property> | ||
+ | <property name="fill">True</property> | ||
+ | <property name="position">2</property> | ||
+ | </packing> | ||
+ | </child> | ||
+ | </object> | ||
+ | </child> | ||
+ | </object> | ||
+ | </interface> | ||
+ | |||
+ | </code> | ||
+ | |||
+ | |||
+ | ===== Versione Posix ===== | ||
<code c> | <code c> |
Il nostro wiki installa solamente cookie tecnici necessari al funzionamento della piattaforma "Dokuwiki". Niente analitics, statistiche, tracciamenti o altro.