From 7604209d02278b5547ae42fb328bfbc7d9043963 Mon Sep 17 00:00:00 2001 From: Dan Gudmundsson Date: Fri, 15 Apr 2016 10:19:59 +0200 Subject: wx: Fix callback problems Commands could be executed twice, if the command was dispatched from a callback and caused a recursive invocation of command loop. Solution is to mark op as -1 before calling wxWidgets. Also commands could be missed when idle processing was done inside while executing a recursive callback, solved be always resetting peak index after idle processing is done. --- lib/wx/api_gen/wx_extra/wxEvtHandler.c_src | 2 +- lib/wx/api_gen/wx_gen_cpp.erl | 12 +++--- lib/wx/c_src/gen/wxe_funcs.cpp | 14 ++++--- lib/wx/c_src/wxe_helpers.cpp | 4 +- lib/wx/c_src/wxe_helpers.h | 2 +- lib/wx/c_src/wxe_impl.cpp | 5 ++- lib/wx/test/wx_class_SUITE.erl | 66 +++++++++++++++++++++++++++++- 7 files changed, 87 insertions(+), 18 deletions(-) diff --git a/lib/wx/api_gen/wx_extra/wxEvtHandler.c_src b/lib/wx/api_gen/wx_extra/wxEvtHandler.c_src index 08fef1c2ff..b9cb4f08cc 100644 --- a/lib/wx/api_gen/wx_extra/wxEvtHandler.c_src +++ b/lib/wx/api_gen/wx_extra/wxEvtHandler.c_src @@ -43,7 +43,7 @@ case 101: { // wxEvtHandler::Disconnect int eventType = wxeEventTypeFromAtom(bp); bp += *eventTypeLen; if(eventType > 0) { if(recurse_level > 1) { - delayed_delete->Append(Ecmd.Save()); + delayed_delete->Append(Ecmd.Save(op)); } else { bool Result = This->Disconnect((int) *winid,(int) *lastId,eventType, (wxObjectEventFunction)(wxEventFunction) diff --git a/lib/wx/api_gen/wx_gen_cpp.erl b/lib/wx/api_gen/wx_gen_cpp.erl index 07486e801b..55c179142d 100644 --- a/lib/wx/api_gen/wx_gen_cpp.erl +++ b/lib/wx/api_gen/wx_gen_cpp.erl @@ -195,11 +195,13 @@ gen_funcs(Defs) -> w("void WxeApp::wxe_dispatch(wxeCommand& Ecmd)~n{~n"), w(" char * bp = Ecmd.buffer;~n"), + w(" int op = Ecmd.op;~n"), + w(" Ecmd.op = -1;~n"), w(" wxeMemEnv *memenv = getMemEnv(Ecmd.port);~n"), %% w(" wxMBConvUTF32 UTFconverter;~n"), - w(" wxeReturn rt = wxeReturn(WXE_DRV_PORT, Ecmd.caller, true);~n"), + w(" wxeReturn rt = wxeReturn(WXE_DRV_PORT, Ecmd.caller, true);~n"), w(" try {~n"), - w(" switch (Ecmd.op)~n{~n"), + w(" switch (op)~n{~n"), %% w(" case WXE_CREATE_PORT:~n", []), %% w(" { newMemEnv(Ecmd.port); } break;~n", []), %% w(" case WXE_REMOVE_PORT:~n", []), @@ -209,7 +211,7 @@ gen_funcs(Defs) -> w(" wxeRefData *refd = getRefData(This);~n"), w(" if(This && refd) {~n"), w(" if(recurse_level > 1 && refd->type != 4) {~n"), - w(" delayed_delete->Append(Ecmd.Save());~n"), + w(" delayed_delete->Append(Ecmd.Save(op));~n"), w(" } else {~n"), w(" delete_object(This, refd);~n"), w(" ((WxeApp *) wxTheApp)->clearPtr(This);}~n"), @@ -228,7 +230,7 @@ gen_funcs(Defs) -> w(" default: {~n"), w(" wxeReturn error = wxeReturn(WXE_DRV_PORT, Ecmd.caller, false);"), w(" error.addAtom(\"_wxe_error_\");~n"), - w(" error.addInt((int) Ecmd.op);~n"), + w(" error.addInt((int) op);~n"), w(" error.addAtom(\"not_supported\");~n"), w(" error.addTupleCount(3);~n"), w(" error.send();~n"), @@ -239,7 +241,7 @@ gen_funcs(Defs) -> w("} catch (wxe_badarg badarg) { // try~n"), w(" wxeReturn error = wxeReturn(WXE_DRV_PORT, Ecmd.caller, false);"), w(" error.addAtom(\"_wxe_error_\");~n"), - w(" error.addInt((int) Ecmd.op);~n"), + w(" error.addInt((int) op);~n"), w(" error.addAtom(\"badarg\");~n"), w(" error.addInt((int) badarg.ref);~n"), w(" error.addTupleCount(2);~n"), diff --git a/lib/wx/c_src/gen/wxe_funcs.cpp b/lib/wx/c_src/gen/wxe_funcs.cpp index 059cee59f4..283e97f4e2 100644 --- a/lib/wx/c_src/gen/wxe_funcs.cpp +++ b/lib/wx/c_src/gen/wxe_funcs.cpp @@ -40,17 +40,19 @@ void WxeApp::wxe_dispatch(wxeCommand& Ecmd) { char * bp = Ecmd.buffer; + int op = Ecmd.op; + Ecmd.op = -1; wxeMemEnv *memenv = getMemEnv(Ecmd.port); - wxeReturn rt = wxeReturn(WXE_DRV_PORT, Ecmd.caller, true); + wxeReturn rt = wxeReturn(WXE_DRV_PORT, Ecmd.caller, true); try { - switch (Ecmd.op) + switch (op) { case DESTROY_OBJECT: { void *This = getPtr(bp,memenv); wxeRefData *refd = getRefData(This); if(This && refd) { if(recurse_level > 1 && refd->type != 4) { - delayed_delete->Append(Ecmd.Save()); + delayed_delete->Append(Ecmd.Save(op)); } else { delete_object(This, refd); ((WxeApp *) wxTheApp)->clearPtr(This);} @@ -114,7 +116,7 @@ case 101: { // wxEvtHandler::Disconnect int eventType = wxeEventTypeFromAtom(bp); bp += *eventTypeLen; if(eventType > 0) { if(recurse_level > 1) { - delayed_delete->Append(Ecmd.Save()); + delayed_delete->Append(Ecmd.Save(op)); } else { bool Result = This->Disconnect((int) *winid,(int) *lastId,eventType, (wxObjectEventFunction)(wxEventFunction) @@ -32077,7 +32079,7 @@ case wxDCOverlay_Clear: { // wxDCOverlay::Clear } default: { wxeReturn error = wxeReturn(WXE_DRV_PORT, Ecmd.caller, false); error.addAtom("_wxe_error_"); - error.addInt((int) Ecmd.op); + error.addInt((int) op); error.addAtom("not_supported"); error.addTupleCount(3); error.send(); @@ -32087,7 +32089,7 @@ case wxDCOverlay_Clear: { // wxDCOverlay::Clear rt.send(); } catch (wxe_badarg badarg) { // try wxeReturn error = wxeReturn(WXE_DRV_PORT, Ecmd.caller, false); error.addAtom("_wxe_error_"); - error.addInt((int) Ecmd.op); + error.addInt((int) op); error.addAtom("badarg"); error.addInt((int) badarg.ref); error.addTupleCount(2); diff --git a/lib/wx/c_src/wxe_helpers.cpp b/lib/wx/c_src/wxe_helpers.cpp index 76958a346f..4798e605e8 100644 --- a/lib/wx/c_src/wxe_helpers.cpp +++ b/lib/wx/c_src/wxe_helpers.cpp @@ -47,8 +47,8 @@ void wxeCommand::Delete() if(len > 64) driver_free(buffer); buffer = NULL; - op = -1; } + op = -1; } /* **************************************************************************** @@ -226,7 +226,7 @@ unsigned int wxeFifo::Cleanup(unsigned int def) // Realloced we need to start from the beginning return 0; } else { - return def; + return def < cb_start? def : cb_start; } } diff --git a/lib/wx/c_src/wxe_helpers.h b/lib/wx/c_src/wxe_helpers.h index 3f66b6d97a..70ffccdc13 100644 --- a/lib/wx/c_src/wxe_helpers.h +++ b/lib/wx/c_src/wxe_helpers.h @@ -46,7 +46,7 @@ class wxeCommand wxeCommand(); virtual ~wxeCommand(); // Use Delete() - wxeCommand * Save() { return this; }; + wxeCommand * Save(int Op) { op = Op; return this; }; void Delete(); ErlDrvTermData caller; diff --git a/lib/wx/c_src/wxe_impl.cpp b/lib/wx/c_src/wxe_impl.cpp index f899839782..175bcfce54 100644 --- a/lib/wx/c_src/wxe_impl.cpp +++ b/lib/wx/c_src/wxe_impl.cpp @@ -238,9 +238,10 @@ void WxeApp::dispatch_cmds() if(wxe_status != WXE_INITIATED) return; recurse_level++; - // fprintf(stderr, "\r\ndispatch_normal %d\r\n", level);fflush(stderr); + // fprintf(stderr, "\r\ndispatch_normal %d\r\n", recurse_level);fflush(stderr); + wxe_queue->cb_start = 0; dispatch(wxe_queue); - // fprintf(stderr, "\r\ndispatch_done \r\n");fflush(stderr); + // fprintf(stderr, "\r\ndispatch_done %d\r\n", recurse_level);fflush(stderr); recurse_level--; // Cleanup old memenv's and deleted objects diff --git a/lib/wx/test/wx_class_SUITE.erl b/lib/wx/test/wx_class_SUITE.erl index e23fd901f5..0e8e9f8feb 100644 --- a/lib/wx/test/wx_class_SUITE.erl +++ b/lib/wx/test/wx_class_SUITE.erl @@ -51,7 +51,7 @@ suite() -> [{ct_hooks,[ts_install_cth]}]. all() -> [calendarCtrl, treeCtrl, notebook, staticBoxSizer, clipboard, helpFrame, htmlWindow, listCtrlSort, listCtrlVirtual, - radioBox, systemSettings, taskBarIcon, toolbar, popup]. + radioBox, systemSettings, taskBarIcon, toolbar, popup, modal]. groups() -> []. @@ -621,3 +621,67 @@ lang_env() -> format_env({match, List}) -> [io:format(" ~ts~n",[L]) || L <- List]; format_env(nomatch) -> ok. + +%% Add a testcase that tests that we can recurse in showModal +%% because it hangs in observer if object are not destroyed correctly +%% when popping the stack + +modal(Config) -> + Wx = wx:new(), + case {?wxMAJOR_VERSION, ?wxMINOR_VERSION, ?wxRELEASE_NUMBER} of + {2, Min, Rel} when Min < 8 orelse (Min =:= 8 andalso Rel < 11) -> + {skip, "old wxWidgets version"}; + _ -> + Frame = wxFrame:new(Wx, -1, "Test Modal windows"), + wxFrame:show(Frame), + Env = wx:get_env(), + Tester = self(), + ets:new(test_state, [named_table, public]), + Upd = wxUpdateUIEvent:getUpdateInterval(), + wxUpdateUIEvent:setUpdateInterval(500), + _Pid = spawn(fun() -> + wx:set_env(Env), + modal_dialog(Frame, 1, Tester) + end), + receive {dialog, M1, 1} -> timer:sleep(200), ets:insert(test_state, {M1, ready}) end, + receive {dialog, M2, 2} -> timer:sleep(200), ets:insert(test_state, {M2, ready}) end, + + receive done -> ok end, + receive {dialog_done, M2, 2} -> M2 end, + receive {dialog_done, M1, 1} -> M1 end, + + wxUpdateUIEvent:setUpdateInterval(Upd), + wx_test_lib:wx_destroy(Frame,Config) + end. + +modal_dialog(Parent, Level, Tester) when Level < 3 -> + M1 = wxTextEntryDialog:new(Parent, "Dialog " ++ integer_to_list(Level)), + io:format("Creating dialog ~p ~p~n",[Level, M1]), + wxDialog:connect(M1, show, [{callback, fun(#wx{event=Ev},_) -> + case Ev of + #wxShow{show=true} -> + Tester ! {dialog, M1, Level}; + _ -> ignore + end + end}]), + DoOnce = fun(_,_) -> + case ets:take(test_state, M1) of + [] -> ignore; + [_] -> modal_dialog(M1, Level+1, Tester) + end + end, + wxDialog:connect(M1, update_ui, [{callback, DoOnce}]), + ?wxID_OK = wxDialog:showModal(M1), + wxDialog:destroy(M1), + case Level > 1 of + true -> + io:format("~p: End dialog ~p ~p~n",[?LINE, Level-1, Parent]), + wxDialog:endModal(Parent, ?wxID_OK); + false -> ok + end, + Tester ! {dialog_done, M1, Level}, + ok; +modal_dialog(Parent, Level, Tester) -> + io:format("~p: End dialog ~p ~p~n",[?LINE, Level-1, Parent]), + wxDialog:endModal(Parent, ?wxID_OK), + Tester ! done. -- cgit v1.2.3 From eeb1a534c7be3648d74f490a3daaccb6bbe8545a Mon Sep 17 00:00:00 2001 From: Dan Gudmundsson Date: Fri, 15 Apr 2016 10:21:03 +0200 Subject: wx test: Setup timetraps and avoid large logs when tests succed --- lib/wx/test/wx_app_SUITE.erl | 10 ++++------ lib/wx/test/wx_basic_SUITE.erl | 8 ++++---- lib/wx/test/wx_class_SUITE.erl | 2 +- lib/wx/test/wx_event_SUITE.erl | 2 +- lib/wx/test/wx_opengl_SUITE.erl | 2 +- lib/wx/test/wx_xtra_SUITE.erl | 2 +- lib/wx/test/wxt.erl | 12 ++++-------- 7 files changed, 16 insertions(+), 22 deletions(-) diff --git a/lib/wx/test/wx_app_SUITE.erl b/lib/wx/test/wx_app_SUITE.erl index 0b885a78b8..3fd5bf689d 100644 --- a/lib/wx/test/wx_app_SUITE.erl +++ b/lib/wx/test/wx_app_SUITE.erl @@ -49,7 +49,7 @@ end_per_testcase(Func,Config) -> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -suite() -> [{ct_hooks,[ts_install_cth]}]. +suite() -> [{ct_hooks,[ts_install_cth]}, {timetrap,{minutes,5}}]. all() -> [fields, modules, exportall, app_depend, undef_funcs, appup]. @@ -221,12 +221,10 @@ check_apps([App|Apps]) -> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -undef_funcs(suite) -> - []; -undef_funcs(doc) -> - []; +undef_funcs() -> + [{timetrap,{minutes,10}}]. + undef_funcs(Config) when is_list(Config) -> - catch test_server:timetrap(timer:minutes(10)), App = wx, AppFile = key1search(app_file, Config), Mods = key1search(modules, AppFile), diff --git a/lib/wx/test/wx_basic_SUITE.erl b/lib/wx/test/wx_basic_SUITE.erl index 5dffdea6be..5fe0de485c 100644 --- a/lib/wx/test/wx_basic_SUITE.erl +++ b/lib/wx/test/wx_basic_SUITE.erl @@ -45,7 +45,7 @@ end_per_testcase(Func,Config) -> wx_test_lib:end_per_testcase(Func,Config). %% SUITE specification -suite() -> [{ct_hooks,[ts_install_cth]}]. +suite() -> [{ct_hooks,[ts_install_cth]}, {timetrap,{minutes,2}}]. all() -> [silent_start, create_window, several_apps, wx_api, wx_misc, @@ -344,13 +344,13 @@ data_types(_Config) -> ImgRGB = ?mt(wxImage, wxImage:new(128, 64, Colors)), ?m(true, wxImage:ok(ImgRGB)), ?m(false, wxImage:hasAlpha(ImgRGB)), - ?m(Colors, wxImage:getData(ImgRGB)), + ?m(ok, case wxImage:getData(ImgRGB) of Colors -> ok; Other -> Other end), ImgRGBA = ?mt(wxImage, wxImage:new(128, 64, Colors, Alpha)), ?m(true, wxImage:ok(ImgRGBA)), ?m(true, wxImage:hasAlpha(ImgRGBA)), - ?m(Colors, wxImage:getData(ImgRGBA)), - ?m(Alpha, wxImage:getAlpha(ImgRGBA)), + ?m(ok, case wxImage:getData(ImgRGBA) of Colors -> ok; Other -> Other end), + ?m(ok, case wxImage:getAlpha(ImgRGBA) of Alpha -> ok; Other -> Other end), wxClientDC:destroy(CDC), %%wx_test_lib:wx_destroy(Frame,Config). diff --git a/lib/wx/test/wx_class_SUITE.erl b/lib/wx/test/wx_class_SUITE.erl index 0e8e9f8feb..f88c10f987 100644 --- a/lib/wx/test/wx_class_SUITE.erl +++ b/lib/wx/test/wx_class_SUITE.erl @@ -46,7 +46,7 @@ end_per_testcase(Func,Config) -> wx_test_lib:end_per_testcase(Func,Config). %% SUITE specification -suite() -> [{ct_hooks,[ts_install_cth]}]. +suite() -> [{ct_hooks,[ts_install_cth]}, {timetrap,{minutes,2}}]. all() -> [calendarCtrl, treeCtrl, notebook, staticBoxSizer, diff --git a/lib/wx/test/wx_event_SUITE.erl b/lib/wx/test/wx_event_SUITE.erl index 62fcf44033..6512cedaf2 100644 --- a/lib/wx/test/wx_event_SUITE.erl +++ b/lib/wx/test/wx_event_SUITE.erl @@ -44,7 +44,7 @@ end_per_testcase(Func,Config) -> wx_test_lib:end_per_testcase(Func,Config). %% SUITE specification -suite() -> [{ct_hooks,[ts_install_cth]}]. +suite() -> [{ct_hooks,[ts_install_cth]}, {timetrap,{minutes,2}}]. all() -> [connect, disconnect, disconnect_cb, connect_msg_20, connect_cb_20, diff --git a/lib/wx/test/wx_opengl_SUITE.erl b/lib/wx/test/wx_opengl_SUITE.erl index 5162078dbf..643a0df6a3 100644 --- a/lib/wx/test/wx_opengl_SUITE.erl +++ b/lib/wx/test/wx_opengl_SUITE.erl @@ -52,7 +52,7 @@ end_per_testcase(Func,Config) -> wx_test_lib:end_per_testcase(Func,Config). %% SUITE specification -suite() -> [{ct_hooks,[ts_install_cth]}]. +suite() -> [{ct_hooks,[ts_install_cth]}, {timetrap,{minutes,2}}]. all() -> [canvas, glu_tesselation]. diff --git a/lib/wx/test/wx_xtra_SUITE.erl b/lib/wx/test/wx_xtra_SUITE.erl index 7aba17ee74..c6268a7f46 100644 --- a/lib/wx/test/wx_xtra_SUITE.erl +++ b/lib/wx/test/wx_xtra_SUITE.erl @@ -45,7 +45,7 @@ end_per_testcase(Func,Config) -> wx_test_lib:end_per_testcase(Func,Config). %% SUITE specification -suite() -> [{ct_hooks,[ts_install_cth]}]. +suite() -> [{ct_hooks,[ts_install_cth]}, {timetrap,{minutes,2}}]. all() -> [destroy_app, multiple_add_in_sizer, app_dies, diff --git a/lib/wx/test/wxt.erl b/lib/wx/test/wxt.erl index fc828e47e8..265cd5c981 100644 --- a/lib/wx/test/wxt.erl +++ b/lib/wx/test/wxt.erl @@ -16,13 +16,9 @@ %% limitations under the License. %% %% %CopyrightEnd% -%%%------------------------------------------------------------------- -%%% File : wxt.erl -%%% Author : Dan Gudmundsson -%%% Description : Shortcuts for starting test with wx internal test_server -%%% -%%% Created : 4 Nov 2008 by Dan Gudmundsson -%%%------------------------------------------------------------------- +%% +%% Description : Shortcuts for running tests with wx internal test_server +%%------------------------------------------------------------------- -module(wxt). -compile(export_all). @@ -40,7 +36,7 @@ t(Mod, TC) when is_atom(Mod), is_atom(TC) -> t({Mod,TC}, []); t(all, Config) when is_list(Config) -> Fs = filelib:wildcard("wx_*_SUITE.erl"), - t([list_to_atom(filename:rootname(File)) || File <- Fs], Config); + t([list_to_atom(filename:rootname(File)) || File <- Fs, File =/= "wx_app_SUITE.erl"], Config); t(Test,Config) when is_list(Config) -> Tests = resolve(Test), write_test_case(Test), -- cgit v1.2.3