The Glade Compiler

Kevin C. O'Kane
Professor Emeritus
Computer Science Department
University of Northern Iowa
Cedar Falls, IA 50613

Last Update: December 4, 2022


Note: this project is not affiliated with The Glade Project so don't blame them for my mistakes!

Latest Source Code Version:

The Glade Compiler is included in the Mumps distribution in the projects directory:

  • Mumps Programming Language Distro

  • The Glade Compiler

      What is Glade?

      "... Glade is a RAD tool to enable quick & easy development of user interfaces for the GTK toolkit and the GNOME desktop environment.

      The user interfaces designed in Glade are saved as XML, and by using the GtkBuilder GTK object these can be loaded by applications dynamically as needed.

      By using GtkBuilder, Glade XML files can be used in numerous programming languages including C, C++, C#, Vala, Java, Perl, Python,and others.

      Glade is Free Software released under the GNU GPL License. ..." The Glade Project

    • Glade produces an XML representation of your GTK GUI layout. The XML file can be read by GTK functions that, together with your code, can build and display this layout.
    • Each active widget in the layout (for example, a button) will most likely have a signal defined in the layout. Signals are raised when actions are performed on a widget. In the case of a button widget, the most common signal is "clicked".
    • Glade will build the XML file describing to your app. This includes iformation giving the location, size, function, and signals associated each widget in the app.
    • The programmer is responsible to build a program based to implement the GUI layout. This includes the basic GTK main loop, declaration of GTK pointers and creation of signal handlers.
    • When a user of an app generates a signal, for example, clicking a button, the GTK main loop attempts to call the signal handler associated with the action or event (for example, a button clicked signal handler). The programmer is responsible for writing the handler to do whatever clicking the button is supposed to do.
    • While the working content of any app is mainly found in the signal or event handlers, the setup to build the code to the point where signal handlers can be written can be tedious.
    • The purpose of this compiler is to read the XML file and create the basic software, including skeletal signal handlers, to realize a working model of the basic layout.
    • Each signal handler created by the compiler contains basic code to support the signal including accessing data from the signaling widget (for example, determining the position of a GUI slider whose movement resulted in a slider moved signal).
    • In summary, if you can build a layout, the compiler will build you a working version of it.
    • Based on user choice, the compiler generates code in C, C++, or Mumps.
    • Not all GTK widgets are supported at present and work is in process to add more recognized widgets as well as add additional GUI support features. As of this point in time, the dfollowing widgets are supported:
    GtkCellRendererText GtkWindow GtkFixed GtkButton GtkComboBox GtkEntryBuffer GtkSwitch GtkLevelBar GtkVolumeButton GtkImage GtkIconView GtkProgressBar GtkSpinner GtkDrawingArea GtkCalendar GtkFontButton GtkAdjustment GtkRadioButton GtkScale GtkBox GtkMenu GtkMenuButton GtkLockButton GtkFileChooserButton GtkFrame GtkColorButton GtkSpinButton GtkScrollbar GtkLabel GtkToggleButton GtkEntry GtkSearchEntry GtkViewport GtkScrolledWindow GtkTextView GtkTextBuffer GtkInfoBar GtkCheckButton GtkTreeView GtkTreeSelection GtkTreeViewColumn GtkCellRendererText GtkListStore GtkTreeStore GtkStackSwitcher GtkStack GtkSeparator

    Examples

    The following examples use the mumps/Mumps-Projects/GTK-Compiler/C-Examples/Button-Widgets directory and code from the distro.

    Before you attempt to run the examples, you will need to install software. The installation scripts are in the distro directory:

    mumps/Mumps-Language-Processors/Mumps-Interpreter-Compiler-Library

    In that directory, as root, run:

    ConfigureNativeMumps.script

    followed by:

    CompileNativeSingleUserMumps.script

    DO NOT run the Makefile.

    The first script will check if you have the needed software and, if not, install it. This only woks of systems that use apt/apt-get.

    The second script configures the code, compiles it, then installs it to /usr/bin.

    All examples were run under Linux Mint 20.3 Una with Mate 1.26.0 and GTK 3.22.16 and Glade 3.22.2

    The following image shows the Glade GUI with an example layout containing several common button related widgets.

    To run the Glade GUI from mumps/Mumps-Projects/Glade-Compiler/C-Examples directory on your computer, in a file explorer, double click on the file mumps.glade or type the command

    glade mumps.glade
    from a terminal window (assumes Glade has been installed on your system). Glade XML files have the .glade extension.

    The leftmost panel gives the names and layout hierarchy of the widgets. At the top is a GtkWindow which contains a GtkFixed container which itself contains individual widgets that are buttons and labels. Each line gives the name of widget widget followed by its GTK data type. Widgets are arranged hierarchically based on containment.

    The button highlighted is a GtkToggleButton whose name (see ID at top of rightmost panel) is SampleGtkTogglebutton. The ID is assigned by the programmer/designer of the app.

    Near the bottom of the rightmost panel, under Label with Optional Image, is the text that appears inside the button. The remainder of the rightmost settings panel are defaults.


    In the following figure we see the second tab of the right most panel:

    This is the tab where you position the widget within the app container. The numbers are in pixels where 0 represents the rightmost / topmost pixel of the app window.


    The next tab consists mostly of defaults except for the width and height requests near the bootom. These determine the size of the widget. The defaults are usually too large (80x100). The request boxes are unchecked which means the widget will only be large enough to for its contents which, in this case, is the SampleGtkToggleButton label. Values of -1 also mean the height or width will only be large enough to contain the assigned content.


    Next is the tab where you establish signals for events you want to process:

    The main action for a toggle button is the toggled signal. The name of the signal handler is: on_SampleGtkToggleButton_toggled. The programmer enters this name. This is the name of the function that will be invoked if the button is toggled. The name should be on_ followed by the widget ID followed by _toggled.

    Hint: a standard name such as shown will be inserted for you if you click on the text and begin typing on.... The Glade GUI will fill in the rest.

    BE SURE TO HIT ENTER to confirm you selection.


    The XML file from Glade is a text file named xxx.glade where xxx is set by the user when they create the project.

    In the case of the code for the GtkCompiler, it is assumed, at present, that this file is named mumps.glade.

    Once the layout has been saved, you run make -B which builds the skelatal project code:

    rm -f on.* key.dat data.dat
    ../../GtkCompiler.mps "C" < mumps.glade
    
    Mumps GTK Application Builder Mon Aug  1 12:26:13 2022
    -----------
    ComboBoxExample GtkComboBox
         signal=on_ComboBoxExample_changed
    Creating signal handler: on.ComboBoxExample.changed.h
    ExampleFontButton GtkFontButton
         signal=on_ExampleFontButton_font_set
    Creating signal handler: on.ExampleFontButton.font.set.h
    ExampleSwitch GtkSwitch
         signal=on_ExampleSwitch_state_set
    Creating signal handler: on.ExampleSwitch.state.set.h
    SampleColorButton GtkColorButton
         signal=on_SampleColorButton_color_set
    Creating signal handler: on.SampleColorButton.color.set.h
    SampleGtkButton GtkButton
         signal=on_SampleGtkButton_clicked
    Creating signal handler: on.SampleGtkButton.clicked.h
    SampleGtkCheckButton GtkCheckButton
         signal=on_SampleGtkCheckButton_toggled
    Creating signal handler: on.SampleGtkCheckButton.toggled.h
    SampleGtkRadio1 GtkRadioButton
         signal=on_SampleGtkRadio1_toggled
    Creating signal handler: on.SampleGtkRadio1.toggled.h
    SampleGtkRadio2 GtkRadioButton
         signal=on_SampleGtkRadio2_toggled
    Creating signal handler: on.SampleGtkRadio2.toggled.h
    SampleGtkRadio3 GtkRadioButton
         signal=on_SampleGtkRadio3_toggled
    Creating signal handler: on.SampleGtkRadio3.toggled.h
    SampleGtkToggleButton GtkToggleButton
         signal=on_SampleGtkToggleButton_toggled
    Creating signal handler: on.SampleGtkToggleButton.toggled.h
    cbentry GtkEntry
         signal=on_cbentry_changed
    Creating signal handler: on.cbentry.changed.h
    entrybuffer1 GtkEntryBuffer
    fixed1 GtkFixed
    label1 GtkLabel
    label2 GtkLabel
    label3 GtkLabel
    lbl4 GtkLabel
    liststore1 GtkListStore
    page_0 GtkFixed
    page_1 GtkFixed
    stack1 GtkStack
    window GtkWindow
    -----------
    
    gcc -O3 -fdiagnostics-color=never \
    	-pthread `pkg-config --cflags --libs glib-2.0` \
    	-o gtk gtk.c `pkg-config --libs glib-2.0` -lpthread \
    	`pkg-config --cflags --libs gtk+-3.0` -export-dynamic
    

    The files created by this process are:

    1. -rw-rw-r-- 1 okane okane   702 Aug  1 12:26 gtk1.h
      -rw-rw-r-- 1 okane okane  2055 Aug  1 12:26 gtk2.h
      -rw-rw-r-- 1 okane okane   541 Aug  1 12:26 gtk3.h
      

      These are files that containg declarations, initializations, and #include code that will be incorporated into the template file gtk.c.

    2. on.cbentry.changed.h 
      on.SampleColorButton.color.set.h 
      on.SampleGtkRadio2.toggled.h 
      on.ComboBoxExample.changed.h
      on.SampleGtkButton.clicked.h 
      on.SampleGtkRadio3.toggled.h 
      on.ExampleFontButton.font.set.h
      on.SampleGtkCheckButton.toggled.h
      on.SampleGtkToggleButton.toggled.h
      on.ExampleSwitch.state.set.h
      on.SampleGtkRadio1.toggled.h
      

      These are the signal handler files. Each contains a function to handle the named signal. If the name of the signal handler function is on_SampleGtkRadio1_toggled the files name will be on.SampleGtkCheckButton.toggled.h These files will also be included into the gtk.c template program at the end.

    3. The file gtk is the exectutable. If you execute it you get:

    4. The signal handler for the SampleGtkToggleButton toggled signal is in file on.SampleGtkToggleButton.toggled.h which contains the following:
      void on_SampleGtkToggleButton_toggled(GtkWidget *w) {
      printf("%s\n", "on.SampleGtkToggleButton.toggled.h");
      printf("\ttoggled = %d\n", gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w)));
      }
    5. If, in the app window, you click the SampleGtkToggleButton, the button will darken to indicate it has been depressed. This will raise the toggled signal and the function in on.SampleGtkToggleButton.toggled.h will be invoked. This will cause a message to appear on the invoking terminal window indicating that the button is active or inactive. This message is from the signal handler:

      Upon invocation of the handler and indication of the button status, the user can perform whatever action the button was intended for.


    Files Created and Used in the Button Example:

    gtk1.h (created by the compiler)

    #ifndef GTK1_H
    #define GTK1_H

    #include
    #include
    GtkBuilder *builder;
    GtkEntryBuffer *entrybuffer1;
    GtkListStore *liststore1;
    GtkWindow *window;
    GtkFixed *fixed1;
    GtkToggleButton *SampleGtkToggleButton;
    GtkCheckButton *SampleGtkCheckButton;
    GtkRadioButton *SampleGtkRadio1;
    GtkRadioButton *SampleGtkRadio2;
    GtkRadioButton *SampleGtkRadio3;
    GtkButton *SampleGtkButton;
    GtkColorButton *SampleColorButton;
    GtkSwitch *ExampleSwitch;
    GtkLabel *label1;
    GtkLabel *label2;
    GtkFontButton *ExampleFontButton;
    GtkComboBox *ComboBoxExample;
    GtkEntry *cbentry;

    #endif
    gtk2.h (created by the compiler)

    #ifndef GTK2_H
    #define GTK2_H

    gtk_init(&argc, &argv);
    builder = gtk_builder_new_from_file ("mumps.glade");

    entrybuffer1 = GTK_ENTRY_BUFFER(gtk_builder_get_object(builder, "entrybuffer1"));

    liststore1 = GTK_LIST_STORE(gtk_builder_get_object(builder, "liststore1"));

    window = GTK_WINDOW(gtk_builder_get_object(builder, "window"));

    fixed1 = GTK_FIXED(gtk_builder_get_object(builder, "fixed1"));

    SampleGtkToggleButton = GTK_TOGGLE_BUTTON(gtk_builder_get_object(builder, "SampleGtkToggleButton"));

    SampleGtkCheckButton = GTK_CHECK_BUTTON(gtk_builder_get_object(builder, "SampleGtkCheckButton"));

    SampleGtkRadio1 = GTK_RADIO_BUTTON(gtk_builder_get_object(builder, "SampleGtkRadio1"));

    SampleGtkRadio2 = GTK_RADIO_BUTTON(gtk_builder_get_object(builder, "SampleGtkRadio2"));

    SampleGtkRadio3 = GTK_RADIO_BUTTON(gtk_builder_get_object(builder, "SampleGtkRadio3"));

    SampleGtkButton = GTK_BUTTON(gtk_builder_get_object(builder, "SampleGtkButton"));

    SampleColorButton = GTK_COLOR_BUTTON(gtk_builder_get_object(builder, "SampleColorButton"));

    ExampleSwitch = GTK_SWITCH(gtk_builder_get_object(builder, "ExampleSwitch"));

    label1 = GTK_LABEL(gtk_builder_get_object(builder, "label1"));

    label2 = GTK_LABEL(gtk_builder_get_object(builder, "label2"));

    ExampleFontButton = GTK_FONT_BUTTON(gtk_builder_get_object(builder, "ExampleFontButton"));

    ComboBoxExample = GTK_COMBO_BOX(gtk_builder_get_object(builder, "ComboBoxExample"));

    cbentry = GTK_ENTRY(gtk_builder_get_object(builder, "cbentry"));

    g_signal_connect(window, "destroy", G_CALLBACK(gtk_main_quit), NULL);
    gtk_builder_connect_signals(builder, NULL);
    gtk_widget_show(GTK_WIDGET(window));

    #endif
    gtk3.h (created by the compiler)

    #ifndef GTK3_H
    #define GTK3_H

    #include "on.SampleGtkToggleButton.toggled.h"
    #include "on.SampleGtkCheckButton.toggled.h"
    #include "on.SampleGtkRadio1.toggled.h"
    #include "on.SampleGtkRadio2.toggled.h"
    #include "on.SampleGtkRadio3.toggled.h"
    #include "on.SampleGtkButton.clicked.h"
    #include "on.SampleColorButton.color.set.h"
    #include "on.ExampleSwitch.state.set.h"
    #include "on.ExampleFontButton.font.set.h"
    #include "on.ComboBoxExample.changed.h"
    #include "on.cbentry.changed.h"

    #endif
    Template file gtk.c

    //#*+++++++++++++++++++++++++++++++++++++++++
    //#+
    //#+ GTK Compiler
    //#+
    //#+ Copyright (C) 2022 by Kevin C. O'Kane
    //#+
    //#+ Kevin C. O'Kane
    //#+ kc.okane@gmail.com
    //#+ okane@uni.edu
    //#+ https://www.cs.uni.edu/~okane
    //#+ https://threadsafebooks.com/
    //#+
    //#+ This program is free software; you can redistribute it and/or modify
    //#+ it under the terms of the GNU General Public License as published by
    //#+ the Free Software Foundation; either version 2 of the License, or
    //#+ (at your option) any later version.
    //#+
    //#+ This program is distributed in the hope that it will be useful,
    //#+ but WITHOUT ANY WARRANTY; without even the implied warranty of
    //#+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    //#+ GNU General Public License for more details.
    //#+
    //#+ You should have received a copy of the GNU General Public License
    //#+ along with this program; if not, write to the Free Software
    //#+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
    //#+
    //#+ July 16, 2022
    //#*+++++++++++++++++++++++++++++++++++++++++

    #include "gtk1.h"

    int main(int argc, char **argv) {

    #include "gtk2.h"

    #include "user.h"

    gtk_main();

    printf("\nBye-bye\n");
    }

    #include "gtk3.h"
    Signal Handlers (created by the compiler)

    on.SampleGtkToggleButton.toggled.h

    void on_SampleGtkToggleButton_toggled(GtkWidget *w) {
    printf("%s\n", "on.SampleGtkToggleButton.toggled.h");
    printf("\ttoggled = %d\n", gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w)));
    }

    on.SampleGtkCheckButton.toggled.h

    void on_SampleGtkCheckButton_toggled(GtkWidget *w) {
    printf("%s\n", "on.SampleGtkCheckButton.toggled.h");
    printf("\tchecked = %d\n", gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w)));
    }

    on.SampleGtkRadio1.toggled.h

    void on_SampleGtkRadio1_toggled(GtkWidget *w) {
    printf("%s\n", "on.SampleGtkRadio1.toggled.h");
    printf("\tButton SampleGtkRadio1 clicked\n");
    printf("\tSampleGtkRadio1");
    if(gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(w)) == 1)
    printf(" active\n"); else printf(" inactive\n");
    }

    on.SampleGtkRadio2.toggled.h

    void on_SampleGtkRadio2_toggled(GtkWidget *w) {
    printf("%s\n", "on.SampleGtkRadio2.toggled.h");
    printf("\tButton SampleGtkRadio2 clicked\n");
    printf("\tSampleGtkRadio2");
    if(gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(w)) == 1)
    printf(" active\n"); else printf(" inactive\n");
    }

    on.SampleGtkRadio3.toggled.h

    void on_SampleGtkRadio3_toggled(GtkWidget *w) {
    printf("%s\n", "on.SampleGtkRadio3.toggled.h");
    printf("\tButton SampleGtkRadio3 clicked\n");
    printf("\tSampleGtkRadio3");
    if(gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(w)) == 1)
    printf(" active\n"); else printf(" inactive\n");
    }

    on.SampleGtkButton.clicked.h

    void on_SampleGtkButton_clicked(GtkWidget *w) {
    printf("%s\n", "on.SampleGtkButton.clicked.h");
    printf("\tButton clicked\n");
    }

    on.SampleColorButton.color.set.h

    void on_SampleColorButton_color_set(GtkWidget *w) {
    printf("%s\n", "on.SampleColorButton.color.set.h");
    GdkRGBA r;
    gtk_color_chooser_get_rgba (GTK_COLOR_CHOOSER(w), &r);
    printf("red=%f green=%f blue=%f alpha=%f\n", r.red, r.green, r.blue, r.alpha );
    }

    on.ExampleSwitch.state.set.h

    void on_ExampleSwitch_state_set(GtkWidget *w) {
    printf("%s\n", "on.ExampleSwitch.state.set.h");
    printf("\tActive: %d\n", gtk_switch_get_active (GTK_SWITCH(w)));
    }

    on.ExampleFontButton.font.set.h

    void on_ExampleFontButton_font_set(GtkWidget *w) {
    printf("%s\n", "on.ExampleFontButton.font.set.h");
    printf("\tfont = %s\n", gtk_font_chooser_get_font(GTK_FONT_CHOOSER(w)));
    }

    on.ComboBoxExample.changed.h

    void on_ComboBoxExample_changed(GtkWidget *w) {
    printf("%s\n", "on.ComboBoxExample.changed.h");
    }

    on.cbentry.changed.h

    void on_cbentry_changed(GtkWidget *w) {
    printf("%s\n", "on.cbentry.changed.h");
    printf("\t%s\n", gtk_entry_get_text(GTK_ENTRY(w)));
    }


    Other Widget Collections

    1. Directory mumps/Mumps-Projects/GTK-Compiler/C-Examples/Input-Widgets

    2. Directory mumps/Mumps-Projects/GTK-Compiler/C-Examples/Slider-Widgets

    3. Improved buttons example mumps/Mumps-Projects/Glade-Compiler/C-Examples/Button-Widgets

    4. Directory mumps/Mumps-Projects/GTK-Compiler/MDH-Examples/Mesh-Tree