diff --git a/src/gdlwidget.cpp b/src/gdlwidget.cpp index 7e25f6246..a5736e47b 100644 --- a/src/gdlwidget.cpp +++ b/src/gdlwidget.cpp @@ -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. @@ -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() @@ -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 ); @@ -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){ @@ -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() @@ -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. } @@ -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 diff --git a/src/gdlwidget.hpp b/src/gdlwidget.hpp index 9454b0a30..0e9901000 100644 --- a/src/gdlwidget.hpp +++ b/src/gdlwidget.hpp @@ -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); diff --git a/src/widget.cpp b/src/widget.cpp index d6b16d2ce..94325fed9 100644 --- a/src/widget.cpp +++ b/src/widget.cpp @@ -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 (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 (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 (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 } diff --git a/testsuite/interactive_tests/test_widgets.pro b/testsuite/interactive_tests/test_widgets.pro index 71a5498b7..0e888250f 100644 --- a/testsuite/interactive_tests/test_widgets.pro +++ b/testsuite/interactive_tests/test_widgets.pro @@ -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 @@ -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 @@ -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 @@ -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)" @@ -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 @@ -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) @@ -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 @@ -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