ftk阅读笔记一(事件响应处理流程)

本文解析了FTK GUI系统中事件处理流程,从初始化、创建窗口和按钮,到事件的捕获、传递及最终处理。重点介绍了如何通过源码理解用户交互事件是如何触发界面更新的。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

看FTK的源码也有些时日了,也该写篇笔记了。
任意一个GUI系统, 所做事情无非是,响应用户事件处理(例如用户按下按键,移动鼠标等事件),做出相应的处理(包括自身控件的重绘,调用其它线程处理相应的业务),ftk也不例外,
此文档主要是记录整个事件处理流程。以用户在按界面的上的按下隐藏按钮键为例

事件:用户按下按钮,响应:界面上的另外一个按钮消失。这其中到底经历怎么 的过程, 这也是我看了ftk源码想要求解一个的问题。以ftk_demo_button.c源码为例,详细说明此过程。
1 fkt初始化,  
     ftk_init(argc, argv);
     初始化g_globals.sources_manager ,g_globals.main_loop

     创建默认的窗体事件管理
     ftk_set_wnd_manager(ftk_wnd_manager_default_create(ftk_default_main_loop()));

     在ftk_wnd_manager_default_create()函数里,创建g_globals.primary_source,g_globals.primary_source是ftk最初级的事件处理源,
     ftk_wnd_manager_default_dispatch_event作为最初级事件处理源的事件处理函数, 处理窗体事件响应。
     ftk_set_primary_source(ftk_source_primary_create((FtkOnEvent)ftk_wnd_manager_default_dispatch_event, thiz));
   
    平台初始化,根据编绎时不同选项,编绎不同的头件,编绎运行于framerbuffer平台时的软件时。

    ftk_backend_init(argc, argv);

    编绎运行于framerbuffer平台时的软件。
 Ret ftk_backend_init(int argc, char* argv[])
 {
  ftk_init_input();
  ftk_set_display(ftk_display_fb_create(getenv("FTK_FB_NAME") ? getenv("FTK_FB_NAME") : FTK_FB_NAME));
  if(ftk_default_display() == NULL)
  {
   ftk_loge("open display failed./n");
   exit(0);
  }

  return RET_OK;
 }
 ftk_init_input()此函数向系统注册外部输入事件处理源。

 source = ftk_source_input_create(filename,
    (FtkOnEvent)ftk_wnd_manager_queue_event, ftk_default_wnd_manager());

 FtkSource* ftk_source_input_create(const char* filename, FtkOnEvent on_event, void* user_data)
 {

  priv->on_event = on_event;
  priv->user_data = user_data;

 }

 

 

2 创建窗体,button.
 win = ftk_app_window_create();
 width = ftk_widget_width(win);
 height = ftk_widget_height(win);


 width = width/3 - 10;
 button = ftk_button_create(win, 0, 30, width, 50);
 ftk_widget_set_text(button, "show");
 ftk_button_set_clicked_listener(button, button_show_clicked, win);

 
 
3 ftk_run();
 ftk的主循环处理采用的select侦听模式,当事件源的描述符可读时,读敢一个event事件,调用该事件的处理函数。
 

 

 当source读到的事件时,首先进行事件信息转换, 转换为事件能识别到的事件内容。

 static Ret ftk_source_input_dispatch(FtkSource* thiz)
 {
 int ret = 0;
 DECL_PRIV(thiz, priv);
 struct input_event ievent;
 return_val_if_fail(priv->fd > 0, RET_FAIL); 
 ret = read(priv->fd, &ievent, sizeof(ievent));
 return_val_if_fail(ret == sizeof(ievent), RET_FAIL);

 处理事件响应时调用此函数priv->on_event(priv->user_data, &priv->event);
 switch(ievent.type)
 {
  case EV_KEY:
  {
   if(ievent.code == BTN_LEFT || ievent.code == BTN_RIGHT
    || ievent.code == BTN_MIDDLE || ievent.code == BTN_TOUCH)
   {
    priv->event.type = ievent.value ? FTK_EVT_MOUSE_DOWN : FTK_EVT_MOUSE_UP;
   }
   else
   {
    priv->event.type = ievent.value ? FTK_EVT_KEY_DOWN : FTK_EVT_KEY_UP;
    priv->event.u.key.code = ftk_key_map(thiz, ievent.code);
    if(priv->on_event != NULL && priv->event.type != FTK_EVT_NOP)
    {
     priv->on_event(priv->user_data, &priv->event);
     priv->event.type = FTK_EVT_NOP;
    }
   }

   break;

 }

 也就是ftk_wnd_manager_queue_event(),调用g_globals.wnd_manager的事件处理函数thiz->queue_event(thiz, event);
 static inline Ret  ftk_wnd_manager_queue_event(FtkWndManager* thiz, FtkEvent* event)
 {
  return_val_if_fail(thiz != NULL && thiz->queue_event != NULL, RET_FAIL);

  return thiz->queue_event(thiz, event);
 }
 
        指针来,指针去,最后可以定位到调用也就是下面的函数。
 static Ret  ftk_wnd_manager_default_queue_event(FtkWndManager* thiz, FtkEvent* event)
 {
  return_val_if_fail(thiz != NULL && event != NULL, RET_FAIL);
  return_val_if_fail(ftk_default_main_loop() != NULL, RET_FAIL);

  if(event->time == 0)
  {
   event->time = ftk_get_relative_time();
  }

  return ftk_source_queue_event(ftk_primary_source(), event);
 }

 还没有结束呀, 此函数的处理,就是向最初级的source写入事件,
 Ret ftk_source_queue_event(FtkSource* thiz, FtkEvent* event)
 {
  int ret = 0;
  DECL_PRIV(thiz, priv);
  return_val_if_fail(thiz != NULL && event != NULL, RET_FAIL);

  ret = ftk_pipe_write(priv->pipe, event, sizeof(FtkEvent));

  return ret == sizeof(FtkEvent) ? RET_OK : RET_FAIL;
 }

 此时primary_source的描述符变为可读, 所以在下一个mainloop里,primary_source处理相应的事件。
  
static Ret ftk_source_primary_dispatch(FtkSource* thiz)
{
 FtkEvent event = {0};
 DECL_PRIV(thiz, priv);
 int ret = ftk_pipe_read(priv->pipe, &event, sizeof(FtkEvent));
 return_val_if_fail(ret == sizeof(FtkEvent), RET_REMOVE);

 switch(event.type)
 {
  case FTK_EVT_NOP:
  {
   break;
  }
  case FTK_EVT_ADD_SOURCE:
  {
   ftk_sources_manager_add(ftk_default_sources_manager(), event.u.extra);
   break;
  }
  case FTK_EVT_REMOVE_SOURCE:
  {
   ftk_sources_manager_remove(ftk_default_sources_manager(), event.u.extra);
   break;
  }
  default:
  {
   if(priv->on_event != NULL)
   {
    priv->on_event(priv->user_data, &event);
   }
  }
 }

 return RET_OK;
}
 primary_source处理相应的事件,会根据event.type来进行不同的操作,当event.type为FTK_EVT_ADD_SOURCE, FTK_EVT_REMOVE_SOURCE,用于管理事件源。
 当event.type为其它时,会调用priv->on_event(priv->user_data, &event)进行事件处理。
 
 priv->on_event 又是什么东西呢?/:-)
 看下面的函数,ftk_wnd_manager_default_dispatch_event 就是我们建立primary_source时,传入事件处理函数指针。
ftk_set_primary_source(ftk_source_primary_create((FtkOnEvent)ftk_wnd_manager_default_dispatch_event, thiz));
 
static Ret  ftk_wnd_manager_default_dispatch_event(FtkWndManager* thiz, FtkEvent* event)
{
 DECL_PRIV(thiz, priv);
 FtkWidget* target = NULL;
 return_val_if_fail(thiz != NULL && event != NULL, RET_FAIL);

 if(event->type == FTK_EVT_KEY_UP)
 {
  ftk_logd("%s: FTK_EVT_KEY_UP/n", __func__);
 }

 if(event->type == FTK_EVT_KEY_DOWN || event->type == FTK_EVT_KEY_UP)
 {
  ftk_wnd_manager_default_key_translate(thiz, event);
 }

 if(ftk_wnd_manager_dispatch_globals(thiz, event) != RET_OK)
 {
  return RET_REMOVE;
 }

 switch(event->type)
 {
  case FTK_EVT_WND_DESTROY:
  {
   if(priv->top_window == event->widget)
   {
    priv->top_window = NULL;
   }
   ftk_wnd_manager_default_remove(thiz, event->widget); 
   return RET_OK;
  }
  case FTK_EVT_HIDE:
  {
   ftk_wnd_manager_default_emit_top_wnd_changed(thiz);
   ftk_wnd_manager_update(thiz);
   return RET_OK;
  }
  case FTK_EVT_SHOW:
  {
   ftk_wnd_manager_default_emit_top_wnd_changed(thiz);
   return RET_OK;
  }
  case FTK_EVT_RELAYOUT_WND:
  {
   ftk_wnd_manager_default_relayout(thiz);
   break;
  }
  default:break;
 }

 if(event->type == FTK_EVT_MOUSE_DOWN || event->type == FTK_EVT_KEY_DOWN)
 {
  priv->pressed_event = *event;
  ftk_source_ref(priv->long_press_timer);
  ftk_source_timer_reset(priv->long_press_timer);
  ftk_main_loop_add_source(ftk_default_main_loop(), priv->long_press_timer);
 }
 
 if(event->type == FTK_EVT_MOUSE_UP|| event->type == FTK_EVT_KEY_UP)
 {
  ftk_main_loop_remove_source(ftk_default_main_loop(), priv->long_press_timer);
 }

 if((event->type == FTK_EVT_MOUSE_DOWN
  || event->type == FTK_EVT_MOUSE_UP
  || event->type == FTK_EVT_MOUSE_MOVE) && priv->grab_widget == NULL)
 {
  int x = event->u.mouse.x;
  int y = event->u.mouse.y;
  
  target = ftk_wnd_manager_find_target(thiz, x, y);
  if(event->type == FTK_EVT_MOUSE_DOWN)
  {
   priv->focus_widget = target;
  }
 }
 else if(event->widget != NULL)
 {
  target = event->widget;
 }
 else if(priv->grab_widget != NULL)
 {
  target = priv->grab_widget;
 }
 else if(priv->focus_widget != NULL)
 {
  target = priv->focus_widget;
 }
 else if(priv->top > 0)
 {
  target = priv->windows[priv->top - 1];
 }

 if(target != NULL && !ftk_widget_is_insensitive(target))
 {
  ftk_widget_ref(target);
  ftk_widget_event(target, event);
  ftk_widget_unref(target);
 }

 return RET_OK;
}
 

  
  
  
 
 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值