diff options
23 files changed, 769 insertions, 358 deletions
diff --git a/bootstrap/lib/kernel/ebin/dist_util.beam b/bootstrap/lib/kernel/ebin/dist_util.beam Binary files differindex e5d0f66e6e..bf3572fe23 100644 --- a/bootstrap/lib/kernel/ebin/dist_util.beam +++ b/bootstrap/lib/kernel/ebin/dist_util.beam diff --git a/bootstrap/lib/kernel/ebin/inet6_tcp_dist.beam b/bootstrap/lib/kernel/ebin/inet6_tcp_dist.beam Binary files differindex 1be1dc1c57..98f70db13c 100644 --- a/bootstrap/lib/kernel/ebin/inet6_tcp_dist.beam +++ b/bootstrap/lib/kernel/ebin/inet6_tcp_dist.beam diff --git a/bootstrap/lib/kernel/ebin/inet_tcp_dist.beam b/bootstrap/lib/kernel/ebin/inet_tcp_dist.beam Binary files differindex 5fd6b3e909..087274e89d 100644 --- a/bootstrap/lib/kernel/ebin/inet_tcp_dist.beam +++ b/bootstrap/lib/kernel/ebin/inet_tcp_dist.beam diff --git a/bootstrap/lib/kernel/ebin/net_kernel.beam b/bootstrap/lib/kernel/ebin/net_kernel.beam Binary files differindex 6cf6916fe6..1197b4f681 100644 --- a/bootstrap/lib/kernel/ebin/net_kernel.beam +++ b/bootstrap/lib/kernel/ebin/net_kernel.beam diff --git a/bootstrap/lib/kernel/include/dist_util.hrl b/bootstrap/lib/kernel/include/dist_util.hrl index 43e50d4325..320e916c04 100644 --- a/bootstrap/lib/kernel/include/dist_util.hrl +++ b/bootstrap/lib/kernel/include/dist_util.hrl @@ -63,7 +63,7 @@ f_getll, %% Get low level port or pid. f_address, %% The address of the "socket", %% generated from Socket,Node - %% These two are used in the tick loop, + %% These three are used in the tick loop, %% so they are not fun's to avoid holding old code. mf_tick, %% Takes the socket as parameters and %% sends a tick, this is no fun, it @@ -74,7 +74,11 @@ %% {ok, RecvCnt, SendCnt, SendPend} for %% a given socket. This is a {M,F}, %% returning {error, Reason on failure} - request_type = normal + request_type = normal, + + %% New in kernel-5.1 (OTP 19.1): + mf_setopts, %% netkernel:setopts on active connection + mf_getopts %% netkernel:getopts on active connection }). diff --git a/erts/emulator/beam/erl_bif_info.c b/erts/emulator/beam/erl_bif_info.c index 3fb866733c..6cedf3c8a5 100644 --- a/erts/emulator/beam/erl_bif_info.c +++ b/erts/emulator/beam/erl_bif_info.c @@ -2284,9 +2284,7 @@ BIF_RETTYPE system_info_1(BIF_ALIST_1) } else if (ERTS_IS_ATOM_STR("dist_ctrl", BIF_ARG_1)) { DistEntry *dep; i = 0; - /* Need to be the only thread running... */ - erts_smp_proc_unlock(BIF_P, ERTS_PROC_LOCK_MAIN); - erts_smp_thr_progress_block(); + erts_smp_rwmtx_rlock(&erts_dist_table_rwmtx); for (dep = erts_visible_dist_entries; dep; dep = dep->next) ++i; for (dep = erts_hidden_dist_entries; dep; dep = dep->next) @@ -2309,8 +2307,7 @@ BIF_RETTYPE system_info_1(BIF_ALIST_1) res = CONS(hp, tpl, res); hp += 2; } - erts_smp_thr_progress_unblock(); - erts_smp_proc_lock(BIF_P, ERTS_PROC_LOCK_MAIN); + erts_smp_rwmtx_runlock(&erts_dist_table_rwmtx); BIF_RET(res); } else if (BIF_ARG_1 == am_system_version) { erts_dsprintf_buf_t *dsbufp = erts_create_tmp_dsbuf(0); diff --git a/lib/kernel/doc/src/inet.xml b/lib/kernel/doc/src/inet.xml index c0dce2f50c..8cc21bf3e2 100644 --- a/lib/kernel/doc/src/inet.xml +++ b/lib/kernel/doc/src/inet.xml @@ -151,6 +151,12 @@ fe80::204:acff:fe17:bf38 <name name="socket_address"/> </datatype> <datatype> + <name name="socket_getopt"/> + </datatype> + <datatype> + <name name="socket_setopt"/> + </datatype> + <datatype> <name name="returned_non_ip_address"/> <desc> <p> @@ -327,8 +333,6 @@ fe80::204:acff:fe17:bf38 <func> <name name="getopts" arity="2"/> <fsummary>Get one or more options for a socket.</fsummary> - <type name="socket_getopt"/> - <type name="socket_setopt"/> <desc> <p>Gets one or more options for a socket. For a list of available options, see @@ -580,7 +584,6 @@ get_tcpi_sacked(Sock) -> <func> <name name="setopts" arity="2"/> <fsummary>Set one or more options for a socket.</fsummary> - <type name="socket_setopt"/> <desc> <p>Sets one or more options for a socket.</p> <p>The following options are available:</p> diff --git a/lib/kernel/doc/src/kernel_app.xml b/lib/kernel/doc/src/kernel_app.xml index 9e6fb60bb7..dc0291babe 100644 --- a/lib/kernel/doc/src/kernel_app.xml +++ b/lib/kernel/doc/src/kernel_app.xml @@ -215,12 +215,14 @@ <p>Defines the <c>First..Last</c> port range for the listener socket of a distributed Erlang node.</p> </item> + <marker id="inet_dist_listen_options"></marker> <tag><c>{inet_dist_listen_options, Opts}</c></tag> <item> <p>Defines a list of extra socket options to be used when opening the listening socket for a distributed Erlang node. See <seealso marker="gen_tcp#listen/2"><c>gen_tcp:listen/2</c></seealso>.</p> </item> + <marker id="inet_dist_connect_options"></marker> <tag><c>{inet_dist_connect_options, Opts}</c></tag> <item> <p>Defines a list of extra socket options to be used when connecting to diff --git a/lib/kernel/doc/src/net_kernel.xml b/lib/kernel/doc/src/net_kernel.xml index f48a534d4f..3c1b3d5190 100644 --- a/lib/kernel/doc/src/net_kernel.xml +++ b/lib/kernel/doc/src/net_kernel.xml @@ -116,6 +116,21 @@ $ <input>erl -sname foobar</input></pre> </func> <func> + <name name="getopts" arity="2"/> + <fsummary>Get distribution socket options.</fsummary> + <desc> + <p>Get one or more options for the distribution socket + connected to <c><anno>Node</anno></c>.</p> + <p>If <c><anno>Node</anno></c> is a connected node + the return value is the same as from + <seealso marker="inet#getopts/2"><c>inet:getopts(Sock, Options)</c></seealso> + where <c>Sock</c> is the distribution socket for <c><anno>Node</anno></c>.</p> + <p>Returns <c>ignored</c> if the local node is not alive or + <c>{error, noconnection}</c> if <c><anno>Node</anno></c> is not connected.</p> + </desc> + </func> + + <func> <name name="monitor_nodes" arity="1"/> <name name="monitor_nodes" arity="2"/> <fsummary>Subscribe to node status change messages.</fsummary> @@ -289,6 +304,27 @@ $ <input>erl -sname foobar</input></pre> </func> <func> + <name name="setopts" arity="2"/> + <fsummary>Set distribution socket options.</fsummary> + <desc> + <p>Set one or more options for distribution sockets. + Argument <c><anno>Node</anno></c> can be either one node name + or the atom <c>new</c> to affect the distribution sockets of all + future connected nodes.</p> + <p>The return value is the same as from + <seealso marker="inet#setopts/2"><c>inet:setopts/2</c></seealso> + or <c>{error, noconnection}</c> if <c><anno>Node</anno></c> is not + a connected node or <c>new</c>.</p> + <p>If <c><anno>Node</anno></c> is <c>new</c> the <c><anno>Options</anno></c> + will then also be added to kernel configration parameters + <seealso marker="kernel:kernel_app#inet_dist_listen_options">inet_dist_listen_options</seealso> + and + <seealso marker="kernel:kernel_app#inet_dist_connect_options">inet_dist_connect_options</seealso>.</p> + <p>Returns <c>ignored</c> if the local node is not alive.</p> + </desc> + </func> + + <func> <name>start([Name]) -> {ok, pid()} | {error, Reason}</name> <name>start([Name, NameType]) -> {ok, pid()} | {error, Reason}</name> <name>start([Name, NameType, Ticktime]) -> {ok, pid()} | {error, Reason}</name> diff --git a/lib/kernel/include/dist_util.hrl b/lib/kernel/include/dist_util.hrl index 43e50d4325..320e916c04 100644 --- a/lib/kernel/include/dist_util.hrl +++ b/lib/kernel/include/dist_util.hrl @@ -63,7 +63,7 @@ f_getll, %% Get low level port or pid. f_address, %% The address of the "socket", %% generated from Socket,Node - %% These two are used in the tick loop, + %% These three are used in the tick loop, %% so they are not fun's to avoid holding old code. mf_tick, %% Takes the socket as parameters and %% sends a tick, this is no fun, it @@ -74,7 +74,11 @@ %% {ok, RecvCnt, SendCnt, SendPend} for %% a given socket. This is a {M,F}, %% returning {error, Reason on failure} - request_type = normal + request_type = normal, + + %% New in kernel-5.1 (OTP 19.1): + mf_setopts, %% netkernel:setopts on active connection + mf_getopts %% netkernel:getopts on active connection }). diff --git a/lib/kernel/src/dist_util.erl b/lib/kernel/src/dist_util.erl index 47d0c1b861..8d2fc4d4b7 100644 --- a/lib/kernel/src/dist_util.erl +++ b/lib/kernel/src/dist_util.erl @@ -143,7 +143,11 @@ handshake_other_started(#hs_data{request_type=ReqType}=HSData0) -> ChallengeB = recv_challenge_reply(HSData, ChallengeA, MyCookie), send_challenge_ack(HSData, gen_digest(ChallengeB, HisCookie)), ?debug({dist_util, self(), accept_connection, Node}), - connection(HSData). + connection(HSData); + +handshake_other_started(OldHsData) when element(1,OldHsData) =:= hs_data -> + handshake_other_started(convert_old_hsdata(OldHsData)). + %% %% check if connecting node is allowed to connect @@ -330,7 +334,20 @@ handshake_we_started(#hs_data{request_type=ReqType, gen_digest(ChallengeA,HisCookie)), reset_timer(NewHSData#hs_data.timer), recv_challenge_ack(NewHSData, MyChallenge, MyCookie), - connection(NewHSData). + connection(NewHSData); + +handshake_we_started(OldHsData) when element(1,OldHsData) =:= hs_data -> + handshake_we_started(convert_old_hsdata(OldHsData)). + +convert_old_hsdata({hs_data, KP, ON, TN, S, T, TF, A, OV, OF, OS, FS, FR, + FS_PRE, FS_POST, FG, FA, MFT, MFG, RT}) -> + #hs_data{ + kernel_pid = KP, other_node = ON, this_node = TN, socket = S, timer = T, + this_flags = TF, allowed = A, other_version = OV, other_flags = OF, + other_started = OS, f_send = FS, f_recv = FR, f_setopts_pre_nodeup = FS_PRE, + f_setopts_post_nodeup = FS_POST, f_getll = FG, f_address = FA, + mf_tick = MFT, mf_getstat = MFG, request_type = RT}. + %% -------------------------------------------------------------- %% The connection has been established. @@ -350,15 +367,15 @@ connection(#hs_data{other_node = Node, mark_nodeup(HSData,Address), case FPostNodeup(Socket) of ok -> - con_loop(HSData#hs_data.kernel_pid, - Node, - Socket, - Address, - HSData#hs_data.this_node, - PType, - #tick{}, - HSData#hs_data.mf_tick, - HSData#hs_data.mf_getstat); + con_loop({HSData#hs_data.kernel_pid, + Node, + Socket, + PType, + HSData#hs_data.mf_tick, + HSData#hs_data.mf_getstat, + HSData#hs_data.mf_setopts, + HSData#hs_data.mf_getopts}, + #tick{}); _ -> ?shutdown2(Node, connection_setup_failed) end; @@ -454,8 +471,8 @@ mark_nodeup(#hs_data{kernel_pid = Kernel, ?shutdown(Node) end. -con_loop(Kernel, Node, Socket, TcpAddress, - MyNode, Type, Tick, MFTick, MFGetstat) -> +con_loop({Kernel, Node, Socket, Type, MFTick, MFGetstat, MFSetOpts, MFGetOpts}=ConData, + Tick) -> receive {tcp_closed, Socket} -> ?shutdown2(Node, connection_closed); @@ -468,15 +485,12 @@ con_loop(Kernel, Node, Socket, TcpAddress, _ -> ignore_it end, - con_loop(Kernel, Node, Socket, TcpAddress, MyNode, Type, - Tick, MFTick, MFGetstat); + con_loop(ConData, Tick); {Kernel, tick} -> case send_tick(Socket, Tick, Type, MFTick, MFGetstat) of {ok, NewTick} -> - con_loop(Kernel, Node, Socket, TcpAddress, - MyNode, Type, NewTick, MFTick, - MFGetstat); + con_loop(ConData, NewTick); {error, not_responding} -> error_msg("** Node ~p not responding **~n" "** Removing (timedout) connection **~n", @@ -489,13 +503,24 @@ con_loop(Kernel, Node, Socket, TcpAddress, case MFGetstat(Socket) of {ok, Read, Write, _} -> From ! {self(), get_status, {ok, Read, Write}}, - con_loop(Kernel, Node, Socket, TcpAddress, - MyNode, - Type, Tick, - MFTick, MFGetstat); + con_loop(ConData, Tick); _ -> ?shutdown2(Node, get_status_failed) - end + end; + {From, Ref, {setopts, Opts}} -> + Ret = case MFSetOpts of + undefined -> {error, enotsup}; + _ -> MFSetOpts(Socket, Opts) + end, + From ! {Ref, Ret}, + con_loop(ConData, Tick); + {From, Ref, {getopts, Opts}} -> + Ret = case MFGetOpts of + undefined -> {error, enotsup}; + _ -> MFGetOpts(Socket, Opts) + end, + From ! {Ref, Ret}, + con_loop(ConData, Tick) end. diff --git a/lib/kernel/src/inet.erl b/lib/kernel/src/inet.erl index a91a6ed517..75dd800c6b 100644 --- a/lib/kernel/src/inet.erl +++ b/lib/kernel/src/inet.erl @@ -75,6 +75,7 @@ -export_type([address_family/0, hostent/0, hostname/0, ip4_address/0, ip6_address/0, ip_address/0, port_number/0, local_address/0, socket_address/0, returned_non_ip_address/0, + socket_setopt/0, socket_getopt/0, posix/0, socket/0, stat_option/0]). %% imports -import(lists, [append/1, duplicate/2, filter/2, foldl/3]). diff --git a/lib/kernel/src/inet6_tcp_dist.erl b/lib/kernel/src/inet6_tcp_dist.erl index 3aa61973af..9b6c2745d5 100644 --- a/lib/kernel/src/inet6_tcp_dist.erl +++ b/lib/kernel/src/inet6_tcp_dist.erl @@ -24,6 +24,7 @@ -export([listen/1, accept/1, accept_connection/5, setup/5, close/1, select/1, is_node_name/1]). +-export([setopts/2, getopts/2]). %% ------------------------------------------------------------ %% Select this protocol based on node name @@ -72,3 +73,9 @@ close(Socket) -> is_node_name(Node) when is_atom(Node) -> inet_tcp_dist:is_node_name(Node). + +setopts(S, Opts) -> + inet_tcp_dist:setopts(S, Opts). + +getopts(S, Opts) -> + inet_tcp_dist:getopts(S, Opts). diff --git a/lib/kernel/src/inet_tcp_dist.erl b/lib/kernel/src/inet_tcp_dist.erl index 94bde55133..3084bd599a 100644 --- a/lib/kernel/src/inet_tcp_dist.erl +++ b/lib/kernel/src/inet_tcp_dist.erl @@ -24,13 +24,16 @@ -export([listen/1, accept/1, accept_connection/5, setup/5, close/1, select/1, is_node_name/1]). +%% Optional +-export([setopts/2, getopts/2]). + %% Generalized dist API -export([gen_listen/2, gen_accept/2, gen_accept_connection/6, gen_setup/6, gen_select/2]). %% internal exports --export([accept_loop/3,do_accept/7,do_setup/7,getstat/1]). +-export([accept_loop/3,do_accept/7,do_setup/7,getstat/1,tick/2]). -import(error_logger,[error_msg/2]). @@ -215,8 +218,10 @@ do_accept(Driver, Kernel, AcceptPid, Socket, MyNode, Allowed, SetupTime) -> inet:getll(S) end, f_address = fun(S, Node) -> get_remote_id(Driver, S, Node) end, - mf_tick = fun(S) -> tick(Driver, S) end, - mf_getstat = fun ?MODULE:getstat/1 + mf_tick = fun(S) -> ?MODULE:tick(Driver, S) end, + mf_getstat = fun ?MODULE:getstat/1, + mf_setopts = fun ?MODULE:setopts/2, + mf_getopts = fun ?MODULE:getopts/2 }, dist_util:handshake_other_started(HSData); {false,IP} -> @@ -320,6 +325,7 @@ do_setup(Driver, Kernel, Node, Type, MyNode, LongOrShortNames, SetupTime) -> {packet, 4}, nodelay()]) end, + f_getll = fun inet:getll/1, f_address = fun(_,_) -> @@ -329,9 +335,11 @@ do_setup(Driver, Kernel, Node, Type, MyNode, LongOrShortNames, SetupTime) -> protocol = tcp, family = AddressFamily} end, - mf_tick = fun(S) -> tick(Driver, S) end, + mf_tick = fun(S) -> ?MODULE:tick(Driver, S) end, mf_getstat = fun ?MODULE:getstat/1, - request_type = Type + request_type = Type, + mf_setopts = fun ?MODULE:setopts/2, + mf_getopts = fun ?MODULE:getopts/2 }, dist_util:handshake_we_started(HSData); _ -> @@ -492,3 +500,12 @@ split_stat([], R, W, P) -> {ok, R, W, P}. +setopts(S, Opts) -> + case [Opt || {K,_}=Opt <- Opts, + K =:= active orelse K =:= deliver orelse K =:= packet] of + [] -> inet:setopts(S,Opts); + Opts1 -> {error, {badopts,Opts1}} + end. + +getopts(S, Opts) -> + inet:getopts(S, Opts). diff --git a/lib/kernel/src/net_kernel.erl b/lib/kernel/src/net_kernel.erl index ac19f4935b..0c679e7349 100644 --- a/lib/kernel/src/net_kernel.erl +++ b/lib/kernel/src/net_kernel.erl @@ -59,6 +59,8 @@ connect_node/1, monitor_nodes/1, monitor_nodes/2, + setopts/2, + getopts/2, start/1, stop/0]). @@ -111,7 +113,7 @@ }). -record(listen, { - listen, %% listen pid + listen, %% listen socket accept, %% accepting pid address, %% #net_address module %% proto module @@ -384,7 +386,7 @@ init({Name, LongOrShortNames, TickT, CleanHalt}) -> connections = ets:new(sys_dist,[named_table, protected, - {keypos, 2}]), + {keypos, #connection.node}]), listen = Listeners, allowed = [], verbose = 0 @@ -554,6 +556,38 @@ handle_call({new_ticktime,_T,_TP}, #state{tick = #tick_change{time = T}} = State) -> async_reply({reply, {ongoing_change_to, T}, State}, From); +handle_call({setopts, new, Opts}, From, State) -> + Ret = setopts_new(Opts, State), + async_reply({reply, Ret, State}, From); + +handle_call({setopts, Node, Opts}, From, State) -> + Return = + case ets:lookup(sys_dist, Node) of + [Conn] when Conn#connection.state =:= up -> + case call_owner(Conn#connection.owner, {setopts, Opts}) of + {ok, Ret} -> Ret; + _ -> {error, noconnection} + end; + + _ -> + {error, noconnection} + end, + async_reply({reply, Return, State}, From); + +handle_call({getopts, Node, Opts}, From, State) -> + Return = + case ets:lookup(sys_dist, Node) of + [Conn] when Conn#connection.state =:= up -> + case call_owner(Conn#connection.owner, {getopts, Opts}) of + {ok, Ret} -> Ret; + _ -> {error, noconnection} + end; + + _ -> + {error, noconnection} + end, + async_reply({reply, Return, State}, From); + handle_call(_Msg, _From, State) -> {noreply, State}. @@ -1608,3 +1642,93 @@ async_gen_server_reply(From, Msg) -> {'EXIT', _} -> ok end. + +call_owner(Owner, Msg) -> + Mref = monitor(process, Owner), + Owner ! {self(), Mref, Msg}, + receive + {Mref, Reply} -> + erlang:demonitor(Mref, [flush]), + {ok, Reply}; + {'DOWN', Mref, _, _, _} -> + error + end. + + +-spec setopts(Node, Options) -> ok | {error, Reason} | ignored when + Node :: node() | new, + Options :: [inet:socket_setopt()], + Reason :: inet:posix() | noconnection. + +setopts(Node, Opts) when is_atom(Node), is_list(Opts) -> + request({setopts, Node, Opts}). + +setopts_new(Opts, State) -> + %% First try setopts on listening socket(s) + %% Bail out on failure. + %% If successful, we are pretty sure Opts are ok + %% and we continue with config params and pending connections. + case setopts_on_listen(Opts, State#state.listen) of + ok -> + setopts_new_1(Opts); + Fail -> Fail + end. + +setopts_on_listen(_, []) -> ok; +setopts_on_listen(Opts, [#listen {listen = LSocket, module = Mod} | T]) -> + try Mod:setopts(LSocket, Opts) of + ok -> + setopts_on_listen(Opts, T); + Fail -> Fail + catch + error:undef -> {error, enotsup} + end. + +setopts_new_1(Opts) -> + ConnectOpts = case application:get_env(kernel, inet_dist_connect_options) of + {ok, CO} -> CO; + _ -> [] + end, + application:set_env(kernel, inet_dist_connect_options, + merge_opts(Opts,ConnectOpts)), + ListenOpts = case application:get_env(kernel, inet_dist_listen_options) of + {ok, LO} -> LO; + _ -> [] + end, + application:set_env(kernel, inet_dist_listen_options, + merge_opts(Opts, ListenOpts)), + case lists:keyfind(nodelay, 1, Opts) of + {nodelay, ND} when is_boolean(ND) -> + application:set_env(kernel, dist_nodelay, ND); + _ -> ignore + end, + + %% Update any pending connections + PendingConns = ets:select(sys_dist, [{'_', + [{'=/=',{element,#connection.state,'$_'},up}], + ['$_']}]), + lists:foreach(fun(#connection{state = pending, owner = Owner}) -> + call_owner(Owner, {setopts, Opts}); + (#connection{state = up_pending, pending_owner = Owner}) -> + call_owner(Owner, {setopts, Opts}); + (_) -> ignore + end, PendingConns), + ok. + +merge_opts([], B) -> + B; +merge_opts([H|T], B0) -> + {Key, _} = H, + B1 = lists:filter(fun({K,_}) -> K =/= Key end, B0), + merge_opts(T, [H | B1]). + +-spec getopts(Node, Options) -> + {'ok', OptionValues} | {'error', Reason} | ignored when + Node :: node(), + Options :: [inet:socket_getopt()], + OptionValues :: [inet:socket_setopt()], + Reason :: inet:posix() | noconnection. + +getopts(Node, Opts) when is_atom(Node), is_list(Opts) -> + request({getopts, Node, Opts}). + diff --git a/lib/kernel/test/erl_distribution_SUITE.erl b/lib/kernel/test/erl_distribution_SUITE.erl index eb58e92224..e43be77428 100644 --- a/lib/kernel/test/erl_distribution_SUITE.erl +++ b/lib/kernel/test/erl_distribution_SUITE.erl @@ -25,6 +25,7 @@ init_per_group/2,end_per_group/2]). -export([tick/1, tick_change/1, illegal_nodenames/1, hidden_node/1, + setopts/1, table_waste/1, net_setuptime/1, inet_dist_options_options/1, @@ -42,6 +43,8 @@ -export([get_socket_priorities/0, tick_cli_test/1, tick_cli_test1/1, tick_serv_test/2, tick_serv_test1/1, + run_remote_test/1, + setopts_do/2, keep_conn/1, time_ping/1]). -export([init_per_testcase/2, end_per_testcase/2]). @@ -66,6 +69,7 @@ suite() -> all() -> [tick, tick_change, illegal_nodenames, hidden_node, + setopts, table_waste, net_setuptime, inet_dist_options_options, {group, monitor_nodes}]. @@ -282,6 +286,165 @@ tick_cli_test1(Node) -> end end. +setopts(Config) when is_list(Config) -> + register(setopts_regname, self()), + [N1,N2,N3,N4] = get_nodenames(4, setopts), + + {_N1F,Port1} = start_node_unconnected(N1, ?MODULE, run_remote_test, + ["setopts_do", atom_to_list(node()), "1", "ping"]), + 0 = wait_for_port_exit(Port1), + + {_N2F,Port2} = start_node_unconnected(N2, ?MODULE, run_remote_test, + ["setopts_do", atom_to_list(node()), "2", "ping"]), + 0 = wait_for_port_exit(Port2), + + {ok, LSock} = gen_tcp:listen(0, [{packet,2}, {active,false}]), + {ok, LTcpPort} = inet:port(LSock), + + {N3F,Port3} = start_node_unconnected(N3, ?MODULE, run_remote_test, + ["setopts_do", atom_to_list(node()), + "1", integer_to_list(LTcpPort)]), + wait_and_connect(LSock, N3F, Port3), + 0 = wait_for_port_exit(Port3), + + {N4F,Port4} = start_node_unconnected(N4, ?MODULE, run_remote_test, + ["setopts_do", atom_to_list(node()), + "2", integer_to_list(LTcpPort)]), + wait_and_connect(LSock, N4F, Port4), + 0 = wait_for_port_exit(Port4), + + ok. + +wait_and_connect(LSock, NodeName, NodePort) -> + {ok, Sock} = gen_tcp:accept(LSock), + {ok, "Connect please"} = gen_tcp:recv(Sock, 0), + flush_from_port(NodePort), + pong = net_adm:ping(NodeName), + gen_tcp:send(Sock, "Connect done"), + gen_tcp:close(Sock). + + +flush_from_port(Port) -> + flush_from_port(Port, 10). + +flush_from_port(Port, Timeout) -> + receive + {Port,{data,String}} -> + io:format("~p: ~s\n", [Port, String]), + flush_from_port(Port, Timeout) + after Timeout -> + timeout + end. + +wait_for_port_exit(Port) -> + case (receive M -> M end) of + {Port,{exit_status,Status}} -> + Status; + {Port,{data,String}} -> + io:format("~p: ~s\n", [Port, String]), + wait_for_port_exit(Port) + end. + +run_remote_test([FuncStr, TestNodeStr | Args]) -> + Status = try + io:format("Node ~p started~n", [node()]), + TestNode = list_to_atom(TestNodeStr), + io:format("Node ~p spawning function ~p~n", [node(), FuncStr]), + {Pid,Ref} = spawn_monitor(?MODULE, list_to_atom(FuncStr), [TestNode, Args]), + io:format("Node ~p waiting for function ~p~n", [node(), FuncStr]), + receive + {'DOWN', Ref, process, Pid, normal} -> + 0; + Other -> + io:format("Node ~p got unexpected msg: ~p\n",[node(), Other]), + 1 + end + catch + C:E -> + io:format("Node ~p got EXCEPTION ~p:~p\nat ~p\n", + [node(), C, E, erlang:get_stacktrace()]), + 2 + end, + io:format("Node ~p doing halt(~p).\n",[node(), Status]), + erlang:halt(Status). + +% Do the actual test on the remote node +setopts_do(TestNode, [OptNr, ConnectData]) -> + [] = nodes(), + {Opt, Val} = opt_from_nr(OptNr), + ok = net_kernel:setopts(new, [{Opt, Val}]), + + [] = nodes(), + {error, noconnection} = net_kernel:getopts(TestNode, [Opt]), + + case ConnectData of + "ping" -> % We connect + net_adm:ping(TestNode); + TcpPort -> % Other connect + {ok, Sock} = gen_tcp:connect("localhost", list_to_integer(TcpPort), + [{active,false},{packet,2}]), + ok = gen_tcp:send(Sock, "Connect please"), + {ok, "Connect done"} = gen_tcp:recv(Sock, 0), + gen_tcp:close(Sock) + end, + [TestNode] = nodes(), + {ok, [{Opt,Val}]} = net_kernel:getopts(TestNode, [Opt]), + {error, noconnection} = net_kernel:getopts('pixie@fairyland', [Opt]), + + NewVal = change_val(Val), + ok = net_kernel:setopts(TestNode, [{Opt, NewVal}]), + {ok, [{Opt,NewVal}]} = net_kernel:getopts(TestNode, [Opt]), + + ok = net_kernel:setopts(TestNode, [{Opt, Val}]), + {ok, [{Opt,Val}]} = net_kernel:getopts(TestNode, [Opt]), + + ok. + +opt_from_nr("1") -> {nodelay, true}; +opt_from_nr("2") -> {nodelay, false}. + +change_val(true) -> false; +change_val(false) -> true. + +start_node_unconnected(Name, Mod, Func, Args) -> + FullName = full_node_name(Name), + CmdLine = mk_node_cmdline(Name,Mod,Func,Args), + io:format("Starting node ~p: ~s~n", [FullName, CmdLine]), + case open_port({spawn, CmdLine}, [exit_status]) of + Port when is_port(Port) -> + {FullName, Port}; + Error -> + exit({failed_to_start_node, FullName, Error}) + end. + +full_node_name(PreName) -> + HostSuffix = lists:dropwhile(fun ($@) -> false; (_) -> true end, + atom_to_list(node())), + list_to_atom(atom_to_list(PreName) ++ HostSuffix). + +mk_node_cmdline(Name,Mod,Func,Args) -> + Static = "-noinput", + Pa = filename:dirname(code:which(?MODULE)), + Prog = case catch init:get_argument(progname) of + {ok,[[P]]} -> P; + _ -> exit(no_progname_argument_found) + end, + NameSw = case net_kernel:longnames() of + false -> "-sname "; + true -> "-name "; + _ -> exit(not_distributed_node) + end, + {ok, Pwd} = file:get_cwd(), + NameStr = atom_to_list(Name), + Prog ++ " " + ++ Static ++ " " + ++ NameSw ++ " " ++ NameStr + ++ " -pa " ++ Pa + ++ " -env ERL_CRASH_DUMP " ++ Pwd ++ "/erl_crash_dump." ++ NameStr + ++ " -setcookie " ++ atom_to_list(erlang:get_cookie()) + ++ " -run " ++ atom_to_list(Mod) ++ " " ++ atom_to_list(Func) + ++ " " ++ string:join(Args, " "). + %% OTP-4255. tick_change(Config) when is_list(Config) -> diff --git a/lib/wx/api_gen/wx_extra/wxListCtrl.erl b/lib/wx/api_gen/wx_extra/wxListCtrl.erl index acdb69fdeb..355a4cdfd1 100644 --- a/lib/wx/api_gen/wx_extra/wxListCtrl.erl +++ b/lib/wx/api_gen/wx_extra/wxListCtrl.erl @@ -43,33 +43,36 @@ SortItems>> <<EXPORT:wxListCtrl new/0, new/1, new/2 wxListCtrl:EXPORT>> <<wxListCtrl_new_0 -%% @spec () -> wxListCtrl() %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxlistctrl.html#wxlistctrlwxlistctrl">external documentation</a>. +-spec new() -> wxListCtrl(). new() -> wxe_util:construct(~s, <<>>). wxListCtrl_new_0>> <<wxListCtrl_new_2 -%% @spec (Parent::wxWindow:wxWindow()) -> wxListCtrl() -%% @equiv new(Parent, []) +-spec new(Parent) -> wxListCtrl() when + Parent::wxWindow:wxWindow(). new(Parent) when is_record(Parent, wx_ref) -> new(Parent, []). -%% @spec (Parent::wxWindow:wxWindow(), [Option]) -> wxListCtrl() -%% Option = {winid, integer()} | -%% {pos, {X::integer(),Y::integer()}} | -%% {size, {W::integer(),H::integer()}} | -%% {style, integer()} | -%% {validator, wx:wx()} | -%% {onGetItemText, OnGetItemText} | -%% {onGetItemAttr, OnGetItemAttr} | -%% {onGetItemColumnImage, OnGetItemColumnImage} +%% @doc Creates a listctrl with optional callback functions: %% -%% OnGetItemText = (This, Item, Column) -> wxString() -%% OnGetItemAttr = (This, Item) -> wxListItemAttr() +%% OnGetItemText = (This, Item, Column) -> unicode:charlist() +%% OnGetItemAttr = (This, Item) -> wxListItemAttr:wxListItemAttr() %% OnGetItemColumnImage = (This, Item, Column) -> integer() -%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxlistctrl.html#wxlistctrlwxlistctrl">external documentation</a>. +%% +%% See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxlistctrl.html#wxlistctrlwxlistctrl">external documentation</a>. +-spec new(Parent, [Option]) -> wxListCtrl() when + Parent::wxWindow:wxWindow(), + Option::{winid, integer()} | + {pos, {X::integer(),Y::integer()}} | + {size, {W::integer(),H::integer()}} | + {style, integer()} | + {validator, wx:wx_object()} | + {onGetItemText, function()} | + {onGetItemAttr, function()} | + {onGetItemColumnImage, function()}. new(#wx_ref{type=ParentT,ref=ParentRef}, Options) when is_list(Options)-> @@ -101,26 +104,27 @@ wxListCtrl_new_2>> <<EXPORT:Create create/2, create/3 Create:EXPORT>> <<Create -%% @spec (This::wxListCtrl(), Parent::wxWindow:wxWindow()) -> bool() %% @equiv create(This,Parent, []) +-spec create(This, Parent) -> wxListCtrl() when + This::wxWindow:wxWindow(), + Parent::wxWindow:wxWindow(). create(This,Parent) when is_record(This, wx_ref),is_record(Parent, wx_ref) -> create(This,Parent, []). -%% @spec (This::wxListCtrl(), Parent::wxWindow:wxWindow(), [Option]) -> bool() -%% Option = {winid, integer()} | -%% {pos, {X::integer(),Y::integer()}} | -%% {size, {W::integer(),H::integer()}} | -%% {style, integer()} | -%% {validator, wx:wx()} | -%% {onGetItemText, OnGetItemText} | -%% {onGetItemAttr, OnGetItemAttr} | -%% {onGetItemColumnImage, OnGetItemColumnImage} -%% -%% OnGetItemText = (This, Item, Column) -> wxString() -%% OnGetItemAttr = (This, Item) -> wxListItemAttr() -%% OnGetItemColumnImage = (This, Item, Column) -> integer() %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxlistctrl.html#wxlistctrlcreate">external documentation</a>. +-spec create(This, Parent, [Option]) -> wxListCtrl() when + This::wxWindow:wxWindow(), + Parent::wxWindow:wxWindow(), + Option::{winid, integer()} | + {pos, {X::integer(),Y::integer()}} | + {size, {W::integer(),H::integer()}} | + {style, integer()} | + {validator, wx:wx_object()} | + {onGetItemText, function()} | + {onGetItemAttr, function()} | + {onGetItemColumnImage, function()}. + create(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=ParentT,ref=ParentRef}, Options) when is_list(Options) -> ?CLASS(ThisT,wxListCtrl), diff --git a/lib/wx/api_gen/wx_extra/wxXmlResource.erl b/lib/wx/api_gen/wx_extra/wxXmlResource.erl index 7700e2333e..b29ffba7c6 100644 --- a/lib/wx/api_gen/wx_extra/wxXmlResource.erl +++ b/lib/wx/api_gen/wx_extra/wxXmlResource.erl @@ -21,8 +21,6 @@ <<EXPORT:xrcctrl xrcctrl/3 xrcctrl:EXPORT>> <<xrcctrl -%% @spec (Window::wxWindow:wxWindow(),Name::string(), Type::atom()) -> wx:wxObject() - %% @doc Looks up a control with Name in a window created with XML %% resources. You can use it to set/get values from controls. %% The object is type casted to <b>Type</b>. @@ -32,6 +30,10 @@ %% true = wxXmlResource:loadDialog(Xrc, Dlg, Frame, "controls_dialog"), <br /> %% LCtrl = xrcctrl(Dlg, "controls_listctrl", wxListCtrl), <br /> %% wxListCtrl:insertColumn(LCtrl, 0, "Name", [{width, 200}]), <br /> +-spec xrcctrl(Window, Name, Type) -> wx:wx_object() when + Window::wxWindow:wxWindow(), + Name::string(), + Type::atom(). xrcctrl(Window = #wx_ref{}, Name, Type) when is_list(Name), is_atom(Type) -> %% Func Id ~s diff --git a/lib/wx/c_src/wxe_main.cpp b/lib/wx/c_src/wxe_main.cpp index 6fcde42eb5..c7565e33bd 100644 --- a/lib/wx/c_src/wxe_main.cpp +++ b/lib/wx/c_src/wxe_main.cpp @@ -67,6 +67,7 @@ int load_native_gui() int start_native_gui(wxe_data *sd) { int res; + ErlDrvThreadOpts *opts = NULL; wxe_status_m = erl_drv_mutex_create((char *) "wxe_status_m"); wxe_status_c = erl_drv_cond_create((char *)"wxe_status_c"); @@ -78,8 +79,11 @@ int start_native_gui(wxe_data *sd) res = erl_drv_steal_main_thread((char *)"wxwidgets", &wxe_thread,wxe_main_loop,(void *) sd->pdl,NULL); #else + opts = erl_drv_thread_opts_create((char *)"wx thread"); + opts->suggested_stack_size = 8192; res = erl_drv_thread_create((char *)"wxwidgets", - &wxe_thread,wxe_main_loop,(void *) sd->pdl,NULL); + &wxe_thread,wxe_main_loop,(void *) sd->pdl,opts); + erl_drv_thread_opts_destroy(opts); #endif if(res == 0) { erl_drv_mutex_lock(wxe_status_m); diff --git a/lib/wx/include/wx.hrl b/lib/wx/include/wx.hrl index af7cca7ed2..30baeebb18 100644 --- a/lib/wx/include/wx.hrl +++ b/lib/wx/include/wx.hrl @@ -33,94 +33,51 @@ %% Here comes the definitions of all event records. %% they contain the event type and possible some extra information. --record(wxInitDialog, {type :: wxInitDialogEventType()}). %% Callback event: {@link wxInitDialogEvent} --type wxInitDialogEventType() :: 'init_dialog'. --type wxInitDialog() :: #wxInitDialog{}. %% Callback event: {@link wxInitDialogEvent} - --record(wxClose, {type :: wxCloseEventType()}). %% Callback event: {@link wxCloseEvent} --type wxCloseEventType() :: 'close_window' | 'end_session' | 'query_end_session'. --type wxClose() :: #wxClose{}. %% Callback event: {@link wxCloseEvent} - --record(wxStyledText,{type :: wxStyledTextEventType(), %% Callback event: {@link wxStyledTextEvent} - position :: integer(), - key :: integer(), - modifiers :: integer(), - modificationType :: integer(), - text :: unicode:chardata(), - length :: integer(), - linesAdded :: integer(), - line :: integer(), - foldLevelNow :: integer(), - foldLevelPrev :: integer(), - margin :: integer(), - message :: integer(), - wParam :: integer(), - lParam :: integer(), - listType :: integer(), - x :: integer(), - y :: integer(), - dragText :: unicode:chardata(), - dragAllowMove :: boolean(), - dragResult :: wx:wx_enum()}). --type wxStyledTextEventType() :: 'stc_change' | 'stc_styleneeded' | 'stc_charadded' | 'stc_savepointreached' | 'stc_savepointleft' | 'stc_romodifyattempt' | 'stc_key' | 'stc_doubleclick' | 'stc_updateui' | 'stc_modified' | 'stc_macrorecord' | 'stc_marginclick' | 'stc_needshown' | 'stc_painted' | 'stc_userlistselection' | 'stc_uridropped' | 'stc_dwellstart' | 'stc_dwellend' | 'stc_start_drag' | 'stc_drag_over' | 'stc_do_drop' | 'stc_zoom' | 'stc_hotspot_click' | 'stc_hotspot_dclick' | 'stc_calltip_click' | 'stc_autocomp_selection'. --type wxStyledText() :: #wxStyledText{}. %% Callback event: {@link wxStyledTextEvent} - --record(wxFileDirPicker,{type :: wxFileDirPickerEventType(), %% Callback event: {@link wxFileDirPickerEvent} - path :: unicode:chardata()}). --type wxFileDirPickerEventType() :: 'command_filepicker_changed' | 'command_dirpicker_changed'. --type wxFileDirPicker() :: #wxFileDirPicker{}. %% Callback event: {@link wxFileDirPickerEvent} - --record(wxNotebook,{type :: wxNotebookEventType(), %% Callback event: {@link wxNotebookEvent} - nSel :: integer(), - nOldSel :: integer()}). --type wxNotebookEventType() :: 'command_notebook_page_changed' | 'command_notebook_page_changing'. --type wxNotebook() :: #wxNotebook{}. %% Callback event: {@link wxNotebookEvent} +-record(wxFocus,{type :: wxFocusEventType(), %% Callback event: {@link wxFocusEvent} + win :: wxWindow:wxWindow()}). +-type wxFocusEventType() :: 'set_focus' | 'kill_focus'. +-type wxFocus() :: #wxFocus{}. %% Callback event: {@link wxFocusEvent} --record(wxIdle, {type :: wxIdleEventType()}). %% Callback event: {@link wxIdleEvent} --type wxIdleEventType() :: 'idle'. --type wxIdle() :: #wxIdle{}. %% Callback event: {@link wxIdleEvent} +-record(wxCommand,{type :: wxCommandEventType(), %% Callback event: {@link wxCommandEvent} + cmdString :: unicode:chardata(), + commandInt :: integer(), + extraLong :: integer()}). +-type wxCommandEventType() :: 'command_button_clicked' | 'command_checkbox_clicked' | 'command_choice_selected' | 'command_listbox_selected' | 'command_listbox_doubleclicked' | 'command_text_updated' | 'command_text_enter' | 'command_menu_selected' | 'command_slider_updated' | 'command_radiobox_selected' | 'command_radiobutton_selected' | 'command_scrollbar_updated' | 'command_vlbox_selected' | 'command_combobox_selected' | 'command_tool_rclicked' | 'command_tool_enter' | 'command_checklistbox_toggled' | 'command_togglebutton_clicked' | 'command_left_click' | 'command_left_dclick' | 'command_right_click' | 'command_set_focus' | 'command_kill_focus' | 'command_enter'. +-type wxCommand() :: #wxCommand{}. %% Callback event: {@link wxCommandEvent} -record(wxColourPicker,{type :: wxColourPickerEventType(), %% Callback event: {@link wxColourPickerEvent} colour :: wx:wx_colour()}). -type wxColourPickerEventType() :: 'command_colourpicker_changed'. -type wxColourPicker() :: #wxColourPicker{}. %% Callback event: {@link wxColourPickerEvent} --record(wxSplitter, {type :: wxSplitterEventType()}). %% Callback event: {@link wxSplitterEvent} --type wxSplitterEventType() :: 'command_splitter_sash_pos_changed' | 'command_splitter_sash_pos_changing' | 'command_splitter_doubleclicked' | 'command_splitter_unsplit'. --type wxSplitter() :: #wxSplitter{}. %% Callback event: {@link wxSplitterEvent} - --record(wxSash,{type :: wxSashEventType(), %% Callback event: {@link wxSashEvent} - edge :: wx:wx_enum(), - dragRect :: {X::integer(), Y::integer(), W::integer(), H::integer()}, - dragStatus :: wx:wx_enum()}). --type wxSashEventType() :: 'sash_dragged'. --type wxSash() :: #wxSash{}. %% Callback event: {@link wxSashEvent} - -record(wxHelp, {type :: wxHelpEventType()}). %% Callback event: {@link wxHelpEvent} -type wxHelpEventType() :: 'help' | 'detailed_help'. -type wxHelp() :: #wxHelp{}. %% Callback event: {@link wxHelpEvent} --record(wxDisplayChanged, {type :: wxDisplayChangedEventType()}). %% Callback event: {@link wxDisplayChangedEvent} --type wxDisplayChangedEventType() :: 'display_changed'. --type wxDisplayChanged() :: #wxDisplayChanged{}. %% Callback event: {@link wxDisplayChangedEvent} - --record(wxMouseCaptureLost, {type :: wxMouseCaptureLostEventType()}). %% Callback event: {@link wxMouseCaptureLostEvent} --type wxMouseCaptureLostEventType() :: 'mouse_capture_lost'. --type wxMouseCaptureLost() :: #wxMouseCaptureLost{}. %% Callback event: {@link wxMouseCaptureLostEvent} +-record(wxSpin,{type :: wxSpinEventType(), %% Callback event: {@link wxSpinEvent} + commandInt :: integer()}). +-type wxSpinEventType() :: 'command_spinctrl_updated' | 'spin_up' | 'spin_down' | 'spin'. +-type wxSpin() :: #wxSpin{}. %% Callback event: {@link wxSpinEvent} --record(wxFontPicker,{type :: wxFontPickerEventType(), %% Callback event: {@link wxFontPickerEvent} - font :: wxFont:wxFont()}). --type wxFontPickerEventType() :: 'command_fontpicker_changed'. --type wxFontPicker() :: #wxFontPicker{}. %% Callback event: {@link wxFontPickerEvent} +-record(wxAuiManager,{type :: wxAuiManagerEventType(), %% Callback event: {@link wxAuiManagerEvent} + manager :: wxAuiManager:wxAuiManager(), + pane :: wxAuiPaneInfo:wxAuiPaneInfo(), + button :: integer(), + veto_flag :: boolean(), + canveto_flag :: boolean(), + dc :: wxDC:wxDC()}). +-type wxAuiManagerEventType() :: 'aui_pane_button' | 'aui_pane_close' | 'aui_pane_maximize' | 'aui_pane_restore' | 'aui_pane_activated' | 'aui_render' | 'aui_find_manager'. +-type wxAuiManager() :: #wxAuiManager{}. %% Callback event: {@link wxAuiManagerEvent} --record(wxFocus,{type :: wxFocusEventType(), %% Callback event: {@link wxFocusEvent} - win :: wxWindow:wxWindow()}). --type wxFocusEventType() :: 'set_focus' | 'kill_focus'. --type wxFocus() :: #wxFocus{}. %% Callback event: {@link wxFocusEvent} +-record(wxDate,{type :: wxDateEventType(), %% Callback event: {@link wxDateEvent} + date :: wx:wx_datetime()}). +-type wxDateEventType() :: 'date_changed'. +-type wxDate() :: #wxDate{}. %% Callback event: {@link wxDateEvent} --record(wxPaletteChanged, {type :: wxPaletteChangedEventType()}). %% Callback event: {@link wxPaletteChangedEvent} --type wxPaletteChangedEventType() :: 'palette_changed'. --type wxPaletteChanged() :: #wxPaletteChanged{}. %% Callback event: {@link wxPaletteChangedEvent} +-record(wxIconize,{type :: wxIconizeEventType(), %% Callback event: {@link wxIconizeEvent} + iconized :: boolean()}). +-type wxIconizeEventType() :: 'iconize'. +-type wxIconize() :: #wxIconize{}. %% Callback event: {@link wxIconizeEvent} -record(wxScroll,{type :: wxScrollEventType(), %% Callback event: {@link wxScrollEvent} commandInt :: integer(), @@ -128,38 +85,41 @@ -type wxScrollEventType() :: 'scroll_top' | 'scroll_bottom' | 'scroll_lineup' | 'scroll_linedown' | 'scroll_pageup' | 'scroll_pagedown' | 'scroll_thumbtrack' | 'scroll_thumbrelease' | 'scroll_changed'. -type wxScroll() :: #wxScroll{}. %% Callback event: {@link wxScrollEvent} --record(wxChildFocus, {type :: wxChildFocusEventType()}). %% Callback event: {@link wxChildFocusEvent} --type wxChildFocusEventType() :: 'child_focus'. --type wxChildFocus() :: #wxChildFocus{}. %% Callback event: {@link wxChildFocusEvent} +-record(wxSplitter, {type :: wxSplitterEventType()}). %% Callback event: {@link wxSplitterEvent} +-type wxSplitterEventType() :: 'command_splitter_sash_pos_changed' | 'command_splitter_sash_pos_changing' | 'command_splitter_doubleclicked' | 'command_splitter_unsplit'. +-type wxSplitter() :: #wxSplitter{}. %% Callback event: {@link wxSplitterEvent} --record(wxAuiNotebook,{type :: wxAuiNotebookEventType(), %% Callback event: {@link wxAuiNotebookEvent} - old_selection :: integer(), - selection :: integer(), - drag_source :: wxAuiNotebook:wxAuiNotebook()}). --type wxAuiNotebookEventType() :: 'command_auinotebook_page_close' | 'command_auinotebook_page_changed' | 'command_auinotebook_page_changing' | 'command_auinotebook_button' | 'command_auinotebook_begin_drag' | 'command_auinotebook_end_drag' | 'command_auinotebook_drag_motion' | 'command_auinotebook_allow_dnd' | 'command_auinotebook_tab_middle_down' | 'command_auinotebook_tab_middle_up' | 'command_auinotebook_tab_right_down' | 'command_auinotebook_tab_right_up' | 'command_auinotebook_page_closed' | 'command_auinotebook_drag_done' | 'command_auinotebook_bg_dclick'. --type wxAuiNotebook() :: #wxAuiNotebook{}. %% Callback event: {@link wxAuiNotebookEvent} +-record(wxPaletteChanged, {type :: wxPaletteChangedEventType()}). %% Callback event: {@link wxPaletteChangedEvent} +-type wxPaletteChangedEventType() :: 'palette_changed'. +-type wxPaletteChanged() :: #wxPaletteChanged{}. %% Callback event: {@link wxPaletteChangedEvent} --record(wxSize,{type :: wxSizeEventType(), %% Callback event: {@link wxSizeEvent} - size :: {W::integer(), H::integer()}, - rect :: {X::integer(), Y::integer(), W::integer(), H::integer()}}). --type wxSizeEventType() :: 'size'. --type wxSize() :: #wxSize{}. %% Callback event: {@link wxSizeEvent} +-record(wxNotebook,{type :: wxNotebookEventType(), %% Callback event: {@link wxNotebookEvent} + nSel :: integer(), + nOldSel :: integer()}). +-type wxNotebookEventType() :: 'command_notebook_page_changed' | 'command_notebook_page_changing'. +-type wxNotebook() :: #wxNotebook{}. %% Callback event: {@link wxNotebookEvent} --record(wxCommand,{type :: wxCommandEventType(), %% Callback event: {@link wxCommandEvent} - cmdString :: unicode:chardata(), - commandInt :: integer(), - extraLong :: integer()}). --type wxCommandEventType() :: 'command_button_clicked' | 'command_checkbox_clicked' | 'command_choice_selected' | 'command_listbox_selected' | 'command_listbox_doubleclicked' | 'command_text_updated' | 'command_text_enter' | 'command_menu_selected' | 'command_slider_updated' | 'command_radiobox_selected' | 'command_radiobutton_selected' | 'command_scrollbar_updated' | 'command_vlbox_selected' | 'command_combobox_selected' | 'command_tool_rclicked' | 'command_tool_enter' | 'command_checklistbox_toggled' | 'command_togglebutton_clicked' | 'command_left_click' | 'command_left_dclick' | 'command_right_click' | 'command_set_focus' | 'command_kill_focus' | 'command_enter'. --type wxCommand() :: #wxCommand{}. %% Callback event: {@link wxCommandEvent} +-record(wxContextMenu,{type :: wxContextMenuEventType(), %% Callback event: {@link wxContextMenuEvent} + pos :: {X::integer(), Y::integer()}}). +-type wxContextMenuEventType() :: 'context_menu'. +-type wxContextMenu() :: #wxContextMenu{}. %% Callback event: {@link wxContextMenuEvent} --record(wxMaximize, {type :: wxMaximizeEventType()}). %% Callback event: {@link wxMaximizeEvent} --type wxMaximizeEventType() :: 'maximize'. --type wxMaximize() :: #wxMaximize{}. %% Callback event: {@link wxMaximizeEvent} +-record(wxFontPicker,{type :: wxFontPickerEventType(), %% Callback event: {@link wxFontPickerEvent} + font :: wxFont:wxFont()}). +-type wxFontPickerEventType() :: 'command_fontpicker_changed'. +-type wxFontPicker() :: #wxFontPicker{}. %% Callback event: {@link wxFontPickerEvent} --record(wxSpin,{type :: wxSpinEventType(), %% Callback event: {@link wxSpinEvent} - commandInt :: integer()}). --type wxSpinEventType() :: 'command_spinctrl_updated' | 'spin_up' | 'spin_down' | 'spin'. --type wxSpin() :: #wxSpin{}. %% Callback event: {@link wxSpinEvent} +-record(wxChildFocus, {type :: wxChildFocusEventType()}). %% Callback event: {@link wxChildFocusEvent} +-type wxChildFocusEventType() :: 'child_focus'. +-type wxChildFocus() :: #wxChildFocus{}. %% Callback event: {@link wxChildFocusEvent} + +-record(wxTaskBarIcon, {type :: wxTaskBarIconEventType()}). %% Callback event: {@link wxTaskBarIconEvent} +-type wxTaskBarIconEventType() :: 'taskbar_move' | 'taskbar_left_down' | 'taskbar_left_up' | 'taskbar_right_down' | 'taskbar_right_up' | 'taskbar_left_dclick' | 'taskbar_right_dclick'. +-type wxTaskBarIcon() :: #wxTaskBarIcon{}. %% Callback event: {@link wxTaskBarIconEvent} + +-record(wxWindowDestroy, {type :: wxWindowDestroyEventType()}). %% Callback event: {@link wxWindowDestroyEvent} +-type wxWindowDestroyEventType() :: 'destroy'. +-type wxWindowDestroy() :: #wxWindowDestroy{}. %% Callback event: {@link wxWindowDestroyEvent} -record(wxMenu,{type :: wxMenuEventType(), %% Callback event: {@link wxMenuEvent} menuId :: integer(), @@ -167,30 +127,63 @@ -type wxMenuEventType() :: 'menu_open' | 'menu_close' | 'menu_highlight'. -type wxMenu() :: #wxMenu{}. %% Callback event: {@link wxMenuEvent} +-record(wxActivate,{type :: wxActivateEventType(), %% Callback event: {@link wxActivateEvent} + active :: boolean()}). +-type wxActivateEventType() :: 'activate' | 'activate_app' | 'hibernate'. +-type wxActivate() :: #wxActivate{}. %% Callback event: {@link wxActivateEvent} + +-record(wxGrid,{type :: wxGridEventType(), %% Callback event: {@link wxGridEvent} + row :: integer(), + col :: integer(), + x :: integer(), + y :: integer(), + selecting :: boolean(), + control :: boolean(), + meta :: boolean(), + shift :: boolean(), + alt :: boolean()}). +-type wxGridEventType() :: 'grid_cell_left_click' | 'grid_cell_right_click' | 'grid_cell_left_dclick' | 'grid_cell_right_dclick' | 'grid_label_left_click' | 'grid_label_right_click' | 'grid_label_left_dclick' | 'grid_label_right_dclick' | 'grid_row_size' | 'grid_col_size' | 'grid_range_select' | 'grid_cell_change' | 'grid_select_cell' | 'grid_editor_shown' | 'grid_editor_hidden' | 'grid_editor_created' | 'grid_cell_begin_drag'. +-type wxGrid() :: #wxGrid{}. %% Callback event: {@link wxGridEvent} + +-record(wxPaint, {type :: wxPaintEventType()}). %% Callback event: {@link wxPaintEvent} +-type wxPaintEventType() :: 'paint'. +-type wxPaint() :: #wxPaint{}. %% Callback event: {@link wxPaintEvent} + -record(wxShow,{type :: wxShowEventType(), %% Callback event: {@link wxShowEvent} show :: boolean()}). -type wxShowEventType() :: 'show'. -type wxShow() :: #wxShow{}. %% Callback event: {@link wxShowEvent} --record(wxWindowDestroy, {type :: wxWindowDestroyEventType()}). %% Callback event: {@link wxWindowDestroyEvent} --type wxWindowDestroyEventType() :: 'destroy'. --type wxWindowDestroy() :: #wxWindowDestroy{}. %% Callback event: {@link wxWindowDestroyEvent} - --record(wxContextMenu,{type :: wxContextMenuEventType(), %% Callback event: {@link wxContextMenuEvent} - pos :: {X::integer(), Y::integer()}}). --type wxContextMenuEventType() :: 'context_menu'. --type wxContextMenu() :: #wxContextMenu{}. %% Callback event: {@link wxContextMenuEvent} - --record(wxActivate,{type :: wxActivateEventType(), %% Callback event: {@link wxActivateEvent} - active :: boolean()}). --type wxActivateEventType() :: 'activate' | 'activate_app' | 'hibernate'. --type wxActivate() :: #wxActivate{}. %% Callback event: {@link wxActivateEvent} +-record(wxStyledText,{type :: wxStyledTextEventType(), %% Callback event: {@link wxStyledTextEvent} + position :: integer(), + key :: integer(), + modifiers :: integer(), + modificationType :: integer(), + text :: unicode:chardata(), + length :: integer(), + linesAdded :: integer(), + line :: integer(), + foldLevelNow :: integer(), + foldLevelPrev :: integer(), + margin :: integer(), + message :: integer(), + wParam :: integer(), + lParam :: integer(), + listType :: integer(), + x :: integer(), + y :: integer(), + dragText :: unicode:chardata(), + dragAllowMove :: boolean(), + dragResult :: wx:wx_enum()}). +-type wxStyledTextEventType() :: 'stc_change' | 'stc_styleneeded' | 'stc_charadded' | 'stc_savepointreached' | 'stc_savepointleft' | 'stc_romodifyattempt' | 'stc_key' | 'stc_doubleclick' | 'stc_updateui' | 'stc_modified' | 'stc_macrorecord' | 'stc_marginclick' | 'stc_needshown' | 'stc_painted' | 'stc_userlistselection' | 'stc_uridropped' | 'stc_dwellstart' | 'stc_dwellend' | 'stc_start_drag' | 'stc_drag_over' | 'stc_do_drop' | 'stc_zoom' | 'stc_hotspot_click' | 'stc_hotspot_dclick' | 'stc_calltip_click' | 'stc_autocomp_selection'. +-type wxStyledText() :: #wxStyledText{}. %% Callback event: {@link wxStyledTextEvent} --record(wxMove,{type :: wxMoveEventType(), %% Callback event: {@link wxMoveEvent} - pos :: {X::integer(), Y::integer()}, - rect :: {X::integer(), Y::integer(), W::integer(), H::integer()}}). --type wxMoveEventType() :: 'move'. --type wxMove() :: #wxMove{}. %% Callback event: {@link wxMoveEvent} +-record(wxAuiNotebook,{type :: wxAuiNotebookEventType(), %% Callback event: {@link wxAuiNotebookEvent} + old_selection :: integer(), + selection :: integer(), + drag_source :: wxAuiNotebook:wxAuiNotebook()}). +-type wxAuiNotebookEventType() :: 'command_auinotebook_page_close' | 'command_auinotebook_page_changed' | 'command_auinotebook_page_changing' | 'command_auinotebook_button' | 'command_auinotebook_begin_drag' | 'command_auinotebook_end_drag' | 'command_auinotebook_drag_motion' | 'command_auinotebook_allow_dnd' | 'command_auinotebook_tab_middle_down' | 'command_auinotebook_tab_middle_up' | 'command_auinotebook_tab_right_down' | 'command_auinotebook_tab_right_up' | 'command_auinotebook_page_closed' | 'command_auinotebook_drag_done' | 'command_auinotebook_bg_dclick'. +-type wxAuiNotebook() :: #wxAuiNotebook{}. %% Callback event: {@link wxAuiNotebookEvent} -record(wxList,{type :: wxListEventType(), %% Callback event: {@link wxListEvent} code :: integer(), @@ -201,9 +194,9 @@ -type wxListEventType() :: 'command_list_begin_drag' | 'command_list_begin_rdrag' | 'command_list_begin_label_edit' | 'command_list_end_label_edit' | 'command_list_delete_item' | 'command_list_delete_all_items' | 'command_list_key_down' | 'command_list_insert_item' | 'command_list_col_click' | 'command_list_col_right_click' | 'command_list_col_begin_drag' | 'command_list_col_dragging' | 'command_list_col_end_drag' | 'command_list_item_selected' | 'command_list_item_deselected' | 'command_list_item_right_click' | 'command_list_item_middle_click' | 'command_list_item_activated' | 'command_list_item_focused' | 'command_list_cache_hint'. -type wxList() :: #wxList{}. %% Callback event: {@link wxListEvent} --record(wxClipboardText, {type :: wxClipboardTextEventType()}). %% Callback event: {@link wxClipboardTextEvent} --type wxClipboardTextEventType() :: 'command_text_copy' | 'command_text_cut' | 'command_text_paste'. --type wxClipboardText() :: #wxClipboardText{}. %% Callback event: {@link wxClipboardTextEvent} +-record(wxUpdateUI, {type :: wxUpdateUIEventType()}). %% Callback event: {@link wxUpdateUIEvent} +-type wxUpdateUIEventType() :: 'update_ui'. +-type wxUpdateUI() :: #wxUpdateUI{}. %% Callback event: {@link wxUpdateUIEvent} -record(wxScrollWin,{type :: wxScrollWinEventType(), %% Callback event: {@link wxScrollWinEvent} commandInt :: integer(), @@ -211,92 +204,81 @@ -type wxScrollWinEventType() :: 'scrollwin_top' | 'scrollwin_bottom' | 'scrollwin_lineup' | 'scrollwin_linedown' | 'scrollwin_pageup' | 'scrollwin_pagedown' | 'scrollwin_thumbtrack' | 'scrollwin_thumbrelease'. -type wxScrollWin() :: #wxScrollWin{}. %% Callback event: {@link wxScrollWinEvent} --record(wxIconize,{type :: wxIconizeEventType(), %% Callback event: {@link wxIconizeEvent} - iconized :: boolean()}). --type wxIconizeEventType() :: 'iconize'. --type wxIconize() :: #wxIconize{}. %% Callback event: {@link wxIconizeEvent} +-record(wxJoystick,{type :: wxJoystickEventType(), %% Callback event: {@link wxJoystickEvent} + pos :: {X::integer(), Y::integer()}, + zPosition :: integer(), + buttonChange :: integer(), + buttonState :: integer(), + joyStick :: integer()}). +-type wxJoystickEventType() :: 'joy_button_down' | 'joy_button_up' | 'joy_move' | 'joy_zmove'. +-type wxJoystick() :: #wxJoystick{}. %% Callback event: {@link wxJoystickEvent} --record(wxUpdateUI, {type :: wxUpdateUIEventType()}). %% Callback event: {@link wxUpdateUIEvent} --type wxUpdateUIEventType() :: 'update_ui'. --type wxUpdateUI() :: #wxUpdateUI{}. %% Callback event: {@link wxUpdateUIEvent} +-record(wxWindowCreate, {type :: wxWindowCreateEventType()}). %% Callback event: {@link wxWindowCreateEvent} +-type wxWindowCreateEventType() :: 'create'. +-type wxWindowCreate() :: #wxWindowCreate{}. %% Callback event: {@link wxWindowCreateEvent} --record(wxMouse,{type :: wxMouseEventType(), %% Callback event: {@link wxMouseEvent} +-record(wxClose, {type :: wxCloseEventType()}). %% Callback event: {@link wxCloseEvent} +-type wxCloseEventType() :: 'close_window' | 'end_session' | 'query_end_session'. +-type wxClose() :: #wxClose{}. %% Callback event: {@link wxCloseEvent} + +-record(wxKey,{type :: wxKeyEventType(), %% Callback event: {@link wxKeyEvent} x :: integer(), y :: integer(), - leftDown :: boolean(), - middleDown :: boolean(), - rightDown :: boolean(), + keyCode :: integer(), controlDown :: boolean(), shiftDown :: boolean(), altDown :: boolean(), metaDown :: boolean(), - wheelRotation :: integer(), - wheelDelta :: integer(), - linesPerAction :: integer()}). --type wxMouseEventType() :: 'left_down' | 'left_up' | 'middle_down' | 'middle_up' | 'right_down' | 'right_up' | 'motion' | 'enter_window' | 'leave_window' | 'left_dclick' | 'middle_dclick' | 'right_dclick' | 'mousewheel'. --type wxMouse() :: #wxMouse{}. %% Callback event: {@link wxMouseEvent} - --record(wxTree,{type :: wxTreeEventType(), %% Callback event: {@link wxTreeEvent} - item :: integer(), - itemOld :: integer(), - pointDrag :: {X::integer(), Y::integer()}}). --type wxTreeEventType() :: 'command_tree_begin_drag' | 'command_tree_begin_rdrag' | 'command_tree_begin_label_edit' | 'command_tree_end_label_edit' | 'command_tree_delete_item' | 'command_tree_get_info' | 'command_tree_set_info' | 'command_tree_item_expanded' | 'command_tree_item_expanding' | 'command_tree_item_collapsed' | 'command_tree_item_collapsing' | 'command_tree_sel_changed' | 'command_tree_sel_changing' | 'command_tree_key_down' | 'command_tree_item_activated' | 'command_tree_item_right_click' | 'command_tree_item_middle_click' | 'command_tree_end_drag' | 'command_tree_state_image_click' | 'command_tree_item_gettooltip' | 'command_tree_item_menu'. --type wxTree() :: #wxTree{}. %% Callback event: {@link wxTreeEvent} - --record(wxSysColourChanged, {type :: wxSysColourChangedEventType()}). %% Callback event: {@link wxSysColourChangedEvent} --type wxSysColourChangedEventType() :: 'sys_colour_changed'. --type wxSysColourChanged() :: #wxSysColourChanged{}. %% Callback event: {@link wxSysColourChangedEvent} + scanCode :: boolean(), + uniChar :: integer(), + rawCode :: integer(), + rawFlags :: integer()}). +-type wxKeyEventType() :: 'char' | 'char_hook' | 'key_down' | 'key_up'. +-type wxKey() :: #wxKey{}. %% Callback event: {@link wxKeyEvent} --record(wxNavigationKey,{type :: wxNavigationKeyEventType(), %% Callback event: {@link wxNavigationKeyEvent} - flags :: integer(), - focus :: wxWindow:wxWindow()}). --type wxNavigationKeyEventType() :: 'navigation_key'. --type wxNavigationKey() :: #wxNavigationKey{}. %% Callback event: {@link wxNavigationKeyEvent} +-record(wxIdle, {type :: wxIdleEventType()}). %% Callback event: {@link wxIdleEvent} +-type wxIdleEventType() :: 'idle'. +-type wxIdle() :: #wxIdle{}. %% Callback event: {@link wxIdleEvent} -record(wxQueryNewPalette, {type :: wxQueryNewPaletteEventType()}). %% Callback event: {@link wxQueryNewPaletteEvent} -type wxQueryNewPaletteEventType() :: 'query_new_palette'. -type wxQueryNewPalette() :: #wxQueryNewPalette{}. %% Callback event: {@link wxQueryNewPaletteEvent} --record(wxMouseCaptureChanged, {type :: wxMouseCaptureChangedEventType()}). %% Callback event: {@link wxMouseCaptureChangedEvent} --type wxMouseCaptureChangedEventType() :: 'mouse_capture_changed'. --type wxMouseCaptureChanged() :: #wxMouseCaptureChanged{}. %% Callback event: {@link wxMouseCaptureChangedEvent} - -record(wxHtmlLink,{type :: wxHtmlLinkEventType(), %% Callback event: {@link wxHtmlLinkEvent} linkInfo :: wx:wx_wxHtmlLinkInfo()}). -type wxHtmlLinkEventType() :: 'command_html_link_clicked'. -type wxHtmlLink() :: #wxHtmlLink{}. %% Callback event: {@link wxHtmlLinkEvent} --record(wxKey,{type :: wxKeyEventType(), %% Callback event: {@link wxKeyEvent} - x :: integer(), - y :: integer(), - keyCode :: integer(), - controlDown :: boolean(), - shiftDown :: boolean(), - altDown :: boolean(), - metaDown :: boolean(), - scanCode :: boolean(), - uniChar :: integer(), - rawCode :: integer(), - rawFlags :: integer()}). --type wxKeyEventType() :: 'char' | 'char_hook' | 'key_down' | 'key_up'. --type wxKey() :: #wxKey{}. %% Callback event: {@link wxKeyEvent} +-record(wxInitDialog, {type :: wxInitDialogEventType()}). %% Callback event: {@link wxInitDialogEvent} +-type wxInitDialogEventType() :: 'init_dialog'. +-type wxInitDialog() :: #wxInitDialog{}. %% Callback event: {@link wxInitDialogEvent} --record(wxTaskBarIcon, {type :: wxTaskBarIconEventType()}). %% Callback event: {@link wxTaskBarIconEvent} --type wxTaskBarIconEventType() :: 'taskbar_move' | 'taskbar_left_down' | 'taskbar_left_up' | 'taskbar_right_down' | 'taskbar_right_up' | 'taskbar_left_dclick' | 'taskbar_right_dclick'. --type wxTaskBarIcon() :: #wxTaskBarIcon{}. %% Callback event: {@link wxTaskBarIconEvent} +-record(wxMaximize, {type :: wxMaximizeEventType()}). %% Callback event: {@link wxMaximizeEvent} +-type wxMaximizeEventType() :: 'maximize'. +-type wxMaximize() :: #wxMaximize{}. %% Callback event: {@link wxMaximizeEvent} --record(wxGrid,{type :: wxGridEventType(), %% Callback event: {@link wxGridEvent} - row :: integer(), - col :: integer(), - x :: integer(), - y :: integer(), - selecting :: boolean(), - control :: boolean(), - meta :: boolean(), - shift :: boolean(), - alt :: boolean()}). --type wxGridEventType() :: 'grid_cell_left_click' | 'grid_cell_right_click' | 'grid_cell_left_dclick' | 'grid_cell_right_dclick' | 'grid_label_left_click' | 'grid_label_right_click' | 'grid_label_left_dclick' | 'grid_label_right_dclick' | 'grid_row_size' | 'grid_col_size' | 'grid_range_select' | 'grid_cell_change' | 'grid_select_cell' | 'grid_editor_shown' | 'grid_editor_hidden' | 'grid_editor_created' | 'grid_cell_begin_drag'. --type wxGrid() :: #wxGrid{}. %% Callback event: {@link wxGridEvent} +-record(wxClipboardText, {type :: wxClipboardTextEventType()}). %% Callback event: {@link wxClipboardTextEvent} +-type wxClipboardTextEventType() :: 'command_text_copy' | 'command_text_cut' | 'command_text_paste'. +-type wxClipboardText() :: #wxClipboardText{}. %% Callback event: {@link wxClipboardTextEvent} + +-record(wxTree,{type :: wxTreeEventType(), %% Callback event: {@link wxTreeEvent} + item :: integer(), + itemOld :: integer(), + pointDrag :: {X::integer(), Y::integer()}}). +-type wxTreeEventType() :: 'command_tree_begin_drag' | 'command_tree_begin_rdrag' | 'command_tree_begin_label_edit' | 'command_tree_end_label_edit' | 'command_tree_delete_item' | 'command_tree_get_info' | 'command_tree_set_info' | 'command_tree_item_expanded' | 'command_tree_item_expanding' | 'command_tree_item_collapsed' | 'command_tree_item_collapsing' | 'command_tree_sel_changed' | 'command_tree_sel_changing' | 'command_tree_key_down' | 'command_tree_item_activated' | 'command_tree_item_right_click' | 'command_tree_item_middle_click' | 'command_tree_end_drag' | 'command_tree_state_image_click' | 'command_tree_item_gettooltip' | 'command_tree_item_menu'. +-type wxTree() :: #wxTree{}. %% Callback event: {@link wxTreeEvent} + +-record(wxErase,{type :: wxEraseEventType(), %% Callback event: {@link wxEraseEvent} + dc :: wxDC:wxDC()}). +-type wxEraseEventType() :: 'erase_background'. +-type wxErase() :: #wxErase{}. %% Callback event: {@link wxEraseEvent} + +-record(wxSash,{type :: wxSashEventType(), %% Callback event: {@link wxSashEvent} + edge :: wx:wx_enum(), + dragRect :: {X::integer(), Y::integer(), W::integer(), H::integer()}, + dragStatus :: wx:wx_enum()}). +-type wxSashEventType() :: 'sash_dragged'. +-type wxSash() :: #wxSash{}. %% Callback event: {@link wxSashEvent} -record(wxCalendar,{type :: wxCalendarEventType(), %% Callback event: {@link wxCalendarEvent} wday :: wx:wx_enum(), @@ -304,42 +286,52 @@ -type wxCalendarEventType() :: 'calendar_sel_changed' | 'calendar_day_changed' | 'calendar_month_changed' | 'calendar_year_changed' | 'calendar_doubleclicked' | 'calendar_weekday_clicked'. -type wxCalendar() :: #wxCalendar{}. %% Callback event: {@link wxCalendarEvent} --record(wxWindowCreate, {type :: wxWindowCreateEventType()}). %% Callback event: {@link wxWindowCreateEvent} --type wxWindowCreateEventType() :: 'create'. --type wxWindowCreate() :: #wxWindowCreate{}. %% Callback event: {@link wxWindowCreateEvent} +-record(wxMouse,{type :: wxMouseEventType(), %% Callback event: {@link wxMouseEvent} + x :: integer(), + y :: integer(), + leftDown :: boolean(), + middleDown :: boolean(), + rightDown :: boolean(), + controlDown :: boolean(), + shiftDown :: boolean(), + altDown :: boolean(), + metaDown :: boolean(), + wheelRotation :: integer(), + wheelDelta :: integer(), + linesPerAction :: integer()}). +-type wxMouseEventType() :: 'left_down' | 'left_up' | 'middle_down' | 'middle_up' | 'right_down' | 'right_up' | 'motion' | 'enter_window' | 'leave_window' | 'left_dclick' | 'middle_dclick' | 'right_dclick' | 'mousewheel'. +-type wxMouse() :: #wxMouse{}. %% Callback event: {@link wxMouseEvent} --record(wxDate,{type :: wxDateEventType(), %% Callback event: {@link wxDateEvent} - date :: wx:wx_datetime()}). --type wxDateEventType() :: 'date_changed'. --type wxDate() :: #wxDate{}. %% Callback event: {@link wxDateEvent} +-record(wxSize,{type :: wxSizeEventType(), %% Callback event: {@link wxSizeEvent} + size :: {W::integer(), H::integer()}, + rect :: {X::integer(), Y::integer(), W::integer(), H::integer()}}). +-type wxSizeEventType() :: 'size'. +-type wxSize() :: #wxSize{}. %% Callback event: {@link wxSizeEvent} --record(wxAuiManager,{type :: wxAuiManagerEventType(), %% Callback event: {@link wxAuiManagerEvent} - manager :: wxAuiManager:wxAuiManager(), - pane :: wxAuiPaneInfo:wxAuiPaneInfo(), - button :: integer(), - veto_flag :: boolean(), - canveto_flag :: boolean(), - dc :: wxDC:wxDC()}). --type wxAuiManagerEventType() :: 'aui_pane_button' | 'aui_pane_close' | 'aui_pane_maximize' | 'aui_pane_restore' | 'aui_pane_activated' | 'aui_render' | 'aui_find_manager'. --type wxAuiManager() :: #wxAuiManager{}. %% Callback event: {@link wxAuiManagerEvent} +-record(wxSysColourChanged, {type :: wxSysColourChangedEventType()}). %% Callback event: {@link wxSysColourChangedEvent} +-type wxSysColourChangedEventType() :: 'sys_colour_changed'. +-type wxSysColourChanged() :: #wxSysColourChanged{}. %% Callback event: {@link wxSysColourChangedEvent} --record(wxJoystick,{type :: wxJoystickEventType(), %% Callback event: {@link wxJoystickEvent} +-record(wxDisplayChanged, {type :: wxDisplayChangedEventType()}). %% Callback event: {@link wxDisplayChangedEvent} +-type wxDisplayChangedEventType() :: 'display_changed'. +-type wxDisplayChanged() :: #wxDisplayChanged{}. %% Callback event: {@link wxDisplayChangedEvent} + +-record(wxMove,{type :: wxMoveEventType(), %% Callback event: {@link wxMoveEvent} pos :: {X::integer(), Y::integer()}, - zPosition :: integer(), - buttonChange :: integer(), - buttonState :: integer(), - joyStick :: integer()}). --type wxJoystickEventType() :: 'joy_button_down' | 'joy_button_up' | 'joy_move' | 'joy_zmove'. --type wxJoystick() :: #wxJoystick{}. %% Callback event: {@link wxJoystickEvent} + rect :: {X::integer(), Y::integer(), W::integer(), H::integer()}}). +-type wxMoveEventType() :: 'move'. +-type wxMove() :: #wxMove{}. %% Callback event: {@link wxMoveEvent} --record(wxPaint, {type :: wxPaintEventType()}). %% Callback event: {@link wxPaintEvent} --type wxPaintEventType() :: 'paint'. --type wxPaint() :: #wxPaint{}. %% Callback event: {@link wxPaintEvent} +-record(wxNavigationKey,{type :: wxNavigationKeyEventType(), %% Callback event: {@link wxNavigationKeyEvent} + flags :: integer(), + focus :: wxWindow:wxWindow()}). +-type wxNavigationKeyEventType() :: 'navigation_key'. +-type wxNavigationKey() :: #wxNavigationKey{}. %% Callback event: {@link wxNavigationKeyEvent} --record(wxErase,{type :: wxEraseEventType(), %% Callback event: {@link wxEraseEvent} - dc :: wxDC:wxDC()}). --type wxEraseEventType() :: 'erase_background'. --type wxErase() :: #wxErase{}. %% Callback event: {@link wxEraseEvent} +-record(wxFileDirPicker,{type :: wxFileDirPickerEventType(), %% Callback event: {@link wxFileDirPickerEvent} + path :: unicode:chardata()}). +-type wxFileDirPickerEventType() :: 'command_filepicker_changed' | 'command_dirpicker_changed'. +-type wxFileDirPicker() :: #wxFileDirPicker{}. %% Callback event: {@link wxFileDirPickerEvent} -record(wxSetCursor,{type :: wxSetCursorEventType(), %% Callback event: {@link wxSetCursorEvent} x :: integer(), @@ -348,6 +340,14 @@ -type wxSetCursorEventType() :: 'set_cursor'. -type wxSetCursor() :: #wxSetCursor{}. %% Callback event: {@link wxSetCursorEvent} +-record(wxMouseCaptureChanged, {type :: wxMouseCaptureChangedEventType()}). %% Callback event: {@link wxMouseCaptureChangedEvent} +-type wxMouseCaptureChangedEventType() :: 'mouse_capture_changed'. +-type wxMouseCaptureChanged() :: #wxMouseCaptureChanged{}. %% Callback event: {@link wxMouseCaptureChangedEvent} + +-record(wxMouseCaptureLost, {type :: wxMouseCaptureLostEventType()}). %% Callback event: {@link wxMouseCaptureLostEvent} +-type wxMouseCaptureLostEventType() :: 'mouse_capture_lost'. +-type wxMouseCaptureLost() :: #wxMouseCaptureLost{}. %% Callback event: {@link wxMouseCaptureLostEvent} + -type event() :: wxActivate() | wxAuiManager() | wxAuiNotebook() | wxCalendar() | wxChildFocus() | wxClipboardText() | wxClose() | wxColourPicker() | wxCommand() | wxContextMenu() | wxDate() | wxDisplayChanged() | wxErase() | wxFileDirPicker() | wxFocus() | wxFontPicker() | wxGrid() | wxHelp() | wxHtmlLink() | wxIconize() | wxIdle() | wxInitDialog() | wxJoystick() | wxKey() | wxList() | wxMaximize() | wxMenu() | wxMouse() | wxMouseCaptureChanged() | wxMouseCaptureLost() | wxMove() | wxNavigationKey() | wxNotebook() | wxPaint() | wxPaletteChanged() | wxQueryNewPalette() | wxSash() | wxScroll() | wxScrollWin() | wxSetCursor() | wxShow() | wxSize() | wxSpin() | wxSplitter() | wxStyledText() | wxSysColourChanged() | wxTaskBarIcon() | wxTree() | wxUpdateUI() | wxWindowCreate() | wxWindowDestroy(). -type wxEventType() :: wxActivateEventType() | wxAuiManagerEventType() | wxAuiNotebookEventType() | wxCalendarEventType() | wxChildFocusEventType() | wxClipboardTextEventType() | wxCloseEventType() | wxColourPickerEventType() | wxCommandEventType() | wxContextMenuEventType() | wxDateEventType() | wxDisplayChangedEventType() | wxEraseEventType() | wxFileDirPickerEventType() | wxFocusEventType() | wxFontPickerEventType() | wxGridEventType() | wxHelpEventType() | wxHtmlLinkEventType() | wxIconizeEventType() | wxIdleEventType() | wxInitDialogEventType() | wxJoystickEventType() | wxKeyEventType() | wxListEventType() | wxMaximizeEventType() | wxMenuEventType() | wxMouseCaptureChangedEventType() | wxMouseCaptureLostEventType() | wxMouseEventType() | wxMoveEventType() | wxNavigationKeyEventType() | wxNotebookEventType() | wxPaintEventType() | wxPaletteChangedEventType() | wxQueryNewPaletteEventType() | wxSashEventType() | wxScrollEventType() | wxScrollWinEventType() | wxSetCursorEventType() | wxShowEventType() | wxSizeEventType() | wxSpinEventType() | wxSplitterEventType() | wxStyledTextEventType() | wxSysColourChangedEventType() | wxTaskBarIconEventType() | wxTreeEventType() | wxUpdateUIEventType() | wxWindowCreateEventType() | wxWindowDestroyEventType(). diff --git a/lib/wx/src/gen/wxListCtrl.erl b/lib/wx/src/gen/wxListCtrl.erl index d1a063d900..851686062a 100644 --- a/lib/wx/src/gen/wxListCtrl.erl +++ b/lib/wx/src/gen/wxListCtrl.erl @@ -94,31 +94,34 @@ parent_class(_Class) -> erlang:error({badtype, ?MODULE}). -type wxListCtrl() :: wx:wx_object(). -%% @spec () -> wxListCtrl() %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxlistctrl.html#wxlistctrlwxlistctrl">external documentation</a>. +-spec new() -> wxListCtrl(). new() -> wxe_util:construct(?wxListCtrl_new_0, <<>>). -%% @spec (Parent::wxWindow:wxWindow()) -> wxListCtrl() -%% @equiv new(Parent, []) +-spec new(Parent) -> wxListCtrl() when + Parent::wxWindow:wxWindow(). new(Parent) when is_record(Parent, wx_ref) -> new(Parent, []). -%% @spec (Parent::wxWindow:wxWindow(), [Option]) -> wxListCtrl() -%% Option = {winid, integer()} | -%% {pos, {X::integer(),Y::integer()}} | -%% {size, {W::integer(),H::integer()}} | -%% {style, integer()} | -%% {validator, wx:wx()} | -%% {onGetItemText, OnGetItemText} | -%% {onGetItemAttr, OnGetItemAttr} | -%% {onGetItemColumnImage, OnGetItemColumnImage} +%% @doc Creates a listctrl with optional callback functions: %% -%% OnGetItemText = (This, Item, Column) -> wxString() -%% OnGetItemAttr = (This, Item) -> wxListItemAttr() +%% OnGetItemText = (This, Item, Column) -> unicode:charlist() +%% OnGetItemAttr = (This, Item) -> wxListItemAttr:wxListItemAttr() %% OnGetItemColumnImage = (This, Item, Column) -> integer() -%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxlistctrl.html#wxlistctrlwxlistctrl">external documentation</a>. +%% +%% See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxlistctrl.html#wxlistctrlwxlistctrl">external documentation</a>. +-spec new(Parent, [Option]) -> wxListCtrl() when + Parent::wxWindow:wxWindow(), + Option::{winid, integer()} | + {pos, {X::integer(),Y::integer()}} | + {size, {W::integer(),H::integer()}} | + {style, integer()} | + {validator, wx:wx_object()} | + {onGetItemText, function()} | + {onGetItemAttr, function()} | + {onGetItemColumnImage, function()}. new(#wx_ref{type=ParentT,ref=ParentRef}, Options) when is_list(Options)-> @@ -185,26 +188,27 @@ clearAll(#wx_ref{type=ThisT,ref=ThisRef}) -> <<ThisRef:32/?UI>>). -%% @spec (This::wxListCtrl(), Parent::wxWindow:wxWindow()) -> bool() %% @equiv create(This,Parent, []) +-spec create(This, Parent) -> wxListCtrl() when + This::wxWindow:wxWindow(), + Parent::wxWindow:wxWindow(). create(This,Parent) when is_record(This, wx_ref),is_record(Parent, wx_ref) -> create(This,Parent, []). -%% @spec (This::wxListCtrl(), Parent::wxWindow:wxWindow(), [Option]) -> bool() -%% Option = {winid, integer()} | -%% {pos, {X::integer(),Y::integer()}} | -%% {size, {W::integer(),H::integer()}} | -%% {style, integer()} | -%% {validator, wx:wx()} | -%% {onGetItemText, OnGetItemText} | -%% {onGetItemAttr, OnGetItemAttr} | -%% {onGetItemColumnImage, OnGetItemColumnImage} -%% -%% OnGetItemText = (This, Item, Column) -> wxString() -%% OnGetItemAttr = (This, Item) -> wxListItemAttr() -%% OnGetItemColumnImage = (This, Item, Column) -> integer() %% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxlistctrl.html#wxlistctrlcreate">external documentation</a>. +-spec create(This, Parent, [Option]) -> wxListCtrl() when + This::wxWindow:wxWindow(), + Parent::wxWindow:wxWindow(), + Option::{winid, integer()} | + {pos, {X::integer(),Y::integer()}} | + {size, {W::integer(),H::integer()}} | + {style, integer()} | + {validator, wx:wx_object()} | + {onGetItemText, function()} | + {onGetItemAttr, function()} | + {onGetItemColumnImage, function()}. + create(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=ParentT,ref=ParentRef}, Options) when is_list(Options) -> ?CLASS(ThisT,wxListCtrl), diff --git a/lib/wx/src/gen/wxXmlResource.erl b/lib/wx/src/gen/wxXmlResource.erl index ae02c74751..aa65b8b04e 100644 --- a/lib/wx/src/gen/wxXmlResource.erl +++ b/lib/wx/src/gen/wxXmlResource.erl @@ -334,8 +334,6 @@ unload(#wx_ref{type=ThisT,ref=ThisRef},Filename) <<ThisRef:32/?UI,(byte_size(Filename_UC)):32/?UI,(Filename_UC)/binary, 0:(((8- ((0+byte_size(Filename_UC)) band 16#7)) band 16#7))/unit:8>>). -%% @spec (Window::wxWindow:wxWindow(),Name::string(), Type::atom()) -> wx:wxObject() - %% @doc Looks up a control with Name in a window created with XML %% resources. You can use it to set/get values from controls. %% The object is type casted to <b>Type</b>. @@ -345,6 +343,10 @@ unload(#wx_ref{type=ThisT,ref=ThisRef},Filename) %% true = wxXmlResource:loadDialog(Xrc, Dlg, Frame, "controls_dialog"), <br /> %% LCtrl = xrcctrl(Dlg, "controls_listctrl", wxListCtrl), <br /> %% wxListCtrl:insertColumn(LCtrl, 0, "Name", [{width, 200}]), <br /> +-spec xrcctrl(Window, Name, Type) -> wx:wx_object() when + Window::wxWindow:wxWindow(), + Name::string(), + Type::atom(). xrcctrl(Window = #wx_ref{}, Name, Type) when is_list(Name), is_atom(Type) -> %% Func Id ?wxXmlResource_xrcctrl diff --git a/lib/wx/src/wx_object.erl b/lib/wx/src/wx_object.erl index 40ee308358..40170b6eb1 100644 --- a/lib/wx/src/wx_object.erl +++ b/lib/wx/src/wx_object.erl @@ -55,7 +55,7 @@ %% 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) %% @@ -171,58 +171,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 +237,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 +258,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 +278,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 +300,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 +312,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}. |