1%% 2%% %CopyrightBegin% 3%% 4%% Copyright Ericsson AB 2008-2017. All Rights Reserved. 5%% 6%% Licensed under the Apache License, Version 2.0 (the "License"); 7%% you may not use this file except in compliance with the License. 8%% You may obtain a copy of the License at 9%% 10%% http://www.apache.org/licenses/LICENSE-2.0 11%% 12%% Unless required by applicable law or agreed to in writing, software 13%% distributed under the License is distributed on an "AS IS" BASIS, 14%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15%% See the License for the specific language governing permissions and 16%% limitations under the License. 17%% 18%% %CopyrightEnd% 19%%%------------------------------------------------------------------- 20%%% File : wx_object.erl 21%%% Author : Dan Gudmundsson <dan.gudmundsson@ericsson.com> 22%%% Description : Frame work for erlang sub-classes. 23%%% 24%%% Created : 25 Nov 2008 by Dan Gudmundsson <dan.gudmundsson@ericsson.com> 25%%%------------------------------------------------------------------- 26%% 27%% @doc wx_object - Generic wx object behaviour 28%% 29%% This is a behaviour module that can be used for "sub classing" 30%% wx objects. It works like a regular gen_server module and creates 31%% a server per object. 32%% 33%% NOTE: Currently no form of inheritance is implemented. 34%% 35%% 36%% The user module should export: 37%% 38%% init(Args) should return <br/> 39%% {wxObject, State} | {wxObject, State, Timeout} | 40%% ignore | {stop, Reason} 41%% 42%% Asynchronous window event handling: <br/> 43%% handle_event(#wx{}, State) should return <br/> 44%% {noreply, State} | {noreply, State, Timeout} | {stop, Reason, State} 45%% 46%% The user module can export the following callback functions: 47%% 48%% handle_call(Msg, {From, Tag}, State) should return <br/> 49%% {reply, Reply, State} | {reply, Reply, State, Timeout} | 50%% {noreply, State} | {noreply, State, Timeout} | 51%% {stop, Reason, Reply, State} 52%% 53%% handle_cast(Msg, State) should return <br/> 54%% {noreply, State} | {noreply, State, Timeout} | 55%% {stop, Reason, State} 56%% 57%% If the above are not exported but called, the wx_object process will crash. 58%% The user module can also export: 59%% 60%% Info is message e.g. {'EXIT', P, R}, {nodedown, N}, ... <br/> 61%% handle_info(Info, State) should return , ... <br/> 62%% {noreply, State} | {noreply, State, Timeout} | {stop, Reason, State} 63%% 64%% If a message is sent to the wx_object process when handle_info is not 65%% exported, the message will be dropped and ignored. 66%% 67%% When stop is returned in one of the functions above with Reason = 68%% normal | shutdown | Term, terminate(State) is called. It lets the 69%% user module clean up, it is always called when server terminates or 70%% when wx_object() in the driver is deleted. If the Parent process 71%% terminates the Module:terminate/2 function is called. <br/> 72%% terminate(Reason, State) 73%% 74%% 75%% Example: 76%% 77%% ``` 78%% -module(myDialog). 79%% -export([new/2, show/1, destroy/1]). %% API 80%% -export([init/1, handle_call/3, handle_event/2, 81%% handle_info/2, code_change/3, terminate/2]). 82%% new/2, showModal/1, destroy/1]). %% Callbacks 83%% 84%% %% Client API 85%% new(Parent, Msg) -> 86%% wx_object:start(?MODULE, [Parent,Id], []). 87%% 88%% show(Dialog) -> 89%% wx_object:call(Dialog, show_modal). 90%% 91%% destroy(Dialog) -> 92%% wx_object:call(Dialog, destroy). 93%% 94%% %% Server Implementation ala gen_server 95%% init([Parent, Str]) -> 96%% Dialog = wxDialog:new(Parent, 42, "Testing", []), 97%% ... 98%% wxDialog:connect(Dialog, command_button_clicked), 99%% {Dialog, MyState}. 100%% 101%% handle_call(show, _From, State) -> 102%% wxDialog:show(State#state.win), 103%% {reply, ok, State}; 104%% ... 105%% handle_event(#wx{}, State) -> 106%% io:format("Users clicked button~n",[]), 107%% {noreply, State}; 108%% ... 109%% ''' 110 111-module(wx_object). 112-include("wxe.hrl"). 113-include("../include/wx.hrl"). 114 115%% API 116-export([start/3, start/4, 117 start_link/3, start_link/4, 118 stop/1, stop/3, 119 call/2, call/3, 120 cast/2, 121 reply/2, 122 get_pid/1, 123 set_pid/2 124 ]). 125 126%% -export([behaviour_info/1]). 127-callback init(Args :: term()) -> 128 {#wx_ref{}, State :: term()} | {#wx_ref{}, State :: term(), timeout() | 'hibernate'} | 129 {'stop', Reason :: term()} | 'ignore'. 130-callback handle_event(Request :: #wx{}, State :: term()) -> 131 {'noreply', NewState :: term()} | 132 {'noreply', NewState :: term(), timeout() | 'hibernate'} | 133 {'stop', Reason :: term(), NewState :: term()}. 134-callback handle_call(Request :: term(), From :: {pid(), Tag :: term()}, 135 State :: term()) -> 136 {'reply', Reply :: term(), NewState :: term()} | 137 {'reply', Reply :: term(), NewState :: term(), timeout() | 'hibernate'} | 138 {'noreply', NewState :: term()} | 139 {'noreply', NewState :: term(), timeout() | 'hibernate'} | 140 {'stop', Reason :: term(), Reply :: term(), NewState :: term()} | 141 {'stop', Reason :: term(), NewState :: term()}. 142-callback handle_cast(Request :: term(), State :: term()) -> 143 {'noreply', NewState :: term()} | 144 {'noreply', NewState :: term(), timeout() | 'hibernate'} | 145 {'stop', Reason :: term(), NewState :: term()}. 146-callback handle_info(Info :: timeout() | term(), State :: term()) -> 147 {'noreply', NewState :: term()} | 148 {'noreply', NewState :: term(), timeout() | 'hibernate'} | 149 {'stop', Reason :: term(), NewState :: term()}. 150-callback handle_sync_event(Request :: #wx{}, Ref :: #wx_ref{}, State :: term()) -> 151 ok. 152-callback terminate(Reason :: ('normal' | 'shutdown' | {'shutdown', term()} | 153 term()), 154 State :: term()) -> 155 term(). 156-callback code_change(OldVsn :: (term() | {'down', term()}), State :: term(), 157 Extra :: term()) -> 158 {'ok', NewState :: term()} | {'error', Reason :: term()}. 159 160-optional_callbacks( 161 [handle_call/3, handle_cast/2, handle_info/2, 162 handle_sync_event/3, terminate/2, code_change/3]). 163 164%% System exports 165-export([system_continue/3, 166 system_terminate/4, 167 system_code_change/4, 168 format_status/2]). 169 170%% Internal exports 171-export([init_it/6]). 172 173-import(error_logger, [format/2]). 174 175%%%========================================================================= 176%%% API 177%%%========================================================================= 178%% @hidden 179%% behaviour_info(callbacks) -> 180%% [{init,1}, 181%% {handle_call,3}, 182%% {handle_info,2}, 183%% {handle_event,2}, 184%% {terminate,2}, 185%% {code_change,3}]; 186%% behaviour_info(_Other) -> 187%% undefined. 188 189 190%% ----------------------------------------------------------------- 191%% @doc Starts a generic wx_object server and invokes Mod:init(Args) in the 192%% new process. 193-spec start(Mod, Args, Options) -> wxWindow:wxWindow() | {error, term()} when 194 Mod::atom(), 195 Args::term(), 196 Flag::trace | log | {logfile, string()} | statistics | debug, 197 Options::[{timeout, timeout()} | {debug, [Flag]}]. 198start(Mod, Args, Options) -> 199 gen_response(gen:start(?MODULE, nolink, Mod, Args, [get(?WXE_IDENTIFIER)|Options])). 200 201%% @doc Starts a generic wx_object server and invokes Mod:init(Args) in the 202%% new process. 203-spec start(Name, Mod, Args, Options) -> wxWindow:wxWindow() | {error, term()} when 204 Name::{local, atom()}, 205 Mod::atom(), 206 Args::term(), 207 Flag::trace | log | {logfile, string()} | statistics | debug, 208 Options::[{timeout, timeout()} | {debug, [Flag]}]. 209start(Name, Mod, Args, Options) -> 210 gen_response(gen:start(?MODULE, nolink, Name, Mod, Args, [get(?WXE_IDENTIFIER)|Options])). 211 212%% @doc Starts a generic wx_object server and invokes Mod:init(Args) in the 213%% new process. 214-spec start_link(Mod, Args, Options) -> wxWindow:wxWindow() | {error, term()} when 215 Mod::atom(), 216 Args::term(), 217 Flag::trace | log | {logfile, string()} | statistics | debug, 218 Options::[{timeout, timeout()} | {debug, [Flag]}]. 219start_link(Mod, Args, Options) -> 220 gen_response(gen:start(?MODULE, link, Mod, Args, [get(?WXE_IDENTIFIER)|Options])). 221 222%% @doc Starts a generic wx_object server and invokes Mod:init(Args) in the 223%% new process. 224-spec start_link(Name, Mod, Args, Options) -> wxWindow:wxWindow() | {error, term()} when 225 Name::{local, atom()}, 226 Mod::atom(), 227 Args::term(), 228 Flag::trace | log | {logfile, string()} | statistics | debug, 229 Options::[{timeout, timeout()} | {debug, [Flag]}]. 230start_link(Name, Mod, Args, Options) -> 231 gen_response(gen:start(?MODULE, link, Name, Mod, Args, [get(?WXE_IDENTIFIER)|Options])). 232 233gen_response({ok, Pid}) -> 234 receive {ack, Pid, Ref = #wx_ref{}} -> Ref end; 235gen_response(Reply) -> 236 Reply. 237 238%% @doc Stops a generic wx_object server with reason 'normal'. 239%% Invokes terminate(Reason,State) in the server. The call waits until 240%% the process is terminated. If the process does not exist, an 241%% exception is raised. 242-spec stop(Obj) -> ok when 243 Obj::wx:wx_object()|atom()|pid(). 244stop(Ref = #wx_ref{state=Pid}) when is_pid(Pid) -> 245 try 246 gen:stop(Pid) 247 catch _:ExitReason -> 248 erlang:error({ExitReason, {?MODULE, stop, [Ref]}}) 249 end; 250stop(Name) when is_atom(Name) orelse is_pid(Name) -> 251 try 252 gen:stop(Name) 253 catch _:ExitReason -> 254 erlang:error({ExitReason, {?MODULE, stop, [Name]}}) 255 end. 256 257%% @doc Stops a generic wx_object server with the given Reason. 258%% Invokes terminate(Reason,State) in the server. The call waits until 259%% the process is terminated. If the call times out, or if the process 260%% does not exist, an exception is raised. 261-spec stop(Obj, Reason, Timeout) -> ok when 262 Obj::wx:wx_object()|atom()|pid(), 263 Reason::term(), 264 Timeout::timeout(). 265stop(Ref = #wx_ref{state=Pid}, Reason, Timeout) when is_pid(Pid) -> 266 try 267 gen:stop(Pid, Reason, Timeout) 268 catch _:ExitReason -> 269 erlang:error({ExitReason, {?MODULE, stop, [Ref, Reason, Timeout]}}) 270 end; 271stop(Name, Reason, Timeout) when is_atom(Name) orelse is_pid(Name) -> 272 try 273 gen:stop(Name, Reason, Timeout) 274 catch _:ExitReason -> 275 erlang:error({ExitReason, {?MODULE, stop, [Name, Reason, Timeout]}}) 276 end. 277 278%% @doc Make a call to a wx_object server. 279%% The call waits until it gets a result. 280%% Invokes handle_call(Request, From, State) in the server 281-spec call(Obj, Request) -> term() when 282 Obj::wx:wx_object()|atom()|pid(), 283 Request::term(). 284call(Ref = #wx_ref{state=Pid}, Request) when is_pid(Pid) -> 285 try 286 {ok,Res} = gen:call(Pid, '$gen_call', Request, infinity), 287 Res 288 catch _:Reason -> 289 erlang:error({Reason, {?MODULE, call, [Ref, Request]}}) 290 end; 291call(Name, Request) when is_atom(Name) orelse is_pid(Name) -> 292 try 293 {ok,Res} = gen:call(Name, '$gen_call', Request, infinity), 294 Res 295 catch _:Reason -> 296 erlang:error({Reason, {?MODULE, call, [Name, Request]}}) 297 end. 298 299%% @doc Make a call to a wx_object server with a timeout. 300%% Invokes handle_call(Request, From, State) in server 301-spec call(Obj, Request, Timeout) -> term() when 302 Obj::wx:wx_object()|atom()|pid(), 303 Request::term(), 304 Timeout::integer(). 305call(Ref = #wx_ref{state=Pid}, Request, Timeout) when is_pid(Pid) -> 306 try 307 {ok,Res} = gen:call(Pid, '$gen_call', Request, Timeout), 308 Res 309 catch _:Reason -> 310 erlang:error({Reason, {?MODULE, call, [Ref, Request, Timeout]}}) 311 end; 312call(Name, Request, Timeout) when is_atom(Name) orelse is_pid(Name) -> 313 try 314 {ok,Res} = gen:call(Name, '$gen_call', Request, Timeout), 315 Res 316 catch _:Reason -> 317 erlang:error({Reason, {?MODULE, call, [Name, Request, Timeout]}}) 318 end. 319 320%% @doc Make a cast to a wx_object server. 321%% Invokes handle_cast(Request, State) in the server 322-spec cast(Obj, Request) -> ok when 323 Obj::wx:wx_object()|atom()|pid(), 324 Request::term(). 325cast(#wx_ref{state=Pid}, Request) when is_pid(Pid) -> 326 Pid ! {'$gen_cast',Request}, 327 ok; 328cast(Name, Request) when is_atom(Name) orelse is_pid(Name) -> 329 Name ! {'$gen_cast',Request}, 330 ok. 331 332%% @doc Get the pid of the object handle. 333-spec get_pid(Obj) -> pid() when 334 Obj::wx:wx_object()|atom()|pid(). 335get_pid(#wx_ref{state=Pid}) when is_pid(Pid) -> 336 Pid. 337 338%% @doc Sets the controlling process of the object handle. 339-spec set_pid(Obj, pid()) -> wx:wx_object() when 340 Obj::wx:wx_object()|atom()|pid(). 341set_pid(#wx_ref{}=R, Pid) when is_pid(Pid) -> 342 R#wx_ref{state=Pid}. 343 344%% ----------------------------------------------------------------- 345%% Send a reply to the client. 346%% ----------------------------------------------------------------- 347%% @doc Get the pid of the object handle. 348-spec reply({pid(), Tag::term()}, Reply::term()) -> pid(). 349reply({To, Tag}, Reply) -> 350 catch To ! {Tag, Reply}. 351 352%%%======================================================================== 353%%% Gen-callback functions 354%%%======================================================================== 355%%% --------------------------------------------------- 356%%% Initiate the new process. 357%%% Register the name using the Rfunc function 358%%% Calls the Mod:init/Args function. 359%%% Finally an acknowledge is sent to Parent and the main 360%%% loop is entered. 361%%% --------------------------------------------------- 362%% @hidden 363init_it(Starter, self, Name, Mod, Args, Options) -> 364 init_it(Starter, self(), Name, Mod, Args, Options); 365init_it(Starter, Parent, Name, Mod, Args, [WxEnv|Options]) -> 366 case WxEnv of 367 undefined -> ok; 368 _ -> wx:set_env(WxEnv) 369 end, 370 put('_wx_object_', {Mod,'_wx_init_'}), 371 Debug = debug_options(Name, Options), 372 case catch Mod:init(Args) of 373 {#wx_ref{} = Ref, State} -> 374 init_it2(Ref, Starter, Parent, Name, State, Mod, infinity, Debug); 375 {#wx_ref{} = Ref, State, Timeout} -> 376 init_it2(Ref, Starter, Parent, Name, State, Mod, Timeout, Debug); 377 {stop, Reason} -> 378 proc_lib:init_ack(Starter, {error, Reason}), 379 exit(Reason); 380 ignore -> 381 proc_lib:init_ack(Starter, ignore), 382 exit(normal); 383 {'EXIT', Reason} -> 384 proc_lib:init_ack(Starter, {error, Reason}), 385 exit(Reason); 386 Else -> 387 Error = {bad_return_value, Else}, 388 proc_lib:init_ack(Starter, {error, Error}), 389 exit(Error) 390 end. 391%% @hidden 392init_it2(Ref, Starter, Parent, Name, State, Mod, Timeout, Debug) -> 393 ok = wxe_util:register_pid(Ref), 394 case ?CLASS_T(Ref#wx_ref.type, wxWindow) of 395 false -> 396 Reason = {Ref, "not a wxWindow subclass"}, 397 proc_lib:init_ack(Starter, {error, Reason}), 398 exit(Reason); 399 true -> 400 proc_lib:init_ack(Starter, {ok, self()}), 401 proc_lib:init_ack(Starter, Ref#wx_ref{state=self()}), 402 loop(Parent, Name, State, Mod, Timeout, Debug) 403 end. 404 405%%%======================================================================== 406%%% Internal functions 407%%%======================================================================== 408%%% --------------------------------------------------- 409%%% The MAIN loop. 410%%% --------------------------------------------------- 411%% @hidden 412loop(Parent, Name, State, Mod, Time, Debug) -> 413 put('_wx_object_', {Mod,State}), 414 Msg = receive 415 Input -> 416 Input 417 after Time -> 418 timeout 419 end, 420 case Msg of 421 {system, From, Req} -> 422 sys:handle_system_msg(Req, From, Parent, ?MODULE, Debug, 423 [Name, State, Mod, Time]); 424 {'EXIT', Parent, Reason} -> 425 terminate(Reason, Name, Msg, Mod, State, Debug); 426 {'_wxe_destroy_', _Me} -> 427 terminate(wx_deleted, Name, Msg, Mod, State, Debug); 428 _Msg when Debug =:= [] -> 429 handle_msg(Msg, Parent, Name, State, Mod); 430 _Msg -> 431 Debug1 = sys:handle_debug(Debug, fun print_event/3, 432 Name, {in, Msg}), 433 handle_msg(Msg, Parent, Name, State, Mod, Debug1) 434 end. 435 436%%% --------------------------------------------------- 437%%% Message handling functions 438%%% --------------------------------------------------- 439%% @hidden 440dispatch({'$gen_cast', Msg}, Mod, State) -> 441 Mod:handle_cast(Msg, State); 442dispatch(Msg = #wx{}, Mod, State) -> 443 Mod:handle_event(Msg, State); 444dispatch(Info, Mod, State) -> 445 Mod:handle_info(Info, State). 446 447%% @hidden 448handle_msg({'$gen_call', From, Msg}, Parent, Name, State, Mod) -> 449 case catch Mod:handle_call(Msg, From, State) of 450 {reply, Reply, NState} -> 451 reply(From, Reply), 452 loop(Parent, Name, NState, Mod, infinity, []); 453 {reply, Reply, NState, Time1} -> 454 reply(From, Reply), 455 loop(Parent, Name, NState, Mod, Time1, []); 456 {noreply, NState} -> 457 loop(Parent, Name, NState, Mod, infinity, []); 458 {noreply, NState, Time1} -> 459 loop(Parent, Name, NState, Mod, Time1, []); 460 {stop, Reason, Reply, NState} -> 461 {'EXIT', R} = 462 (catch terminate(Reason, Name, Msg, Mod, NState, [])), 463 reply(From, Reply), 464 exit(R); 465 Other -> handle_common_reply(Other, Name, Msg, Mod, State, []) 466 end; 467handle_msg(Msg, Parent, Name, State, Mod) -> 468 case catch dispatch(Msg, Mod, State) of 469 {'EXIT', {undef, [{Mod, handle_info, [_,_], _}|_]}} -> 470 handle_no_reply({noreply, State}, Parent, Name, Msg, Mod, State, []); 471 Reply -> 472 handle_no_reply(Reply, Parent, Name, Msg, Mod, State, []) 473 end. 474 475%% @hidden 476handle_msg({'$gen_call', From, Msg}, Parent, Name, State, Mod, Debug) -> 477 case catch Mod:handle_call(Msg, From, State) of 478 {reply, Reply, NState} -> 479 Debug1 = reply(Name, From, Reply, NState, Debug), 480 loop(Parent, Name, NState, Mod, infinity, Debug1); 481 {reply, Reply, NState, Time1} -> 482 Debug1 = reply(Name, From, Reply, NState, Debug), 483 loop(Parent, Name, NState, Mod, Time1, Debug1); 484 {noreply, NState} -> 485 Debug1 = sys:handle_debug(Debug, fun print_event/3, 486 Name, {noreply, NState}), 487 loop(Parent, Name, NState, Mod, infinity, Debug1); 488 {noreply, NState, Time1} -> 489 Debug1 = sys:handle_debug(Debug, fun print_event/3, 490 Name, {noreply, NState}), 491 loop(Parent, Name, NState, Mod, Time1, Debug1); 492 {stop, Reason, Reply, NState} -> 493 {'EXIT', R} = 494 (catch terminate(Reason, Name, Msg, Mod, NState, Debug)), 495 _ = reply(Name, From, Reply, NState, Debug), 496 exit(R); 497 Other -> 498 handle_common_reply(Other, Name, Msg, Mod, State, Debug) 499 end; 500handle_msg(Msg, Parent, Name, State, Mod, Debug) -> 501 Reply = (catch dispatch(Msg, Mod, State)), 502 handle_no_reply(Reply, Parent, Name, Msg, Mod, State, Debug). 503%% @hidden 504handle_no_reply({noreply, NState}, Parent, Name, _Msg, Mod, _State, []) -> 505 loop(Parent, Name, NState, Mod, infinity, []); 506handle_no_reply({noreply, NState, Time1}, Parent, Name, _Msg, Mod, _State, []) -> 507 loop(Parent, Name, NState, Mod, Time1, []); 508handle_no_reply({noreply, NState}, Parent, Name, _Msg, Mod, _State, Debug) -> 509 Debug1 = sys:handle_debug(Debug, fun print_event/3, 510 Name, {noreply, NState}), 511 loop(Parent, Name, NState, Mod, infinity, Debug1); 512handle_no_reply({noreply, NState, Time1}, Parent, Name, _Msg, Mod, _State, Debug) -> 513 Debug1 = sys:handle_debug(Debug, fun print_event/3, 514 Name, {noreply, NState}), 515 loop(Parent, Name, NState, Mod, Time1, Debug1); 516handle_no_reply(Reply, _Parent, Name, Msg, Mod, State, Debug) -> 517 handle_common_reply(Reply, Name, Msg, Mod, State,Debug). 518 519%% @hidden 520-spec handle_common_reply(_, _, _, _, _, _) -> no_return(). 521handle_common_reply(Reply, Name, Msg, Mod, State, Debug) -> 522 case Reply of 523 {stop, Reason, NState} -> 524 terminate(Reason, Name, Msg, Mod, NState, Debug); 525 {'EXIT', What} -> 526 terminate(What, Name, Msg, Mod, State, Debug); 527 _ -> 528 terminate({bad_return_value, Reply}, Name, Msg, Mod, State, Debug) 529 end. 530 531%% @hidden 532reply(Name, {To, Tag}, Reply, State, Debug) -> 533 reply({To, Tag}, Reply), 534 sys:handle_debug(Debug, fun print_event/3, 535 Name, {out, Reply, To, State}). 536 537 538%%----------------------------------------------------------------- 539%% Callback functions for system messages handling. 540%%----------------------------------------------------------------- 541%% @hidden 542system_continue(Parent, Debug, [Name, State, Mod, Time]) -> 543 loop(Parent, Name, State, Mod, Time, Debug). 544 545%% @hidden 546-spec system_terminate(_, _, _, [_]) -> no_return(). 547system_terminate(Reason, _Parent, Debug, [Name, State, Mod, _Time]) -> 548 terminate(Reason, Name, [], Mod, State, Debug). 549 550%% @hidden 551system_code_change([Name, State, Mod, Time], _Module, OldVsn, Extra) -> 552 case catch Mod:code_change(OldVsn, State, Extra) of 553 {ok, NewState} -> {ok, [Name, NewState, Mod, Time]}; 554 Else -> Else 555 end. 556 557%%----------------------------------------------------------------- 558%% Format debug messages. Print them as the call-back module sees 559%% them, not as the real erlang messages. Use trace for that. 560%%----------------------------------------------------------------- 561print_event(Dev, {in, Msg}, Name) -> 562 case Msg of 563 {'$gen_call', {From, _Tag}, Call} -> 564 io:format(Dev, "*DBG* ~tp got call ~tp from ~w~n", 565 [Name, Call, From]); 566 {'$gen_cast', Cast} -> 567 io:format(Dev, "*DBG* ~tp got cast ~tp~n", 568 [Name, Cast]); 569 _ -> 570 io:format(Dev, "*DBG* ~tp got ~tp~n", [Name, Msg]) 571 end; 572print_event(Dev, {out, Msg, To, State}, Name) -> 573 io:format(Dev, "*DBG* ~tp sent ~tp to ~w, new state ~tp~n", 574 [Name, Msg, To, State]); 575print_event(Dev, {noreply, State}, Name) -> 576 io:format(Dev, "*DBG* ~tp new state ~tp~n", [Name, State]); 577print_event(Dev, Event, Name) -> 578 io:format(Dev, "*DBG* ~tp dbg ~tp~n", [Name, Event]). 579 580%%% --------------------------------------------------- 581%%% Terminate the server. 582%%% --------------------------------------------------- 583%% @hidden 584terminate(Reason, Name, Msg, Mod, State, Debug) -> 585 case try_terminate(Mod, Reason, State) of 586 {'EXIT', R} -> 587 error_info(R, Name, Msg, State, Debug), 588 exit(R); 589 _ -> 590 case Reason of 591 normal -> 592 exit(normal); 593 shutdown -> 594 exit(shutdown); 595 wx_deleted -> 596 exit(normal); 597 _ -> 598 error_info(Reason, Name, Msg, State, Debug), 599 exit(Reason) 600 end 601 end. 602 603try_terminate(Mod, Reason, State) -> 604 case erlang:function_exported(Mod, terminate, 2) of 605 true -> 606 catch Mod:terminate(Reason, State); 607 _ -> 608 ok 609 end. 610 611%% @hidden 612error_info(_Reason, application_controller, _Msg, _State, _Debug) -> 613 ok; 614error_info(Reason, Name, Msg, State, Debug) -> 615 Reason1 = 616 case Reason of 617 {undef,[{M,F,A,L}|MFAs]} -> 618 case code:is_loaded(M) of 619 false -> 620 {'module could not be loaded',[{M,F,A,L}|MFAs]}; 621 _ -> 622 case erlang:function_exported(M, F, length(A)) of 623 true -> 624 Reason; 625 false -> 626 {'function not exported',[{M,F,A,L}|MFAs]} 627 end 628 end; 629 _ -> 630 Reason 631 end, 632 format("** wx object server ~tp terminating \n" 633 "** Last message in was ~tp~n" 634 "** When Server state == ~tp~n" 635 "** Reason for termination == ~n** ~tp~n", 636 [Name, Msg, State, Reason1]), 637 sys:print_log(Debug), 638 ok. 639 640%%% --------------------------------------------------- 641%%% Misc. functions. 642%%% --------------------------------------------------- 643%% @hidden 644opt(Op, [{Op, Value}|_]) -> 645 {ok, Value}; 646opt(Op, [_|Options]) -> 647 opt(Op, Options); 648opt(_, []) -> 649 false. 650%% @hidden 651debug_options(Name, Opts) -> 652 case opt(debug, Opts) of 653 {ok, Options} -> dbg_opts(Name, Options); 654 _ -> [] 655 end. 656%% @hidden 657dbg_opts(Name, Opts) -> 658 case catch sys:debug_options(Opts) of 659 {'EXIT',_} -> 660 format("~tp: ignoring erroneous debug options - ~tp~n", 661 [Name, Opts]), 662 []; 663 Dbg -> 664 Dbg 665 end. 666 667%% @hidden 668%%----------------------------------------------------------------- 669%% Status information 670%%----------------------------------------------------------------- 671format_status(Opt, StatusData) -> 672 [PDict, SysState, Parent, Debug, [Name, State, Mod, _Time]] = StatusData, 673 StatusHdr = "Status for wx object ", 674 Header = if 675 is_pid(Name) -> 676 lists:concat([StatusHdr, pid_to_list(Name)]); 677 is_atom(Name); is_list(Name) -> 678 lists:concat([StatusHdr, Name]); 679 true -> 680 {StatusHdr, Name} 681 end, 682 Log = sys:get_debug(log, Debug, []), 683 Specfic = 684 case erlang:function_exported(Mod, format_status, 2) of 685 true -> 686 case catch Mod:format_status(Opt, [PDict, State]) of 687 {'EXIT', _} -> [{data, [{"State", State}]}]; 688 Else -> Else 689 end; 690 _ -> 691 [{data, [{"State", State}]}] 692 end, 693 [{header, Header}, 694 {data, [{"Status", SysState}, 695 {"Parent", Parent}, 696 {"Logged events", Log}]} | 697 Specfic]. 698