diff options
Diffstat (limited to 'lib/wx/src/wxe_server.erl')
-rw-r--r-- | lib/wx/src/wxe_server.erl | 95 |
1 files changed, 67 insertions, 28 deletions
diff --git a/lib/wx/src/wxe_server.erl b/lib/wx/src/wxe_server.erl index 40412987a5..6e982c97f6 100644 --- a/lib/wx/src/wxe_server.erl +++ b/lib/wx/src/wxe_server.erl @@ -1,19 +1,19 @@ %% %% %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 %% 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% %%%------------------------------------------------------------------- %%% File : wxe_server.erl @@ -24,7 +24,7 @@ %%% Created : 17 Jan 2007 by Dan Gudmundsson <[email protected]> %%%------------------------------------------------------------------- -%% @hidden +%% @hidden -module(wxe_server). -behaviour(gen_server). @@ -65,7 +65,7 @@ start() -> end; Env = #wx_env{sv=Pid} -> case erlang:is_process_alive(Pid) of - true -> + true -> Env; false -> %% Ok we got an old wx env, someone forgot erase(?WXE_IDENTIFIER), %% to call wx:destroy() @@ -94,7 +94,7 @@ init([]) -> {ok,#state{port=Port, cb_port=CBPort, users=gb_trees:empty(), cb=gb_trees:empty(), cb_cnt=1}}. -%% Register process +%% Register process handle_call(register_me, {From,_}, State=#state{users=Users}) -> erlang:monitor(process, From), case gb_trees:is_defined(From, Users) of @@ -147,7 +147,7 @@ handle_cast({debug, Level}, State) -> put(?WXE_IDENTIFIER, Env#wx_env{debug=Level}), {noreply, State}; -handle_cast(_Msg, State) -> +handle_cast(_Msg, State) -> ?log("Unknown message ~p sent to ~p~n",[_Msg, ?MODULE]), {noreply, State}. @@ -156,7 +156,7 @@ handle_cast(_Msg, State) -> %% Callback request from driver handle_info(Cb = {_, _, '_wx_invoke_cb_'}, State) -> invoke_cb(Cb, State), - {noreply, State}; + {noreply, State}; handle_info({wx_delete_cb, FunId}, State0 = #state{cb=CB}) when is_integer(FunId) -> case get(FunId) of undefined -> @@ -166,7 +166,7 @@ handle_info({wx_delete_cb, FunId}, State0 = #state{cb=CB}) when is_integer(FunId {noreply, State0#state{cb=gb_trees:delete(Fun, CB)}} end; handle_info({'DOWN',_,process,Pid,_}, State=#state{users=Users0,cleaners=Cs}) -> - try + try User = gb_trees:get(Pid,Users0), Users = gb_trees:delete(Pid,Users0), Env = wx:get_env(), @@ -210,7 +210,7 @@ handle_connect(Object, EvData, From, State0 = #state{users=Users}) -> case Handler0 of #wx_ref{} when Callback =:= 0 -> CBHandler = Handler0, - Handler = Handler0; + Handler = Handler0; undefined when Callback =:= 0 -> Handler = new_evt_listener(State0), CBHandler = Handler; @@ -221,14 +221,15 @@ handle_connect(Object, EvData, From, State0 = #state{users=Users}) -> Evs = [#event{object=Object,callback=Callback, cb_handler=CBHandler}|Evs0], User = User0#user{events=Evs, evt_handler=Handler}, State1 = State0#state{users=gb_trees:update(From, User, Users)}, - if is_function(Callback) -> + if is_function(Callback) orelse is_pid(Callback) -> {FunId, State} = attach_fun(Callback,State1), Res = wxEvtHandler:connect_impl(CBHandler,Object, wxEvtHandler:replace_fun_with_id(EvData,FunId)), - case Res of + case Res of ok -> {reply,Res,State}; _Error -> {reply,Res,State0} end; + true -> Res = {call_impl, connect_cb, CBHandler}, {reply, Res, State1} @@ -238,11 +239,9 @@ invoke_cb({{Ev=#wx{}, Ref=#wx_ref{}}, FunId,_}, _S) -> %% Event callbacks case get(FunId) of Fun when is_function(Fun) -> - invoke_callback(fun() -> - wxe_util:cast(?WXE_CB_START, <<>>), - Fun(Ev, Ref), - <<>> - end); + invoke_callback(fun() -> Fun(Ev, Ref), <<>> end); + Pid when is_pid(Pid) -> %% wx_object sync event + invoke_callback(Pid, Ev, Ref); Err -> ?log("Internal Error ~p~n",[Err]) end; @@ -254,12 +253,14 @@ invoke_cb({FunId, Args, _}, _S) when is_list(Args), is_integer(FunId) -> Err -> ?log("Internal Error ~p ~p ~p~n",[Err, FunId, Args]) end. - + invoke_callback(Fun) -> Env = get(?WXE_IDENTIFIER), CB = fun() -> wx:set_env(Env), - Res = try Return = Fun(), + wxe_util:cast(?WXE_CB_START, <<>>), + Res = try + Return = Fun(), true = is_binary(Return), Return catch _:Reason -> @@ -272,15 +273,53 @@ invoke_callback(Fun) -> spawn(CB), ok. +invoke_callback(Pid, Ev, Ref) -> + Env = get(?WXE_IDENTIFIER), + CB = fun() -> + wx:set_env(Env), + wxe_util:cast(?WXE_CB_START, <<>>), + try + case get_wx_object_state(Pid) of + ignore -> + %% Ignore early events + wxEvent:skip(Ref); + {Mod, State} -> + case Mod:handle_sync_event(Ev, Ref, State) of + ok -> ok; + noreply -> ok; + Return -> exit({bad_return, Return}) + end + end + catch _:Reason -> + wxEvent:skip(Ref), + ?log("Callback fun crashed with {'EXIT, ~p, ~p}~n", + [Reason, erlang:get_stacktrace()]) + end, + wxe_util:cast(?WXE_CB_RETURN, <<>>) + end, + spawn(CB), + ok. + +get_wx_object_state(Pid) -> + case process_info(Pid, dictionary) of + {dictionary, Dict} -> + case lists:keysearch('_wx_object_',1,Dict) of + {value, {'_wx_object_', {_Mod, '_wx_init_'}}} -> ignore; + {value, {'_wx_object_', Value}} -> Value; + _ -> ignore + end; + _ -> ignore + end. + new_evt_listener(State) -> #wx_env{port=Port} = wx:get_env(), _ = erlang:port_control(Port,98,<<>>), get_result(State). get_result(_State) -> - receive + receive {'_wxe_result_', Res} -> Res; - {'_wxe_error_', Op, Error} -> + {'_wxe_error_', Op, Error} -> erlang:error({Error, {wxEvtHandler, {internal_installer, Op}}}) end. @@ -289,7 +328,7 @@ attach_fun(Fun, S = #state{cb=CB,cb_cnt=Next}) -> {value, ID} -> {ID,S}; none -> - put(Next,Fun), + put(Next,Fun), {Next,S#state{cb=gb_trees:insert(Fun,Next,CB),cb_cnt=Next+1}} end. @@ -297,7 +336,7 @@ handle_disconnect(Object, Evh, From, State0 = #state{users=Users0}) -> User0 = #user{events=Evs0, evt_handler=PidH} = gb_trees:get(From, Users0), Fun = wxEvtHandler:get_callback(Evh), case find_handler(Evs0, Object, Fun) of - [] -> + [] -> {reply, false, State0}; Handlers -> case disconnect(Object,Evh, Handlers) of @@ -310,7 +349,7 @@ handle_disconnect(Object, Evh, From, State0 = #state{users=Users0}) -> [] when PidH =/= undefined -> wxEvtHandler:destroy_evt_listener(PidH), User0#user{events=[], evt_handler=undefined}; - Evs -> + Evs -> User0#user{events=Evs} end, {reply, true, State0#state{users=gb_trees:update(From,User,Users0)}}; @@ -345,7 +384,7 @@ find_handler([],_Object,_Fun,Res) -> %% Cleanup -%% The server handles callbacks from driver so every other wx call must +%% The server handles callbacks from driver so every other wx call must %% be called from another process, therefore the cleaning must be spawned. %% cleanup(Env, _Pid, Data) -> @@ -358,7 +397,7 @@ cleanup(#user{objects=_Os,events=Evs, evt_handler=Handler}) -> lists:foreach(fun(#event{object=_O, callback=CB, cb_handler=CbH}) -> %%catch wxEvtHandler:disconnect_impl(CbH,O), case is_function(CB) of - true -> + true -> wxEvtHandler:destroy_evt_listener(CbH); false -> ignore |