Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

remove blocking eventloop. #1882

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 7 additions & 35 deletions src/gdlwidget.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -633,8 +633,7 @@ WidgetListT GDLWidget::widgetList;
wxImageList *gdlDefaultTreeStateImages;
wxImageList *gdlDefaultTreeImages;

GDLEventQueue GDLWidget::BlockingEventQueue; // the event queue in which all widget events are versed in case of blocking (XMANAGER)
GDLEventQueue GDLWidget::InteractiveEventQueue; // event queue used when no blocking is made -- part of the main GDLEventHandler()
GDLEventQueue GDLWidget::widgetEventQueue; // event queue used by the main GDLEventHandler()
bool GDLWidget::wxIsOn=false;
bool GDLWidget::handlersOk=false;
wxFont GDLWidget::defaultFont=wxNullFont; //the font defined by widget_control,default_font.
Expand Down Expand Up @@ -1252,8 +1251,7 @@ void GDLWidget::SendWidgetTimerEvent(int millisecs) {
}

void GDLWidget::ClearEvents() {
InteractiveEventQueue.Purge(this->GetWidgetID());
BlockingEventQueue.Purge(this->GetWidgetID());
widgetEventQueue.Purge(this->GetWidgetID());
}

void GDLWidget::HandleUnblockedWidgetEvents()
Expand All @@ -1262,7 +1260,7 @@ void GDLWidget::HandleUnblockedWidgetEvents()
CallWXEventLoop();
//treat our GDL events...
DStructGDL* ev = NULL;
while( (ev = GDLWidget::InteractiveEventQueue.Pop()) != NULL)
while( (ev = GDLWidget::widgetEventQueue.Pop()) != NULL)
{
ev = CallEventHandler( ev );

Expand All @@ -1277,22 +1275,7 @@ void GDLWidget::HandleUnblockedWidgetEvents()
}

void GDLWidget::PushEvent( WidgetIDT baseWidgetID, DStructGDL* ev) {
// Get XmanagerActiveCommand status
GDLWidget *baseWidget = GDLWidget::GetWidget( baseWidgetID );
if ( baseWidget != NULL ) {
bool interactive = baseWidget->IsUsingInteractiveEventLoop( );
if ( interactive ) { //non-Blocking: events in InteractiveEventQueue.
#ifdef GDL_DEBUG_WIDGETS
wxMessageOutputStderr().Printf(_T("InteractiveEventQueue.PushEvent: %d\n"),baseWidgetID);
#endif
InteractiveEventQueue.PushBack( ev );
} else { //blocking: events in BlockingEventQueue.
#ifdef GDL_DEBUG_WIDGETS
wxMessageOutputStderr().Printf(_T("BlockingEventQueue.PushEvent: %d\n"),baseWidgetID);
#endif
BlockingEventQueue.PushBack( ev );
}
} else cerr << "NULL baseWidget (possibly Destroyed?) found in GDLWidget::PushEvent( WidgetIDT baseWidgetID=" << baseWidgetID << ", DStructGDL* ev=" << ev << "), please report!\n";
widgetEventQueue.PushBack( ev );
}

void GDLWidget::InformAuthorities(const std::string& message){
Expand All @@ -1302,7 +1285,7 @@ void GDLWidget::InformAuthorities(const std::string& message){
ev->InitTag( "TOP", DLongGDL( 0 ) );
ev->InitTag( "HANDLER", DLongGDL( 0 ) );
ev->InitTag( "MESSAGE", DStringGDL(message) );
InteractiveEventQueue.PushFront( ev ); // push front (will be handled next)
widgetEventQueue.PushFront( ev ); // push front (will be handled next)
}
//return false if already blocked by XManager (one managed realized top Widget is not marked as interactive).
bool GDLWidget::IsXmanagerBlocking()
Expand Down Expand Up @@ -1488,8 +1471,7 @@ void GDLWidget::UnInit() {
if (wxIsStarted()) {
ResetWidgets();
//clear all events --- otherwise baoum!)
InteractiveEventQueue.Purge();
BlockingEventQueue.Purge();
widgetEventQueue.Purge();
// the following cannot be done: once unitialized, the wxWidgets library cannot be safely initilized again.: wxUninitialize( );
UnsetWxStarted(); //reset handlersOk too.
}
Expand Down Expand Up @@ -2542,17 +2524,7 @@ GDLWidgetTopBase::~GDLWidgetTopBase() {
ev->InitTag("ID", DLongGDL(widgetID));
ev->InitTag("TOP", DLongGDL(widgetID));
ev->InitTag("HANDLER", DLongGDL(0));
if (this->IsUsingInteractiveEventLoop()) {
#ifdef GDL_DEBUG_WIDGETS
wxMessageOutputStderr().Printf(_T("~GDLWidgetTopBase InteractiveEventQueue.Push: %d\n"),widgetID);
#endif
InteractiveEventQueue.PushFront(ev); // push front (will be handled next)
} else {
#ifdef GDL_DEBUG_WIDGETS
wxMessageOutputStderr().Printf(_T("~GDLWidgetTopBase BlockingEventQueue.Push: %d\n"),widgetID);
#endif
BlockingEventQueue.PushFront(ev); // push front (will be handled next)
}
widgetEventQueue.PushFront(ev); // push front (will be handled next)
}
/*********************************************************/
// Context Menu pseudo-base
Expand Down
2 changes: 1 addition & 1 deletion src/gdlwidget.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -396,7 +396,7 @@ class GDLWidget
static wxFont defaultFont;
static wxFont systemFont;
static GDLEventQueue BlockingEventQueue;
static GDLEventQueue InteractiveEventQueue;
static GDLEventQueue widgetEventQueue;
static void PushEvent( WidgetIDT baseWidgetID, DStructGDL* ev);
static void InformAuthorities(const std::string& message);

Expand Down
102 changes: 43 additions & 59 deletions src/widget.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2501,74 +2501,58 @@ BaseGDL* widget_info( EnvT* e ) {
int infinity = (nowait) ? 0 : 1;
DStructGDL* ev;

do { // outer while loop, will run once if NOWAIT
do { // outer while loop, will run once if NOWAIT
while (1) { //inner loop, catch controlC, default return if no event trapped in nowait mode
GDLWidget::CallWXEventLoop();
if (!all) {
//specific widget(s)
// we cannot check only readlineEventQueue thinking our XMANAGER in blocking state looks to ALL widgets.
// because XMANAGER may have been called AFTER events are created.
while ((ev = GDLWidget::BlockingEventQueue.Pop()) != NULL) { // get event
static int idIx = ev->Desc()->TagIndex("ID");
id = (*static_cast<DLongGDL*> (ev->GetTag(idIx, 0)))[0]; // get its id
for (SizeT i = 0; i < widgetIDList.size(); i++) { //is ID corresponding to any widget in list?
if (widgetIDList.at(i) == id) { //if yes
ev = CallEventHandler(ev); //process it recursively (going up hierarchy) in eventHandler. Should block waiting for xmanager.
if (ev == NULL) return defaultRes;
else return ev;
}
}
// blocking eventqueue should drain (just Pop() ) when unconcerned interactive events must be preserved
// to be executed normally when widget_event returns (so, pusehd back in InteractiveEventQueue).
}
while ((ev = GDLWidget::InteractiveEventQueue.Pop()) != NULL) { // get event
static int idIx = ev->Desc()->TagIndex("ID");
id = (*static_cast<DLongGDL*> (ev->GetTag(idIx, 0)))[0]; // get its id
for (SizeT i = 0; i < widgetIDList.size(); i++) { //is ID corresponding to any widget in list?
if (widgetIDList.at(i) == id) { //if yes
GDLWidget::CallWXEventLoop();
if (!all) {
//specific widget(s)
while ((ev = GDLWidget::widgetEventQueue.Pop()) != NULL) { // get event
static int idIx = ev->Desc()->TagIndex("ID");
id = (*static_cast<DLongGDL*> (ev->GetTag(idIx, 0)))[0]; // get its id
for (SizeT i = 0; i < widgetIDList.size(); i++) { //is ID corresponding to any widget in list?
if (widgetIDList.at(i) == id) { //if yes
//IMPORTANT: return ev immediately. This is what permits #1685: an event trapped by WIDGET_EVENT does not behave
//like the same event processed in the evenloop.
return ev;
}
}
GDLWidget::InteractiveEventQueue.PushBack(ev);
return ev;
}
}
GDLWidget::widgetEventQueue.PushBack(ev);
GDLWidget::CallWXEventLoop();
// avoid looping like crazy
// avoid looping like crazy
#ifdef _WIN32
Sleep(10); // this just to quiet down the character input from readline. 2 was not enough. 20 was ok.
Sleep(10); // this just to quiet down the character input from readline. 2 was not enough. 20 was ok.
#else
const long SLEEP = 10000000; // 10ms
struct timespec delay;
delay.tv_sec = 0;
delay.tv_nsec = SLEEP; // 20ms
nanosleep(&delay, NULL);
const long SLEEP = 10000000; // 10ms
struct timespec delay;
delay.tv_sec = 0;
delay.tv_nsec = SLEEP; // 20ms
nanosleep(&delay, NULL);
#endif
}
} else {
//wait for ALL . This is the case of /XMANAGER_BLOCK for example. Both queues may be active, some widgets being managed other not.
if ((ev = GDLWidget::BlockingEventQueue.Pop()) != NULL) goto endwait;
if ((ev = GDLWidget::InteractiveEventQueue.Pop()) != NULL) goto endwait;
}
if (nowait) return defaultRes;
if (sigControlC) return defaultRes;
} //end inner loop
//here we got a real event, process it, walking back the hierachy (in CallEventHandler()) for modified ev in case of function handlers.
endwait:
if (blockedByXmanager && ev->Desc( )->Name( ) == "*TOPLEVEL_DESTROYED*" ) {
// deleted widgets list are hopefully handled internally by xmanager
GDLDelete(ev);
return defaultRes;
}
ev = CallEventHandler(ev); //process it recursively (going up hierarchy) in eventHandler. Should block waiting for xmanager.
// examine return:
if (ev == NULL) { //swallowed by a procedure or non-event-stucture returning function
if (nowait) return defaultRes; //else will loop again
} else { // untreated or modified by a function
return ev;
}
}
} else {
//wait for ALL . This is the case of /XMANAGER_BLOCK for example.
if ((ev = GDLWidget::widgetEventQueue.Pop()) != NULL) goto endwait;
}
if (nowait) return defaultRes;
if (sigControlC) return defaultRes;
} //end inner loop
//here we got a real event, process it, walking back the hierachy (in CallEventHandler()) for modified ev in case of function handlers.
endwait:
if (blockedByXmanager && ev->Desc()->Name() == "*TOPLEVEL_DESTROYED*") {
// deleted widgets list are hopefully handled internally by xmanager
GDLDelete(ev);
return defaultRes;
}
ev = CallEventHandler(ev); //process it recursively (going up hierarchy) in eventHandler. Should block waiting for xmanager.
// examine return:
if (ev == NULL) { //swallowed by a procedure or non-event-stucture returning function
if (nowait) return defaultRes; //else will loop again
} else { // untreated or modified by a function
return ev;
}
GDLWidget::CallWXEventLoop();

} while (infinity);
} while (infinity);
return NULL; //pacifier.
#endif //HAVE_LIBWXWIDGETS
}
Expand Down
37 changes: 31 additions & 6 deletions testsuite/interactive_tests/test_widgets.pro
Original file line number Diff line number Diff line change
Expand Up @@ -173,10 +173,16 @@ pro list_event,event
toto=["A","list","created","with","WIDGET_LIST","YSIZE=3"]
print,toto[event.index]
end

; called by XMANAGER : main eventloop
pro handle_Event,ev
common mycount,count
common pixmaps,green_bmp,red_bmp
help,ev,/str
common forprogressbar,progressbar,pbarid,pbarpos

; avoid to report timer events
if tag_names(ev, /structure_name) ne 'WIDGET_TIMER' then help,ev,/str

if tag_names(ev, /structure_name) eq 'WIDGET_KILL_REQUEST' then begin
acceptance=dialog_message(dialog_parent=ev.id,"I Do want to close the window", /CANCEL, /DEFAULT_NO,/QUESTION) ; +strtrim(ev.id,2))
if acceptance eq "Yes" then begin
Expand Down Expand Up @@ -230,7 +236,7 @@ pro handle_Event,ev
return
endif

print,"uvalue.type=",uv.type
if uv.type ne 'timer' then print,"uvalue.type=",uv.type
case uv.type of
'file': begin
widget_control,ev.id,get_value=value ;& print,value
Expand Down Expand Up @@ -262,6 +268,9 @@ pro handle_Event,ev
if val eq 'ON' then begin
widget_control,ev.id,set_value = 'OFF'
endif else begin
vv=widget_info(/xmanager)
widget_control,ev.id,set_value = "MANAGED: "+strtrim(vv,2)
wait,1
widget_control,ev.id,set_value = 'ON'
endelse
end
Expand All @@ -275,6 +284,14 @@ pro handle_Event,ev
widget_control,ev.id,set_value = green_bmp, set_uvalue= val
endelse
end
'timer': begin
wset,pbarid
pbarpos += 5
pbarpos MOD= 300
ERASE, 255
POLYFILL, pbarpos+[0,0,5,5], [0, 19, 19,0], /DEVICE, color=140
WIDGET_CONTROL, ev.id, TIMER=.2
end
'quit': widget_control,ev.top,/DESTROY
else: begin
print, "(other, not treated, event: ok)"
Expand Down Expand Up @@ -321,7 +338,8 @@ siz= widget_button(menu,VALUE="Resize (error)",EVENT_PRO="resize_gui") ; 5
pro test_widgets,table,help=help,nocanvas=nocanvas,notree=notree,block=block,fontname=fontname,present=present,select=select,_extra=extra
common mycount,count
common pixmaps,green_bmp,red_bmp

common forprogressbar,progressbar,pbarid,pbarpos

green_bmp= bytarr(7,7,3)& green_bmp[*,*,1] = 255& & green_bmp[0,0,1] = 254
red_bmp= bytarr(7,7,3)& red_bmp[*,*,0] = 255& & red_bmp[0,0,0] = 254
if (n_elements(select) gt 0) then present=select
Expand Down Expand Up @@ -364,7 +382,9 @@ ev = {vEv,type:'',pos:[0,0]}
base = WIDGET_BASE(/col,MBAR=mbar,title=title,event_pro='base_event_nok',kill_notify='cleanup',/tlb_kill_request_events,/tlb_size_events) ; ---> PROBLEM: ,/tlb_size_events) ;,/scroll)
doMbar,mbar,fontname
;mysize=widget_info(base,string_size='012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234')

; add a progress bar to test timer
progressbar = WIDGET_DRAW(base, XSIZE=300, YSIZE=20, UVALUE={vEv,'timer',[0,0]})
pbarpos=0
; define a tabbed base that contains everything:
label=widget_label(base,value='to best mimic IDL`s widgets, call GDL ',/align_left)
label=widget_label(base,value='with option "--widget-compat" ',/align_left)
Expand Down Expand Up @@ -738,7 +758,9 @@ widget_control,base,notify_realize='i_am_realized'
;Realize the widgets.
WIDGET_CONTROL, /REALIZE, base

;;Obtain the window index.
;;Obtain the window index.
WIDGET_CONTROL, progressbar, GET_VALUE = pbarId

if ~keyword_set(nocanvas) and total(strcmp('DRAW',present,/fold)) then begin
print,"Draw widgets:",draw,draw2
WIDGET_CONTROL, draw, GET_VALUE = index
Expand Down Expand Up @@ -767,5 +789,8 @@ print,"Draw widgets:",draw,draw2
tv,image,10,10,/data; ,/true
endif

xmanager,"handle",base,cleanup="cleanup_xmanager",no_block=~block
; create a timer event --- otherwise will not be active and thus not catched in eventloop
widget_control,progressbar,timer=0

xmanager,"handle",base,cleanup="cleanup_xmanager";,no_block=~block
end
Loading