Run External Program from GTK Application

Run external program from GTK application using GTK 3 and the C programming language. How to run an external program from within a GTK application written in the C programming language using Glade interface designer. This tutorial shows how to invoke a command line command from a GTK 3 GUI application and redirect the output to the GUI application. Running an application from another application is called spawning a process.

The example used in this tutorial calls the Unix free command to get the amount of free memory available on the system. It then displays the result from the free command in the window of the GTK 3 application. Demonstrated on a Linux Mint system. See below for an image of the application example built in this part of the GTK 3 C programming tutorial series.

Run External Program from GTK Application Example using free Command
Run External Program from GTK Application Example using free Command

Part 28 of GTK 3 Programming with C and Glade Tutorial

See the full GTK3 tutorial index

Using the free Command

As our application calls the free command, we look at the free command here before using it in our application.

The free command displays the total amount of free and used physical and swap memory in the system. Enter the following in a terminal window to run the free command.

free

Values returned vary, depending on the system hardware and software running. See the example below.

              total        used        free      shared  buff/cache   available
Mem:        8041240     1238332     4188316      121084     2614592     6382580
Swap:      15999484           0    15999484

Use the -h switch with the free command to show memory sizes in human readable units. Enter the following in a terminal window.

free -h

Values that are easier to read are returned. See below for an example of values returned and displayed in the terminal window.

              total        used        free      shared  buff/cache   available
Mem:           7.7G        1.3G        3.9G        105M        2.5G        6.0G
Swap:           15G          0B         15G

Access the Linux manual pages for more information on the free command. Do this by entering the following in a terminal window.

man free

Use the up and down arrow keys, and page up and page down keys to navigate the manual pages. Press Q to quit back to the command prompt.

Run External Program from GTK Tutorial Steps

Follow the tutorial steps below to build the application that runs an external program from a GTK application.

1. Start a New GTK 3 Glade C Project

Start a new project using the template files from part 24 of this GTK Glade C programming tutorial series. Make a copy of the template folder and rename it to memory.

Change the target name in the make file to memory as well. Below is a full listing of the make file.

makefile

# change application name here (executable output name)
TARGET=memory

# compiler
CC=gcc
# debug
DEBUG=-g
# optimisation
OPT=-O0
# warnings
WARN=-Wall

PTHREAD=-pthread

CCFLAGS=$(DEBUG) $(OPT) $(WARN) $(PTHREAD) -pipe

GTKLIB=`pkg-config --cflags --libs gtk+-3.0`

# linker
LD=gcc
LDFLAGS=$(PTHREAD) $(GTKLIB) -export-dynamic

OBJS=    main.o

all: $(OBJS)
	$(LD) -o $(TARGET) $(OBJS) $(LDFLAGS)
    
main.o: src/main.c
	$(CC) -c $(CCFLAGS) src/main.c $(GTKLIB) -o main.o
    
clean:
	rm -f *.o $(TARGET)

2. Edit the Glade File used to Run External Program from GTK

Widgets placed in this part of the tutorial are shown in the image below.

Run External Program from GTK Glade File
Run External Program from GTK Glade File

Open the window_main.glade file from the project glade folder for editing in Glade. The steps below show how to place the widgets for this project. Layout is largely based on the text reader from part 22 of this GTK tutorial series, only simplified.

2.1 Place a GtkBox Container

Place a GtkBox in the main window and change its number of items to 2.

2.2 Place a GtkScrolledWindow Container

Place a GtkScrolledWindow in the top part of the GtkBox.

Under the Packing tab, Fill and Expand must both be checked.

2.3 Place a GtkTextView Display

Place a GtkTextView in the GtkScrolledWindow and give it an ID of txt_vw_memory.

2.4 Add a GtkTextBuffer

With the GtkTextView still selected, click the pencil icon at the right of Buffer under the General tab. Add a new GtkTextBuffer and give it an ID of textbuffer_main.

Give it default text of Click button to get memory sizes.

2.5 Place a GtkButton Control

Place a GtkButton in the bottom of the GtkBox. Give the button an ID of btn_get_mem_size and Label of Get Memory Size.

Under the common tab, give the button top and bottom margins of 10 pixels each.

2.6 Add a Button Handler

With the button still selected, click the Signals tab. Add a button handler for the clicked signal called on_btn_get_mem_size_clicked.

2.7 Change Main Window Attributes

Select the main window (window_main) by clicking it in the left pane of Glade. Change the title of the window to Get Memory Size.

Change the default width of the main window to 700 and the height to 180. This makes the text returned from the free command fit in the window without scroll bars.

3. Write the C Code to Run External Program from GTK

Open main.c from the project src folder. Modify the code as shown in the listing below.

main.c

#include <gtk/gtk.h>

// Custom structure that holds pointers to widgets and user variables
typedef struct {
    // Add pointers to widgets below
    GtkWidget     *w_txt_vw_memory;
    GtkTextBuffer *textbuffer_main;
} app_widgets;

int main(int argc, char *argv[])
{
    GtkBuilder      *builder; 
    GtkWidget       *window;
    // Instantiate structure, allocating memory for it
    app_widgets     *widgets = g_slice_new(app_widgets);
    
    gtk_init(&argc, &argv);

    builder = gtk_builder_new_from_file("glade/window_main.glade");

    window = GTK_WIDGET(gtk_builder_get_object(builder, "window_main"));
    // Get pointers to widgets here
    widgets->w_txt_vw_memory  = GTK_WIDGET(gtk_builder_get_object(builder, "txt_vw_memory"));
    widgets->textbuffer_main  = GTK_TEXT_BUFFER(gtk_builder_get_object(builder, "textbuffer_main"));
    
     // Widgets pointer are passed to all widget handler functions as the user_data parameter
    gtk_builder_connect_signals(builder, widgets);

    g_object_unref(builder);

    gtk_widget_show_all(window);                
    gtk_main();
    // Free up widget structure memory
    g_slice_free(app_widgets, widgets);

    return 0;
}

// Calls "free -h" and displays the result when the button is clicked
void on_btn_get_mem_size_clicked(GtkButton *button, app_widgets *app_wdgts)
{
    gboolean result;
    gchar *standard_out;
    gchar *standard_err;
    gint exit_state;
    GError *err;
    
    result = g_spawn_command_line_sync(
                           "free -h",
                           &standard_out,
                           &standard_err,
                           &exit_state,
                           &err);
    if (result == FALSE) {
        g_print("An error occured\n");
    }
    else {
       gtk_text_buffer_set_text(app_wdgts->textbuffer_main, standard_out, -1);
    }
}

// called when window is closed
void on_window_main_destroy()
{
    gtk_main_quit();
}

After adding the above code, save the file.

4. Build and Run the Application

Open a terminal window from the project folder and run make to build the project. Run the application from the terminal window by entering the following.

./memory

When the application is running, click the button to display the output from the free command.

5. Improve the User Interface

Under the General tab of the GtkTextView, switch on Monospace. This correctly aligns the text returned by the free command.

With the GtkTextView still selected, under the General tab, add 10 pixels of margin all around. This improves the appearance of text displayed in this widget.

Still under the same General tab, uncheck the Editable option. This prevents the application user from deleting and editing the text in this widget.

Run the application again to see the changes take effect.

6. How the Program Works

This explanation only covers how to run an external program from GTK. All of the other aspects of the program are covered in previous parts of this tutorial series.

6.1 How to Run External Application from GTK Application

In the button handler function, g_spawn_command_line_sync() is called, which runs the free command with the -h switch and captures its output. The button handler function is shown in the following listing.

void on_btn_get_mem_size_clicked(GtkButton *button, app_widgets *app_wdgts)
{
    gboolean result;
    gchar *standard_out;
    gchar *standard_err;
    gint exit_state;
    GError *err;
    
    result = g_spawn_command_line_sync(
                           "free -h",
                           &standard_out,
                           &standard_err,
                           &exit_state,
                           &err);
    if (result == FALSE) {
        g_print("An error occured\n");
    }
    else {
       gtk_text_buffer_set_text(app_wdgts->textbuffer_main, standard_out, -1);
    }
}

6.2 GLib Documentation for Spawning Processes

The g_spawn_command_line_sync() function is part of the GLib library. GLib documentation is part of the Gnome Developer documentation. Documentation for spawning processes using GLib functions contains information on how to use g_spawn_command_line_sync() in an application.

6.3 g_spawn_command_line_sync() Parameters

In short, the command to execute is passed as the first parameter to g_spawn_command_line_sync(). The second parameter is a pointer that points to dynamically allocated memory containing the output from the application that is run or spawned. We do not use the other parameters.

Once the output from the free command is captured by this function, it is written to the text buffer widget. This in turn displays the text in the text view widget.

7. Spawning Asynchronous or Synchronous Processes

The example in this tutorial is very simple. Because the free command returns its output very quickly, a synchronous spawn function was used. Synchronous functions are simpler to use but block the rest of the application while they run. No visible blocking is seen because free returns so fast.

If a program is called from a GTK application that takes a significant amount of time to run to completion, it must be called using an asynchronous function. This is so that the calling application will not appear to hang while the spawned process is running.

Leave a Reply

Your email address will not be published. Required fields are marked *