|
|
|
/*
|
|
|
|
* Copyright (C) 2004 Girish Ramakrishnan All Rights Reserved.
|
|
|
|
*
|
|
|
|
* This is free software; you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This software 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 General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this software; if not, write to the Free Software
|
|
|
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
|
|
|
|
* USA.
|
|
|
|
*/
|
|
|
|
|
|
|
|
// $Id: tdedocker.cpp,v 1.24 2005/02/04 10:25:46 cs19713 Exp $
|
|
|
|
|
|
|
|
#include <tqdir.h>
|
|
|
|
#include <tqfile.h>
|
|
|
|
#include <tqtextcodec.h>
|
|
|
|
#include <tqtextstream.h>
|
|
|
|
#include <tqstring.h>
|
|
|
|
|
|
|
|
#include <tdecmdlineargs.h>
|
|
|
|
#include <tdeconfig.h>
|
|
|
|
#include <tdelocale.h>
|
|
|
|
|
|
|
|
#include "trace.h"
|
|
|
|
#include "traylabelmgr.h"
|
|
|
|
#include "tdedocker.h"
|
|
|
|
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/stat.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
|
|
|
#define TMPFILE_PREFIX TQString("/tmp/tdedocker.")
|
|
|
|
|
|
|
|
TDEDocker::TDEDocker()
|
|
|
|
: TDEApplication(), mTrayLabelMgr(NULL)
|
|
|
|
{
|
|
|
|
// Set ourselves up to be called from the application loop
|
|
|
|
connect(&mInitTimer, SIGNAL(timeout()), this, SLOT(doInit()));
|
|
|
|
mInitTimer.start(0, true);
|
|
|
|
|
|
|
|
// Required so that the saved config is correctly loaded
|
|
|
|
// (see TrayLabelMgr::doRestoreSession() for usage)
|
|
|
|
if (TDEApplication::kApplication()->isRestored())
|
|
|
|
{
|
|
|
|
TDEApplication::kApplication()->sessionConfig();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void TDEDocker::doInit()
|
|
|
|
{
|
|
|
|
INIT_TRACE();
|
|
|
|
/*
|
|
|
|
* Detect and transfer control to previous instance (if one exists)
|
|
|
|
* _TDEDOCKER_RUNNING is a X Selection. We start out by trying to locate the
|
|
|
|
* selection owner. If someone else owns it, transfer control to that
|
|
|
|
* instance of TDEDocker
|
|
|
|
*/
|
|
|
|
Display *display = TQPaintDevice::x11AppDisplay();
|
|
|
|
Atom tdedocker = XInternAtom(display, "_TDEDOCKER_RUNNING", False);
|
|
|
|
Window prev_instance = XGetSelectionOwner(display, tdedocker);
|
|
|
|
|
|
|
|
if (prev_instance == None)
|
|
|
|
{
|
|
|
|
mSelectionOwner = XCreateSimpleWindow(display, tqt_xrootwin(), 1, 1, 1, 1, 1, 1, 1);
|
|
|
|
XSetSelectionOwner(display, tdedocker, mSelectionOwner, CurrentTime);
|
|
|
|
TRACE("Selection owner set to 0x%x", (unsigned) mSelectionOwner);
|
|
|
|
mTrayLabelMgr = TrayLabelMgr::instance();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
notifyPreviousInstance(prev_instance); // does not return
|
|
|
|
}
|
|
|
|
|
|
|
|
void TDEDocker::notifyPreviousInstance(Window prevInstance)
|
|
|
|
{
|
|
|
|
Display *display = TQPaintDevice::x11AppDisplay();
|
|
|
|
|
|
|
|
TRACE("Notifying previous instance [%x]", (unsigned) prevInstance);
|
|
|
|
|
|
|
|
// Dump all arguments in temporary file
|
|
|
|
TQFile f(TMPFILE_PREFIX + TQString().setNum(getpid()));
|
|
|
|
if (!f.open(IO_WriteOnly)) return;
|
|
|
|
TQTextStream s(&f);
|
|
|
|
|
|
|
|
// Its normal to use TDEDocker in startup scripts. We could be getting restored
|
|
|
|
// from a session at the same time, so in such case pass along the info.
|
|
|
|
if (isRestored())
|
|
|
|
{
|
|
|
|
s << TDECmdLineArgs::appName() << " --restore-internal";
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
TDECmdLineArgs *args = TDECmdLineArgs::parsedArgs();
|
|
|
|
s << TDECmdLineArgs::appName();
|
|
|
|
|
|
|
|
// Options
|
|
|
|
if (args->isSet("b"))
|
|
|
|
{
|
|
|
|
s << " -b";
|
|
|
|
}
|
|
|
|
if (args->isSet("d"))
|
|
|
|
{
|
|
|
|
s << " -d";
|
|
|
|
}
|
|
|
|
if (args->isSet("e"))
|
|
|
|
{
|
|
|
|
s << " -e";
|
|
|
|
}
|
|
|
|
if (args->isSet("f"))
|
|
|
|
{
|
|
|
|
s << " -f";
|
|
|
|
}
|
|
|
|
if (args->isSet("i"))
|
|
|
|
{
|
|
|
|
s << " -i " << args->getOption("i");
|
|
|
|
}
|
|
|
|
if (args->isSet("m"))
|
|
|
|
{
|
|
|
|
s << " -m";
|
|
|
|
}
|
|
|
|
if (args->isSet("o"))
|
|
|
|
{
|
|
|
|
s << " -o";
|
|
|
|
}
|
|
|
|
if (args->isSet("p"))
|
|
|
|
{
|
|
|
|
s << " -p " << args->getOption("p");
|
|
|
|
}
|
|
|
|
if (args->isSet("q"))
|
|
|
|
{
|
|
|
|
s << " -q";
|
|
|
|
}
|
|
|
|
if (args->isSet("t"))
|
|
|
|
{
|
|
|
|
s << " -t";
|
|
|
|
}
|
|
|
|
if (args->isSet("w"))
|
|
|
|
{
|
|
|
|
s << " -w " << args->getOption("w");
|
|
|
|
}
|
|
|
|
|
|
|
|
// Arguments
|
|
|
|
for (int i = 0; i < args->count(); i++)
|
|
|
|
{
|
|
|
|
s << " " << args->arg(i);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
f.close();
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Now tell our previous instance that we came to pass. Actually, it can
|
|
|
|
* figure it out itself using PropertyNotify events but this is a lot nicer
|
|
|
|
*/
|
|
|
|
XClientMessageEvent dock_event;
|
|
|
|
memset(&dock_event, 0, sizeof(XClientMessageEvent));
|
|
|
|
dock_event.display = display;
|
|
|
|
dock_event.window = prevInstance;
|
|
|
|
dock_event.send_event = True;
|
|
|
|
dock_event.type = ClientMessage;
|
|
|
|
dock_event.message_type = 0x220679; // it all started this day
|
|
|
|
dock_event.format = 8;
|
|
|
|
dock_event.data.l[0] = 0xBABE; // love letter ;)
|
|
|
|
dock_event.data.l[1] = getpid();
|
|
|
|
XSendEvent(display, prevInstance, False, 0, (XEvent *) &dock_event);
|
|
|
|
XSync(display, False);
|
|
|
|
|
|
|
|
quit();
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* The X11 Event filter called by TQt. Look out for ClientMessage events from
|
|
|
|
* our new instance
|
|
|
|
*/
|
|
|
|
bool TDEDocker::x11EventFilter(XEvent * event)
|
|
|
|
{
|
|
|
|
if (event->type == ClientMessage)
|
|
|
|
{
|
|
|
|
// look for requests from a new instance of tdedocker
|
|
|
|
XClientMessageEvent *client = (XClientMessageEvent *) event;
|
|
|
|
if (!(client->message_type == 0x220679 && client->data.l[0] == 0xBABE))
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
TRACE("ClientMessage from PID=%ld. SelOwn=0x%x",
|
|
|
|
client->data.l[1], (unsigned) mSelectionOwner);
|
|
|
|
char tmp[50];
|
|
|
|
struct stat buf;
|
|
|
|
sprintf(tmp, TQString(TMPFILE_PREFIX+"%ld").local8Bit(), client->data.l[1]);
|
|
|
|
if (stat(tmp, &buf) || (getuid()!=buf.st_uid))
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* We make sure that the owner of this process and the owner of the file
|
|
|
|
* are the same. This will prevent someone from executing arbitrary
|
|
|
|
* programs by sending client message. Of course, you can send a message
|
|
|
|
* only if you are authenticated to the X session and have permission to
|
|
|
|
* create files in TMPFILE_PREFIX. So this code is there just for the
|
|
|
|
* heck of it.
|
|
|
|
*/
|
|
|
|
TRACE("User %i is trying something fishy...", buf.st_uid);
|
|
|
|
unlink(tmp);
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
TQFile f(tmp);
|
|
|
|
if (!f.open(IO_ReadOnly)) return TRUE;
|
|
|
|
TQTextStream s(&f);
|
|
|
|
TQStringList argv;
|
|
|
|
while (!s.atEnd()) { TQString x; s >> x; argv += x; }
|
|
|
|
f.close();
|
|
|
|
unlink(tmp); // delete the tmp file
|
|
|
|
mTrayLabelMgr->processCommand(argv);
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (mTrayLabelMgr->x11EventFilter(event))
|
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return TDEApplication::x11EventFilter(event);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#include "tdedocker.moc"
|