Add an option to use the matching launcher icon for task items..

With the option disabled, task items use the window icon whenever
possible. With the option enabled, the launcher icon is used
instead. This prevents a jarring icon change when applications use
a different icon theme from Plasma Desktop, at the cost of losing
realtime window icon updates being reflected in the Task Manager.

Defaults to on. The Task Manager applets are getting a checkbox
for it.

This is a rock-and-a-hard-place decision. Users are regularly
upset about what they perceive as their theming choice not being
respected, and pleading for app fixes appears to be fairly fruit-
less. It also looks like Wayland will nix runtime window icon
changes. Nonetheless this will likely produce complaints about
edge cases (e.g. Gimp miniature window previews).

CCMAIL:348050
wilder-5.14
Eike Hein 11 years ago
parent 6cefb78d1e
commit fbd4a876f3
  1. 2
      CMakeLists.txt
  2. 33
      libtaskmanager/groupmanager.cpp
  3. 8
      libtaskmanager/groupmanager.h
  4. 8
      libtaskmanager/launcheritem.cpp
  5. 2
      libtaskmanager/launcheritem.h
  6. 90
      libtaskmanager/taskitem.cpp
  7. 12
      libtaskmanager/taskitem.h

@ -27,7 +27,7 @@ find_package(KF5 REQUIRED COMPONENTS Package)
find_package(KF5 5.1 REQUIRED COMPONENTS Baloo) find_package(KF5 5.1 REQUIRED COMPONENTS Baloo)
find_package(KF5TextEditor) find_package(KF5TextEditor)
find_package(KWinDBusInterface CONFIG REQUIRED) find_package(KWinDBusInterface CONFIG REQUIRED)
find_package(KF5WebKit) #find_package(KF5WebKit)
find_package(Phonon4Qt5 4.6.60 REQUIRED NO_MODULE) find_package(Phonon4Qt5 4.6.60 REQUIRED NO_MODULE)
set_package_properties(Phonon4Qt5 PROPERTIES set_package_properties(Phonon4Qt5 PROPERTIES

@ -75,6 +75,7 @@ public:
changingGroupingStrategy(false), changingGroupingStrategy(false),
readingLauncherConfig(false), readingLauncherConfig(false),
separateLaunchers(true), separateLaunchers(true),
alwaysUseLauncherIcons(true),
forceGrouping(false), forceGrouping(false),
launchersLocked(false) launchersLocked(false)
{ {
@ -139,6 +140,7 @@ public:
bool changingGroupingStrategy : 1; bool changingGroupingStrategy : 1;
bool readingLauncherConfig : 1; bool readingLauncherConfig : 1;
bool separateLaunchers : 1; bool separateLaunchers : 1;
bool alwaysUseLauncherIcons : 1;
bool forceGrouping : 1; bool forceGrouping : 1;
bool launchersLocked : 1; bool launchersLocked : 1;
}; };
@ -984,6 +986,35 @@ void GroupManager::setSeparateLaunchers(bool s)
} }
} }
bool GroupManager::alwaysUseLauncherIcons() const
{
return d->alwaysUseLauncherIcons;
}
void GroupManager::setAlwaysUseLauncherIcons(bool keep)
{
if (d->alwaysUseLauncherIcons != keep) {
d->alwaysUseLauncherIcons = keep;
QStack<TaskGroup *> groups;
groups.push(d->currentRootGroup());
while (!groups.isEmpty()) {
TaskGroup *group = groups.pop();
foreach (AbstractGroupableItem * item, group->members()) {
if (item->itemType() == GroupItemType) {
groups.push(static_cast<TaskGroup *>(item));
} else if (item->itemType() == TaskItemType) {
static_cast<TaskItem *>(item)->setAnnounceIconChanges(!keep);
}
}
}
emit alwaysUseLauncherIconsChanged(keep);
}
}
bool GroupManager::forceGrouping() const bool GroupManager::forceGrouping() const
{ {
return d->forceGrouping; return d->forceGrouping;
@ -1106,7 +1137,7 @@ int GroupManagerPrivate::launcherIndex(const QUrl &url)
index = 0; index = 0;
foreach (const LauncherItem * item, launchers) { foreach (const LauncherItem * item, launchers) {
if (item->launcherUrl().scheme() == "preferred") { if (item->launcherUrl().scheme() == "preferred") {
KService::Ptr service = KService::serviceByStorageId(item->defaultApplication()); KService::Ptr service = KService::serviceByStorageId(item->defaultApplication(item->launcherUrl()));
if (service) { if (service) {
QUrl prefUrl(service->entryPath()); QUrl prefUrl(service->entryPath());

@ -60,6 +60,7 @@ class TASKMANAGER_EXPORT GroupManager: public QObject
Q_PROPERTY(bool showOnlyCurrentActivity READ showOnlyCurrentActivity WRITE setShowOnlyCurrentActivity NOTIFY showOnlyCurrentActivityChanged) Q_PROPERTY(bool showOnlyCurrentActivity READ showOnlyCurrentActivity WRITE setShowOnlyCurrentActivity NOTIFY showOnlyCurrentActivityChanged)
Q_PROPERTY(bool showOnlyMinimized READ showOnlyMinimized WRITE setShowOnlyMinimized NOTIFY showOnlyMinimizedChanged) Q_PROPERTY(bool showOnlyMinimized READ showOnlyMinimized WRITE setShowOnlyMinimized NOTIFY showOnlyMinimizedChanged)
Q_PROPERTY(bool separateLaunchers READ separateLaunchers WRITE setSeparateLaunchers NOTIFY separateLaunchersChanged) Q_PROPERTY(bool separateLaunchers READ separateLaunchers WRITE setSeparateLaunchers NOTIFY separateLaunchersChanged)
Q_PROPERTY(bool alwaysUseLauncherIcons READ alwaysUseLauncherIcons WRITE setAlwaysUseLauncherIcons NOTIFY alwaysUseLauncherIconsChanged)
Q_PROPERTY(QList<QUrl> launcherList READ launcherList WRITE setLauncherList NOTIFY launcherListChanged) Q_PROPERTY(QList<QUrl> launcherList READ launcherList WRITE setLauncherList NOTIFY launcherListChanged)
public: public:
@ -189,6 +190,12 @@ public:
/** set if launchers should been show separate from tasks */ /** set if launchers should been show separate from tasks */
void setSeparateLaunchers(bool s); void setSeparateLaunchers(bool s);
/** keep using launcher icon for running tasks */
bool alwaysUseLauncherIcons() const;
/** set whether to keep using launcher icons for running tasks */
void setAlwaysUseLauncherIcons(bool keep);
/** Should grouping *always* happen? */ /** Should grouping *always* happen? */
bool forceGrouping() const; bool forceGrouping() const;
@ -225,6 +232,7 @@ Q_SIGNALS:
void showOnlyCurrentActivityChanged(bool); void showOnlyCurrentActivityChanged(bool);
void showOnlyMinimizedChanged(bool); void showOnlyMinimizedChanged(bool);
void separateLaunchersChanged(bool); void separateLaunchersChanged(bool);
void alwaysUseLauncherIconsChanged(bool);
private: private:
Q_PRIVATE_SLOT(d, void currentDesktopChanged(int)) Q_PRIVATE_SLOT(d, void currentDesktopChanged(int))

@ -238,7 +238,7 @@ void LauncherItem::launch()
//NOTE: preferred is NOT a protocol, it's just a magic string //NOTE: preferred is NOT a protocol, it's just a magic string
if (d->url.scheme() == "preferred") { if (d->url.scheme() == "preferred") {
KService::Ptr service = KService::serviceByStorageId(defaultApplication()); KService::Ptr service = KService::serviceByStorageId(defaultApplication(d->url));
if (!service) { if (!service) {
return; return;
@ -262,9 +262,9 @@ QUrl LauncherItem::launcherUrl() const
} }
//Ugly hack written by Aaron Seigo from plasmagenericshell/scripting/scriptengine.cpp //Ugly hack written by Aaron Seigo from plasmagenericshell/scripting/scriptengine.cpp
QString LauncherItem::defaultApplication() const QString LauncherItem::defaultApplication(const QUrl &url)
{ {
const QString application = d->url.host(); const QString application = url.host();
if (application.isEmpty()) { if (application.isEmpty()) {
return QString(); return QString();
} }
@ -380,7 +380,7 @@ void LauncherItem::setLauncherUrl(const QUrl& url)
} }
} else if (d->url.scheme() == "preferred") { } else if (d->url.scheme() == "preferred") {
//NOTE: preferred is NOT a protocol, it's just a magic string //NOTE: preferred is NOT a protocol, it's just a magic string
const KService::Ptr service = KService::serviceByStorageId(defaultApplication()); const KService::Ptr service = KService::serviceByStorageId(defaultApplication(d->url));
if (service) { if (service) {
QString desktopFile = QStandardPaths::locate(QStandardPaths::ApplicationsLocation, service->entryPath()); QString desktopFile = QStandardPaths::locate(QStandardPaths::ApplicationsLocation, service->entryPath());

@ -89,7 +89,7 @@ public:
void setLauncherUrl(const QUrl &url); void setLauncherUrl(const QUrl &url);
//preferred applications hack //preferred applications hack
QString defaultApplication() const; static QString defaultApplication(const QUrl &url);
public Q_SLOTS: public Q_SLOTS:
void toDesktop(int); void toDesktop(int);

@ -24,11 +24,13 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
// Own // Own
#include "taskitem.h" #include "taskitem.h"
#include "launcheritem.h"
#include <KActivities/Info> #include <KActivities/Info>
#include <KConfig> #include <KConfig>
#include <KConfigGroup> #include <KConfigGroup>
#include <KDesktopFile> #include <KDesktopFile>
#include <KFileItem>
#include <KService> #include <KService>
#include <KServiceTypeTrader> #include <KServiceTypeTrader>
#include <processcore/processes.h> #include <processcore/processes.h>
@ -45,24 +47,36 @@ namespace TaskManager
{ {
class TaskItem::Private class TaskItemPrivate
{ {
public: public:
Private() TaskItemPrivate(TaskItem *item)
: checkedForLauncher(false) { : q(item),
announceIconChanges(false),
checkedForLauncher(false) {
} }
void filterChange(::TaskManager::TaskChanges change);
TaskItem *q;
QWeakPointer<Task> task; QWeakPointer<Task> task;
QWeakPointer<Startup> startupTask; QWeakPointer<Startup> startupTask;
QUrl launcherUrl; QUrl launcherUrl;
QIcon launcherIcon;
bool announceIconChanges;
bool checkedForLauncher; bool checkedForLauncher;
QString taskName; QString taskName;
}; };
void TaskItemPrivate::filterChange(::TaskManager::TaskChanges change)
{
if (announceIconChanges || change != ::TaskManager::TaskChange::IconChanged) {
emit q->changed(change);
}
}
TaskItem::TaskItem(QObject *parent, Task *task) TaskItem::TaskItem(QObject *parent, Task *task)
: AbstractGroupableItem(parent), : AbstractGroupableItem(parent),
d(new Private) d(new TaskItemPrivate(this))
{ {
setTaskPointer(task); setTaskPointer(task);
} }
@ -70,10 +84,10 @@ TaskItem::TaskItem(QObject *parent, Task *task)
TaskItem::TaskItem(QObject *parent, Startup *task) TaskItem::TaskItem(QObject *parent, Startup *task)
: AbstractGroupableItem(parent), : AbstractGroupableItem(parent),
d(new Private) d(new TaskItemPrivate(this))
{ {
d->startupTask = task; d->startupTask = task;
connect(task, SIGNAL(changed(::TaskManager::TaskChanges)), this, SIGNAL(changed(::TaskManager::TaskChanges))); connect(task, SIGNAL(changed(::TaskManager::TaskChanges)), this, SLOT(filterChange(::TaskManager::TaskChanges)));
connect(task, SIGNAL(destroyed(QObject*)), this, SLOT(taskDestroyed())); //this item isn't useful anymore if the Task was closed connect(task, SIGNAL(destroyed(QObject*)), this, SLOT(taskDestroyed())); //this item isn't useful anymore if the Task was closed
} }
@ -119,7 +133,7 @@ void TaskItem::setTaskPointer(Task *task)
d->task = task; d->task = task;
if (task) { if (task) {
connect(task, SIGNAL(changed(::TaskManager::TaskChanges)), this, SIGNAL(changed(::TaskManager::TaskChanges))); connect(task, SIGNAL(changed(::TaskManager::TaskChanges)), this, SLOT(filterChange(::TaskManager::TaskChanges)));
connect(task, SIGNAL(destroyed(QObject*)), this, SLOT(taskDestroyed())); connect(task, SIGNAL(destroyed(QObject*)), this, SLOT(taskDestroyed()));
emit gotTaskPointer(); emit gotTaskPointer();
} }
@ -166,8 +180,20 @@ WindowList TaskItem::winIds() const
QIcon TaskItem::icon() const QIcon TaskItem::icon() const
{ {
if (d->task) { if (d->task) {
if (static_cast<GroupManager *>(parent())->alwaysUseLauncherIcons()) {
if (d->launcherIcon.isNull()) {
d->launcherIcon = launcherIconFromUrl(launcherUrl());
}
if (!d->launcherIcon.isNull()) {
return d->launcherIcon;
} else {
return d->task.data()->icon(); return d->task.data()->icon();
} }
} else {
return d->task.data()->icon();
}
}
if (d->startupTask) { if (d->startupTask) {
return d->startupTask.data()->icon(); return d->startupTask.data()->icon();
@ -176,6 +202,16 @@ QIcon TaskItem::icon() const
return QIcon(); return QIcon();
} }
bool TaskItem::announceIconChanges() const
{
return d->announceIconChanges;
}
void TaskItem::setAnnounceIconChanges(bool announce)
{
d->announceIconChanges = announce;
}
QString TaskItem::name() const QString TaskItem::name() const
{ {
if (d->task) { if (d->task) {
@ -437,7 +473,13 @@ void TaskItem::setLauncherUrl(const QUrl &url)
if (!d->launcherUrl.isEmpty()) { if (!d->launcherUrl.isEmpty()) {
return; return;
} }
d->launcherUrl = url; d->launcherUrl = url;
if (static_cast<GroupManager *>(parent())->alwaysUseLauncherIcons()) {
d->launcherIcon = launcherIconFromUrl(url);
}
d->taskName = QString(); // Cause name to be re-generated... d->taskName = QString(); // Cause name to be re-generated...
KConfig cfg("taskmanagerrulesrc"); KConfig cfg("taskmanagerrulesrc");
@ -451,7 +493,13 @@ void TaskItem::setLauncherUrl(const AbstractGroupableItem *item)
if (!d->launcherUrl.isEmpty() || !item) { if (!d->launcherUrl.isEmpty() || !item) {
return; return;
} }
d->launcherUrl = item->launcherUrl(); d->launcherUrl = item->launcherUrl();
if (static_cast<GroupManager *>(parent())->alwaysUseLauncherIcons()) {
d->launcherIcon = launcherIconFromUrl(d->launcherUrl);
}
d->taskName = QString(); // Cause name to be re-generated... d->taskName = QString(); // Cause name to be re-generated...
} }
@ -716,6 +764,32 @@ QUrl TaskItem::launcherUrlFromTask(GroupManager *groupManager, Task *task, Start
return launcherUrl; return launcherUrl;
} }
QIcon TaskItem::launcherIconFromUrl(const QUrl &url)
{
if (url.isLocalFile() && KDesktopFile::isDesktopFile(url.toLocalFile())) {
KDesktopFile f(url.toLocalFile());
if (f.tryExec()) {
return QIcon::fromTheme(f.readIcon());
}
} else if (url.scheme() == "preferred") {
//NOTE: preferred is NOT a protocol, it's just a magic string
const KService::Ptr service = KService::serviceByStorageId(LauncherItem::defaultApplication(url));
if (service) {
QString desktopFile = QStandardPaths::locate(QStandardPaths::ApplicationsLocation, service->entryPath());
KDesktopFile f(desktopFile);
return QIcon::fromTheme(f.readIcon());
}
} else {
const KFileItem fileItem(url);
return QIcon::fromTheme(fileItem.iconName());
}
return QIcon();
}
void TaskItem::resetLauncherCheck() void TaskItem::resetLauncherCheck()
{ {
if (d->launcherUrl.isEmpty()) { if (d->launcherUrl.isEmpty()) {
@ -749,4 +823,4 @@ bool TaskItem::demandsAttention() const
} // TaskManager namespace } // TaskManager namespace
#include "moc_taskitem.cpp"

@ -35,6 +35,7 @@ namespace TaskManager
{ {
class GroupManager; class GroupManager;
class TaskItemPrivate;
/** /**
* 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
@ -63,6 +64,7 @@ public:
TASKMANAGER_DEPRECATED bool isGroupItem() const; TASKMANAGER_DEPRECATED bool isGroupItem() const;
QIcon icon() const; QIcon icon() const;
QString name() const; QString name() const;
QString taskName() const; QString taskName() const;
@ -87,8 +89,12 @@ public:
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); static QUrl launcherUrlFromTask(GroupManager *groupManager, Task *task, Startup *startup = 0);
static QIcon launcherIconFromUrl(const QUrl &url);
void resetLauncherCheck(); void resetLauncherCheck();
bool announceIconChanges() const;
void setAnnounceIconChanges(bool announce);
public Q_SLOTS: public Q_SLOTS:
void toDesktop(int); void toDesktop(int);
@ -118,8 +124,10 @@ Q_SIGNALS:
void gotTaskPointer(); void gotTaskPointer();
private: private:
class Private; Q_PRIVATE_SLOT(d, void filterChange(::TaskManager::TaskChanges change))
Private * const d;
friend class TaskItemPrivate;
TaskItemPrivate * const d;
}; };
} // TaskManager namespace } // TaskManager namespace

Loading…
Cancel
Save