Conversion to TDE application.

Notable changes:
1) save/restore data are saved in TDE session files.
2) remove -a, -l options. Removed "Launch on startup" option.
3) docked application are restored automatically by the TDE session
manager. After being restored, tdedocker will wait for 5 seconds to let
the various applications be restored, then it will try to grab the
required windows.
4) save/restore of docked applications is now working properly.
5) due to the way TDE manages command line options, at the moment
additional parameters cannot be passed to the application to be
docked. This will be address in a subsequent commit.

Signed-off-by: Michele Calgaro <michele.calgaro@yahoo.it>
pull/2/head
Michele Calgaro 5 years ago
parent d9e1d9fa71
commit ab3e99d8ee
Signed by: MicheleC
GPG Key ID: 2A75B7CA8ADED5CF

@ -35,6 +35,7 @@ tde_add_executable( tdedocker AUTOMOC
trace.cpp trace.cpp
traylabelmgr.cpp traylabelmgr.cpp
util.cpp util.cpp
trace.cpp
LINK LINK
tdecore-shared tdeui-shared DCOP-shared tdecore-shared tdeui-shared DCOP-shared
${XMU_LIBRARIES} ${XPM_LIBRARIES} ${XMU_LIBRARIES} ${XPM_LIBRARIES}

@ -21,22 +21,25 @@
#include <tqsettings.h> #include <tqsettings.h>
#include <tqpopupmenu.h> #include <tqpopupmenu.h>
#include <tqmessagebox.h> #include <tdepopupmenu.h>
#include <tqfiledialog.h> #include <tqfiledialog.h>
#include <tqinputdialog.h> #include <tqinputdialog.h>
#include <tqaction.h>
#include <tqtimer.h> #include <tqtimer.h>
#include <tqsize.h>
#include <stdlib.h> #include <stdlib.h>
#include <khelpmenu.h>
#include <kstdaction.h>
#include <kiconloader.h> #include <kiconloader.h>
#include <kstdguiitem.h>
#include <tdeaction.h>
#include <tdeconfig.h>
#include <tdeglobal.h> #include <tdeglobal.h>
#include <tdelocale.h> #include <tdelocale.h>
#include <tdemessagebox.h>
#include "trace.h" #include "trace.h"
#include "customtraylabel.h"
#include "traylabelmgr.h" #include "traylabelmgr.h"
#include "tdedocker.h" #include "customtraylabel.h"
CustomTrayLabel::CustomTrayLabel(Window w, TQWidget* p, const TQString& t) CustomTrayLabel::CustomTrayLabel(Window w, TQWidget* p, const TQString& t)
: TQTrayLabel(w, p, t), mUndockWhenDead(false) : TQTrayLabel(w, p, t), mUndockWhenDead(false)
@ -51,34 +54,25 @@ CustomTrayLabel::CustomTrayLabel(const TQStringList& argv, pid_t pid,
installMenu(); installMenu();
} }
/* // Installs a popup menu on the tray label
* Installs a popup menu on the tray label
*/
void CustomTrayLabel::installMenu() void CustomTrayLabel::installMenu()
{ {
//TQPixmap tdedocker_png(TDEGlobal::iconLoader()->loadIcon("tdedocker", TDEIcon::NoGroup, TDEIcon::SizeSmall)); TQPixmap tdedocker_png(TDEGlobal::iconLoader()->loadIcon("tdedocker", TDEIcon::NoGroup, TDEIcon::SizeSmall));
TQPixmap *tdedocker_png = new TQPixmap("tdedocker"); setIcon(tdedocker_png);
setIcon(*tdedocker_png);
TrayLabelMgr *tlMgr = TrayLabelMgr::instance(); TrayLabelMgr *tlMgr = TrayLabelMgr::instance();
mOptionsMenu = new TQPopupMenu(this); mOptionsMenu = new TDEPopupMenu(this);
mSessionManagement = new TQAction(i18n("Dock when session restored"), 0, this); mSessionManagement = new TQAction(i18n("Dock when session restored"), 0, this);
mSessionManagement->setToggleAction(true); mSessionManagement->setToggleAction(true);
connect(mSessionManagement, SIGNAL(toggled(bool)), connect(mSessionManagement, SIGNAL(toggled(bool)),
this, SLOT(enableSessionManagement(bool))); this, SLOT(enableSessionManagement(bool)));
mSessionManagement->addTo(mOptionsMenu); mSessionManagement->addTo(mOptionsMenu);
mAutoLaunch = new TQAction(i18n("Launch on startup"), 0, this);
mAutoLaunch->setToggleAction(true);
connect(mAutoLaunch, SIGNAL(activated()),
this, SLOT(slotSetLaunchOnStartup()));
mAutoLaunch->addTo(mOptionsMenu);
mOptionsMenu->insertItem(i18n("Set Icon"), this, SLOT(setCustomIcon())); mOptionsMenu->insertItem(i18n("Set Icon"), this, SLOT(setCustomIcon()));
mBalloonTimeout = new TQAction(i18n("Set balloon timeout"), 0, this); mBalloonTimeout = new TQAction(i18n("Set balloon timeout"), 0, this);
connect(mBalloonTimeout, SIGNAL(activated()), connect(mBalloonTimeout, SIGNAL(activated()),
this, SLOT(slotSetBalloonTimeout())); this, SLOT(slotSetBalloonTimeout()));
mBalloonTimeout->addTo(mOptionsMenu); mBalloonTimeout->addTo(mOptionsMenu);
mDockWhenObscured = new TQAction(i18n("Dock when obscured"), 0, this); mDockWhenObscured = new TQAction(i18n("Dock when obscured"), 0, this);
@ -94,10 +88,10 @@ void CustomTrayLabel::installMenu()
mDockWhenMinimized->addTo(mOptionsMenu); mDockWhenMinimized->addTo(mOptionsMenu);
mDockWhenFocusLost = new TQAction(i18n("Dock when focus lost"), 0, this); mDockWhenFocusLost = new TQAction(i18n("Dock when focus lost"), 0, this);
mDockWhenFocusLost->setToggleAction(true); mDockWhenFocusLost->setToggleAction(true);
connect(mDockWhenFocusLost, SIGNAL(toggled(bool)), connect(mDockWhenFocusLost, SIGNAL(toggled(bool)),
this, SLOT(setDockWhenFocusLost(bool))); this, SLOT(setDockWhenFocusLost(bool)));
mDockWhenFocusLost->addTo(mOptionsMenu); mDockWhenFocusLost->addTo(mOptionsMenu);
mSkipTaskbar = new TQAction(i18n("Skip taskbar"), 0, this); mSkipTaskbar = new TQAction(i18n("Skip taskbar"), 0, this);
mSkipTaskbar->setToggleAction(true); mSkipTaskbar->setToggleAction(true);
@ -106,9 +100,6 @@ void CustomTrayLabel::installMenu()
mSkipTaskbar->addTo(mOptionsMenu); mSkipTaskbar->addTo(mOptionsMenu);
mMainMenu = new TQPopupMenu(this); mMainMenu = new TQPopupMenu(this);
mMainMenu->insertItem(TQIconSet(*tdedocker_png),
i18n("About TDEDocker"), tlMgr, SLOT(about()));
mMainMenu->insertSeparator();
mMainMenu->insertItem(i18n("Options"), mOptionsMenu); mMainMenu->insertItem(i18n("Options"), mOptionsMenu);
mMainMenu->insertItem(i18n("Dock Another"), tlMgr, SLOT(dockAnother())); mMainMenu->insertItem(i18n("Dock Another"), tlMgr, SLOT(dockAnother()));
mMainMenu->insertItem(i18n("Undock All"), tlMgr, SLOT(undockAll())); mMainMenu->insertItem(i18n("Undock All"), tlMgr, SLOT(undockAll()));
@ -117,12 +108,15 @@ void CustomTrayLabel::installMenu()
mShowId = mMainMenu->insertItem(TQString("Show/Hide [untitled]"), mShowId = mMainMenu->insertItem(TQString("Show/Hide [untitled]"),
this, SLOT(toggleShow())); this, SLOT(toggleShow()));
mMainMenu->insertItem(TQString(i18n("Undock")), this, SLOT(undock())); mMainMenu->insertItem(TQString(i18n("Undock")), this, SLOT(undock()));
mMainMenu->insertItem(TQString(i18n("Close")), this, SLOT(close())); mMainMenu->insertSeparator();
mMainMenu->insertItem(SmallIcon("help"),KStdGuiItem::help().text(), (new KHelpMenu(this, TDEGlobal::instance()->aboutData()))->menu(), false);
TDEAction *quitAction = KStdAction::quit(this, SLOT(close()), NULL);
quitAction->plug(mMainMenu);
connect(mMainMenu, SIGNAL(aboutToShow()), this, SLOT(updateMenu())); connect(mMainMenu, SIGNAL(aboutToShow()), this, SLOT(updateMenu()));
// Apply defaults here // Apply defaults here
setLaunchOnStartup(false);
setDockWhenObscured(false); setDockWhenObscured(false);
enableSessionManagement(true); enableSessionManagement(true);
mDockWhenMinimized->setOn(isDockWhenMinimized()); mDockWhenMinimized->setOn(isDockWhenMinimized());
@ -130,28 +124,21 @@ void CustomTrayLabel::installMenu()
setAcceptDrops(true); // and you thought this function only installs the menu setAcceptDrops(true); // and you thought this function only installs the menu
} }
/* // Session Management
* Session Management bool CustomTrayLabel::restoreState(TDEConfig *config)
*/
bool CustomTrayLabel::restoreState(TQSettings& settings)
{ {
mAutoLaunch->setOn(settings.readBoolEntry("/LaunchOnStartup")); setDockWhenObscured(config->readBoolEntry("DockWhenObscured", false));
setDockWhenObscured(settings.readBoolEntry("/DockWhenObscured")); TRACE("DWM=%i DWO=%i", isDockWhenMinimized(), isDockWhenObscured());
TRACE("AutoLaunch=%i DWM=%i DWO=%i", isLaunchOnStartup(), return TQTrayLabel::restoreState(config);
isDockWhenMinimized(), isDockWhenObscured());
return TQTrayLabel::restoreState(settings);
} }
bool CustomTrayLabel::saveState(TQSettings& settings) void CustomTrayLabel::saveState(TDEConfig *config)
{ {
if (!mSessionManagement->isOn()) return false; if (!mSessionManagement->isOn()) return;
TQTrayLabel::saveState(settings); TQTrayLabel::saveState(config);
settings.writeEntry("/LaunchOnStartup", isLaunchOnStartup()); config->writeEntry("DockWhenObscured", isDockWhenObscured());
settings.writeEntry("/DockWhenObscured", isDockWhenObscured()); TRACE("WM=%i DWO=%i", isDockWhenMinimized(), isDockWhenObscured());
TRACE("AutoLaunch=%i DWM=%i DWO=%i", isLaunchOnStartup(),
isDockWhenMinimized(), isDockWhenObscured());
return true;
} }
static bool which(const char *app) static bool which(const char *app)
@ -214,9 +201,8 @@ void CustomTrayLabel::setCustomIcon(void)
icon = TQFileDialog::getOpenFileName(); icon = TQFileDialog::getOpenFileName();
if (icon.isNull()) return; // user cancelled if (icon.isNull()) return; // user cancelled
if (!TQPixmap(icon).isNull()) break; if (!TQPixmap(icon).isNull()) break;
TRACE("Attempting to set icon to %s", icon.latin1()); TRACE("Attempting to set icon to %s", icon.local8Bit());
TQMessageBox::critical(this, i18n("TDEDocker"), KMessageBox::error(this, i18n("%1 is not a valid icon").arg(icon), i18n("TDEDocker"));
i18n("%1 is not a valid icon").arg(icon));
} }
setTrayIcon(icon); setTrayIcon(icon);
@ -228,56 +214,12 @@ void CustomTrayLabel::slotSetBalloonTimeout(void)
bool ok; bool ok;
int timeout = TQInputDialog::getInteger(i18n("TDEDocker"), int timeout = TQInputDialog::getInteger(i18n("TDEDocker"),
i18n("Enter balloon timeout (secs). 0 to disable ballooning"), i18n("Enter balloon timeout (secs). 0 to disable ballooning"),
balloonTimeout()/1000, 0, 60, 1, &ok); balloonTimeout()/1000, 0, 60, 1, &ok);
if (!ok) return; if (!ok) return;
setBalloonTimeout(timeout * 1000); setBalloonTimeout(timeout * 1000);
} }
void CustomTrayLabel::setLaunchOnStartup(bool launch)
{
mAutoLaunch->setOn(launch);
slotSetLaunchOnStartup(); // fake an "activated" signal
}
void CustomTrayLabel::slotSetLaunchOnStartup()
{
TRACE("%i", mAutoLaunch->isOn());
if (!mAutoLaunch->isOn()) return;
TQString app = appName();
TRACE("Validating %s", app.latin1());
while (true)
{
if (which(app.latin1()))
{
TRACE("Autolaunch enabled to %s", app.latin1());
setAppName(app);
mAutoLaunch->setOn(true);
return;
}
// Request user to provide file name himself
if (TQMessageBox::critical(NULL, i18n("TDEDocker"),
i18n("\"%1\" is not a valid executable "
"or was not found in your $PATH").arg(app),
i18n("Select program"), i18n("Cancel")) == 1)
{
mAutoLaunch->setOn(false);
return; // cancelled
}
app = TQFileDialog::getOpenFileName();
if (app.isNull())
{
TRACE("Disabling auto launch");
mAutoLaunch->setOn(false);
return;
}
}
}
// Called when we are just about to display the menu // Called when we are just about to display the menu
void CustomTrayLabel::updateMenu(void) void CustomTrayLabel::updateMenu(void)
{ {
@ -310,13 +252,19 @@ void CustomTrayLabel::obscureEvent(void)
void CustomTrayLabel::focusLostEvent() void CustomTrayLabel::focusLostEvent()
{ {
if (mDockWhenFocusLost->isOn()) withdraw(); if (mDockWhenFocusLost->isOn()) withdraw();
} }
void CustomTrayLabel::mouseReleaseEvent(TQMouseEvent * ev) void CustomTrayLabel::mouseReleaseEvent(TQMouseEvent *ev)
{ {
if (ev->button() == TQt::RightButton) if (ev->button() == TQt::RightButton)
{
mMainMenu->popup(ev->globalPos()); mMainMenu->popup(ev->globalPos());
/* contextMenuAboutToShow(contextMenu());
contextMenu()->popup(e->globalPos());
e->accept();
return;*/
}
else else
toggleShow(); toggleShow();
} }
@ -356,9 +304,8 @@ bool CustomTrayLabel::canDockWindow(Window w)
void CustomTrayLabel::dropEvent(TQDropEvent *) void CustomTrayLabel::dropEvent(TQDropEvent *)
{ {
TQMessageBox::information(NULL, "TDEDocker", KMessageBox::error(NULL, i18n("You cannot drop an item into the tray icon. Drop it on the window\n"
i18n("You cannot drop an item into the tray icon. Drop it on the window\n" "that is brought in front when you hover the item over the tray icon"), i18n("TDEDocker"));
"that is brought in front when you hover the item over the tray icon"));
} }

@ -28,6 +28,7 @@
class TQStringList; class TQStringList;
class TQPopupMenu; class TQPopupMenu;
class TDEPopupMenu;
class TQString; class TQString;
class TQSettings; class TQSettings;
class TQWidget; class TQWidget;
@ -42,10 +43,9 @@ public:
CustomTrayLabel(const TQStringList& argv, pid_t pid, TQWidget* parent = 0); CustomTrayLabel(const TQStringList& argv, pid_t pid, TQWidget* parent = 0);
// Session management // Session management
bool saveState(TQSettings& settings); void saveState(TDEConfig *config);
bool restoreState(TQSettings& settings); bool restoreState(TDEConfig *config);
bool isLaunchOnStartup(void) const { return mAutoLaunch->isOn(); }
bool isDockWhenObscured(void) const { return mDockWhenObscured->isOn(); } bool isDockWhenObscured(void) const { return mDockWhenObscured->isOn(); }
void setAppName(const TQString& name); void setAppName(const TQString& name);
@ -53,10 +53,9 @@ public:
public slots: public slots:
// overridden to update our menu // overridden to update our menu
void setDockWhenMinimized(bool dwm); void setDockWhenMinimized(bool dwm);
void setDockWhenFocusLost(bool dfl) { mDockWhenFocusLost->setOn(dfl); } void setDockWhenFocusLost(bool dfl) { mDockWhenFocusLost->setOn(dfl); }
void setSkipTaskbar(bool skip); void setSkipTaskbar(bool skip);
void setLaunchOnStartup(bool launch);
void setDockWhenObscured(bool dock) { mDockWhenObscured->setOn(dock); } void setDockWhenObscured(bool dock) { mDockWhenObscured->setOn(dock); }
void enableSessionManagement(bool sm) { mSessionManagement->setOn(sm); } void enableSessionManagement(bool sm) { mSessionManagement->setOn(sm); }
@ -75,15 +74,14 @@ private slots:
void setCustomIcon(void); void setCustomIcon(void);
void updateMenu(); void updateMenu();
void slotSetBalloonTimeout(void); void slotSetBalloonTimeout(void);
void slotSetLaunchOnStartup(void);
private: private:
void installMenu(); void installMenu();
bool mUndockWhenDead; bool mUndockWhenDead;
TQPopupMenu *mOptionsMenu, *mMainMenu; TQPopupMenu *mMainMenu;
TQAction *mDockOnRestore, *mAutoLaunch, *mBalloonTimeout, *mSkipTaskbar, TDEPopupMenu *mOptionsMenu;
*mDockWhenMinimized, *mDockWhenObscured, *mSessionManagement, TQAction *mDockOnRestore, *mBalloonTimeout, *mSkipTaskbar, *mDockWhenMinimized,
*mDockWhenFocusLost; *mDockWhenObscured, *mSessionManagement, *mDockWhenFocusLost;
int mShowId; int mShowId;
}; };

@ -24,6 +24,10 @@
#include <unistd.h> #include <unistd.h>
#include <signal.h> #include <signal.h>
#include <tdeaboutdata.h>
#include <tdeapplication.h>
#include <tdecmdlineargs.h>
#include <tdeglobal.h>
#include <tdelocale.h> #include <tdelocale.h>
#include <tqdir.h> #include <tqdir.h>
@ -36,14 +40,33 @@ static void sighandler(int sig)
{ {
if (sig == SIGUSR1) if (sig == SIGUSR1)
{ {
DUMP_TRACE(TQDir::homeDirPath() + "/tdedocker.trace"); DUMP_TRACE((TQDir::homeDirPath() + "/tdedocker.trace").ascii());
return; return;
} }
tqDebug("%s", i18n("Caught signal %1. Cleaning up.").arg(sig).local8Bit().data()); tqDebug("%s", i18n("Caught signal %1. Cleaning up.").arg(sig).local8Bit().data());
((TDEDocker *)tqApp)->trayLabelMgr()->undockAll(); ((TDEDocker *)tqApp)->trayLabelMgr()->undockAll();
::exit(0);
} }
static const TDECmdLineOptions options[] =
{
{ "b", I18N_NOOP("Dont warn about non-normal windows (blind mode)"), 0L },
{ "d", I18N_NOOP("Disable session management"), 0L },
{ "e", I18N_NOOP("Enable session management"), 0L },
{ "f", I18N_NOOP("Dock window that has the focus(active window)"), 0L },
{ "i icon", I18N_NOOP("Custom dock Icon"), 0L },
{ "m", I18N_NOOP("Keep application window mapped (dont hide on dock)"), 0L },
{ "o", I18N_NOOP("Dock when obscured"), 0L },
{ "p secs", I18N_NOOP("Set ballooning timeout (popup time)"), 0L },
{ "q", I18N_NOOP("Disable ballooning title changes (quiet)"), 0L },
{ "t", I18N_NOOP("Remove this application from the task bar"), 0L },
{ "w wid", I18N_NOOP("Window id of the application to dock"), 0L },
{ "+[command <args>]", I18N_NOOP("Application to dock"), 0 },
TDECmdLineLastOption
};
//extern "C" int KDE_EXPORT kdemain(int argc, char* argv[])
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
// setup signal handlers that undock and quit // setup signal handlers that undock and quit
@ -52,6 +75,17 @@ int main(int argc, char *argv[])
signal(SIGINT, sighandler); signal(SIGINT, sighandler);
signal(SIGUSR1, sighandler); signal(SIGUSR1, sighandler);
TDEDocker app(argc, argv); TDEAboutData about("tdedocker", I18N_NOOP("tdedocker"), "1.3",
I18N_NOOP("Docks any application into the system tray\nNOTE: Use -d for all startup scripts."), TDEAboutData::License_GPL);
about.addAuthor("John Schember", I18N_NOOP("Original KDocker maintainer"), "john@nachtimwald.com");
about.addAuthor("Girish Ramakrishnan", I18N_NOOP("Original KDocker developer"), "ramakrishnan.girish@gmail.com");
TDEGlobal::locale()->setMainCatalogue("tdedocker");
TDECmdLineArgs::init(argc, argv, &about);
TDECmdLineArgs::addCmdLineOptions(options);
TDEDocker::addCmdLineOptions();
TDEDocker app;
return app.exec(); return app.exec();
} }

@ -30,7 +30,7 @@
#include <tqfileinfo.h> #include <tqfileinfo.h>
#include <tqapplication.h> #include <tqapplication.h>
#include "trace.h" #include "trace.h"
#include "qtraylabel.h" #include <tdeconfig.h>
#include <kiconloader.h> #include <kiconloader.h>
#include <tdeglobal.h> #include <tdeglobal.h>
@ -43,9 +43,10 @@
#include <stdlib.h> #include <stdlib.h>
#include <sys/types.h> #include <sys/types.h>
#include <sys/wait.h> #include <sys/wait.h>
#include "util.h" #include "util.h"
#include "qtraylabel.h"
void TQTrayLabel::initialize(void) void TQTrayLabel::initialize(void)
{ {
mDocked = false; mDocked = false;
@ -82,7 +83,7 @@ const char *TQTrayLabel::me(void) const
{ {
static char temp[100]; static char temp[100];
snprintf(temp, sizeof(temp), "(%s,PID=%i,WID=0x%x)", snprintf(temp, sizeof(temp), "(%s,PID=%i,WID=0x%x)",
mProgName[0].latin1(), mPid, (unsigned) mDockedWindow); mProgName[0].local8Bit().data(), mPid, (unsigned) mDockedWindow);
return temp; return temp;
} }
@ -128,15 +129,15 @@ void TQTrayLabel::scanClients()
for(unsigned i=0; i<nchildren; i++) for(unsigned i=0; i<nchildren; i++)
{ {
Window w = XmuClientWindow(display, children[i]); Window w = XmuClientWindow(display, children[i]);
TRACE("\t%s checking 0x%x", me(), (unsigned) w); TRACE("\t%s checking(1) 0x%x", me(), (unsigned) w);
if (!isNormalWindow(display, w)) continue; if (!isNormalWindow(display, w)) continue;
if (analyzeWindow(display, w, mPid, ename.latin1())) if (analyzeWindow(display, w, mPid, ename.local8Bit()))
{ {
TRACE("\t%s SOULMATE FOUND", me()); TRACE("\t%s SOULMATE FOUND (1)", me());
setDockedWindow(w); setDockedWindow(w);
break; return;
} }
} }
} }
/* /*
@ -222,7 +223,7 @@ void TQTrayLabel::dock(void)
{ {
TRACE("%s", me()); TRACE("%s", me());
mDocked = true; mDocked = true;
if (mDockedWindow == None) return; // nothing to add if (mDockedWindow == None) return; // nothing to add
if (mSysTray == None) // no system tray yet if (mSysTray == None) // no system tray yet
{ {
@ -243,7 +244,7 @@ void TQTrayLabel::dock(void)
Atom tray_atom = Atom tray_atom =
XInternAtom(display, "_KDE_NET_WM_SYSTEM_TRAY_WINDOW_FOR", False); XInternAtom(display, "_KDE_NET_WM_SYSTEM_TRAY_WINDOW_FOR", False);
XChangeProperty(display, wid, tray_atom, XA_WINDOW, 32, XChangeProperty(display, wid, tray_atom, XA_WINDOW, 32,
PropModeReplace, (unsigned char *) &wid, 1); PropModeReplace, (unsigned char *) &wid, 1);
// 3. All other KDEs // 3. All other KDEs
tray_atom = XInternAtom(display, "KWM_DOCKWINDOW", False); tray_atom = XInternAtom(display, "KWM_DOCKWINDOW", False);
@ -255,7 +256,7 @@ void TQTrayLabel::dock(void)
handleTitleChange(); handleTitleChange();
handleIconChange(); handleIconChange();
if (mProgName.count() == 0) setAppName(mClass); if (mProgName.count() == 0) setAppName(mClass);
/* /*
* For Gnome, a delay is required before we do a show (dont ask me why) * For Gnome, a delay is required before we do a show (dont ask me why)
@ -324,12 +325,12 @@ void TQTrayLabel::map(void)
} }
XMapWindow(display, mDockedWindow); XMapWindow(display, mDockedWindow);
mSizeHint.flags = USPosition; // Obsolete ? mSizeHint.flags = USPosition; // Obsolete ?
XSetWMNormalHints(display, mDockedWindow, &mSizeHint); XSetWMNormalHints(display, mDockedWindow, &mSizeHint);
// make it the active window // make it the active window
long l[5] = { None, CurrentTime, None, 0, 0 }; long l[5] = { None, CurrentTime, None, 0, 0 };
sendMessage(display, tqt_xrootwin(), mDockedWindow, "_NET_ACTIVE_WINDOW", 32, sendMessage(display, tqt_xrootwin(), mDockedWindow, "_NET_ACTIVE_WINDOW", 32,
SubstructureNotifyMask | SubstructureRedirectMask, l, sizeof(l)); SubstructureNotifyMask | SubstructureRedirectMask, l, sizeof(l));
// skipTaskbar modifies _NET_WM_STATE. Make sure we dont override WMs value // skipTaskbar modifies _NET_WM_STATE. Make sure we dont override WMs value
TQTimer::singleShot(230, this, SLOT(skipTaskbar())); TQTimer::singleShot(230, this, SLOT(skipTaskbar()));
// disable docking when minized for some time (since we went to Iconic state) // disable docking when minized for some time (since we went to Iconic state)
@ -357,7 +358,7 @@ void TQTrayLabel::withdraw(void)
* state will remove us from the taskbar. * state will remove us from the taskbar.
* Reference: ICCCM 4.1.4 Changing Window State * Reference: ICCCM 4.1.4 Changing Window State
*/ */
XIconifyWindow(display, mDockedWindow, screen); // good for effects too XIconifyWindow(display, mDockedWindow, screen); // good for effects too
XUnmapWindow(display, mDockedWindow); XUnmapWindow(display, mDockedWindow);
XUnmapEvent ev; XUnmapEvent ev;
memset(&ev, 0, sizeof(ev)); memset(&ev, 0, sizeof(ev));
@ -389,8 +390,8 @@ void TQTrayLabel::skipTaskbar(void)
Atom _NET_WM_STATE = XInternAtom(display, "_NET_WM_STATE", True); Atom _NET_WM_STATE = XInternAtom(display, "_NET_WM_STATE", True);
Atom skip_atom = XInternAtom(display, "_NET_WM_STATE_SKIP_TASKBAR", False); Atom skip_atom = XInternAtom(display, "_NET_WM_STATE_SKIP_TASKBAR", False);
int ret = XGetWindowProperty(display, mDockedWindow, _NET_WM_STATE, 0, int ret = XGetWindowProperty(display, mDockedWindow, _NET_WM_STATE, 0,
20, False, AnyPropertyType, &type, &format, 20, False, AnyPropertyType, &type, &format,
&nitems, &left, (unsigned char **) &data); &nitems, &left, (unsigned char **) &data);
Atom *old_states = (Atom *) data; Atom *old_states = (Atom *) data;
bool append = true, replace = false; bool append = true, replace = false;
@ -406,7 +407,7 @@ void TQTrayLabel::skipTaskbar(void)
{ {
if (num_states < nitems) if (num_states < nitems)
{ {
replace = true; // need to remove skip_atom replace = true; // need to remove skip_atom
for (; num_states < nitems - 1; num_states++) for (; num_states < nitems - 1; num_states++)
old_states[num_states] = old_states[num_states + 1]; old_states[num_states] = old_states[num_states + 1];
} }
@ -442,6 +443,7 @@ void TQTrayLabel::setSkipTaskbar(bool skip)
void TQTrayLabel::close(void) void TQTrayLabel::close(void)
{ {
TRACE("%s", me()); TRACE("%s", me());
undock();
Display *display = TQPaintDevice::x11AppDisplay(); Display *display = TQPaintDevice::x11AppDisplay();
long l[5] = { 0, 0, 0, 0, 0 }; long l[5] = { 0, 0, 0, 0, 0 };
map(); map();
@ -457,7 +459,7 @@ void TQTrayLabel::setTrayIcon(const TQString& icon)
{ {
mCustomIcon = icon; mCustomIcon = icon;
if (TQPixmap(mCustomIcon).isNull()) mCustomIcon = TQString::null; if (TQPixmap(mCustomIcon).isNull()) mCustomIcon = TQString::null;
TRACE("%s mCustomIcon=%s", me(), mCustomIcon.latin1()); TRACE("%s mCustomIcon=%s", me(), mCustomIcon.local8Bit());
updateIcon(); updateIcon();
} }
@ -476,8 +478,7 @@ void TQTrayLabel::setDockedWindow(Window w)
if (w != None) mDockedWindow = canDockWindow(w) ? w : None; if (w != None) mDockedWindow = canDockWindow(w) ? w : None;
else mDockedWindow = None; else mDockedWindow = None;
if (mDockedWindow == None) mRealityMonitor.start(500); if (mDockedWindow == None) mRealityMonitor.start(500); else mRealityMonitor.stop();
else mRealityMonitor.stop();
Display *d = TQPaintDevice::x11AppDisplay(); Display *d = TQPaintDevice::x11AppDisplay();
@ -491,7 +492,7 @@ void TQTrayLabel::setDockedWindow(Window w)
subscribe(d, w, subscribe(d, w,
StructureNotifyMask | PropertyChangeMask | StructureNotifyMask | PropertyChangeMask |
VisibilityChangeMask | FocusChangeMask, VisibilityChangeMask | FocusChangeMask,
true); true);
} }
@ -515,7 +516,7 @@ void TQTrayLabel::setDockedWindow(Window w)
void TQTrayLabel::balloonText() void TQTrayLabel::balloonText()
{ {
TRACE("%s BalloonText=%s ToolTipText=%s", me(), TRACE("%s BalloonText=%s ToolTipText=%s", me(),
mBalloon->text().latin1(), TQToolTip::textFor(this).latin1()); mBalloon->text().local8Bit(), TQToolTip::textFor(this).local8Bit());
if (mBalloon->text() == TQToolTip::textFor(this)) return; if (mBalloon->text() == TQToolTip::textFor(this)) return;
#if 0 // I_GOT_NETWM_BALLOONING_TO_WORK #if 0 // I_GOT_NETWM_BALLOONING_TO_WORK
@ -528,7 +529,7 @@ void TQTrayLabel::balloonText()
SubstructureNotifyMask | SubstructureRedirectMask, SubstructureNotifyMask | SubstructureRedirectMask,
l, sizeof(l)); l, sizeof(l));
int length = mTitle.length(); int length = mTitle.length();
const char *data = mTitle.latin1(); const char *data = mTitle.local8Bit();
while (length > 0) while (length > 0)
{ {
sendMessage(display, mSystemTray, winId(), "_NET_SYSTEM_TRAY_MESSAGE_DATA", 8, sendMessage(display, mSystemTray, winId(), "_NET_SYSTEM_TRAY_MESSAGE_DATA", 8,
@ -564,7 +565,7 @@ void TQTrayLabel::handleTitleChange(void)
XFetchName(display, mDockedWindow, &window_name); XFetchName(display, mDockedWindow, &window_name);
mTitle = window_name; mTitle = window_name;
TRACE("%s has title [%s]", me(), mTitle.latin1()); TRACE("%s has title [%s]", me(), mTitle.local8Bit());
if (window_name) XFree(window_name); if (window_name) XFree(window_name);
XClassHint ch; XClassHint ch;
@ -698,10 +699,10 @@ bool TQTrayLabel::x11EventFilter(XEvent *ev)
mWithdrawn = true; mWithdrawn = true;
unmapEvent(); unmapEvent();
} }
else if (event->type == FocusOut) else if (event->type == FocusOut)
{ {
focusLostEvent(); focusLostEvent();
} }
return true; // Dont process this again return true; // Dont process this again
} }
@ -713,7 +714,7 @@ bool TQTrayLabel::x11EventFilter(XEvent *ev)
Window w = XmuClientWindow(display, ((XMapEvent *) event)->window); Window w = XmuClientWindow(display, ((XMapEvent *) event)->window);
if (!isNormalWindow(display, w)) return FALSE; if (!isNormalWindow(display, w)) return FALSE;
if (!analyzeWindow(display, w, mPid, if (!analyzeWindow(display, w, mPid,
TQFileInfo(mProgName[0]).fileName().latin1())) return FALSE; TQFileInfo(mProgName[0]).fileName().local8Bit())) return FALSE;
// All right. Lets dock this baby // All right. Lets dock this baby
setDockedWindow(w); setDockedWindow(w);
return true; return true;
@ -759,8 +760,8 @@ void TQTrayLabel::propertyChangeEvent(Atom property)
unsigned long nitems, after; unsigned long nitems, after;
unsigned char *data = NULL; unsigned char *data = NULL;
int r = XGetWindowProperty(display, mDockedWindow, WM_STATE, int r = XGetWindowProperty(display, mDockedWindow, WM_STATE,
0, 1, False, AnyPropertyType, &type, 0, 1, False, AnyPropertyType, &type,
&format, &nitems, &after, &data); &format, &nitems, &after, &data);
if ((r == Success) && data && (*(long *) data == IconicState)) if ((r == Success) && data && (*(long *) data == IconicState))
{ {
@ -771,40 +772,37 @@ void TQTrayLabel::propertyChangeEvent(Atom property)
} }
// Session Management // Session Management
bool TQTrayLabel::saveState(TQSettings &settings) void TQTrayLabel::saveState(TDEConfig *config)
{ {
TRACE("%s saving state", me()); TRACE("%s saving state", me());
settings.writeEntry("/Application", mProgName.join(" ")); config->writeEntry("Application", mProgName.join(" "));
settings.writeEntry("/CustomIcon", mCustomIcon); config->writeEntry("BalloonTimeout", mBalloonTimeout);
settings.writeEntry("/BalloonTimeout", mBalloonTimeout); config->writeEntry("CustomIcon", mCustomIcon);
settings.writeEntry("/DockWhenMinimized", mDockWhenMinimized); config->writeEntry("DockWhenMinimized", mDockWhenMinimized);
settings.writeEntry("/SkipTaskbar", mSkippingTaskbar); config->writeEntry("SkipTaskbar", mSkippingTaskbar);
settings.writeEntry("/Withdraw", mWithdrawn); config->writeEntry("Withdraw", mWithdrawn);
return true;
} }
bool TQTrayLabel::restoreState(TQSettings &settings) bool TQTrayLabel::restoreState(TDEConfig *config)
{ {
TRACE("%s restoring state", me()); TRACE("%s restoring state", me());
mCustomIcon = settings.readEntry("/CustomIcon"); setBalloonTimeout(config->readNumEntry("BalloonTimeout", 4000));
setBalloonTimeout(settings.readNumEntry("/BalloonTimeout")); mCustomIcon = config->readEntry("CustomIcon", TQString::null);
setDockWhenMinimized(settings.readBoolEntry("/DockWhenMinimized")); setDockWhenMinimized(config->readBoolEntry("DockWhenMinimized", false));
setSkipTaskbar(settings.readBoolEntry("/SkipTaskbar")); setSkipTaskbar(config->readBoolEntry("SkipTaskbar", false));
mWithdrawn = settings.readBoolEntry("/Withdraw"); mWithdrawn = config->readBoolEntry("Withdraw", false);
dock(); dock();
scanClients(); // Grab window
/* if (mWithdrawn)
* Since we are getting restored, it is likely that the application that we {
* are interested in has already been started (if we didnt launch it). withdraw();
* So we scan the list of windows and grab the first one that satisfies us }
* This implicitly assumes that if mPid!=0 then we launched it. Wait till else
* the application really shows itself up before we do a scan (the reason {
* why we have 2s map();
*/ }
if (!mPid) TQTimer::singleShot(2000, this, SLOT(scanClients())); return true;
return true;
} }
// End kicking butt // End kicking butt

@ -42,6 +42,7 @@
class TQMouseEvent; class TQMouseEvent;
class TQDragEnterEvent; class TQDragEnterEvent;
class TQPoint; class TQPoint;
class TDEConfig;
class TQTrayLabel : public TQLabel class TQTrayLabel : public TQLabel
{ {
@ -69,8 +70,8 @@ public:
bool x11EventFilter(XEvent * event); bool x11EventFilter(XEvent * event);
// Session Management // Session Management
virtual bool saveState(TQSettings& settings); virtual void saveState(TDEConfig *config);
virtual bool restoreState(TQSettings& settings); virtual bool restoreState(TDEConfig *config);
public slots: public slots:
void dock(void); // puts us in the system tray void dock(void); // puts us in the system tray
@ -110,7 +111,7 @@ protected:
virtual void balloonText(void); // balloons text virtual void balloonText(void); // balloons text
virtual void obscureEvent(void) { } virtual void obscureEvent(void) { }
virtual void mapEvent(void) { } virtual void mapEvent(void) { }
virtual void focusLostEvent(void) { } virtual void focusLostEvent(void) { }
virtual void unmapEvent(void) { } virtual void unmapEvent(void) { }
virtual void minimizeEvent(void); virtual void minimizeEvent(void);
virtual void destroyEvent(void); virtual void destroyEvent(void);
@ -136,26 +137,28 @@ private:
void initialize(void); void initialize(void);
void handleTitleChange(void); void handleTitleChange(void);
void handleIconChange(void); void handleIconChange(void);
public:
const char *me(void) const; const char *me(void) const;
private:
// Member variables // Member variables
long mDesktop; // desktop on which the window is being shown long mDesktop; // desktop on which the window is being shown
TQLabel *mBalloon; // tooltip text simulator TQLabel *mBalloon; // tooltip text simulator
TQString mCustomIcon; // CustomIcon of the docked application TQString mCustomIcon; // CustomIcon of the docked application
Window mDockedWindow; // the window which is being docked Window mDockedWindow; // the window which is being docked
int mBalloonTimeout; int mBalloonTimeout;
bool mDocked, mWithdrawn, mSkippingTaskbar; bool mDocked, mWithdrawn, mSkippingTaskbar;
bool mDockWhenMinimized; bool mDockWhenMinimized;
TQString mTitle, mClass; // Title and hint of mDockedWindow TQString mTitle, mClass; // Title and hint of mDockedWindow
TQPixmap mAppIcon; // The current app icon (may not be same as pixmap()) TQPixmap mAppIcon; // The current app icon (may not be same as pixmap())
XSizeHints mSizeHint; // SizeHint of mDockedWindow XSizeHints mSizeHint; // SizeHint of mDockedWindow
TQTimer mRealityMonitor; // Helps us sync up with reality TQTimer mRealityMonitor; // Helps us sync up with reality
TQStringList mProgName; // The program whose window we are docking TQStringList mProgName; // The program whose window we are docking
pid_t mPid; // The PID of program whose window we are docking pid_t mPid; // The PID of program whose window we are docking
Window mSysTray; // System tray window id Window mSysTray; // System tray window id
}; };
#endif // _QTRAYLABEL_H #endif // _QTRAYLABEL_H

@ -19,7 +19,6 @@
// $Id: tdedocker.cpp,v 1.24 2005/02/04 10:25:46 cs19713 Exp $ // $Id: tdedocker.cpp,v 1.24 2005/02/04 10:25:46 cs19713 Exp $
#include <tqsessionmanager.h>
#include <tqdir.h> #include <tqdir.h>
#include <tqfile.h> #include <tqfile.h>
#include <tqtextcodec.h> #include <tqtextcodec.h>
@ -27,6 +26,8 @@
#include <tqtimer.h> #include <tqtimer.h>
#include <tqstring.h> #include <tqstring.h>
#include <tdecmdlineargs.h>
#include <tdeconfig.h>
#include <tdelocale.h> #include <tdelocale.h>
#include "trace.h" #include "trace.h"
@ -39,83 +40,37 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
// #define TMPFILE_PREFIX TQString("/tmp/tdedocker.") #define TMPFILE_PREFIX TQString("/tmp/tdedocker.")
#define TMPFILE_PREFIX TQDir::homeDirPath() + "/.tdedocker."
TDEDocker::TDEDocker(int& argc, char** argv) TDEDocker::TDEDocker()
:TQApplication(argc, argv), mTrayLabelMgr(0) : TDEApplication(), mTrayLabelMgr(NULL), firstSaveState(true)
{ {
INIT_TRACE(); 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) * Detect and transfer control to previous instance (if one exists)
* _KDOCKER_RUNNING is a X Selection. We start out by trying to locate the * _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 * selection owner. If someone else owns it, transfer control to that
* instance of TDEDocker * instance of TDEDocker
*/ */
Display *display = TQPaintDevice::x11AppDisplay(); Display *display = TQPaintDevice::x11AppDisplay();
Atom tdedocker = XInternAtom(display, "_KDOCKER_RUNNING", False); Atom tdedocker = XInternAtom(display, "_TDEDOCKER_RUNNING", False);
Window prev_instance = XGetSelectionOwner(display, tdedocker); Window prev_instance = XGetSelectionOwner(display, tdedocker);
if (prev_instance == None) if (prev_instance == None)
{ {
mSelectionOwner = XCreateSimpleWindow(display, tqt_xrootwin(), 1, 1, 1, if (TDEApplication::kApplication()->isRestored())
1, 1, 1, 1); {
// Required so that the saved config is correctly loaded
// (see TrayLabelMgr::doRestoreSession() for usage)
TDEApplication::kApplication()->sessionConfig();
}
mSelectionOwner = XCreateSimpleWindow(display, tqt_xrootwin(), 1, 1, 1, 1, 1, 1, 1);
XSetSelectionOwner(display, tdedocker, mSelectionOwner, CurrentTime); XSetSelectionOwner(display, tdedocker, mSelectionOwner, CurrentTime);
TRACE("Selection owner set to 0x%x", (unsigned) mSelectionOwner); TRACE("Selection owner set to 0x%x", (unsigned) mSelectionOwner);
mTrayLabelMgr = TrayLabelMgr::instance(); mTrayLabelMgr = TrayLabelMgr::instance();
} }
else else
notifyPreviousInstance(prev_instance); // does not return 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) void TDEDocker::notifyPreviousInstance(Window prevInstance)
@ -129,17 +84,21 @@ void TDEDocker::notifyPreviousInstance(Window prevInstance)
if (!f.open(IO_WriteOnly)) return; if (!f.open(IO_WriteOnly)) return;
TQTextStream s(&f); TQTextStream s(&f);
/* // Its normal to use TDEDocker in startup scripts. We could be getting restored
* 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.
* from a session at the same time. So, if we were getting restored and if (isRestored())
* 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. s << TDECmdLineArgs::appName() << " --restore-internal";
*/ }
if (isSessionRestored())
s << argv()[0] << " " << "-session" << " " << sessionId();
else else
for (int i = 0; i < argc(); i++) s << argv()[i] << " "; {
TDECmdLineArgs *args = TDECmdLineArgs::parsedArgs();
s << TDECmdLineArgs::appName();
for (int i = 0; i < args->count(); i++)
{
s << " " << args->arg(i);
}
}
f.close(); f.close();
/* /*
@ -154,7 +113,7 @@ void TDEDocker::notifyPreviousInstance(Window prevInstance)
dock_event.type = ClientMessage; dock_event.type = ClientMessage;
dock_event.message_type = 0x220679; // it all started this day dock_event.message_type = 0x220679; // it all started this day
dock_event.format = 8; dock_event.format = 8;
dock_event.data.l[0] = 0xBABE; // love letter ;) dock_event.data.l[0] = 0xBABE; // love letter ;)
dock_event.data.l[1] = getpid(); dock_event.data.l[1] = getpid();
XSendEvent(display, prevInstance, False, 0, (XEvent *) &dock_event); XSendEvent(display, prevInstance, False, 0, (XEvent *) &dock_event);
XSync(display, False); XSync(display, False);
@ -179,7 +138,7 @@ bool TDEDocker::x11EventFilter(XEvent * event)
client->data.l[1], (unsigned) mSelectionOwner); client->data.l[1], (unsigned) mSelectionOwner);
char tmp[50]; char tmp[50];
struct stat buf; struct stat buf;
sprintf(tmp, TQString(TMPFILE_PREFIX "%ld").local8Bit(), client->data.l[1]); sprintf(tmp, TQString(TMPFILE_PREFIX+"%ld").local8Bit(), client->data.l[1]);
if (stat(tmp, &buf) || (getuid()!=buf.st_uid)) if (stat(tmp, &buf) || (getuid()!=buf.st_uid))
{ {
/* /*
@ -204,30 +163,14 @@ bool TDEDocker::x11EventFilter(XEvent * event)
mTrayLabelMgr->processCommand(argv); mTrayLabelMgr->processCommand(argv);
return TRUE; return TRUE;
} }
else return mTrayLabelMgr->x11EventFilter(event); else
} {
if (mTrayLabelMgr->x11EventFilter(event))
/* {
* XSMP Support return true;
*/ }
void TDEDocker::saveState(TQSessionManager &sm) return TDEApplication::x11EventFilter(event);
{ }
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" #include "tdedocker.moc"

@ -19,41 +19,34 @@
// $Id: tdedocker.h,v 1.11 2005/02/09 03:32:26 cs19713 Exp $ // $Id: tdedocker.h,v 1.11 2005/02/09 03:32:26 cs19713 Exp $
#ifndef _KDOCKER_H #ifndef _TDEDOCKER_H
#define _KDOCKER_H #define _TDEDOCKER_H
#include <tqapplication.h> #include <tdeapplication.h>
#include <X11/Xlib.h> #include <X11/Xlib.h>
#define KDOCKER_APP_VERSION "1.3"
class TrayLabelMgr; class TrayLabelMgr;
class TDEDocker : public TQApplication class TDEDocker : public TDEApplication
{ {
Q_OBJECT Q_OBJECT
public: public:
TDEDocker(int& argc, char** argv); TDEDocker();
TrayLabelMgr *trayLabelMgr(void) { return mTrayLabelMgr; } TrayLabelMgr *trayLabelMgr(void) { return mTrayLabelMgr; }
void dumpState(const TQString &file); void dumpState(const TQString &file);
void printUsage(char optopt = 'h');
protected: protected:
bool x11EventFilter(XEvent * event); bool x11EventFilter(XEvent * event);
void saveState(TQSessionManager &sm);
private: private:
TQString saveSession();
bool restoreSession();
void notifyPreviousInstance(Window prevInstance); void notifyPreviousInstance(Window prevInstance);
void printVersion();
Window mSelectionOwner; Window mSelectionOwner;
TrayLabelMgr *mTrayLabelMgr; TrayLabelMgr *mTrayLabelMgr;
bool firstSaveState;
}; };
#endif // _KDOCKER_H #endif // _TDEDOCKER_H

@ -11,7 +11,7 @@ void TRACER(TQtMsgType, const char *msg)
tracer->append(&msg[*msg == '~' ? 1 : 0]); tracer->append(&msg[*msg == '~' ? 1 : 0]);
if (msg[0] != '~') if (msg[0] != '~')
{ {
fprintf(stderr, msg); fprintf(stderr, "%s", msg);
fprintf(stderr, "\r\n"); fprintf(stderr, "\r\n");
} }
} }

@ -19,17 +19,14 @@
// $Id: traylabelmgr.cpp,v 1.10 2005/02/09 03:38:43 cs19713 Exp $ // $Id: traylabelmgr.cpp,v 1.10 2005/02/09 03:38:43 cs19713 Exp $
#include <tqdir.h>
#include <tqapplication.h>
#include <tqmessagebox.h>
#include <tqtimer.h>
#include <tqfile.h> #include <tqfile.h>
#include <tqaction.h>
#include <tqpopupmenu.h>
#include <tqtextstream.h> #include <tqtextstream.h>
#include <tqfiledialog.h>
#include <tdeapplication.h>
#include <tdecmdlineargs.h>
#include <tdeconfig.h>
#include <tdelocale.h> #include <tdelocale.h>
#include <tdemessagebox.h>
#include "trace.h" #include "trace.h"
#include "traylabelmgr.h" #include "traylabelmgr.h"
@ -40,9 +37,9 @@
#include <stdlib.h> #include <stdlib.h>
TrayLabelMgr* TrayLabelMgr::gTrayLabelMgr = NULL; TrayLabelMgr* TrayLabelMgr::gTrayLabelMgr = NULL;
const char *TrayLabelMgr::mOptionString = "+abdefi:lmop:qtw:"; const char *TrayLabelMgr::mOptionString = "+bdefi:lmop:qtw:";
TrayLabelMgr* TrayLabelMgr::instance(void) TrayLabelMgr* TrayLabelMgr::instance()
{ {
if (gTrayLabelMgr) return gTrayLabelMgr; if (gTrayLabelMgr) return gTrayLabelMgr;
TRACE("Creating new instance"); TRACE("Creating new instance");
@ -51,6 +48,8 @@ TrayLabelMgr* TrayLabelMgr::instance(void)
TrayLabelMgr::TrayLabelMgr() : mReady(false), mHiddenLabelsCount(0) TrayLabelMgr::TrayLabelMgr() : mReady(false), mHiddenLabelsCount(0)
{ {
connect(&restoreSessionTimer, SIGNAL(timeout()), this, SLOT(doRestoreSession()));
// Set ourselves up to be called from the application loop // Set ourselves up to be called from the application loop
TQTimer::singleShot(0, this, SLOT(startup())); TQTimer::singleShot(0, this, SLOT(startup()));
} }
@ -60,15 +59,6 @@ TrayLabelMgr::~TrayLabelMgr()
undockAll(); undockAll();
} }
void TrayLabelMgr::about(void)
{
if (TQMessageBox::information(NULL, i18n("About TDEDocker"),
i18n("Bugs/wishes to Girish Ramakrishnan (gramakri@uiuc.edu)\n"
"English translation by Girish (gramakri@uiuc.edu)\n\n"
"http://tdedocker.sourceforge.net for updates"),
TQString::null, SHOW_TRACE_TEXT) == 1) SHOW_TRACE();
}
void TrayLabelMgr::startup(void) void TrayLabelMgr::startup(void)
{ {
const int WAIT_TIME = 10; const int WAIT_TIME = 10;
@ -78,7 +68,7 @@ void TrayLabelMgr::startup(void)
* stdout is a tty) OR if we are getting restored, wait for WAIT_TIME until * stdout is a tty) OR if we are getting restored, wait for WAIT_TIME until
* the system tray shows up (before informing the user) * the system tray shows up (before informing the user)
*/ */
static bool do_wait = !isatty(fileno(stdout)) || tqApp->isSessionRestored(); static bool do_wait = !isatty(fileno(stdout)) || TDEApplication::kApplication()->isRestored();
SysTrayState state = sysTrayStatus(TQPaintDevice::x11AppDisplay()); SysTrayState state = sysTrayStatus(TQPaintDevice::x11AppDisplay());
@ -91,10 +81,9 @@ void TrayLabelMgr::startup(void)
return; return;
} }
if (TQMessageBox::warning(NULL, i18n("TDEDocker"), if (KMessageBox::warningContinueCancel(NULL,
i18n(state == SysTrayAbsent ? "No system tray found" state == SysTrayAbsent ? i18n("No system tray found") : i18n("System tray appears to be hidden"),
: "System tray appears to be hidden"), i18n("TDEDocker")) == KMessageBox::Cancel)
TQMessageBox::Abort, TQMessageBox::Ignore) == TQMessageBox::Abort)
{ {
tqApp->quit(); tqApp->quit();
return; return;
@ -104,10 +93,17 @@ void TrayLabelMgr::startup(void)
// Things are fine or user with OK with the state of system tray // Things are fine or user with OK with the state of system tray
mReady = true; mReady = true;
bool ok = false; bool ok = false;
if (tqApp->isSessionRestored()) ok = restoreSession(tqApp->sessionId()); if (TDEApplication::kApplication()->isRestored())
else ok = processCommand(tqApp->argc(), tqApp->argv()); {
// Process the request Q from previous instances restoreSession();
ok = true;
}
else
{
ok = processCommand(TDECmdLineArgs::parsedArgs());
}
// Process the request Q from previous instances
TRACE("Request queue has %i requests", mRequestQ.count()); TRACE("Request queue has %i requests", mRequestQ.count());
for(unsigned i=0; i < mRequestQ.count(); i++) for(unsigned i=0; i < mRequestQ.count(); i++)
ok |= processCommand(mRequestQ[i]); ok |= processCommand(mRequestQ[i]);
@ -117,8 +113,7 @@ void TrayLabelMgr::startup(void)
// Initialize a TQTrayLabel after its creation // Initialize a TQTrayLabel after its creation
void TrayLabelMgr::manageTrayLabel(TQTrayLabel *t) void TrayLabelMgr::manageTrayLabel(TQTrayLabel *t)
{ {
connect(t, SIGNAL(destroyed(TQObject *)), connect(t, SIGNAL(destroyed(TQObject *)), this, SLOT(trayLabelDestroyed(TQObject *)));
this, SLOT(trayLabelDestroyed(TQObject *)));
connect(t, SIGNAL(undocked(TQTrayLabel *)), t, SLOT(deleteLater())); connect(t, SIGNAL(undocked(TQTrayLabel *)), t, SLOT(deleteLater()));
// All TQTrayLabels will emit this signal. We just need one of them // All TQTrayLabels will emit this signal. We just need one of them
@ -152,7 +147,7 @@ void TrayLabelMgr::undockAll()
} }
// Process the command line // Process the command line
bool TrayLabelMgr::processCommand(const TQStringList& args) bool TrayLabelMgr::processCommand(const TQStringList &args)
{ {
if (!mReady) if (!mReady)
{ {
@ -161,19 +156,83 @@ bool TrayLabelMgr::processCommand(const TQStringList& args)
return true; return true;
} }
const int MAX_ARGS = 20; const int MAX_ARGS = 50;
const char *argv[MAX_ARGS]; const char *argv[MAX_ARGS];
int argc = args.count(); int argc = args.count();
if (argc >= MAX_ARGS) argc = MAX_ARGS - 1; if (argc >= MAX_ARGS) argc = MAX_ARGS - 1;
for(int i =0 ; i<argc; i++) for(int i = 0; i < argc; i++)
argv[i] = args[i].latin1(); {
argv[i] = args[i].local8Bit();
}
argv[argc] = NULL; // null terminate the array argv[argc] = NULL; // null terminate the array
return processCommand(argc, const_cast<char **>(argv)); return processCommand(argc, const_cast<char **>(argv));
} }
// Process the command line
bool TrayLabelMgr::processCommand(TDECmdLineArgs *args)
{
TQStringList argl;
argl.append(TDECmdLineArgs::appName());
if (args->isSet("b"))
{
argl.append("-b");
}
if (args->isSet("d"))
{
argl.append("-d");
}
if (args->isSet("e"))
{
argl.append("-e");
}
if (args->isSet("f"))
{
argl.append("-f");
}
if (args->isSet("i"))
{
argl.append("-i");
argl.append(args->getOption("i"));
}
if (args->isSet("m"))
{
argl.append("-m");
}
if (args->isSet("o"))
{
argl.append("-o");
}
if (args->isSet("p"))
{
argl.append("-p");
argl.append(args->getOption("p"));
}
if (args->isSet("q"))
{
argl.append("-q");
}
if (args->isSet("t"))
{
argl.append("-t");
}
if (args->isSet("w"))
{
argl.append("-w");
argl.append(args->getOption("w"));
}
for (int i = 0; i < args->count(); ++i)
{
argl.append(args->arg(i));
}
return processCommand(argl);
}
// Process the command line // Process the command line
bool TrayLabelMgr::processCommand(int argc, char** argv) bool TrayLabelMgr::processCommand(int argc, char** argv)
{ {
@ -182,11 +241,12 @@ bool TrayLabelMgr::processCommand(int argc, char** argv)
if (argc < 1) return false; if (argc < 1) return false;
// Restore session (See the comments in TDEDocker::notifyPreviousInstance() // Restore session (see the comments in TDEDocker::notifyPreviousInstance() )
if (qstrcmp(argv[1], "-session") == 0) if (qstrcmp(argv[1], "--restore-internal") == 0)
{ {
TRACE("Restoring session %s (new instance request)", argv[2]); TRACE("Restoring session (new instance request)");
return restoreSession(TQString(argv[2])); restoreSession();
return true;
} }
int option; int option;
@ -194,8 +254,7 @@ bool TrayLabelMgr::processCommand(int argc, char** argv)
const char *icon = NULL; const char *icon = NULL;
int balloon_timeout = 4000; int balloon_timeout = 4000;
bool withdraw = true, skip_taskbar = false, bool withdraw = true, skip_taskbar = false,
auto_launch = false, dock_obscure = false, check_normality = true, dock_obscure = false, check_normality = true, enable_sm = true;
enable_sm = true;
optind = 0; // initialise the getopt static optind = 0; // initialise the getopt static
@ -205,9 +264,6 @@ bool TrayLabelMgr::processCommand(int argc, char** argv)
{ {
case '?': case '?':
return false; return false;
case 'a':
tqDebug("%s", i18n("Girish Ramakrishnan (gramakri@uiuc.edu)").local8Bit().data());
return false;
case 'b': case 'b':
check_normality = false; check_normality = false;
break; break;
@ -224,9 +280,6 @@ bool TrayLabelMgr::processCommand(int argc, char** argv)
case 'i': case 'i':
icon = optarg; icon = optarg;
break; break;
case 'l':
auto_launch = true;
break;
case 'm': case 'm':
withdraw = false; withdraw = false;
break; break;
@ -259,7 +312,7 @@ bool TrayLabelMgr::processCommand(int argc, char** argv)
// Launch an application if present in command line. else request from user // Launch an application if present in command line. else request from user
CustomTrayLabel *t = (CustomTrayLabel *) // this should be dynamic_cast CustomTrayLabel *t = (CustomTrayLabel *) // this should be dynamic_cast
((optind < argc) ? dockApplication(&argv[optind]) ((optind < argc) ? dockApplication(&argv[optind])
: selectAndDock(w, check_normality)); : selectAndDock(w, check_normality));
if (t == NULL) return false; if (t == NULL) return false;
// apply settings and add to tray // apply settings and add to tray
manageTrayLabel(t); manageTrayLabel(t);
@ -270,7 +323,6 @@ bool TrayLabelMgr::processCommand(int argc, char** argv)
if (withdraw) t->withdraw(); else t->map(); if (withdraw) t->withdraw(); else t->map();
t->enableSessionManagement(enable_sm); t->enableSessionManagement(enable_sm);
t->dock(); t->dock();
t->setLaunchOnStartup(auto_launch);
return true; return true;
} }
@ -288,7 +340,10 @@ TQTrayLabel *TrayLabelMgr::selectAndDock(Window w, bool checkNormality)
if ((w = selectWindow(TQPaintDevice::x11AppDisplay(), &err)) == None) if ((w = selectWindow(TQPaintDevice::x11AppDisplay(), &err)) == None)
{ {
if (err) TQMessageBox::critical(NULL, i18n("TDEDocker"), i18n(err)); if (err)
{
KMessageBox::error(NULL, err, i18n("TDEDocker"));
}
return NULL; return NULL;
} }
} }
@ -299,20 +354,20 @@ TQTrayLabel *TrayLabelMgr::selectAndDock(Window w, bool checkNormality)
* Abort should be the only option here really. "Ignore" is provided here * Abort should be the only option here really. "Ignore" is provided here
* for the curious user who wants to screw himself very badly * for the curious user who wants to screw himself very badly
*/ */
if (TQMessageBox::warning(NULL, i18n("TDEDocker"), if (KMessageBox::warningContinueCancel(NULL,
i18n("The window you are attempting to dock does not seem to be a" i18n("The window you are attempting to dock does not seem to be a normal window."),
" normal window."), TQMessageBox::Abort, i18n("TDEDocker")) == KMessageBox::Cancel)
TQMessageBox::Ignore) == TQMessageBox::Abort) {
return NULL; return NULL;
}
} }
if (!isWindowDocked(w)) return new CustomTrayLabel(w); if (!isWindowDocked(w)) return new CustomTrayLabel(w);
TRACE("0x%x is not docked", (unsigned) w); TRACE("0x%x is not docked", (unsigned) w);
TQMessageBox::message(i18n("TDEDocker"), KMessageBox::error(NULL, i18n("This window is already docked.\n"
i18n("This window is already docked.\n" "Click on system tray icon to toggle docking."), i18n("TDEDocker"));
"Click on system tray icon to toggle docking."));
return NULL; return NULL;
} }
@ -349,7 +404,6 @@ TQTrayLabel *TrayLabelMgr::dockApplication(char *argv[])
close(filedes[1]); close(filedes[1]);
read(filedes[0], buf, sizeof(buf)); read(filedes[0], buf, sizeof(buf));
close(filedes[0]); close(filedes[0]);
if (execvp(argv[0], argv) == -1) if (execvp(argv[0], argv) == -1)
{ {
tqDebug("%s", i18n("Failed to exec [%1]: %2").arg(argv[0]).arg(strerror(errno)).local8Bit().data()); tqDebug("%s", i18n("Failed to exec [%1]: %2").arg(argv[0]).arg(strerror(errno)).local8Bit().data());
@ -360,8 +414,7 @@ TQTrayLabel *TrayLabelMgr::dockApplication(char *argv[])
if (pid == -1) if (pid == -1)
{ {
TQMessageBox::critical(NULL, "TDEDocker", KMessageBox::error(NULL, i18n("Failed to fork: %1").arg(strerror(errno)), i18n("Ignore"));
i18n("Failed to fork: %1").arg(strerror(errno)));
return NULL; return NULL;
} }
@ -427,72 +480,60 @@ void TrayLabelMgr::notifySysTrayAbsence()
if (state == SysTrayPresent) if (state == SysTrayPresent)
return; // So sweet of the systray to come back so soon return; // So sweet of the systray to come back so soon
if (TQMessageBox::warning(NULL, i18n("TDEDocker"), KMessageBox::error(NULL, i18n("The System tray was hidden or removed. All applications "
i18n("The System tray was hidden or removed"), "will be undocked."), i18n("TDEDocker"));
i18n("Undock All"), i18n("Ignore")) == 0) undockAll();
undockAll();
} }
/* void TrayLabelMgr::restoreSession()
* Session Management. Always return "true". Atleast, for now
*/
bool TrayLabelMgr::restoreSession(const TQString& sessionId)
{ {
TQString session_file = "tdedocker_" + sessionId; // After restoring a session, the TDE session manager will relaunch the applications
// that were previously docked before terminating the previous session. To avoid
// launching the same apps twice, wait for a while before restoring the tdedocker
// session, so that we give tdedocker a chance to simply docks the applications
// already launched by TDE session manager.
restoreSessionTimer.start(5000, true);
}
TQSettings settings; void TrayLabelMgr::doRestoreSession()
settings.beginGroup(TQString("/" + session_file)); {
TRACE("Restoring session");
for(int i = 1;; i++) TDEConfig *config = TDEApplication::kApplication()->sessionConfig();
for (int i = 1; ; ++i)
{ {
settings.beginGroup(TQString("/Instance") + TQString("").setNum(i)); if (!config->hasGroup("Instance" + TQString::number(i)))
TQString pname = settings.readEntry("/Application");
TRACE("Restoring Application[%s]", pname.latin1());
if (pname.isEmpty()) break;
if (settings.readBoolEntry("/LaunchOnStartup"))
{ {
TQStringList args("tdedocker"); return;
args += TQStringList::split(" ", pname);
TRACE("Triggering AutoLaunch");
if (!processCommand(args)) continue;
} }
else config->setGroup("Instance" + TQString::number(i));
TQString pname = config->readEntry("Application", TQString::null);
if (!pname.isEmpty())
{
TRACE("Restoring Application[%s]", pname.ascii());
manageTrayLabel(new CustomTrayLabel(TQStringList::split(" ", pname), 0)); manageTrayLabel(new CustomTrayLabel(TQStringList::split(" ", pname), 0));
mTrayLabels.getFirst()->restoreState(config);
TQTrayLabel *tl = mTrayLabels.getFirst(); // the one that was created above }
tl->restoreState(settings);
settings.endGroup();
} }
return true;
} }
TQString TrayLabelMgr::saveSession(void) bool TrayLabelMgr::saveState(TQSessionManager &sm)
{ {
TQString session_file = "tdedocker_" + tqApp->sessionId();
TQSettings settings;
settings.beginGroup(TQString("/" + session_file));
TRACE("Saving session"); TRACE("Saving session");
TQPtrListIterator <TQTrayLabel> it(mTrayLabels);
TQTrayLabel *t;
int i = 1; int i = 1;
while ((t = it.current()) != 0) TQTrayLabel *t;
TDEConfig *config = TDEApplication::kApplication()->sessionConfig();
TQPtrListIterator <TQTrayLabel> it(mTrayLabels);
for (it.toFirst(); it.current(); ++it)
{ {
++it; t = it.current();
TRACE("Saving instance %i", i); TRACE("Saving instance %i", i);
settings.beginGroup(TQString("/Instance") + TQString("").setNum(i)); config->setGroup("Instance" + TQString::number(i));
bool ok = t->saveState(settings); t->saveState(config);
settings.endGroup(); ++i;
if (ok) ++i; else TRACE("Saving of instance %i was skipped", i);
} }
return true;
// Aaaaaaaaaaaaaa.........
settings.removeEntry(TQString("/Instance") + TQString("").setNum(i));
return TQDir::homeDirPath() + "/.qt/" + session_file + "rc";
} }
/* /*

@ -25,12 +25,16 @@
#include <tqptrlist.h> #include <tqptrlist.h>
#include <tqvaluelist.h> #include <tqvaluelist.h>
#include <tqstringlist.h> #include <tqstringlist.h>
#include <tqtimer.h>
#include <tdeapplication.h>
#include "customtraylabel.h" #include "customtraylabel.h"
class CustomTrayLabel; class CustomTrayLabel;
class TDECmdLineArgs;
class TQSessionManager;
class TrayLabelMgr : public TQObject class TrayLabelMgr : public TQObject, public KSessionManaged
{ {
Q_OBJECT Q_OBJECT
@ -40,21 +44,21 @@ public:
~TrayLabelMgr(); ~TrayLabelMgr();
TQString saveSession(); bool saveState(TQSessionManager &sm);
bool x11EventFilter(XEvent *); bool x11EventFilter(XEvent *);
bool processCommand(const TQStringList& argv); bool processCommand(const TQStringList &argv);
int hiddenLabelsCount(void) const; int hiddenLabelsCount(void) const;
int dockedLabelsCount(void) const; int dockedLabelsCount(void) const;
bool isWindowDocked(Window w); bool isWindowDocked(Window w);
public slots: public slots:
void about();
void undockAll(); void undockAll();
void dockAnother(); void dockAnother();
private slots: private slots:
void startup(); void startup();
void doRestoreSession();
void trayLabelDestroyed(TQObject *); void trayLabelDestroyed(TQObject *);
void sysTrayDestroyed(void); void sysTrayDestroyed(void);
void notifySysTrayAbsence(); void notifySysTrayAbsence();
@ -62,14 +66,16 @@ private slots:
private: private:
TrayLabelMgr(); TrayLabelMgr();
bool processCommand(int argc, char** argv); bool processCommand(int argc, char** argv);
bool processCommand(TDECmdLineArgs *args);
void manageTrayLabel(TQTrayLabel *l); void manageTrayLabel(TQTrayLabel *l);
bool restoreSession(const TQString& sessionId); void restoreSession();
TQTrayLabel *dockApplication(char *argv[]); TQTrayLabel *dockApplication(char *argv[]);
TQTrayLabel *selectAndDock(Window w = None, bool checkNormality = true); TQTrayLabel *selectAndDock(Window w = None, bool checkNormality = true);
TQPtrList<TQTrayLabel> mTrayLabels; TQPtrList<TQTrayLabel> mTrayLabels;
TQValueList<TQStringList> mRequestQ; TQValueList<TQStringList> mRequestQ;
TQTimer restoreSessionTimer;
bool mReady; bool mReady;
int mHiddenLabelsCount; int mHiddenLabelsCount;

@ -126,9 +126,9 @@ pid_t pid(Display *display, Window w)
pid_t pid_return = -1; pid_t pid_return = -1;
if (XGetWindowProperty(display, w, if (XGetWindowProperty(display, w,
XInternAtom(display, "_NET_WM_PID", False), 0, XInternAtom(display, "_NET_WM_PID", False), 0,
1, False, XA_CARDINAL, &actual_type, 1, False, XA_CARDINAL, &actual_type,
&actual_format, &nitems, &leftover, &pid) == Success) &actual_format, &nitems, &leftover, &pid) == Success)
{ {
if (pid) pid_return = *(pid_t *) pid; if (pid) pid_return = *(pid_t *) pid;
XFree(pid); XFree(pid);
@ -163,9 +163,12 @@ bool analyzeWindow(Display *display, Window w, pid_t epid, const TQString &ename
XClassHint ch; XClassHint ch;
pid_t apid = pid(display, w); pid_t apid = pid(display, w);
TRACE("WID=0x%x PID=%i ExpectedName=%s", (unsigned) w, (unsigned) epid, TRACE("WID=0x%x EPID=%i APID=%i ExpectedName=%s", (unsigned) w, (unsigned) epid, (unsigned) apid,
ename.latin1()); ename.local8Bit());
if (epid == apid) return true; if (epid == apid) return true;
// Only analyze window name if no process pid was provided, to avoid associating
// the wrong window to a given process
if (epid) return false;
// no plans to analyze windows without a name // no plans to analyze windows without a name
char *window_name = NULL; char *window_name = NULL;

@ -1,6 +1,6 @@
[Desktop Entry] [Desktop Entry]
Name=TDEDocker Name=TDEDocker
GenericName=Docking utility GenericName=Application docking utility
Comment=Docks any application into system tray Comment=Docks any application into system tray
Exec=tdedocker Exec=tdedocker
TryExec=tdedocker TryExec=tdedocker

Loading…
Cancel
Save