How to spawn a new application from Gnome/GTK to a CLI application and read its output back into Gnome/GTK application?

StackOverflow https://stackoverflow.com/questions/17248842

  •  01-06-2022
  •  | 
  •  

Pergunta

I am trying to spawn a new application from Gnome/GTK to a CLI application and read its output back into my Gnome/GTK application.

The code works as expected for most shell commands but with tail -f /var/log/messages and top it does not. Is there any way to parse the output from these two commands ?

Am running Ubuntu 12.04.2 LTS and libgtk2.0.

#include <gtk/gtk.h>

static GtkWidget *window;          // pointer to window  
static GtkWidget *view;            // pointer to textview
static GtkTextBuffer *buffer;      // pointer to buffer
static GtkTextIter   iter;         // gtktextview iterator 
static GtkWidget *scrolled_window; // pointer to scrolled window

FILE *fp;                          // pointer to stdin/out file pipe
char line[256];                    // line read buffer size

static gboolean on_delete_event (GtkWidget *widget, GdkEvent *event, gpointer data){
  gtk_main_quit();  
  return FALSE;
}

void create_gui(){
    window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
    g_signal_connect (G_OBJECT (window), "delete_event",
    G_CALLBACK(on_delete_event), NULL);
    gtk_window_set_title (GTK_WINDOW (window), "GUI Front-End for CLI");

    GtkWidget *box = gtk_vbox_new(FALSE, 10);                // Create a box and 
    gtk_container_add (GTK_CONTAINER(window), box);          // set it as window's main child.

    scrolled_window=gtk_scrolled_window_new(NULL, NULL);     // Now create scrolled window...  
    gtk_widget_set_usize(scrolled_window, 650, 450);         // Set scrolled window size..

    gtk_container_add(GTK_CONTAINER(box), scrolled_window);  // Add scrolled window to vbox.. 
    view = gtk_text_view_new();                              // Create textview..
    gtk_container_add(GTK_CONTAINER(scrolled_window), view); // Add textview to scrolled window..
    buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(view));  // Assign textview buffer 
    }

void populate(){

 fp = popen("cat /var/log/messages", "r");                   // run shell command using pipe

 while ( fgets( line, sizeof line, fp)){                     //
   gtk_text_buffer_get_end_iter (buffer, &iter);             
   gtk_text_buffer_insert (buffer, &iter, line, -1);
 }  
   pclose(fp);                                               // CLOSE Pipe 
}

int main (int argc, char *argv[]){
  gtk_init (&argc, &argv);
  create_gui();
  populate(); 
  gtk_widget_show_all (window);
  gtk_main ();
  return 0;
}

// TODO
// fp = popen("ls -al", "r");        
// fp = popen("cat /proc/cpuinfo", "r");        
// fp = popen("cat /var/log/messages", "r");        
// fp = popen("lspci -v", "r");        
// fp = popen("w", "r");        
// fp = popen("last", "r");        
// fp = popen("pstree", "r");         

// fp = popen("tail -f /var/log/messages &", "r");  THIS DOES NOT WORK !      
// fp = popen("top", "r");                          NEITHER DOES THIS..
enter code here
Foi útil?

Solução

top and tail -f are long-running programs (in fact, they never exit), so your strategy of reading the whole output and populating the the textbuffer with it obviously won't work.

Instead, you need to create an IO channel that watches what's going on with the pipe, hook the channel into the event loop, and append it to the text buffer as new output arrives. The minimalistic change to your program would be to rewrite the prepare function like this:

static gboolean data_ready(GIOChannel *channel, GIOCondition cond, gpointer data)
{
  FILE *fp = data;
  char line[256];

  if (fgets(line, sizeof line, fp)) {
      gtk_text_buffer_get_end_iter (buffer, &iter);             
      gtk_text_buffer_insert (buffer, &iter, line, -1);
      return TRUE;
  }
  else {
      fclose(fp);
      return FALSE;
  }
}

void populate(){
  FILE *fp = popen("top -b", "r");
  GIOChannel *channel = g_io_channel_unix_new(fileno(fp));
  g_io_add_watch(channel, G_IO_IN, data_ready, fp);
}
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top