Skip to content

Commit

Permalink
Merge pull request #770 from Willy-JL/js-widget-keyboard-refactor
Browse files Browse the repository at this point in the history
JS: Refactor widget and keyboard modules, fix crash
  • Loading branch information
xMasterX authored Jun 27, 2024
2 parents a91a4af + 8148c9b commit c93eb07
Show file tree
Hide file tree
Showing 2 changed files with 100 additions and 135 deletions.
67 changes: 33 additions & 34 deletions applications/system/js_app/modules/js_keyboard.c
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
#include "../js_modules.h"
#include <gui/modules/text_input.h>
#include <gui/modules/byte_input.h>
#include <gui/view_dispatcher.h>
#include <gui/view_holder.h>
#include <toolbox/api_lock.h>

#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;
Expand All @@ -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) {
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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);
Expand Down
168 changes: 67 additions & 101 deletions applications/system/js_app/modules/js_widget.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
#include <assets_icons.h>
#include <gui/view_dispatcher.h>
#include <gui/view.h>
#include <gui/view_holder.h>
#include <m-array.h>
#include <m-list.h>
#include <string.h>
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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);
}
Expand All @@ -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);
}
Expand All @@ -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)
Expand Down Expand Up @@ -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);
}

Expand Down

0 comments on commit c93eb07

Please sign in to comment.