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
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions