summaryrefslogtreecommitdiffstats
path: root/tdecore/tdeuniqueapplication.cpp
diff options
context:
space:
mode:
authorMichele Calgaro <[email protected]>2024-11-05 12:24:20 +0900
committerMichele Calgaro <[email protected]>2024-11-19 22:26:14 +0900
commit1711870a073597c2282f32ad39a9b8ad5e1cf6bb (patch)
tree1fb9f1d9ad4ec650960add05c3dd287cd42c7d61 /tdecore/tdeuniqueapplication.cpp
parent87ad1e6c4d56fb52faa0d1af4afe5c33f05e6dca (diff)
downloadtdelibs-1711870a073597c2282f32ad39a9b8ad5e1cf6bb.tar.gz
tdelibs-1711870a073597c2282f32ad39a9b8ad5e1cf6bb.zip
Rename KUniqueApplication to TDEUniqueApplication and remove obsolete kapp.h and kuniqueapp.h headers
Signed-off-by: Michele Calgaro <[email protected]>
Diffstat (limited to 'tdecore/tdeuniqueapplication.cpp')
-rw-r--r--tdecore/tdeuniqueapplication.cpp505
1 files changed, 505 insertions, 0 deletions
diff --git a/tdecore/tdeuniqueapplication.cpp b/tdecore/tdeuniqueapplication.cpp
new file mode 100644
index 000000000..7db9f528e
--- /dev/null
+++ b/tdecore/tdeuniqueapplication.cpp
@@ -0,0 +1,505 @@
+/* This file is part of the KDE libraries
+ Copyright (c) 1999 Preston Brown <[email protected]>
+
+ $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 <tdecmdlineargs.h>
+#include <kstandarddirs.h>
+#include <tdeaboutdata.h>
+
+#if defined TQ_WS_X11
+#include <twin.h>
+#include <tdestartupinfo.h>
+#endif
+
+#include <tdeconfig.h>
+#include "kdebug.h"
+#include "tdeuniqueapplication.h"
+
+#if defined TQ_WS_X11
+#include <netwm.h>
+#include <X11/Xlib.h>
+#define DISPLAY "DISPLAY"
+#else
+# ifdef TQ_WS_QWS
+# define DISPLAY "QWS_DISPLAY"
+# else
+# define DISPLAY "DISPLAY"
+# endif
+#endif
+
+bool TDEUniqueApplication::s_nofork = false;
+bool TDEUniqueApplication::s_multipleInstances = false;
+bool TDEUniqueApplication::s_uniqueTestDone = false;
+bool TDEUniqueApplication::s_handleAutoStarted = false;
+
+static TDECmdLineOptions tdeunique_options[] =
+{
+ { "nofork", "Don't run in the background.", 0 },
+ TDECmdLineLastOption
+};
+
+struct DCOPRequest {
+ TQCString fun;
+ TQByteArray data;
+ DCOPClientTransaction *transaction;
+};
+
+class TDEUniqueApplicationPrivate {
+public:
+ TQPtrList <DCOPRequest> requestList;
+ bool processingRequest;
+ bool firstInstance;
+};
+
+void
+TDEUniqueApplication::addCmdLineOptions()
+{
+ TDECmdLineArgs::addCmdLineOptions(tdeunique_options, 0, "tdeuniqueapp", "tde" );
+}
+
+bool
+TDEUniqueApplication::start()
+{
+ if( s_uniqueTestDone )
+ return true;
+ s_uniqueTestDone = true;
+ addCmdLineOptions(); // Make sure to add cmd line options
+#ifdef TQ_WS_WIN
+ s_nofork = true;
+#else
+ TDECmdLineArgs *args = TDECmdLineArgs::parsedArgs("tdeuniqueapp");
+ s_nofork = !args->isSet("fork");
+ delete args;
+#endif
+
+ TQCString appName = TDECmdLineArgs::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 TQ_WS_WIN //TODO
+ if(dcopClient()->registerAs(appName, false).isEmpty()) {
+ startKdeinit();
+ if(dcopClient()->registerAs(appName, false).isEmpty()) {
+ kdError() << "TDEUniqueApplication: 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() << "TDEUniqueApplication: pipe() failed!" << endl;
+ ::exit(255);
+ }
+ int fork_result = fork();
+ switch(fork_result) {
+ case -1:
+ kdError() << "TDEUniqueApplication: 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() << "TDEUniqueApplication: 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() << "TDEUniqueApplication: 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 TQ_WS_X11
+ // say we're up and running ( probably no new window will appear )
+ TDEStartupInfoId id;
+ if( kapp != NULL ) // TDEApplication constructor unsets the env. variable
+ id.initId( kapp->startupId());
+ else
+ id = TDEStartupInfo::currentStartupIdEnv();
+ if( !id.none())
+ {
+ Display* disp = XOpenDisplay( NULL );
+ if( disp != NULL ) // use extra X connection
+ {
+ TDEStartupInfo::sendFinishX( disp, id );
+ XCloseDisplay( disp );
+ }
+ }
+#else //FIXME(E): implement
+#endif
+#endif
+ return false;
+ }
+ dc->setPriorityCall(true);
+ }
+
+ {
+#ifdef TQ_WS_X11
+ TDEStartupInfoId id;
+ if( kapp != NULL ) // TDEApplication constructor unsets the env. variable
+ id.initId( kapp->startupId());
+ else
+ id = TDEStartupInfo::currentStartupIdEnv();
+ if( !id.none())
+ { // notice about pid change
+ Display* disp = XOpenDisplay( NULL );
+ if( disp != NULL ) // use extra X connection
+ {
+ TDEStartupInfoData data;
+ data.addPid( getpid());
+ TDEStartupInfo::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() << "TDEUniqueApplication: Pipe closed unexpectedly." << endl;
+ ::exit(255);
+ }
+ if (errno != EINTR)
+ {
+ kdError() << "TDEUniqueApplication: 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() << "TDEUniqueApplication: Parent process can't attach to DCOP." << endl;
+ delete dc; // Clean up DCOP commmunication
+ ::exit(255);
+ }
+ if (!dc->isApplicationRegistered(appName)) {
+ kdError() << "TDEUniqueApplication: Registering failed!" << endl;
+ }
+
+ TQCString new_asn_id;
+#if defined TQ_WS_X11
+ TDEStartupInfoId id;
+ if( kapp != NULL ) // TDEApplication constructor unsets the env. variable
+ id.initId( kapp->startupId());
+ else
+ id = TDEStartupInfo::currentStartupIdEnv();
+ if( !id.none())
+ new_asn_id = id.id();
+#endif
+
+ TQByteArray data, reply;
+ TQDataStream ds(data, IO_WriteOnly);
+
+ TDECmdLineArgs::saveAppArgs(ds);
+ ds << new_asn_id;
+
+ dc->setPriorityCall(true);
+ TQCString replyType;
+ if (!dc->call(appName, TDECmdLineArgs::about->appName(), "newInstance()", data, replyType, reply))
+ {
+ kdError() << "Communication problem with " << TDECmdLineArgs::about->appName() << ", it probably crashed." << endl;
+ delete dc; // Clean up DCOP commmunication
+ ::exit(255);
+ }
+ dc->setPriorityCall(false);
+ if (replyType != "int")
+ {
+ kdError() << "TDEUniqueApplication: 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
+}
+
+
+TDEUniqueApplication::TDEUniqueApplication(bool allowStyles, bool GUIenabled, bool configUnique)
+ : TDEApplication( allowStyles, GUIenabled, initHack( configUnique )),
+ DCOPObject(TDECmdLineArgs::about->appName())
+{
+ d = new TDEUniqueApplicationPrivate;
+ 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, TQ_SLOT(newInstanceNoFork()) );
+ }
+ else {
+ // Force to handle DCOP requests (newInstance call)
+ TQTimer::singleShot( 0, this, TQ_SLOT(processDelayed()));
+ }
+}
+
+
+#ifdef TQ_WS_X11
+TDEUniqueApplication::TDEUniqueApplication(Display *display, TQt::HANDLE visual,
+ TQt::HANDLE colormap, bool allowStyles, bool configUnique)
+ : TDEApplication( display, visual, colormap, allowStyles, initHack( configUnique )),
+ DCOPObject(TDECmdLineArgs::about->appName())
+{
+ d = new TDEUniqueApplicationPrivate;
+ 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, TQ_SLOT(newInstanceNoFork()) );
+ }
+ else {
+ // Force to handle DCOP requests (newInstance call)
+ TQTimer::singleShot( 0, this, TQ_SLOT(processDelayed()));
+ }
+}
+#endif
+
+
+TDEUniqueApplication::~TDEUniqueApplication()
+{
+ delete d;
+}
+
+// this gets called before even entering TQApplication::TQApplication()
+TDEInstance* TDEUniqueApplication::initHack( bool configUnique )
+{
+ TDEInstance* inst = new TDEInstance( TDECmdLineArgs::about );
+ if (configUnique)
+ {
+ TDEConfigGroupSaver saver( inst->config(), "KDE" );
+ s_multipleInstances = inst->config()->readBoolEntry("MultipleInstances", false);
+ }
+ if( !start())
+ // Already running
+ ::exit( 0 );
+ return inst;
+}
+
+void TDEUniqueApplication::newInstanceNoFork()
+{
+ if (dcopClient()->isSuspended())
+ {
+ // Try again later.
+ TQTimer::singleShot( 200, this, TQ_SLOT(newInstanceNoFork()) );
+ return;
+ }
+
+ s_handleAutoStarted = false;
+ newInstance();
+ d->firstInstance = false;
+#if defined TQ_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 TDEStartupInfo::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 )
+ TDEStartupInfo::handleAutoAppStartedSending();
+#endif
+ // What to do with the return value ?
+}
+
+bool TDEUniqueApplication::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
+TDEUniqueApplication::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, TQ_SLOT(processDelayed()));
+ }
+}
+
+void
+TDEUniqueApplication::processDelayed()
+{
+ if (dcopClient()->isSuspended())
+ {
+ // Try again later.
+ TQTimer::singleShot( 200, this, TQ_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);
+ TDECmdLineArgs::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 TQ_WS_X11
+ if( s_handleAutoStarted )
+ TDEStartupInfo::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 TDEUniqueApplication::restoringSession()
+{
+ return d->firstInstance && isRestored();
+}
+
+int TDEUniqueApplication::newInstance()
+{
+ if (!d->firstInstance)
+ {
+
+ if ( mainWidget() )
+ {
+ mainWidget()->show();
+#if defined TQ_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).
+ TDEStartupInfo::setNewStartupId( mainWidget(), kapp->startupId());
+#endif
+ }
+ }
+ return 0; // do nothing in default implementation
+}
+
+void TDEUniqueApplication::setHandleAutoStarted()
+{
+ s_handleAutoStarted = false;
+}
+
+void TDEUniqueApplication::virtual_hook( int id, void* data )
+{ TDEApplication::virtual_hook( id, data );
+ DCOPObject::virtual_hook( id, data ); }
+
+#include "tdeuniqueapplication.moc"