diff options
Diffstat (limited to 'src/tdedocker.cpp')
-rw-r--r-- | src/tdedocker.cpp | 233 |
1 files changed, 233 insertions, 0 deletions
diff --git a/src/tdedocker.cpp b/src/tdedocker.cpp new file mode 100644 index 0000000..2b404c7 --- /dev/null +++ b/src/tdedocker.cpp @@ -0,0 +1,233 @@ +/* + * 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 <tqsessionmanager.h> +#include <tqdir.h> +#include <tqfile.h> +#include <tqtextcodec.h> +#include <tqtextstream.h> +#include <tqtimer.h> +#include <tqstring.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.") +#define TMPFILE_PREFIX TQDir::homeDirPath() + "/.tdedocker." + +TDEDocker::TDEDocker(int& argc, char** argv) + :TQApplication(argc, argv), mTrayLabelMgr(0) +{ + INIT_TRACE(); + + // 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 TDEDocker + */ + Display *display = TQPaintDevice::x11AppDisplay(); + Atom tdedocker = XInternAtom(display, "_KDOCKER_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::printVersion(void) +{ + tqDebug("TQt: %s", tqVersion()); + tqDebug("TDEDocker: %s", KDOCKER_APP_VERSION); +} + +// Prints the CLI arguments. Does not return +void TDEDocker::printUsage(char optopt) +{ + if (optopt != 'h') tqDebug("%s", i18n("tdedocker: invalid option -- %1").arg(optopt).local8Bit().data()); + + tqDebug("%s", i18n("Usage: TDEDocker [options] command\n").local8Bit().data()); + tqDebug("%s", i18n("Docks any application into the system tray\n").local8Bit().data()); + tqDebug("%s", i18n("command \tCommand to execute\n").local8Bit().data()); + tqDebug("%s", i18n("Options").local8Bit().data()); + tqDebug("%s", i18n("-a \tShow author information").local8Bit().data()); + tqDebug("%s", i18n("-b \tDont warn about non-normal windows (blind mode)").local8Bit().data()); + tqDebug("%s", i18n("-d \tDisable session management").local8Bit().data()); + tqDebug("%s", i18n("-e \tEnable session management").local8Bit().data()); + tqDebug("%s", i18n("-f \tDock window that has the focus(active window)").local8Bit().data()); + tqDebug("%s", i18n("-h \tDisplay this help").local8Bit().data()); + tqDebug("%s", i18n("-i icon\tCustom dock Icon").local8Bit().data()); + tqDebug("%s", i18n("-l \tLaunch on startup").local8Bit().data()); + tqDebug("%s", i18n("-m \tKeep application window mapped (dont hide on dock)").local8Bit().data()); + tqDebug("%s", i18n("-o \tDock when obscured").local8Bit().data()); + tqDebug("%s", i18n("-p secs\tSet ballooning timeout (popup time)").local8Bit().data()); + tqDebug("%s", i18n("-q \tDisable ballooning title changes (quiet)").local8Bit().data()); + tqDebug("%s", i18n("-t \tRemove this application from the task bar").local8Bit().data()); + tqDebug("%s", i18n("-v \tDisplay version").local8Bit().data()); + tqDebug("%s", i18n("-w wid \tWindow id of the application to dock\n").local8Bit().data()); + + tqDebug("%s", i18n("NOTE: Use -d for all startup scripts.\n").local8Bit().data()); + + tqDebug("%s", i18n("Bugs and wishes to gramakri@uiuc.edu").local8Bit().data()); + tqDebug("%s", i18n("Project information at http://tdedocker.sourceforge.net").local8Bit().data()); +} + +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, 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 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 return mTrayLabelMgr->x11EventFilter(event); +} + +/* + * XSMP Support + */ +void TDEDocker::saveState(TQSessionManager &sm) +{ + TQString sf = mTrayLabelMgr->saveSession(); + + TQStringList discard_command; + discard_command << "rm" << sf; + sm.setDiscardCommand(discard_command); + + sm.setRestartHint(TQSessionManager::RestartIfRunning); + TQStringList 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(TQDir::homeDirPath() + "/tdedocker.trace"); + // sm.setRestartCommand(applicationFilePath()); +} + + +#include "tdedocker.moc" |