diff options
Diffstat (limited to 'lib/wx/c_src/wxe_impl.cpp')
-rw-r--r-- | lib/wx/c_src/wxe_impl.cpp | 409 |
1 files changed, 212 insertions, 197 deletions
diff --git a/lib/wx/c_src/wxe_impl.cpp b/lib/wx/c_src/wxe_impl.cpp index f617aaf349..1510866f09 100644 --- a/lib/wx/c_src/wxe_impl.cpp +++ b/lib/wx/c_src/wxe_impl.cpp @@ -1,18 +1,19 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2008-2014. All Rights Reserved. + * Copyright Ericsson AB 2008-2017. 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/. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * 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. + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. * * %CopyrightEnd% */ @@ -55,9 +56,9 @@ extern ErlDrvCond * wxe_batch_locker_c; extern ErlDrvTermData init_caller; extern int wxe_status; -wxList * wxe_batch = NULL; -wxList * wxe_batch_cb_saved = NULL; -int wxe_batch_caller = 0; // inside batch if larger than 0 +wxeFifo * wxe_queue = NULL; + +unsigned int wxe_needs_signal = 0; // inside batch if larger than 0 /* ************************************************************ * Commands from erlang @@ -68,38 +69,37 @@ void push_command(int op,char * buf,int len, wxe_data *sd) { /* fprintf(stderr, "Op %d %d [%ld] %d\r\n", op, (int) driver_caller(sd->port_handle), wxe_batch->size(), wxe_batch_caller),fflush(stderr); */ - wxeCommand *Cmd = new wxeCommand(op, buf, len, sd); erl_drv_mutex_lock(wxe_batch_locker_m); - wxe_batch->Append(Cmd); + wxe_queue->Add(op, buf, len, sd); - if(wxe_batch_caller > 0) { + if(wxe_needs_signal) { // wx-thread is waiting on batch end in cond_wait erl_drv_cond_signal(wxe_batch_locker_c); + erl_drv_mutex_unlock(wxe_batch_locker_m); } else { // wx-thread is waiting gui-events - if(op == WXE_BATCH_BEGIN) { - wxe_batch_caller = 1; - } - erl_drv_cond_signal(wxe_batch_locker_c); + erl_drv_mutex_unlock(wxe_batch_locker_m); wxWakeUpIdle(); } - erl_drv_mutex_unlock(wxe_batch_locker_m); } void meta_command(int what, wxe_data *sd) { - if(what == PING_PORT) { + if(what == PING_PORT && wxe_status == WXE_INITIATED) { 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); + if(wxe_needs_signal) { + wxe_queue->Add(WXE_DEBUG_PING, NULL, 0, sd); erl_drv_cond_signal(wxe_batch_locker_c); } wxWakeUpIdle(); erl_drv_mutex_unlock(wxe_batch_locker_m); } else { - if(sd) { + if(sd && wxe_status == WXE_INITIATED) { wxeMetaCommand Cmd(sd, what); wxTheApp->AddPendingEvent(Cmd); + if(what == DELETE_PORT) { + driver_free(sd->bin); + free(sd); + } } } } @@ -121,15 +121,14 @@ bool WxeApp::OnInit() { global_me = new wxeMemEnv(); - wxe_batch = new wxList; - wxe_batch_cb_saved = new wxList; + wxe_queue = new wxeFifo(2000); cb_buff = NULL; recurse_level = 0; - delayed_cleanup = new wxList; - delayed_delete = new wxList; + delayed_delete = new wxeFifo(100); + delayed_cleanup = new wxList; wxe_ps_init2(); - // wxIdleEvent::SetMode(wxIDLE_PROCESS_SPECIFIED); // Hmm printpreview doesn't work in 2.9 with this + wxIdleEvent::SetMode(wxIDLE_PROCESS_SPECIFIED); Connect(wxID_ANY, wxEVT_IDLE, (wxObjectEventFunction) (wxEventFunction) &WxeApp::idle); Connect(CREATE_PORT, wxeEVT_META_COMMAND,(wxObjectEventFunction) (wxEventFunction) &WxeApp::newMemEnv); @@ -168,7 +167,9 @@ void WxeApp::MacOpenFile(const wxString &filename) { #endif void WxeApp::shutdown(wxeMetaCommand& Ecmd) { + wxe_status = WXE_EXITING; ExitMainLoop(); + delete wxe_queue; } void WxeApp::dummy_close(wxEvent& Ev) { @@ -177,10 +178,30 @@ void WxeApp::dummy_close(wxEvent& Ev) { // windows open, and this will kill the erlang, override default handling } +void WxeApp::OnAssertFailure(const wxChar *file, int line, const wxChar *cfunc, + const wxChar *cond, const wxChar *cmsgUser) { + wxString msg; + wxString func(cfunc); + wxString msgUser(cmsgUser); + + msg.Printf(wxT("wxWidgets Assert failure: %s(%d): \"%s\""), + file, line, cond); + if ( !func.empty() ) { + msg << wxT(" in ") << func << wxT("()"); + } + // and the message itself + if ( !msgUser.empty() ) { + msg << wxT(" : ") << msgUser; + } + + send_msg("error", &msg); +} + // Called by wx thread void WxeApp::idle(wxIdleEvent& event) { event.Skip(true); - dispatch_cmds(); + if(dispatch_cmds()) + event.RequestMore(); } /* ************************************************************ @@ -197,41 +218,42 @@ void handle_event_callback(ErlDrvPort port, ErlDrvTermData process) { WxeApp * app = (WxeApp *) wxTheApp; ErlDrvMonitor monitor; + + if(wxe_status != WXE_INITIATED) + return; + // Is thread safe if pdl have been incremented if(driver_monitor_process(port, process, &monitor) == 0) { // Should we be able to handle commands when recursing? probably - erl_drv_mutex_lock(wxe_batch_locker_m); - //fprintf(stderr, "\r\nCB EV Start %lu \r\n", process);fflush(stderr); + // fprintf(stderr, "\r\nCB EV Start %lu \r\n", process);fflush(stderr); app->recurse_level++; - app->dispatch_cb(wxe_batch, wxe_batch_cb_saved, process); + app->dispatch_cb(wxe_queue, process); app->recurse_level--; - //fprintf(stderr, "CB EV done %lu \r\n", process);fflush(stderr); - wxe_batch_caller = 0; - erl_drv_mutex_unlock(wxe_batch_locker_m); + // fprintf(stderr, "CB EV done %lu \r\n", process);fflush(stderr); driver_demonitor_process(port, &monitor); } } -void WxeApp::dispatch_cmds() +int WxeApp::dispatch_cmds() { - erl_drv_mutex_lock(wxe_batch_locker_m); + int more = 0; + if(wxe_status != WXE_INITIATED) + return more; recurse_level++; - int level = dispatch(wxe_batch_cb_saved, 0, WXE_STORED); - dispatch(wxe_batch, level, WXE_NORMAL); + // fprintf(stderr, "\r\ndispatch_normal %d\r\n", recurse_level);fflush(stderr); + wxe_queue->cb_start = 0; + more = dispatch(wxe_queue); + // fprintf(stderr, "\r\ndispatch_done %d\r\n", recurse_level);fflush(stderr); recurse_level--; - wxe_batch_caller = 0; - erl_drv_mutex_unlock(wxe_batch_locker_m); + // Cleanup old memenv's and deleted objects if(recurse_level == 0) { - if(delayed_delete->size() > 0) - for( wxList::compatibility_iterator node = delayed_delete->GetFirst(); - node; - node = delayed_delete->GetFirst()) { - wxeCommand *event = (wxeCommand *)node->GetData(); - delayed_delete->Erase(node); - wxe_dispatch(*event); - event->Delete(); - } + wxeCommand *curr; + while((curr = delayed_delete->Get()) != NULL) { + wxe_dispatch(*curr); + curr->Delete(); + } + delayed_delete->Cleanup(); if(delayed_cleanup->size() > 0) for( wxList::compatibility_iterator node = delayed_cleanup->GetFirst(); node; @@ -242,154 +264,137 @@ void WxeApp::dispatch_cmds() delete event; } } + return more; } -// 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) +#define BREAK_BATCH 10000 + +int WxeApp::dispatch(wxeFifo * batch) { 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 - if(event->len > 0) { - cb_buff = (char *) driver_alloc(event->len); - 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; - } - event->Delete(); - } - } 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; + int blevel = 0; + int wait = 0; // Let event handling generate events sometime + wxeCommand *event; + erl_drv_mutex_lock(wxe_batch_locker_m); + while(true) { + while((event = batch->Get()) != NULL) { + erl_drv_mutex_unlock(wxe_batch_locker_m); + switch(event->op) { + case WXE_BATCH_END: + if(blevel>0) { + blevel--; + if(blevel==0) + wait += BREAK_BATCH/4; + } + 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: + if(event->len > 0) { + cb_buff = (char *) driver_alloc(event->len); + memcpy(cb_buff, event->buffer, event->len); } - // 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); + event->Delete(); + return 1; + default: + 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); } + break; + } + event->Delete(); + erl_drv_mutex_lock(wxe_batch_locker_m); + batch->Cleanup(); + } + if(blevel <= 0 || wait >= BREAK_BATCH) { + erl_drv_mutex_unlock(wxe_batch_locker_m); + if(blevel > 0) { + return 1; // We are still in a batch but we can let wx check for events + } else { + return 0; } } + // sleep until something happens + // fprintf(stderr, "%s:%d sleep %d %d %d\r\n", __FILE__, __LINE__, batch->m_n, blevel, wait);fflush(stderr); + wxe_needs_signal = 1; + wait += 1; + while(batch->m_n == 0) { + erl_drv_cond_wait(wxe_batch_locker_c, wxe_batch_locker_m); + } + wxe_needs_signal = 0; + } } -void WxeApp::dispatch_cb(wxList * batch, wxList * temp, ErlDrvTermData process) { - int callback_returned = 0; +void WxeApp::dispatch_cb(wxeFifo * batch, ErlDrvTermData process) { + wxeCommand *event; + unsigned int peek; + erl_drv_mutex_lock(wxe_batch_locker_m); + peek = batch->Cleanup(batch->cb_start); while(true) { - if (batch->size() > 0) { - for( wxList::compatibility_iterator node = batch->GetFirst(); - node; - node = batch->GetFirst()) - { - wxeCommand *event = (wxeCommand *)node->GetData(); - wxeMemEnv *memenv = getMemEnv(event->port); - batch->Erase(node); - // fprintf(stderr, " Ev %d %lu\r\n", event->op, event->caller); - if(event->caller == process || // Callbacks from CB process only - event->op == WXE_CB_START || // Event callback start change process - event->op == WXE_CB_DIED || // Event callback process died - // Allow connect_cb during CB i.e. msg from wxe_server. - (memenv && event->caller == memenv->owner)) - { - switch(event->op) { - case WXE_BATCH_END: - case WXE_BATCH_BEGIN: - case WXE_DEBUG_PING: - break; - case WXE_CB_RETURN: - if(event->len > 0) { - cb_buff = (char *) driver_alloc(event->len); - memcpy(cb_buff, event->buffer, event->len); - } // continue - case WXE_CB_DIED: - 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); - size_t start=temp->GetCount(); - 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); - if(temp->GetCount() > start) { - // We have recursed dispatch_cb and messages for this - // callback may be saved on temp list move them - // to orig list - for(wxList::compatibility_iterator node = temp->Item(start); - node; - node = node->GetNext()) { - wxeCommand *ev = (wxeCommand *)node->GetData(); - if(ev->caller == process) { - batch->Append(ev); - temp->Erase(node); - } - } - } - if(callback_returned) - return; - break; - } - event->Delete(); - } else { - // fprintf(stderr, " save %d \r\n", event->op); - temp->Append(event); + while((event = batch->Peek(&peek)) != NULL) { + wxeMemEnv *memenv = getMemEnv(event->port); + // fprintf(stderr, " Ev %d %lu\r\n", event->op, event->caller); + if(event->caller == process || // Callbacks from CB process only + event->op == WXE_CB_START || // Event callback start change process + event->op == WXE_CB_DIED || // Event callback process died + // Allow connect_cb during CB i.e. msg from wxe_server. + (memenv && event->caller == memenv->owner)) { + erl_drv_mutex_unlock(wxe_batch_locker_m); + switch(event->op) { + case WXE_BATCH_END: + case WXE_BATCH_BEGIN: + case WXE_DEBUG_PING: + break; + case WXE_CB_RETURN: + if(event->len > 0) { + cb_buff = (char *) driver_alloc(event->len); + memcpy(cb_buff, event->buffer, event->len); + } // continue + case WXE_CB_DIED: + batch->cb_start = 0; + event->Delete(); + erl_drv_mutex_lock(wxe_batch_locker_m); + batch->Strip(); + erl_drv_mutex_unlock(wxe_batch_locker_m); + return; + case WXE_CB_START: + // CB start from now accept message from CB process only + process = event->caller; + break; + default: + batch->cb_start = peek; // In case of recursive callbacks + if(event->op < OPENGL_START) { + wxe_dispatch(*event); + } else { + gl_dispatch(event->op,event->buffer,event->caller,event->bin); } + break; } - } 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); + event->Delete(); + erl_drv_mutex_lock(wxe_batch_locker_m); + peek = batch->Cleanup(peek); } } + // sleep until something happens + // fprintf(stderr, "%s:%d sleep %d %d\r\n", __FILE__, __LINE__, + // peek, batch->m_n);fflush(stderr); + wxe_needs_signal = 1; + while(peek >= batch->m_n) { + erl_drv_cond_wait(wxe_batch_locker_c, wxe_batch_locker_m); + peek = batch->Cleanup(peek); + } + wxe_needs_signal = 0; } } @@ -500,7 +505,7 @@ void WxeApp::destroyMemEnv(wxeMetaCommand& Ecmd) if(it != ptr2ref.end()) { wxeRefData *refd = it->second; if(refd->alloc_in_erl) { - if((refd->type == 1) && ((wxObject *)ptr)->IsKindOf(CLASSINFO(wxBufferedDC))) { + if((refd->type == 8) && ((wxObject *)ptr)->IsKindOf(CLASSINFO(wxBufferedDC))) { ((wxBufferedDC *)ptr)->m_dc = NULL; // Workaround } wxString msg; @@ -510,7 +515,7 @@ void WxeApp::destroyMemEnv(wxeMetaCommand& Ecmd) msg.Printf(wxT("Memory leak: {wx_ref, %d, %s}"), refd->ref, cinfo->GetClassName()); send_msg("error", &msg); - } else { + } else if(refd->type != 4) { cleanup_ref = delete_object(ptr, refd); } if(cleanup_ref) { @@ -539,6 +544,17 @@ void WxeApp::destroyMemEnv(wxeMetaCommand& Ecmd) refmap.erase((ErlDrvTermData) Ecmd.port); } + +wxeRefData * WxeApp::getRefData(void *ptr) { + ptrMap::iterator it = ptr2ref.find(ptr); + if(it != ptr2ref.end()) { + wxeRefData *refd = it->second; + return refd; + } + return NULL; +} + + wxeMemEnv * WxeApp::getMemEnv(ErlDrvTermData port) { return refmap[port]; } @@ -561,7 +577,12 @@ int WxeApp::newPtr(void * ptr, int type, wxeMemEnv *memenv) { if(wxe_debug) { wxString msg; - msg.Printf(wxT("Creating {wx_ref, %d, unknown} at %p "), ref, ptr); + const wxChar *class_info = wxT("unknown"); + if(type < 10) { + wxClassInfo *cinfo = ((wxObject *)ptr)->GetClassInfo(); + class_info = cinfo->GetClassName(); + } + msg.Printf(wxT("Creating {wx_ref, %d, %s} at %p "), ref, class_info, ptr); send_msg("debug", &msg); } @@ -613,12 +634,6 @@ void WxeApp::clearPtr(void * ptr) { 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(((int) refd->pid) != -1) { // Send terminate pid to owner wxeReturn rt = wxeReturn(WXE_DRV_PORT,refd->pid, false); @@ -666,7 +681,7 @@ void * WxeApp::getPtr(char * bp, wxeMemEnv *memenv) { throw wxe_badarg(index); } void * temp = memenv->ref2ptr[index]; - if((index < memenv->next) && ((index == 0) || (temp > NULL))) + if((index < memenv->next) && ((index == 0) || (temp != (void *)NULL))) return temp; else { throw wxe_badarg(index); @@ -678,7 +693,7 @@ void WxeApp::registerPid(char * bp, ErlDrvTermData pid, wxeMemEnv * memenv) { if(!memenv) throw wxe_badarg(index); void * temp = memenv->ref2ptr[index]; - if((index < memenv->next) && ((index == 0) || (temp > NULL))) { + if((index < memenv->next) && ((index == 0) || (temp != (void *) NULL))) { ptrMap::iterator it; it = ptr2ref.find(temp); if(it != ptr2ref.end()) { |