From 3ada90257e695509cae80f1d13219899f6aa602f Mon Sep 17 00:00:00 2001
From: Toshio Sekiya
tfe
(Text File Editor).GtkListView, GtkGridView, GtkColumnView and related objects are -described in Section 26 to 29.
+described in Section 29 to 33.A list is a sequential data structure. For example, an ordered string sequence “one”, “two”, “three”, “four” is a list. Each element is called item. A list is like an array, but in many cases it is implemented with pointers which point to the next items of the list. And it has a start point. So, each item can be referred by the index of the item (first -item, second item, …, nth item, …). There are two cases. One is the +item, second item, …, nth item, …). There are two cases. The one is the index starts from one (one-based) and the other is from zero (zero-based).
Gio provides GListModel interface. It is a zero-based list and its @@ -138,12 +139,12 @@ implement the same interface. An object implements GListModel is not a widget. So, the list is not displayed on the screen directly. There’s another object GtkListView which is a widget to display the list. The items in the list need to be connected to the items in GtkListView. -GtkListItemFactory instance maps items in the list to GListView.
+GtkListItemFactory instance maps items in the list to GtkListView. -If you want to make a list of strings with GListModel, for example, “one”, “two”, “three”, “four”, note that strings can’t be items of the list. Because GListModel is a list of GObject objects and strings aren’t @@ -356,7 +357,7 @@ instantiated.
Therefore, GtkListItem instance is used as the this
object of the lookup tag when it is evaluated. this
object
-will be explained in section 30.
The C source code is as follows. Its name is list2.c
and
located under src/misc directory.
g_file_enumerate_children_async() to get the GFileInfo objects. The list model is created bygtk_directory_list_new
function. -+*gtk_directory_list_new (const char *attributes, GFile *file); GtkDirectoryList
*gtk_directory_list_new (const char *attributes, GFile *file); GtkDirectoryList
attributes
is a comma separated list of file attributes. File attributes are key-value pairs. A key consists of a namespace and a name. For example, “standard::name” key is the name of a file. @@ -477,7 +478,7 @@ seconds since the UNIX epochThe current directory is “.”. The following program makes GtkDirectoryList
-dl
and its contents are GFileInfo objects under the current directory.*file = g_file_new_for_path ("."); + GFile
*file = g_file_new_for_path ("."); GFile *dl = gtk_directory_list_new ("standard::name", file); GtkDirectoryList (file); g_object_unref
It is not so difficult to make file listing program by changing @@ -486,7 +487,7 @@ GInfoFile doesn’t have properties. Lookup tag look for a property, so it is useless for looking for a filename from a GFileInfo object. Instead, closure tag is appropriate in this case. Closure tag specifies a function and the type of the return value of the function.
-const char * +
char * (GtkListItem *item, GFileInfo *info) { get_file_name return G_IS_FILE_INFO (info) ? g_strdup (g_file_info_get_name (info)) : NULL; } @@ -526,7 +527,7 @@ the function. the value of the item property of the GtkListItem. This will be the second argument of the function. The first parameter is always the GListItem instance, which is a ‘this’ object. The ‘this’ object is -explained in section 28. +explained in section 31.
gtk_file_name
function is the callback function for the closure tag. It first checks theinfo
parameter. Because it can be NULL when GListItemitem
is unbounded. If it’s diff --git a/docs/sec30.html b/docs/sec30.html index 5a47641..734391d 100644 --- a/docs/sec30.html +++ b/docs/sec30.html @@ -173,8 +173,7 @@ registered to IANA media types. Such “x-” subtype is not a standard mime type.) Content type is also used by desktop systems.GtkGridView uses the same GtkSingleSelection instance -(
+(singleselection
). So, its model property is set with -it.singleselection
). So, its model property is set to it.Ui file of the window
The window is built with the following ui file. (See the screenshot at the beginning of this section).
@@ -291,7 +290,7 @@ GtkListView or GtkGridView.The action
-view
is created, connected to the “activate” signal handler and inserted to the window (action map) as follows.= g_simple_action_new_stateful ("view", g_variant_type_new("s"), g_variant_new_string ("list")); + act_view
= g_simple_action_new_stateful ("view", g_variant_type_new("s"), g_variant_new_string ("list")); act_view (act_view, "activate", G_CALLBACK (view_activated), NULL); g_signal_connect (G_ACTION_MAP (win), G_ACTION (act_view)); g_action_map_add_action
The signal handler
view_activated
will be explained @@ -464,7 +463,7 @@ pressed. You can do anything you like by connecting the “activate” signal to the handler.The example
-list4
launchestfe
text file editor if the item of the list is a text file.static void +
static void (GtkListView *list, int position, gpointer user_data) { list_activate *info = G_FILE_INFO (g_list_model_get_item (G_LIST_MODEL (gtk_list_view_get_model (list)), position)); GFileInfo (info); @@ -558,12 +557,12 @@ list and items. launch_tfe_with_file
g_app_info_launch_default_for_uri
is convenient. The function automatically determines the default application from the file and launches it. For example, if the file is text, then it launches -gedit with the file. Such feature comes from desktop. +GNOME text editor with the file. Such feature comes from desktop.Compilation and execution
The source files are located in src/list4 directory. To compile and execute list4, type as follows.
$ cd list4 # or cd src/list4. It depends your current directory. -$ meson _build +$ meson setup _build $ ninja -C _build $ _build/list4
Then a file list appears as a list style. Click on a button on the diff --git a/docs/sec31.html b/docs/sec31.html index 00ea9f9..d4564e3 100644 --- a/docs/sec31.html +++ b/docs/sec31.html @@ -191,13 +191,13 @@ value of the expression. The type of the value is int.
G_TYPE_POINTER -+ void * gpointer -+ general pointer @@ -250,7 +250,7 @@ instance to another expression. G_TYPE_STRING -+ char * gchararray null-terminated Cstring 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.
-+= gtk_property_expression_new (GTK_TYPE_LABEL, another_expression, "label"); expression
= gtk_property_expression_new (GTK_TYPE_LABEL, another_expression, "label"); expression
The second parameter
another_expression
is one of:
- An expression that gives a GtkLabel instance when it is @@ -259,14 +259,14 @@ evaluated.
is evaluated. The instance is calledthis
object.For example,
-= gtk_label_new ("Hello"); + label
= gtk_label_new ("Hello"); label = gtk_constant_expression_new (GTK_TYPE_LABEL, label); another_expression = gtk_property_expression_new (GTK_TYPE_LABEL, another_expression, "label"); expression
If
+the label and the evaluation results in “Hello”.expression
is evaluated, the second parameteranother_expression
is evaluated in advance. The value ofanother_expression
is thelabel
(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 @@ -291,7 +291,7 @@ class="sourceCode numberSource C numberLines">if (gtk_expression_evaluate (expression, label, &value)) g_print ("The value is %s.\n", g_value_get_string (&value)); else - g_print ("The constant expression wasn't evaluated correctly.\n"); + g_print ("The property expression wasn't evaluated correctly.\n"); gtk_expression_unref (expression); g_value_unset (&value); @@ -311,8 +311,8 @@ the expression with a ‘this’ instance
label
. The result is stored in the GValuevalue
. The functiong_value_get_string
gets a string from the GValue. But the string is owned by the GValue so you must not free the string. -18-19: Release the expression and unset the GValue. At the same time -the string in the GValue is freed. +18-19: Releases the expression and unset the GValue. At the same +time the string in the GValue is freed. If the second argument of
gtk_property_expression_new
isn’t NULL, it is another expression. The expression is owned by a newly @@ -334,79 +334,44 @@ respectively. When you program in C language, GtkCClosureExpression and GCClosure are appropriate.A closure expression is created with
-gtk_cclosure_expression_new
function.-* - GtkExpression (GType value_type, - gtk_cclosure_expression_new , - GClosureMarshal marshal, - guint n_params**params, - GtkExpression , - GCallback callback_func, - gpointer user_data); GClosureNotify user_destroy
-
-- -
value_type
is the type of the value when it is -evaluated.- -
marshal
is a marshaller. You can assign NULL. If it is -NULL, theng_cclosure_marshal_generic ()
is used as a -marshaller. It is a generic marshaller function implemented via -libffi.- -
n_params
is the number of parameters.- -
params
points expressions for each parameter of the -call back function.- -
callback_func
is a callback function. It is given -argumentsthis
and parameters above. So, if -n_params
is 3, the number of arguments of the function is -4. (this
andparams
. See below.)- -
user_data
is user data. You can add it for the closure. -It is likeuser_data
ing_signal_connect
. If -it is not necessary, assign NULL.- -
user_destroy
is a destroy notify for -user_data
. It is called to destroyuser_data
-when it is no longer needed. If NULL is assigned to -user_data
, assign NULL touser_destroy
, -too.Call back functions have the following format.
--C-type -callback (this, param1, param2, ...)
For example,
-+int -(GObject *object, int x, const char *s) callback
int +(GObject *object, int x, const char *s) callback
The following is
-exp_closure_simple.c
insrc/expression
.+#include <gtk/gtk.h> - -static int -calc (GtkLabel *label) { /* this object */ - const char * s; - int i, j; - - s = gtk_label_get_text (label); /* s is owned by the label. */ - sscanf (s, "%d+%d", &i, &j); - return i+j; -} - -int -main (int argc, char **argv) { - GtkExpression *expression; - GValue value = G_VALUE_INIT; - GtkLabel *label; - - gtk_init (); - label = GTK_LABEL (gtk_label_new ("123+456")); - g_object_ref_sink (label); - expression = gtk_cclosure_expression_new (G_TYPE_INT, NULL, 0, NULL, - G_CALLBACK (calc), NULL, NULL); - if (gtk_expression_evaluate (expression, label, &value)) /* 'this' object is the label. */ - g_print ("%d\n", g_value_get_int (&value)); - else - g_print ("The closure expression wasn't evaluated correctly.\n"); - gtk_expression_unref (expression); - g_value_unset (&value); - g_object_unref (label); - - return 0; -}
#include <gtk/gtk.h> + +static int +calc (GtkLabel *label) { /* this object */ + const char * s; + int i, j; + + s = gtk_label_get_text (label); /* s is owned by the label. */ + sscanf (s, "%d+%d", &i, &j); + return i+j; +} + +int +main (int argc, char **argv) { + GtkExpression *expression; + GValue value = G_VALUE_INIT; + GtkLabel *label; + + gtk_init (); + label = GTK_LABEL (gtk_label_new ("123+456")); + g_object_ref_sink (label); + expression = gtk_cclosure_expression_new (G_TYPE_INT, NULL, 0, NULL, + G_CALLBACK (calc), NULL, NULL); + if (gtk_expression_evaluate (expression, label, &value)) /* 'this' object is the label. */ + g_print ("%d\n", g_value_get_int (&value)); + else + g_print ("The closure expression wasn't evaluated correctly.\n"); + gtk_expression_unref (expression); + g_value_unset (&value); + g_object_unref (label); + + return 0; +}
- 3-11: A call back function. The parameter is only one and it is a ‘this’ object. It is a GtkLabel and its label is assumed to be @@ -419,16 +384,17 @@ argument of
-gtk_cclosure_expression_new
isG_TYPE_POINTER
. There is a sample programexp_closure_with_error_report
insrc/expression
directory.- 19: gtk_init initializes GTK. It is necessary for GtkLabel.
+- 19: The function `gtk_init`` initializes GTK. It is necessary for +GtkLabel.
- 20: A GtkLabel instance is created with “123+456”.
- 21: The instance has floating reference. It is changed to an ordinary reference count.
-- 22-23: Create a closure expression. Its return value type is +
- 22-23: Creates a closure expression. Its return value type is
G_TYPE_INT
and no parameters or ‘this’ object.- 24: Evaluates the expression with the label as a ‘this’ object.
-- 25: If the evaluation successes, show the sum of “123+456”. It’s -579.
-- 27: If it fails, show an error message.
+- 25: If the evaluation successes, the sum of “123+456”, which is 579, +is shown.
+- 27: If it fails, an error message appears.
- 28-30: Releases the expression and the label. Unsets the value.
Closure expression is flexible than other type of expression because @@ -436,18 +402,19 @@ 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.
+structure. They aregtk_expression_bind
and +gtk_expression_watch
.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 * self, - GtkExpression* target, - GObjectconst char* property, - * this_ - GObject)
* + GtkExpressionWatch( + gtk_expression_bind * self, + GtkExpression* target, + GObjectconst char* property, + * this_ + GObject)
This function takes the ownership of the expression. So, if you want to own the expression, call
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. -gtk_expression_ref ()
to increase the reference count of the expression. And you should unref it @@ -463,41 +430,41 @@ about releasing the expression.+<?xml version='1.0' encoding='UTF-8'?> -<interface> - <object class='GtkApplicationWindow' id='win'> - <property name='default-width'>600</property> - <child> - <object class='GtkBox'> - <property name='orientation'>GTK_ORIENTATION_VERTICAL</property> - <child> - <object class='GtkLabel' id='label'> - <property name="label">10</property> - </object> - </child> - <child> - <object class='GtkScale'> - <property name='adjustment'> - <object class='GtkAdjustment' id='adjustment'> - <property name='upper'>20.0</property> - <property name='lower'>0.0</property> - <property name='value'>10.0</property> - <property name='step-increment'>1.0</property> - <property name='page-increment'>5.0</property> - <property name='page-size'>0.0</property> - </object> - </property> - <property name='digits'>0</property> - <property name='draw-value'>true</property> - <property name='has-origin'>true</property> - <property name='round-digits'>0</property> - </object> - </child> - </object> - </child> - </object> -</interface>
<?xml version='1.0' encoding='UTF-8'?> +<interface> + <object class='GtkApplicationWindow' id='win'> + <property name='default-width'>600</property> + <child> + <object class='GtkBox'> + <property name='orientation'>GTK_ORIENTATION_VERTICAL</property> + <child> + <object class='GtkLabel' id='label'> + <property name="label">10</property> + </object> + </child> + <child> + <object class='GtkScale'> + <property name='adjustment'> + <object class='GtkAdjustment' id='adjustment'> + <property name='upper'>20.0</property> + <property name='lower'>0.0</property> + <property name='value'>10.0</property> + <property name='step-increment'>1.0</property> + <property name='page-increment'>5.0</property> + <property name='page-size'>0.0</property> + </object> + </property> + <property name='digits'>0</property> + <property name='draw-value'>true</property> + <property name='has-origin'>true</property> + <property name='round-digits'>0</property> + </object> + </child> + </object> + </child> + </object> +</interface>
The ui file describes the following parent-child relationship.
@@ -523,73 +490,73 @@ orange bar appears between the origin and the current point. changes. For example, if it is zero, the slider moves to an integer point. -GtkApplicationWindow (win) -- GtkBox -+- GtkLabel (label) +- GtkScale
+#include <gtk/gtk.h> - -GtkExpressionWatch *watch; - -static int -f2i (GObject *object, double d) { - return (int) d; -} - -static int -close_request_cb (GtkWindow *win) { - gtk_expression_watch_unwatch (watch); - return false; -} - -static void -app_activate (GApplication *application) { - GtkApplication *app = GTK_APPLICATION (application); - gtk_window_present (gtk_application_get_active_window(app)); -} - -static void -app_startup (GApplication *application) { - GtkApplication *app = GTK_APPLICATION (application); - GtkBuilder *build; - GtkWidget *win, *label; - GtkAdjustment *adjustment; - GtkExpression *expression, *params[1]; - - /* Builds a window with exp.ui resource */ - build = gtk_builder_new_from_file ("exp_bind.ui"); - win = GTK_WIDGET (gtk_builder_get_object (build, "win")); - label = GTK_WIDGET (gtk_builder_get_object (build, "label")); - // scale = GTK_WIDGET (gtk_builder_get_object (build, "scale")); - adjustment = GTK_ADJUSTMENT (gtk_builder_get_object (build, "adjustment")); - gtk_window_set_application (GTK_WINDOW (win), app); - g_signal_connect (win, "close-request", G_CALLBACK (close_request_cb), NULL); - g_object_unref (build); - - /* GtkExpressionWatch */ - params[0] = gtk_property_expression_new (GTK_TYPE_ADJUSTMENT, NULL, "value"); - expression = gtk_cclosure_expression_new (G_TYPE_INT, NULL, 1, params, G_CALLBACK (f2i), NULL, NULL); - watch = gtk_expression_bind (expression, label, "label", adjustment); /* watch takes the ownership of the expression. */ -} - -#define APPLICATION_ID "com.github.ToshioCP.exp_watch" - -int -main (int argc, char **argv) { - GtkApplication *app; - int stat; - - app = gtk_application_new (APPLICATION_ID, G_APPLICATION_DEFAULT_FLAGS); - - g_signal_connect (app, "startup", G_CALLBACK (app_startup), NULL); - g_signal_connect (app, "activate", G_CALLBACK (app_activate), NULL); - - stat =g_application_run (G_APPLICATION (app), argc, argv); - g_object_unref (app); - return stat; -}
#include <gtk/gtk.h> + +GtkExpressionWatch *watch; + +static int +f2i (GObject *object, double d) { + return (int) d; +} + +static int +close_request_cb (GtkWindow *win) { + gtk_expression_watch_unwatch (watch); + return false; +} + +static void +app_activate (GApplication *application) { + GtkApplication *app = GTK_APPLICATION (application); + gtk_window_present (gtk_application_get_active_window(app)); +} + +static void +app_startup (GApplication *application) { + GtkApplication *app = GTK_APPLICATION (application); + GtkBuilder *build; + GtkWidget *win, *label; + GtkAdjustment *adjustment; + GtkExpression *expression, *params[1]; + + /* Builds a window with exp.ui resource */ + build = gtk_builder_new_from_resource ("/com/github/ToshioCP/exp/exp_bind.ui"); + win = GTK_WIDGET (gtk_builder_get_object (build, "win")); + label = GTK_WIDGET (gtk_builder_get_object (build, "label")); + // scale = GTK_WIDGET (gtk_builder_get_object (build, "scale")); + adjustment = GTK_ADJUSTMENT (gtk_builder_get_object (build, "adjustment")); + gtk_window_set_application (GTK_WINDOW (win), app); + g_signal_connect (win, "close-request", G_CALLBACK (close_request_cb), NULL); + g_object_unref (build); + + /* GtkExpressionWatch */ + params[0] = gtk_property_expression_new (GTK_TYPE_ADJUSTMENT, NULL, "value"); + expression = gtk_cclosure_expression_new (G_TYPE_INT, NULL, 1, params, G_CALLBACK (f2i), NULL, NULL); + watch = gtk_expression_bind (expression, label, "label", adjustment); /* watch takes the ownership of the expression. */ +} + +#define APPLICATION_ID "com.github.ToshioCP.exp_watch" + +int +main (int argc, char **argv) { + GtkApplication *app; + int stat; + + app = gtk_application_new (APPLICATION_ID, G_APPLICATION_DEFAULT_FLAGS); + + g_signal_connect (app, "startup", G_CALLBACK (app_startup), NULL); + g_signal_connect (app, "activate", G_CALLBACK (app_activate), NULL); + + stat =g_application_run (G_APPLICATION (app), argc, argv); + g_object_unref (app); + return stat; +}
The point of the program is:
- 41-42: Two expressions are defined. One is a property expression and -the other is a closure expression. The property expression look up the -“value”property of the adjustment instance. The closure expression just +the other is a closure expression. The property expression looks up the +“value” property of the adjustment instance. The closure expression just converts the double into an integer.
- 43:
gtk_expression_bind
binds the label property of the GtkLabel instance to the integer returned by the closure expression. It @@ -603,24 +570,23 @@ is destroyed.close_request_cb
. This signal is emitted when the close button is clicked. The handler is called just before the window closes. It is the right moment to make the GtkExpressionWatch unwatched. -- 10-14: “close-request” signal handler. +
- 10-14: “close-request” signal handler. The function
+watching the expression. It also releases the expression.gtk_expression_watch_unwatch (watch)
makes the watch stop -watching the expression. It releases the expression and calls -gtk_expression_watch_unref (watch)
in it.If you want to bind a property to an expression,
gtk_expression_bind
is the best choice. You can do it withgtk_expression_watch
function, but it is less suitable.gtk_expression_watch function
-+* - GtkExpressionWatch( - gtk_expression_watch * self, - GtkExpression* this_, - GObject, - GtkExpressionNotify notify, - gpointer user_data - GDestroyNotify user_destroy)
* + GtkExpressionWatch( + gtk_expression_watch * self, + GtkExpression* this_, + GObject, + 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 @@ -630,10 +596,10 @@ to give it to the callback. The last parameter is a function to destroy theuser_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)
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
@@ -646,63 +612,63 @@ window to the standard output.gtk_expression_bind
instead.When you resize the window, the width is displayed in the terminal.
-+#include <gtk/gtk.h> - -GtkExpression *expression; -GtkExpressionWatch *watch; - -static void -notify (gpointer user_data) { - GValue value = G_VALUE_INIT; - - if (gtk_expression_watch_evaluate (watch, &value)) - g_print ("width = %d\n", g_value_get_int (&value)); - else - g_print ("evaluation failed.\n"); -} - -static int -close_request_cb (GtkWindow *win) { - gtk_expression_watch_unwatch (watch); - gtk_expression_unref (expression); - return false; -} - -static void -app_activate (GApplication *application) { - GtkApplication *app = GTK_APPLICATION (application); - gtk_window_present (gtk_application_get_active_window(app)); -} - -static void -app_startup (GApplication *application) { - GtkApplication *app = GTK_APPLICATION (application); - GtkWidget *win; - - win = GTK_WIDGET (gtk_application_window_new (app)); - g_signal_connect (win, "close-request", G_CALLBACK (close_request_cb), NULL); - - expression = gtk_property_expression_new (GTK_TYPE_WINDOW, NULL, "default-width"); - watch = gtk_expression_watch (expression, win, notify, NULL, NULL); -} - -#define APPLICATION_ID "com.github.ToshioCP.exp_watch" - -int -main (int argc, char **argv) { - GtkApplication *app; - int stat; - - app = gtk_application_new (APPLICATION_ID, G_APPLICATION_DEFAULT_FLAGS); - - g_signal_connect (app, "startup", G_CALLBACK (app_startup), NULL); - g_signal_connect (app, "activate", G_CALLBACK (app_activate), NULL); - - stat =g_application_run (G_APPLICATION (app), argc, argv); - g_object_unref (app); - return stat; -}
#include <gtk/gtk.h> + +GtkExpression *expression; +GtkExpressionWatch *watch; + +static void +notify (gpointer user_data) { + GValue value = G_VALUE_INIT; + + if (gtk_expression_watch_evaluate (watch, &value)) + g_print ("width = %d\n", g_value_get_int (&value)); + else + g_print ("evaluation failed.\n"); +} + +static int +close_request_cb (GtkWindow *win) { + gtk_expression_watch_unwatch (watch); + gtk_expression_unref (expression); + return false; +} + +static void +app_activate (GApplication *application) { + GtkApplication *app = GTK_APPLICATION (application); + gtk_window_present (gtk_application_get_active_window(app)); +} + +static void +app_startup (GApplication *application) { + GtkApplication *app = GTK_APPLICATION (application); + GtkWidget *win; + + win = GTK_WIDGET (gtk_application_window_new (app)); + g_signal_connect (win, "close-request", G_CALLBACK (close_request_cb), NULL); + + expression = gtk_property_expression_new (GTK_TYPE_WINDOW, NULL, "default-width"); + watch = gtk_expression_watch (expression, win, notify, NULL, NULL); +} + +#define APPLICATION_ID "com.github.ToshioCP.exp_watch" + +int +main (int argc, char **argv) { + GtkApplication *app; + int stat; + + app = gtk_application_new (APPLICATION_ID, G_APPLICATION_DEFAULT_FLAGS); + + g_signal_connect (app, "startup", G_CALLBACK (app_startup), NULL); + g_signal_connect (app, "activate", G_CALLBACK (app_activate), NULL); + + stat =g_application_run (G_APPLICATION (app), argc, argv); + g_object_unref (app); + return stat; +}
-
- 37: A property expression looks up the “default-width” property of the window.
@@ -738,37 +704,36 @@ expressions. content of an object tag. Name attribute specifies the property name of the object. The content is an expression.+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> </
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> </
+interface> + <template class="GtkListItem"> + <property name="child"> + <object class="GtkLabel"> + <binding name="label"> + <lookup name="string" type="GtkStringObject"> + <lookup name="item">GtkListItem</lookup> + <lookup> + </binding> + </object> + </property> + </template> + </interface> </
GtkBuilderListItemFactory uses GtkBuilder to extends the GtkListItem +with the XML data.
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:GtkBuilder calls
gtk_expression_bind
function when it +finds a binding tag. The function sets the ‘this’ object like this:
- If the binding tag has object attribute, the object will be the ‘this’ object.
@@ -794,41 +759,41 @@ constant tags are not used so often. window. If you type characters in the entry, the same characters appear on the label.The ui file is as follows.
-+<?xml version="1.0" encoding="UTF-8"?> -<interface> - <object class="GtkApplicationWindow" id="win"> - <binding name="title"> - <closure type="gchararray" function="set_title"> - <lookup name="default-width" type="GtkWindow"></lookup> - <lookup name="default-height" type="GtkWindow"></lookup> - </closure> - </binding> - <property name="default-width">600</property> - <property name="default-height">400</property> - <child> - <object class="GtkBox"> - <property name="orientation">GTK_ORIENTATION_VERTICAL</property> - <child> - <object class="GtkLabel"> - <binding name="label"> - <lookup name="text"> - buffer - </lookup> - </binding> - </object> - </child> - <child> - <object class="GtkEntry"> - <property name="buffer"> - <object class="GtkEntryBuffer" id="buffer"></object> - </property> - </object> - </child> - </object> - </child> - </object> -</interface>
<?xml version="1.0" encoding="UTF-8"?> +<interface> + <object class="GtkApplicationWindow" id="win"> + <binding name="title"> + <closure type="gchararray" function="set_title"> + <lookup name="default-width" type="GtkWindow"></lookup> + <lookup name="default-height" type="GtkWindow"></lookup> + </closure> + </binding> + <property name="default-width">600</property> + <property name="default-height">400</property> + <child> + <object class="GtkBox"> + <property name="orientation">GTK_ORIENTATION_VERTICAL</property> + <child> + <object class="GtkLabel"> + <binding name="label"> + <lookup name="text"> + buffer + </lookup> + </binding> + </object> + </child> + <child> + <object class="GtkEntry"> + <property name="buffer"> + <object class="GtkEntryBuffer" id="buffer"></object> + </property> + </object> + </child> + </object> + </child> + </object> +</interface>
- 4-9: The title property of the main window is bound to a closure expression. Its callback function
set_title
is defined in @@ -844,48 +809,48 @@ defined in line 25. If a user types characters in the entry, the same characters appear on the label.The C source file is as follows.
-+#include <gtk/gtk.h> - -char * -set_title (GtkWidget *win, int width, int height) { - return g_strdup_printf ("%d x %d", width, height); -} - -static void -app_activate (GApplication *application) { - GtkApplication *app = GTK_APPLICATION (application); - gtk_window_present (gtk_application_get_active_window(app)); -} - -static void -app_startup (GApplication *application) { - GtkApplication *app = GTK_APPLICATION (application); - GtkBuilder *build; - GtkWidget *win; - - build = gtk_builder_new_from_resource ("/com/github/ToshioCP/exp/exp.ui"); - win = GTK_WIDGET (gtk_builder_get_object (build, "win")); - gtk_window_set_application (GTK_WINDOW (win), app); - g_object_unref (build); -} - -#define APPLICATION_ID "com.github.ToshioCP.exp" - -int -main (int argc, char **argv) { - GtkApplication *app; - int stat; - - app = gtk_application_new (APPLICATION_ID, G_APPLICATION_DEFAULT_FLAGS); - - g_signal_connect (app, "startup", G_CALLBACK (app_startup), NULL); - g_signal_connect (app, "activate", G_CALLBACK (app_activate), NULL); - - stat =g_application_run (G_APPLICATION (app), argc, argv); - g_object_unref (app); - return stat; -}
#include <gtk/gtk.h> + +char * +set_title (GtkWidget *win, int width, int height) { + return g_strdup_printf ("%d x %d", width, height); +} + +static void +app_activate (GApplication *application) { + GtkApplication *app = GTK_APPLICATION (application); + gtk_window_present (gtk_application_get_active_window(app)); +} + +static void +app_startup (GApplication *application) { + GtkApplication *app = GTK_APPLICATION (application); + GtkBuilder *build; + GtkWidget *win; + + build = gtk_builder_new_from_resource ("/com/github/ToshioCP/exp/exp.ui"); + win = GTK_WIDGET (gtk_builder_get_object (build, "win")); + gtk_window_set_application (GTK_WINDOW (win), app); + g_object_unref (build); +} + +#define APPLICATION_ID "com.github.ToshioCP.exp" + +int +main (int argc, char **argv) { + GtkApplication *app; + int stat; + + app = gtk_application_new (APPLICATION_ID, G_APPLICATION_DEFAULT_FLAGS); + + g_signal_connect (app, "startup", G_CALLBACK (app_startup), NULL); + g_signal_connect (app, "activate", G_CALLBACK (app_activate), NULL); + + stat =g_application_run (G_APPLICATION (app), argc, argv); + g_object_unref (app); + return stat; +}
- 4-6: The callback function. It returns a string (w)x(h), where the w and h are the width and height of the window. String duplication is @@ -893,18 +858,18 @@ necessary.
The C source file is very simple because almost everything is done in the ui file.
-Conversion between GValues
+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"> - < - winlookup> - </binding> - </object> </
object class="GtkLabel"> + <binding name="label"> + <lookup name="default-width"> + < + winlookup> + </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 @@ -912,6 +877,37 @@ if possible. If the current width is 100, an int
100
is converted to a string"100"
.If you use
+g_object_get
andg_object_set
to copy properties, the value is automatically converted.Meson.build
+The source files are in
+src/expression
directory. You +can build all the files at once.+$ cd src/expression +$ meson setup _build +$ ninja -C _build
For example, if you want to run “exp”, which is the executable file +from “exp.c”, type
+_build/exp
. You can run other programs +as well.The file
+meson.build
is as follows.project('exp', 'c') + +gtkdep = dependency('gtk4') + +gnome=import('gnome') +resources = gnome.compile_resources('resources','exp.gresource.xml') + +sourcefiles=files('exp.c') + +executable('exp', sourcefiles, resources, dependencies: gtkdep, export_dynamic: true, install: false) +executable('exp_constant', 'exp_constant.c', dependencies: gtkdep, export_dynamic: true, install: false) +executable('exp_constant_simple', 'exp_constant_simple.c', dependencies: gtkdep, export_dynamic: true, install: false) +executable('exp_property_simple', 'exp_property_simple.c', dependencies: gtkdep, export_dynamic: true, install: false) +executable('closure', 'closure.c', dependencies: gtkdep, export_dynamic: true, install: false) +executable('closure_each', 'closure_each.c', dependencies: gtkdep, export_dynamic: true, install: false) +executable('exp_closure_simple', 'exp_closure_simple.c', dependencies: gtkdep, export_dynamic: true, install: false) +executable('exp_closure_with_error_report', 'exp_closure_with_error_report.c', dependencies: gtkdep, export_dynamic: true, install: false) +executable('exp_bind', 'exp_bind.c', resources, dependencies: gtkdep, export_dynamic: true, install: false) +executable('exp_watch', 'exp_watch.c', dependencies: gtkdep, export_dynamic: true, install: false) +executable('exp_test', 'exp_test.c', resources, dependencies: gtkdep, export_dynamic: true, install: false)
GtkBuilderlistItemFactory is convenient when GtkListView just shows -the contents of a list. Its binding direction is always from an item of -a list to a child of GtkListItem.
-When it comes to dynamic connection, it’s not enough. For example, -you want to edit the contents of a list. You set a child of GtkListItem -to a GtkText instance so a user can edit a text with it. You need to -bind an item in the list with the buffer of the GtkText. The direction -is opposite from the one with GtkBuilderListItemFactory. It is from the -GtkText instance to the item in the list. You can implement this with -GtkSignalListItemFactory, which is more flexible than -GtkBuilderListItemFactory.
-Two things are shown in this section.
-This section shows just a part of the source file
-listeditor.c
. If you want to see the whole codes, see
-src/listeditor
directory of the Gtk4 tutorial
-repository.
The sample program is a list editor and data of the list are strings. -It’s the same as a line editor. It reads a text file line by line. Each -line is an item of the list. The list is displayed with GtkColumnView. -There are two columns. The one is a button, which makes the line be a -current line. If the line is the current line, the button is colored -with red. The other is a string which is the contents of the -corresponding item of the list.
- -The source files are located at src/listeditor
-directory. You can compile end execute it as follows.
src/listeditor
.$ meson _build
-$ ninja -C _build
-$ _build/listeditor
-The current line number (zero-based) is shown at the left of the tool -bar. The file name is shown at the right of the write button.
-The second column (GtkColumnViewColumn) sets its factory property to -GtkSignalListItemFactory. It uses three signals setup, bind and unbind. -The following is their sgnal handlers.
-static void
-setup2_cb (GtkListItemFactory *factory, GtkListItem *listitem) {
- GtkWidget *text = gtk_text_new ();
- gtk_list_item_set_child (listitem, GTK_WIDGET (text));
- gtk_editable_set_alignment (GTK_EDITABLE (text), 0.0);
-}
-
-static void
-bind2_cb (GtkListItemFactory *factory, GtkListItem *listitem) {
- GtkWidget *text = gtk_list_item_get_child (listitem);
- GtkEntryBuffer *buffer = gtk_text_get_buffer (GTK_TEXT (text));
- LeData *data = LE_DATA (gtk_list_item_get_item (listitem));
- GBinding *bind;
-
- gtk_editable_set_text (GTK_EDITABLE (text), le_data_look_string (data));
- gtk_editable_set_position (GTK_EDITABLE (text), 0);
-
- bind = g_object_bind_property (buffer, "text", data, "string", G_BINDING_DEFAULT);
- g_object_set_data (G_OBJECT (listitem), "bind", bind);
-}
-
-static void
-unbind2_cb (GtkListItemFactory *factory, GtkListItem *listitem) {
- GBinding *bind = G_BINDING (g_object_get_data (G_OBJECT (listitem), "bind"));
-
- g_binding_unbind(bind);
- g_object_set_data (G_OBJECT (listitem), "bind", NULL);
-}
setup2_cb
is a setup signal handler on the
-GtkSignalListItemFactory. This factory is inserted to the factory
-property of the second GtkColumnViewColumn. The handler just creates a
-GtkText instance and sets the child of listitem
to it. The
-instance will be destroyed automatically when the listitem
-is destroyed. So, teardown signal handler isn’t necessary.bind2_cb
is a bind signal handler. It is called
-when the listitem
is bound to an item in the list. The list
-items are LeData instances. LeData is defined in the file
-listeditor.c
(the C source file of the list editor). It is
-a child class of GObject and has two data. The one is
-listitem
which points a first column GtkListItem instance
-when they are connected. Be careful that the GtkListItem instance is
-not the listitem
in this handler. If no
-GtkListItem is connected, it is NULL. The other is string
-which is a content of the line.
-text
is a child of the listitem
and
-it is a GtkText instance. And buffer
is a GtkTextBuffer
-instance of the text
.data
is an item pointed by the
-listitem
.text
to
-le_data_look_string (data)
. le_data_look_string returns the
-string of the data
and the ownership of the string is still
-taken by the data
. So, the caller don’t need to free the
-string.g_object_bind_property
binds a property and another
-object property. This line binds the “text” property of the
-buffer
(source) and the “string” property of the
-data
(destination). It is a uni-directional binding
-(G_BINDING_DEFAULT
). When a user changes the GtkText text,
-the same string is immediately put into the data
. The
-function returns a GBinding instance. This binding is different from
-bindings of GtkExpression. This binding needs the existence of the two
-properties.g_object_set_data
sets the association from the key to the
-value. This line sets the association from “bind” to bind
-instance. It makes possible for the “unbind” handler to get the
-bind
instance.unbind2_cb
is a unbind signal handler.
-bind
instance from the table in the
-listitem
instance.This technique is not so complicated. You can use it when you make a -cell editable application.
-Next topic is to change the GtkColumnView (or GtkListView) cells -dynamically. The example changes the color of the buttons, which are -children of GtkListItem instances, as the current line position -moves.
-The line editor has the current position of the list.
-The button of the current line is colored with red and otherwise -white.
-The current line has no relationship to GtkSingleSelection object. -GtkSingleSelection selects a line on the display. The current line -doesn’t need to be on the display. It is possible to be on the line out -of the Window (GtkScrolledWindow). Actually, the program doesn’t use -GtkSingleSelection.
-It is necessary to know the corresponding GtkListItem instance from
-the item in the list. It is the opposite direction from
-gtk_list_item_get_item
function. To accomplish this, we set
-a listitem
element of LeData to point the corresponding
-GtkListItem instance. Therefore, items (LeData) in the list always know
-the GtkListItem. If there’s no GtkListItem bound to the item, NULL is
-assigned.
void
-select_cb (GtkButton *btn, GtkListItem *listitem) {
- LeWindow *win = LE_WINDOW (gtk_widget_get_ancestor (GTK_WIDGET (btn), LE_TYPE_WINDOW));
-
- update_current (win, gtk_list_item_get_position (listitem));
-}
-
-static void
-setup1_cb (GtkListItemFactory *factory, GtkListItem *listitem) {
- GtkWidget *button = gtk_button_new ();
- gtk_list_item_set_child (listitem, button);
- gtk_widget_set_focusable (GTK_WIDGET (button), FALSE);
- g_signal_connect (button, "clicked", G_CALLBACK (select_cb), listitem);
-}
-
-static void
-bind1_cb (GtkListItemFactory *factory, GtkListItem *listitem, gpointer user_data) {
- LeWindow *win = LE_WINDOW (user_data);
- GtkWidget *button = gtk_list_item_get_child (listitem);
- const char *non_current[1] = {NULL};
- const char *current[2] = {"current", NULL};
- LeData *data = LE_DATA (gtk_list_item_get_item (listitem));
-
- if (data) {
- le_data_set_listitem (data, listitem);
- if (win->position == gtk_list_item_get_position (listitem))
- gtk_widget_set_css_classes (GTK_WIDGET (button), current);
- else
- gtk_widget_set_css_classes (GTK_WIDGET (button), non_current);
- }
-}
-
-static void
-unbind1_cb (GtkListItemFactory *factory, GtkListItem *listitem) {
- LeData *data = LE_DATA (gtk_list_item_get_item (listitem));
- if (data)
- le_data_set_listitem (data, NULL);
-}
setup1_cb
is a setup signal handler on the
-GtkSignalListItemFactory. This factory is inserted to the factory
-property of the first GtkColumnViewColumn. It sets the child of
-listitem
to a GtkButton instance. The “clicked” signal on
-the button is connected to the handler select_cb
. When the
-listitem is destroyed, the child (GtkButton) is also destroyed. At the
-same time, the connection of the signal and the handler is also
-destroyed. So, you don’t need teardown signal handler.select_cb
is a “clicked” signal handler. LeWindow
-is defined in listeditor.c
. It’s a child class of
-GtkApplicationWindow. The handler just calls the
-update_current
function. The function will be explained
-later.bind1_cb
is a bind signal handler. It sets the
-“listitem” element of the item (LeData) to point the
-listitem
(GtkListItem instance). It makes the item possible
-to find the corresponding GtkListItem instance. If the item is the
-current line, the CSS class of the button includes “current” class.
-Otherwise it has no CSS class. This is necessary because the button may
-be recycled and it has had former CSS class. The class need to be
-updated.unbind1_cb
is an unbind signal handler. It
-removes the listitem
instance from the “listitem” element
-of the item. The element becomes NULL, which tells no GtkListItem is
-bound. When referring GtkListItem, it needs to check the “listitem”
-element whether it points a GtkListItem or not (NULL). Otherwise bad
-things will happen.static void
-update_current (LeWindow *win, int new) {
- char *s;
- LeData *data;
- GtkListItem *listitem;
- GtkButton *button;
- const char *non_current[1] = {NULL};
- const char *current[2] = {"current", NULL};
-
- if (new >= 0)
- s = g_strdup_printf ("%d", new);
- else
- s = "";
- gtk_label_set_text (GTK_LABEL (win->position_label), s);
- if (*s) // s isn't an empty string
- g_free (s);
-
- if (win->position >=0) {
- data = LE_DATA (g_list_model_get_item (G_LIST_MODEL (win->liststore), win->position));
- if ((listitem = le_data_get_listitem (data)) != NULL) {
- button = GTK_BUTTON (gtk_list_item_get_child (listitem));
- gtk_widget_set_css_classes (GTK_WIDGET (button), non_current);
- g_object_unref (listitem);
- }
- g_object_unref (data);
- }
- win->position = new;
- if (win->position >=0) {
- data = LE_DATA (g_list_model_get_item (G_LIST_MODEL (win->liststore), win->position));
- if ((listitem = le_data_get_listitem (data)) != NULL) {
- button = GTK_BUTTON (gtk_list_item_get_child (listitem));
- gtk_widget_set_css_classes (GTK_WIDGET (button), current);
- g_object_unref (listitem);
- }
- g_object_unref (data);
- }
-}
The function update_current
does several things.
win
, which is
-an instance of LeWindow class. It has some elements.
-new
, which is the new current
-position. At the beginning of the function, win->position points the
-old position.{"current", NULL}
. It is a NULL-terminated array of
-strings. Each string is a CSS class. Now the button has “current” style
-class.The color of buttons are determined by the “background” CSS style. -The following CSS is applied to the default GdkDisplay in advance (in -the startup handler of the application).
-.current {background: red;} columnview listview row button
The selectors “columnview listview row” is needed before “button” -selector. Otherwise the buttons in the GtkColumnview won’t be found. The -button selector has “current” class. So, the only “current” class button -is colored with red. Other buttons are not colored, which means they are -white.
-The function gtk_widget_dispose_template
clears the
-template children for the given widget. This is the opposite of
-gtk_widget_init_template()
. It is a new function of GTK 4.8
-version. If your GTK version is lower than 4.8, you need to modify the
-program.
If your program has the following two, a warning message can be -issued.
-GtkText - unexpected blinking selection. Removing
-I don’t have an exact idea why this happens. But if GtkText -“focusable” property is FALSE, the warning doesn’t happen. So it -probably comes from focus and scroll.
-You can avoid this by unsetting any focus widget under the main -window. When scroll begins, the “value-changed” signal on the vertical -adjustment of the scrolled window is emitted.
-The following is extracted from the ui file and C source file.
-
- ... ... ...object class="GtkScrolledWindow">
- <property name="hexpand">TRUE</property>
- <property name="vexpand">TRUE</property>
- <property name="vadjustment">
- <object class="GtkAdjustment">
- <signal name="value-changed" handler="adjustment_value_changed_cb" swapped="no" object="LeWindow"/>
- <object>
- </property>
- </ ... ... ...
diff --git a/docs/sec32.html b/docs/sec32.html index 5026a1f..42f6898 100644 --- a/docs/sec32.html +++ b/docs/sec32.html @@ -328,10 +328,9 @@ header of the column. as much as possible. (See the image above).
factory_list.ui
in the section
-27.
+template to extend GtkListItem class. The CDATA section (line 36-66) is
+the ui string to put into the “bytes” property. The contents are the
+same as the ui file factory_list.ui
in the section 30.
Compilation and execution.
All the source files are in src/column
directory. Change
your current directory to the directory and type the following.
-$ meson _build
+$ cd src/colomn
+$ meson setup _build
$ ninja -C _build
$ _build/column
Then, a window appears.
diff --git a/docs/sec33.html b/docs/sec33.html
index 3788a8d..aad14ea 100644
--- a/docs/sec33.html
+++ b/docs/sec33.html
@@ -116,25 +116,14 @@ and GtkBulderListItemFactory
the contents of a list. Its binding direction is always from an item of
a list to a child of GtkListItem.
When it comes to dynamic connection, it’s not enough. For example,
-you want to edit the contents of a list. You set a child of GtkListItem
-to a GtkText instance so a user can edit a text with it. You need to
-bind an item in the list with the buffer of the GtkText. The direction
-is opposite from the one with GtkBuilderListItemFactory. It is from the
-GtkText instance to the item in the list. You can implement this with
-GtkSignalListItemFactory, which is more flexible than
+suppose you want to edit the contents of a list. You set a child of
+GtkListItem to a GtkText instance so a user can edit a text with it. You
+need to bind an item in the list with the buffer of the GtkText. The
+direction is opposite from the one with GtkBuilderListItemFactory. It is
+from the GtkText instance to the item in the list. You can implement
+this with GtkSignalListItemFactory, which is more flexible than
GtkBuilderListItemFactory.
-Two things are shown in this section.
-
-- Binding from a child of a GtkListItem instance to an item of a
-list.
-- Access a child of GtkListItem dynamically. This direction is the
-same as the one with GtkBulderListItemFactory. But
-GtkBulderListItemFactory uses GtkExpression from the item property of
-the GtkListItem. So, it updates its child widget only when the item
-property changes. In this example the child reflects the change in the
-same item in the list dynamically.
-
-This section shows just a part of the source file
+
This section shows just some parts of the source file
listeditor.c
. If you want to see the whole codes, see
src/listeditor
directory of the Gtk4 tutorial
@@ -143,7 +132,7 @@ repository.
The sample program is a list editor and data of the list are strings.
It’s the same as a line editor. It reads a text file line by line. Each
line is an item of the list. The list is displayed with GtkColumnView.
-There are two columns. The one is a button, which makes the line be a
+There are two columns. The one is a button, which shows if the line is a
current line. If the line is the current line, the button is colored
with red. The other is a string which is the contents of the
corresponding item of the list.
@@ -159,18 +148,19 @@ href="https://github.com/ToshioCP/Gtk4-tutorial">repository.
src/listeditor
.-
$ meson _build
+$ meson setup _build
$ ninja -C _build
$ _build/listeditor
- Append button: appends a line after the current line, or at the last
line if no current line exists.
-- Insert button: inserts a line before the current line.
+- Insert button: inserts a line before the current line, or at the top
+line if no current line exists.
- Remove button: removes a current line.
- Read button: reads a file.
- Write button: writes the contents to a file.
-- close button: close the contents.
-- quit button: quit the application.
+- close button: closes the contents.
+- quit button: quits the application.
- Button on the select column: makes the line current.
- String column: GtkText. You can edit a string in the field.
@@ -180,7 +170,7 @@ bar. The file name is shown at the right of the write button.
GtkText instance and an item in the list
The second column (GtkColumnViewColumn) sets its factory property to
GtkSignalListItemFactory. It uses three signals setup, bind and unbind.
-The following is their sgnal handlers.
+The following shows the signal handlers.
static void
setup2_cb (GtkListItemFactory *factory, GtkListItem *listitem) {
@@ -193,7 +183,7 @@ class="sourceCode numberSource C numberLines">bind2_cb (GtkListItemFactory *factory, GtkListItem *listitem) {
GtkWidget *text = gtk_list_item_get_child (listitem);
GtkEntryBuffer *buffer = gtk_text_get_buffer (GTK_TEXT (text));
- LeData *data = LE_DATA (gtk_list_item_get_item (listitem));
+ LeData *data = LE_DATA (gtk_list_item_get_item(listitem));
GBinding *bind;
gtk_editable_set_text (GTK_EDITABLE (text), le_data_look_string (data));
@@ -207,9 +197,10 @@ class="sourceCode numberSource C numberLines">unbind2_cb (GtkListItemFactory *factory, GtkListItem *listitem) {
GBinding *bind = G_BINDING (g_object_get_data (G_OBJECT (listitem), "bind"));
- g_binding_unbind(bind);
- g_object_set_data (G_OBJECT (listitem), "bind", NULL);
-}
+ if (bind)
+ g_binding_unbind(bind);
+ g_object_set_data (G_OBJECT (listitem), "bind", NULL);
+}
setup2_cb
is a setup signal handler on the
GtkSignalListItemFactory. This factory is inserted to the factory
@@ -221,22 +212,18 @@ is destroyed. So, teardown signal handler isn’t necessary.listitem
is bound to an item in the list. The list
items are LeData instances. LeData is defined in the file
listeditor.c
(the C source file of the list editor). It is
-a child class of GObject and has two data. The one is
-listitem
which points a first column GtkListItem instance
-when they are connected. Be careful that the GtkListItem instance is
-not the listitem
in this handler. If no
-GtkListItem is connected, it is NULL. The other is string
-which is a content of the line.
+a child class of GObject and has string data which is the content of the
+line.
text
is a child of the listitem
and
-it is a GtkText instance. And buffer
is a GtkTextBuffer
+it is a GtkText instance. And buffer
is a GtkEntryBuffer
instance of the text
.data
is an item pointed by the
listitem
.text
to
le_data_look_string (data)
. le_data_look_string returns the
string of the data
and the ownership of the string is still
-taken by the data
. So, the caller don’t need to free the
+taken by the data
. So, the caller doesn’t need to free the
string.g_object_bind_property
binds a property and another
object property. This line binds the “text” property of the
@@ -254,16 +241,22 @@ value. This line sets the association from “bind” to bind
instance. It makes possible for the “unbind” handler to get the
bind
instance.unbind2_cb
is a unbind signal handler.
+unbind2_cb
is a unbind signal handler.
bind
instance from the table in the
listitem
instance.This technique is not so complicated. You can use it when you make a cell editable application.
+
If it is impossible to use g_object_bind_property
, use a
+notify signal on the GtkEntryBuffer instance. You can use “deleted-text”
+and “inserted-text” signal instead. The handler of the signals above
+copies the text in the GtkEntryBuffer instance to the LeData string.
+Connect the notify signal handler in bind2_cb
and
+disconnect it in unbind2_cb
.
Next topic is to change the GtkColumnView (or GtkListView) cells @@ -289,164 +282,148 @@ GtkSingleSelection selects a line on the display. The current line doesn’t need to be on the display. It is possible to be on the line out of the Window (GtkScrolledWindow). Actually, the program doesn’t use GtkSingleSelection.
-
It is necessary to know the corresponding GtkListItem instance from
-the item in the list. It is the opposite direction from
-gtk_list_item_get_item
function. To accomplish this, we set
-a listitem
element of LeData to point the corresponding
-GtkListItem instance. Therefore, items (LeData) in the list always know
-the GtkListItem. If there’s no GtkListItem bound to the item, NULL is
-assigned.
+
The LeWindow instance has two instance variables for recording the +current line.
+
win->position
: An int type variable. It is the
+position of the current line. It is zero-based. If no current line
+exists, it is -1.win->current_button
: A variable points the button,
+located at the first column, on the current line. If no current line
+exists, it is NULL.+
If the current line moves, the following two functions are called. +They updates the two varables.
void
-select_cb (GtkButton *btn, GtkListItem *listitem) {
- LeWindow *win = LE_WINDOW (gtk_widget_get_ancestor (GTK_WIDGET (btn), LE_TYPE_WINDOW));
+class="sourceCode numberSource C numberLines">static void
+update_current_position (LeWindow *win, int new) {
+ char *s;
- update_current (win, gtk_list_item_get_position (listitem));
-}
-
-static void
-setup1_cb (GtkListItemFactory *factory, GtkListItem *listitem) {
- GtkWidget *button = gtk_button_new ();
- gtk_list_item_set_child (listitem, button);
- gtk_widget_set_focusable (GTK_WIDGET (button), FALSE);
- g_signal_connect (button, "clicked", G_CALLBACK (select_cb), listitem);
-}
-
-static void
-bind1_cb (GtkListItemFactory *factory, GtkListItem *listitem, gpointer user_data) {
- LeWindow *win = LE_WINDOW (user_data);
- GtkWidget *button = gtk_list_item_get_child (listitem);
- const char *non_current[1] = {NULL};
- const char *current[2] = {"current", NULL};
- LeData *data = LE_DATA (gtk_list_item_get_item (listitem));
-
- if (data) {
- le_data_set_listitem (data, listitem);
- if (win->position == gtk_list_item_get_position (listitem))
- gtk_widget_set_css_classes (GTK_WIDGET (button), current);
- else
- gtk_widget_set_css_classes (GTK_WIDGET (button), non_current);
- }
-}
-
-static void
-unbind1_cb (GtkListItemFactory *factory, GtkListItem *listitem) {
- LeData *data = LE_DATA (gtk_list_item_get_item (listitem));
- if (data)
- le_data_set_listitem (data, NULL);
-}
-
setup1_cb
is a setup signal handler on the
-GtkSignalListItemFactory. This factory is inserted to the factory
-property of the first GtkColumnViewColumn. It sets the child of
-listitem
to a GtkButton instance. The “clicked” signal on
-the button is connected to the handler select_cb
. When the
-listitem is destroyed, the child (GtkButton) is also destroyed. At the
-same time, the connection of the signal and the handler is also
-destroyed. So, you don’t need teardown signal handler.select_cb
is a “clicked” signal handler. LeWindow
-is defined in listeditor.c
. It’s a child class of
-GtkApplicationWindow. The handler just calls the
-update_current
function. The function will be explained
-later.bind1_cb
is a bind signal handler. It sets the
-“listitem” element of the item (LeData) to point the
-listitem
(GtkListItem instance). It makes the item possible
-to find the corresponding GtkListItem instance. If the item is the
-current line, the CSS class of the button includes “current” class.
-Otherwise it has no CSS class. This is necessary because the button may
-be recycled and it has had former CSS class. The class need to be
-updated.unbind1_cb
is an unbind signal handler. It
-removes the listitem
instance from the “listitem” element
-of the item. The element becomes NULL, which tells no GtkListItem is
-bound. When referring GtkListItem, it needs to check the “listitem”
-element whether it points a GtkListItem or not (NULL). Otherwise bad
-things will happen.+ win->position = new; + if (win->position >= 0) + s = g_strdup_printf ("%d", win->position); + else + s = ""; + gtk_label_set_text (GTK_LABEL (win->position_label), s); + if (*s) // s isn't an empty string + g_free (s); +} + +static void +update_current_button (LeWindow *win, GtkButton *new_button) { + const char *non_current[1] = {NULL}; + const char *current[2] = {"current", NULL}; + + if (win->current_button) { + gtk_widget_set_css_classes (GTK_WIDGET (win->current_button), non_current); + g_object_unref (win->current_button); + } + win->current_button = new_button; + if (win->current_button) { + g_object_ref (win->current_button); + gtk_widget_set_css_classes (GTK_WIDGET (win->current_button), current); + } +} +
The varable win->position_label
points a GtkLabel
+instance. The label shows the current line position.
+
The current button has CSS “current” class. The button is colored red +through the CSS “button.current {background: red;}”.
+
The order of the call for these two functions is important. The first +function, which updates the position, is usually called first. After +that, a new line is appended or inserted. Then, the second function is +called.
+
The following functions call the two functions above. Be careful +about the order of the call.
static void
-update_current (LeWindow *win, int new) {
- char *s;
- LeData *data;
- GtkListItem *listitem;
- GtkButton *button;
- const char *non_current[1] = {NULL};
- const char *current[2] = {"current", NULL};
-
- if (new >= 0)
- s = g_strdup_printf ("%d", new);
- else
- s = "";
- gtk_label_set_text (GTK_LABEL (win->position_label), s);
- if (*s) // s isn't an empty string
- g_free (s);
-
- if (win->position >=0) {
- data = LE_DATA (g_list_model_get_item (G_LIST_MODEL (win->liststore), win->position));
- if ((listitem = le_data_get_listitem (data)) != NULL) {
- button = GTK_BUTTON (gtk_list_item_get_child (listitem));
- gtk_widget_set_css_classes (GTK_WIDGET (button), non_current);
- g_object_unref (listitem);
- }
- g_object_unref (data);
- }
- win->position = new;
- if (win->position >=0) {
- data = LE_DATA (g_list_model_get_item (G_LIST_MODEL (win->liststore), win->position));
- if ((listitem = le_data_get_listitem (data)) != NULL) {
- button = GTK_BUTTON (gtk_list_item_get_child (listitem));
- gtk_widget_set_css_classes (GTK_WIDGET (button), current);
- g_object_unref (listitem);
- }
- g_object_unref (data);
- }
-}
-
The function update_current
does several things.
+class="sourceCode numberSource C numberLines">void
+select_cb (GtkButton *btn, GtkListItem *listitem) {
+ LeWindow *win = LE_WINDOW (gtk_widget_get_ancestor (GTK_WIDGET (btn), LE_TYPE_WINDOW));
+
+ update_current_position (win, gtk_list_item_get_position (listitem));
+ update_current_button (win, btn);
+}
+
+static void
+setup1_cb (GtkListItemFactory *factory, GtkListItem *listitem) {
+ GtkWidget *button = gtk_button_new ();
+ gtk_list_item_set_child (listitem, button);
+ gtk_widget_set_focusable (GTK_WIDGET (button), FALSE);
+ g_signal_connect (button, "clicked", G_CALLBACK (select_cb), listitem);
+}
+
+static void
+bind1_cb (GtkListItemFactory *factory, GtkListItem *listitem, gpointer user_data) {
+ LeWindow *win = LE_WINDOW (user_data);
+ GtkWidget *button = gtk_list_item_get_child (listitem);
+
+ if (win->position == gtk_list_item_get_position (listitem))
+ update_current_button (win, GTK_BUTTON (button));
+}
win
, which is
-an instance of LeWindow class. It has some elements.
-new
, which is the new current
-position. At the beginning of the function, win->position points the
-old position.select_cb
is a “clicked” signal handler. The
+handler just calls the two functions and update the position and
button.{"current", NULL}
. It is a NULL-terminated array of
-strings. Each string is a CSS class. Now the button has “current” style
-class.setup1_cb
is a setup signal handler on the
+GtkSignalListItemFactory. It sets the child of listitem
to
+a GtkButton instance. The “clicked” signal on the button is connected to
+the handler select_cb
. When the listitem is destroyed, the
+child (GtkButton) is also destroyed. At the same time, the connection of
+the signal and the handler is also destroyed. So, you don’t need
+teardown signal handler.bind1_cb
is a bind signal handler. Usually, the
+position moves before this handler is called. If the item is on the
+current line, the button is updated. No unbind handler is
+necessary.-
The color of buttons are determined by the “background” CSS style. -The following CSS is applied to the default GdkDisplay in advance (in -the startup handler of the application).
+
When a line is added, the current position is updated in advance.
.current {background: red;} columnview listview row button
-
The selectors “columnview listview row” is needed before “button” -selector. Otherwise the buttons in the GtkColumnview won’t be found. The -button selector has “current” class. So, the only “current” class button -is colored with red. Other buttons are not colored, which means they are -white.
-
-
The function gtk_widget_dispose_template
clears the
-template children for the given widget. This is the opposite of
-gtk_widget_init_template()
. It is a new function of GTK 4.8
-version. If your GTK version is lower than 4.8, you need to modify the
-program.
+class="sourceCode numberSource C numberLines">static void
+app_cb (GtkButton *btn, LeWindow *win) {
+ LeData *data = le_data_new_with_data ("");
+
+ if (win->position >= 0) {
+ update_current_position (win, win->position + 1);
+ g_list_store_insert (win->liststore, win->position, data);
+ } else {
+ update_current_position (win, g_list_model_get_n_items (G_LIST_MODEL (win->liststore)));
+ g_list_store_append (win->liststore, data);
+ }
+ g_object_unref (data);
+}
+
+static void
+ins_cb (GtkButton *btn, LeWindow *win) {
+ LeData *data = le_data_new_with_data ("");
+
+ if (win->position >= 0)
+ g_list_store_insert (win->liststore, win->position, data);
+ else {
+ update_current_position (win, 0);
+ g_list_store_insert (win->liststore, 0, data);
+ }
+ g_object_unref (data);
+}
+
When a line is removed, the current position becomes -1 and no button +is current.
+
static void
+rm_cb (GtkButton *btn, LeWindow *win) {
+ if (win->position >= 0) {
+ g_list_store_remove (win->liststore, win->position);
+ update_current_position (win, -1);
+ update_current_button (win, NULL);
+ }
+}
+
The color of buttons are determined by the “background” CSS style.
+The following CSS node is a bit complicated. CSS node
+column view
has listview
child node. It covers
+the rows in the GtkColumnView. The listview
node is the
+same as the one for GtkListView. It has row
child node,
+which is for each child widget. Therefore, the following node
+corresponds buttons on the GtkColumnView widget. In addition, it is
+applied to the “current” class.
+
.current {background: red;} columnview listview row button
If your program has the following two, a warning message can be issued.
@@ -462,24 +439,24 @@ probably comes from focus and scroll.
window. When scroll begins, the “value-changed” signal on the vertical adjustment of the scrolled window is emitted.
The following is extracted from the ui file and C source file.
-
- ... ... ...object class="GtkScrolledWindow">
- <property name="hexpand">TRUE</property>
- <property name="vexpand">TRUE</property>
- <property name="vadjustment">
- <object class="GtkAdjustment">
- <signal name="value-changed" handler="adjustment_value_changed_cb" swapped="no" object="LeWindow"/>
- <object>
- </property>
- </ ... ... ...
-
static void
-adjustment_value_changed_cb (GtkAdjustment *adjustment, gpointer user_data) {
- GtkWidget *win = GTK_WIDGET (user_data);
-
- gtk_window_set_focus (GTK_WINDOW (win), NULL);
-}
+
+ ... ... ...object class="GtkScrolledWindow">
+ <property name="hexpand">TRUE</property>
+ <property name="vexpand">TRUE</property>
+ <property name="vadjustment">
+ <object class="GtkAdjustment">
+ <signal name="value-changed" handler="adjustment_value_changed_cb" swapped="no" object="LeWindow"/>
+ <object>
+ </property>
+ </ ... ... ...
+
static void
+adjustment_value_changed_cb (GtkAdjustment *adjustment, gpointer user_data) {
+ GtkWidget *win = GTK_WIDGET (user_data);
+
+ gtk_window_set_focus (GTK_WINDOW (win), NULL);
+}
diff --git a/docs/sec34.html b/docs/sec34.html deleted file mode 100644 index 1dbb942..0000000 --- a/docs/sec34.html +++ /dev/null @@ -1,486 +0,0 @@ - - -
- - - - -
- - -
-