Skip to content

AWTK最新版本存在几个bug的解决 #976

@Sokyx

Description

@Sokyx

hscroll_label的bug

hscroll_label在滚动过程中,设置空字符串,后台timer没有移除,仍然在运行占用CPU,对于嵌入式设备来说,hlab一直在运行timer刷新,挺占用CPU的,patch如下:

diff --git a/src/ext_widgets/scroll_label/hscroll_label.c b/src/ext_widgets/scroll_label/hscroll_label.c
index 39ca077..7be3ec4 100644
--- a/src/ext_widgets/scroll_label/hscroll_label.c
+++ b/src/ext_widgets/scroll_label/hscroll_label.c
@@ -310,6 +310,9 @@ static ret_t hscroll_label_set_prop(widget_t* widget, const char* name, const va
     if (hscroll_label->timer_id != TK_INVALID_ID) {
       hscroll_label->elapsed = 0;
     }
+       if (tk_strlen(value_str(v)) <= 0) {
+               hscroll_label_stop(widget);
+       }
     return RET_NOT_FOUND;
   } else if (tk_str_eq(name, HSCROLL_LABEL_PROP_STOP_AT_BEGIN)) {
     return hscroll_label_set_stop_at_begin(widget, value_bool(v));

slide_view的bug

slide_view存在两个bug:

  1. 一是在开启auto_play的情况下,正常会自动翻页到第二页—第三页— ... —第一页,但是slide_view里面只添加一个子控件,也会翻页到第二页,但是第二页会显示空白,然后再回到第一页,这是有问题的。
  2. 二是slide_view在用手指触摸左右翻页的过程中,如果此时有销毁里面的子控件,会导致野指针死机,比如你可以直接widget_destroy_children(slide_view)试试,左右翻页的操作可以这样:目前处于第一页,你可以向第二页翻页,但是不要松手,此时屏幕上显示第一页在左半边,右半边会显示第二页,这样方便观察,当执行widget_destroy_children之后,我这边是有重新add进去几页,会发现屏幕出现空白页,此时松开手指让slide_view翻到第二页(其实是显示的空白页了),这种情况下是有野指针会导致死机的。
  3. 修改点说明,针对第一个bug,slide_view_on_timer_next里面判断next指针是否为NULL,因为slide_view_get_next里面其实是没有判断nr==1的情况,导致如果只有一页的时候会返回NULL,NULL的时候是不需要进行翻页的。针对第二个bug,添加on_remove_child指针,移除child的时候要把prev和next指针置为NULL,否则这两个指针可能成为野指针,此时slide_view_on_scroll_done里面的widget_index_of会返回-1,所以active变量需要改为int32_t,并且重新设置一下active = active < 0 ? 0 : active; 实际上野指针死机也是widget_index_of这里,因为next和prev野指针了。
  4. patch如下:
diff --git a/src/ext_widgets/slide_view/slide_view.c b/src/ext_widgets/slide_view/slide_view.c
index ecfdd13..f54e8db 100644
--- a/src/ext_widgets/slide_view/slide_view.c
+++ b/src/ext_widgets/slide_view/slide_view.c
@@ -140,6 +140,18 @@ static ret_t slide_view_on_paint_self(widget_t* widget, canvas_t* c) {
   return RET_OK;
 }

+static ret_t slide_view_on_remove_child(widget_t* widget, widget_t* child) {
+  slide_view_t* slide_view = SLIDE_VIEW(widget);
+  return_value_if_fail(slide_view != NULL && widget != NULL && child != NULL, RET_BAD_PARAMS);
+  if (slide_view->next == child) {
+    slide_view->next = NULL;
+  } else if (slide_view->prev == child) {
+         slide_view->prev = NULL;
+  }
+
+  return RET_FAIL;
+}
+
 static ret_t slide_view_on_pointer_down(slide_view_t* slide_view, pointer_event_t* e) {
   velocity_t* v = &(slide_view->velocity);

@@ -152,13 +164,14 @@ static ret_t slide_view_on_pointer_down(slide_view_t* slide_view, pointer_event_
 }

 static ret_t slide_view_on_scroll_done(void* ctx, event_t* e) {
-  uint32_t active;
+  int32_t active;
   widget_t* widget = WIDGET(ctx);
   slide_view_t* slide_view = SLIDE_VIEW(ctx);
   return_value_if_fail(widget != NULL && slide_view != NULL, RET_BAD_PARAMS);

   if (slide_view->xoffset < 0 || slide_view->yoffset < 0) {
     active = widget_index_of(slide_view->prev);
+    active = active < 0 ? 0 : active; /* Maybe children are destroyed before, slide_view->prev and next had been already set NULL */
     if (slide_view->check_last) {
       active = active == slide_view->last_active ? active : slide_view->last_active;
     }
@@ -170,6 +183,7 @@ static ret_t slide_view_on_scroll_done(void* ctx, event_t* e) {
     }
   } else if (slide_view->xoffset > 0 || slide_view->yoffset > 0) {
     active = widget_index_of(slide_view->next);
+    active = active < 0 ? 0 : active;
     if (slide_view->check_last) {
       active = active == slide_view->last_active ? active : slide_view->last_active;
     }
@@ -808,6 +822,7 @@ TK_DECL_VTABLE(slide_view) = {.size = sizeof(slide_view_t),
                               .find_target = slide_view_find_target,
                               .on_paint_children = slide_view_on_paint_children,
                               .on_paint_self = slide_view_on_paint_self,
+                              .on_remove_child = slide_view_on_remove_child,
                               .on_destroy = slide_view_on_destroy};

 static ret_t slide_view_on_idle_init_save_target(const idle_info_t* idle) {
@@ -1067,7 +1082,9 @@ static ret_t slide_view_on_timer_next(const timer_info_t* timer) {
   }

   slide_view->next = slide_view_get_next(slide_view);
-  slide_view_animate_to(slide_view, 0, 0, xoffset_end, yoffset_end);
+  if (slide_view->next != NULL) {
+    slide_view_animate_to(slide_view, 0, 0, xoffset_end, yoffset_end);
+  }

   return RET_REPEAT;
 }

edit的优化

  1. 我一直都想把edit改成手指抬起后再弹出键盘,目前手指按下就会弹出键盘,体验上会有很大问题,比如一个list_view里面有好几行edit,根本不能滑动了,因为点击到edit就直接弹出键盘了,只能在edit区域之外触摸滑动,但用户怎么知道,这在交互上非常糟糕。所以我的修改点如下,增加手指抬起后的键盘弹出属性,以及该属性下需要禁止聚焦后自动弹出键盘(当然也可以内部直接强制):
diff --git a/src/widgets/edit.c b/src/widgets/edit.c
index 166a091..5514c64 100644
--- a/src/widgets/edit.c
+++ b/src/widgets/edit.c
@@ -831,12 +831,14 @@ ret_t edit_on_event(widget_t* widget, event_t* e) {
         widget_grab(widget->parent, widget);
       }

-      if (widget->target == NULL && !edit->readonly) {
-        input_method_request(input_method(), widget);
+      if (!edit->open_im_when_pointer_up || input_method()->keyboard != NULL) {
+        if (widget->target == NULL && !edit->readonly) {
+          input_method_request(input_method(), widget);
+        }
+        edit_start_update_caret(edit);
       }
       edit_update_status(widget);
       widget_invalidate(widget, NULL);
-      edit_start_update_caret(edit);
       break;
     }
     case EVT_POINTER_DOWN_ABORT: {
@@ -848,13 +850,19 @@ ret_t edit_on_event(widget_t* widget, event_t* e) {
       pointer_event_t evt = *(pointer_event_t*)e;
       if (widget->parent && widget->parent->grab_widget == widget) {
         text_edit_drag(edit->model, evt.x, evt.y);
-        ret = RET_STOP;
+        //ret = RET_STOP;
       }

       widget_invalidate(widget, NULL);
       break;
     }
     case EVT_POINTER_UP: {
+      if (edit->open_im_when_pointer_up && input_method()->keyboard == NULL && widget->parent && widget->parent->grab_widget == widget) {
+        if (widget->target == NULL && !edit->readonly) {
+          input_method_request(input_method(), widget);
+        }
+        edit_start_update_caret(edit);
+      }
       widget_ungrab(widget->parent, widget);
       widget_invalidate(widget, NULL);
       break;
@@ -1388,6 +1396,9 @@ ret_t edit_get_prop(widget_t* widget, const char* name, value_t* v) {
   } else if (tk_str_eq(name, WIDGET_PROP_CLOSE_IM_WHEN_BLURED)) {
     value_set_bool(v, edit->close_im_when_blured);
     return RET_OK;
+  } else if (tk_str_eq(name, EDIT_PROP_OPEN_IM_WHEN_POINTER_UP)) {
+       value_set_bool(v, edit->open_im_when_pointer_up);
+    return RET_OK;
   } else if (tk_str_eq(name, WIDGET_PROP_LEFT_MARGIN)) {
     uint32_t margin = 0;
     if (widget->astyle != NULL) {
@@ -1596,6 +1607,9 @@ ret_t edit_set_prop(widget_t* widget, const char* name, const value_t* v) {
   } else if (tk_str_eq(name, WIDGET_PROP_CLOSE_IM_WHEN_BLURED)) {
     edit->close_im_when_blured = value_bool(v);
     return RET_OK;
+  } else if (tk_str_eq(name, EDIT_PROP_OPEN_IM_WHEN_POINTER_UP)) {
+    edit->open_im_when_pointer_up = value_bool(v);
+    return RET_OK;
   } else if (tk_str_eq(name, WIDGET_PROP_MARGIN)) {
     edit->margin = value_int(v);
     edit_reset_layout(widget);
@@ -2122,6 +2136,7 @@ static ret_t edit_init(widget_t* widget) {
   edit->close_im_when_blured = TRUE;
   edit->open_im_when_focused = TRUE;
   edit->focus_next_when_enter = FALSE;
+  edit->open_im_when_pointer_up = FALSE;
   edit_set_text_limit(widget, 0, 1024);

   edit_update_status(widget);
diff --git a/src/widgets/edit.h b/src/widgets/edit.h
index 29e80f8..ac23364 100644
--- a/src/widgets/edit.h
+++ b/src/widgets/edit.h
@@ -228,7 +228,13 @@ typedef struct _edit_t {
    * 输入回车后是否跳到下一个控件中。
    *
    */
-  bool_t focus_next_when_enter;
+  bool_t focus_next_when_enter;^M
+  /**^M
+   * @property {bool_t} open_im_when_pointer_up^M
+   * @annotation ["set_prop","get_prop","readable","persitent","design","scriptable"]^M
+   * 手指抬起后再时打开输入法。^M
+   */^M
+  bool_t open_im_when_pointer_up;
   /*private*/
   uint8_t margin;
   uint8_t top_margin;
@@ -733,7 +739,8 @@ ret_t edit_pre_delete_with_sep(widget_t* widget, delete_type_t delete_type, char
 #define STR_EDIT_DEC_NAME "dec"
 #define STR_EDIT_CLEAR_NAME "clear"
 #define STR_EDIT_VISIBLE_NAME "visible"
-#define EDIT_PROP_FOCUS_NEXT_WHEN_ENTER "focus_next_when_enter"
+#define EDIT_PROP_FOCUS_NEXT_WHEN_ENTER "focus_next_when_enter"^M
+#define EDIT_PROP_OPEN_IM_WHEN_POINTER_UP      "open_im_when_pointer_up"

 #define TK_EDIT_PROPS                                                                            \
   WIDGET_PROP_MIN, WIDGET_PROP_MAX, WIDGET_PROP_STEP, WIDGET_PROP_INPUT_TYPE,                    \

  1. 改完之后使用上只有一个问题,不好触摸选中edit内容了,因为EVT_POINTER_MOVE事件中注释掉了ret = RET_STOP,但我这边实际上不需要这种功能,无所谓。如果需要这个功能的话,我觉得是要能判断出手指滑动过程中在这个edit范围内就仍然返回RET_STOP,否则就不返回RET_STOP,并且要ungrab控件,类似这样你们可以优化一下。

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions