Skip to content

Commit 61cbc2a

Browse files
authored
remove blocking eventloop. (#1882)
1 parent fb0caa0 commit 61cbc2a

File tree

4 files changed

+82
-101
lines changed

4 files changed

+82
-101
lines changed

src/gdlwidget.cpp

+7-35
Original file line numberDiff line numberDiff line change
@@ -633,8 +633,7 @@ WidgetListT GDLWidget::widgetList;
633633
wxImageList *gdlDefaultTreeStateImages;
634634
wxImageList *gdlDefaultTreeImages;
635635

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

12541253
void GDLWidget::ClearEvents() {
1255-
InteractiveEventQueue.Purge(this->GetWidgetID());
1256-
BlockingEventQueue.Purge(this->GetWidgetID());
1254+
widgetEventQueue.Purge(this->GetWidgetID());
12571255
}
12581256

12591257
void GDLWidget::HandleUnblockedWidgetEvents()
@@ -1262,7 +1260,7 @@ void GDLWidget::HandleUnblockedWidgetEvents()
12621260
CallWXEventLoop();
12631261
//treat our GDL events...
12641262
DStructGDL* ev = NULL;
1265-
while( (ev = GDLWidget::InteractiveEventQueue.Pop()) != NULL)
1263+
while( (ev = GDLWidget::widgetEventQueue.Pop()) != NULL)
12661264
{
12671265
ev = CallEventHandler( ev );
12681266

@@ -1277,22 +1275,7 @@ void GDLWidget::HandleUnblockedWidgetEvents()
12771275
}
12781276

12791277
void GDLWidget::PushEvent( WidgetIDT baseWidgetID, DStructGDL* ev) {
1280-
// Get XmanagerActiveCommand status
1281-
GDLWidget *baseWidget = GDLWidget::GetWidget( baseWidgetID );
1282-
if ( baseWidget != NULL ) {
1283-
bool interactive = baseWidget->IsUsingInteractiveEventLoop( );
1284-
if ( interactive ) { //non-Blocking: events in InteractiveEventQueue.
1285-
#ifdef GDL_DEBUG_WIDGETS
1286-
wxMessageOutputStderr().Printf(_T("InteractiveEventQueue.PushEvent: %d\n"),baseWidgetID);
1287-
#endif
1288-
InteractiveEventQueue.PushBack( ev );
1289-
} else { //blocking: events in BlockingEventQueue.
1290-
#ifdef GDL_DEBUG_WIDGETS
1291-
wxMessageOutputStderr().Printf(_T("BlockingEventQueue.PushEvent: %d\n"),baseWidgetID);
1292-
#endif
1293-
BlockingEventQueue.PushBack( ev );
1294-
}
1295-
} else cerr << "NULL baseWidget (possibly Destroyed?) found in GDLWidget::PushEvent( WidgetIDT baseWidgetID=" << baseWidgetID << ", DStructGDL* ev=" << ev << "), please report!\n";
1278+
widgetEventQueue.PushBack( ev );
12961279
}
12971280

12981281
void GDLWidget::InformAuthorities(const std::string& message){
@@ -1302,7 +1285,7 @@ void GDLWidget::InformAuthorities(const std::string& message){
13021285
ev->InitTag( "TOP", DLongGDL( 0 ) );
13031286
ev->InitTag( "HANDLER", DLongGDL( 0 ) );
13041287
ev->InitTag( "MESSAGE", DStringGDL(message) );
1305-
InteractiveEventQueue.PushFront( ev ); // push front (will be handled next)
1288+
widgetEventQueue.PushFront( ev ); // push front (will be handled next)
13061289
}
13071290
//return false if already blocked by XManager (one managed realized top Widget is not marked as interactive).
13081291
bool GDLWidget::IsXmanagerBlocking()
@@ -1488,8 +1471,7 @@ void GDLWidget::UnInit() {
14881471
if (wxIsStarted()) {
14891472
ResetWidgets();
14901473
//clear all events --- otherwise baoum!)
1491-
InteractiveEventQueue.Purge();
1492-
BlockingEventQueue.Purge();
1474+
widgetEventQueue.Purge();
14931475
// the following cannot be done: once unitialized, the wxWidgets library cannot be safely initilized again.: wxUninitialize( );
14941476
UnsetWxStarted(); //reset handlersOk too.
14951477
}
@@ -2542,17 +2524,7 @@ GDLWidgetTopBase::~GDLWidgetTopBase() {
25422524
ev->InitTag("ID", DLongGDL(widgetID));
25432525
ev->InitTag("TOP", DLongGDL(widgetID));
25442526
ev->InitTag("HANDLER", DLongGDL(0));
2545-
if (this->IsUsingInteractiveEventLoop()) {
2546-
#ifdef GDL_DEBUG_WIDGETS
2547-
wxMessageOutputStderr().Printf(_T("~GDLWidgetTopBase InteractiveEventQueue.Push: %d\n"),widgetID);
2548-
#endif
2549-
InteractiveEventQueue.PushFront(ev); // push front (will be handled next)
2550-
} else {
2551-
#ifdef GDL_DEBUG_WIDGETS
2552-
wxMessageOutputStderr().Printf(_T("~GDLWidgetTopBase BlockingEventQueue.Push: %d\n"),widgetID);
2553-
#endif
2554-
BlockingEventQueue.PushFront(ev); // push front (will be handled next)
2555-
}
2527+
widgetEventQueue.PushFront(ev); // push front (will be handled next)
25562528
}
25572529
/*********************************************************/
25582530
// Context Menu pseudo-base

src/gdlwidget.hpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -396,7 +396,7 @@ class GDLWidget
396396
static wxFont defaultFont;
397397
static wxFont systemFont;
398398
static GDLEventQueue BlockingEventQueue;
399-
static GDLEventQueue InteractiveEventQueue;
399+
static GDLEventQueue widgetEventQueue;
400400
static void PushEvent( WidgetIDT baseWidgetID, DStructGDL* ev);
401401
static void InformAuthorities(const std::string& message);
402402

src/widget.cpp

+43-59
Original file line numberDiff line numberDiff line change
@@ -2501,74 +2501,58 @@ BaseGDL* widget_info( EnvT* e ) {
25012501
int infinity = (nowait) ? 0 : 1;
25022502
DStructGDL* ev;
25032503

2504-
do { // outer while loop, will run once if NOWAIT
2504+
do { // outer while loop, will run once if NOWAIT
25052505
while (1) { //inner loop, catch controlC, default return if no event trapped in nowait mode
2506-
GDLWidget::CallWXEventLoop();
2507-
if (!all) {
2508-
//specific widget(s)
2509-
// we cannot check only readlineEventQueue thinking our XMANAGER in blocking state looks to ALL widgets.
2510-
// because XMANAGER may have been called AFTER events are created.
2511-
while ((ev = GDLWidget::BlockingEventQueue.Pop()) != NULL) { // get event
2512-
static int idIx = ev->Desc()->TagIndex("ID");
2513-
id = (*static_cast<DLongGDL*> (ev->GetTag(idIx, 0)))[0]; // get its id
2514-
for (SizeT i = 0; i < widgetIDList.size(); i++) { //is ID corresponding to any widget in list?
2515-
if (widgetIDList.at(i) == id) { //if yes
2516-
ev = CallEventHandler(ev); //process it recursively (going up hierarchy) in eventHandler. Should block waiting for xmanager.
2517-
if (ev == NULL) return defaultRes;
2518-
else return ev;
2519-
}
2520-
}
2521-
// blocking eventqueue should drain (just Pop() ) when unconcerned interactive events must be preserved
2522-
// to be executed normally when widget_event returns (so, pusehd back in InteractiveEventQueue).
2523-
}
2524-
while ((ev = GDLWidget::InteractiveEventQueue.Pop()) != NULL) { // get event
2525-
static int idIx = ev->Desc()->TagIndex("ID");
2526-
id = (*static_cast<DLongGDL*> (ev->GetTag(idIx, 0)))[0]; // get its id
2527-
for (SizeT i = 0; i < widgetIDList.size(); i++) { //is ID corresponding to any widget in list?
2528-
if (widgetIDList.at(i) == id) { //if yes
2506+
GDLWidget::CallWXEventLoop();
2507+
if (!all) {
2508+
//specific widget(s)
2509+
while ((ev = GDLWidget::widgetEventQueue.Pop()) != NULL) { // get event
2510+
static int idIx = ev->Desc()->TagIndex("ID");
2511+
id = (*static_cast<DLongGDL*> (ev->GetTag(idIx, 0)))[0]; // get its id
2512+
for (SizeT i = 0; i < widgetIDList.size(); i++) { //is ID corresponding to any widget in list?
2513+
if (widgetIDList.at(i) == id) { //if yes
25292514
//IMPORTANT: return ev immediately. This is what permits #1685: an event trapped by WIDGET_EVENT does not behave
25302515
//like the same event processed in the evenloop.
2531-
return ev;
2532-
}
2533-
}
2534-
GDLWidget::InteractiveEventQueue.PushBack(ev);
2516+
return ev;
2517+
}
2518+
}
2519+
GDLWidget::widgetEventQueue.PushBack(ev);
25352520
GDLWidget::CallWXEventLoop();
2536-
// avoid looping like crazy
2521+
// avoid looping like crazy
25372522
#ifdef _WIN32
2538-
Sleep(10); // this just to quiet down the character input from readline. 2 was not enough. 20 was ok.
2523+
Sleep(10); // this just to quiet down the character input from readline. 2 was not enough. 20 was ok.
25392524
#else
2540-
const long SLEEP = 10000000; // 10ms
2541-
struct timespec delay;
2542-
delay.tv_sec = 0;
2543-
delay.tv_nsec = SLEEP; // 20ms
2544-
nanosleep(&delay, NULL);
2525+
const long SLEEP = 10000000; // 10ms
2526+
struct timespec delay;
2527+
delay.tv_sec = 0;
2528+
delay.tv_nsec = SLEEP; // 20ms
2529+
nanosleep(&delay, NULL);
25452530
#endif
2546-
}
2547-
} else {
2548-
//wait for ALL . This is the case of /XMANAGER_BLOCK for example. Both queues may be active, some widgets being managed other not.
2549-
if ((ev = GDLWidget::BlockingEventQueue.Pop()) != NULL) goto endwait;
2550-
if ((ev = GDLWidget::InteractiveEventQueue.Pop()) != NULL) goto endwait;
2551-
}
2552-
if (nowait) return defaultRes;
2553-
if (sigControlC) return defaultRes;
2554-
} //end inner loop
2555-
//here we got a real event, process it, walking back the hierachy (in CallEventHandler()) for modified ev in case of function handlers.
2556-
endwait:
2557-
if (blockedByXmanager && ev->Desc( )->Name( ) == "*TOPLEVEL_DESTROYED*" ) {
2558-
// deleted widgets list are hopefully handled internally by xmanager
2559-
GDLDelete(ev);
2560-
return defaultRes;
2561-
}
2562-
ev = CallEventHandler(ev); //process it recursively (going up hierarchy) in eventHandler. Should block waiting for xmanager.
2563-
// examine return:
2564-
if (ev == NULL) { //swallowed by a procedure or non-event-stucture returning function
2565-
if (nowait) return defaultRes; //else will loop again
2566-
} else { // untreated or modified by a function
2567-
return ev;
2568-
}
2531+
}
2532+
} else {
2533+
//wait for ALL . This is the case of /XMANAGER_BLOCK for example.
2534+
if ((ev = GDLWidget::widgetEventQueue.Pop()) != NULL) goto endwait;
2535+
}
2536+
if (nowait) return defaultRes;
2537+
if (sigControlC) return defaultRes;
2538+
} //end inner loop
2539+
//here we got a real event, process it, walking back the hierachy (in CallEventHandler()) for modified ev in case of function handlers.
2540+
endwait:
2541+
if (blockedByXmanager && ev->Desc()->Name() == "*TOPLEVEL_DESTROYED*") {
2542+
// deleted widgets list are hopefully handled internally by xmanager
2543+
GDLDelete(ev);
2544+
return defaultRes;
2545+
}
2546+
ev = CallEventHandler(ev); //process it recursively (going up hierarchy) in eventHandler. Should block waiting for xmanager.
2547+
// examine return:
2548+
if (ev == NULL) { //swallowed by a procedure or non-event-stucture returning function
2549+
if (nowait) return defaultRes; //else will loop again
2550+
} else { // untreated or modified by a function
2551+
return ev;
2552+
}
25692553
GDLWidget::CallWXEventLoop();
25702554

2571-
} while (infinity);
2555+
} while (infinity);
25722556
return NULL; //pacifier.
25732557
#endif //HAVE_LIBWXWIDGETS
25742558
}

testsuite/interactive_tests/test_widgets.pro

+31-6
Original file line numberDiff line numberDiff line change
@@ -173,10 +173,16 @@ pro list_event,event
173173
toto=["A","list","created","with","WIDGET_LIST","YSIZE=3"]
174174
print,toto[event.index]
175175
end
176+
177+
; called by XMANAGER : main eventloop
176178
pro handle_Event,ev
177179
common mycount,count
178180
common pixmaps,green_bmp,red_bmp
179-
help,ev,/str
181+
common forprogressbar,progressbar,pbarid,pbarpos
182+
183+
; avoid to report timer events
184+
if tag_names(ev, /structure_name) ne 'WIDGET_TIMER' then help,ev,/str
185+
180186
if tag_names(ev, /structure_name) eq 'WIDGET_KILL_REQUEST' then begin
181187
acceptance=dialog_message(dialog_parent=ev.id,"I Do want to close the window", /CANCEL, /DEFAULT_NO,/QUESTION) ; +strtrim(ev.id,2))
182188
if acceptance eq "Yes" then begin
@@ -230,7 +236,7 @@ pro handle_Event,ev
230236
return
231237
endif
232238

233-
print,"uvalue.type=",uv.type
239+
if uv.type ne 'timer' then print,"uvalue.type=",uv.type
234240
case uv.type of
235241
'file': begin
236242
widget_control,ev.id,get_value=value ;& print,value
@@ -262,6 +268,9 @@ pro handle_Event,ev
262268
if val eq 'ON' then begin
263269
widget_control,ev.id,set_value = 'OFF'
264270
endif else begin
271+
vv=widget_info(/xmanager)
272+
widget_control,ev.id,set_value = "MANAGED: "+strtrim(vv,2)
273+
wait,1
265274
widget_control,ev.id,set_value = 'ON'
266275
endelse
267276
end
@@ -275,6 +284,14 @@ pro handle_Event,ev
275284
widget_control,ev.id,set_value = green_bmp, set_uvalue= val
276285
endelse
277286
end
287+
'timer': begin
288+
wset,pbarid
289+
pbarpos += 5
290+
pbarpos MOD= 300
291+
ERASE, 255
292+
POLYFILL, pbarpos+[0,0,5,5], [0, 19, 19,0], /DEVICE, color=140
293+
WIDGET_CONTROL, ev.id, TIMER=.2
294+
end
278295
'quit': widget_control,ev.top,/DESTROY
279296
else: begin
280297
print, "(other, not treated, event: ok)"
@@ -321,7 +338,8 @@ siz= widget_button(menu,VALUE="Resize (error)",EVENT_PRO="resize_gui") ; 5
321338
pro test_widgets,table,help=help,nocanvas=nocanvas,notree=notree,block=block,fontname=fontname,present=present,select=select,_extra=extra
322339
common mycount,count
323340
common pixmaps,green_bmp,red_bmp
324-
341+
common forprogressbar,progressbar,pbarid,pbarpos
342+
325343
green_bmp= bytarr(7,7,3)& green_bmp[*,*,1] = 255& & green_bmp[0,0,1] = 254
326344
red_bmp= bytarr(7,7,3)& red_bmp[*,*,0] = 255& & red_bmp[0,0,0] = 254
327345
if (n_elements(select) gt 0) then present=select
@@ -364,7 +382,9 @@ ev = {vEv,type:'',pos:[0,0]}
364382
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)
365383
doMbar,mbar,fontname
366384
;mysize=widget_info(base,string_size='012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234')
367-
385+
; add a progress bar to test timer
386+
progressbar = WIDGET_DRAW(base, XSIZE=300, YSIZE=20, UVALUE={vEv,'timer',[0,0]})
387+
pbarpos=0
368388
; define a tabbed base that contains everything:
369389
label=widget_label(base,value='to best mimic IDL`s widgets, call GDL ',/align_left)
370390
label=widget_label(base,value='with option "--widget-compat" ',/align_left)
@@ -738,7 +758,9 @@ widget_control,base,notify_realize='i_am_realized'
738758
;Realize the widgets.
739759
WIDGET_CONTROL, /REALIZE, base
740760

741-
;;Obtain the window index.
761+
;;Obtain the window index.
762+
WIDGET_CONTROL, progressbar, GET_VALUE = pbarId
763+
742764
if ~keyword_set(nocanvas) and total(strcmp('DRAW',present,/fold)) then begin
743765
print,"Draw widgets:",draw,draw2
744766
WIDGET_CONTROL, draw, GET_VALUE = index
@@ -767,5 +789,8 @@ print,"Draw widgets:",draw,draw2
767789
tv,image,10,10,/data; ,/true
768790
endif
769791

770-
xmanager,"handle",base,cleanup="cleanup_xmanager",no_block=~block
792+
; create a timer event --- otherwise will not be active and thus not catched in eventloop
793+
widget_control,progressbar,timer=0
794+
795+
xmanager,"handle",base,cleanup="cleanup_xmanager";,no_block=~block
771796
end

0 commit comments

Comments
 (0)