aboutsummaryrefslogtreecommitdiffstats
path: root/lib/wx/test
diff options
context:
space:
mode:
authorDan Gudmundsson <[email protected]>2011-12-02 16:26:45 +0100
committerDan Gudmundsson <[email protected]>2011-12-06 10:13:49 +0100
commit8b6f6db0f5faddc970a7867aecdb03f3cde5fa78 (patch)
tree9a1798efd7150d9f416d2d32180dc4be5cac3732 /lib/wx/test
parent50b488753358d38348f2d4051bfcea8d860e739b (diff)
downloadotp-8b6f6db0f5faddc970a7867aecdb03f3cde5fa78.tar.gz
otp-8b6f6db0f5faddc970a7867aecdb03f3cde5fa78.tar.bz2
otp-8b6f6db0f5faddc970a7867aecdb03f3cde5fa78.zip
[wx] Avoid deadlock in handle_sync_event
Avoid sending cb messages to the wx_object, since it may deadlock. Instead send it to the wxe_server which reads the state from the wx_object's process_dictionary. Ugly but it's the only way I can avoid the deadlock.
Diffstat (limited to 'lib/wx/test')
-rw-r--r--lib/wx/test/Makefile2
-rw-r--r--lib/wx/test/wx_basic_SUITE.erl76
-rw-r--r--lib/wx/test/wx_obj_test.erl86
-rw-r--r--lib/wx/test/wx_test_lib.hrl7
4 files changed, 165 insertions, 6 deletions
diff --git a/lib/wx/test/Makefile b/lib/wx/test/Makefile
index cf51d7918f..333711789f 100644
--- a/lib/wx/test/Makefile
+++ b/lib/wx/test/Makefile
@@ -27,7 +27,7 @@ PWD = $(shell pwd)
APPDIR = $(shell dirname $(PWD))
ERL_COMPILE_FLAGS = -pa $(APPDIR)/ebin
-Mods = wxt wx_test_lib \
+Mods = wxt wx_test_lib wx_obj_test \
wx_app_SUITE \
wx_basic_SUITE \
wx_event_SUITE \
diff --git a/lib/wx/test/wx_basic_SUITE.erl b/lib/wx/test/wx_basic_SUITE.erl
index 9ad34248a9..46c72bb453 100644
--- a/lib/wx/test/wx_basic_SUITE.erl
+++ b/lib/wx/test/wx_basic_SUITE.erl
@@ -48,7 +48,7 @@ suite() -> [{ct_hooks,[ts_install_cth]}].
all() ->
[create_window, several_apps, wx_api, wx_misc,
- data_types].
+ data_types, wx_object].
groups() ->
[].
@@ -298,3 +298,77 @@ data_types(_Config) ->
wxClientDC:destroy(CDC),
%%wx_test_lib:wx_destroy(Frame,Config).
wx:destroy().
+
+wx_object(TestInfo) when is_atom(TestInfo) -> wx_test_lib:tc_info(TestInfo);
+wx_object(Config) ->
+ wx:new(),
+ Frame = ?mt(wxFrame, wx_obj_test:start([])),
+ timer:sleep(500),
+ ?m(ok, check_events(flush())),
+
+ Me = self(),
+ ?m({call, foobar, {Me, _}}, wx_object:call(Frame, foobar)),
+ ?m(ok, wx_object:cast(Frame, foobar2)),
+ ?m([{cast, foobar2}], flush()),
+ FramePid = wx_object:get_pid(Frame),
+ io:format("wx_object pid ~p~n",[FramePid]),
+ FramePid ! foo3,
+ ?m([{info, foo3}], flush()),
+
+ ?m(ok, wx_object:cast(Frame, fun(_) -> hehe end)),
+ ?m([{cast, hehe}], flush()),
+ wxWindow:refresh(Frame),
+ ?m([{sync_event, #wx{event=#wxPaint{}}, _}], flush()),
+ ?m(ok, wx_object:cast(Frame, fun(_) -> timer:sleep(200), slept end)),
+ %% The sleep above should not hinder the Paint event below
+ %% Which it did in my buggy handling of the sync_callback
+ wxWindow:refresh(Frame),
+ ?m([{sync_event, #wx{event=#wxPaint{}}, _}], flush()),
+ ?m([{cast, slept}], flush()),
+
+ Monitor = erlang:monitor(process, FramePid),
+ case proplists:get_value(user, Config, false) of
+ false ->
+ timer:sleep(100),
+ wxFrame:destroy(Frame);
+ true ->
+ timer:sleep(500),
+ ?m(ok, wxFrame:destroy(Frame));
+ _ ->
+ ?m(ok, wxEvtHandler:connect(Frame, close_window, [{skip,true}])),
+ wx_test_lib:wait_for_close()
+ end,
+ ?m(ok, receive
+ {'DOWN', Monitor, _, _, _} ->
+ ?m([{terminate, wx_deleted}], flush()),
+ ok
+ after 1000 ->
+ Msgs = flush(),
+ io:format("Error ~p Alive ~p~n",[Msgs, is_process_alive(FramePid)])
+ end),
+ catch wx:destroy(),
+ ok.
+
+check_events(Msgs) ->
+ check_events(Msgs, 0,0).
+
+check_events([{event, #wx{event=#wxSize{}}}|Rest], Async, Sync) ->
+ check_events(Rest, Async+1, Sync);
+check_events([{sync_event, #wx{event=#wxPaint{}}, Obj}|Rest], Async, Sync) ->
+ ?mt(wxPaintEvent, Obj),
+ check_events(Rest, Async, Sync+1);
+check_events([], Async, Sync) ->
+ case Async > 0 of %% Test sync explictly
+ true -> ok;
+ false -> {Async, Sync}
+ end.
+
+flush() ->
+ flush([], 500).
+
+flush(Acc, Wait) ->
+ receive
+ Msg -> flush([Msg|Acc], Wait div 10)
+ after Wait ->
+ lists:reverse(Acc)
+ end.
diff --git a/lib/wx/test/wx_obj_test.erl b/lib/wx/test/wx_obj_test.erl
new file mode 100644
index 0000000000..b4d7640c7e
--- /dev/null
+++ b/lib/wx/test/wx_obj_test.erl
@@ -0,0 +1,86 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2011. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+-module(wx_obj_test).
+-include_lib("wx/include/wx.hrl").
+
+-export([start/1]).
+
+%% wx_object callbacks
+-export([init/1, handle_info/2, terminate/2, code_change/3, handle_call/3,
+ handle_sync_event/3, handle_event/2, handle_cast/2]).
+
+-record(state, {frame, panel, opts}).
+
+start(Opts) ->
+ wx_object:start_link(?MODULE, [{parent, self()}, Opts], []).
+
+init(Opts) ->
+ put(parent_pid, proplists:get_value(parent, Opts)),
+ Frame = wxFrame:new(wx:null(), ?wxID_ANY, "Test wx_object", [{size, {500, 400}}]),
+ Sz = wxBoxSizer:new(?wxHORIZONTAL),
+ Panel = wxPanel:new(Frame),
+ wxSizer:add(Sz, Panel, [{flag, ?wxEXPAND}, {proportion, 1}]),
+ wxPanel:connect(Panel, size, [{skip, true}]),
+ wxPanel:connect(Panel, paint, [callback, {userData, proplists:get_value(parent, Opts)}]),
+ wxWindow:show(Frame),
+ {Frame, #state{frame=Frame, panel=Panel, opts=Opts}}.
+
+handle_sync_event(Event = #wx{obj=Panel}, WxEvent, #state{opts=Opts}) ->
+ DC=wxPaintDC:new(Panel), %% We must create & destroy paintDC, or call wxEvent:skip(WxEvent))
+ wxPaintDC:destroy(DC), %% in sync_event. Otherwise wx on windows keeps sending the events.
+ Pid = proplists:get_value(parent, Opts),
+ true = is_pid(Pid),
+ Pid ! {sync_event, Event, WxEvent},
+ ok.
+
+handle_event(Event, State = #state{opts=Opts}) ->
+ Pid = proplists:get_value(parent, Opts),
+ Pid ! {event, Event},
+ {noreply, State}.
+
+handle_call(What, From, State) when is_function(What) ->
+ Result = What(State),
+ {reply, {call, Result, From}, State};
+handle_call(What, From, State) ->
+ {reply, {call, What, From}, State}.
+
+handle_cast(What, State = #state{opts=Opts}) when is_function(What) ->
+ Result = What(State),
+ Pid = proplists:get_value(parent, Opts),
+ Pid ! {cast, Result},
+ {noreply, State};
+
+handle_cast(What, State = #state{opts=Opts}) ->
+ Pid = proplists:get_value(parent, Opts),
+ Pid ! {cast, What},
+ {noreply, State}.
+
+handle_info(What, State = #state{opts=Opts}) ->
+ Pid = proplists:get_value(parent, Opts),
+ Pid ! {info, What},
+ {noreply, State}.
+
+terminate(What, #state{opts=Opts}) ->
+ Pid = proplists:get_value(parent, Opts),
+ Pid ! {terminate, What},
+ ok.
+
+code_change(Ver1, Ver2, State = #state{opts=Opts}) ->
+ Pid = proplists:get_value(parent, Opts),
+ Pid ! {code_change, Ver1, Ver2},
+ State.
diff --git a/lib/wx/test/wx_test_lib.hrl b/lib/wx/test/wx_test_lib.hrl
index 34e1e9c6b8..820e8f0050 100644
--- a/lib/wx/test/wx_test_lib.hrl
+++ b/lib/wx/test/wx_test_lib.hrl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2009. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -40,7 +40,6 @@
-define(m(ExpectedRes, Expr),
fun() ->
- {TeStFILe, TeSTLiNe} = {?FILE, ?LINE},
AcTuAlReS = (catch (Expr)),
case AcTuAlReS of
ExpectedRes ->
@@ -48,8 +47,8 @@
AcTuAlReS;
_ ->
wx_test_lib:error("Not Matching Actual result was:~n ~p ~n Expected ~s~n",
- [AcTuAlReS, ??ExpectedRes],
- TeStFILe,TeSTLiNe),
+ [AcTuAlReS, ??ExpectedRes],
+ ?FILE,?LINE),
AcTuAlReS
end
end()).