aboutsummaryrefslogtreecommitdiffstats
path: root/lib/wx/c_src/wxe_impl.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/wx/c_src/wxe_impl.cpp')
-rw-r--r--lib/wx/c_src/wxe_impl.cpp863
1 files changed, 863 insertions, 0 deletions
diff --git a/lib/wx/c_src/wxe_impl.cpp b/lib/wx/c_src/wxe_impl.cpp
new file mode 100644
index 0000000000..d115bb2243
--- /dev/null
+++ b/lib/wx/c_src/wxe_impl.cpp
@@ -0,0 +1,863 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 2008-2009. All Rights Reserved.
+ *
+ * The contents of this file are subject to the Erlang Public License,
+ * Version 1.1, (the "License"); you may not use this file except in
+ * compliance with the License. You should have received a copy of the
+ * Erlang Public License along with this software. If not, it can be
+ * retrieved online at http://www.erlang.org/.
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * %CopyrightEnd%
+ */
+
+#include <stdio.h>
+#include <signal.h>
+
+
+#include <wx/wx.h>
+
+// Avoid including these in dcbuffer below
+#include "wx/dcmemory.h"
+#include "wx/dcclient.h"
+#include "wx/window.h"
+// Ok ugly but needed for wxBufferedDC crash workaround
+#define private public
+#include <wx/dcbuffer.h>
+#undef private
+
+#include "wxe_impl.h"
+#include "wxe_events.h"
+#include "wxe_return.h"
+
+IMPLEMENT_APP_NO_MAIN(WxeApp)
+
+DECLARE_APP(WxeApp)
+
+DEFINE_EVENT_TYPE(wxeEVT_META_COMMAND)
+
+#define WXE_NOT_INITIATED 0
+#define WXE_INITIATED 1
+#define WXE_EXITED 2
+#define WXE_ERROR -1
+
+#define WXE_NORMAL 0
+#define WXE_CALLBACK 1
+#define WXE_STORED 2
+
+ErlDrvTid wxe_thread;
+
+ErlDrvMutex *wxe_status_m;
+ErlDrvCond *wxe_status_c;
+
+ErlDrvMutex * wxe_batch_locker_m;
+ErlDrvCond * wxe_batch_locker_c;
+
+static int wxe_status = WXE_NOT_INITIATED;
+
+wxList * wxe_batch = NULL;
+wxList * wxe_batch_cb_saved = NULL;
+
+ErlDrvTermData wxe_batch_caller = 0;
+ErlDrvTermData init_caller = 0;
+
+// extern opengl
+extern int gl_initiated;
+void gl_dispatch(int op, char *bp, ErlDrvTermData caller, WXEBinRef *bins[]);
+
+
+// Until fixed in emulator
+#ifndef _WIN32
+extern "C" {
+extern void erts_thread_disable_fpe(void);
+}
+#endif
+
+void *wxe_main_loop(void * );
+
+/* ************************************************************
+ * START AND STOP of driver thread
+ * ************************************************************/
+
+int load_native_gui()
+{
+ return 1;
+}
+
+int start_native_gui(wxe_data *sd)
+{
+ int res;
+ wxe_status_m = erl_drv_mutex_create((char *) "wxe_status_m");
+ wxe_status_c = erl_drv_cond_create((char *)"wxe_status_c");
+
+ wxe_batch_locker_m = erl_drv_mutex_create((char *)"wxe_batch_locker_m");
+ wxe_batch_locker_c = erl_drv_cond_create((char *)"wxe_batch_locker_c");
+ init_caller = driver_connected(sd->port);
+
+ if((res = erl_drv_thread_create((char *)"wxwidgets",
+ &wxe_thread,wxe_main_loop,NULL,NULL)) == 0) {
+ erl_drv_mutex_lock(wxe_status_m);
+ for(;wxe_status == WXE_NOT_INITIATED;) {
+ erl_drv_cond_wait(wxe_status_c, wxe_status_m);
+ }
+ erl_drv_mutex_unlock(wxe_status_m);
+ return wxe_status;
+ } else {
+ wxString msg;
+ msg.Printf(wxT("Erlang failed to create wxe-thread %d\r\n"), res);
+ send_msg("error", &msg);
+ return -1;
+ }
+}
+
+void stop_native_gui(wxe_data *sd)
+{
+ erl_drv_thread_join(wxe_thread, NULL);
+ erl_drv_mutex_destroy(wxe_status_m);
+ erl_drv_cond_destroy(wxe_status_c);
+ erl_drv_mutex_destroy(wxe_batch_locker_m);
+ erl_drv_cond_destroy(wxe_batch_locker_c);
+}
+
+void unload_native_gui()
+{
+
+}
+
+/* ************************************************************
+ * Commands from erlang
+ * Called by emulator thread
+ * ************************************************************/
+
+void push_command(int op,char * buf,int len, wxe_data *sd)
+{
+ // fprintf(stderr, "Op %d %d\r\n", op, (int) driver_caller(sd->port)),fflush(stderr);
+ wxeCommand *Cmd = new wxeCommand(op, buf, len, sd);
+ erl_drv_mutex_lock(wxe_batch_locker_m);
+ wxe_batch->Append(Cmd);
+
+ if(wxe_batch_caller > 0) {
+ // wx-thread is waiting on batch end in cond_wait
+ erl_drv_cond_signal(wxe_batch_locker_c);
+ } else {
+ // wx-thread is waiting gui-events
+ if(op == WXE_BATCH_BEGIN) {
+ wxe_batch_caller = 1;
+ }
+ erl_drv_cond_signal(wxe_batch_locker_c);
+ wxWakeUpIdle();
+ }
+ erl_drv_mutex_unlock(wxe_batch_locker_m);
+}
+
+void meta_command(int what, wxe_data *sd) {
+ if(what == PING_PORT) {
+ erl_drv_mutex_lock(wxe_batch_locker_m);
+ if(wxe_batch_caller > 0) {
+ wxeCommand *Cmd = new wxeCommand(WXE_DEBUG_PING, NULL, 0, sd);
+ wxe_batch->Append(Cmd);
+ erl_drv_cond_signal(wxe_batch_locker_c);
+ } else {
+ wxWakeUpIdle();
+ }
+ erl_drv_mutex_unlock(wxe_batch_locker_m);
+ } else {
+ if(sd) {
+ wxeMetaCommand Cmd(sd, what);
+ wxTheApp->AddPendingEvent(Cmd);
+ }
+ }
+}
+
+/* ************************************************************
+ * wxWidgets Thread
+ * ************************************************************/
+
+void *wxe_main_loop(void * not_used)
+{
+ int result;
+ int argc = 1;
+ char * temp = (char *) "Erlang\0";
+ char ** argv = &temp;
+
+ // ErlDrvSysInfo einfo;
+ // driver_system_info(&einfo, sizeof(ErlDrvSysInfo));
+ // Disable floating point execption if they are on.
+ // This should be done in emulator but it's not in yet.
+#ifndef _WIN32
+ erts_thread_disable_fpe();
+#endif
+
+ result = wxEntry(argc, argv);
+ // fprintf(stderr, "WXWidgets quits main loop %d \r\n", result);
+ if(result >= 0 && wxe_status == WXE_INITIATED) {
+ /* We are done try to make a clean exit */
+ wxe_status = WXE_EXITED;
+ erl_drv_thread_exit(NULL);
+ return NULL;
+ } else {
+ erl_drv_mutex_lock(wxe_status_m);
+ wxe_status = WXE_ERROR;
+ erl_drv_cond_signal(wxe_status_c);
+ erl_drv_mutex_unlock(wxe_status_m);
+ return NULL;
+ }
+}
+
+wxFrame * dummy_window;
+
+void create_dummy_window() {
+ dummy_window = new wxFrame(NULL,-1, wxT("wx driver"),
+ wxDefaultPosition, wxSize(5,5),
+ wxFRAME_NO_TASKBAR);
+ dummy_window->Connect(wxID_ANY, wxEVT_CLOSE_WINDOW,
+ (wxObjectEventFunction) (wxEventFunction) &WxeApp::dummy_close);
+}
+
+// wxMac really wants a top level window which command-q quits if there are no
+// windows open, and this will kill the thread, so restart the dummy_window each
+// time a we receive a close.
+void WxeApp::dummy_close(wxEvent& Ev) {
+ // fprintf(stderr, "Tried to close dummy window\r\n"); fflush(stderr);
+ create_dummy_window();
+}
+
+// Init wx-widgets thread
+bool WxeApp::OnInit()
+{
+ wxe_ps_init();
+
+ global_me = new wxeMemEnv();
+ wxe_batch = new wxList;
+ wxe_batch_cb_saved = new wxList;
+
+ wxIdleEvent::SetMode(wxIDLE_PROCESS_SPECIFIED);
+
+ this->Connect(wxID_ANY, wxEVT_IDLE,
+ (wxObjectEventFunction) (wxEventFunction) &WxeApp::idle);
+ this->Connect(CREATE_PORT, wxeEVT_META_COMMAND,
+ (wxObjectEventFunction) (wxEventFunction) &WxeApp::newMemEnv);
+ this->Connect(DELETE_PORT, wxeEVT_META_COMMAND,
+ (wxObjectEventFunction) (wxEventFunction) &WxeApp::destroyMemEnv);
+ this->Connect(WXE_SHUTDOWN, wxeEVT_META_COMMAND,
+ (wxObjectEventFunction) (wxEventFunction) &WxeApp::shutdown);
+
+// fprintf(stderr, "Size void* %d: long %d long long %d int64 %d \r\n",
+// sizeof(void *), sizeof(long), sizeof(long long), sizeof(wxInt64));
+ initEventTable();
+ wxInitAllImageHandlers();
+
+ /* Create a dummy window so wxWidgets don't automagicly quits the main loop
+ after the last window */
+ create_dummy_window();
+
+ init_nonconsts(global_me, init_caller);
+ erl_drv_mutex_lock(wxe_status_m);
+ wxe_status = WXE_INITIATED;
+ gl_initiated = FALSE;
+ erl_drv_cond_signal(wxe_status_c);
+ erl_drv_mutex_unlock(wxe_status_m);
+ return TRUE;
+}
+
+void WxeApp::shutdown(wxeMetaCommand& Ecmd) {
+ delete dummy_window;
+ ExitMainLoop();
+}
+
+void send_msg(const char * type, wxString * msg) {
+ wxeReturn rt = wxeReturn(WXE_DRV_PORT, init_caller);
+ rt.addAtom((char *) "wxe_driver");
+ rt.addAtom((char *) type);
+ rt.add(msg);
+ rt.addTupleCount(3);
+ rt.send();
+}
+
+/* ************************************************************
+ * Erlang Command execution *
+ * ************************************************************/
+
+/* Callback from printer and event callbacks */
+void pre_callback()
+{
+ // no-op
+}
+
+void handle_event_callback(ErlDrvPort port, ErlDrvTermData process)
+{
+ WxeApp * app = (WxeApp *) wxTheApp;
+ ErlDrvMonitor monitor;
+ driver_monitor_process(port, process, &monitor);
+ // Should we be able to handle commands when recursing? probably
+ erl_drv_mutex_lock(wxe_batch_locker_m);
+ //fprintf(stderr, "\r\nCB Start ");fflush(stderr);
+ app->dispatch_cb(wxe_batch, wxe_batch_cb_saved, process);
+ //fprintf(stderr, ".. done \r\n");fflush(stderr);
+ wxe_batch_caller = 0;
+ erl_drv_mutex_unlock(wxe_batch_locker_m);
+ driver_demonitor_process(port, &monitor);
+}
+
+void handle_callback_batch(ErlDrvPort port)
+{
+ WxeApp * app = (WxeApp *) wxTheApp;
+ // Should we be able to handle commands when recursing? probably
+ erl_drv_mutex_lock(wxe_batch_locker_m);
+ app->dispatch(wxe_batch, 0, WXE_CALLBACK);
+ wxe_batch_caller = 0;
+ erl_drv_mutex_unlock(wxe_batch_locker_m);
+}
+
+// Called by wx thread
+void WxeApp::idle(wxIdleEvent& event) {
+ dispatch_cmds();
+}
+
+void WxeApp::dispatch_cmds() {
+ erl_drv_mutex_lock(wxe_batch_locker_m);
+ int level = dispatch(wxe_batch_cb_saved, 0, WXE_STORED);
+ dispatch(wxe_batch, level, WXE_NORMAL);
+ wxe_batch_caller = 0;
+ erl_drv_mutex_unlock(wxe_batch_locker_m);
+}
+
+// Should have erl_drv_mutex_lock(wxe_batch_locker_m);
+// when entering this function and it should be released
+// afterwards
+int WxeApp::dispatch(wxList * batch, int blevel, int list_type)
+{
+ int ping = 0;
+ // erl_drv_mutex_lock(wxe_batch_locker_m); must be locked already
+ while(true)
+ {
+ if (batch->size() > 0) {
+ for( wxList::compatibility_iterator node = batch->GetFirst();
+ node;
+ node = batch->GetFirst())
+ {
+ wxeCommand *event = (wxeCommand *)node->GetData();
+ batch->Erase(node);
+ switch(event->op) {
+ case WXE_BATCH_END:
+ {--blevel; }
+ break;
+ case WXE_BATCH_BEGIN:
+ {blevel++; }
+ break;
+ case WXE_DEBUG_PING:
+ // When in debugger we don't want to hang waiting for a BATCH_END
+ // that never comes, because a breakpoint have hit.
+ ping++;
+ if(ping > 2)
+ blevel = 0;
+ break;
+ case WXE_CB_RETURN:
+ // erl_drv_mutex_unlock(wxe_batch_locker_m); should be called after
+ // whatever cleaning is necessary
+ memcpy(cb_buff, event->buffer, event->len);
+ return blevel;
+ default:
+ erl_drv_mutex_unlock(wxe_batch_locker_m);
+ if(event->op < OPENGL_START) {
+ // fprintf(stderr, " c %d (%d) \r\n", event->op, blevel);
+ wxe_dispatch(*event);
+ } else {
+ gl_dispatch(event->op,event->buffer,event->caller,event->bin);
+ }
+ erl_drv_mutex_lock(wxe_batch_locker_m);
+ break;
+ }
+ delete event;
+ }
+ } else {
+ if((list_type == WXE_STORED) || (blevel <= 0 && list_type == WXE_NORMAL)) {
+ // erl_drv_mutex_unlock(wxe_batch_locker_m); should be called after
+ // whatever cleaning is necessary
+ return blevel;
+ }
+ // sleep until something happens
+ //fprintf(stderr, "%s:%d sleep %d %d %d %d \r\n", __FILE__, __LINE__, batch->size(), callback_returned, blevel, is_callback);fflush(stderr);
+ wxe_batch_caller++;
+ while(batch->size() == 0) {
+ erl_drv_cond_wait(wxe_batch_locker_c, wxe_batch_locker_m);
+ }
+ }
+ }
+}
+
+void WxeApp::dispatch_cb(wxList * batch, wxList * temp, ErlDrvTermData process) {
+ int callback_returned = 0;
+ while(true) {
+ if (batch->size() > 0) {
+ for( wxList::compatibility_iterator node = batch->GetFirst();
+ node;
+ node = batch->GetFirst())
+ {
+ wxeCommand *event = (wxeCommand *)node->GetData();
+ batch->Erase(node);
+ if(event->caller == process || // Callbacks from CB process only
+ event->op == WXE_CB_START || // Recursive event callback allow
+ // Allow connect_cb during CB i.e. msg from wxe_server.
+ event->caller == driver_connected(event->port))
+ {
+ switch(event->op) {
+ case WXE_BATCH_END:
+ case WXE_BATCH_BEGIN:
+ case WXE_DEBUG_PING:
+ break;
+ case WXE_CB_RETURN:
+ memcpy(cb_buff, event->buffer, event->len);
+ callback_returned = 1;
+ return;
+ case WXE_CB_START:
+ // CB start from now accept message from CB process only
+ process = event->caller;
+ break;
+ default:
+ erl_drv_mutex_unlock(wxe_batch_locker_m);
+ if(event->op < OPENGL_START) {
+ // fprintf(stderr, " cb %d \r\n", event->op);
+ wxe_dispatch(*event);
+ } else {
+ gl_dispatch(event->op,event->buffer,event->caller,event->bin);
+ }
+ erl_drv_mutex_lock(wxe_batch_locker_m);
+ break;
+ if(callback_returned)
+ return;
+ }
+ delete event;
+ } else {
+ // fprintf(stderr, " sav %d \r\n", event->op);
+ temp->Append(event);
+ }
+ }
+ } else {
+ if(callback_returned) {
+ return;
+ }
+ // sleep until something happens
+ //fprintf(stderr, "%s:%d sleep %d %d %d %d \r\n", __FILE__, __LINE__, batch->size(), callback_returned, blevel, is_callback);fflush(stderr);
+ while(batch->size() == 0) {
+ erl_drv_cond_wait(wxe_batch_locker_c, wxe_batch_locker_m);
+ }
+ }
+ }
+}
+
+/* Memory handling */
+
+void WxeApp::newMemEnv(wxeMetaCommand& Ecmd) {
+ wxeMemEnv * memenv = new wxeMemEnv();
+ for(int i = 0; i < global_me->next; i++) {
+ memenv->ref2ptr[i] = global_me->ref2ptr[i];
+ }
+ memenv->next = global_me->next;
+ refmap[(ErlDrvTermData) Ecmd.port] = memenv;
+ memenv->owner = Ecmd.caller;
+
+ ErlDrvTermData rt[] = {ERL_DRV_ATOM, driver_mk_atom((char *)"wx_port_initiated")};
+ driver_send_term(WXE_DRV_PORT,Ecmd.caller,rt,2);
+}
+
+void WxeApp::destroyMemEnv(wxeMetaCommand& Ecmd) {
+ // Clear incoming cmd queue first
+ // dispatch_cmds();
+ wxWindow *parent = NULL;
+ wxeMemEnv * memenv = refmap[(ErlDrvTermData) Ecmd.port];
+
+ if(wxe_debug) {
+ wxString msg;
+ msg.Printf(wxT("Destroying all memory "));
+ send_msg("debug", &msg);
+ }
+
+ // pre-pass delete all dialogs first since they might crash erlang otherwise
+ for(int i=1; i < memenv->next; i++) {
+ wxObject * ptr = (wxObject *) memenv->ref2ptr[i];
+ if(ptr) {
+ ptrMap::iterator it = ptr2ref.find(ptr);
+ if(it != ptr2ref.end()) {
+ wxeRefData *refd = it->second;
+ if(refd->alloc_in_erl) {
+ if(refd->type == 2) {
+ wxDialog *win = (wxDialog *) ptr;
+ if(win->IsModal()) {
+ win->EndModal(-1);
+ }
+ parent = win->GetParent();
+ if(parent) {
+ ptrMap::iterator parentRef = ptr2ref.find(parent);
+ if(parentRef == ptr2ref.end()) {
+ // The parent is already dead delete the parent ref
+ win->SetParent(NULL);
+ }
+ }
+ delete win;
+ }
+ }
+ }
+ }
+ }
+ // First pass, delete all top parents/windows of all linked objects
+ // fprintf(stderr, "close port %x\r\n", Ecmd.port);fflush(stderr);
+
+ for(int i=1; i < memenv->next; i++) {
+ void * ptr = memenv->ref2ptr[i];
+ if(ptr) {
+ ptrMap::iterator it = ptr2ref.find(ptr);
+ if(it != ptr2ref.end()) {
+ wxeRefData *refd = it->second;
+ if(refd->alloc_in_erl && refd->type == 0) {
+ parent = (wxWindow *) ptr;
+ // fprintf(stderr, "window %x %d\r\n", (int) parent, refd->ref);
+ while(parent->GetParent()) {
+ parent = parent->GetParent();
+ // fprintf(stderr, " parent %x \r\n", (int) parent);
+ }
+ ptrMap::iterator pdata = ptr2ref.find(parent);
+ if(pdata != ptr2ref.end()) {
+ delete parent;
+ } // else parent is already deleted
+ }
+ } else {
+ // fprintf(stderr, "Error found no ref in %d => %x\r\n", i, ptr);
+ }
+ }
+ }
+ // Second pass delete everything else allocated
+ // everything linked from windows should now be deleted
+ for(int i=1; i < memenv->next; i++) {
+ void * ptr = memenv->ref2ptr[i];
+ if(ptr) {
+ ptrMap::iterator it = ptr2ref.find(ptr);
+ if(it != ptr2ref.end()) {
+ wxeRefData *refd = it->second;
+ if(refd->alloc_in_erl) {
+ int type = refd->type;
+ if((refd->type == 1) && ((wxObject *)ptr)->IsKindOf(CLASSINFO(wxBufferedDC))) {
+ ((wxBufferedDC *)ptr)->m_dc = NULL; // Workaround
+ }
+ wxString msg;
+ if((refd->type == 0)) { // Maybe also class 1
+ wxClassInfo *cinfo = ((wxObject *)ptr)->GetClassInfo();
+ msg.Printf(wxT("Memory leak: {wx_ref, %d, %s}"),
+ refd->ref, cinfo->GetClassName());
+ send_msg("error", &msg);
+ } else {
+ delete_object(ptr, refd);
+ }
+ if(type == 0 || type > 3) {
+ // Delete refs for leaks and non overridden allocs
+ delete refd;
+ ptr2ref.erase(it);
+ } // overridden allocs deletes meta-data in clearPtr
+ } else { // Not alloced in erl just delete references
+ if(refd->ref >= global_me->next) { // if it is not part of global ptrs
+ delete refd;
+ ptr2ref.erase(it);
+ }
+ }
+ }
+ }
+ }
+ // Assert ?
+// for(ptrMap::iterator it = ptr2ref.begin(); it != ptr2ref.end(); it++) {
+// wxeRefData *refd = it->second;
+// if(refd->ref >= global_me->next)
+// fprintf(stderr, "L %d %d\r\n", refd->ref, refd->alloc_in_erl);
+// }
+// fflush(stderr);
+ delete memenv;
+ refmap.erase((ErlDrvTermData) Ecmd.port);
+}
+
+wxeMemEnv * WxeApp::getMemEnv(ErlDrvPort port) {
+ return refmap[(ErlDrvTermData) port];
+}
+
+int WxeApp::newPtr(void * ptr, int type, wxeMemEnv *memenv) {
+ int ref;
+ intList free = memenv->free;
+
+ if(free.IsEmpty()) {
+ ref = memenv->next++;
+ } else {
+ ref = free.Pop();
+ };
+ if(ref >= memenv->max) {
+ memenv->max *= 2;
+ memenv->ref2ptr =
+ (void **) driver_realloc(memenv->ref2ptr,memenv->max * sizeof(void*));
+ }
+ memenv->ref2ptr[ref] = ptr;
+
+ if(wxe_debug) {
+ wxString msg;
+ msg.Printf(wxT("Creating {wx_ref, %d, unknown} at %p "), ref, ptr);
+ send_msg("debug", &msg);
+ }
+
+ ptr2ref[ptr] = new wxeRefData(ref, type, true, memenv);
+ // fprintf(stderr, "ptr %x id %d\r\n", (int) ptr,ref);
+ return ref;
+}
+
+int WxeApp::getRef(void * ptr, wxeMemEnv *memenv) {
+ if(!ptr) return 0; // NULL and zero is the same
+ ptrMap::iterator it = ptr2ref.find(ptr);
+ if(it != ptr2ref.end()) {
+ wxeRefData *refd = it->second;
+ return refd->ref;
+ } else { // New Ptr
+ int ref;
+ intList free = memenv->free;
+
+ if(free.IsEmpty()) {
+ ref = memenv->next++;
+ } else {
+ ref = free.Pop();
+ };
+ if(ref >= memenv->max) {
+ memenv->max *= 2;
+ memenv->ref2ptr =
+ (void **) driver_realloc(memenv->ref2ptr,memenv->max * sizeof(void*));
+ }
+
+ memenv->ref2ptr[ref] = ptr;
+ ptr2ref[ptr] = new wxeRefData(ref, 0, false, memenv);
+ return ref;
+ }
+}
+
+void WxeApp::clearPtr(void * ptr) {
+ ptrMap::iterator it;
+ it = ptr2ref.find(ptr);
+
+ if(it != ptr2ref.end()) {
+ wxeRefData *refd = it->second;
+ intList free = refd->memenv->free;
+ int ref = refd->ref;
+ refd->memenv->ref2ptr[ref] = NULL;
+ free.Append(ref);
+
+ if(wxe_debug) {
+ wxString msg;
+ msg.Printf(wxT("Deleting {wx_ref, %d, unknown} at %p "), ref, ptr);
+ send_msg("debug", &msg);
+ }
+
+ if(refd->pid != -1) {
+ // Send terminate pid to owner
+ wxeReturn rt = wxeReturn(WXE_DRV_PORT,refd->memenv->owner, false);
+ rt.addAtom("_wxe_destroy_");
+ rt.add(ERL_DRV_PID, refd->pid);
+ rt.addTupleCount(2);
+ rt.send();
+ refd->pid = -1;
+ };
+ if(refd->type == 1 && ((wxObject*)ptr)->IsKindOf(CLASSINFO(wxSizer))) {
+ wxSizerItemList list = ((wxSizer*)ptr)->GetChildren();
+ for(wxSizerItemList::compatibility_iterator node = list.GetFirst();
+ node; node = node->GetNext()) {
+ wxSizerItem *item = node->GetData();
+ wxObject *content=NULL;
+ if((content = item->GetWindow()))
+ if(ptr2ref.end() == ptr2ref.find(content)) {
+ wxString msg;
+ wxClassInfo *cinfo = ((wxObject *)ptr)->GetClassInfo();
+ msg.Printf(wxT("Double usage detected of window at %p in sizer {wx_ref, %d, %s}"),
+ content, ref, cinfo->GetClassName());
+ send_msg("error", &msg);
+ ((wxSizer*)ptr)->Detach((wxWindow*)content);
+ }
+ if((content = item->GetSizer()))
+ if(ptr2ref.end() == ptr2ref.find(content)) {
+ wxString msg;
+ wxClassInfo *cinfo = ((wxObject *)ptr)->GetClassInfo();
+ msg.Printf(wxT("Double usage detected of sizer at %p in sizer {wx_ref, %d, %s}"),
+ content, ref, cinfo->GetClassName());
+ send_msg("error", &msg);
+ ((wxSizer*)ptr)->Detach((wxSizer*)content);
+ }
+ }
+ }
+
+ delete refd;
+ ptr2ref.erase(it);
+ }
+}
+
+void * WxeApp::getPtr(char * bp, wxeMemEnv *memenv) {
+ int index = *(int *) bp;
+ if(!memenv)
+ throw wxe_badarg(index);
+ void * temp = memenv->ref2ptr[index];
+ if((index < memenv->next) && ((index == 0) || (temp > NULL)))
+ return temp;
+ else
+ throw wxe_badarg(index);
+}
+
+void WxeApp::registerPid(char * bp, ErlDrvTermData pid, wxeMemEnv * memenv) {
+ int index = *(int *) bp;
+ if(!memenv)
+ throw wxe_badarg(index);
+ void * temp = memenv->ref2ptr[index];
+ if((index < memenv->next) && ((index == 0) || (temp > NULL))) {
+ ptrMap::iterator it;
+ it = ptr2ref.find(temp);
+ if(it != ptr2ref.end()) {
+ wxeRefData *refd = it->second;
+ refd->pid = pid;
+ return ;
+ }
+ };
+ throw wxe_badarg(index);
+}
+
+
+/* ************************************************************
+ * Misc utility classes
+ * ************************************************************/
+
+/* ****************************************************************************
+ * Memory handling
+ * ****************************************************************************/
+
+wxeMemEnv::wxeMemEnv() {
+ ref2ptr = (void **) driver_alloc(128*sizeof(void *));
+ ref2ptr[0] = NULL;
+ next = 1;
+ max = 128;
+}
+
+wxeMemEnv::~wxeMemEnv() {
+ driver_free(ref2ptr);
+}
+
+/* ****************************************************************************
+ * Erlang Commands (don't need to be derived of wxEvent anymore should
+ * be re-written to own class struct)
+ * ****************************************************************************/
+
+wxeCommand::wxeCommand(int fc,char * cbuf,int buflen, wxe_data *sd)
+ : wxObject()
+{
+ WXEBinRef *temp, *start, *prev;
+ int n = 0;
+ caller = driver_caller(sd->port);
+ port = sd->port;
+ op = fc;
+ len = buflen;
+ bin[0] = NULL;
+ bin[1] = NULL;
+ bin[2] = NULL;
+
+ if(cbuf) {
+ buffer = (char *) driver_alloc(len);
+ memcpy((void *) buffer, (void *) cbuf, len);;
+
+ temp = sd->bin;
+
+ prev = NULL;
+ start = temp;
+
+ while(temp) {
+ if(caller == temp->from) {
+ bin[n++] = temp;
+ if(prev) {
+ prev->next = temp->next;
+ } else {
+ start = temp->next;
+ }
+ temp = temp->next;
+ } else {
+ prev = temp;
+ temp = temp->next;
+ }
+ }
+ sd->bin = start;
+ } else { // No-op only PING currently
+ buffer = NULL;
+ }
+}
+
+wxeCommand::~wxeCommand() {
+ int n = 0;
+ if(buffer) {
+ while(bin[n]) {
+ if(bin[n]->bin)
+ driver_free_binary(bin[n]->bin);
+ driver_free(bin[n++]);
+ }
+ driver_free(buffer);
+ }
+}
+
+/* ****************************************************************************
+ * TreeItemData
+ * ****************************************************************************/
+
+wxETreeItemData::wxETreeItemData(int sz, char * data) {
+ size = sz;
+ bin = (char *) driver_alloc(sz);
+ memcpy(bin, data, sz);
+}
+
+wxETreeItemData::~wxETreeItemData()
+{
+ driver_free(bin);
+}
+
+/* ****************************************************************************
+ * CallbackData *
+ * ****************************************************************************/
+
+wxeCallbackData::wxeCallbackData(ErlDrvTermData caller,void * req, char *req_type,
+ int funcb, int skip_ev, wxeErlTerm * userData)
+ : wxObject()
+{
+ listener = caller;
+ obj = req;
+ fun_id = funcb;
+ strcpy(class_name, req_type);
+ skip = skip_ev;
+ user_data = userData;
+}
+
+wxeCallbackData::~wxeCallbackData() {
+ // fprintf(stderr, "CBD Deleteing %x %s\r\n", (unsigned int) this, class_name); fflush(stderr);
+ if(user_data) {
+ delete user_data;
+ }
+}
+
+/* ****************************************************************************
+ * wxListCtrlCompare wrapper
+ * ****************************************************************************/
+
+int wxCALLBACK wxEListCtrlCompare(long item1, long item2, long callbackInfoPtr)
+{
+ callbackInfo * cb = (callbackInfo *)callbackInfoPtr;
+ wxeMemEnv * memenv = ((WxeApp *) wxTheApp)->getMemEnv(cb->port);
+ char * bp = ((WxeApp *) wxTheApp)->cb_buff;
+
+ wxeReturn rt = wxeReturn(WXE_DRV_PORT, memenv->owner, false);
+ rt.addInt(cb->callbackID);
+ rt.addInt(item1);
+ rt.addInt(item2);
+ rt.endList(2);
+ rt.addAtom("_wx_invoke_cb_");
+ rt.addTupleCount(3);
+ rt.send();
+ handle_callback_batch(cb->port);
+ return *(int*) bp;
+}