You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
250 lines
8.5 KiB
250 lines
8.5 KiB
/*
|
|
* 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: kdocker.cpp,v 1.24 2005/02/04 10:25:46 cs19713 Exp $
|
|
|
|
#include <qsessionmanager.h>
|
|
#include <qdir.h>
|
|
#include <qfile.h>
|
|
#include <qtranslator.h>
|
|
#include <qtextcodec.h>
|
|
#include <qtextstream.h>
|
|
#include <qtimer.h>
|
|
#include <qstring.h>
|
|
|
|
#include "trace.h"
|
|
#include "traylabelmgr.h"
|
|
#include "kdocker.h"
|
|
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
#include <unistd.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
|
|
// #define TMPFILE_PREFIX QString("/tmp/kdocker.")
|
|
#define TMPFILE_PREFIX QDir::homeDirPath() + "/.kdocker."
|
|
|
|
KDocker::KDocker(int& argc, char** argv)
|
|
:QApplication(argc, argv), mTrayLabelMgr(0)
|
|
{
|
|
INIT_TRACE();
|
|
|
|
/*
|
|
* Load localisation strings. Most examples I have seen load QTranslator
|
|
* in main(). As a result the translator object lingers around till the end
|
|
* of the program. I tried the same thing here and all i got was translations
|
|
* for usage(). You dont want to know about the sleepless night i spent
|
|
* trying to figure this out (yup, the source helped)
|
|
*/
|
|
QTranslator *translator = new QTranslator(0);
|
|
QString f = QString("kdocker_") + QTextCodec::locale();
|
|
|
|
if (!translator->load(f, QString(TRANSLATIONS_PATH)) &&
|
|
!translator->load(f, applicationDirPath() + "/i18n") &&
|
|
!translator->load(f, QDir::currentDirPath() + "/i18n")) {
|
|
qDebug("Sorry, your locale is not supported. If you are interested "
|
|
"in providing translations for your locale, contact "
|
|
"gramakri@uiuc.edu\n");
|
|
}
|
|
installTranslator(translator);
|
|
|
|
// Attempt doing anything only if the CLI arguments were good
|
|
opterr = 0; // suppress the warning
|
|
int option;
|
|
while ((option = getopt(argc, argv, TrayLabelMgr::options().latin1())) != EOF)
|
|
{
|
|
if (option == '?')
|
|
{
|
|
if (optopt == 'v') printVersion(); else printUsage(optopt);
|
|
::exit(0);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Detect and transfer control to previous instance (if one exists)
|
|
* _KDOCKER_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 KDocker
|
|
*/
|
|
Display *display = QPaintDevice::x11AppDisplay();
|
|
Atom kdocker = XInternAtom(display, "_KDOCKER_RUNNING", False);
|
|
Window prev_instance = XGetSelectionOwner(display, kdocker);
|
|
|
|
if (prev_instance == None)
|
|
{
|
|
mSelectionOwner = XCreateSimpleWindow(display, qt_xrootwin(), 1, 1, 1,
|
|
1, 1, 1, 1);
|
|
XSetSelectionOwner(display, kdocker, mSelectionOwner, CurrentTime);
|
|
TRACE("Selection owner set to 0x%x", (unsigned) mSelectionOwner);
|
|
mTrayLabelMgr = TrayLabelMgr::instance();
|
|
}
|
|
else
|
|
notifyPreviousInstance(prev_instance); // does not return
|
|
}
|
|
|
|
void KDocker::printVersion(void)
|
|
{
|
|
qDebug("Qt: %s", qVersion());
|
|
qDebug("KDocker: %s", KDOCKER_APP_VERSION);
|
|
}
|
|
|
|
// Prints the CLI arguments. Does not return
|
|
void KDocker::printUsage(char optopt)
|
|
{
|
|
if (optopt != 'h') qDebug(tr("kdocker: invalid option -- %1").arg(optopt));
|
|
|
|
qDebug(tr("Usage: KDocker [options] command\n"));
|
|
qDebug(tr("Docks any application into the system tray\n"));
|
|
qDebug(tr("command \tCommand to execute\n"));
|
|
qDebug(tr("Options"));
|
|
qDebug(tr("-a \tShow author information"));
|
|
qDebug(tr("-b \tDont warn about non-normal windows (blind mode)"));
|
|
qDebug(tr("-d \tDisable session management"));
|
|
qDebug(tr("-e \tEnable session management"));
|
|
qDebug(tr("-f \tDock window that has the focus(active window)"));
|
|
qDebug(tr("-h \tDisplay this help"));
|
|
qDebug(tr("-i icon\tCustom dock Icon"));
|
|
qDebug(tr("-l \tLaunch on startup"));
|
|
qDebug(tr("-m \tKeep application window mapped (dont hide on dock)"));
|
|
qDebug(tr("-o \tDock when obscured"));
|
|
qDebug(tr("-p secs\tSet ballooning timeout (popup time)"));
|
|
qDebug(tr("-q \tDisable ballooning title changes (quiet)"));
|
|
qDebug(tr("-t \tRemove this application from the task bar"));
|
|
qDebug(tr("-v \tDisplay version"));
|
|
qDebug(tr("-w wid \tWindow id of the application to dock\n"));
|
|
|
|
qDebug(tr("NOTE: Use -d for all startup scripts.\n"));
|
|
|
|
qDebug(tr("Bugs and wishes to gramakri@uiuc.edu"));
|
|
qDebug(tr("Project information at http://kdocker.sourceforge.net"));
|
|
}
|
|
|
|
void KDocker::notifyPreviousInstance(Window prevInstance)
|
|
{
|
|
Display *display = QPaintDevice::x11AppDisplay();
|
|
|
|
TRACE("Notifying previous instance [%x]", (unsigned) prevInstance);
|
|
|
|
// Dump all arguments in temporary file
|
|
QFile f(TMPFILE_PREFIX + QString().setNum(getpid()));
|
|
if (!f.open(IO_WriteOnly)) return;
|
|
QTextStream s(&f);
|
|
|
|
/*
|
|
* Its normal to use KDocker in startup scripts. We could be getting restored
|
|
* from a session at the same time. So, if we were getting restored and
|
|
* another instance already exists, send across the session id. Remember, qt
|
|
* strips out all the arguments that it understands. So need to do it by hand.
|
|
*/
|
|
if (isSessionRestored())
|
|
s << argv()[0] << " " << "-session" << " " << sessionId();
|
|
else
|
|
for (int i = 0; i < argc(); i++) s << argv()[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);
|
|
|
|
::exit(0);
|
|
}
|
|
|
|
/*
|
|
* The X11 Event filter called by Qt. Look out for ClientMessage events from
|
|
* our new instance
|
|
*/
|
|
bool KDocker::x11EventFilter(XEvent * event)
|
|
{
|
|
if (event->type == ClientMessage)
|
|
{
|
|
// look for requests from a new instance of kdocker
|
|
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, TMPFILE_PREFIX "%ld", 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;
|
|
}
|
|
QFile f(tmp);
|
|
if (!f.open(IO_ReadOnly)) return TRUE;
|
|
QTextStream s(&f);
|
|
QStringList argv;
|
|
while (!s.atEnd()) { QString x; s >> x; argv += x; }
|
|
f.close();
|
|
unlink(tmp); // delete the tmp file
|
|
mTrayLabelMgr->processCommand(argv);
|
|
return TRUE;
|
|
}
|
|
else return mTrayLabelMgr->x11EventFilter(event);
|
|
}
|
|
|
|
/*
|
|
* XSMP Support
|
|
*/
|
|
void KDocker::saveState(QSessionManager &sm)
|
|
{
|
|
QString sf = mTrayLabelMgr->saveSession();
|
|
|
|
QStringList discard_command;
|
|
discard_command << "rm" << sf;
|
|
sm.setDiscardCommand(discard_command);
|
|
|
|
sm.setRestartHint(QSessionManager::RestartIfRunning);
|
|
QStringList restart_command;
|
|
restart_command << this->argv()[0]
|
|
<< "-session" << sm.sessionId();
|
|
sm.setRestartCommand(restart_command);
|
|
|
|
TRACE("SessionFile=%s AppName=%s", sf.latin1(), this->argv()[0]);
|
|
DUMP_TRACE(QDir::homeDirPath() + "/kdocker.trace");
|
|
// sm.setRestartCommand(applicationFilePath());
|
|
}
|
|
|