GTK

1. GTK Implementation

The gtk implementation uses the base benchmark structure. To be able to use the gtk features we need the gtk.h header file.

{Includes 2:3} +=
#include <gtk/gtk.h>

Added to in section 4:1

Redefined in section 5:1

Used in sections 2:3 and 5:1

Since this is a benchmark we will leave "org.gtk.example" as the identifier. To initialize the application we register a callback to build the window and then start the application by passing the received command line arguments.

{Graphical Initialization 5:1}
GtkApplication *app;

app = gtk_application_new ("org.gtk.example", G_APPLICATION_FLAGS_NONE);
g_signal_connect (app, "activate", G_CALLBACK (activate), NULL);
status = g_application_run (G_APPLICATION (app), argc, argv);
g_object_unref (app);

Used in sections 2:3 and 5:1

Here we have the main structure for building the window according to the specified mockup.

{Window Construction 4:1}
{Insert Button Callback, 4:1}
{Search Changed Callback, 4:1}

static void activate (GtkApplication* app, gpointer user_data){
  {Widgets Declaration, 1}
  {Layout Organization, 1}

  {Widgets Initialization, 1}
  {Widgets Packing, 1}

  gtk_widget_show_all (window);
}

Used in section 2:3

The two main areas of the window are the place to insert new notes and the area to filter and display them. Here we declare the widgets variables. The components in the GTK stack are all based from GTKWidget.

{Widgets Declaration 1}
GtkWidget * main_box;

GtkWidget * insert_button;
GtkWidget * insert_box;
GtkWidget * insert_label;

GtkWidget * search_label;
GtkWidget * search_box;
GtkWidget * search_scroll;

Since we need to access the insert box, the search list and the search text from their callback functions we will make them globals.

{Globals 4:1}
GtkWidget * window;
GtkWidget * insert_text;
GtkWidget * search_list;
GtkWidget * search_text;

Added to in section 4:1

Used in section 2:3

Here we create the window with the title "Notes Reminder" and set the size to 400x300 as specified before. After that, the main areas of the interface layout are created and their margins and spacings are defined.


To make the list with the notes be scrolable and not expand infinitely we create a scrolled window and put the search box inside it.

{Layout Organization 1}
// create window
window = gtk_application_window_new (app);
gtk_window_set_title (GTK_WINDOW (window), TITLE);
gtk_window_set_default_size (GTK_WINDOW (window), 400, 300);

// create containing boxes
main_box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 15);

// Insert Box
insert_box = gtk_button_box_new(GTK_ORIENTATION_HORIZONTAL);
gtk_button_box_set_layout (GTK_BUTTON_BOX (insert_box), GTK_BUTTONBOX_SPREAD);

// Search Box
search_box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 15);
gtk_widget_set_margin_start (search_box, 10);
gtk_widget_set_margin_end (search_box, 10);

// Scroll Window
search_scroll = gtk_scrolled_window_new (NULL, NULL);
gtk_scrolled_window_set_min_content_height(GTK_SCROLLED_WINDOW (search_scroll), 120);

gtk_container_add(GTK_CONTAINER (window), main_box);

With the layout defined now we instantiate the widgets that will be used. We register the callback for the note insertion when the insert button is clicked and the callback of the note search that will fill the search results in the listbox when new text is written.


The search-changed event doesn't trigger instantly after each change, so it was chosen to be used in the search field instead of a keypress event because it would make the refreshing of the list look like flickering.


Since the list starts empty, we make an initial search with a blank text string which will match all the notes in the .remember file.

{Widgets Initialization 1}
// Insert Widgets
insert_label = gtk_label_new ("Create New");
insert_button = gtk_button_new_with_label("Insert");
insert_text = gtk_entry_new ();
g_signal_connect(insert_button, "clicked", G_CALLBACK (insert_clicked), NULL);

// Search Widgets
search_text = gtk_search_entry_new ();
search_label = gtk_label_new ("Search");
search_list = gtk_list_box_new ();
g_signal_connect(search_text, "search-changed", G_CALLBACK (search_changed), NULL);

gchar * text = "";
{Search Notes, 2:3}

With the widgets instantiated we pack them into the layout widgets we set up before.

{Widgets Packing 1}
// Fill the containers
gtk_container_add(GTK_CONTAINER (main_box), insert_label);

gtk_container_add(GTK_CONTAINER (main_box), insert_box);
gtk_container_add(GTK_CONTAINER (insert_box), insert_text);
gtk_container_add(GTK_CONTAINER (insert_box), insert_button);

gtk_container_add(GTK_CONTAINER (main_box), search_box);
gtk_container_add(GTK_CONTAINER (search_box), search_label);
gtk_container_add(GTK_CONTAINER (search_box), search_text);
gtk_container_add(GTK_CONTAINER (search_scroll), search_list);
gtk_container_add(GTK_CONTAINER (search_box), search_scroll);

After we have text in the text field to insert new notes and we click the Insert button we want the text to be added to our notes database. If there is no text in the text field we can ignore the button click. If there is text and the note was inserted we want to clear the text box so we can add other new notes.

{Insert Button Callback 4:1}
static void insert_clicked (GtkWidget *widget, gpointer data){
  guint16 text_length = gtk_entry_get_text_length (GTK_ENTRY (insert_text));
  if(text_length != 0){
	gchar * text;
	text = gtk_entry_get_text (GTK_ENTRY (insert_text));

    {Insert Note, 2:3}

    if(result == 0){
      gtk_entry_set_text (GTK_ENTRY (insert_text), "");
    }
  }
}

Used in section 4:1

When the text in the notes search field changes we want to update the notes list. To do this when a change is detected in the search field we clear the list, query the remember text field with our new query and insert the results in the list.


Since we instantiated new GtkWidgets and added them to the list. We need to tell the window to show all the new widgets.

{Search Changed Callback 4:1}
static void search_changed (GtkWidget *widget, gpointer data){
  gchar * text;
  text = gtk_entry_get_text (GTK_ENTRY (search_text));
	
  gtk_container_foreach(GTK_CONTAINER (search_list), gtk_widget_destroy, NULL);

  {Search Notes, 2:3}

  gtk_widget_show_all (window);
}

Used in section 4:1

For each of the results of the note search in the text file we will build a GtkLabel element, make its appear with '...' at the end if needed to fit in the current window and add it to the notes list.

{Display Note 4:1}
GtkWidget * label = gtk_label_new(current_note);
gtk_label_set_ellipsize(GTK_LABEL (label), PANGO_ELLIPSIZE_END);
gtk_container_add (GTK_CONTAINER (search_list), label);

Used in section 2:3

In order to compile this code we can use the pkg-config to import the gtk3 dependencies.

{gtk/Makefile 1}
all:
	gcc `pkg-config --cflags gtk+-3.0` -o main main.c `pkg-config --libs gtk+-3.0`
clean:
	rm main

2. Results

Obtained Interface


GTK Notes


GTK Notes Search

Evaluation


RAM Usage - 26.54MB


Implementation Dificulty - All the widgets are based on the GtkWidget which allows fastly understand how they can be used. Their documentation is good and this implemented was done just with the help of their reference manual. The code implementation gave us full control of the implementaiton, but we could use the glade tool which allows us to drag and drop most of the gtk components to build the UI. The layout boxes took a bit to be able to manage the position of the elements,


Supported Platforms - GNU/Linux, Unix, Windows and Mac OS X


Previous ChapterNext Chapter