diff options
Diffstat (limited to 'kdecore/kuniqueapplication.cpp')
-rw-r--r-- | kdecore/kuniqueapplication.cpp | 495 |
1 files changed, 0 insertions, 495 deletions
diff --git a/kdecore/kuniqueapplication.cpp b/kdecore/kuniqueapplication.cpp deleted file mode 100644 index 193aafcd3..000000000 --- a/kdecore/kuniqueapplication.cpp +++ /dev/null @@ -1,495 +0,0 @@ -/* This file is part of the KDE libraries - Copyright (c) 1999 Preston Brown <pbrown@kde.org> - - $Id$ - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public License - along with this library; see the file COPYING.LIB. If not, write to - the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1301, USA. -*/ - -#include <config.h> - -#include <sys/types.h> -#include <sys/wait.h> - -#include <assert.h> -#include <errno.h> -#include <stdlib.h> -#include <unistd.h> - -#include <tqfile.h> -#include <tqptrlist.h> -#include <tqtimer.h> - -#include <dcopclient.h> -#include <kcmdlineargs.h> -#include <kstandarddirs.h> -#include <kaboutdata.h> - -#if defined Q_WS_X11 -#include <kwin.h> -#include <kstartupinfo.h> -#endif - -#include <kconfig.h> -#include "kdebug.h" -#include "kuniqueapplication.h" - -#if defined Q_WS_X11 -#include <netwm.h> -#include <X11/Xlib.h> -#define DISPLAY "DISPLAY" -#else -# ifdef Q_WS_QWS -# define DISPLAY "QWS_DISPLAY" -# else -# define DISPLAY "DISPLAY" -# endif -#endif - -bool KUniqueApplication::s_nofork = false; -bool KUniqueApplication::s_multipleInstances = false; -bool KUniqueApplication::s_uniqueTestDone = false; -bool KUniqueApplication::s_handleAutoStarted = false; - -static KCmdLineOptions kunique_options[] = -{ - { "nofork", "Don't run in the background.", 0 }, - KCmdLineLastOption -}; - -struct DCOPRequest { - TQCString fun; - TQByteArray data; - DCOPClientTransaction *transaction; -}; - -class KUniqueApplicationPrivate { -public: - TQPtrList <DCOPRequest> requestList; - bool processingRequest; - bool firstInstance; -}; - -void -KUniqueApplication::addCmdLineOptions() -{ - KCmdLineArgs::addCmdLineOptions(kunique_options, 0, "kuniqueapp", "kde" ); -} - -bool -KUniqueApplication::start() -{ - if( s_uniqueTestDone ) - return true; - s_uniqueTestDone = true; - addCmdLineOptions(); // Make sure to add cmd line options -#ifdef Q_WS_WIN - s_nofork = true; -#else - KCmdLineArgs *args = KCmdLineArgs::parsedArgs("kuniqueapp"); - s_nofork = !args->isSet("fork"); - delete args; -#endif - - TQCString appName = KCmdLineArgs::about->appName(); - - if (s_nofork) - { - if (s_multipleInstances) - { - TQCString pid; - pid.setNum(getpid()); - appName = appName + "-" + pid; - } - - // Check to make sure that we're actually able to register with the DCOP - // server. - -#ifndef Q_WS_WIN //TODO - if(dcopClient()->registerAs(appName, false).isEmpty()) { - startKdeinit(); - if(dcopClient()->registerAs(appName, false).isEmpty()) { - kdError() << "KUniqueApplication: Can't setup DCOP communication." << endl; - ::exit(255); - } - } -#endif - - // We'll call newInstance in the constructor. Do nothing here. - return true; - } - DCOPClient *dc; - int fd[2]; - signed char result; - if (0 > pipe(fd)) - { - kdError() << "KUniqueApplication: pipe() failed!" << endl; - ::exit(255); - } - int fork_result = fork(); - switch(fork_result) { - case -1: - kdError() << "KUniqueApplication: fork() failed!" << endl; - ::exit(255); - break; - case 0: - // Child - ::close(fd[0]); - if (s_multipleInstances) - appName.append("-").append(TQCString().setNum(getpid())); - dc = dcopClient(); - { - TQCString regName = dc->registerAs(appName, false); - if (regName.isEmpty()) - { - // Check DISPLAY - if (TQCString(getenv(DISPLAY)).isEmpty()) - { - kdError() << "KUniqueApplication: Can't determine DISPLAY. Aborting." << endl; - result = -1; // Error - ::write(fd[1], &result, 1); - ::exit(255); - } - - // Try to launch tdeinit. - startKdeinit(); - regName = dc->registerAs(appName, false); - if (regName.isEmpty()) - { - kdError() << "KUniqueApplication: Can't setup DCOP communication." << endl; - result = -1; - delete dc; // Clean up DCOP commmunication - ::write(fd[1], &result, 1); - ::exit(255); - } - } - if (regName != appName) - { - // Already running. Ok. - result = 0; - delete dc; // Clean up DCOP commmunication - ::write(fd[1], &result, 1); - ::close(fd[1]); -#if 0 -#ifdef Q_WS_X11 - // say we're up and running ( probably no new window will appear ) - KStartupInfoId id; - if( kapp != NULL ) // KApplication constructor unsets the env. variable - id.initId( kapp->startupId()); - else - id = KStartupInfo::currentStartupIdEnv(); - if( !id.none()) - { - Display* disp = XOpenDisplay( NULL ); - if( disp != NULL ) // use extra X connection - { - KStartupInfo::sendFinishX( disp, id ); - XCloseDisplay( disp ); - } - } -#else //FIXME(E): implement -#endif -#endif - return false; - } - dc->setPriorityCall(true); - } - - { -#ifdef Q_WS_X11 - KStartupInfoId id; - if( kapp != NULL ) // KApplication constructor unsets the env. variable - id.initId( kapp->startupId()); - else - id = KStartupInfo::currentStartupIdEnv(); - if( !id.none()) - { // notice about pid change - Display* disp = XOpenDisplay( NULL ); - if( disp != NULL ) // use extra X connection - { - KStartupInfoData data; - data.addPid( getpid()); - KStartupInfo::sendChangeX( disp, id, data ); - XCloseDisplay( disp ); - } - } -#else //FIXME(E): Implement -#endif - } - result = 0; - ::write(fd[1], &result, 1); - ::close(fd[1]); - return true; // Finished. - default: - // Parent -// DCOPClient::emergencyClose(); -// dcopClient()->detach(); - if (s_multipleInstances) - appName.append("-").append(TQCString().setNum(fork_result)); - ::close(fd[1]); - for(;;) - { - int n = ::read(fd[0], &result, 1); - if (n == 1) break; - if (n == 0) - { - kdError() << "KUniqueApplication: Pipe closed unexpectedly." << endl; - ::exit(255); - } - if (errno != EINTR) - { - kdError() << "KUniqueApplication: Error reading from pipe." << endl; - ::exit(255); - } - } - ::close(fd[0]); - - if (result != 0) - ::exit(result); // Error occurred in child. - - dc = new DCOPClient(); - if (!dc->attach()) - { - kdError() << "KUniqueApplication: Parent process can't attach to DCOP." << endl; - delete dc; // Clean up DCOP commmunication - ::exit(255); - } - if (!dc->isApplicationRegistered(appName)) { - kdError() << "KUniqueApplication: Registering failed!" << endl; - } - - TQCString new_asn_id; -#if defined Q_WS_X11 - KStartupInfoId id; - if( kapp != NULL ) // KApplication constructor unsets the env. variable - id.initId( kapp->startupId()); - else - id = KStartupInfo::currentStartupIdEnv(); - if( !id.none()) - new_asn_id = id.id(); -#endif - - TQByteArray data, reply; - TQDataStream ds(data, IO_WriteOnly); - - KCmdLineArgs::saveAppArgs(ds); - ds << new_asn_id; - - dc->setPriorityCall(true); - TQCString replyType; - if (!dc->call(appName, KCmdLineArgs::about->appName(), "newInstance()", data, replyType, reply)) - { - kdError() << "Communication problem with " << KCmdLineArgs::about->appName() << ", it probably crashed." << endl; - delete dc; // Clean up DCOP commmunication - ::exit(255); - } - dc->setPriorityCall(false); - if (replyType != "int") - { - kdError() << "KUniqueApplication: DCOP communication error!" << endl; - delete dc; // Clean up DCOP commmunication - ::exit(255); - } - TQDataStream rs(reply, IO_ReadOnly); - int exitCode; - rs >> exitCode; - delete dc; // Clean up DCOP commmunication - ::exit(exitCode); - break; - } - return false; // make insure++ happy -} - - -KUniqueApplication::KUniqueApplication(bool allowStyles, bool GUIenabled, bool configUnique) - : KApplication( allowStyles, GUIenabled, initHack( configUnique )), - DCOPObject(KCmdLineArgs::about->appName()) -{ - d = new KUniqueApplicationPrivate; - d->processingRequest = false; - d->firstInstance = true; - - if (s_nofork) - // Can't call newInstance directly from the constructor since it's virtual... - TQTimer::singleShot( 0, this, TQT_SLOT(newInstanceNoFork()) ); -} - - -#ifdef Q_WS_X11 -KUniqueApplication::KUniqueApplication(Display *display, Qt::HANDLE visual, - Qt::HANDLE colormap, bool allowStyles, bool configUnique) - : KApplication( display, visual, colormap, allowStyles, initHack( configUnique )), - DCOPObject(KCmdLineArgs::about->appName()) -{ - d = new KUniqueApplicationPrivate; - d->processingRequest = false; - d->firstInstance = true; - - if (s_nofork) - // Can't call newInstance directly from the constructor since it's virtual... - TQTimer::singleShot( 0, this, TQT_SLOT(newInstanceNoFork()) ); -} -#endif - - -KUniqueApplication::~KUniqueApplication() -{ - delete d; -} - -// this gets called before even entering TQApplication::TQApplication() -KInstance* KUniqueApplication::initHack( bool configUnique ) -{ - KInstance* inst = new KInstance( KCmdLineArgs::about ); - if (configUnique) - { - KConfigGroupSaver saver( inst->config(), "KDE" ); - s_multipleInstances = inst->config()->readBoolEntry("MultipleInstances", false); - } - if( !start()) - // Already running - ::exit( 0 ); - return inst; -} - -void KUniqueApplication::newInstanceNoFork() -{ - if (dcopClient()->isSuspended()) - { - // Try again later. - TQTimer::singleShot( 200, this, TQT_SLOT(newInstanceNoFork()) ); - return; - } - - s_handleAutoStarted = false; - newInstance(); - d->firstInstance = false; -#if defined Q_WS_X11 - // KDE4 remove - // A hack to make startup notification stop for apps which override newInstance() - // and reuse an already existing window there, but use KWin::activateWindow() - // instead of KStartupInfo::setNewStartupId(). Therefore KWin::activateWindow() - // for now sets this flag. Automatically ending startup notification always - // would cause problem if the new window would show up with a small delay. - if( s_handleAutoStarted ) - KStartupInfo::handleAutoAppStartedSending(); -#endif - // What to do with the return value ? -} - -bool KUniqueApplication::process(const TQCString &fun, const TQByteArray &data, - TQCString &replyType, TQByteArray &replyData) -{ - if (fun == "newInstance()") - { - delayRequest(fun, data); - return true; - } else - return DCOPObject::process(fun, data, replyType, replyData); -} - -void -KUniqueApplication::delayRequest(const TQCString &fun, const TQByteArray &data) -{ - DCOPRequest *request = new DCOPRequest; - request->fun = fun; - request->data = data; - request->transaction = dcopClient()->beginTransaction(); - d->requestList.append(request); - if (!d->processingRequest) - { - TQTimer::singleShot(0, this, TQT_SLOT(processDelayed())); - } -} - -void -KUniqueApplication::processDelayed() -{ - if (dcopClient()->isSuspended()) - { - // Try again later. - TQTimer::singleShot( 200, this, TQT_SLOT(processDelayed())); - return; - } - d->processingRequest = true; - while( !d->requestList.isEmpty() ) - { - DCOPRequest *request = d->requestList.take(0); - TQByteArray replyData; - TQCString replyType; - if (request->fun == "newInstance()") { - dcopClient()->setPriorityCall(false); - TQDataStream ds(request->data, IO_ReadOnly); - KCmdLineArgs::loadAppArgs(ds); - if( !ds.atEnd()) // backwards compatibility - { - TQCString asn_id; - ds >> asn_id; - setStartupId( asn_id ); - } - s_handleAutoStarted = false; - int exitCode = newInstance(); - d->firstInstance = false; -#if defined Q_WS_X11 - if( s_handleAutoStarted ) - KStartupInfo::handleAutoAppStartedSending(); // KDE4 remove? -#endif - TQDataStream rs(replyData, IO_WriteOnly); - rs << exitCode; - replyType = "int"; - } - dcopClient()->endTransaction( request->transaction, replyType, replyData); - delete request; - } - - d->processingRequest = false; -} - -bool KUniqueApplication::restoringSession() -{ - return d->firstInstance && isRestored(); -} - -int KUniqueApplication::newInstance() -{ - if (!d->firstInstance) - { - - if ( mainWidget() ) - { - mainWidget()->show(); -#if defined Q_WS_X11 - // This is the line that handles window activation if necessary, - // and what's important, it does it properly. If you reimplement newInstance(), - // and don't call the inherited one, use this (but NOT when newInstance() - // is called for the first time, like here). - KStartupInfo::setNewStartupId( mainWidget(), kapp->startupId()); -#endif - } - } - return 0; // do nothing in default implementation -} - -void KUniqueApplication::setHandleAutoStarted() -{ - s_handleAutoStarted = false; -} - -void KUniqueApplication::virtual_hook( int id, void* data ) -{ KApplication::virtual_hook( id, data ); - DCOPObject::virtual_hook( id, data ); } - -#include "kuniqueapplication.moc" |