aboutsummaryrefslogtreecommitdiffstats
path: root/lib/wx/src/wx_object.erl
diff options
context:
space:
mode:
Diffstat (limited to 'lib/wx/src/wx_object.erl')
-rw-r--r--lib/wx/src/wx_object.erl135
1 files changed, 89 insertions, 46 deletions
diff --git a/lib/wx/src/wx_object.erl b/lib/wx/src/wx_object.erl
index 40ee308358..42973335b4 100644
--- a/lib/wx/src/wx_object.erl
+++ b/lib/wx/src/wx_object.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -39,23 +39,35 @@
%% {wxObject, State} | {wxObject, State, Timeout} |
%% ignore | {stop, Reason}
%%
+%% Asynchronous window event handling: <br/>
+%% handle_event(#wx{}, State) should return <br/>
+%% {noreply, State} | {noreply, State, Timeout} | {stop, Reason, State}
+%%
+%% The user module can export the following callback functions:
+%%
%% handle_call(Msg, {From, Tag}, State) should return <br/>
%% {reply, Reply, State} | {reply, Reply, State, Timeout} |
%% {noreply, State} | {noreply, State, Timeout} |
%% {stop, Reason, Reply, State}
%%
-%% Asynchronous window event handling: <br/>
-%% handle_event(#wx{}, State) should return <br/>
-%% {noreply, State} | {noreply, State, Timeout} | {stop, Reason, State}
+%% handle_cast(Msg, State) should return <br/>
+%% {noreply, State} | {noreply, State, Timeout} |
+%% {stop, Reason, State}
+%%
+%% If the above are not exported but called, the wx_object process will crash.
+%% The user module can also export:
%%
%% Info is message e.g. {'EXIT', P, R}, {nodedown, N}, ... <br/>
%% handle_info(Info, State) should return , ... <br/>
%% {noreply, State} | {noreply, State, Timeout} | {stop, Reason, State}
-%%
+%%
+%% If a message is sent to the wx_object process when handle_info is not
+%% exported, the message will be dropped and ignored.
+%%
%% When stop is returned in one of the functions above with Reason =
%% normal | shutdown | Term, terminate(State) is called. It lets the
%% user module clean up, it is always called when server terminates or
-%% when wxObject() in the driver is deleted. If the Parent process
+%% when wx_object() in the driver is deleted. If the Parent process
%% terminates the Module:terminate/2 function is called. <br/>
%% terminate(Reason, State)
%%
@@ -135,6 +147,8 @@
{'noreply', NewState :: term()} |
{'noreply', NewState :: term(), timeout() | 'hibernate'} |
{'stop', Reason :: term(), NewState :: term()}.
+-callback handle_sync_event(Request :: #wx{}, Ref :: #wx_ref{}, State :: term()) ->
+ ok.
-callback terminate(Reason :: ('normal' | 'shutdown' | {'shutdown', term()} |
term()),
State :: term()) ->
@@ -143,6 +157,9 @@
Extra :: term()) ->
{'ok', NewState :: term()} | {'error', Reason :: term()}.
+-optional_callbacks(
+ [handle_call/3, handle_cast/2, handle_info/2,
+ handle_sync_event/3, terminate/2, code_change/3]).
%% System exports
-export([system_continue/3,
@@ -171,58 +188,59 @@
%% -----------------------------------------------------------------
-%% @spec (Mod, Args, Options) -> wxWindow:wxWindow()
-%% Mod = atom()
-%% Args = term()
-%% Options = [{timeout, Timeout} | {debug, [Flag]}]
-%% Flag = trace | log | {logfile, File} | statistics | debug
%% @doc Starts a generic wx_object server and invokes Mod:init(Args) in the
%% new process.
+-spec start(Mod, Args, Options) -> wxWindow:wxWindow() | {error, term()} when
+ Mod::atom(),
+ Args::term(),
+ Flag::trace | log | {logfile, string()} | statistics | debug,
+ Options::[{timeout, timeout()} | {debug, [Flag]}].
start(Mod, Args, Options) ->
gen_response(gen:start(?MODULE, nolink, Mod, Args, [get(?WXE_IDENTIFIER)|Options])).
-
-%% @spec (Name, Mod, Args, Options) -> wxWindow:wxWindow()
-%% Name = {local, atom()}
-%% Mod = atom()
-%% Args = term()
-%% Options = [{timeout, Timeout} | {debug, [Flag]}]
-%% Flag = trace | log | {logfile, File} | statistics | debug
+
%% @doc Starts a generic wx_object server and invokes Mod:init(Args) in the
%% new process.
+-spec start(Name, Mod, Args, Options) -> wxWindow:wxWindow() | {error, term()} when
+ Name::{local, atom()},
+ Mod::atom(),
+ Args::term(),
+ Flag::trace | log | {logfile, string()} | statistics | debug,
+ Options::[{timeout, timeout()} | {debug, [Flag]}].
start(Name, Mod, Args, Options) ->
gen_response(gen:start(?MODULE, nolink, Name, Mod, Args, [get(?WXE_IDENTIFIER)|Options])).
-%% @spec (Mod, Args, Options) -> wxWindow:wxWindow()
-%% Mod = atom()
-%% Args = term()
-%% Options = [{timeout, Timeout} | {debug, [Flag]}]
-%% Flag = trace | log | {logfile, File} | statistics | debug
%% @doc Starts a generic wx_object server and invokes Mod:init(Args) in the
%% new process.
+-spec start_link(Mod, Args, Options) -> wxWindow:wxWindow() | {error, term()} when
+ Mod::atom(),
+ Args::term(),
+ Flag::trace | log | {logfile, string()} | statistics | debug,
+ Options::[{timeout, timeout()} | {debug, [Flag]}].
start_link(Mod, Args, Options) ->
gen_response(gen:start(?MODULE, link, Mod, Args, [get(?WXE_IDENTIFIER)|Options])).
-%% @spec (Name, Mod, Args, Options) -> wxWindow:wxWindow()
-%% Name = {local, atom()}
-%% Mod = atom()
-%% Args = term()
-%% Options = [{timeout, Timeout} | {debug, [Flag]}]
-%% Flag = trace | log | {logfile, File} | statistics | debug
%% @doc Starts a generic wx_object server and invokes Mod:init(Args) in the
%% new process.
+-spec start_link(Name, Mod, Args, Options) -> wxWindow:wxWindow() | {error, term()} when
+ Name::{local, atom()},
+ Mod::atom(),
+ Args::term(),
+ Flag::trace | log | {logfile, string()} | statistics | debug,
+ Options::[{timeout, timeout()} | {debug, [Flag]}].
start_link(Name, Mod, Args, Options) ->
gen_response(gen:start(?MODULE, link, Name, Mod, Args, [get(?WXE_IDENTIFIER)|Options])).
-
+
gen_response({ok, Pid}) ->
receive {ack, Pid, Ref = #wx_ref{}} -> Ref end;
gen_response(Reply) ->
Reply.
-%% @spec (Ref::wxObject()|atom()|pid()) -> ok
%% @doc Stops a generic wx_object server with reason 'normal'.
%% Invokes terminate(Reason,State) in the server. The call waits until
%% the process is terminated. If the process does not exist, an
%% exception is raised.
+-spec stop(Obj) -> ok when
+ Obj::wx:wx_object()|atom()|pid().
stop(Ref = #wx_ref{state=Pid}) when is_pid(Pid) ->
try
gen:stop(Pid)
@@ -236,11 +254,14 @@ stop(Name) when is_atom(Name) orelse is_pid(Name) ->
erlang:error({ExitReason, {?MODULE, stop, [Name]}})
end.
-%% @spec (Ref::wxObject()|atom()|pid(), Reason::term(), Timeout::timeout()) -> ok
%% @doc Stops a generic wx_object server with the given Reason.
%% Invokes terminate(Reason,State) in the server. The call waits until
%% the process is terminated. If the call times out, or if the process
%% does not exist, an exception is raised.
+-spec stop(Obj, Reason, Timeout) -> ok when
+ Obj::wx:wx_object()|atom()|pid(),
+ Reason::term(),
+ Timeout::timeout().
stop(Ref = #wx_ref{state=Pid}, Reason, Timeout) when is_pid(Pid) ->
try
gen:stop(Pid, Reason, Timeout)
@@ -254,12 +275,14 @@ stop(Name, Reason, Timeout) when is_atom(Name) orelse is_pid(Name) ->
erlang:error({ExitReason, {?MODULE, stop, [Name, Reason, Timeout]}})
end.
-%% @spec (Ref::wxObject()|atom()|pid(), Request::term()) -> term()
%% @doc Make a call to a wx_object server.
%% The call waits until it gets a result.
%% Invokes handle_call(Request, From, State) in the server
+-spec call(Obj, Request) -> term() when
+ Obj::wx:wx_object()|atom()|pid(),
+ Request::term().
call(Ref = #wx_ref{state=Pid}, Request) when is_pid(Pid) ->
- try
+ try
{ok,Res} = gen:call(Pid, '$gen_call', Request, infinity),
Res
catch _:Reason ->
@@ -272,10 +295,13 @@ call(Name, Request) when is_atom(Name) orelse is_pid(Name) ->
catch _:Reason ->
erlang:error({Reason, {?MODULE, call, [Name, Request]}})
end.
-
-%% @spec (Ref::wxObject()|atom()|pid(), Request::term(), Timeout::integer()) -> term()
+
%% @doc Make a call to a wx_object server with a timeout.
%% Invokes handle_call(Request, From, State) in server
+-spec call(Obj, Request, Timeout) -> term() when
+ Obj::wx:wx_object()|atom()|pid(),
+ Request::term(),
+ Timeout::integer().
call(Ref = #wx_ref{state=Pid}, Request, Timeout) when is_pid(Pid) ->
try
{ok,Res} = gen:call(Pid, '$gen_call', Request, Timeout),
@@ -291,10 +317,11 @@ call(Name, Request, Timeout) when is_atom(Name) orelse is_pid(Name) ->
erlang:error({Reason, {?MODULE, call, [Name, Request, Timeout]}})
end.
-%% @spec (Ref::wxObject()|atom()|pid(), Request::term()) -> ok
%% @doc Make a cast to a wx_object server.
%% Invokes handle_cast(Request, State) in the server
-
+-spec cast(Obj, Request) -> ok when
+ Obj::wx:wx_object()|atom()|pid(),
+ Request::term().
cast(#wx_ref{state=Pid}, Request) when is_pid(Pid) ->
Pid ! {'$gen_cast',Request},
ok;
@@ -302,21 +329,23 @@ cast(Name, Request) when is_atom(Name) orelse is_pid(Name) ->
Name ! {'$gen_cast',Request},
ok.
-%% @spec (Ref::wxObject()) -> pid()
%% @doc Get the pid of the object handle.
+-spec get_pid(Obj) -> pid() when
+ Obj::wx:wx_object()|atom()|pid().
get_pid(#wx_ref{state=Pid}) when is_pid(Pid) ->
Pid.
-%% @spec (Ref::wxObject(), pid()) -> wxObject()
%% @doc Sets the controlling process of the object handle.
+-spec set_pid(Obj, pid()) -> wx:wx_object() when
+ Obj::wx:wx_object()|atom()|pid().
set_pid(#wx_ref{}=R, Pid) when is_pid(Pid) ->
R#wx_ref{state=Pid}.
%% -----------------------------------------------------------------
%% Send a reply to the client.
%% -----------------------------------------------------------------
-%% @spec (From::tuple(), Reply::term()) -> pid()
%% @doc Get the pid of the object handle.
+-spec reply({pid(), Tag::term()}, Reply::term()) -> pid().
reply({To, Tag}, Reply) ->
catch To ! {Tag, Reply}.
@@ -414,6 +443,7 @@ dispatch(Msg = #wx{}, Mod, State) ->
Mod:handle_event(Msg, State);
dispatch(Info, Mod, State) ->
Mod:handle_info(Info, State).
+
%% @hidden
handle_msg({'$gen_call', From, Msg}, Parent, Name, State, Mod) ->
case catch Mod:handle_call(Msg, From, State) of
@@ -435,8 +465,12 @@ handle_msg({'$gen_call', From, Msg}, Parent, Name, State, Mod) ->
Other -> handle_common_reply(Other, Name, Msg, Mod, State, [])
end;
handle_msg(Msg, Parent, Name, State, Mod) ->
- Reply = (catch dispatch(Msg, Mod, State)),
- handle_no_reply(Reply, Parent, Name, Msg, Mod, State, []).
+ case catch dispatch(Msg, Mod, State) of
+ {'EXIT', {undef, [{Mod, handle_info, [_,_], _}|_]}} ->
+ handle_no_reply({noreply, State}, Parent, Name, Msg, Mod, State, []);
+ Reply ->
+ handle_no_reply(Reply, Parent, Name, Msg, Mod, State, [])
+ end.
%% @hidden
handle_msg({'$gen_call', From, Msg}, Parent, Name, State, Mod, Debug) ->
@@ -516,8 +550,8 @@ system_terminate(Reason, _Parent, Debug, [Name, State, Mod, _Time]) ->
%% @hidden
system_code_change([Name, State, Mod, Time], _Module, OldVsn, Extra) ->
case catch Mod:code_change(OldVsn, State, Extra) of
- {ok, NewState} -> {ok, [Name, NewState, Mod, Time]};
- Else -> Else
+ {ok, NewState} -> {ok, [Name, NewState, Mod, Time]};
+ Else -> Else
end.
%%-----------------------------------------------------------------
@@ -548,7 +582,7 @@ print_event(Dev, Event, Name) ->
%%% ---------------------------------------------------
%% @hidden
terminate(Reason, Name, Msg, Mod, State, Debug) ->
- case catch Mod:terminate(Reason, State) of
+ case try_terminate(Mod, Reason, State) of
{'EXIT', R} ->
error_info(R, Name, Msg, State, Debug),
exit(R);
@@ -565,6 +599,15 @@ terminate(Reason, Name, Msg, Mod, State, Debug) ->
exit(Reason)
end
end.
+
+try_terminate(Mod, Reason, State) ->
+ case erlang:function_exported(Mod, terminate, 2) of
+ true ->
+ catch Mod:terminate(Reason, State);
+ _ ->
+ ok
+ end.
+
%% @hidden
error_info(_Reason, application_controller, _Msg, _State, _Debug) ->
ok;