/* * 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 #include #include #include #include #include #include #include #include "trace.h" #include "traylabelmgr.h" #include "tdedocker.h" #include #include #include #include #include #define TMPFILE_PREFIX TQString("/tmp/tdedocker.") TDEDocker::TDEDocker() : TDEApplication(), mTrayLabelMgr(NULL) { // Set ourselves up to be called from the application loop connect(&mInitTimer, TQ_SIGNAL(timeout()), this, TQ_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"