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 taskDestroyed(QObject *item);
void startupItemDestroyed(AbstractGroupableItem *);
void startupDestroyed(QObject *);
void checkIfFull();
void actuallyCheckIfFull();
bool addTask(::TaskManager::Task *);
void removeTask(::TaskManager::Task *);
void addStartup(::TaskManager::Startup *);
void removeStartup(::TaskManager::Startup *);
void actuallyRemoveStartup();
void sycocaChanged(const QStringList &types);
void launcherVisibilityChange();
void checkLauncherVisibility(LauncherItem *launcher);
@ -124,6 +126,7 @@ public:
QHash<QString, QHash<int, TaskGroup*> > rootGroups; //container for groups
QList<LauncherItem *> launchers;
QList< ::TaskManager::Startup *> startupRemoveList;
int currentDesktop;
QString currentActivity;
@ -218,32 +221,80 @@ void GroupManagerPrivate::actuallyReloadTasks()
emit q->reload();
}
void GroupManagerPrivate::addStartup(::TaskManager::Startup *task)
void GroupManagerPrivate::addStartup(::TaskManager::Startup *startup)
{
//kDebug();
if (!startupList.contains(task)) {
TaskItem *item = new TaskItem(q, task);
startupList.insert(task, item);
currentRootGroup()->add(item);
QObject::connect(item, SIGNAL(destroyed(AbstractGroupableItem*)),
q, SLOT(startupItemDestroyed(AbstractGroupableItem*)));
if (startupList.contains(startup)) {
return;
}
QHash<Startup *, TaskItem *>::iterator it = startupList.begin();
QHash<Startup *, TaskItem *>::iterator itEnd = startupList.end();
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();
if (!startupList.contains(task)) {
qWarning() << "invalid startup task";
startupRemoveList.append(startup);
QTimer::singleShot(2000, q, SLOT(actuallyRemoveStartup()));
}
void GroupManagerPrivate::actuallyRemoveStartup()
{
if (startupRemoveList.isEmpty()) {
return;
}
TaskItem *item = startupList.take(task);
::TaskManager::Startup *startup = startupRemoveList.takeFirst();
if (!startupList.contains(startup)) {
return;
}
TaskItem *item = startupList.take(startup);
if (item->parentGroup()) {
item->parentGroup()->remove(item);
}
item->setTaskPointer(0);
foreach (LauncherItem * launcher, launchers) {
launcher->removeItemIfAssociated(item);
}
delete startup;
}
bool GroupManagerPrivate::addTask(::TaskManager::Task *task)
@ -320,15 +371,19 @@ bool GroupManagerPrivate::addTask(::TaskManager::Task *task)
TaskItem *startupItem = 0;
QHash<Startup *, TaskItem *>::iterator it = startupList.begin();
QHash<Startup *, TaskItem *>::iterator itEnd = startupList.end();
const QString desktopId = TaskItem::launcherUrlFromTask(q, task).toLocalFile();
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";
item = startupItem = it.value();
::TaskManager::Startup *startup = it.key();
startupRemoveList.removeAll(startup);
startupList.erase(it);
QObject::disconnect(item, 0, q, 0);
if (!skip) {
item->setTaskPointer(task);
}
delete startup;
break;
}
++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)
{
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 checkScreenChange())
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 actuallyCheckIfFull())
Q_PRIVATE_SLOT(d, bool addTask(::TaskManager::Task *))
Q_PRIVATE_SLOT(d, void removeTask(::TaskManager::Task *))
Q_PRIVATE_SLOT(d, void addStartup(::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 taskDestroyed(QObject *))
Q_PRIVATE_SLOT(d, void sycocaChanged(const QStringList &))

@ -109,6 +109,8 @@ void TaskItem::setTaskPointer(Task *task)
d->launcherUrl.clear();
}
resetLauncherCheck();
if (differentTask) {
if (d->task) {
disconnect(d->task.data(), 0, this, 0);
@ -559,24 +561,35 @@ QUrl TaskItem::launcherUrl() const
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
// See http://techbase.kde.org/Development/Tutorials/Services/Traders#The_KTrader_Query_Language
KService::List services;
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
// 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())) {
if (task && !(task->classClass().isEmpty() && task->className().isEmpty())) {
// 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
// "kdeinit4:" or "[kdeinit]", so we remove these first.
if ("Kcmshell4" == d->task.data()->classClass()) {
d->launcherUrl = getServiceLauncherUrl(d->task.data()->pid(), "KCModule", QStringList() << "kdeinit4:" << "[kdeinit]");
if (!d->launcherUrl.isEmpty()) {
return d->launcherUrl;
if ("Kcmshell4" == task->classClass()) {
launcherUrl = getServiceLauncherUrl(task->pid(), "KCModule", QStringList() << "kdeinit4:" << "[kdeinit]");
if (!launcherUrl.isEmpty()) {
return launcherUrl;
}
}
@ -587,31 +600,31 @@ QUrl TaskItem::launcherUrl() const
// Some apps have different launchers depending upon commandline...
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;
services = getServicesViaPid(d->task.data()->pid());
services = getServicesViaPid(task->pid());
}
// 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;
services = getServicesViaPid(d->task.data()->pid());
services = getServicesViaPid(task->pid());
}
// 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")) {
d->launcherUrl = QUrl(mapped);
return d->launcherUrl;
launcherUrl = mapped;
return launcherUrl;
}
if (!d->task.data()->classClass().isEmpty()) {
if (!task->classClass().isEmpty()) {
if (mapped.isEmpty()) {
mapped = grp.readEntry(d->task.data()->classClass(), QString());
mapped = grp.readEntry(task->classClass(), QString());
if (mapped.endsWith(".desktop")) {
d->launcherUrl = QUrl(mapped);
return d->launcherUrl;
launcherUrl = mapped;
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...
QStringList manualOnly = set.readEntry("ManualOnly", QStringList());
if (!d->task.data()->classClass().isEmpty() && manualOnly.contains(d->task.data()->classClass())) {
return d->launcherUrl;
if (!task->classClass().isEmpty() && manualOnly.contains(task->classClass())) {
return launcherUrl;
}
if (!mapped.isEmpty()) {
@ -631,44 +644,44 @@ QUrl TaskItem::launcherUrl() const
services = KServiceTypeTrader::self()->query("Application", QString("exist Exec and ('%1' =~ Name)").arg(mapped));
}
if (services.empty() && qobject_cast<GroupManager *>(parent())) {
QUrl savedUrl = static_cast<GroupManager *>(parent())->launcherForWmClass(d->task.data()->classClass());
if (services.empty() && groupManager) {
QUrl savedUrl = groupManager->launcherForWmClass(task->classClass());
if (savedUrl.isValid()) {
d->launcherUrl = savedUrl;
return d->launcherUrl;
launcherUrl = savedUrl;
return launcherUrl;
}
}
// To match other docks (docky, unity, etc.) attempt to match on DesktopEntryName first...
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
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!!))
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!)...
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...
if (!startup()->desktopId().isNull() && startup()->desktopId().endsWith(".desktop")) {
if (startup()->desktopId().startsWith("/")) {
d->launcherUrl = QUrl::fromLocalFile(startup()->desktopId());
return d->launcherUrl;
if (!startup->desktopId().isNull() && startup->desktopId().endsWith(".desktop")) {
if (startup->desktopId().startsWith("/")) {
launcherUrl = QUrl::fromLocalFile(startup->desktopId());
return launcherUrl;
} else {
QString desktopName = startup()->desktopId();
QString desktopName = startup->desktopId();
if (desktopName.endsWith(".desktop")) {
desktopName = desktopName.mid(desktopName.length() - 8);
@ -679,13 +692,13 @@ QUrl TaskItem::launcherUrl() const
}
// Try StartupWMClass
if (services.empty() && !startup()->wmClass().isNull()) {
services = KServiceTypeTrader::self()->query("Application", QString("exist Exec and ('%1' =~ StartupWMClass)").arg(startup()->wmClass()));
if (services.empty() && !startup->wmClass().isNull()) {
services = KServiceTypeTrader::self()->query("Application", QString("exist Exec and ('%1' =~ StartupWMClass)").arg(startup->wmClass()));
}
// Try via name...
if (services.empty() && !startup()->text().isNull()) {
services = KServiceTypeTrader::self()->query("Application", QString("exist Exec and ('%1' =~ Name)").arg(startup()->text()));
if (services.empty() && !startup->text().isNull()) {
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()) {
d->launcherUrl = QUrl::fromLocalFile(path);
launcherUrl = QUrl::fromLocalFile(path);
}
}
return d->launcherUrl;
return launcherUrl;
}
void TaskItem::resetLauncherCheck()

@ -34,6 +34,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
namespace TaskManager
{
class GroupManager;
/**
* 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 AbstractGroupableItem *item);
QUrl launcherUrl() const;
static QUrl launcherUrlFromTask(GroupManager *groupManager, Task *task, Startup *startup = 0);
void resetLauncherCheck();
public Q_SLOTS:

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

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

Loading…
Cancel
Save