26 #include <tqobjectlist.h>
27 #include <tqmetaobject.h>
28 #include <tqvariant.h>
30 #include <tqintdict.h>
31 #include <tqeventloop.h>
40 #include <sys/types.h>
43 #include <sys/socket.h>
57 #include <tqguardedptr.h>
58 #include <tqtextstream.h>
61 #include <tqapplication.h>
62 #include <tqsocketnotifier.h>
65 #include <tqucomextra_p.h>
67 #include <dcopglobal.h>
68 #include <dcopclient.h>
69 #include <dcopobject.h>
71 #if defined TQ_WS_X11 && ! defined K_WS_QTONLY
75 #include <KDE-ICE/ICElib.h>
76 #include <KDE-ICE/ICEutil.h>
77 #include <KDE-ICE/ICEmsg.h>
78 #include <KDE-ICE/ICEproto.h>
83 extern TQMap<TQCString, DCOPObject *> * kde_dcopObjMap;
88 typedef TQAsciiDict<DCOPClient> client_map_t;
89 static client_map_t *DCOPClient_CliMap = 0;
92 client_map_t *cliMap()
94 if (!DCOPClient_CliMap)
95 DCOPClient_CliMap =
new client_map_t;
96 return DCOPClient_CliMap;
101 return cliMap()->find(_appId.data());
105 void registerLocalClient(
const TQCString &_appId,
DCOPClient *client )
107 cliMap()->replace(_appId.data(), client);
111 void unregisterLocalClient(
const TQCString &_appId )
113 client_map_t *map = cliMap();
114 map->remove(_appId.data());
118 template class TQPtrList<DCOPObjectProxy>;
119 template class TQPtrList<DCOPClientTransaction>;
120 template class TQPtrList<_IceConn>;
122 struct DCOPClientMessage
129 class DCOPClient::ReplyStruct
132 enum ReplyStatus { Pending, Ok, Failed };
142 TQCString* replyType;
143 TQByteArray* replyData;
145 TQ_INT32 transactionId;
147 TQGuardedPtr<TQObject> replyObject;
151 class DCOPClientPrivate
159 int majorVersion, minorVersion;
161 static const char* serverAddr;
162 TQSocketNotifier *notifier;
163 bool non_blocking_call_lock;
167 bool accept_calls_override;
168 bool qt_bridge_enabled;
174 TQCString defaultObject;
175 TQPtrList<DCOPClientTransaction> *transactionList;
177 TQ_INT32 transactionId;
187 CARD32 currentKeySaved;
189 TQTimer postMessageTimer;
190 TQPtrList<DCOPClientMessage> messages;
192 TQPtrList<DCOPClient::ReplyStruct> pendingReplies;
193 TQPtrList<DCOPClient::ReplyStruct> asyncReplyQueue;
195 struct LocalTransactionResult
198 TQByteArray replyData;
201 TQIntDict<LocalTransactionResult> localTransActionList;
203 TQTimer eventLoopTimer;
206 class DCOPClientTransaction
216 #if defined(ICEAUTH_PATH)
218 #
if defined(TQ_WS_WIN)
219 access(ICEAUTH_PATH, 0) == 0
221 access(ICEAUTH_PATH, X_OK) == 0
225 return TQCString(ICEAUTH_PATH);
228 #elif defined(Q_OS_WIN32)
232 ret = SearchPathA(NULL,
"iceauth.exe",NULL,
sizeof(szPath)/
sizeof(szPath[0]),szPath,&pszFilePart);
234 return TQCString(szPath);
237 TQCString path = ::getenv(
"PATH");
239 path =
"/bin:/usr/bin";
240 path +=
":/usr/bin/X11:/usr/X11/bin:/usr/X11R6/bin";
241 TQCString fPath = strtok(path.data(),
":\b");
242 while (!fPath.isNull())
245 if (access(fPath.data(), X_OK) == 0)
249 fPath = strtok(NULL,
":\b");
256 static TQCString dcopServerFile(
const TQCString &hostname,
bool old)
258 TQCString fName = ::getenv(
"DCOPAUTHORITY");
259 if (!old && !fName.isEmpty())
262 fName = TQFile::encodeName( TQDir::homeDirPath() );
266 fprintf(stderr,
"Aborting. $HOME is not set.\n");
270 TQCString disp = getenv(
"DISPLAY");
271 #elif defined(TQ_WS_QWS)
272 TQCString disp = getenv(
"QWS_DISPLAY");
280 if((i = disp.findRev(
'.')) > disp.findRev(KPATH_SEPARATOR) && i >= 0)
285 while( (i = disp.find(KPATH_SEPARATOR)) >= 0)
289 fName +=
"/.DCOPserver_";
290 if (hostname.isEmpty())
294 if (getenv(
"XAUTHLOCALHOSTNAME"))
295 fName += getenv(
"XAUTHLOCALHOSTNAME");
296 else if (gethostname(hostName,
sizeof(hostName)))
298 fName +=
"localhost";
302 hostName[
sizeof(hostName)-1] =
'\0';
318 return ::dcopServerFile(hostname,
false);
325 return ::dcopServerFile(hostname,
true);
329 const char* DCOPClientPrivate::serverAddr = 0;
331 static void DCOPProcessInternal( DCOPClientPrivate *d,
int opcode, CARD32 key,
const TQByteArray& dataReceived,
bool canPost );
333 void DCOPClient::handleAsyncReply(ReplyStruct *replyStruct)
335 if (replyStruct->replyObject)
337 TQObject::connect(
this, TQ_SIGNAL(callBack(
int,
const TQCString&,
const TQByteArray &)),
338 replyStruct->replyObject, replyStruct->replySlot);
339 emit callBack(replyStruct->replyId, *(replyStruct->replyType), *(replyStruct->replyData));
340 TQObject::disconnect(
this, TQ_SIGNAL(callBack(
int,
const TQCString&,
const TQByteArray &)),
341 replyStruct->replyObject, replyStruct->replySlot);
349 static void DCOPProcessMessage(IceConn iceConn, IcePointer clientObject,
350 int opcode,
unsigned long length, Bool ,
351 IceReplyWaitInfo *replyWait,
355 DCOPClientPrivate *d =
static_cast<DCOPClientPrivate *
>(clientObject);
356 DCOPClient::ReplyStruct *replyStruct = replyWait ?
static_cast<DCOPClient::ReplyStruct*
>(replyWait->reply) : 0;
358 IceReadMessageHeader(iceConn,
sizeof(DCOPMsg), DCOPMsg, pMsg);
359 CARD32
key = pMsg->key;
363 TQByteArray dataReceived( length );
364 IceReadData(iceConn, length, dataReceived.data() );
369 case DCOPReplyFailed:
371 replyStruct->status = DCOPClient::ReplyStruct::Failed;
372 replyStruct->transactionId = 0;
373 *replyWaitRet = True;
376 tqWarning(
"Very strange! got a DCOPReplyFailed opcode, but we were not waiting for a reply!");
381 TQByteArray* b = replyStruct->replyData;
382 TQCString* t = replyStruct->replyType;
383 replyStruct->status = DCOPClient::ReplyStruct::Ok;
384 replyStruct->transactionId = 0;
386 TQCString calledApp, app;
387 TQDataStream ds( dataReceived, IO_ReadOnly );
388 ds >> calledApp >> app >> *t >> *b;
390 *replyWaitRet = True;
393 tqWarning(
"Very strange! got a DCOPReply opcode, but we were not waiting for a reply!");
398 TQCString calledApp, app;
400 TQDataStream ds( dataReceived, IO_ReadOnly );
401 ds >> calledApp >> app >> id;
402 replyStruct->transactionId = id;
403 replyStruct->calledApp = calledApp;
404 d->pendingReplies.append(replyStruct);
405 *replyWaitRet = True;
408 tqWarning(
"Very strange! got a DCOPReplyWait opcode, but we were not waiting for a reply!");
411 case DCOPReplyDelayed:
413 TQDataStream ds( dataReceived, IO_ReadOnly );
414 TQCString calledApp, app;
417 ds >> calledApp >> app >> id;
418 if (replyStruct && (
id == replyStruct->transactionId) && (calledApp == replyStruct->calledApp))
420 *replyWaitRet = True;
423 for(DCOPClient::ReplyStruct *rs = d->pendingReplies.first(); rs;
424 rs = d->pendingReplies.next())
426 if ((rs->transactionId ==
id) && (rs->calledApp == calledApp))
428 d->pendingReplies.remove();
429 TQByteArray* b = rs->replyData;
430 TQCString* t = rs->replyType;
433 rs->status = DCOPClient::ReplyStruct::Ok;
434 rs->transactionId = 0;
435 if (!rs->replySlot.isEmpty())
437 d->parent->handleAsyncReply(rs);
442 tqWarning(
"Very strange! got a DCOPReplyDelayed opcode, but we were not waiting for a reply!");
448 DCOPProcessInternal( d, opcode, key, dataReceived,
true );
452 void DCOPClient::processPostedMessagesInternal()
454 if ( d->messages.isEmpty() )
456 TQPtrListIterator<DCOPClientMessage> it (d->messages );
457 DCOPClientMessage* msg ;
458 while ( ( msg = it.current() ) ) {
460 if ( d->currentKey && msg->key != d->currentKey )
462 d->messages.removeRef( msg );
463 d->opcode = msg->opcode;
464 DCOPProcessInternal( d, msg->opcode, msg->key, msg->data,
false );
467 if ( !d->messages.isEmpty() )
468 d->postMessageTimer.start( 100,
true );
474 void DCOPProcessInternal( DCOPClientPrivate *d,
int opcode, CARD32 key,
const TQByteArray& dataReceived,
bool canPost )
476 if (!d->accept_calls && (opcode == DCOPSend))
479 IceConn iceConn = d->iceConn;
482 TQDataStream ds( dataReceived, IO_ReadOnly );
486 if (fromApp.isEmpty())
489 if (!d->accept_calls)
492 TQDataStream replyStream( reply, IO_WriteOnly );
494 replyStream << d->appId << fromApp;
495 IceGetHeader( iceConn, d->majorOpcode, DCOPReplyFailed,
496 sizeof(DCOPMsg), DCOPMsg, pMsg );
497 int datalen = reply.size();
499 pMsg->length += datalen;
500 IceSendData( iceConn, datalen, reply.data());
504 TQCString app, objId, fun;
506 ds >> app >> objId >> fun >> data;
507 d->senderId = fromApp;
513 if ( canPost && d->currentKey && key != d->currentKey ) {
514 DCOPClientMessage* msg =
new DCOPClientMessage;
515 msg->opcode = opcode;
517 msg->data = dataReceived;
518 d->messages.append( msg );
519 d->postMessageTimer.start( 0,
true );
527 TQByteArray replyData;
529 CARD32 oldCurrentKey = d->currentKey;
530 if ( opcode != DCOPSend )
533 if ( opcode == DCOPFind )
534 b = c->find(app, objId, fun, data, replyType, replyData );
536 b = c->receive( app, objId, fun, data, replyType, replyData );
539 if ( opcode == DCOPSend )
542 if ((d->currentKey == key) || (oldCurrentKey != 2))
543 d->currentKey = oldCurrentKey;
546 TQDataStream replyStream( reply, IO_WriteOnly );
551 replyStream << d->appId << fromApp << id;
553 IceGetHeader( iceConn, d->majorOpcode, DCOPReplyWait,
554 sizeof(DCOPMsg), DCOPMsg, pMsg );
556 pMsg->length += reply.size();
557 IceSendData( iceConn, reply.size(),
const_cast<char *
>(reply.data()));
564 replyStream << d->appId << fromApp;
565 IceGetHeader( iceConn, d->majorOpcode, DCOPReplyFailed,
566 sizeof(DCOPMsg), DCOPMsg, pMsg );
567 int datalen = reply.size();
569 pMsg->length += datalen;
570 IceSendData( iceConn, datalen,
const_cast<char *
>(reply.data()));
575 replyStream << d->appId << fromApp << replyType << replyData.size();
579 IceGetHeader( iceConn, d->majorOpcode,
DCOPReply,
580 sizeof(DCOPMsg), DCOPMsg, pMsg );
581 int datalen = reply.size() + replyData.size();
583 pMsg->length += datalen;
586 IceSendData( iceConn, reply.size(),
const_cast<char *
>(reply.data()));
587 IceSendData( iceConn, replyData.size(),
const_cast<char *
>(replyData.data()));
592 static IcePoVersionRec DCOPClientVersions[] = {
593 { DCOPVersionMajor, DCOPVersionMinor, DCOPProcessMessage }
601 return dcop_main_client;
606 dcop_main_client = client;
612 d =
new DCOPClientPrivate;
620 d->non_blocking_call_lock =
false;
621 d->registered =
false;
622 d->foreign_server =
true;
623 d->accept_calls =
true;
624 d->accept_calls_override =
false;
625 d->qt_bridge_enabled =
true;
626 d->transactionList = 0L;
627 d->transactionId = 0;
628 TQObject::connect( &d->postMessageTimer, TQ_SIGNAL( timeout() ),
this, TQ_SLOT( processPostedMessagesInternal() ) );
629 TQObject::connect( &d->eventLoopTimer, TQ_SIGNAL( timeout() ),
this, TQ_SLOT( eventLoopTimeout() ) );
637 #ifdef DCOPCLIENT_DEBUG
638 tqWarning(
"d->messages.count() = %d", d->messages.count());
639 TQPtrListIterator<DCOPClientMessage> it (d->messages );
640 DCOPClientMessage* msg ;
641 while ( ( msg = it.current() ) ) {
643 d->messages.removeRef( msg );
644 tqWarning(
"DROPPING UNHANDLED DCOP MESSAGE:");
645 tqWarning(
" opcode = %d key = %d", msg->opcode, msg->key);
646 TQDataStream ds( msg->data, IO_ReadOnly );
648 TQCString fromApp, app, objId, fun;
649 ds >> fromApp >> app >> objId >> fun;
650 tqWarning(
" from = %s", fromApp.data());
651 tqWarning(
" to = %s / %s / %s", app.data(), objId.data(), fun.data());
656 if (IceConnectionStatus(d->iceConn) == IceConnectAccepted)
660 unregisterLocalClient( d->appId );
663 delete d->transactionList;
664 d->messages.setAutoDelete(
true);
673 TQCString env =
"DCOPSERVER=" + addr;
674 putenv(strdup(env.data()));
675 delete [] DCOPClientPrivate::serverAddr;
676 DCOPClientPrivate::serverAddr = tqstrdup( addr.data() );
681 if (!attachInternal(
true ))
682 if (!attachInternal(
true ))
687 void DCOPClient::bindToApp()
694 d->notifier =
new TQSocketNotifier(
socket(),
695 TQSocketNotifier::Read, 0, 0);
696 TQObject::connect(d->notifier, TQ_SIGNAL(activated(
int)),
703 #ifdef TQ_WS_WIN //TODO: remove (win32 ports sometimes do not create notifiers)
708 d->notifier->setEnabled(
false);
713 #ifdef TQ_WS_WIN //TODO: remove
718 d->notifier->setEnabled(
true);
723 #if defined(TQ_WS_WIN) || defined(TQ_WS_MAC) //TODO: REMOVE
727 return !d->notifier->isEnabled();
730 #if defined(SO_PEERCRED) || defined(LOCAL_PEEREID) || defined(HAVE_GETPEERUCRED)
731 #define USE_PEER_IS_US
733 static bool peerIsUs(
int sockfd)
736 #if defined(__OpenBSD__)
737 struct sockpeercred cred;
741 socklen_t siz =
sizeof(cred);
742 if (getsockopt(sockfd, SOL_SOCKET, SO_PEERCRED, &cred, &siz) != 0)
744 return (cred.uid == getuid());
745 #elif defined LOCAL_PEEREID
747 socklen_t siz =
sizeof(cred);
748 if (getsockopt(sockfd, 0, LOCAL_PEEREID, &cred, &siz) != 0 || siz !=
sizeof(cred))
750 return (cred.unp_euid == geteuid());
751 #elif defined(HAVE_GETPEERUCRED)
752 ucred_t *cred =
nullptr;
755 if (getpeerucred(sockfd, &cred) != 0) {
760 peer_uid = ucred_geteuid(cred);
762 return (peer_uid == getuid());
767 static bool isServerSocketOwnedByUser(
const char*server)
770 if (strncmp(server,
"tcp/", 4) != 0)
775 if (strncmp(server,
"local/", 6) != 0)
777 const char *path = strchr(server, KPATH_SEPARATOR);
782 struct stat stat_buf;
783 if (stat(path, &stat_buf) != 0)
786 return (stat_buf.st_uid == getuid());
792 bool DCOPClient::attachInternal(
bool registerAsAnonymous )
799 if ((d->majorOpcode = IceRegisterForProtocolSetup(
const_cast<char *
>(
"DCOP"),
800 const_cast<char *
>(DCOPVendorString),
801 const_cast<char *
>(DCOPReleaseString),
802 1, DCOPClientVersions,
804 const_cast<char **
>(DCOPAuthNames),
805 DCOPClientAuthProcs, 0L)) < 0) {
806 emit
attachFailed(TQString::fromLatin1(
"Communications could not be established." ));
810 bool bClearServerAddr =
false;
812 if (!d->serverAddr) {
816 dcopSrv = ::getenv(
"DCOPSERVER");
817 if (dcopSrv.isEmpty()) {
819 TQFile f(TQFile::decodeName(fName));
820 if (!f.open(IO_ReadOnly)) {
821 emit
attachFailed(TQString::fromLatin1(
"Could not read network connection list.\n" )+TQFile::decodeName(fName));
824 int size = TQMIN( (
long)1024, f.size() );
825 TQCString contents( size+1 );
826 if ( f.readBlock( contents.data(), size ) != size )
828 tqDebug(
"Error reading from %s, didn't read the expected %d bytes", fName.data(), size);
831 contents[size] =
'\0';
832 int pos = contents.find(
'\n');
835 tqDebug(
"Only one line in dcopserver file !: %s", contents.data());
840 if(contents[pos - 1] ==
'\r')
842 dcopSrv = contents.left( pos );
848 d->serverAddr = tqstrdup(
const_cast<char *
>(dcopSrv.data()) );
849 bClearServerAddr =
true;
852 if ((d->iceConn = IceOpenConnection(
const_cast<char*
>(d->serverAddr),
853 static_cast<IcePointer
>(
this), False, d->majorOpcode,
854 sizeof(errBuf), errBuf)) == 0L) {
855 tqDebug(
"DCOPClient::attachInternal. Attach failed %s", errBuf);
857 if (bClearServerAddr) {
858 delete [] d->serverAddr;
864 fcntl(
socket(), F_SETFL, FD_CLOEXEC);
866 IceSetShutdownNegotiation(d->iceConn, False);
871 setupstat = IceProtocolSetup(d->iceConn, d->majorOpcode,
872 static_cast<IcePointer
>(d),
874 &(d->majorVersion), &(d->minorVersion),
875 &(vendor), &(release), 1024, errBuf);
876 if (vendor) free(vendor);
877 if (release) free(release);
879 if (setupstat == IceProtocolSetupFailure ||
880 setupstat == IceProtocolSetupIOError) {
881 IceCloseConnection(d->iceConn);
883 if (bClearServerAddr) {
884 delete [] d->serverAddr;
889 }
else if (setupstat == IceProtocolAlreadyActive) {
890 if (bClearServerAddr) {
891 delete [] d->serverAddr;
895 emit
attachFailed(TQString::fromLatin1(
"internal error in IceOpenConnection" ));
900 if (IceConnectionStatus(d->iceConn) != IceConnectAccepted) {
901 if (bClearServerAddr) {
902 delete [] d->serverAddr;
905 emit
attachFailed(TQString::fromLatin1(
"DCOP server did not accept the connection." ));
909 #ifdef USE_PEER_IS_US
910 d->foreign_server = !peerIsUs(
socket());
912 d->foreign_server = !isServerSocketOwnedByUser(d->serverAddr);
914 if (!d->accept_calls_override)
915 d->accept_calls = !d->foreign_server;
919 if ( registerAsAnonymous )
931 IceProtocolShutdown(d->iceConn, d->majorOpcode);
932 status = IceCloseConnection(d->iceConn);
933 if (status != IceClosedNow)
940 unregisterLocalClient(d->appId);
944 d->registered =
false;
945 d->foreign_server =
true;
954 return (IceConnectionStatus(d->iceConn) == IceConnectAccepted);
970 d->accept_calls_override =
true;
975 return d->qt_bridge_enabled;
980 d->qt_bridge_enabled = b;
987 TQCString _appId =
appId;
991 pid.sprintf(
"-%d", getpid());
992 _appId = _appId + pid;
995 if( d->appId == _appId )
998 #if 0 // no need to detach, dcopserver can handle renaming
1006 if (!attachInternal(
false ))
1007 if (!attachInternal(
false ))
1012 TQCString replyType;
1013 TQByteArray data, replyData;
1014 TQDataStream arg( data, IO_WriteOnly );
1016 if (
call(
"DCOPServer",
"",
"registerAs(TQCString)", data, replyType, replyData ) ) {
1017 TQDataStream reply( replyData, IO_ReadOnly );
1022 d->registered = !result.isNull();
1025 registerLocalClient( d->appId,
this );
1032 return d->registered;
1045 return IceConnectionNumber(d->iceConn);
1049 static inline bool isIdentChar(
char x )
1051 return x ==
'_' || (x >=
'0' && x <=
'9') ||
1052 (x >=
'a' && x <=
'z') || (x >=
'A' && x <=
'Z');
1056 if ( fun.isEmpty() )
1058 TQCString result( fun.size() );
1059 char *from =
const_cast<TQCString&
>(fun).data();
1060 char *to = result.data();
1064 while ( *from && isspace(*from) )
1066 if ( last && isIdentChar( last ) && isIdentChar( *from ) )
1068 while ( *from && !isspace(*from) ) {
1075 if ( to > first && *(to-1) == 0x20 )
1078 result.resize( (
int)((long)to - (
long)result.data()) + 1 );
1090 const TQCString &remFun,
const TQByteArray &data)
1092 if (remApp.isEmpty())
1096 if ( localClient ) {
1097 bool saveTransaction = d->transaction;
1098 TQ_INT32 saveTransactionId = d->transactionId;
1099 TQCString saveSenderId = d->senderId;
1102 TQCString replyType;
1103 TQByteArray replyData;
1104 (void) localClient->receive( remApp, remObjId, remFun, data, replyType, replyData );
1106 d->transaction = saveTransaction;
1107 d->transactionId = saveTransactionId;
1108 d->senderId = saveSenderId;
1123 TQDataStream ds(ba, IO_WriteOnly);
1126 IceGetHeader(d->iceConn, d->majorOpcode, DCOPSend,
1127 sizeof(DCOPMsg), DCOPMsg, pMsg);
1130 int datalen = ba.size() + data.size();
1131 pMsg->length += datalen;
1133 IceSendData( d->iceConn, ba.size(),
const_cast<char *
>(ba.data()) );
1134 IceSendData( d->iceConn, data.size(),
const_cast<char *
>(data.data()) );
1138 if (IceConnectionStatus(d->iceConn) == IceConnectAccepted)
1144 const TQCString &remFun,
const TQString &data)
1147 TQDataStream ds(ba, IO_WriteOnly);
1149 return send(remApp, remObjId, remFun, ba);
1153 const TQCString &remFun,
const TQByteArray &data,
1154 TQCString &foundApp, TQCString &foundObj,
1157 return findObject( remApp, remObj, remFun, data, foundApp, foundObj, useEventLoop, -1 );
1161 const TQCString &remFun,
const TQByteArray &data,
1162 TQCString &foundApp, TQCString &foundObj,
1163 bool useEventLoop,
int timeout)
1165 QCStringList appList;
1166 TQCString app = remApp;
1173 if (app[app.length()-1] ==
'*')
1178 int len = app.length()-1;
1180 for( QCStringList::ConstIterator it = apps.begin();
1184 if ( strncmp( (*it).data(), app.data(), len) == 0)
1185 appList.append(*it);
1190 appList.append(app);
1194 for(
int phase=1; phase <= 2; phase++)
1196 for( QCStringList::ConstIterator it = appList.begin();
1197 it != appList.end();
1200 TQCString remApp = *it;
1201 TQCString replyType;
1202 TQByteArray replyData;
1203 bool result =
false;
1206 if ( (phase == 1) && localClient ) {
1208 bool saveTransaction = d->transaction;
1209 TQ_INT32 saveTransactionId = d->transactionId;
1210 TQCString saveSenderId = d->senderId;
1213 result = localClient->find( remApp, remObj, remFun, data, replyType, replyData );
1219 TQApplication::eventLoop()->processEvents( TQEventLoop::WaitForMore);
1220 }
while( !localClient->isLocalTransactionFinished(
id, replyType, replyData));
1223 d->transaction = saveTransaction;
1224 d->transactionId = saveTransactionId;
1225 d->senderId = saveSenderId;
1227 else if ((phase == 2) && !localClient)
1230 result = callInternal(remApp, remObj, remFun, data,
1231 replyType, replyData, useEventLoop, timeout, DCOPFind);
1236 if (replyType ==
"DCOPRef")
1239 TQDataStream reply( replyData, IO_ReadOnly );
1242 if (ref.app() == remApp)
1245 foundApp = ref.
app();
1246 foundObj = ref.object();
1257 TQCString&, TQByteArray &)
1264 TQCString replyType;
1265 TQByteArray data, replyData;
1266 TQDataStream arg( data, IO_WriteOnly );
1269 if (
call(
"DCOPServer",
"",
"isApplicationRegistered(TQCString)", data, replyType, replyData ) ) {
1270 TQDataStream reply( replyData, IO_ReadOnly );
1278 TQCString replyType;
1279 TQByteArray data, replyData;
1280 QCStringList result;
1281 if (
call(
"DCOPServer",
"",
"registeredApplications()", data, replyType, replyData ) ) {
1282 TQDataStream reply( replyData, IO_ReadOnly );
1290 TQCString replyType;
1291 TQByteArray data, replyData;
1292 QCStringList result;
1295 if (
call( remApp,
"DCOPClient",
"objects()", data, replyType, replyData ) ) {
1296 TQDataStream reply( replyData, IO_ReadOnly );
1306 TQCString replyType;
1307 TQByteArray data, replyData;
1308 QCStringList result;
1311 if (
call( remApp, remObj,
"interfaces()", data, replyType, replyData ) && replyType ==
"QCStringList") {
1312 TQDataStream reply( replyData, IO_ReadOnly );
1322 TQCString replyType;
1323 TQByteArray data, replyData;
1324 QCStringList result;
1327 if (
call( remApp, remObj,
"functions()", data, replyType, replyData ) && replyType ==
"QCStringList") {
1328 TQDataStream reply( replyData, IO_ReadOnly );
1339 TQDataStream ds(data, IO_WriteOnly);
1340 ds << static_cast<TQ_INT8>(enabled);
1342 TQCString replyType;
1344 if (!
call(
"DCOPServer",
"",
"setNotifications( bool )", data, replyType, reply))
1345 tqWarning(
"I couldn't enable notifications at the dcopserver!");
1351 TQDataStream ds(data, IO_WriteOnly);
1352 ds << static_cast<TQ_INT8>( daemonMode );
1354 TQCString replyType;
1356 if (!
call(
"DCOPServer",
"",
"setDaemonMode(bool)", data, replyType, reply))
1357 tqWarning(
"I couldn't enable daemon mode at the dcopserver!");
1367 static void fillQtObjects( QCStringList& l, TQObject* o, TQCString path )
1369 if ( !path.isEmpty() )
1373 const TQObjectList list = o ? o->childrenListObject() : TQObject::objectTreesListObject();
1374 if ( !list.isEmpty() ) {
1375 TQObjectListIt it( list );
1377 while ( (obj=it.current()) ) {
1379 TQCString n = obj->name();
1380 if ( n ==
"unnamed" || n.isEmpty() )
1382 n.sprintf(
"%p", (
void *) obj);
1383 n = TQString(TQString(
"unnamed%1(%2, %3)").arg(++unnamed).arg(obj->className()).arg(TQString(n))).latin1();
1385 TQCString fn = path + n;
1387 if ( !obj->childrenListObject().isEmpty() )
1388 fillQtObjects( l, obj, fn );
1398 O (
const TQCString& str, TQObject* obj ):s(str), o(obj){}
1404 static void fillQtObjectsEx( TQValueList<O>& l, TQObject* o, TQCString path )
1406 if ( !path.isEmpty() )
1410 const TQObjectList list = o ? o->childrenListObject() : TQObject::objectTreesListObject();
1411 if ( !list.isEmpty() ) {
1412 TQObjectListIt it( list );
1414 while ( (obj=it.current()) ) {
1416 TQCString n = obj->name();
1417 if ( n ==
"unnamed" || n.isEmpty() )
1419 n.sprintf(
"%p", (
void *) obj);
1420 n = TQString(TQString(
"unnamed%1(%2, %3)").arg(++unnamed).arg(obj->className()).arg(TQString(n))).latin1();
1422 TQCString fn = path + n;
1423 l.append( O( fn, obj ) );
1424 if ( !obj->childrenListObject().isEmpty() )
1425 fillQtObjectsEx( l, obj, fn );
1431 static TQObject* findQtObject( TQCString
id )
1433 TQRegExp expr(
id );
1435 fillQtObjectsEx( l, 0,
"qt" );
1437 TQObject* firstContains = 0L;
1438 for ( TQValueList<O>::ConstIterator it = l.begin(); it != l.end(); ++it ) {
1439 if ( (*it).s ==
id )
1441 if ( !firstContains && (*it).s.contains( expr ) ) {
1442 firstContains = (*it).o;
1445 return firstContains;
1448 static QCStringList findQtObjects( TQCString
id )
1450 TQRegExp expr(
id );
1452 fillQtObjectsEx( l, 0,
"qt" );
1453 QCStringList result;
1454 for ( TQValueList<O>::ConstIterator it = l.begin(); it != l.end(); ++it ) {
1455 if ( (*it).s.contains( expr ) )
1461 static bool receiveQtObject(
const TQCString &objId,
const TQCString &fun,
const TQByteArray &data,
1462 TQCString& replyType, TQByteArray &replyData)
1464 if ( objId ==
"qt" ) {
1465 if ( fun ==
"interfaces()" ) {
1466 replyType =
"QCStringList";
1467 TQDataStream reply( replyData, IO_WriteOnly );
1473 }
else if ( fun ==
"functions()" ) {
1474 replyType =
"QCStringList";
1475 TQDataStream reply( replyData, IO_WriteOnly );
1477 l <<
"QCStringList functions()";
1478 l <<
"QCStringList interfaces()";
1479 l <<
"QCStringList objects()";
1480 l <<
"QCStringList find(TQCString)";
1483 }
else if ( fun ==
"objects()" ) {
1484 replyType =
"QCStringList";
1485 TQDataStream reply( replyData, IO_WriteOnly );
1487 fillQtObjects( l, 0,
"qt" );
1490 }
else if ( fun ==
"find(TQCString)" ) {
1491 TQDataStream ds( data, IO_ReadOnly );
1494 replyType =
"QCStringList";
1495 TQDataStream reply( replyData, IO_WriteOnly );
1496 reply << findQtObjects(
id ) ;
1499 }
else if ( objId.left(3) ==
"qt/" ) {
1500 TQObject* o = findQtObject( objId );
1503 if ( fun ==
"functions()" ) {
1504 replyType =
"QCStringList";
1505 TQDataStream reply( replyData, IO_WriteOnly );
1507 l <<
"QCStringList functions()";
1508 l <<
"QCStringList interfaces()";
1509 l <<
"QCStringList properties()";
1510 l <<
"bool setProperty(TQCString,TQVariant)";
1511 l <<
"TQVariant property(TQCString)";
1512 TQStrList lst = o->metaObject()->slotNames(
true );
1514 for ( TQPtrListIterator<char> it( lst ); it.current(); ++it ) {
1515 if ( o->metaObject()->slot( i++,
true )->access != TQMetaData::Public )
1517 TQCString slot = it.current();
1518 if ( slot.contains(
"()" ) ) {
1519 slot.prepend(
"void ");
1525 }
else if ( fun ==
"interfaces()" ) {
1526 replyType =
"QCStringList";
1527 TQDataStream reply( replyData, IO_WriteOnly );
1529 TQMetaObject *meta = o->metaObject();
1531 l.prepend( meta->className() );
1532 meta = meta->superClass();
1536 }
else if ( fun ==
"properties()" ) {
1537 replyType =
"QCStringList";
1538 TQDataStream reply( replyData, IO_WriteOnly );
1540 TQStrList lst = o->metaObject()->propertyNames(
true );
1541 for ( TQPtrListIterator<char> it( lst ); it.current(); ++it ) {
1542 TQMetaObject *mo = o->metaObject();
1543 const TQMetaProperty* p = mo->property( mo->findProperty( it.current(),
true ),
true );
1546 TQCString prop = p->type();
1549 if ( !p->writable() )
1550 prop +=
" readonly";
1555 }
else if ( fun ==
"property(TQCString)" ) {
1556 replyType =
"TQVariant";
1557 TQDataStream ds( data, IO_ReadOnly );
1560 TQVariant result = o->property( name );
1561 TQDataStream reply( replyData, IO_WriteOnly );
1564 }
else if ( fun ==
"setProperty(TQCString,TQVariant)" ) {
1565 TQDataStream ds( data, IO_ReadOnly );
1568 ds >>
name >> value;
1570 TQDataStream reply( replyData, IO_WriteOnly );
1571 reply << (TQ_INT8) o->setProperty( name, value );
1574 int slot = o->metaObject()->findSlot( fun,
true );
1578 o->tqt_invoke( slot, uo );
1595 bool DCOPClient::receive(
const TQCString &,
const TQCString &objId,
1596 const TQCString &fun,
const TQByteArray &data,
1597 TQCString& replyType, TQByteArray &replyData)
1599 d->transaction =
false;
1600 if ( objId ==
"DCOPClient" ) {
1601 if ( fun ==
"objects()" ) {
1602 replyType =
"QCStringList";
1603 TQDataStream reply( replyData, IO_WriteOnly );
1605 if (d->qt_bridge_enabled)
1609 if ( kde_dcopObjMap ) {
1610 TQMap<TQCString, DCOPObject *>::ConstIterator it( kde_dcopObjMap->begin());
1611 for (; it != kde_dcopObjMap->end(); ++it) {
1612 if ( !it.key().isEmpty() ) {
1613 if ( it.key() == d->defaultObject )
1624 if ( objId.isEmpty() || objId ==
"DCOPClient" ) {
1625 if ( fun ==
"applicationRegistered(TQCString)" ) {
1626 TQDataStream ds( data, IO_ReadOnly );
1631 }
else if ( fun ==
"applicationRemoved(TQCString)" ) {
1632 TQDataStream ds( data, IO_ReadOnly );
1639 if (
process( fun, data, replyType, replyData ) )
1643 }
else if (d->qt_bridge_enabled &&
1644 (objId ==
"qt" || objId.left(3) ==
"qt/") ) {
1645 return receiveQtObject( objId, fun, data, replyType, replyData );
1648 if ( objId.isEmpty() || objId ==
"default" ) {
1651 objPtr->setCallingDcopClient(
this);
1652 if (objPtr->
process(fun, data, replyType, replyData))
1660 if (!objId.isEmpty() && ((objId.length()>0)?(objId[objId.length()-1] ==
'*'):0)) {
1663 TQPtrList<DCOPObject> matchList =
1666 objPtr != 0L; objPtr = matchList.next()) {
1667 objPtr->setCallingDcopClient(
this);
1668 if (!objPtr->
process(fun, data, replyType, replyData))
1673 if ( DCOPObjectProxy::proxies ) {
1674 for ( TQPtrListIterator<DCOPObjectProxy> it( *DCOPObjectProxy::proxies ); it.current(); ++it ) {
1676 if ( it.current()->process( objId, fun, data, replyType, replyData ) )
1684 objPtr->setCallingDcopClient(
this);
1685 if (!objPtr->
process(fun, data, replyType, replyData)) {
1697 static bool findResultOk(TQCString &replyType, TQByteArray &replyData)
1700 if (replyType !=
"bool")
return false;
1702 TQDataStream reply( replyData, IO_ReadOnly );
1705 if (!success)
return false;
1711 static bool findSuccess(
const TQCString &app,
const TQCString objId, TQCString &replyType, TQByteArray &replyData)
1714 replyType =
"DCOPRef";
1716 replyData = TQByteArray();
1717 TQDataStream final_reply( replyData, IO_WriteOnly );
1723 bool DCOPClient::find(
const TQCString &app,
const TQCString &objId,
1724 const TQCString &fun,
const TQByteArray &data,
1725 TQCString& replyType, TQByteArray &replyData)
1727 d->transaction =
false;
1728 if ( !app.isEmpty() && app != d->appId && app[app.length()-1] !=
'*') {
1729 tqWarning(
"WEIRD! we somehow received a DCOP message w/a different appId");
1733 if (objId.isEmpty() || objId[objId.length()-1] !=
'*')
1738 return findSuccess(app, objId, replyType, replyData);
1742 if (receive(app, objId, fun, data, replyType, replyData))
1744 if (findResultOk(replyType, replyData))
1745 return findSuccess(app, objId, replyType, replyData);
1751 TQPtrList<DCOPObject> matchList =
1754 objPtr != 0L; objPtr = matchList.next())
1757 replyData = TQByteArray();
1759 return findSuccess(app, objPtr->
objId(), replyType, replyData);
1760 objPtr->setCallingDcopClient(
this);
1761 if (objPtr->
process(fun, data, replyType, replyData))
1762 if (findResultOk(replyType, replyData))
1763 return findSuccess(app, objPtr->
objId(), replyType, replyData);
1771 const TQCString &remFun,
const TQByteArray &data,
1772 TQCString& replyType, TQByteArray &replyData,
1775 return call( remApp, remObjId, remFun, data, replyType, replyData, useEventLoop, -1,
false );
1779 const TQCString &remFun,
const TQByteArray &data,
1780 TQCString& replyType, TQByteArray &replyData,
1781 bool useEventLoop,
int timeout)
1783 return call( remApp, remObjId, remFun, data, replyType, replyData, useEventLoop, timeout,
false );
1787 const TQCString &remFun,
const TQByteArray &data,
1788 TQCString& replyType, TQByteArray &replyData,
1789 bool useEventLoop,
int timeout,
bool forceRemote)
1791 if (remApp.isEmpty())
1795 if ( localClient && !forceRemote ) {
1796 bool saveTransaction = d->transaction;
1797 TQ_INT32 saveTransactionId = d->transactionId;
1798 TQCString saveSenderId = d->senderId;
1801 bool b = localClient->receive( remApp, remObjId, remFun, data, replyType, replyData );
1807 TQApplication::eventLoop()->processEvents(TQEventLoop::WaitForMore);
1808 }
while( !localClient->isLocalTransactionFinished(
id, replyType, replyData));
1811 d->transaction = saveTransaction;
1812 d->transactionId = saveTransactionId;
1813 d->senderId = saveSenderId;
1817 return callInternal(remApp, remObjId, remFun, data,
1818 replyType, replyData, useEventLoop, timeout, DCOPCall);
1821 void DCOPClient::asyncReplyReady()
1823 while( d->asyncReplyQueue.count() )
1825 ReplyStruct *replyStruct = d->asyncReplyQueue.take(0);
1826 handleAsyncReply(replyStruct);
1831 const TQCString &remFun,
const TQByteArray &data,
1832 TQObject *callBackObj,
const char *callBackSlot)
1834 TQCString replyType;
1835 TQByteArray replyData;
1837 ReplyStruct *replyStruct =
new ReplyStruct;
1838 replyStruct->replyType =
new TQCString;
1839 replyStruct->replyData =
new TQByteArray;
1840 replyStruct->replyObject = callBackObj;
1841 replyStruct->replySlot = callBackSlot;
1842 replyStruct->replyId = ++d->transactionId;
1843 if (d->transactionId < 0)
1844 d->transactionId = 0;
1846 bool b = callInternal(remApp, remObjId, remFun, data,
1847 replyStruct,
false, -1, DCOPCall);
1850 delete replyStruct->replyType;
1851 delete replyStruct->replyData;
1856 if (replyStruct->transactionId == 0)
1859 TQTimer::singleShot(0,
this, TQ_SLOT(asyncReplyReady()));
1860 d->asyncReplyQueue.append(replyStruct);
1863 return replyStruct->replyId;
1866 bool DCOPClient::callInternal(
const TQCString &remApp,
const TQCString &remObjId,
1867 const TQCString &remFun,
const TQByteArray &data,
1868 TQCString& replyType, TQByteArray &replyData,
1869 bool useEventLoop,
int timeout,
int minor_opcode)
1871 ReplyStruct replyStruct;
1872 replyStruct.replyType = &replyType;
1873 replyStruct.replyData = &replyData;
1874 return callInternal(remApp, remObjId, remFun, data, &replyStruct, useEventLoop, timeout, minor_opcode);
1877 bool DCOPClient::callInternal(
const TQCString &remApp,
const TQCString &remObjId,
1878 const TQCString &remFun,
const TQByteArray &data,
1879 ReplyStruct *replyStruct,
1880 bool useEventLoop,
int timeout,
int minor_opcode)
1887 CARD32 oldCurrentKey = d->currentKey;
1888 if ( !d->currentKey )
1889 d->currentKey = d->key;
1892 TQDataStream ds(ba, IO_WriteOnly);
1895 IceGetHeader(d->iceConn, d->majorOpcode, minor_opcode,
1896 sizeof(DCOPMsg), DCOPMsg, pMsg);
1898 pMsg->key = d->currentKey;
1899 int datalen = ba.size() + data.size();
1900 pMsg->length += datalen;
1904 IceSendData(d->iceConn, ba.size(),
const_cast<char *
>(ba.data()));
1905 IceSendData(d->iceConn, data.size(),
const_cast<char *
>(data.data()));
1907 if (IceConnectionStatus(d->iceConn) != IceConnectAccepted)
1910 IceFlush (d->iceConn);
1912 IceReplyWaitInfo waitInfo;
1913 waitInfo.sequence_of_request = IceLastSentSequenceNumber(d->iceConn);
1914 waitInfo.major_opcode_of_request = d->majorOpcode;
1915 waitInfo.minor_opcode_of_request = minor_opcode;
1917 replyStruct->transactionId = -1;
1918 waitInfo.reply =
static_cast<IcePointer
>(replyStruct);
1920 Bool readyRet = False;
1921 IceProcessMessagesStatus s;
1927 gettimeofday( &time_start, NULL );
1928 time_left = timeout;
1931 bool checkMessages =
true;
1933 ? d->notifier != NULL
1935 const int guiTimeout = 100;
1936 checkMessages =
false;
1938 int msecs = useEventLoop
1944 FD_SET(
socket(), &fds );
1945 tv.tv_sec = msecs / 1000;
1946 tv.tv_usec = (msecs % 1000) * 1000;
1947 if ( select(
socket() + 1, &fds, 0, 0, &tv ) <= 0 ) {
1948 if( useEventLoop && (timeout < 0 || time_left > guiTimeout)) {
1951 bool old_lock = d->non_blocking_call_lock;
1953 d->non_blocking_call_lock =
true;
1957 d->eventLoopTimer.start(time_left - guiTimeout,
true);
1958 tqApp->enter_loop();
1959 d->eventLoopTimer.stop();
1961 d->non_blocking_call_lock =
false;
1968 checkMessages =
true;
1974 if( replyStruct->transactionId != -1 )
1976 if (replyStruct->transactionId == 0)
1978 if (!replyStruct->replySlot.isEmpty())
1982 if( checkMessages ) {
1983 s = IceProcessMessages(d->iceConn, &waitInfo,
1985 if (s == IceProcessMessagesIOError) {
1987 d->currentKey = oldCurrentKey;
1992 if( replyStruct->transactionId != -1 )
1994 if (replyStruct->transactionId == 0)
1996 if (!replyStruct->replySlot.isEmpty())
2003 gettimeofday( &time_now, NULL );
2004 time_left = timeout -
2005 ((time_now.tv_sec - time_start.tv_sec) * 1000) -
2006 ((time_now.tv_usec - time_start.tv_usec) / 1000);
2013 useEventLoop =
false;
2016 *(replyStruct->replyType) = TQCString();
2017 *(replyStruct->replyData) = TQByteArray();
2018 replyStruct->status = ReplyStruct::Failed;
2024 if ( d->non_blocking_call_lock ) {
2028 d->currentKey = oldCurrentKey;
2029 return replyStruct->status != ReplyStruct::Failed;
2032 void DCOPClient::eventLoopTimeout()
2043 timeout.tv_usec = 0;
2046 int result = select(fd+1, &fds, 0, 0, &timeout);
2050 if ( d->non_blocking_call_lock ) {
2058 d->notifier->deleteLater();
2060 tqWarning(
"received an error processing data from the DCOP server!");
2064 IceProcessMessagesStatus s = IceProcessMessages(d->iceConn, 0, 0);
2066 if (s == IceProcessMessagesIOError) {
2068 tqWarning(
"received an error processing data from the DCOP server!");
2075 d->defaultObject = objId;
2081 return d->defaultObject;
2085 DCOPClient::isLocalTransactionFinished(TQ_INT32
id, TQCString &replyType, TQByteArray &replyData)
2087 DCOPClientPrivate::LocalTransactionResult *result = d->localTransActionList.take(
id);
2091 replyType = result->replyType;
2092 replyData = result->replyData;
2098 DCOPClientTransaction *
2101 if (d->opcode == DCOPSend)
2103 if (!d->transactionList)
2104 d->transactionList =
new TQPtrList<DCOPClientTransaction>;
2106 d->transaction =
true;
2107 DCOPClientTransaction *trans =
new DCOPClientTransaction();
2108 trans->senderId = d->senderId;
2109 trans->id = ++d->transactionId;
2110 if (d->transactionId < 0)
2111 d->transactionId = 0;
2112 trans->key = d->currentKey;
2114 d->transactionList->append( trans );
2123 return d->transactionId;
2130 TQByteArray &replyData)
2138 if ( !d->transactionList) {
2139 tqWarning(
"Transaction unknown: No pending transactions!");
2143 if ( !d->transactionList->removeRef( trans ) ) {
2144 tqWarning(
"Transaction unknown: Not on list of pending transactions!");
2148 if (trans->senderId.isEmpty())
2151 DCOPClientPrivate::LocalTransactionResult *result =
new DCOPClientPrivate::LocalTransactionResult();
2152 result->replyType = replyType;
2153 result->replyData = replyData;
2155 d->localTransActionList.insert(trans->id, result);
2165 TQDataStream ds(ba, IO_WriteOnly);
2166 ds << d->appId << trans->senderId << trans->id << replyType << replyData;
2168 IceGetHeader(d->iceConn, d->majorOpcode, DCOPReplyDelayed,
2169 sizeof(DCOPMsg), DCOPMsg, pMsg);
2170 pMsg->key = trans->key;
2171 pMsg->length += ba.size();
2173 IceSendData( d->iceConn, ba.size(),
const_cast<char *
>(ba.data()) );
2193 const TQCString &signal,
2194 const TQCString &receiverObj,
const TQCString &slot,
bool Volatile)
2196 TQCString replyType;
2197 TQByteArray data, replyData;
2198 TQ_INT8 iVolatile = Volatile ? 1 : 0;
2200 TQDataStream args(data, IO_WriteOnly );
2203 if (!
call(
"DCOPServer", 0,
2204 "connectSignal(TQCString,TQCString,TQCString,TQCString,TQCString,bool)",
2205 data, replyType, replyData))
2210 if (replyType !=
"bool")
2213 TQDataStream reply(replyData, IO_ReadOnly );
2216 return (result != 0);
2221 const TQCString &receiverObj,
const TQCString &slot,
bool Volatile)
2228 const TQCString &signal,
2229 const TQCString &receiverObj,
const TQCString &slot)
2231 TQCString replyType;
2232 TQByteArray data, replyData;
2234 TQDataStream args(data, IO_WriteOnly );
2237 if (!
call(
"DCOPServer", 0,
2238 "disconnectSignal(TQCString,TQCString,TQCString,TQCString,TQCString)",
2239 data, replyType, replyData))
2244 if (replyType !=
"bool")
2247 TQDataStream reply(replyData, IO_ReadOnly );
2250 return (result != 0);
2255 const TQCString &receiverObj,
const TQCString &slot)
2261 DCOPClient::setPriorityCall(
bool b)
2265 if (d->currentKey == 2)
2267 d->currentKeySaved = d->currentKey;
2272 if (d->currentKey != 2)
2274 d->currentKey = d->currentKeySaved;
2275 if ( !d->messages.isEmpty() )
2276 d->postMessageTimer.start( 0,
true );
2283 DCOPClient::emergencyClose()
2285 TQPtrList<DCOPClient> list;
2286 client_map_t *map = DCOPClient_CliMap;
2288 TQAsciiDictIterator<DCOPClient> it(*map);
2289 while(it.current()) {
2290 list.removeRef(it.current());
2291 list.append(it.current());
2294 for(
DCOPClient *cl = list.first(); cl; cl = list.next())
2296 if (cl->d->iceConn) {
2297 IceProtocolShutdown(cl->d->iceConn, cl->d->majorOpcode);
2298 IceCloseConnection(cl->d->iceConn);
2299 cl->d->iceConn = 0L;
2305 DCOPClient::postMortemSender()
2307 if (!dcop_main_client)
2309 if (dcop_main_client->d->senderId.isEmpty())
2311 return dcop_main_client->d->senderId.data();
2315 DCOPClient::postMortemObject()
2317 if (!dcop_main_client)
2319 return dcop_main_client->d->objId.data();
2322 DCOPClient::postMortemFunction()
2324 if (!dcop_main_client)
2326 return dcop_main_client->d->function.data();
2329 void DCOPClient::virtual_hook(
int,
void* )
2332 #include <dcopclient.moc>