参考:gfm/sec3.md · qmork/Gtk4-tutorial - Gitee.com
GtkApplication and GtkApplicationWindow
GtkApplication
GtkApplication是基于GTK库的程序。
那么,怎么创建一个GtkAppplication呢。看一个最简单的例子。
#include <gtk/gtk.h>
static void
app_activate (GApplication *app, gpointer *user_data) {
g_print ("GtkApplication is activated.\n");
}
int
main (int argc, char **argv) {
GtkApplication *app;
int stat;
app = gtk_application_new ("com.github.ToshioCP.pr1", G_APPLICATION_DEFAULT_FLAGS);
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;
}
编译命令如下:
gcc $(pkg-config --cflags gtk4) pr1.c -o pr1 $(pkg-config --libs gtk4)
对于上述例子,我们主要讨论一下"activate"信号。
首先,在上述例子中,如果没有g_signal_connect,程序运行会有如下输出
(pr1:93351): GLib-GIO-WARNING **: 10:46:46.860: Your application does not implement g_application_activate() and has no handlers connected to the 'activate' signal. It should do one of these.
那么,这是怎么回事呢。我们跟踪一下函数流程。
static void
g_application_real_activate (GApplication *application)
{
if (!g_signal_has_handler_pending (application,
g_application_signals[SIGNAL_ACTIVATE],
0, TRUE) &&
G_APPLICATION_GET_CLASS (application)->activate == g_application_real_activate)
{
......
g_warning ("Your application does not implement "
"g_application_activate() and has no handlers connected "
"to the 'activate' signal. It should do one of these.");
......
}
}
g_application_real_activate函数首先判断用户是否为GApplication的activate信号设置了信号处理函数,如果没设置且activate函数还是用默认的函数g_application_real_activate,那么就会有warning出现。这个现象我们通过运行上例程序得到验证。
根据g_application_real_activate的if的判断条件,还有一种情况是正常的,那就是,不为activate信号设置信号处理函数,但是更改GApplicationClass的activate的值。我们来看看GTK官方的例子。我们选择的是官方的bloatpad.c.
static void
bloat_pad_class_init (BloatPadClass *class)
{
GApplicationClass *application_class = G_APPLICATION_CLASS (class);
GObjectClass *object_class = G_OBJECT_CLASS (class);
application_class->startup = bloat_pad_startup;
application_class->shutdown = bloat_pad_shutdown;
application_class->activate = bloat_pad_activate;
application_class->open = bloat_pad_open;
object_class->finalize = bloat_pad_finalize;
}
static void
bloat_pad_activate (GApplication *application)
{
new_window (application, NULL);
}
示例程序pr1.c非要设置activate信号的信号处理函数的原因便一目了然。
那,GApplicationClass的activate是在什么时候,由谁调用的呢?
我们通过g_application_class_init,知道g_application_real_activate是GApplicationClass在初始化过程中设置到结构体的activate成员的。
static void
g_application_class_init (GApplicationClass *class)
{
GObjectClass *object_class = G_OBJECT_CLASS (class);
......
class->activate = g_application_real_activate;
......
}
接下来跟踪一下active信号的创建过程。
static void
g_application_class_init (GApplicationClass *class)
{
......
g_application_signals[SIGNAL_ACTIVATE] =
g_signal_new (I_("activate"), G_TYPE_APPLICATION, G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (GApplicationClass, activate),
NULL, NULL, NULL, G_TYPE_NONE, 0);
......
}
guint
g_signal_new (const gchar *signal_name,
GType itype,
GSignalFlags signal_flags,
guint class_offset,
GSignalAccumulator accumulator,
gpointer accu_data,
GSignalCMarshaller c_marshaller,
GType return_type,
guint n_params,
...)
{
......
signal_id = g_signal_new_valist (signal_name, itype, signal_flags,
class_offset ? g_signal_type_cclosure_new (itype, class_offset) : NULL,
accumulator, accu_data, c_marshaller,
return_type, n_params, args);
......
}
guint
g_signal_new_valist (const gchar *signal_name,
GType itype,
GSignalFlags signal_flags,
GClosure *class_closure,
GSignalAccumulator accumulator,
gpointer accu_data,
GSignalCMarshaller c_marshaller,
GType return_type,
guint n_params,
va_list args)
{
.......
signal_id = g_signal_newv (signal_name, itype, signal_flags,
class_closure, accumulator, accu_data, c_marshaller,
return_type, n_params, param_types);
.......
}
/*
* If c_marshaller is %NULL, g_cclosure_marshal_generic() will be used as
* the marshaller for this signal.
*/
guint
g_signal_newv (const gchar *signal_name,
GType itype,
GSignalFlags signal_flags,
GClosure *class_closure,
GSignalAccumulator accumulator,
gpointer accu_data,
GSignalCMarshaller c_marshaller,
GType return_type,
guint n_params,
GType *param_types)
{
......
signal_id = signal_id_lookup (name, itype);
node = LOOKUP_SIGNAL_NODE (signal_id);
......
if (n_params == 0 && return_type == G_TYPE_NONE)
{
builtin_c_marshaller = g_cclosure_marshal_VOID__VOID;
builtin_va_marshaller = g_cclosure_marshal_VOID__VOIDv;
}
......
if (c_marshaller == NULL)
{
if (builtin_c_marshaller)
{
c_marshaller = builtin_c_marshaller;
va_marshaller = builtin_va_marshaller;
}
......
}
......
node->va_marshaller = va_marshaller;
......
if (class_closure)
signal_add_class_closure (node, 0, class_closure);
......
}
由以上流程可知,与acitive信号相关的node结构体的va_marshaller成员被设置为g_cclosure_marshal_VOID__VOIDv。
现在我们在看看g_signal_new函数中调用的函数g_signal_type_cclosure_new的流程。
/*
* Creates a new closure which invokes the function found at the offset
* @struct_offset in the class structure of the interface or classed type
* identified by @itype.
*/
GClosure*
g_signal_type_cclosure_new (GType itype,
guint struct_offset)
{
......
if (G_TYPE_IS_INTERFACE (itype))
{
......
}
else
{
g_closure_set_meta_marshal (closure, GUINT_TO_POINTER (struct_offset), g_type_class_meta_marshal);
g_closure_set_meta_va_marshal (closure, g_type_class_meta_marshalv);
}
......
}
static void
g_closure_set_meta_va_marshal (GClosure *closure,
GVaClosureMarshal va_meta_marshal)
{
......
real_closure->va_meta_marshal = va_meta_marshal;
......
}
由以上流程可知,与acitive信号相关的GRealClosure结构体的va_meta_marshal被设置为g_type_class_meta_marshalv。
接下来,我们看看这些设置完成的函数是怎么调用起来的。
对于我们上述的例子pr1.c来说,最终需要调用g_application_run。我们来跟踪一下此函数。
g_application_run (GApplication *application,
int argc,
char **argv)
{
......
if (!G_APPLICATION_GET_CLASS (application)
->local_command_line (application, &arguments, &status))
......
}
static gboolean
g_application_real_local_command_line (GApplication *application,
gchar ***arguments,
int *exit_status)
{
......
if (n_args <= 1)
{
g_print("lv_test activate jj\n");
g_application_activate (application);
*exit_status = 0;
}
......
}
void
g_application_activate (GApplication *application)
{
......
g_signal_emit (application, g_application_signals[SIGNAL_ACTIVATE], 0);
......
}
void
g_signal_emit (gpointer instance,
guint signal_id,
GQuark detail,
...)
{
......
g_signal_emit_valist (instance, signal_id, detail, var_args);
......
}
void
g_signal_emit_valist (gpointer instance,
guint signal_id,
GQuark detail,
va_list var_args)
{
......
if (signal_emit_valist_unlocked (instance, signal_id, detail, var_args))
......
}
static gboolean
signal_emit_valist_unlocked (gpointer instance,
guint signal_id,
GQuark detail,
va_list var_args)
{
......
_g_closure_invoke_va (closure,
return_accu,
instance,
var_args,
node_copy.n_params,
node_copy.param_types);
......
}
void
_g_closure_invoke_va (GClosure *closure,
GValue /*out*/ *return_value,
gpointer instance,
va_list args,
int n_params,
GType *param_types)
{
......
if (real_closure->va_meta_marshal)
{
marshal_data = real_closure->meta_marshal_data;
marshal = real_closure->va_meta_marshal;
}
......
marshal (closure,
return_value,
instance, args,
marshal_data,
n_params, param_types);
......
}
最终会运行real_closure->va_meta_marshal,即 g_type_class_meta_marshalv函数。那么,我们继续跟踪一下g_type_class_meta_marshalv函数。
static void
g_type_class_meta_marshalv (GClosure *closure,
GValue *return_value,
gpointer instance,
va_list args,
gpointer marshal_data,
int n_params,
GType *param_types)
{
......
guint offset = GPOINTER_TO_UINT (marshal_data);
real_closure = G_REAL_CLOSURE (closure);
......
callback = G_STRUCT_MEMBER (gpointer, class, offset);
if (callback)
real_closure->va_marshal (closure,
return_value,
instance, args,
callback,
n_params,
param_types);
}
这个函数,会调用real_closure->va_marshal,那么, va_marshal又是谁呢?我们之前分析的g_signal_newv函数,其最后会调用signal_add_class_closure。我们来看看此函数的作用
static void
signal_add_class_closure (SignalNode *node,
GType itype,
GClosure *closure)
{
......
_g_closure_set_va_marshal (closure, node->va_marshaller);
......
}
void
_g_closure_set_va_marshal (GClosure *closure,
GVaClosureMarshal marshal)
{
......
real_closure->va_marshal = marshal;
......
}
因此, real_closure->va_marshal被设置为node->va_marshaller. 由之前的分析知道node->va_marshaller的值为g_cclosure_marshal_VOID__VOIDv。我们接着来分析g_cclosure_marshal_VOID__VOIDv。
void
g_cclosure_marshal_VOID__VOIDv (GClosure *closure,
GValue *return_value,
gpointer instance,
va_list args,
gpointer marshal_data,
int n_params,
GType *param_types)
{
......
callback = (GMarshalFunc_VOID__VOID) (marshal_data ? marshal_data : cc->callback);
callback (data1,
data2);
}
到此,我们知道我们的例子pr1.c,当为activate信号设置信号处理函数时,程序的输出是怎么来的了。