GTK tutorial 十五

参考: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信号设置信号处理函数时,程序的输出是怎么来的了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值