aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDan Gudmundsson <dgud@ubuntu.(none)>2014-02-05 20:19:41 +0100
committerDan Gudmundsson <[email protected]>2014-02-13 16:42:36 +0100
commitce28e4940a6d313db19d996ff3cece21d7372a7b (patch)
treeaed103c158692c6f471ec597d6494693637808db
parent8d71ab498974b5f0623eac50c4f94f62fc229a94 (diff)
downloadotp-ce28e4940a6d313db19d996ff3cece21d7372a7b.tar.gz
otp-ce28e4940a6d313db19d996ff3cece21d7372a7b.tar.bz2
otp-ce28e4940a6d313db19d996ff3cece21d7372a7b.zip
wx: Rewrite eventhandling again
Remove the extra wxEvtListener that only caused confusion, now everything is automatically cleaned up by the destructors and event sent to erlang when it becomes delete for all cases.
-rw-r--r--lib/wx/api_gen/Makefile4
-rw-r--r--lib/wx/api_gen/wx_extra/wxEvtHandler.c_src36
-rw-r--r--lib/wx/api_gen/wx_extra/wxEvtHandler.erl46
-rw-r--r--lib/wx/api_gen/wx_gen_cpp.erl11
-rw-r--r--lib/wx/c_src/gen/wxe_events.cpp12
-rw-r--r--lib/wx/c_src/gen/wxe_funcs.cpp36
-rw-r--r--lib/wx/c_src/wxe_callback_impl.cpp27
-rw-r--r--lib/wx/c_src/wxe_callback_impl.h18
-rw-r--r--lib/wx/c_src/wxe_events.h31
-rw-r--r--lib/wx/src/gen/wxEvtHandler.erl48
-rw-r--r--lib/wx/src/wxe.hrl5
-rw-r--r--lib/wx/src/wxe_server.erl192
-rw-r--r--lib/wx/src/wxe_util.erl33
-rw-r--r--lib/wx/test/wx_event_SUITE.erl12
14 files changed, 195 insertions, 316 deletions
diff --git a/lib/wx/api_gen/Makefile b/lib/wx/api_gen/Makefile
index 8adb485ba9..3e41ac7bc5 100644
--- a/lib/wx/api_gen/Makefile
+++ b/lib/wx/api_gen/Makefile
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2008-2012. All Rights Reserved.
+# Copyright Ericsson AB 2008-2014. All Rights Reserved.
#
# The contents of this file are subject to the Erlang Public License,
# Version 1.1, (the "License"); you may not use this file except in
@@ -60,7 +60,7 @@ $(GL): glxml_generated $(GL_COMP_T) glapi.conf
erl -noshell -run gl_gen code && touch gl_code_generated
%.beam: %.erl wx_gen.hrl gl_gen.hrl
- $(ERLC) -W $(ERL_FLAGS) $(ERL_COMPILE_FLAGS) $< -o$(EBIN)
+ $(ERLC) -W $(ERL_FLAGS) $(ERL_COMPILE_FLAGS) -o$(EBIN) $<
# TODO split cleans into separate targets?
complete_clean:
diff --git a/lib/wx/api_gen/wx_extra/wxEvtHandler.c_src b/lib/wx/api_gen/wx_extra/wxEvtHandler.c_src
index 9c5f46b253..5d20019d8f 100644
--- a/lib/wx/api_gen/wx_extra/wxEvtHandler.c_src
+++ b/lib/wx/api_gen/wx_extra/wxEvtHandler.c_src
@@ -1,17 +1,5 @@
-case 98: { // wxeEvtListener::wxeEvtListener
- wxeEvtListener *Result = new wxeEvtListener(Ecmd.port);
- rt.addRef(getRef((void *)Result,memenv), "wxeEvtListener");
- break;
-}
-case 99: { // wxeEvtListener::destroy
- wxObject *This = (wxObject *) getPtr(bp,memenv);
- rt.addAtom("ok");
- delete This;
- break;
-}
-case 100: { // wxEvtHandler::Connect
- wxeEvtListener *Listener = (wxeEvtListener *) getPtr(bp,memenv); bp += 4;
+case 100: { // wxEvtHandler::Connect
wxEvtHandler *This = (wxEvtHandler *) getPtr(bp, memenv); bp += 4;
int * winid = (int *) bp; bp += 4;
int * lastId = (int *) bp; bp += 4;
@@ -22,20 +10,22 @@ case 100: { // wxEvtHandler::Connect
int * eventTypeLen = (int *) bp; bp += 4;
int * class_nameLen = (int *) bp; bp += 4;
- if(*haveUserData) {
+ if(*haveUserData) {
userData = new wxeErlTerm(Ecmd.bin[0]);
}
int eventType = wxeEventTypeFromAtom(bp); bp += *eventTypeLen;
char *class_name = bp; bp+= *class_nameLen;
if(eventType > 0 ) {
- wxeCallbackData * Evt_cb = new wxeCallbackData(Ecmd.caller,getRef(This, memenv),
- class_name,*fun_cb,
- *skip, userData, Listener);
+ wxeEvtListener * Evt_cb = new wxeEvtListener(Ecmd.caller,getRef(This, memenv),
+ class_name,*fun_cb,
+ *skip, userData, Ecmd.port);
This->Connect((int) *winid,(int) *lastId,eventType,
(wxObjectEventFunction)(wxEventFunction) &wxeEvtListener::forward,
- Evt_cb, Listener);
+ Evt_cb, Evt_cb);
rt.addAtom("ok");
+ rt.addRef(getRef((void *)Evt_cb,memenv), "wxeEvtListener");
+ rt.addTupleCount(2);
} else {
rt.addAtom("badarg");
rt.addAtom("event_type");
@@ -43,7 +33,7 @@ case 100: { // wxEvtHandler::Connect
}
break;
}
-case 101: { // wxEvtHandler::Disconnect
+case 101: { // wxEvtHandler::Disconnect
wxeEvtListener *Listener = (wxeEvtListener *) getPtr(bp,memenv); bp += 4;
wxEvtHandler *This = (wxEvtHandler *) getPtr(bp, memenv); bp += 4;
int * winid = (int *) bp; bp += 4;
@@ -53,14 +43,14 @@ case 101: { // wxEvtHandler::Disconnect
int eventType = wxeEventTypeFromAtom(bp); bp += *eventTypeLen;
if(eventType > 0) {
bool Result = This->Disconnect((int) *winid,(int) *lastId,eventType,
- (wxObjectEventFunction)(wxEventFunction)
- &wxeEvtListener::forward,
- NULL, Listener);
+ (wxObjectEventFunction)(wxEventFunction)
+ &wxeEvtListener::forward,
+ NULL, Listener);
rt.addBool(Result);
} else {
rt.addAtom("badarg");
rt.addAtom("event_type");
- rt.addTupleCount(2);
+ rt.addTupleCount(2);
}
break;
}
diff --git a/lib/wx/api_gen/wx_extra/wxEvtHandler.erl b/lib/wx/api_gen/wx_extra/wxEvtHandler.erl
index c5802af679..c9726fd475 100644
--- a/lib/wx/api_gen/wx_extra/wxEvtHandler.erl
+++ b/lib/wx/api_gen/wx_extra/wxEvtHandler.erl
@@ -27,15 +27,11 @@
-export([connect/2, connect/3, disconnect/1, disconnect/2, disconnect/3]).
%% internal exports
--export([connect_impl/3, disconnect_impl/2, disconnect_impl/3,
- new_evt_listener/0, destroy_evt_listener/1,
- get_callback/1, replace_fun_with_id/2]).
+-export([connect_impl/2, disconnect_impl/2]).
-export_type([wxEvtHandler/0, wx/0, event/0]).
-type wxEvtHandler() :: wx:wx_object().
--record(evh, {et=null,id=?wxID_ANY,lastId=?wxID_ANY,skip=undefined,userdata=[],cb=0}).
-
%% @doc Equivalent to {@link connect/3. connect(This, EventType, [])}
-spec connect(This::wxEvtHandler(), EventType::wxEventType()) -> ok.
connect(This, EventType) ->
@@ -130,54 +126,34 @@ disconnect(This=#wx_ref{type=ThisT,ref=_ThisRef}, EventType, Opts) ->
%% @hidden
-connect_impl(#wx_ref{type=wxeEvtListener,ref=EvtList},
- #wx_ref{type=ThisT,ref=ThisRef},
- #evh{id=Winid, lastId=LastId, et=EventType,
- skip=Skip, userdata=Userdata, cb=FunID})
+connect_impl(#wx_ref{type=ThisT,ref=ThisRef},
+ #evh{id=Winid, lastId=LastId, et=EventType,
+ skip=Skip, userdata=Userdata, cb=FunID})
when is_integer(FunID)->
EventTypeBin = list_to_binary([atom_to_list(EventType)|[0]]),
ThisTypeBin = list_to_binary([atom_to_list(ThisT)|[0]]),
UD = if Userdata =:= [] -> 0;
- true ->
+ true ->
wxe_util:send_bin(term_to_binary(Userdata)),
1
end,
- wxe_util:call(100, <<EvtList:32/?UI,ThisRef:32/?UI,
+ wxe_util:call(100, <<ThisRef:32/?UI,
Winid:32/?UI,LastId:32/?UI,
(wxe_util:from_bool(Skip)):32/?UI,
UD:32/?UI,
FunID:32/?UI,
(size(EventTypeBin)):32/?UI,
- (size(ThisTypeBin)):32/?UI,
+ (size(ThisTypeBin)):32/?UI,
%% Note no alignment
EventTypeBin/binary,ThisTypeBin/binary>>).
%% @hidden
-disconnect_impl(Listener, Object) ->
- disconnect_impl(Listener, Object, #evh{}).
-%% @hidden
-disconnect_impl(#wx_ref{type=wxeEvtListener,ref=EvtList},
- #wx_ref{type=_ThisT,ref=ThisRef},
- #evh{id=Winid, lastId=LastId, et=EventType}) ->
+disconnect_impl(#wx_ref{type=_ThisT,ref=ThisRef},
+ #evh{id=Winid, lastId=LastId, et=EventType,
+ handler=#wx_ref{type=wxeEvtListener,ref=EvtList}}) ->
EventTypeBin = list_to_binary([atom_to_list(EventType)|[0]]),
- wxe_util:call(101, <<EvtList:32/?UI,
+ wxe_util:call(101, <<EvtList:32/?UI,
ThisRef:32/?UI,Winid:32/?UI,LastId:32/?UI,
(size(EventTypeBin)):32/?UI,
%% Note no alignment
EventTypeBin/binary>>).
-
-%% @hidden
-new_evt_listener() ->
- wxe_util:call(98, <<>>).
-
-%% @hidden
-destroy_evt_listener(#wx_ref{type=wxeEvtListener,ref=EvtList}) ->
- wxe_util:call(99, <<EvtList:32/?UI>>).
-
-%% @hidden
-get_callback(#evh{cb=Callback}) ->
- Callback.
-
-%% @hidden
-replace_fun_with_id(Evh, Id) ->
- Evh#evh{cb=Id}.
diff --git a/lib/wx/api_gen/wx_gen_cpp.erl b/lib/wx/api_gen/wx_gen_cpp.erl
index 5ac57e4929..ea5d89be72 100644
--- a/lib/wx/api_gen/wx_gen_cpp.erl
+++ b/lib/wx/api_gen/wx_gen_cpp.erl
@@ -1190,15 +1190,6 @@ find_id(OtherClass) ->
encode_events(Evs) ->
?WTC("encode_events"),
- w("void wxeEvtListener::forward(wxEvent& event)~n"
- "{~n"
- "#ifdef DEBUG~n"
- " if(!sendevent(&event, port))~n"
- " fprintf(stderr, \"Couldn't send event!\\r\\n\");~n"
- "#else~n"
- "sendevent(&event, port);~n"
- "#endif~n"
- "}~n~n"),
w("int getRef(void* ptr, wxeMemEnv* memenv)~n"
"{~n"
" WxeApp * app = (WxeApp *) wxTheApp;~n"
@@ -1209,7 +1200,7 @@ encode_events(Evs) ->
" char * evClass = NULL;~n"
" wxMBConvUTF32 UTFconverter;~n"
" wxeEtype *Etype = etmap[event->GetEventType()];~n"
- " wxeCallbackData *cb = (wxeCallbackData *)event->m_callbackUserData;~n"
+ " wxeEvtListener *cb = (wxeEvtListener *)event->m_callbackUserData;~n"
" WxeApp * app = (WxeApp *) wxTheApp;~n"
" wxeMemEnv *memenv = app->getMemEnv(port);~n"
" if(!memenv) return 0;~n~n"
diff --git a/lib/wx/c_src/gen/wxe_events.cpp b/lib/wx/c_src/gen/wxe_events.cpp
index a1b4d090b3..1bd17366a2 100644
--- a/lib/wx/c_src/gen/wxe_events.cpp
+++ b/lib/wx/c_src/gen/wxe_events.cpp
@@ -316,16 +316,6 @@ void initEventTable()
}
}
-void wxeEvtListener::forward(wxEvent& event)
-{
-#ifdef DEBUG
- if(!sendevent(&event, port))
- fprintf(stderr, "Couldn't send event!\r\n");
-#else
-sendevent(&event, port);
-#endif
-}
-
int getRef(void* ptr, wxeMemEnv* memenv)
{
WxeApp * app = (WxeApp *) wxTheApp;
@@ -338,7 +328,7 @@ bool sendevent(wxEvent *event, ErlDrvTermData port)
char * evClass = NULL;
wxMBConvUTF32 UTFconverter;
wxeEtype *Etype = etmap[event->GetEventType()];
- wxeCallbackData *cb = (wxeCallbackData *)event->m_callbackUserData;
+ wxeEvtListener *cb = (wxeEvtListener *)event->m_callbackUserData;
WxeApp * app = (WxeApp *) wxTheApp;
wxeMemEnv *memenv = app->getMemEnv(port);
if(!memenv) return 0;
diff --git a/lib/wx/c_src/gen/wxe_funcs.cpp b/lib/wx/c_src/gen/wxe_funcs.cpp
index 82dd414911..3f5cb4c0f5 100644
--- a/lib/wx/c_src/gen/wxe_funcs.cpp
+++ b/lib/wx/c_src/gen/wxe_funcs.cpp
@@ -67,20 +67,8 @@ void WxeApp::wxe_dispatch(wxeCommand& Ecmd)
case WXE_INIT_OPENGL:
wxe_initOpenGL(rt, bp);
break;
-case 98: { // wxeEvtListener::wxeEvtListener
- wxeEvtListener *Result = new wxeEvtListener(Ecmd.port);
- rt.addRef(getRef((void *)Result,memenv), "wxeEvtListener");
- break;
-}
-case 99: { // wxeEvtListener::destroy
- wxObject *This = (wxObject *) getPtr(bp,memenv);
- rt.addAtom("ok");
- delete This;
- break;
-}
-case 100: { // wxEvtHandler::Connect
- wxeEvtListener *Listener = (wxeEvtListener *) getPtr(bp,memenv); bp += 4;
+case 100: { // wxEvtHandler::Connect
wxEvtHandler *This = (wxEvtHandler *) getPtr(bp, memenv); bp += 4;
int * winid = (int *) bp; bp += 4;
int * lastId = (int *) bp; bp += 4;
@@ -91,20 +79,22 @@ case 100: { // wxEvtHandler::Connect
int * eventTypeLen = (int *) bp; bp += 4;
int * class_nameLen = (int *) bp; bp += 4;
- if(*haveUserData) {
+ if(*haveUserData) {
userData = new wxeErlTerm(Ecmd.bin[0]);
}
int eventType = wxeEventTypeFromAtom(bp); bp += *eventTypeLen;
char *class_name = bp; bp+= *class_nameLen;
if(eventType > 0 ) {
- wxeCallbackData * Evt_cb = new wxeCallbackData(Ecmd.caller,getRef(This, memenv),
- class_name,*fun_cb,
- *skip, userData, Listener);
+ wxeEvtListener * Evt_cb = new wxeEvtListener(Ecmd.caller,getRef(This, memenv),
+ class_name,*fun_cb,
+ *skip, userData, Ecmd.port);
This->Connect((int) *winid,(int) *lastId,eventType,
(wxObjectEventFunction)(wxEventFunction) &wxeEvtListener::forward,
- Evt_cb, Listener);
+ Evt_cb, Evt_cb);
rt.addAtom("ok");
+ rt.addRef(getRef((void *)Evt_cb,memenv), "wxeEvtListener");
+ rt.addTupleCount(2);
} else {
rt.addAtom("badarg");
rt.addAtom("event_type");
@@ -112,7 +102,7 @@ case 100: { // wxEvtHandler::Connect
}
break;
}
-case 101: { // wxEvtHandler::Disconnect
+case 101: { // wxEvtHandler::Disconnect
wxeEvtListener *Listener = (wxeEvtListener *) getPtr(bp,memenv); bp += 4;
wxEvtHandler *This = (wxEvtHandler *) getPtr(bp, memenv); bp += 4;
int * winid = (int *) bp; bp += 4;
@@ -122,14 +112,14 @@ case 101: { // wxEvtHandler::Disconnect
int eventType = wxeEventTypeFromAtom(bp); bp += *eventTypeLen;
if(eventType > 0) {
bool Result = This->Disconnect((int) *winid,(int) *lastId,eventType,
- (wxObjectEventFunction)(wxEventFunction)
- &wxeEvtListener::forward,
- NULL, Listener);
+ (wxObjectEventFunction)(wxEventFunction)
+ &wxeEvtListener::forward,
+ NULL, Listener);
rt.addBool(Result);
} else {
rt.addAtom("badarg");
rt.addAtom("event_type");
- rt.addTupleCount(2);
+ rt.addTupleCount(2);
}
break;
}
diff --git a/lib/wx/c_src/wxe_callback_impl.cpp b/lib/wx/c_src/wxe_callback_impl.cpp
index 8ba2557d82..e06f68dcbf 100644
--- a/lib/wx/c_src/wxe_callback_impl.cpp
+++ b/lib/wx/c_src/wxe_callback_impl.cpp
@@ -30,27 +30,27 @@
* CallbackData *
* ****************************************************************************/
-wxeCallbackData::wxeCallbackData(ErlDrvTermData caller, int req, char *req_type,
- int funcb, int skip_ev, wxeErlTerm * userData,
- wxeEvtListener *handler_cb)
- : wxObject()
+wxeEvtListener::wxeEvtListener(ErlDrvTermData caller, int req, char *req_type,
+ int funcb, int skip_ev, wxeErlTerm * userData,
+ ErlDrvTermData from_port)
+ : wxEvtHandler()
{
+ port=from_port;
listener = caller;
obj = req;
fun_id = funcb;
strcpy(class_name, req_type);
skip = skip_ev;
user_data = userData;
- handler = handler_cb;
}
-wxeCallbackData::~wxeCallbackData() {
- // fprintf(stderr, "CBD Deleteing %p %s\r\n", this, class_name); fflush(stderr);
+wxeEvtListener::~wxeEvtListener() {
+ // fprintf(stderr, "CBD Deleteing %p %s\r\n", this, class_name); fflush(stderr);
if(user_data) {
delete user_data;
}
ptrMap::iterator it;
- it = ((WxeApp *)wxTheApp)->ptr2ref.find(handler);
+ it = ((WxeApp *)wxTheApp)->ptr2ref.find(this);
if(it != ((WxeApp *)wxTheApp)->ptr2ref.end()) {
wxeRefData *refd = it->second;
wxeReturn rt = wxeReturn(WXE_DRV_PORT, refd->memenv->owner, false);
@@ -61,6 +61,17 @@ wxeCallbackData::~wxeCallbackData() {
rt.addTupleCount(4);
rt.send();
}
+ ((WxeApp *)wxTheApp)->clearPtr(this);
+}
+
+void wxeEvtListener::forward(wxEvent& event)
+{
+#ifdef DEBUG
+ if(!sendevent(&event, port))
+ fprintf(stderr, "Couldn't send event!\r\n");
+#else
+sendevent(&event, port);
+#endif
}
/* *****************************************************************/
diff --git a/lib/wx/c_src/wxe_callback_impl.h b/lib/wx/c_src/wxe_callback_impl.h
index c7243e23a4..1c355e4d38 100644
--- a/lib/wx/c_src/wxe_callback_impl.h
+++ b/lib/wx/c_src/wxe_callback_impl.h
@@ -23,6 +23,24 @@
void pre_callback();
void handle_event_callback(ErlDrvPort port, ErlDrvTermData process);
+/* Fun Callback id */
+class wxeEvtListener : public wxEvtHandler
+{
+public:
+ wxeEvtListener(ErlDrvTermData caller, int req, char *req_type,
+ int funcb, int skip_ev, wxeErlTerm * userData,
+ ErlDrvTermData Thisport);
+ ~wxeEvtListener();
+ void forward(wxEvent& event);
+ ErlDrvTermData port;
+ ErlDrvTermData listener;
+ int fun_id;
+ int obj;
+ char class_name[40];
+ int skip;
+ wxeErlTerm * user_data;
+};
+
class wxEPrintout : public wxPrintout
{
public:
diff --git a/lib/wx/c_src/wxe_events.h b/lib/wx/c_src/wxe_events.h
index 22a737d854..93b5551123 100644
--- a/lib/wx/c_src/wxe_events.h
+++ b/lib/wx/c_src/wxe_events.h
@@ -32,38 +32,7 @@ public:
int cID;
};
-/* One EvtListener per listening erlang process */
-/* If callbacks are used the receiver is wxe_master process */
-/* and a wxeEvtListener pre callback is registered */
-class wxeEvtListener : public wxEvtHandler
-{
- public:
- wxeEvtListener(ErlDrvTermData Thisport) : port(Thisport)
- {}
- // {fprintf(stderr, "Creating %x\r\n", (unsigned int) this); fflush(stderr);}
- ~wxeEvtListener() {}
- void forward(wxEvent& event);
- ErlDrvTermData port;
-};
-
void initEventTable();
int wxeEventTypeFromAtom(char *etype_atom);
-/* Fun Callback id */
-class wxeCallbackData : public wxObject
-{
-public:
- wxeCallbackData(ErlDrvTermData caller, int req, char *req_type,
- int funcb, int skip_ev, wxeErlTerm * userData,
- wxeEvtListener *handler_cb);
- ~wxeCallbackData();
- wxeEvtListener * handler;
- ErlDrvTermData listener;
- int fun_id;
- int obj;
- char class_name[40];
- int skip;
- wxeErlTerm * user_data;
-};
-
#endif
diff --git a/lib/wx/src/gen/wxEvtHandler.erl b/lib/wx/src/gen/wxEvtHandler.erl
index 22c203392c..44b7254cfb 100644
--- a/lib/wx/src/gen/wxEvtHandler.erl
+++ b/lib/wx/src/gen/wxEvtHandler.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2012. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2014. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -46,15 +46,11 @@
-export([connect/2, connect/3, disconnect/1, disconnect/2, disconnect/3]).
%% internal exports
--export([connect_impl/3, disconnect_impl/2, disconnect_impl/3,
- new_evt_listener/0, destroy_evt_listener/1,
- get_callback/1, replace_fun_with_id/2]).
+-export([connect_impl/2, disconnect_impl/2]).
-export_type([wxEvtHandler/0, wx/0, event/0]).
-type wxEvtHandler() :: wx:wx_object().
--record(evh, {et=null,id=?wxID_ANY,lastId=?wxID_ANY,skip=undefined,userdata=[],cb=0}).
-
%% @doc Equivalent to {@link connect/3. connect(This, EventType, [])}
-spec connect(This::wxEvtHandler(), EventType::wxEventType()) -> ok.
connect(This, EventType) ->
@@ -149,55 +145,35 @@ disconnect(This=#wx_ref{type=ThisT,ref=_ThisRef}, EventType, Opts) ->
%% @hidden
-connect_impl(#wx_ref{type=wxeEvtListener,ref=EvtList},
- #wx_ref{type=ThisT,ref=ThisRef},
- #evh{id=Winid, lastId=LastId, et=EventType,
- skip=Skip, userdata=Userdata, cb=FunID})
+connect_impl(#wx_ref{type=ThisT,ref=ThisRef},
+ #evh{id=Winid, lastId=LastId, et=EventType,
+ skip=Skip, userdata=Userdata, cb=FunID})
when is_integer(FunID)->
EventTypeBin = list_to_binary([atom_to_list(EventType)|[0]]),
ThisTypeBin = list_to_binary([atom_to_list(ThisT)|[0]]),
UD = if Userdata =:= [] -> 0;
- true ->
+ true ->
wxe_util:send_bin(term_to_binary(Userdata)),
1
end,
- wxe_util:call(100, <<EvtList:32/?UI,ThisRef:32/?UI,
+ wxe_util:call(100, <<ThisRef:32/?UI,
Winid:32/?UI,LastId:32/?UI,
(wxe_util:from_bool(Skip)):32/?UI,
UD:32/?UI,
FunID:32/?UI,
(size(EventTypeBin)):32/?UI,
- (size(ThisTypeBin)):32/?UI,
+ (size(ThisTypeBin)):32/?UI,
%% Note no alignment
EventTypeBin/binary,ThisTypeBin/binary>>).
%% @hidden
-disconnect_impl(Listener, Object) ->
- disconnect_impl(Listener, Object, #evh{}).
-%% @hidden
-disconnect_impl(#wx_ref{type=wxeEvtListener,ref=EvtList},
- #wx_ref{type=_ThisT,ref=ThisRef},
- #evh{id=Winid, lastId=LastId, et=EventType}) ->
+disconnect_impl(#wx_ref{type=_ThisT,ref=ThisRef},
+ #evh{id=Winid, lastId=LastId, et=EventType,
+ handler=#wx_ref{type=wxeEvtListener,ref=EvtList}}) ->
EventTypeBin = list_to_binary([atom_to_list(EventType)|[0]]),
- wxe_util:call(101, <<EvtList:32/?UI,
+ wxe_util:call(101, <<EvtList:32/?UI,
ThisRef:32/?UI,Winid:32/?UI,LastId:32/?UI,
(size(EventTypeBin)):32/?UI,
%% Note no alignment
EventTypeBin/binary>>).
-%% @hidden
-new_evt_listener() ->
- wxe_util:call(98, <<>>).
-
-%% @hidden
-destroy_evt_listener(#wx_ref{type=wxeEvtListener,ref=EvtList}) ->
- wxe_util:call(99, <<EvtList:32/?UI>>).
-
-%% @hidden
-get_callback(#evh{cb=Callback}) ->
- Callback.
-
-%% @hidden
-replace_fun_with_id(Evh, Id) ->
- Evh#evh{cb=Id}.
-
diff --git a/lib/wx/src/wxe.hrl b/lib/wx/src/wxe.hrl
index bd34b13385..66ec9ac45e 100644
--- a/lib/wx/src/wxe.hrl
+++ b/lib/wx/src/wxe.hrl
@@ -29,6 +29,11 @@
-record(wx_mem, {bin, size}).
+-record(evh, {et=null,id=-1,lastId=-1,cb=0,
+ skip=undefined,userdata=[], % temp
+ handler=undefined % added after connect
+ }).
+
-define(CLASS(Type,Class), ((Type) =:= Class) orelse (Type):parent_class(Class)).
-define(CLASS_T(Type,Class),
diff --git a/lib/wx/src/wxe_server.erl b/lib/wx/src/wxe_server.erl
index 04e0d0faf4..aed9dca7ce 100644
--- a/lib/wx/src/wxe_server.erl
+++ b/lib/wx/src/wxe_server.erl
@@ -36,8 +36,8 @@
terminate/2, code_change/3]).
-record(state, {port,cb_port,users,cleaners=[],cb,cb_cnt}).
--record(user, {events=[], evt_handler}).
--record(event, {object, callback, cb_handler}).
+-record(user, {events=[]}).
+%%-record(event, {object, callback, cb_handler}).
-define(APPLICATION, wxe).
-define(log(S,A), log(?MODULE,?LINE,S,A)).
@@ -119,7 +119,7 @@ handle_call(stop,{_From,_},State = #state{users=Users0, cleaners=Cs0}) ->
Env = get(?WXE_IDENTIFIER),
Users = gb_trees:to_list(Users0),
Cs = lists:map(fun({_Pid,User}) ->
- spawn_link(fun() -> cleanup(Env,[User], false) end)
+ spawn_link(fun() -> cleanup(Env,[User]) end)
end, Users),
{noreply, State#state{users=gb_trees:empty(), cleaners=Cs ++ Cs0}};
@@ -178,13 +178,13 @@ handle_info({'DOWN',_,process,Pid,_}, State=#state{users=Users0,cleaners=Cs}) ->
Users = gb_trees:delete(Pid,Users0),
Env = wx:get_env(),
case User of
- #user{events=[], evt_handler=undefined} -> %% No need to spawn
+ #user{events=[]} -> %% No need to spawn
case Cs =:= [] andalso gb_trees:is_empty(Users) of
- true -> {stop, normal, State#state{cleaners=Cs}};
- false -> {noreply, State#state{users=Users,cleaners=Cs}}
+ true -> {stop, normal, State#state{users=Users}};
+ false -> {noreply, State#state{users=Users}}
end;
_ ->
- Cleaner = spawn_link(fun() -> cleanup(Env,[User],true) end),
+ Cleaner = spawn_link(fun() -> cleanup(Env,[User]) end),
{noreply, State#state{users=Users,cleaners=[Cleaner|Cs]}}
end
catch _E:_R ->
@@ -222,36 +222,26 @@ code_change(_OldVsn, State, _Extra) ->
log(Mod,Line,Str,Args) ->
error_logger:format("~p:~p: " ++ Str, [Mod,Line|Args]).
-handle_connect(Object, EvData, From, State0 = #state{users=Users}) ->
- User0 = #user{events=Evs0,evt_handler=Handler0} = gb_trees:get(From, Users),
- Callback = wxEvtHandler:get_callback(EvData),
- case Handler0 of
- #wx_ref{} when Callback =:= 0 ->
- CBHandler = Handler0,
- Handler = Handler0;
- undefined when Callback =:= 0 ->
- Handler = new_evt_listener(State0, From),
- CBHandler = Handler;
- _ ->
- CBHandler = new_evt_listener(State0, From),
- Handler = Handler0
- end,
- Evs = [#event{object=Object,callback=Callback, cb_handler=CBHandler}|Evs0],
- User = User0#user{events=Evs, evt_handler=Handler},
- State1 = State0#state{users=gb_trees:update(From, User, Users)},
- if is_function(Callback) orelse is_pid(Callback) ->
- {FunId, State} = attach_fun(Callback,State1),
- Res = wxEvtHandler:connect_impl(CBHandler,Object,
- wxEvtHandler:replace_fun_with_id(EvData,FunId)),
- case Res of
- ok -> {reply,Res,State};
- _Error -> {reply,Res,State0}
- end;
-
- true ->
- Res = {call_impl, connect_cb, CBHandler},
- {reply, Res, State1}
- end.
+handle_connect(Object, #evh{handler=undefined, cb=Callback} = EvData0,
+ From, State0) ->
+ %% Callback let this process listen to the events
+ {FunId, State} = attach_fun(Callback,State0),
+ EvData1 = EvData0#evh{cb=FunId},
+ case wxEvtHandler:connect_impl(Object,EvData1) of
+ {ok, Handler} ->
+ EvData = EvData1#evh{handler=Handler,userdata=undefined},
+ handle_connect(Object, EvData, From, State);
+ Error ->
+ {reply, Error, State0}
+ end;
+handle_connect(Object, EvData=#evh{handler=Handler},
+ From, State0 = #state{users=Users}) ->
+ %% Correct process is already listening just register it
+ put(Handler, From),
+ User0 = #user{events=Listeners0} = gb_trees:get(From, Users),
+ User = User0#user{events=[{Object,EvData}|Listeners0]},
+ State = State0#state{users=gb_trees:update(From, User, Users)},
+ {reply, ok, State}.
invoke_cb({{Ev=#wx{}, Ref=#wx_ref{}}, FunId,_}, _S) ->
%% Event callbacks
@@ -329,20 +319,6 @@ get_wx_object_state(Pid) ->
_ -> ignore
end.
-new_evt_listener(State, Owner) ->
- #wx_env{port=Port} = wx:get_env(),
- _ = erlang:port_control(Port,98,<<>>),
- Listener = get_result(State),
- put(Listener, Owner),
- Listener.
-
-get_result(_State) ->
- receive
- {'_wxe_result_', Res} -> Res;
- {'_wxe_error_', Op, Error} ->
- erlang:error({Error, {wxEvtHandler, {internal_installer, Op}}})
- end.
-
attach_fun(Fun, S = #state{cb=CB,cb_cnt=Next}) ->
case gb_trees:lookup(Fun,CB) of
{value, ID} ->
@@ -367,90 +343,72 @@ delete_fun(FunId, State = #state{cb=CB}) ->
State
end.
-cleanup_evt_listener(U=#user{events=Evs0,evt_handler=Handler}, EvtListener, Object) ->
- {Evs, Del} = lists:foldl(fun(#event{object=Obj,cb_handler=CBH}, {Acc, Delete})
- when CBH =:= EvtListener, Obj =:= Object ->
- {Acc, Delete};
- (Event = #event{cb_handler=CBH}, {Acc, _Delete})
- when CBH =:= EvtListener ->
- {[Event|Acc], false};
- (Event, {Acc, Delete}) ->
- {[Event|Acc], Delete}
- end, {[], true}, Evs0),
- Del andalso wxEvtHandler:destroy_evt_listener(EvtListener),
- case Del andalso Handler =:= EvtListener of
- true ->
- U#user{events=Evs, evt_handler=undefined};
- false ->
- U#user{events=Evs}
- end.
+cleanup_evt_listener(U=#user{events=Evs0}, EvtListener, Object) ->
+ Filter = fun({Obj,#evh{handler=Evl}}) ->
+ not (Object =:= Obj andalso Evl =:= EvtListener)
+ end,
+ U#user{events=lists:filter(Filter, Evs0)}.
-handle_disconnect(Object, Evh, From, State0 = #state{users=Users0}) ->
+handle_disconnect(Object, Evh = #evh{cb=Fun}, From,
+ State0 = #state{users=Users0, cb=Callbacks}) ->
#user{events=Evs0} = gb_trees:get(From, Users0),
- Fun = wxEvtHandler:get_callback(Evh),
- case find_handler(Evs0, Object, Fun) of
- [] -> {reply, false, State0};
+ FunId = gb_trees:lookup(Fun, Callbacks),
+ case find_handler(Evs0, Object, Evh#evh{cb=FunId}) of
+ [] ->
+ {reply, false, State0};
Handlers ->
- case disconnect(Object,Evh, Handlers) of
- #event{} ->
- {reply, true, State0};
- Result ->
- {reply, Result, State0}
+ case disconnect(Object,Handlers) of
+ #evh{} -> {reply, true, State0};
+ Result -> {reply, Result, State0}
end
end.
-disconnect(Object,Evh,[Ev=#event{cb_handler=Handler}|Evs]) ->
- try wxEvtHandler:disconnect_impl(Handler,Object,Evh) of
+disconnect(Object,[Ev|Evs]) ->
+ try wxEvtHandler:disconnect_impl(Object,Ev) of
true -> Ev;
- false -> disconnect(Object, Evh, Evs);
+ false -> disconnect(Object, Evs);
Error -> Error
catch _:_ ->
false
end;
-disconnect(_, _, []) -> false.
-
-find_handler(Evs, Object, Fun) ->
- find_handler(Evs, Object, Fun, []).
-
-find_handler([Ev =#event{object=Object,callback=FunReg}|Evs],Object,Search,Acc) ->
- case FunReg =:= Search of
- true -> find_handler(Evs,Object,Search,[Ev|Acc]);
- false when is_function(FunReg), Search =:= 0 ->
- find_handler(Evs,Object,Search,[Ev|Acc]);
- _ ->
- find_handler(Evs,Object,Search,Acc)
+disconnect(_, []) -> false.
+
+find_handler([{Object,Evh}|Evs], Object, Match) ->
+ case match_handler(Match, Evh) of
+ false -> find_handler(Evs, Object, Match);
+ Res -> [Res|find_handler(Evs,Object,Match)]
end;
-find_handler([_|Evs],Object,Fun,Res) ->
- find_handler(Evs,Object,Fun,Res);
-find_handler([],_Object,_Fun,Res) ->
- Res.
+find_handler([_|Evs], Object, Match) ->
+ find_handler(Evs, Object, Match);
+find_handler([], _, _) -> [].
+
+match_handler(M=#evh{et=MET, cb=MCB},
+ #evh{et=ET, cb=CB, handler=Handler}) ->
+ %% Let wxWidgets handle the id matching
+ Match = match_et(MET, ET)
+ andalso match_cb(MCB, CB),
+ Match andalso M#evh{handler=Handler}.
+match_et(null, _) -> true;
+match_et(Met, Et) -> Met =:= Et.
+
+match_cb(none, _) -> true;
+match_cb({value,MId}, Id) -> MId =:= Id.
%% Cleanup
%% The server handles callbacks from driver so every other wx call must
%% be called from another process, therefore the cleaning must be spawned.
%%
-%% Using Disconnect when we terminate can crash, it is timing releated
-%% but it seems that disconnect on windows that are being deleted are bad.
-%% Since we are terminating the data will be cleaned up anyway.
-cleanup(Env, Data, Disconnect) ->
+cleanup(Env, Data) ->
put(?WXE_IDENTIFIER, Env),
- lists:foreach(fun(User) -> cleanup(User, Disconnect) end, Data),
+ Disconnect = fun({Object, Ev}) ->
+ try wxEvtHandler:disconnect_impl(Object,Ev)
+ catch _:_ -> ok
+ end
+ end,
+
+ lists:foreach(fun(#user{events=Evs}) ->
+ [Disconnect(Ev) || Ev <- Evs]
+ end, Data),
gen_server:cast(Env#wx_env.sv, {cleaned, self()}),
normal.
-
-cleanup(#user{events=Evs, evt_handler=Handler}, Disconnect) ->
- lists:foreach(fun(#event{object=O, callback=CB, cb_handler=CbH}) ->
- Disconnect andalso (catch wxEvtHandler:disconnect_impl(CbH,O)),
- case is_function(CB) of
- true ->
- wxEvtHandler:destroy_evt_listener(CbH);
- false ->
- ignore
- end
- end, Evs),
- case Handler of
- undefined -> ignore;
- _ -> wxEvtHandler:destroy_evt_listener(Handler)
- end,
- ok.
diff --git a/lib/wx/src/wxe_util.erl b/lib/wx/src/wxe_util.erl
index a31c3e30b8..02ac4ddfa6 100644
--- a/lib/wx/src/wxe_util.erl
+++ b/lib/wx/src/wxe_util.erl
@@ -74,7 +74,7 @@ call(Op, Args) ->
true ->
debug_call(Dbg band 15, Op, Args, Port)
end.
-
+
rec(Op) ->
receive
{'_wxe_result_', Res} -> Res;
@@ -108,21 +108,26 @@ send_bin(Bin) when is_binary(Bin) ->
get_cbId(Fun) ->
gen_server:call((wx:get_env())#wx_env.sv,{register_cb, Fun}, infinity).
-connect_cb(Object,EvData) ->
- handle_listener(connect_cb, Object, EvData).
-
-disconnect_cb(Object,EvData) ->
- handle_listener(disconnect_cb, Object, EvData).
-
-handle_listener(Op,Object,EvData) ->
- Listener = gen_server:call((wx:get_env())#wx_env.sv, {Op,Object,EvData}, infinity),
- case Listener of
- {call_impl, connect_cb, EvtList} ->
- wxEvtHandler:connect_impl(EvtList,Object,EvData);
- Res ->
- Res
+connect_cb(Object,EvData0 = #evh{cb=Callback}) ->
+ Server = (wx:get_env())#wx_env.sv,
+ case Callback of
+ 0 -> %% Message api connect from this process
+ case wxEvtHandler:connect_impl(Object,EvData0) of
+ {ok, Listener} ->
+ EvData = EvData0#evh{handler=Listener, userdata=undefined},
+ gen_server:call(Server, {connect_cb,Object,EvData}, infinity);
+ Error ->
+ Error
+ end;
+ _ -> %% callback, fun or pid (pid for wx_object:sync_events masked callbacks)
+ %% let the server do the connect
+ gen_server:call(Server, {connect_cb,Object,EvData0}, infinity)
end.
+disconnect_cb(Object,EvData) ->
+ Server = (wx:get_env())#wx_env.sv,
+ gen_server:call(Server, {disconnect_cb,Object,EvData}, infinity).
+
debug_cast(1, Op, _Args, _Port) ->
check_previous(),
case ets:lookup(wx_debug_info,Op) of
diff --git a/lib/wx/test/wx_event_SUITE.erl b/lib/wx/test/wx_event_SUITE.erl
index b9c2fafe0e..076f16ba16 100644
--- a/lib/wx/test/wx_event_SUITE.erl
+++ b/lib/wx/test/wx_event_SUITE.erl
@@ -149,7 +149,7 @@ disconnect(Config) ->
timer:sleep(1000),
wx_test_lib:flush(),
- ?m({'EXIT', {{badarg,_},_}}, wxEvtHandler:disconnect(Panel, non_existing_event_type)),
+ ?m(false, wxEvtHandler:disconnect(Panel, non_existing_event_type)),
?m(true, wxEvtHandler:disconnect(Panel, size)),
?m(ok, wxWindow:setSize(Panel, {200,102})),
timer:sleep(1000),
@@ -499,14 +499,14 @@ callback_clean(Config) ->
end
end),
timer:sleep(500), %% Give it time to remove it
- ?m({[{Pid,_,_}],[_],[_]}, white_box_check_event_handlers()),
+ ?m({[{Pid,_}],[_],[_]}, white_box_check_event_handlers()),
Pid ! remove,
timer:sleep(500), %% Give it time to remove it
?m({[],[],[]}, white_box_check_event_handlers()),
SetupEventHandlers(),
- ?m({[{_,_,_}],[_],[_]}, white_box_check_event_handlers()),
+ ?m({[{_,_}],[_],[_]}, white_box_check_event_handlers()),
wxDialog:show(Dlg),
wx_test_lib:wx_close(Dlg, Config),
@@ -526,9 +526,9 @@ white_box_check_event_handlers() ->
{status, _, _, [Env, _, _, _, Data]} = sys:get_status(Server),
[_H, _data, {data, [{_, Record}]}] = Data,
{state, _Port1, _Port2, Users, [], CBs, _Next} = Record,
- {[{Pid, Evs, Listener} ||
- {Pid, {user, Evs, Listener}} <- gb_trees:to_list(Users),
- (Evs =/= [] orelse Listener =/= undefined)], %% Ignore empty
+ {[{Pid, Evs} ||
+ {Pid, {user, Evs}} <- gb_trees:to_list(Users),
+ Evs =/= []], %% Ignore empty
gb_trees:to_list(CBs),
[Funs || Funs = {Id, {Fun,_}} <- Env, is_integer(Id), is_function(Fun)]
}.