diff --git a/applications/system/js_app/modules/js_keyboard.c b/applications/system/js_app/modules/js_keyboard.c index 2bfb296e00..fc2f761351 100644 --- a/applications/system/js_app/modules/js_keyboard.c +++ b/applications/system/js_app/modules/js_keyboard.c @@ -1,14 +1,16 @@ #include "../js_modules.h" #include #include -#include +#include +#include #define membersof(x) (sizeof(x) / sizeof(x[0])) typedef struct { TextInput* text_input; ByteInput* byte_input; - ViewDispatcher* view_dispatcher; + ViewHolder* view_holder; + FuriApiLock lock; char* header; bool accepted; } JsKeyboardInst; @@ -28,14 +30,13 @@ static JsKeyboardInst* get_this_ctx(struct mjs* mjs) { static void keyboard_callback(void* context) { JsKeyboardInst* keyboard = (JsKeyboardInst*)context; keyboard->accepted = true; - view_dispatcher_stop(keyboard->view_dispatcher); + api_lock_unlock(keyboard->lock); } -static bool keyboard_exit(void* context) { +static void keyboard_exit(void* context) { JsKeyboardInst* keyboard = (JsKeyboardInst*)context; keyboard->accepted = false; - view_dispatcher_stop(keyboard->view_dispatcher); - return true; + api_lock_unlock(keyboard->lock); } static void js_keyboard_set_header(struct mjs* mjs) { @@ -84,22 +85,21 @@ static void js_keyboard_text(struct mjs* mjs) { text_input_set_minimum_length(keyboard->text_input, 0); + keyboard->lock = api_lock_alloc_locked(); Gui* gui = furi_record_open(RECORD_GUI); - keyboard->view_dispatcher = view_dispatcher_alloc(); - view_dispatcher_enable_queue(keyboard->view_dispatcher); - view_dispatcher_add_view( - keyboard->view_dispatcher, 0, text_input_get_view(keyboard->text_input)); - view_dispatcher_set_event_callback_context(keyboard->view_dispatcher, keyboard); - view_dispatcher_set_navigation_event_callback(keyboard->view_dispatcher, keyboard_exit); - view_dispatcher_attach_to_gui(keyboard->view_dispatcher, gui, ViewDispatcherTypeFullscreen); - view_dispatcher_switch_to_view(keyboard->view_dispatcher, 0); - - view_dispatcher_run(keyboard->view_dispatcher); - - view_dispatcher_remove_view(keyboard->view_dispatcher, 0); - view_dispatcher_free(keyboard->view_dispatcher); - keyboard->view_dispatcher = NULL; + keyboard->view_holder = view_holder_alloc(); + view_holder_attach_to_gui(keyboard->view_holder, gui); + view_holder_set_back_callback(keyboard->view_holder, keyboard_exit, keyboard); + + view_holder_set_view(keyboard->view_holder, text_input_get_view(keyboard->text_input)); + view_holder_start(keyboard->view_holder); + api_lock_wait_unlock(keyboard->lock); + + view_holder_stop(keyboard->view_holder); + view_holder_free(keyboard->view_holder); + furi_record_close(RECORD_GUI); + api_lock_free(keyboard->lock); text_input_reset(keyboard->text_input); if(keyboard->header) { @@ -141,22 +141,21 @@ static void js_keyboard_byte(struct mjs* mjs) { byte_input_set_result_callback( keyboard->byte_input, keyboard_callback, NULL, keyboard, buffer, input_length); + keyboard->lock = api_lock_alloc_locked(); Gui* gui = furi_record_open(RECORD_GUI); - keyboard->view_dispatcher = view_dispatcher_alloc(); - view_dispatcher_enable_queue(keyboard->view_dispatcher); - view_dispatcher_add_view( - keyboard->view_dispatcher, 0, byte_input_get_view(keyboard->byte_input)); - view_dispatcher_set_event_callback_context(keyboard->view_dispatcher, keyboard); - view_dispatcher_set_navigation_event_callback(keyboard->view_dispatcher, keyboard_exit); - view_dispatcher_attach_to_gui(keyboard->view_dispatcher, gui, ViewDispatcherTypeFullscreen); - view_dispatcher_switch_to_view(keyboard->view_dispatcher, 0); - - view_dispatcher_run(keyboard->view_dispatcher); - - view_dispatcher_remove_view(keyboard->view_dispatcher, 0); - view_dispatcher_free(keyboard->view_dispatcher); - keyboard->view_dispatcher = NULL; + keyboard->view_holder = view_holder_alloc(); + view_holder_attach_to_gui(keyboard->view_holder, gui); + view_holder_set_back_callback(keyboard->view_holder, keyboard_exit, keyboard); + + view_holder_set_view(keyboard->view_holder, byte_input_get_view(keyboard->byte_input)); + view_holder_start(keyboard->view_holder); + api_lock_wait_unlock(keyboard->lock); + + view_holder_stop(keyboard->view_holder); + view_holder_free(keyboard->view_holder); + furi_record_close(RECORD_GUI); + api_lock_free(keyboard->lock); if(keyboard->header) { free(keyboard->header); diff --git a/applications/system/js_app/modules/js_widget.c b/applications/system/js_app/modules/js_widget.c index 69279bb7c7..0d6aeb1dba 100644 --- a/applications/system/js_app/modules/js_widget.c +++ b/applications/system/js_app/modules/js_widget.c @@ -1,6 +1,5 @@ #include -#include -#include +#include #include #include #include @@ -113,8 +112,8 @@ typedef struct { typedef struct { View* view; - ViewDispatcher* view_dispatcher; - FuriThread* thread; + ViewHolder* view_holder; + bool is_shown; } JsWidgetInst; static JsWidgetInst* get_this_ctx(struct mjs* mjs) { @@ -754,60 +753,34 @@ static void js_widget_is_open(struct mjs* mjs) { JsWidgetInst* widget = get_this_ctx(mjs); if(!check_arg_count(mjs, 0)) return; - mjs_return(mjs, mjs_mk_boolean(mjs, !!widget->thread)); -} - -static void widget_deinit(void* context) { - JsWidgetInst* widget = context; - if(widget->thread) { - furi_thread_join(widget->thread); - furi_thread_free(widget->thread); - widget->thread = NULL; - - furi_assert(widget->view_dispatcher); - view_dispatcher_remove_view(widget->view_dispatcher, 0); - view_dispatcher_free(widget->view_dispatcher); - widget->view_dispatcher = NULL; - - furi_record_close(RECORD_GUI); - } + mjs_return(mjs, mjs_mk_boolean(mjs, widget->is_shown)); } static void widget_callback(void* context, uint32_t arg) { UNUSED(arg); - widget_deinit(context); + JsWidgetInst* widget = context; + view_holder_stop(widget->view_holder); + widget->is_shown = false; } -static bool widget_exit(void* context) { +static void widget_exit(void* context) { JsWidgetInst* widget = context; - view_dispatcher_stop(widget->view_dispatcher); + // Using timer to schedule view_holder stop, will not work under high CPU load furi_timer_pending_callback(widget_callback, widget, 0); - return true; -} - -static int32_t widget_thread(void* context) { - ViewDispatcher* view_dispatcher = context; - view_dispatcher_run(view_dispatcher); - return 0; } static void js_widget_show(struct mjs* mjs) { JsWidgetInst* widget = get_this_ctx(mjs); if(!check_arg_count(mjs, 0)) return; - Gui* gui = furi_record_open(RECORD_GUI); - - widget->view_dispatcher = view_dispatcher_alloc(); - view_dispatcher_enable_queue(widget->view_dispatcher); - view_dispatcher_add_view(widget->view_dispatcher, 0, widget->view); - view_dispatcher_set_event_callback_context(widget->view_dispatcher, widget); - view_dispatcher_set_navigation_event_callback(widget->view_dispatcher, widget_exit); - view_dispatcher_attach_to_gui(widget->view_dispatcher, gui, ViewDispatcherTypeFullscreen); - view_dispatcher_switch_to_view(widget->view_dispatcher, 0); + if(widget->is_shown) { + mjs_prepend_errorf(mjs, MJS_INTERNAL_ERROR, "Widget is already shown"); + mjs_return(mjs, MJS_UNDEFINED); + return; + } - widget->thread = - furi_thread_alloc_ex("JsWidget", 1024, widget_thread, widget->view_dispatcher); - furi_thread_start(widget->thread); + view_holder_start(widget->view_holder); + widget->is_shown = true; mjs_return(mjs, MJS_UNDEFINED); } @@ -816,10 +789,8 @@ static void js_widget_close(struct mjs* mjs) { JsWidgetInst* widget = get_this_ctx(mjs); if(!check_arg_count(mjs, 0)) return; - if(widget->thread) { - view_dispatcher_stop(widget->view_dispatcher); - widget_deinit(widget); - } + view_holder_stop(widget->view_holder); + widget->is_shown = false; mjs_return(mjs, MJS_UNDEFINED); } @@ -839,57 +810,9 @@ static void widget_draw_callback(Canvas* canvas, void* model) { } } -static void widget_remove_view(void* context) { - JsWidgetInst* widget = context; - - if(widget->view) { - with_view_model( - widget->view, - WidgetModel * model, - { - ComponentArray_it_t it; - ComponentArray_it(it, model->component); - while(!ComponentArray_end_p(it)) { - WidgetComponent* component = *ComponentArray_ref(it); - if(component && component->free) { - component->free(component); - } - ComponentArray_next(it); - } - ComponentArray_reset(model->component); - ComponentArray_clear(model->component); - }, - false); - with_view_model( - widget->view, WidgetModel * model, { XbmImageList_clear(model->image); }, false); - view_free(widget->view); - widget->view = NULL; - } -} - -static JsWidgetInst* widget_alloc(void) { +static void* js_widget_create(struct mjs* mjs, mjs_val_t* object) { JsWidgetInst* widget = malloc(sizeof(JsWidgetInst)); - widget->thread = NULL; - widget->view_dispatcher = NULL; - - widget->view = view_alloc(); - view_allocate_model(widget->view, ViewModelTypeLockFree, sizeof(WidgetModel)); - view_set_draw_callback(widget->view, widget_draw_callback); - with_view_model( - widget->view, - WidgetModel * model, - { - ComponentArray_init(model->component); - XbmImageList_init(model->image); - model->max_assigned_id = 0; - }, - true); - return widget; -} - -static void* js_widget_create(struct mjs* mjs, mjs_val_t* object) { - JsWidgetInst* widget = widget_alloc(); mjs_val_t widget_obj = mjs_mk_object(mjs); mjs_set(mjs, widget_obj, INST_PROP_NAME, ~0, mjs_mk_foreign(mjs, widget)); // addBox(x: number, y: number, w: number, h: number): number (returns id of the added component) @@ -924,17 +847,60 @@ static void* js_widget_create(struct mjs* mjs, mjs_val_t* object) { mjs_set(mjs, widget_obj, "show", ~0, MJS_MK_FN(js_widget_show)); // close(): void (closes the widget) mjs_set(mjs, widget_obj, "close", ~0, MJS_MK_FN(js_widget_close)); + + widget->view = view_alloc(); + view_allocate_model(widget->view, ViewModelTypeLockFree, sizeof(WidgetModel)); + view_set_draw_callback(widget->view, widget_draw_callback); + with_view_model( + widget->view, + WidgetModel * model, + { + ComponentArray_init(model->component); + XbmImageList_init(model->image); + model->max_assigned_id = 0; + }, + true); + + Gui* gui = furi_record_open(RECORD_GUI); + widget->view_holder = view_holder_alloc(); + view_holder_attach_to_gui(widget->view_holder, gui); + view_holder_set_back_callback(widget->view_holder, widget_exit, widget); + view_holder_set_view(widget->view_holder, widget->view); + *object = widget_obj; return widget; } static void js_widget_destroy(void* inst) { JsWidgetInst* widget = inst; - if(widget->thread) { - view_dispatcher_stop(widget->view_dispatcher); - widget_deinit(widget); - } - widget_remove_view(widget); + + view_holder_stop(widget->view_holder); + view_holder_free(widget->view_holder); + widget->view_holder = NULL; + + furi_record_close(RECORD_GUI); + + with_view_model( + widget->view, + WidgetModel * model, + { + ComponentArray_it_t it; + ComponentArray_it(it, model->component); + while(!ComponentArray_end_p(it)) { + WidgetComponent* component = *ComponentArray_ref(it); + if(component && component->free) { + component->free(component); + } + ComponentArray_next(it); + } + ComponentArray_reset(model->component); + ComponentArray_clear(model->component); + XbmImageList_clear(model->image); + }, + false); + view_free(widget->view); + widget->view = NULL; + free(widget); }