diff --git a/harbour/ChangeLog b/harbour/ChangeLog index 161c52b143..0f1f2ecd7a 100644 --- a/harbour/ChangeLog +++ b/harbour/ChangeLog @@ -17,6 +17,23 @@ past entries belonging to author(s): Viktor Szakats. */ +2009-08-30 17:30 UTC-0800 Pritpal Bedi (pritpal@vouchcac.com) + * contrib/hbqt/hbqt_slots.cpp + ! Completely reworked events management. It now supports multi-threads. + + * contrib/hbxbp/xbpbrowse.prg + * contrib/hbxbp/xbpdialog.prg + * contrib/hbxbp/xbpgeneric.prg + ! Reworked event management to support multi threads. + + * contrib/hbxbp/tests/demoxbp.prg + ! Demonstrated the MT support. Click on on main menu and play + with more than one dialog. + + /* Still there are few glitches in MT mode and I do request Przemek to + look into the code and suggest us what else is required. + */ + 2009-08-30 17:25 UTC-0800 Pritpal Bedi (pritpal@vouchcac.com) * contrib/hbwin/wapi_winuser.c + Added two more functions. diff --git a/harbour/contrib/hbqt/hbqt_slots.cpp b/harbour/contrib/hbqt/hbqt_slots.cpp index ab54323dfe..ea125fe392 100644 --- a/harbour/contrib/hbqt/hbqt_slots.cpp +++ b/harbour/contrib/hbqt/hbqt_slots.cpp @@ -56,6 +56,7 @@ #include "hbapi.h" #include "hbvm.h" #include "hbapiitm.h" +#include "hbstack.h" #include "hbqt.h" @@ -75,8 +76,56 @@ /*----------------------------------------------------------------------*/ -static Slots *s_s = NULL; -static Events *s_e = NULL; +typedef struct +{ + Events * events; +} HB_EVENTS, * PHB_EVENTS; + +static HB_TSD_NEW( s_events, sizeof( HB_EVENTS ), NULL, NULL ); + +#define hb_getQtEventFilter() ( ( PHB_EVENTS ) hb_stackGetTSD( &s_events ) ) + + + +typedef struct +{ + Slots * slot; +} HB_SLOTS, * PHB_SLOTS; + +static HB_TSD_NEW( s_slots, sizeof( HB_SLOTS ), NULL, NULL ); + +#define hb_getQtEventSlots() ( ( PHB_SLOTS ) hb_stackGetTSD( &s_slots ) ) + +/*----------------------------------------------------------------------*/ + +void qt_setEventFilter( Events * event ) +{ + hb_getQtEventFilter()->events = event; +} + +Events * qt_getEventFilter( void ) +{ + Events * s_e = hb_getQtEventFilter()->events; + if( !s_e ) + hb_getQtEventFilter()->events = new Events(); + + return hb_getQtEventFilter()->events; +} + + +void qt_setEventSlots( Slots * slot ) +{ + hb_getQtEventSlots()->slot = slot; +} + +Slots * qt_getEventSlots( void ) +{ + Slots * s_s = hb_getQtEventSlots()->slot; + if( !s_s ) + hb_getQtEventSlots()->slot = new Slots(); + + return hb_getQtEventSlots()->slot; +} /*----------------------------------------------------------------------*/ @@ -91,6 +140,7 @@ static void SlotsExec( QObject* object, char* event ) { if( object ) { + Slots * s_s = qt_getEventSlots(); int i = object->property( event ).toInt(); if( ( i > 0 ) && ( s_s->listActv.at( i - 1 ) == true ) ) { @@ -105,6 +155,7 @@ static void SlotsExecBool( QObject* object, char* event, bool bBool ) { if( object ) { + Slots * s_s = qt_getEventSlots(); int i = object->property( event ).toInt(); if( ( i > 0 ) && ( s_s->listActv.at( i - 1 ) == true ) ) { @@ -121,6 +172,7 @@ static void SlotsExecInt( QObject* object, char* event, int iValue ) { if( object ) { + Slots * s_s = qt_getEventSlots(); int i = object->property( event ).toInt(); if( ( i > 0 ) && ( s_s->listActv.at( i - 1 ) == true ) ) { @@ -137,6 +189,7 @@ static void SlotsExecIntInt( QObject* object, char* event, int iValue1, int iVal { if( object ) { + Slots * s_s = qt_getEventSlots(); int i = object->property( event ).toInt(); if( i > 0 && ( s_s->listActv.at( i - 1 ) == true ) ) { @@ -155,6 +208,7 @@ static void SlotsExecIntIntInt( QObject* object, char* event, int iValue1, int i { if( object ) { + Slots * s_s = qt_getEventSlots(); int i = object->property( event ).toInt(); if( i > 0 && ( s_s->listActv.at( i - 1 ) == true ) ) { @@ -175,6 +229,7 @@ static void SlotsExecIntIntRect( QObject* object, char* event, int iValue1, int { if( object ) { + Slots * s_s = qt_getEventSlots(); int i = object->property( event ).toInt(); if( i > 0 && ( s_s->listActv.at( i - 1 ) == true ) ) { @@ -195,6 +250,7 @@ static void SlotsExecString( QObject* object, char* event, const QString & strin { if( object ) { + Slots * s_s = qt_getEventSlots(); int i = object->property( event ).toInt(); if( i > 0 && ( s_s->listActv.at( i - 1 ) == true ) ) { @@ -211,6 +267,7 @@ static void SlotsExecString2( QObject* object, char* event, const QString & s1, { if( object ) { + Slots * s_s = qt_getEventSlots(); int i = object->property( event ).toInt(); if( i > 0 && ( s_s->listActv.at( i - 1 ) == true ) ) { @@ -229,6 +286,7 @@ static void SlotsExecString3( QObject* object, char* event, const QString & s1, { if( object ) { + Slots * s_s = qt_getEventSlots(); int i = object->property( event ).toInt(); if( i > 0 && ( s_s->listActv.at( i - 1 ) == true ) ) { @@ -249,6 +307,7 @@ static void SlotsExecModel( QObject* object, char* event, const QModelIndex & in { if( object ) { + Slots * s_s = qt_getEventSlots(); int i = object->property( event ).toInt(); if( ( i > 0 ) && ( s_s->listActv.at( i - 1 ) == true ) ) { @@ -265,6 +324,7 @@ static void SlotsExecRect( QObject* object, char* event, const QRect & rect ) { if( object ) { + Slots * s_s = qt_getEventSlots(); int i = object->property( event ).toInt(); if( ( i > 0 ) && ( s_s->listActv.at( i - 1 ) == true ) ) { @@ -281,6 +341,7 @@ static void SlotsExecUrl( QObject* object, char* event, const QUrl & url ) { if( object ) { + Slots * s_s = qt_getEventSlots(); int i = object->property( event ).toInt(); if( ( i > 0 ) && ( s_s->listActv.at( i - 1 ) == true ) ) { @@ -297,6 +358,7 @@ static void SlotsExecTextCharFormat( QObject* object, char* event, const QTextCh { if( object ) { + Slots * s_s = qt_getEventSlots(); int i = object->property( event ).toInt(); if( ( i > 0 ) && ( s_s->listActv.at( i - 1 ) == true ) ) { @@ -313,6 +375,7 @@ static void SlotsExecFont( QObject* object, char* event, const QFont & font ) { if( object ) { + Slots * s_s = qt_getEventSlots(); int i = object->property( event ).toInt(); if( ( i > 0 ) && ( s_s->listActv.at( i - 1 ) == true ) ) { @@ -329,6 +392,7 @@ static void SlotsExecStringList( QObject* object, char* event, const QStringList { if( object ) { + Slots * s_s = qt_getEventSlots(); int i = object->property( event ).toInt(); if( ( i > 0 ) && ( s_s->listActv.at( i - 1 ) == true ) ) { @@ -345,6 +409,7 @@ static void SlotsExecNetworkRequest( QObject* object, char* event, const QNetwor { if( object ) { + Slots * s_s = qt_getEventSlots(); int i = object->property( event ).toInt(); if( ( i > 0 ) && ( s_s->listActv.at( i - 1 ) == true ) ) { @@ -361,6 +426,7 @@ static void SlotsExecPointer( QObject* object, char* event, void * p1 ) { if( object ) { + Slots * s_s = qt_getEventSlots(); int i = object->property( event ).toInt(); if( ( i > 0 ) && ( s_s->listActv.at( i - 1 ) == true ) ) { @@ -377,6 +443,7 @@ static void SlotsExecPointerString( QObject* object, char* event, void * p1, QSt { if( object ) { + Slots * s_s = qt_getEventSlots(); int i = object->property( event ).toInt(); if( ( i > 0 ) && ( s_s->listActv.at( i - 1 ) == true ) ) { @@ -395,6 +462,7 @@ static void SlotsExecPointerInt( QObject* object, char* event, void * p1, int iI { if( object ) { + Slots * s_s = qt_getEventSlots(); int i = object->property( event ).toInt(); if( ( i > 0 ) && ( s_s->listActv.at( i - 1 ) == true ) ) { @@ -413,6 +481,7 @@ static void SlotsExecPointerPointer( QObject* object, char* event, void * p1, vo { if( object ) { + Slots * s_s = qt_getEventSlots(); int i = object->property( event ).toInt(); if( ( i > 0 ) && ( s_s->listActv.at( i - 1 ) == true ) ) { @@ -979,9 +1048,7 @@ HB_FUNC( QT_CONNECT_SIGNAL ) QString signal = hb_parcx( 2 ); /* get signal */ PHB_ITEM codeblock = hb_itemNew( hb_param( 3, HB_IT_BLOCK | HB_IT_BYREF ) ); /* get codeblock */ bool ret = false; /* return value */ - - if( s_s == NULL ) - s_s = new Slots(); + Slots * s_s = qt_getEventSlots(); if( signal == ( QString ) "clicked()" ) { @@ -1523,29 +1590,9 @@ HB_FUNC( QT_CONNECT_SIGNAL ) if( ret == true ) { - bool bFound = false; - int i; - - for( i = 0; i < s_s->listBlock.size(); i++ ) - { - if( s_s->listBlock.at( i ) == NULL ) - { - bFound = true; - break; - } - } - if( bFound ) - { - s_s->listBlock[ i ] = codeblock; - s_s->listActv[ i ] = true; - object->setProperty( hb_parcx( 2 ), ( int ) i + 1 ); - } - else - { - s_s->listBlock << codeblock; - s_s->listActv << true; - object->setProperty( hb_parcx( 2 ), ( int ) s_s->listBlock.size() ); - } + s_s->listBlock << codeblock; + s_s->listActv << true; + object->setProperty( hb_parcx( 2 ), ( int ) s_s->listBlock.size() ); } } @@ -1557,17 +1604,15 @@ HB_FUNC( QT_DISCONNECT_SIGNAL ) QObject * object = ( QObject* ) hb_parptr( 1 ); if( object ) { + Slots * s_s = qt_getEventSlots(); const char * event = hb_parcx( 2 ); int i = object->property( event ).toInt(); if( i > 0 && i <= s_s->listBlock.size() ) { - if( s_s->listBlock.at( i - 1 ) != NULL ) - { - hb_itemRelease( s_s->listBlock.at( i - 1 ) ); - s_s->listBlock[ i - 1 ] = NULL; - s_s->listActv[ i - 1 ] = false; - } + hb_itemRelease( ( PHB_ITEM ) s_s->listBlock.at( i - 1 ) ); + s_s->listBlock[ i - 1 ] = NULL; + s_s->listActv[ i - 1 ] = false; } } } @@ -1578,6 +1623,8 @@ HB_FUNC( QT_DISCONNECT_SIGNAL ) */ HB_FUNC( RELEASE_CODEBLOCKS ) { + Slots * s_s = qt_getEventSlots(); + if( s_s ) { for( int i = 0; i < s_s->listBlock.size(); ++i ) @@ -1599,6 +1646,7 @@ HB_FUNC( RELEASE_CODEBLOCKS ) */ void release_codeblocks( void ) { + Slots * s_s = qt_getEventSlots(); if( s_s ) { for( int i = 0; i < s_s->listBlock.size(); ++i ) @@ -1703,15 +1751,12 @@ bool Events::eventFilter( QObject * object, QEvent * event ) else event->ignore(); } - return ret; //true; + return ret; } HB_FUNC( QT_QEVENTFILTER ) { - if( s_e == NULL ) - s_e = new Events(); - - hb_retptr( ( Events * ) s_e ); + hb_retptr( qt_getEventFilter() ); } HB_FUNC( QT_CONNECT_EVENT ) @@ -1719,44 +1764,24 @@ HB_FUNC( QT_CONNECT_EVENT ) QObject * object = ( QObject * ) hb_parptr( 1 ); int type = hb_parni( 2 ); PHB_ITEM codeblock = hb_itemNew( hb_param( 3, HB_IT_BLOCK | HB_IT_BYREF ) ); + Events * s_e = qt_getEventFilter(); - if( s_e == NULL ) - s_e = new Events(); - - bool bFound = false; - int i; - char str[ 10 ]; + char str[ 20 ]; hb_snprintf( str, sizeof( str ), "%s%i%s", "P", type, "P" ); /* Make it a unique identifier */ - for( i = 0; i < s_e->listBlock.size(); i++ ) - { - if( s_e->listBlock.at( i ) == NULL ) - { - bFound = true; - break; - } - } - if( bFound ) - { - s_e->listBlock[ i ] = codeblock; - s_e->listActv[ i ] = true; - object->setProperty( str, ( int ) i + 1 ); - } - else - { - s_e->listBlock << codeblock; - s_e->listActv << true; - object->setProperty( str, ( int ) s_e->listBlock.size() ); - } + s_e->listBlock << codeblock; + s_e->listActv << true; + object->setProperty( str, ( int ) s_e->listBlock.size() ); hb_retl( true ); } HB_FUNC( QT_DISCONNECT_EVENT ) { - QObject * object = ( QObject * ) hb_parptr( 1 ); - int type = hb_parni( 2 ); - bool bRet = false; + QObject * object = ( QObject * ) hb_parptr( 1 ); + int type = hb_parni( 2 ); + bool bRet = false; + Events * s_e = qt_getEventFilter(); char str[ 10 ]; hb_snprintf( str, sizeof( str ), "%s%i%s", "P", type, "P" ); /* Make it a unique identifier */ @@ -1764,13 +1789,10 @@ HB_FUNC( QT_DISCONNECT_EVENT ) int i = object->property( str ).toInt(); if( i > 0 && i <= s_e->listBlock.size() ) { - if( s_e->listBlock.at( i - 1 ) != NULL ) - { - hb_itemRelease( s_e->listBlock.at( i - 1 ) ); - s_e->listBlock[ i - 1 ] = NULL; - s_e->listActv[ i - 1 ] = false; - bRet = true; - } + hb_itemRelease( s_e->listBlock.at( i - 1 ) ); + s_e->listBlock[ i - 1 ] = NULL; + s_e->listActv[ i - 1 ] = false; + bRet = true; } hb_retl( bRet ); } @@ -1820,7 +1842,7 @@ void HbTableView::resizeEvent( QResizeEvent * event ) } QModelIndex HbTableView::moveCursor( HbTableView::CursorAction cursorAction, Qt::KeyboardModifiers modifiers ) { - // char str[ 50 ]; hb_snprintf( str, sizeof( str ), "HbTableView: action=%i %i", cursorAction, QAbstractItemView::MoveDown ); OutputDebugString( str ); +// char str[ 50 ]; hb_snprintf( str, sizeof( str ), "HbTableView: action=%i %i", cursorAction, QAbstractItemView::MoveDown ); OutputDebugString( str ); //emit sg_moveCursor( cursorAction, modifiers ); return QTableView::moveCursor( cursorAction, modifiers ); @@ -1888,12 +1910,6 @@ QVariant fetchRole( PHB_ITEM block, int what, int par1, int par2 ) return( hb_itemGetND( ret ) ); else if( hb_itemType( ret ) & HB_IT_NUMERIC ) return( hb_itemGetNI( ret ) ); - #if 0 - else if( hb_itemType( ret ) & HB_IT_POINTER ) - { - QPixmap pixmap = qobject_cast( (QPixmap*) hb_itemGetPtr( ret ) ); - } - #endif else return QVariant(); } diff --git a/harbour/contrib/hbxbp/tests/demoxbp.prg b/harbour/contrib/hbxbp/tests/demoxbp.prg index 017e9b0edc..d72b73d195 100644 --- a/harbour/contrib/hbxbp/tests/demoxbp.prg +++ b/harbour/contrib/hbxbp/tests/demoxbp.prg @@ -82,12 +82,25 @@ REQUEST DbfCdx #define CRLF chr( 13 )+chr( 10 ) -STATIC oMLE /* Change Font elsewhere */ +#ifdef __HARBOUR__ +THREAD STATIC oMLE /* Change Font elsewhere */ +#else +STATIC oMLE +#endif /*----------------------------------------------------------------------*/ PROCEDURE Main() + _BuildADialog() + + RETURN + +/*----------------------------------------------------------------------*/ + +PROCEDURE _BuildADialog() + + hb_gtReload( 'GUI' ) BuildADialog() RETURN @@ -248,7 +261,7 @@ STATIC FUNCTION uiXtoS( xVar ) /*----------------------------------------------------------------------*/ -FUNCTION uiDebug( p1, p2, p3, p4, p5, p6, p7, p8, p9, p10 ) +FUNCTION MyDebug( p1, p2, p3, p4, p5, p6, p7, p8, p9, p10 ) LOCAL s s := uiXtoS( p1 ) + CRLF @@ -347,7 +360,7 @@ STATIC FUNCTION Build_MenuBar( oDlg ) oSubMenu:title := "~Dialogs" #if 1 /* T H R E D E D D I A L O G */ oSubMenu:addItem( { "~One More Instance"+ chr( K_TAB ) +"Ctrl+M", ; - {|| hb_threadStart( {|| BuildADialog() } ) } } ) + {|| hb_threadStart( {|| _BuildADialog() } ) } } ) #else oSubMenu:addItem( { "~One More Instance"+ chr( K_TAB )+ "Ctrl+M", {|| BuildADialog() } } ) #endif @@ -1360,7 +1373,7 @@ FUNCTION Build_PrintDialog( oWnd ) IF valtype( oPrn := oDlg:display() ) == "O" - uiDebug( oPrn:devName , ; + MyDebug( oPrn:devName , ; oPrn:setOrientation() , ; oPrn:setFormSize() , ; oPrn:setResolution()[1], ; diff --git a/harbour/contrib/hbxbp/xbpbrowse.prg b/harbour/contrib/hbxbp/xbpbrowse.prg index 84bb4a468d..baab09a399 100644 --- a/harbour/contrib/hbxbp/xbpbrowse.prg +++ b/harbour/contrib/hbxbp/xbpbrowse.prg @@ -3768,7 +3768,9 @@ METHOD applyKey( nKey ) CLASS XbpBrowse METHOD setKey( nKey, bBlock ) CLASS XbpBrowse - + HB_SYMBOL_UNUSED( nKey ) + HB_SYMBOL_UNUSED( bBlock ) +#if 0 LOCAL bReturn LOCAL nPos @@ -3816,7 +3818,9 @@ METHOD setKey( nKey, bBlock ) CLASS XbpBrowse ENDIF RETURN bReturn - +#else + RETURN .f. +#endif METHOD setStyle( nStyle, lNewValue ) CLASS XbpBrowse @@ -3839,7 +3843,7 @@ METHOD setStyle( nStyle, lNewValue ) CLASS XbpBrowse RETURN ::styles[ nStyle ] - +#if 0 FUNCTION TBMouse( oBrw, nMRow, nMCol ) LOCAL n @@ -3870,7 +3874,7 @@ FUNCTION TBMouse( oBrw, nMRow, nMCol ) ENDIF RETURN TBR_EXCEPTION - +#endif /*----------------------------------------------------------------------*/ /*----------------------------------------------------------------------*/ /*----------------------------------------------------------------------*/ diff --git a/harbour/contrib/hbxbp/xbpdialog.prg b/harbour/contrib/hbxbp/xbpdialog.prg index 2cb0b6438f..f3a2e42bc9 100644 --- a/harbour/contrib/hbxbp/xbpdialog.prg +++ b/harbour/contrib/hbxbp/xbpdialog.prg @@ -85,7 +85,7 @@ CLASS XbpDialog FROM XbpWindow DATA tasklist INIT .t. DATA oEventLoop - METHOD init() + METHOD new() METHOD create() METHOD configure() METHOD destroy() @@ -107,7 +107,7 @@ CLASS XbpDialog FROM XbpWindow /*----------------------------------------------------------------------*/ -METHOD XbpDialog:init( oParent, oOwner, aPos, aSize, aPresParams, lVisible ) +METHOD XbpDialog:new( oParent, oOwner, aPos, aSize, aPresParams, lVisible ) ::xbpWindow:init( oParent, oOwner, aPos, aSize, aPresParams, lVisible ) @@ -152,7 +152,7 @@ METHOD XbpDialog:create( oParent, oOwner, aPos, aSize, aPresParams, lVisible ) /* Install Event Loop per Dialog Basis */ /* Limitng */ ::oEventLoop := QEventLoop():new( ::pWidget ) - AddEventLoop( ::oEventLoop ) + SetEventLoop( ::oEventLoop ) /* Instal Event Filter */ ::oWidget:installEventFilter( SetEventFilter() ) @@ -207,7 +207,6 @@ METHOD XbpDialog:configure( oParent, oOwner, aPos, aSize, aPresParams, lVisible METHOD XbpDialog:destroy() ::oEventLoop:exit( 0 ) - RemoveEventLoop( ::oEventLoop ) ::xbpWindow:destroy() diff --git a/harbour/contrib/hbxbp/xbpgeneric.prg b/harbour/contrib/hbxbp/xbpgeneric.prg index 8d3a92da7f..95a891c4bf 100644 --- a/harbour/contrib/hbxbp/xbpgeneric.prg +++ b/harbour/contrib/hbxbp/xbpgeneric.prg @@ -82,9 +82,8 @@ STATIC ts_mutex STATIC oApp -THREAD STATIC aEventLoop := {} +THREAD STATIC aEventLoop -//STATIC ts_events THREAD STATIC ts_events THREAD STATIC nEventIn := 0 @@ -93,7 +92,8 @@ THREAD STATIC oDummy THREAD STATIC oAppWindow -THREAD STATIC sEventFilter +//THREAD STATIC sEventFilter +STATIC sEventFilter THREAD STATIC oEventLoop /*----------------------------------------------------------------------*/ @@ -136,7 +136,7 @@ FUNCTION SetAppEvent( nEvent, mp1, mp2, oXbp ) nEventIn := 1 ENDIF -//xbp_debug( "SetAppEvent ... ", threadID(), nEventIn ) +xbp_debug( "SetAppEvent ... ", threadID(), nEventIn ) ts_events[ nEventIn,1 ] := nEvent ts_events[ nEventIn,2 ] := mp1 @@ -158,9 +158,9 @@ FUNCTION AppEvent( mp1, mp2, oXbp, nTimeout ) IF ++nEventOut > EVENT_BUFFER nEventOut := 1 ENDIF -//xbp_debug( " AppEvent ... ", threadID(), nEventOut ) +xbp_debug( " AppEvent ... ", nThreadID, nEventOut ) DO WHILE .t. - aEventLoop[ 1,1 ]:processEvents_1( 0, 200 ) + oEventLoop:processEvents( 0 ) IF ts_events[ nEventOut,5 ] == nThreadID nEvent := ts_events[ nEventOut,1 ] @@ -175,7 +175,7 @@ FUNCTION AppEvent( mp1, mp2, oXbp, nTimeout ) hb_idleSleep( 0.001 ) /* Releases CPU cycles */ ENDDO -//( "..........................", threadID() ) +xbp_debug( "..........................", threadID() ) RETURN nEvent @@ -242,7 +242,7 @@ FUNCTION MsgBox( cMsg, cTitle ) oMB:setParent( SetAppWindow():pWidget ) oMB:setWindowFlags( Qt_Dialog ) oMB:setWindowTitle( cTitle ) - SetAppWindow():oWidget:setFocus() + //SetAppWindow():oWidget:setFocus() oMB:exec() oMB:destroy() @@ -268,43 +268,14 @@ FUNCTION GraMakeRGBColor( aRGB ) /*----------------------------------------------------------------------*/ FUNCTION SetEventFilter() - LOCAL pEventFilter - IF empty( sEventFilter ) - pEventFilter := QT_QEventFilter() - IF hb_isPointer( pEventFilter ) - sEventFilter := pEventFilter - ENDIF - ENDIF - - RETURN sEventFilter + RETURN QT_QEventFilter() /*----------------------------------------------------------------------*/ -FUNCTION AddEventLoop( oEventLoop ) +FUNCTION SetEventLoop( oELoop ) - //hb_mutexLock( ts_mutex ) - - aadd( aEventLoop, { oEventLoop, threadID() } ) - - //hb_mutexUnLock( ts_mutex ) - - RETURN nil - -/*----------------------------------------------------------------------*/ - -FUNCTION RemoveEventLoop( oEventLoop ) - LOCAL n - - n := ascan( aEventLoop, {|o_| o_[ 1 ] == oEventLoop } ) - IF n > 0 - hb_mutexLock( ts_mutex ) - - aEventLoop[ n,1 ] := NIL - aEventLoop[ n,2 ] := 0 - - hb_mutexUnLock( ts_mutex ) - ENDIF + oEventLoop := oELoop RETURN nil