From 3e549d00272e218144bf0a1cc7d10a070bb325a7 Mon Sep 17 00:00:00 2001 From: Pritpal Bedi Date: Wed, 20 Jun 2012 05:03:46 +0000 Subject: [PATCH] 2012-06-19 21:29 UTC-0800 Pritpal Bedi (bedipritpal@hotmail.com) * contrib/hbqt/qtcore/hbqt_bind.cpp + Implemented: Events, Slots, Destroyers on thread level. Previously those were created per object level. This greatly decreased the os-resource count and also simplifies the code. Thanks to Przemek for the tip. + Implemented: release of all objects per thread level. hbQT employs internal counter to identify threads. All widgets are created in one global list which has made it possible to use Qt's blocking widgets, like QMessageBox, in Harbour MT applications. It seems that Qt looks for the event processing only in main appln thread and hence these widgets were not usable in other threads. The testbed is hbqt/tests/demoqt.prg which is now multithreaded. You check it with menu option . + Formatting: in tracelog entries. * contrib/hbqt/qtcore/hbqt_hbqevents.cpp - Commented out: a hack where QClosEvent was being treated differently then other events. * contrib/hbqt/tests/demoqt.prg * Parented: QMessageBox() ( Read below ) * contrib/hbide/idedocks.prg - Removed: one hack which at begining was there to activate QMainWindow's docking area resizable. * contrib/hbide/idemain.prg + Changed: ::cWrkCodec to be "EN" by default. It fixes recent regression in hbIDE for certain users. * contrib/hbide/idemisc.prg * Parented: QMessageBox() should always be constructed with a parent because of special handelling of blocking dialog where parent is treated slightly different than other Qt widgets. This fixes a long-standing bug in hbIDE where appnl was rendered in indefinite loop when "X" button was employed to terminate and confirm dialog would not be terminated internally. So for QMessageBox() and, to be on the safer side, all widets derived from QDialog() should be constructed with a parent and at the end be reparented with a just-to-be-deleted-QWidget(), like: oMB := QMessageBox( oParent ) ... oMB:setParent( QWidget() ) RETURN something --- harbour/ChangeLog | 52 ++ harbour/contrib/hbide/idedocks.prg | 1 - harbour/contrib/hbide/idemain.prg | 2 +- harbour/contrib/hbide/idemisc.prg | 31 +- harbour/contrib/hbqt/qtcore/hbqt_bind.cpp | 485 ++++++++++-------- .../contrib/hbqt/qtcore/hbqt_hbqevents.cpp | 2 + harbour/contrib/hbqt/tests/demoqt.prg | 35 +- 7 files changed, 365 insertions(+), 243 deletions(-) diff --git a/harbour/ChangeLog b/harbour/ChangeLog index fbe406b921..900f4f2a0a 100644 --- a/harbour/ChangeLog +++ b/harbour/ChangeLog @@ -16,6 +16,58 @@ The license applies to all entries newer than 2009-04-28. */ +2012-06-19 21:29 UTC-0800 Pritpal Bedi (bedipritpal@hotmail.com) + * contrib/hbqt/qtcore/hbqt_bind.cpp + + Implemented: Events, Slots, Destroyers on thread level. + Previously those were created per object level. This greatly + decreased the os-resource count and also simplifies the code. + Thanks to Przemek for the tip. + + + Implemented: release of all objects per thread level. + hbQT employs internal counter to identify threads. + All widgets are created in one global list which has + made it possible to use Qt's blocking widgets, like + QMessageBox, in Harbour MT applications. It seems that + Qt looks for the event processing only in main appln + thread and hence these widgets were not usable in + other threads. The testbed is hbqt/tests/demoqt.prg + which is now multithreaded. You check it with + menu option . + + + Formatting: in tracelog entries. + + * contrib/hbqt/qtcore/hbqt_hbqevents.cpp + - Commented out: a hack where QClosEvent was being treated + differently then other events. + + * contrib/hbqt/tests/demoqt.prg + * Parented: QMessageBox() ( Read below ) + + * contrib/hbide/idedocks.prg + - Removed: one hack which at begining was there to activate + QMainWindow's docking area resizable. + + * contrib/hbide/idemain.prg + + Changed: ::cWrkCodec to be "EN" by default. + It fixes recent regression in hbIDE for certain users. + + * contrib/hbide/idemisc.prg + * Parented: QMessageBox() should always be constructed with a + parent because of special handelling of blocking dialog + where parent is treated slightly different than other + Qt widgets. This fixes a long-standing bug in hbIDE where + appnl was rendered in indefinite loop when "X" button + was employed to terminate and confirm dialog would + not be terminated internally. + So for QMessageBox() and, to be on the safer side, all + widets derived from QDialog() should be constructed + with a parent and at the end be reparented with a + just-to-be-deleted-QWidget(), like: + oMB := QMessageBox( oParent ) + ... + oMB:setParent( QWidget() ) + RETURN something + 2012-06-19 16:24 UTC+0200 Viktor Szakats (harbour syenar.net) * config/win/watcom.mk ! fixed RC compilation for watcom diff --git a/harbour/contrib/hbide/idedocks.prg b/harbour/contrib/hbide/idedocks.prg index 5bc16cbd42..218d2ed64e 100644 --- a/harbour/contrib/hbide/idedocks.prg +++ b/harbour/contrib/hbide/idedocks.prg @@ -364,7 +364,6 @@ METHOD IdeDocks:buildDialog() ::oIde:oDlg := XbpDialog():new() ::oDlg:icon := hbide_image( "hbide" ) ::oDlg:title := "Harbour IDE" - ::oDlg:qtObject := hbide_getUI( "mainwindow" ) ::oDlg:create( , , , , , .f. ) ::oDlg:oWidget:setStyleSheet( GetStyleSheet( "QMainWindow", ::nAnimantionMode ) ) diff --git a/harbour/contrib/hbide/idemain.prg b/harbour/contrib/hbide/idemain.prg index 5adddcadca..4eb9b5cc66 100644 --- a/harbour/contrib/hbide/idemain.prg +++ b/harbour/contrib/hbide/idemain.prg @@ -284,7 +284,7 @@ CLASS HbIde DATA cWrkFolderLast INIT "" DATA cWrkProject INIT "" DATA cWrkTheme INIT "" - DATA cWrkCodec INIT "" + DATA cWrkCodec INIT "EN" DATA cWrkPathMk2 INIT hb_getenv( "HBIDE_DIR_HBMK2" ) DATA cWrkPathEnv INIT hb_DirBase() DATA cWrkEnvironment INIT "" diff --git a/harbour/contrib/hbide/idemisc.prg b/harbour/contrib/hbide/idemisc.prg index c73d7feab9..970093d586 100644 --- a/harbour/contrib/hbide/idemisc.prg +++ b/harbour/contrib/hbide/idemisc.prg @@ -217,60 +217,69 @@ FUNCTION hbide_posAndSize( qWidget ) /*----------------------------------------------------------------------*/ FUNCTION hbide_showWarning( cMsg, cInfo, cTitle, qParent ) - LOCAL oMB + LOCAL oMB, nRet DEFAULT cTitle TO "Information" DEFAULT qParent TO SetAppWindow():oWidget - oMB := QMessageBox() + oMB := QMessageBox( qParent ) oMB:setText( cMsg ) IF !empty( cInfo ) oMB:setInformativeText( cInfo ) ENDIF oMB:setIcon( QMessageBox_Critical ) - oMB:setParent( qParent ) oMB:setWindowFlags( Qt_Dialog ) oMB:setWindowTitle( cTitle ) - RETURN oMB:exec() + nRet := oMB:exec() + oMB:setParent( QWidget() ) + + RETURN nRet /*----------------------------------------------------------------------*/ FUNCTION hbide_getYesNo( cMsg, cInfo, cTitle ) - LOCAL oMB + LOCAL oMB, nRet DEFAULT cTitle TO "Option Please!" - oMB := QMessageBox() + oMB := QMessageBox( hbide_setIde():oDlg:oWidget ) oMB:setText( ""+ cMsg +"" ) IF !empty( cInfo ) oMB:setInformativeText( cInfo ) ENDIF oMB:setIcon( QMessageBox_Information ) oMB:setWindowTitle( cTitle ) + oMB:setWindowFlags( Qt_Dialog ) oMB:setStandardButtons( QMessageBox_Yes + QMessageBox_No ) - RETURN ( oMB:exec() == QMessageBox_Yes ) + nRet := oMB:exec() + + oMB:setParent( QWidget() ) + + RETURN ( nRet == QMessageBox_Yes ) /*----------------------------------------------------------------------*/ FUNCTION hbide_getYesNoCancel( cMsg, cInfo, cTitle ) - LOCAL oMB + LOCAL oMB, nRet DEFAULT cTitle TO "Option Please!" - oMB := QMessageBox() + oMB := QMessageBox( SetAppWindow():oWidget ) oMB:setText( ""+ cMsg +"" ) IF !empty( cInfo ) oMB:setInformativeText( cInfo ) ENDIF oMB:setIcon( QMessageBox_Information ) - oMB:setParent( SetAppWindow():oWidget ) oMB:setWindowFlags( Qt_Dialog ) oMB:setWindowTitle( cTitle ) oMB:setStandardButtons( QMessageBox_Yes + QMessageBox_No + QMessageBox_Cancel ) - RETURN oMB:exec() + nRet := oMB:exec() + oMB:setParent( QWidget() ) + + RETURN nRet /*----------------------------------------------------------------------*/ diff --git a/harbour/contrib/hbqt/qtcore/hbqt_bind.cpp b/harbour/contrib/hbqt/qtcore/hbqt_bind.cpp index c00b5b504e..d60f26f13d 100644 --- a/harbour/contrib/hbqt/qtcore/hbqt_bind.cpp +++ b/harbour/contrib/hbqt/qtcore/hbqt_bind.cpp @@ -55,6 +55,7 @@ #include "hbapi.h" #include "hbapiitm.h" #include "hbstack.h" +#include "hbthread.h" #include "hbvm.h" #include "hbapierr.h" @@ -63,65 +64,6 @@ #include "hbqt_hbqslots.h" #include "hbqt_hbqevents.h" - -typedef struct _HBQT_BIND -{ - void * qtObject; - void * hbObject; - PHBQT_DEL_FUNC pDelFunc; - int iFlags; - bool fDeleting; - char szClassName[ HB_SYMBOL_NAME_LEN + 1 ]; - HBQDestroyer * pDestroyer; - HBQSlots * pReceiverSlots; - HBQEvents * pReceiverEvents; - bool fEventFilterInstalled; - struct _HBQT_BIND * next; -} -HBQT_BIND, * PHBQT_BIND; - -typedef struct -{ - PHBQT_BIND s_hbqt_binds; -} HB_BIND_DATA, * PHB_BIND_DATA; - -#define __HBQT_WITH_MT_SUPPORT__NO - -#ifdef __HBQT_WITH_MT_SUPPORT__ - -static void hbqt_bindInit( void * cargo ) -{ - HB_TRACE( HB_TR_DEBUG, ( "....................................hbqt_bindInit............0............................." ) ); - ( ( PHB_BIND_DATA ) cargo )->s_hbqt_binds = NULL; - HB_TRACE( HB_TR_DEBUG, ( "....................................hbqt_bindInit............1............................." ) ); -} - -static void hbqt_bindRelease( void * cargo ) -{ - HB_TRACE( HB_TR_DEBUG, ( "....................................hbqt_bindRelease.........0............................." ) ); - PHBQT_BIND hbqt_bind; - - while( ( ( PHB_BIND_DATA ) cargo )->s_hbqt_binds ) - { - hbqt_bind = ( ( PHB_BIND_DATA ) cargo )->s_hbqt_binds; - HB_TRACE( HB_TR_DEBUG, ( "....................................hbqt_bindRelease( %p, %s )", hbqt_bind->qtObject, hbqt_bind->szClassName ) ); - hbqt_bindDestroyHbObject( hb_arrayFromId( NULL, hbqt_bind->hbObject ) ); - } - ( ( PHB_BIND_DATA ) cargo )->s_hbqt_binds = NULL; - HB_TRACE( HB_TR_DEBUG, ( "....................................hbqt_bindRelease.........1............................." ) ); -} - -static HB_TSD_NEW( s_bindData, sizeof( HB_BIND_DATA ), hbqt_bindInit, hbqt_bindRelease ); - -#define hbqt_bindGetData() ( ( ( PHB_BIND_DATA ) hb_stackGetTSD( &s_bindData ) )->s_hbqt_binds ) - -#else - -static PHB_BIND_DATA s_bindData = NULL; -#define hbqt_bindGetData() ( ( ( PHB_BIND_DATA ) &s_bindData )->s_hbqt_binds ) - -#endif - /* locks for MT mode, now just dummy definitions which checks * if all locks are correctly released. * @@ -144,6 +86,129 @@ static PHB_DYNS s_dynsym_SETSLOTS = NULL; static PHB_DYNS s_dynsym___EVENTS = NULL; static PHB_DYNS s_dynsym_SETEVENTS = NULL; +typedef struct _HBQT_BIND +{ + void * qtObject; + void * hbObject; + PHBQT_DEL_FUNC pDelFunc; + int iFlags; + bool fDeleting; + char szClassName[ HB_SYMBOL_NAME_LEN + 1 ]; + bool fEventFilterInstalled; + int iThreadId; + struct _HBQT_BIND * next; +} +HBQT_BIND, * PHBQT_BIND; + +typedef struct +{ + PHBQT_BIND s_hbqt_binds; +} HB_BIND_DATA, * PHB_BIND_DATA; + +typedef struct +{ + int iThreadId; + HBQDestroyer * pDestroyer; + HBQSlots * pReceiverSlots; + HBQEvents * pReceiverEvents; +} HB_BIND_THREADDATA, * PHB_BIND_THREADDATA; + +HB_FUNC_EXTERN( HB_THREADID ); + +static int s_bind_threadId = 0; + +static int hbqt_bindGetThreadId() +{ + HBQT_BIND_LOCK + s_bind_threadId++; + HBQT_BIND_UNLOCK + return s_bind_threadId; +} + +#define __HBQT_WITH_MT_SUPPORT__NO +#ifdef __HBQT_WITH_MT_SUPPORT__ +static void hbqt_bindInit( void * cargo ) +{ + HB_TRACE( HB_TR_DEBUG, ( "...hbqt_bindInit............0........." ) ); + ( ( PHB_BIND_DATA ) cargo )->s_hbqt_binds = NULL; + HB_TRACE( HB_TR_DEBUG, ( "...hbqt_bindInit............1........." ) ); +} +static void hbqt_bindRelease( void * cargo ) +{ + HB_TRACE( HB_TR_DEBUG, ( "...hbqt_bindRelease.........0........." ) ); + PHBQT_BIND hbqt_bind; + + while( ( ( PHB_BIND_DATA ) cargo )->s_hbqt_binds ) + { + hbqt_bind = ( ( PHB_BIND_DATA ) cargo )->s_hbqt_binds; + HB_TRACE( HB_TR_DEBUG, ( "...hbqt_bindRelease( %p, %s )", hbqt_bind->qtObject, hbqt_bind->szClassName ) ); + hbqt_bindDestroyHbObject( hb_arrayFromId( NULL, hbqt_bind->hbObject ) ); + } + ( ( PHB_BIND_DATA ) cargo )->s_hbqt_binds = NULL; + HB_TRACE( HB_TR_DEBUG, ( "...hbqt_bindRelease.........1........." ) ); +} +static HB_TSD_NEW( s_bindData, sizeof( HB_BIND_DATA ), hbqt_bindInit, hbqt_bindRelease ); +#define hbqt_bindGetData() ( ( ( PHB_BIND_DATA ) hb_stackGetTSD( &s_bindData ) )->s_hbqt_binds ) +#else +static PHB_BIND_DATA s_bindData = NULL; +#define hbqt_bindGetData() ( ( ( PHB_BIND_DATA ) &s_bindData )->s_hbqt_binds ) +#endif + + +static void hbqt_bindThreadInit( void * cargo ) +{ + PHB_BIND_THREADDATA pBindThreadData = ( ( PHB_BIND_THREADDATA ) cargo ); + + pBindThreadData->iThreadId = hbqt_bindGetThreadId(); + HB_TRACE( HB_TR_DEBUG, ( "...hbqt_bindThreadInit( %i )...STARTS",pBindThreadData->iThreadId ) ); + pBindThreadData->pDestroyer = new HBQDestroyer(); + pBindThreadData->pReceiverSlots = new HBQSlots(); + pBindThreadData->pReceiverEvents = new HBQEvents(); + HB_TRACE( HB_TR_DEBUG, ( "...hbqt_bindThreadInit( %i )...ENDS",pBindThreadData->iThreadId ) ); +} +static void hbqt_bindThreadRelease( void * cargo ) +{ + PHB_BIND_THREADDATA pBindThreadData = ( ( PHB_BIND_THREADDATA ) cargo ); + int id = pBindThreadData->iThreadId; + + HB_TRACE( HB_TR_DEBUG, ( "...hbqt_bindThreadRelease( %i )...STARTS", id ) ); + + QList deleteIt; + + PHBQT_BIND bind; + HBQT_BIND_LOCK + bind = hbqt_bindGetData(); + while( bind ) + { + if( bind->iThreadId == id ) + { + deleteIt << bind->hbObject; + } + bind = bind->next; + } + HBQT_BIND_UNLOCK + + while( ! deleteIt.isEmpty() ) + { + if( hbqt_bindIsHbObject( ( PHB_ITEM ) deleteIt.at( 0 ) ) ) + { + hbqt_bindDestroyHbObject( hb_arrayFromId( NULL, deleteIt.at( 0 ) ) ); + hb_itemRelease( ( PHB_ITEM ) deleteIt.at( 0 ) ); + } + deleteIt.removeAt( 0 ); + } + + delete pBindThreadData->pDestroyer; + delete pBindThreadData->pReceiverSlots; + delete pBindThreadData->pReceiverEvents; + + HB_TRACE( HB_TR_DEBUG, ( "...hbqt_bindThreadRelease( %i )...ENDS",id ) ); +} + +static HB_TSD_NEW( s_bindThreadData, sizeof( HB_BIND_THREADDATA ), hbqt_bindThreadInit, hbqt_bindThreadRelease ); +#define hbqt_bindGetThreadData() ( ( PHB_BIND_THREADDATA ) hb_stackGetTSD( &s_bindThreadData ) ) + + static void hbqt_bind_init( void * cargo ) { HB_SYMBOL_UNUSED( cargo ); @@ -165,9 +230,11 @@ static void hbqt_bind_exit( void * cargo ) PHB_ITEM hbqt_bindGetHbObject( PHB_ITEM pItem, void * qtObject, const char * szClassName, PHBQT_DEL_FUNC pDelFunc, int iFlags ) { + int id = hbqt_bindGetThreadData()->iThreadId; + char * pname = ( char * ) hb_xgrab( 200 ); char * pname1 = ( char * ) hb_xgrab( 200 ); - HB_TRACE( HB_TR_DEBUG, ( ".................HARBOUR_REQUEST_BIND_OBJECT( %p, %i, %s, %s, %s ).................", qtObject, iFlags, szClassName, hb_procname( 0, pname, HB_TRUE ), hb_procname( 1, pname1, HB_TRUE ) ) ); + HB_TRACE( HB_TR_DEBUG, ( "......HARBOUR_REQUEST_BIND_OBJECT( %p, %s, %i, %i, %s, %s )", qtObject, szClassName, iFlags, id, hb_procname( 0, pname, HB_TRUE ), hb_procname( 1, pname1, HB_TRUE ) ) ); hb_xfree( pname ); hb_xfree( pname1 ); @@ -188,7 +255,7 @@ PHB_ITEM hbqt_bindGetHbObject( PHB_ITEM pItem, void * qtObject, const char * szC { if( bind->qtObject == qtObject ) { - HB_TRACE( HB_TR_DEBUG, ( "...hbqt_bindGetHbObject( %p ):if( bind->qtObject == qtObject )", qtObject ) ); + HB_TRACE( HB_TR_DEBUG, ( "......hbqt_bindGetHbObject( %p ):if( bind->qtObject == qtObject )", qtObject ) ); pObject = hb_arrayFromId( pItem, bind->hbObject ); break; } @@ -204,7 +271,9 @@ PHB_ITEM hbqt_bindGetHbObject( PHB_ITEM pItem, void * qtObject, const char * szC if( HB_IS_OBJECT( hb_stackReturnItem() ) && hb_vmRequestQuery() == 0 ) { if( pItem == NULL ) + { pItem = hb_itemNew( NULL ); + } pObject = hb_stackReturnItem(); if( pItem != pObject ) { @@ -219,10 +288,8 @@ PHB_ITEM hbqt_bindGetHbObject( PHB_ITEM pItem, void * qtObject, const char * szC bind->pDelFunc = pDelFunc; bind->iFlags = iFlags; bind->fDeleting = false; - bind->pDestroyer = new HBQDestroyer(); - bind->pReceiverSlots = new HBQSlots(); - bind->pReceiverEvents = new HBQEvents(); bind->fEventFilterInstalled = false; + bind->iThreadId = id; hb_strncpy( bind->szClassName, szClassName, HB_SIZEOFARRAY( bind->szClassName ) - 1 ); bind->next = hbqt_bindGetData(); hbqt_bindGetData() = bind; @@ -235,25 +302,23 @@ PHB_ITEM hbqt_bindGetHbObject( PHB_ITEM pItem, void * qtObject, const char * szC QObject * obj = ( QObject * ) qtObject; QString className = ( QString ) obj->metaObject()->className(); - if( ( ( className != "HBQSlots" ) && ( className != "HBQEvents" ) ) ) + if( pDelFunc != NULL ) { - if( pDelFunc != NULL ) - QObject::connect( obj, SIGNAL( destroyed(QObject*) ), bind->pDestroyer, SLOT( destroyer() ) ); - - HB_TRACE( HB_TR_DEBUG, ( "hbqt_bindGetHbObject_connected_to_destroy()( %p )...%s", qtObject, szClassName ) ); - - hb_vmPushDynSym( s_dynsym_SETSLOTS ); /* initializes __Slots hash */ - hb_vmPush( pObject ); - hb_vmSend( 0 ); - - hb_vmPushDynSym( s_dynsym_SETEVENTS ); /* initializes __Events hash */ - hb_vmPush( pObject ); - hb_vmSend( 0 ); + QObject::connect( obj, SIGNAL( destroyed(QObject*) ), hbqt_bindGetThreadData()->pDestroyer, SLOT( destroyer() ) ); } + HB_TRACE( HB_TR_DEBUG, ( "......hbqt_bindGetHbObject_connected_to_destroy()( %p, %s )", qtObject, szClassName ) ); + + hb_vmPushDynSym( s_dynsym_SETSLOTS ); /* initializes __Slots hash */ + hb_vmPush( pObject ); + hb_vmSend( 0 ); + + hb_vmPushDynSym( s_dynsym_SETEVENTS ); /* initializes __Events hash */ + hb_vmPush( pObject ); + hb_vmSend( 0 ); } else { - HB_TRACE( HB_TR_DEBUG, ( "hbqt_bindGetHbObject( %p )", qtObject ) ); + HB_TRACE( HB_TR_DEBUG, ( "......hbqt_bindGetHbObject( %p )", qtObject ) ); } } } @@ -264,8 +329,10 @@ PHB_ITEM hbqt_bindGetHbObject( PHB_ITEM pItem, void * qtObject, const char * szC PHB_ITEM hbqt_bindSetHbObject( PHB_ITEM pItem, void * qtObject, const char * szClassName, PHBQT_DEL_FUNC pDelFunc, int iFlags ) { + int id = hbqt_bindGetThreadData()->iThreadId; + Q_UNUSED( szClassName ); - HB_TRACE( HB_TR_DEBUG, ( "ENTER hbqt_bindSetHbObject( %p, %s )", qtObject, szClassName ) ); + HB_TRACE( HB_TR_DEBUG, ( "......ENTER hbqt_bindSetHbObject( %p, %s )", qtObject, szClassName ) ); PHB_ITEM pObject = NULL; @@ -281,50 +348,141 @@ PHB_ITEM hbqt_bindSetHbObject( PHB_ITEM pItem, void * qtObject, const char * szC bind = hbqt_bindGetData(); pObject = hb_param( 0, HB_IT_OBJECT ); - if( 1 == 1 ) /* QUESTION: What is this? */ + if( pObject && hb_vmRequestQuery() == 0 ) { - if( pObject && hb_vmRequestQuery() == 0 ) + if( pItem == NULL ) { - if( pItem == NULL ) - pItem = hb_itemNew( NULL ); + pItem = hb_itemNew( NULL ); + } + if( pItem != pObject ) + { + hb_itemMove( pItem, pObject ); + pObject = pItem; + } - if( pItem != pObject ) + bind = ( PHBQT_BIND ) hb_xgrab( sizeof( HBQT_BIND ) ); + memset( bind, 0, sizeof( HBQT_BIND ) ); + bind->qtObject = qtObject; + bind->pDelFunc = pDelFunc; + bind->iFlags = iFlags; + bind->fDeleting = false; + bind->fEventFilterInstalled = false; + bind->iThreadId = id; + hb_strncpy( bind->szClassName, szClassName, HB_SIZEOFARRAY( bind->szClassName ) - 1 ); + bind->next = hbqt_bindGetData(); + hbqt_bindGetData() = bind; + + bind->hbObject = hb_arrayId( pObject ); + + if( iFlags & HBQT_BIT_QOBJECT ) + { + if( pDelFunc != NULL ) { - hb_itemMove( pItem, pObject ); - pObject = pItem; - } - - bind = ( PHBQT_BIND ) hb_xgrab( sizeof( HBQT_BIND ) ); - memset( bind, 0, sizeof( HBQT_BIND ) ); - bind->qtObject = qtObject; - bind->pDelFunc = pDelFunc; - bind->iFlags = iFlags; - bind->fDeleting = false; - bind->pDestroyer = new HBQDestroyer(); - bind->pReceiverSlots = new HBQSlots(); - bind->pReceiverEvents = new HBQEvents(); - bind->fEventFilterInstalled = false; - hb_strncpy( bind->szClassName, szClassName, HB_SIZEOFARRAY( bind->szClassName ) - 1 ); - bind->next = hbqt_bindGetData(); - hbqt_bindGetData() = bind; - - bind->hbObject = hb_arrayId( pObject ); - - if( iFlags & HBQT_BIT_QOBJECT ) - { - if( pDelFunc != NULL ) - QObject::connect( ( QObject * ) qtObject, SIGNAL( destroyed(QObject*) ), bind->pDestroyer, SLOT( destroyer() ) ); - - HB_TRACE( HB_TR_DEBUG, ( "hbqt_bindSetHbObject( QObject %p )...%s", qtObject, ( ( QObject * ) qtObject )->metaObject()->className() ) ); + QObject::connect( ( QObject * ) qtObject, SIGNAL( destroyed(QObject*) ), hbqt_bindGetThreadData()->pDestroyer, SLOT( destroyer() ) ); } + HB_TRACE( HB_TR_DEBUG, ( "......hbqt_bindSetHbObject( QObject %p )...%s", qtObject, ( ( QObject * ) qtObject )->metaObject()->className() ) ); } } HBQT_BIND_UNLOCK - HB_TRACE( HB_TR_DEBUG, ( "hbqt_bindSetHbObject returns PHB_ITEM = %p", pObject ) ); + HB_TRACE( HB_TR_DEBUG, ( "......hbqt_bindSetHbObject returns PHB_ITEM = %p", pObject ) ); return pObject; } +void hbqt_bindDestroyHbObject( PHB_ITEM pObject ) +{ + void * hbObject = hb_arrayId( pObject ); + + if( hbObject ) + { + PHBQT_BIND * bind_ptr, bind; + + HBQT_BIND_LOCK + bind_ptr = &( hbqt_bindGetData() ); + while( ( bind = * bind_ptr ) != NULL ) + { + if( bind->hbObject == hbObject ) + { + bool fDelQtObject = false; + + if( bind->iFlags & HBQT_BIT_OWNER ) + { + if( bind->iFlags & HBQT_BIT_QOBJECT ) + { + if( ( ( QObject * ) bind->qtObject )->metaObject()->className() != ( const char * ) "QAction" ) + if( ( ( QObject * ) bind->qtObject )->parent() == NULL ) + fDelQtObject = true; + } + else + fDelQtObject = true; + } + + HB_TRACE( HB_TR_DEBUG, ( ".........HARBOUR_DESTROY_BEGINS( %p, %s, %i )", bind->qtObject, bind->szClassName, bind->iFlags ) ); + * bind_ptr = bind->next; + + if( fDelQtObject ) + { + if( bind->pDelFunc != NULL ) + { + HB_TRACE( HB_TR_DEBUG, ( ".........HARBOUR_DESTROYING_ACTUAL_QT_OBJECT( %p, %s, %i )", bind->qtObject, bind->szClassName, bind->iFlags ) ); + if( bind->iFlags & HBQT_BIT_QOBJECT ) + { + HB_TRACE( HB_TR_DEBUG, ( ".........HARBOUR_DESTROYING_ACTUAL_QT_OBJECT_NAMED( %p, %s )", bind->qtObject, ( ( QObject * ) bind->qtObject )->objectName().toAscii().data() ) ); + if( bind->iThreadId == 1 && ( ( QObject * ) bind->qtObject )->objectName() == "PleaseDoNotDelete" ) /* This is a hack: will be removed a bit later */ + { + fDelQtObject = false; + } +// else if( ( QString ) ( ( QObject * ) bind->qtObject )->metaObject()->className() == "QDesktopWidget" ) +// fDelQtObject = false; + } + if( fDelQtObject ) + { + HB_TRACE( HB_TR_DEBUG, ( ".........HARBOUR_DESTROYING_ACTUAL_QT_OBJECT_NAMED( %p, %s )", bind->qtObject, bind->szClassName ) ); + bind->fDeleting = true; + bind->pDelFunc( bind->qtObject, bind->iFlags ); + bind->fDeleting = false; + } + } + } + hb_xfree( bind ); + break; + } + bind_ptr = &bind->next; + } + HBQT_BIND_UNLOCK + } +} + +void hbqt_bindDestroyQtObject( void * qtObject ) +{ + HB_TRACE( HB_TR_DEBUG, ( "............QT_DESTROY_BEGINS( %p )..............", qtObject ) ); + if( qtObject && hb_vmRequestReenter() ) + { + PHBQT_BIND * bind_ptr, bind; + + HBQT_BIND_LOCK + bind_ptr = &( hbqt_bindGetData() ); + while( ( bind = * bind_ptr ) != NULL ) + { + if( bind->qtObject == qtObject ) + { + HB_TRACE( HB_TR_DEBUG, ( "............QT_DESTROYING( %p, %s )", qtObject, bind->szClassName ) ); + * bind_ptr = bind->next; + if( ! bind->fDeleting ) + { + hb_xfree( bind ); + HB_TRACE( HB_TR_DEBUG, ( "............QT_DESTROYED()" ) ); + } + break; + } + bind_ptr = &bind->next; + } + HBQT_BIND_UNLOCK + + hb_vmRequestRestore(); + } +} + HBQSlots * hbqt_bindGetReceiverSlotsByHbObject( PHB_ITEM pObject ) { HBQSlots * pReceiverSlot = NULL; @@ -339,7 +497,7 @@ HBQSlots * hbqt_bindGetReceiverSlotsByHbObject( PHB_ITEM pObject ) { if( bind->hbObject == hbObject ) { - pReceiverSlot = bind->pReceiverSlots; + pReceiverSlot = hbqt_bindGetThreadData()->pReceiverSlots; HB_TRACE( HB_TR_DEBUG, ( "hbqt_bindGetReceiverSlotByHbObject( %p )", bind->qtObject ) ); break; } @@ -364,11 +522,11 @@ HBQEvents * hbqt_bindGetReceiverEventsByHbObject( PHB_ITEM pObject ) { if( bind->hbObject == hbObject ) { - pReceiverEvents = bind->pReceiverEvents; + pReceiverEvents = hbqt_bindGetThreadData()->pReceiverEvents; if( ! bind->fEventFilterInstalled ) { bind->fEventFilterInstalled = true; - bind->pReceiverEvents->hbInstallEventFilter( pObject ); + hbqt_bindGetThreadData()->pReceiverEvents->hbInstallEventFilter( pObject ); } HB_TRACE( HB_TR_DEBUG, ( "hbqt_bindGetReceiverEventsByHbObject( %p )", bind->qtObject ) ); break; @@ -454,105 +612,6 @@ void * hbqt_bindGetQtObject( PHB_ITEM pObject ) return qtObject; } -void hbqt_bindDestroyHbObject( PHB_ITEM pObject ) -{ - void * hbObject = hb_arrayId( pObject ); - - if( hbObject ) - { - PHBQT_BIND * bind_ptr, bind; - - HBQT_BIND_LOCK - bind_ptr = &( hbqt_bindGetData() ); - while( ( bind = * bind_ptr ) != NULL ) - { - if( bind->hbObject == hbObject ) - { - bool fDelQtObject = false; - - if( bind->iFlags & HBQT_BIT_OWNER ) - { - if( bind->iFlags & HBQT_BIT_QOBJECT ) - { - if( ( ( QObject * ) bind->qtObject )->metaObject()->className() != ( const char * ) "QAction" ) - if( ( ( QObject * ) bind->qtObject )->parent() == NULL ) - fDelQtObject = true; - } - else - fDelQtObject = true; - } - - HB_TRACE( HB_TR_DEBUG, ( "..............HARBOUR_DESTROY_BEGINS( %p, %i ).............. %s", bind->qtObject, bind->iFlags, bind->szClassName ) ); - * bind_ptr = bind->next; - - delete bind->pReceiverSlots; - delete bind->pReceiverEvents; - if( fDelQtObject ) - { - if( bind->pDelFunc != NULL ) - { - HB_TRACE( HB_TR_DEBUG, ( ".......HARBOUR_DESTROYING_ACTUAL_QT_OBJECT( %p, %i ).............. %s", bind->qtObject, bind->iFlags, bind->szClassName ) ); - if( bind->iFlags & HBQT_BIT_QOBJECT ) - { - HB_TRACE( HB_TR_DEBUG, ( ".......HARBOUR_DESTROYING_ACTUAL_QT_OBJECT_NAMED( %p, %s )..............", bind->qtObject, ( ( QObject * ) bind->qtObject )->objectName().toAscii().data() ) ); - if( ( QString ) ( ( QObject * ) bind->qtObject )->metaObject()->className() == "QMainWindow" ) - { - if( ( ( QObject * ) bind->qtObject )->objectName() == "PleaseDoNotDelete" ) /* This is a hack: will be removed a bit later */ - fDelQtObject = false; - } - else if( ( QString ) ( ( QObject * ) bind->qtObject )->metaObject()->className() == "QDesktopWidget" ) - fDelQtObject = false; - } - if( fDelQtObject ) - { - HB_TRACE( HB_TR_DEBUG, ( ".......HARBOUR_DESTROYING_ACTUAL_QT_OBJECT_NAMED( %p, %s )", bind->qtObject, bind->szClassName ) ); - bind->fDeleting = true; - bind->pDelFunc( bind->qtObject, bind->iFlags ); - bind->fDeleting = false; - } - } - } - delete bind->pDestroyer; - - hb_xfree( bind ); - break; - } - bind_ptr = &bind->next; - } - HBQT_BIND_UNLOCK - } -} - -void hbqt_bindDestroyQtObject( void * qtObject ) -{ - HB_TRACE( HB_TR_DEBUG, ( "....................................QT_DESTROY_BEGINS( %p )..............", qtObject ) ); - if( qtObject && hb_vmRequestReenter() ) - { - PHBQT_BIND * bind_ptr, bind; - - HBQT_BIND_LOCK - bind_ptr = &( hbqt_bindGetData() ); - while( ( bind = * bind_ptr ) != NULL ) - { - if( bind->qtObject == qtObject ) - { - HB_TRACE( HB_TR_DEBUG, ( "........................QT_DESTROYING( %p ).....%s ... fDeleting=%s", qtObject, bind->szClassName, bind->fDeleting ? "YES" : "NO" ) ); - * bind_ptr = bind->next; - if( ! bind->fDeleting ) - { - hb_xfree( bind ); - HB_TRACE( HB_TR_DEBUG, ( "........................QT_DESTROYED()" ) ); - } - break; - } - bind_ptr = &bind->next; - } - HBQT_BIND_UNLOCK - - hb_vmRequestRestore(); - } -} - void hbqt_bindSetOwner( void * qtObject, HB_BOOL fOwner ) { PHBQT_BIND bind; diff --git a/harbour/contrib/hbqt/qtcore/hbqt_hbqevents.cpp b/harbour/contrib/hbqt/qtcore/hbqt_hbqevents.cpp index 65ecfb5a38..15a721c58e 100644 --- a/harbour/contrib/hbqt/qtcore/hbqt_hbqevents.cpp +++ b/harbour/contrib/hbqt/qtcore/hbqt_hbqevents.cpp @@ -183,10 +183,12 @@ bool HBQEvents::eventFilter( QObject * object, QEvent * event ) hb_itemRelease( pArray ); } } + #if 0 if( eventtype == QEvent::Close ) { stopTheEventChain = true; } + #endif } } hb_vmRequestRestore(); diff --git a/harbour/contrib/hbqt/tests/demoqt.prg b/harbour/contrib/hbqt/tests/demoqt.prg index dbf50ff720..cf07ecd356 100644 --- a/harbour/contrib/hbqt/tests/demoqt.prg +++ b/harbour/contrib/hbqt/tests/demoqt.prg @@ -74,8 +74,8 @@ STATIC oSys, oMenuSys, oActShow, oActHide /*----------------------------------------------------------------------*/ -FUNCTION My_Events( e ) - MsgInfo( "Pressed: " + hb_ntos( e:key() ) ) +FUNCTION My_Events( oWnd, e ) + MsgInfo( oWnd, "Pressed: " + hb_ntos( e:key() ) ) RETURN nil /*----------------------------------------------------------------------*/ @@ -114,7 +114,7 @@ PROCEDURE Main() oBtn := Build_PushButton( oDA, { 30,240 }, { 100,50 } ) oBtn:setStyleSheet( "background: #a00fff;" ) - oWnd:connect( QEvent_KeyPress, {|e| My_Events( e ) } ) + oWnd:connect( QEvent_KeyPress, {|e| My_Events( oWnd, e ) } ) oWnd:connect( QEvent_Close , {|| lExit := .t. } ) oWnd:Show() @@ -170,11 +170,11 @@ PROCEDURE ExecOneMore() aMenu := Build_MenuBar( oWnd ) aTool := Build_ToolBar( oWnd ) oLabel := Build_Label( oDA, { 30,190 }, { 300, 30 } ) - oBtn := Build_PushButton( oDA, { 30,240 }, { 100,50 }, "CLOSE", "This dialog will be closed now!", @lExit ) aGrid := Build_Grid( oDA, { 30, 30 }, { 450,150 } ) aTabs := Build_Tabs( oDA, { 510, 5 }, { 360, 400 } ) oProg := Build_ProgressBar( oDA, { 30,300 }, { 200,30 } ) aList := Build_ListBox( oDA, { 310,240 }, { 150, 100 } ) + oBtn := Build_PushButton( oDA, { 30,240 }, { 100,50 }, "CLOSE", "This dialog will be closed now!", @lExit ) oSBar := QStatusBar( oWnd ) oWnd:setStatusBar( oSBar ) @@ -257,7 +257,7 @@ STATIC FUNCTION Build_MenuBar( oWnd ) oMenu2:addSeparator() oActOther := oMenu2:addAction( "&Another Dialog" ) - oActOther:connect( "triggered(bool)", {|| ExecOneMore() } ) + oActOther:connect( "triggered(bool)", {|| hb_threadStart( {|| ExecOneMore( oWnd ) } ) } ) oMenuBar:addMenu( oMenu2 ) @@ -324,7 +324,7 @@ STATIC FUNCTION Build_PushButton( oWnd, aPos, aSize, cLabel, cMsg, lExit ) IF HB_ISLOGICAL( lExit ) oBtn:connect( "clicked()", {|| lExit := .t. } ) ELSE - oBtn:connect( "clicked()", {|| MsgInfo( cMsg ), lExit := .t. } ) + oBtn:connect( "clicked()", {|| MsgInfo( oWnd, cMsg ), lExit := .t. } ) ENDIF RETURN oBtn @@ -446,7 +446,7 @@ STATIC FUNCTION Build_Controls( oWnd ) LOCAL oEdit, oCheckBox, oComboBox, oSpinBox, oRadioButton oEdit := QLineEdit( oWnd ) - oEdit:connect( "returnPressed()", {|i| i := i, MsgInfo( oEdit:text() ) } ) + oEdit:connect( "returnPressed()", {|i| i := i, MsgInfo( oWnd, oEdit:text() ) } ) oEdit:move( 5, 10 ) oEdit:resize( 345, 30 ) oEdit:setMaxLength( 40 ) @@ -459,13 +459,13 @@ STATIC FUNCTION Build_Controls( oWnd ) oComboBox:addItem( "Third" ) oComboBox:addItem( "First" ) oComboBox:addItem( "Second" ) - oComboBox:connect( "currentIndexChanged(int)", {|i| i := i, MsgInfo( oComboBox:itemText( i ) ) } ) + oComboBox:connect( "currentIndexChanged(int)", {|i| i := i, MsgInfo( oWnd, oComboBox:itemText( i ) ) } ) oComboBox:move( 5, 60 ) oComboBox:resize( 345, 30 ) oComboBox:show() oCheckBox := QCheckBox( oWnd ) - oCheckBox:connect( "stateChanged(int)", {|i| i := i, MsgInfo( IF( i == 0,"Uncheckd","Checked" ) ) } ) + oCheckBox:connect( "stateChanged(int)", {|i| i := i, MsgInfo( oWnd, iif( i == 0,"Uncheckd","Checked" ) ) } ) oCheckBox:setText( "Testing CheckBox HbQt" ) oCheckBox:move( 5, 110 ) oCheckBox:resize( 345, 30 ) @@ -477,7 +477,7 @@ STATIC FUNCTION Build_Controls( oWnd ) oSpinBox:Show() oRadioButton := QRadioButton( oWnd ) - oRadioButton:connect( "clicked()", {|i| i := i, MsgInfo( "Checked" ) } ) + oRadioButton:connect( "clicked()", {|i| i := i, MsgInfo( oWnd, "Checked" ) } ) oRadioButton:Move( 5, 210 ) oRadioButton:ReSize( 345, 30 ) oRadioButton:Show() @@ -514,17 +514,17 @@ STATIC FUNCTION Build_Label( oWnd, aPos, aSize ) /*----------------------------------------------------------------------*/ -STATIC FUNCTION MsgInfo( cMsg ) +STATIC FUNCTION MsgInfo( oWnd, cMsg ) LOCAL oMB - oMB := QMessageBox() + oMB := QMessageBox( oWnd ) oMB:setInformativeText( cMsg ) oMB:setWindowTitle( "Harbour-QT" ) oMB:exec() - oMB := NIL + oMB:setParent( QWidget() ) - RETURN nil + RETURN NIL /*----------------------------------------------------------------------*/ @@ -540,8 +540,8 @@ STATIC FUNCTION FileDialog() /*----------------------------------------------------------------------*/ -STATIC FUNCTION Dialogs( cType ) - LOCAL oDlg //, oUrl +STATIC FUNCTION Dialogs( cType, oParent ) + LOCAL oDlg DO CASE CASE cType == "PageSetup" @@ -557,9 +557,10 @@ STATIC FUNCTION Dialogs( cType ) oDlg:setWindowTitle( "Harbour-QT Wizard to Show Slides etc." ) oDlg:exec() CASE cType == "Colors" - oDlg := QColorDialog() + oDlg := QColorDialog( oParent ) oDlg:setWindowTitle( "Harbour-QT Color Selection Dialog" ) oDlg:exec() + oDlg:setParent( QWidget() ) CASE cType == "WebPage" #if 0 // Till we resolve for oDlg:show() oDlg := QWebView()