Cleanup Launcher->Startup->Task handoff lifecycle.

wilder-5.14
Eike Hein 12 years ago
parent 548388eefd
commit 0a22efb6b2
  1. 105
      libtaskmanager/groupmanager.cpp
  2. 2
      libtaskmanager/groupmanager.h
  3. 97
      libtaskmanager/taskitem.cpp
  4. 2
      libtaskmanager/taskitem.h
  5. 7
      libtaskmanager/taskmanager.cpp
  6. 2
      libtaskmanager/taskmanager.h

@ -93,12 +93,14 @@ public:
void checkScreenChange(); void checkScreenChange();
void taskDestroyed(QObject *item); void taskDestroyed(QObject *item);
void startupItemDestroyed(AbstractGroupableItem *); void startupItemDestroyed(AbstractGroupableItem *);
void startupDestroyed(QObject *);
void checkIfFull(); void checkIfFull();
void actuallyCheckIfFull(); void actuallyCheckIfFull();
bool addTask(::TaskManager::Task *); bool addTask(::TaskManager::Task *);
void removeTask(::TaskManager::Task *); void removeTask(::TaskManager::Task *);
void addStartup(::TaskManager::Startup *); void addStartup(::TaskManager::Startup *);
void removeStartup(::TaskManager::Startup *); void removeStartup(::TaskManager::Startup *);
void actuallyRemoveStartup();
void sycocaChanged(const QStringList &types); void sycocaChanged(const QStringList &types);
void launcherVisibilityChange(); void launcherVisibilityChange();
void checkLauncherVisibility(LauncherItem *launcher); void checkLauncherVisibility(LauncherItem *launcher);
@ -124,6 +126,7 @@ public:
QHash<QString, QHash<int, TaskGroup*> > rootGroups; //container for groups QHash<QString, QHash<int, TaskGroup*> > rootGroups; //container for groups
QList<LauncherItem *> launchers; QList<LauncherItem *> launchers;
QList< ::TaskManager::Startup *> startupRemoveList;
int currentDesktop; int currentDesktop;
QString currentActivity; QString currentActivity;
@ -218,32 +221,80 @@ void GroupManagerPrivate::actuallyReloadTasks()
emit q->reload(); emit q->reload();
} }
void GroupManagerPrivate::addStartup(::TaskManager::Startup *task) void GroupManagerPrivate::addStartup(::TaskManager::Startup *startup)
{ {
//kDebug(); if (startupList.contains(startup)) {
if (!startupList.contains(task)) { return;
TaskItem *item = new TaskItem(q, task); }
startupList.insert(task, item);
currentRootGroup()->add(item); QHash<Startup *, TaskItem *>::iterator it = startupList.begin();
QObject::connect(item, SIGNAL(destroyed(AbstractGroupableItem*)), QHash<Startup *, TaskItem *>::iterator itEnd = startupList.end();
q, SLOT(startupItemDestroyed(AbstractGroupableItem*)));
while (it != itEnd) {
if (it.key()->desktopId() == startup->desktopId() && it.key()->bin() == startup->bin()) {
return;
}
++it;
}
foreach(const AbstractGroupableItem *item, currentRootGroup()->members()) {
if (item->itemType() == TaskItemType)
{
const TaskItem *task = static_cast<const TaskItem* >(item);
if (task->launcherUrl().toLocalFile() == startup->desktopId()
|| task->taskName().toLower() == startup->bin()) {
return;
}
}
} }
TaskItem *item = new TaskItem(q, startup);
foreach (LauncherItem * launcher, launchers) {
if (launcher->associateItemIfMatches(item)) {
// Task demands attention, so is to be shown, therefore hide the launcher...
currentRootGroup()->remove(launcher);
}
}
startupList.insert(startup, item);
currentRootGroup()->add(item);
QObject::connect(startup, SIGNAL(destroyed(QObject*)), q, SLOT(startupDestroyed(QObject*)));
QObject::connect(item, SIGNAL(destroyed(AbstractGroupableItem*)),
q, SLOT(startupItemDestroyed(AbstractGroupableItem*)));
} }
void GroupManagerPrivate::removeStartup(::TaskManager::Startup *task) void GroupManagerPrivate::removeStartup(::TaskManager::Startup *startup)
{ {
//kDebug(); startupRemoveList.append(startup);
if (!startupList.contains(task)) { QTimer::singleShot(2000, q, SLOT(actuallyRemoveStartup()));
qWarning() << "invalid startup task"; }
void GroupManagerPrivate::actuallyRemoveStartup()
{
if (startupRemoveList.isEmpty()) {
return; return;
} }
TaskItem *item = startupList.take(task); ::TaskManager::Startup *startup = startupRemoveList.takeFirst();
if (!startupList.contains(startup)) {
return;
}
TaskItem *item = startupList.take(startup);
if (item->parentGroup()) { if (item->parentGroup()) {
item->parentGroup()->remove(item); item->parentGroup()->remove(item);
} }
item->setTaskPointer(0); item->setTaskPointer(0);
foreach (LauncherItem * launcher, launchers) {
launcher->removeItemIfAssociated(item);
}
delete startup;
} }
bool GroupManagerPrivate::addTask(::TaskManager::Task *task) bool GroupManagerPrivate::addTask(::TaskManager::Task *task)
@ -320,15 +371,19 @@ bool GroupManagerPrivate::addTask(::TaskManager::Task *task)
TaskItem *startupItem = 0; TaskItem *startupItem = 0;
QHash<Startup *, TaskItem *>::iterator it = startupList.begin(); QHash<Startup *, TaskItem *>::iterator it = startupList.begin();
QHash<Startup *, TaskItem *>::iterator itEnd = startupList.end(); QHash<Startup *, TaskItem *>::iterator itEnd = startupList.end();
const QString desktopId = TaskItem::launcherUrlFromTask(q, task).toLocalFile();
while (it != itEnd) { while (it != itEnd) {
if (it.key()->matchesWindow(task->window())) { if (it.key()->matchesWindow(task->window()) || it.key()->desktopId() == desktopId || it.key()->bin() == task->className()) {
//kDebug() << "startup task found"; //kDebug() << "startup task found";
item = startupItem = it.value(); item = startupItem = it.value();
::TaskManager::Startup *startup = it.key();
startupRemoveList.removeAll(startup);
startupList.erase(it); startupList.erase(it);
QObject::disconnect(item, 0, q, 0); QObject::disconnect(item, 0, q, 0);
if (!skip) { if (!skip) {
item->setTaskPointer(task); item->setTaskPointer(task);
} }
delete startup;
break; break;
} }
++it; ++it;
@ -409,6 +464,28 @@ void GroupManagerPrivate::taskDestroyed(QObject *item)
} }
} }
void GroupManagerPrivate::startupDestroyed(QObject *obj)
{
::TaskManager::Startup *startup = static_cast< ::TaskManager::Startup *>(obj);
if (!startupList.contains(startup)) {
return;
}
TaskItem *item = startupList.take(startup);
startupRemoveList.removeAll(startup);
if (item->parentGroup()) {
item->parentGroup()->remove(item);
}
item->setTaskPointer(0);
foreach (LauncherItem * launcher, launchers) {
launcher->removeItemIfAssociated(item);
}
}
void GroupManagerPrivate::startupItemDestroyed(AbstractGroupableItem *item) void GroupManagerPrivate::startupItemDestroyed(AbstractGroupableItem *item)
{ {
TaskItem *taskItem = static_cast<TaskItem*>(item); TaskItem *taskItem = static_cast<TaskItem*>(item);

@ -228,12 +228,14 @@ private:
Q_PRIVATE_SLOT(d, void taskChanged(::TaskManager::Task *, ::TaskManager::TaskChanges)) Q_PRIVATE_SLOT(d, void taskChanged(::TaskManager::Task *, ::TaskManager::TaskChanges))
Q_PRIVATE_SLOT(d, void checkScreenChange()) Q_PRIVATE_SLOT(d, void checkScreenChange())
Q_PRIVATE_SLOT(d, void startupItemDestroyed(AbstractGroupableItem *)) Q_PRIVATE_SLOT(d, void startupItemDestroyed(AbstractGroupableItem *))
Q_PRIVATE_SLOT(d, void startupDestroyed(QObject *))
Q_PRIVATE_SLOT(d, void checkIfFull()) Q_PRIVATE_SLOT(d, void checkIfFull())
Q_PRIVATE_SLOT(d, void actuallyCheckIfFull()) Q_PRIVATE_SLOT(d, void actuallyCheckIfFull())
Q_PRIVATE_SLOT(d, bool addTask(::TaskManager::Task *)) Q_PRIVATE_SLOT(d, bool addTask(::TaskManager::Task *))
Q_PRIVATE_SLOT(d, void removeTask(::TaskManager::Task *)) Q_PRIVATE_SLOT(d, void removeTask(::TaskManager::Task *))
Q_PRIVATE_SLOT(d, void addStartup(::TaskManager::Startup *)) Q_PRIVATE_SLOT(d, void addStartup(::TaskManager::Startup *))
Q_PRIVATE_SLOT(d, void removeStartup(::TaskManager::Startup *)) Q_PRIVATE_SLOT(d, void removeStartup(::TaskManager::Startup *))
Q_PRIVATE_SLOT(d, void actuallyRemoveStartup())
Q_PRIVATE_SLOT(d, void actuallyReloadTasks()) Q_PRIVATE_SLOT(d, void actuallyReloadTasks())
Q_PRIVATE_SLOT(d, void taskDestroyed(QObject *)) Q_PRIVATE_SLOT(d, void taskDestroyed(QObject *))
Q_PRIVATE_SLOT(d, void sycocaChanged(const QStringList &)) Q_PRIVATE_SLOT(d, void sycocaChanged(const QStringList &))

@ -109,6 +109,8 @@ void TaskItem::setTaskPointer(Task *task)
d->launcherUrl.clear(); d->launcherUrl.clear();
} }
resetLauncherCheck();
if (differentTask) { if (differentTask) {
if (d->task) { if (d->task) {
disconnect(d->task.data(), 0, this, 0); disconnect(d->task.data(), 0, this, 0);
@ -559,24 +561,35 @@ QUrl TaskItem::launcherUrl() const
return d->launcherUrl; return d->launcherUrl;
} }
// Set a flag so that we remeber that we have already checked for a launcher. This is becasue if we fail, then
// we will keep on failing so the isEmpty() check above is not enough.
d->checkedForLauncher = true;
if (d->task || d->startupTask) {
d->launcherUrl = launcherUrlFromTask(static_cast<GroupManager *>(parent()), d->task.data(), d->startupTask.data());
}
return d->launcherUrl;
}
QUrl TaskItem::launcherUrlFromTask(GroupManager *groupManager, Task *task, Startup *startup)
{
QUrl launcherUrl;
// Search for applications which are executable and case-insensitively match the windowclass of the task and // Search for applications which are executable and case-insensitively match the windowclass of the task and
// See http://techbase.kde.org/Development/Tutorials/Services/Traders#The_KTrader_Query_Language // See http://techbase.kde.org/Development/Tutorials/Services/Traders#The_KTrader_Query_Language
KService::List services; KService::List services;
bool triedPid = false; bool triedPid = false;
// Set a flag so that we remeber that we have already checked for a launcher. This is becasue if we fail, then if (task && !(task->classClass().isEmpty() && task->className().isEmpty())) {
// we will keep on failing so the isEmpty() check above is not enough.
d->checkedForLauncher = true;
if (d->task && !(d->task.data()->classClass().isEmpty() && d->task.data()->className().isEmpty())) {
// For KCModules, if we matched on window class, etc, we would end up matching to kcmshell4 - but we are more than likely // For KCModules, if we matched on window class, etc, we would end up matching to kcmshell4 - but we are more than likely
// interested in the actual control module. Therefore we obtain this via the commandline. This commandline may contain // interested in the actual control module. Therefore we obtain this via the commandline. This commandline may contain
// "kdeinit4:" or "[kdeinit]", so we remove these first. // "kdeinit4:" or "[kdeinit]", so we remove these first.
if ("Kcmshell4" == d->task.data()->classClass()) { if ("Kcmshell4" == task->classClass()) {
d->launcherUrl = getServiceLauncherUrl(d->task.data()->pid(), "KCModule", QStringList() << "kdeinit4:" << "[kdeinit]"); launcherUrl = getServiceLauncherUrl(task->pid(), "KCModule", QStringList() << "kdeinit4:" << "[kdeinit]");
if (!d->launcherUrl.isEmpty()) { if (!launcherUrl.isEmpty()) {
return d->launcherUrl; return launcherUrl;
} }
} }
@ -587,31 +600,31 @@ QUrl TaskItem::launcherUrl() const
// Some apps have different launchers depending upon commandline... // Some apps have different launchers depending upon commandline...
QStringList matchCommandLineFirst = set.readEntry("MatchCommandLineFirst", QStringList()); QStringList matchCommandLineFirst = set.readEntry("MatchCommandLineFirst", QStringList());
if (!d->task.data()->classClass().isEmpty() && matchCommandLineFirst.contains(d->task.data()->classClass())) { if (!task->classClass().isEmpty() && matchCommandLineFirst.contains(task->classClass())) {
triedPid = true; triedPid = true;
services = getServicesViaPid(d->task.data()->pid()); services = getServicesViaPid(task->pid());
} }
// Try to match using className also // Try to match using className also
if (!d->task.data()->className().isEmpty() && matchCommandLineFirst.contains("::"+d->task.data()->className())) { if (!task->className().isEmpty() && matchCommandLineFirst.contains("::"+task->className())) {
triedPid = true; triedPid = true;
services = getServicesViaPid(d->task.data()->pid()); services = getServicesViaPid(task->pid());
} }
// If the user has manualy set a mapping, respect this first... // If the user has manualy set a mapping, respect this first...
QString mapped(grp.readEntry(d->task.data()->classClass() + "::" + d->task.data()->className(), QString())); QString mapped(grp.readEntry(task->classClass() + "::" + task->className(), QString()));
if (mapped.endsWith(".desktop")) { if (mapped.endsWith(".desktop")) {
d->launcherUrl = QUrl(mapped); launcherUrl = mapped;
return d->launcherUrl; return launcherUrl;
} }
if (!d->task.data()->classClass().isEmpty()) { if (!task->classClass().isEmpty()) {
if (mapped.isEmpty()) { if (mapped.isEmpty()) {
mapped = grp.readEntry(d->task.data()->classClass(), QString()); mapped = grp.readEntry(task->classClass(), QString());
if (mapped.endsWith(".desktop")) { if (mapped.endsWith(".desktop")) {
d->launcherUrl = QUrl(mapped); launcherUrl = mapped;
return d->launcherUrl; return launcherUrl;
} }
} }
@ -619,8 +632,8 @@ QUrl TaskItem::launcherUrl() const
// So, Settings/ManualOnly lists window classes where the user will always have to manualy set the launcher... // So, Settings/ManualOnly lists window classes where the user will always have to manualy set the launcher...
QStringList manualOnly = set.readEntry("ManualOnly", QStringList()); QStringList manualOnly = set.readEntry("ManualOnly", QStringList());
if (!d->task.data()->classClass().isEmpty() && manualOnly.contains(d->task.data()->classClass())) { if (!task->classClass().isEmpty() && manualOnly.contains(task->classClass())) {
return d->launcherUrl; return launcherUrl;
} }
if (!mapped.isEmpty()) { if (!mapped.isEmpty()) {
@ -631,44 +644,44 @@ QUrl TaskItem::launcherUrl() const
services = KServiceTypeTrader::self()->query("Application", QString("exist Exec and ('%1' =~ Name)").arg(mapped)); services = KServiceTypeTrader::self()->query("Application", QString("exist Exec and ('%1' =~ Name)").arg(mapped));
} }
if (services.empty() && qobject_cast<GroupManager *>(parent())) { if (services.empty() && groupManager) {
QUrl savedUrl = static_cast<GroupManager *>(parent())->launcherForWmClass(d->task.data()->classClass()); QUrl savedUrl = groupManager->launcherForWmClass(task->classClass());
if (savedUrl.isValid()) { if (savedUrl.isValid()) {
d->launcherUrl = savedUrl; launcherUrl = savedUrl;
return d->launcherUrl; return launcherUrl;
} }
} }
// To match other docks (docky, unity, etc.) attempt to match on DesktopEntryName first... // To match other docks (docky, unity, etc.) attempt to match on DesktopEntryName first...
if (services.empty()) { if (services.empty()) {
services = KServiceTypeTrader::self()->query("Application", QString("exist Exec and ('%1' =~ DesktopEntryName)").arg(d->task.data()->classClass())); services = KServiceTypeTrader::self()->query("Application", QString("exist Exec and ('%1' =~ DesktopEntryName)").arg(task->classClass()));
} }
// Try StartupWMClass // Try StartupWMClass
if (services.empty()) { if (services.empty()) {
services = KServiceTypeTrader::self()->query("Application", QString("exist Exec and ('%1' =~ StartupWMClass)").arg(d->task.data()->classClass())); services = KServiceTypeTrader::self()->query("Application", QString("exist Exec and ('%1' =~ StartupWMClass)").arg(task->classClass()));
} }
// Try 'Name' - unfortunately this can be translated, so has a good chance of failing! (As it does for KDE's own "System Settings" (even in English!!)) // Try 'Name' - unfortunately this can be translated, so has a good chance of failing! (As it does for KDE's own "System Settings" (even in English!!))
if (services.empty()) { if (services.empty()) {
services = KServiceTypeTrader::self()->query("Application", QString("exist Exec and ('%1' =~ Name)").arg(d->task.data()->classClass())); services = KServiceTypeTrader::self()->query("Application", QString("exist Exec and ('%1' =~ Name)").arg(task->classClass()));
} }
} }
// Ok, absolute *last* chance, try matching via pid (but only if we have not already tried this!)... // Ok, absolute *last* chance, try matching via pid (but only if we have not already tried this!)...
if (services.empty() && !triedPid) { if (services.empty() && !triedPid) {
services = getServicesViaPid(d->task.data()->pid()); services = getServicesViaPid(task->pid());
} }
} }
if (services.empty() && isStartupItem()) { if (services.empty() && startup) {
// Try to match via desktop filename... // Try to match via desktop filename...
if (!startup()->desktopId().isNull() && startup()->desktopId().endsWith(".desktop")) { if (!startup->desktopId().isNull() && startup->desktopId().endsWith(".desktop")) {
if (startup()->desktopId().startsWith("/")) { if (startup->desktopId().startsWith("/")) {
d->launcherUrl = QUrl::fromLocalFile(startup()->desktopId()); launcherUrl = QUrl::fromLocalFile(startup->desktopId());
return d->launcherUrl; return launcherUrl;
} else { } else {
QString desktopName = startup()->desktopId(); QString desktopName = startup->desktopId();
if (desktopName.endsWith(".desktop")) { if (desktopName.endsWith(".desktop")) {
desktopName = desktopName.mid(desktopName.length() - 8); desktopName = desktopName.mid(desktopName.length() - 8);
@ -679,13 +692,13 @@ QUrl TaskItem::launcherUrl() const
} }
// Try StartupWMClass // Try StartupWMClass
if (services.empty() && !startup()->wmClass().isNull()) { if (services.empty() && !startup->wmClass().isNull()) {
services = KServiceTypeTrader::self()->query("Application", QString("exist Exec and ('%1' =~ StartupWMClass)").arg(startup()->wmClass())); services = KServiceTypeTrader::self()->query("Application", QString("exist Exec and ('%1' =~ StartupWMClass)").arg(startup->wmClass()));
} }
// Try via name... // Try via name...
if (services.empty() && !startup()->text().isNull()) { if (services.empty() && !startup->text().isNull()) {
services = KServiceTypeTrader::self()->query("Application", QString("exist Exec and ('%1' =~ Name)").arg(startup()->text())); services = KServiceTypeTrader::self()->query("Application", QString("exist Exec and ('%1' =~ Name)").arg(startup->text()));
} }
} }
@ -696,11 +709,11 @@ QUrl TaskItem::launcherUrl() const
} }
if (!path.isEmpty()) { if (!path.isEmpty()) {
d->launcherUrl = QUrl::fromLocalFile(path); launcherUrl = QUrl::fromLocalFile(path);
} }
} }
return d->launcherUrl; return launcherUrl;
} }
void TaskItem::resetLauncherCheck() void TaskItem::resetLauncherCheck()

@ -34,6 +34,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
namespace TaskManager namespace TaskManager
{ {
class GroupManager;
/** /**
* Wrapper class so we do not have to use the Task class directly and the Task* remains guarded * Wrapper class so we do not have to use the Task class directly and the Task* remains guarded
@ -85,6 +86,7 @@ public:
void setLauncherUrl(const QUrl &url); void setLauncherUrl(const QUrl &url);
void setLauncherUrl(const AbstractGroupableItem *item); void setLauncherUrl(const AbstractGroupableItem *item);
QUrl launcherUrl() const; QUrl launcherUrl() const;
static QUrl launcherUrlFromTask(GroupManager *groupManager, Task *task, Startup *startup = 0);
void resetLauncherCheck(); void resetLauncherCheck();
public Q_SLOTS: public Q_SLOTS:

@ -422,6 +422,7 @@ void TaskManager::currentDesktopChanged(int desktop)
void TaskManager::gotNewStartup(const KStartupInfoId& id, const KStartupInfoData& data) void TaskManager::gotNewStartup(const KStartupInfoId& id, const KStartupInfoData& data)
{ {
Startup *s = new Startup(id, data, 0); Startup *s = new Startup(id, data, 0);
connect(s, SIGNAL(destroyed(QObject*)), this, SLOT(startupDestroyed(QObject*)));
d->startups.append(s); d->startups.append(s);
emit startupAdded(s); emit startupAdded(s);
} }
@ -442,11 +443,15 @@ void TaskManager::killStartup(const KStartupInfoId& id)
if (startup->id() == id) { if (startup->id() == id) {
d->startups.removeAll(startup); d->startups.removeAll(startup);
emit startupRemoved(startup); emit startupRemoved(startup);
delete startup;
} }
} }
} }
void TaskManager::startupDestroyed(QObject* obj)
{
d->startups.removeAll(static_cast<Startup *>(obj));
}
QString TaskManager::desktopName(int desk) const QString TaskManager::desktopName(int desk) const
{ {
return KWindowSystem::desktopName(desk); return KWindowSystem::desktopName(desk);

@ -206,6 +206,8 @@ protected Q_SLOTS:
void gotNewStartup(const KStartupInfoId&, const KStartupInfoData&); void gotNewStartup(const KStartupInfoId&, const KStartupInfoData&);
//* @internal //* @internal
void gotStartupChange(const KStartupInfoId&, const KStartupInfoData&); void gotStartupChange(const KStartupInfoId&, const KStartupInfoData&);
//* @internal
void startupDestroyed(QObject*);
//* @internal //* @internal
void taskChanged(::TaskManager::TaskChanges changes); void taskChanged(::TaskManager::TaskChanges changes);

Loading…
Cancel
Save