GtkExpression

GtkExpression is a fundamental type. It is not a descendant of GObject. GtkExpression provides a way to describe references to values. GtkExpression needs to be evaluated to obtain a value.

It is similar to arithmetic calculation.

1 + 2 = 3

1+2 is an expression. It shows the way how to calculate. 3 is the value comes from the expression. Evaluation is to calculate the expression and get the value.

GtkExpression is a way to get a value. Evaluation is like a calculation. A value is got by evaluating the expression.

Constant expression

A constant expression (GtkConstantExpression) provides constant value or instance when it is evaluated.

  GValue value = G_VALUE_INIT;
  expression = gtk_constant_expression_new (G_TYPE_INT,100);
  gtk_expression_evaluate (expression, NULL, &value);
GType C type type name notes
G_TYPE_CHAR char gchar
G_TYPE_BOOLEAN int gboolean
G_TYPE_INT int gint
G_TYPE_FLOAT float gfloat
G_TYPE_DOUBLE double gdouble
G_TYPE_POINTER gpointer
G_TYPE_STRING gchararray null-terminated Cstring
G_TYPE_OBJECT GObject
GTK_TYPE_WINDOW GtkWindow

A sample program exp_constant_simple.c is in src/expression directory.

@@@include expression/exp_constant_simple.c @@@

Constant expression is usually used to give a constant value or instance to another expression.

Property expression

A property expression (GtkPropertyExpression) looks up a property in a GObject instance. For example, a property expression that refers “label” property in a GtkLabel object is created like this.

expression = gtk_property_expression_new (GTK_TYPE_LABEL, another_expression, "label");

The second parameter another_expression is one of:

For example,

label = gtk_label_new ("Hello");
another_expression = gtk_constant_expression_new (GTK_TYPE_LABEL, label);
expression = gtk_property_expression_new (GTK_TYPE_LABEL, another_expression, "label");

If expression is evaluated, the second parameter another_expression is evaluated in advance. The value of another_expression is the label (GtkLabel instance). Then, expression looks up “label” property of the label and the evaluation results “Hello”.

In the example above, the second argument of gtk_property_expression_new is another expression. But the second argument can be NULL. If it is NULL, this instance is used instead. this is given by gtk_expression_evaluate function.

There’s a simple program exp_property_simple.c in src/expression directory.

@@@include expression/exp_property_simple.c @@@

If the second argument of gtk_property_expression_new isn’t NULL, it is another expression. The expression is owned by a newly created property expression. So, when the expressions are useless, you just release the last expression. Then it releases another expression it has.

Closure expression

A closure expression calls closure when it is evaluated. A closure is a generic representation of a callback (a pointer to a function). For information about closure, see GObject API Reference – The GObject messaging system. There are simple closure example files closure.c and closure_each.c in the src/expression directory.

There are two types of closure expressions, GtkCClosureExpression and GtkClosureExpression. They corresponds to GCClosure and GClosure respectively. When you program in C language, GtkCClosureExpression and GCClosure are appropriate.

A closure expression is created with gtk_cclosure_expression_new function.

GtkExpression *
gtk_cclosure_expression_new (GType value_type,
                             GClosureMarshal marshal,
                             guint n_params,
                             GtkExpression **params,
                             GCallback callback_func,
                             gpointer user_data,
                             GClosureNotify user_destroy);

Call back functions have the following format.

C-type
callback (this, param1, param2, ...)

For example,

int
callback (GObject *object, int x, const char *s)

The following is exp_closure_simple.c in src/expression.

@@@include expression/exp_closure_simple.c @@@

Closure expression is flexible than other type of expression because you can specify your own callback function.

GtkExpressionWatch

GtkExpressionWatch is a structure, not an object. It represents a watched GtkExpression. Two functions create GtkExpressionWatch structure.

gtk_expression_bind function

This function binds the target object’s property to the expression. If the value of the expression changes, the property reflects the value immediately.

GtkExpressionWatch*
gtk_expression_bind (
  GtkExpression* self,
  GObject* target,
  const char* property,
  GObject* this_
)

This function takes the ownership of the expression. So, if you want to own the expression, call gtk_expression_ref () to increase the reference count of the expression. And you should unref it when it is useless. If you don’t own the expression, you don’t care about releasing the expression.

An example exp_bind.c and exp_bind.ui is in src/expression directory.

exp_bind

It includes a label and a scale. If you move the slider to the right, the scale value increases and the number on the label also increases. In the same way, if you move it to the left, the number on the label decreases. The label is bound to the scale value via an adjustment.

@@@include expression/exp_bind.ui @@@

The ui file describes the following parent-child relationship.

GtkApplicationWindow (win) -- GtkBox -+- GtkLabel (label)
                                      +- GtkScale

Four GtkScale properties are defined.

@@@include expression/exp_bind.c @@@

The point of the program is:

If you want to bind a property to an expression, gtk_expression_bind is the best choice. You can do it with gtk_expression_watch function, but it is less suitable.

gtk_expression_watch function

GtkExpressionWatch*
gtk_expression_watch (
  GtkExpression* self,
  GObject* this_,
  GtkExpressionNotify notify,
  gpointer user_data,
  GDestroyNotify user_destroy
)

The function doesn’t take the ownership of the expression. It differs from gtk_expression_bind. So, you need to release the expression when it is useless. It creates a GtkExpressionWatch structure. The third parameter notify is a callback to invoke when the expression changes. You can set user_data to give it to the callback. The last parameter is a function to destroy the user_data when the watch is unwatched. Put NULL if you don’t need them.

Notify callback has the following format.

void
notify (
  gpointer user_data
)

This function is used to do something when the value of the expression changes. But if you want to bind a property to the value, use gtk_expression_bind instead.

There’s a sample program exp_watch.c in src/expression directory. It outputs the width of the window to the standard output.

exp_watch

When you resize the window, the width is displayed in the terminal.

@@@include expression/exp_watch.c @@@

Gtkexpression in ui files

GtkBuilder supports GtkExpressions. There are four tags.

<constant type="gchararray">Hello world</constant>
<lookup name="label" type="GtkLabel">label</lookup>
<closure type="gint" function="callback_function"></closure>
<bind name="label">
  <lookup name="default-width">win</lookup>
</bind>

These tags are usually used for GtkBuilderListItemFactory.

<interface>
  <template class="GtkListItem">
    <property name="child">
      <object class="GtkLabel">
        <binding name="label">
          <lookup name="name" type="string">
            <lookup name="item">GtkListItem</lookup>
          </lookup>
        </binding>
      </object>
    </property>
  </template>
</interface>

In the xml file above, “GtkListItem” is an instance of the GtkListItem template. It is the ‘this’ object given to the expressions. (The information is in the GTK Development Blog).

GtkBuilderListItemFactory uses GtkBuilder to build the XML data. It sets the current object of the GtkBuilder to the GtkListItem instance.

GtkBuilder calls gtk_expression_bind function in the binding tag analysis. The function sets the ‘this’ object like this:

  1. If the binding tag has object attribute, the object will be the ‘this’ object.
  2. If the current object of the GtkBuilder exists, it will be the ‘this’ object. That’s why a GtkListItem instance is the ‘this’ object of the XML data for a GtkBuilderListItemFactory.
  3. Otherwise, the target object of the binding tag will be the ‘this’ object.

GTK 4 document doesn’t describe information about “this” object when expressions are defined in a ui file. The information above is found from the GTK 4 source files and it is possible to include mistakes. If you have accurate information, please let me know.

A sample program exp.c and a ui file exp.ui is in src/expression directory. The ui file includes lookup, closure and bind tags. No constant tag is included. However, constant tags are not used so often.

exp.c

If you resize the window, the size is shown at the title of the window. If you type characters in the entry, the same characters appear on the label.

The ui file is as follows.

@@@include expression/exp.ui @@@

The C source file is as follows.

@@@include expression/exp.c @@@

The C source file is very simple because almost everything is done in the ui file.

Conversion between GValues

If you bind different type properties, type conversion is automatically done. Suppose a label property (string) is bound to default-width property (int).

<object class="GtkLabel">
  <binding name="label">
    <lookup name="default-width">
      win
    </lookup>
  </binding>
</object>

The expression created by the lookup tag returns a int type GValue. On the other hand “label” property holds a string type GValue. When a GValue is copied to another GValue, the type is automatically converted if possible. If the current width is 100, an int 100 is converted to a string "100".

If you use g_object_get and g_object_set to copy properties, the value is automatically converted.