7#include "waylandtasksmodel.h"
8#include "libtaskmanager_debug.h"
10#include "virtualdesktopinfo.h"
13#include <KSharedConfig>
14#include <KWindowSystem>
16#include <qwayland-plasma-window-management.h>
20#include <QFutureWatcher>
21#include <QGuiApplication>
24#include <QQuickWindow>
28#include <QWaylandClientExtension>
30#include <QtConcurrentRun>
31#include <qpa/qplatformwindow_p.h>
40class PlasmaWindow :
public QObject,
public QtWayland::org_kde_plasma_window
44 PlasmaWindow(
const QString &uuid, ::org_kde_plasma_window *
id)
45 : org_kde_plasma_window(id)
53 using state = QtWayland::org_kde_plasma_window_management::state;
58 QFlags<state> windowState;
59 QList<QString> virtualDesktops;
61 QString applicationMenuService;
62 QString applicationMenuObjectPath;
63 QList<QString> activities;
66 QPointer<PlasmaWindow> parentWindow;
67 bool wasUnmapped =
false;
75 void minimizedChanged();
76 void maximizedChanged();
77 void fullscreenChanged();
78 void keepAboveChanged();
79 void keepBelowChanged();
80 void onAllDesktopsChanged();
81 void demandsAttentionChanged();
82 void closeableChanged();
83 void minimizeableChanged();
84 void maximizeableChanged();
85 void fullscreenableChanged();
86 void skiptaskbarChanged();
87 void shadeableChanged();
89 void movableChanged();
90 void resizableChanged();
91 void virtualDesktopChangeableChanged();
92 void skipSwitcherChanged();
93 void virtualDesktopEntered();
94 void virtualDesktopLeft();
95 void geometryChanged();
96 void skipTaskbarChanged();
97 void applicationMenuChanged();
98 void activitiesChanged();
99 void parentWindowChanged();
100 void initialStateDone();
103 void org_kde_plasma_window_unmapped()
override
108 void org_kde_plasma_window_title_changed(
const QString &title)
override
113 void org_kde_plasma_window_app_id_changed(
const QString &app_id)
override
118 void org_kde_plasma_window_icon_changed()
override
121 if (pipe2(pipeFds, O_CLOEXEC) != 0) {
122 qCWarning(TASKMANAGER_DEBUG) <<
"failed creating pipe";
125 get_icon(pipeFds[1]);
127 auto readIcon = [uuid = uuid](
int fd) {
128 auto closeGuard = qScopeGuard([fd]() {
133 pollFd.events = POLLIN;
136 int ready = poll(&pollFd, 1, 1000);
137 if (ready < 0 && errno != EINTR) {
138 qCWarning(TASKMANAGER_DEBUG) <<
"polling for icon of window" << uuid <<
"failed";
140 }
else if (ready == 0) {
141 qCWarning(TASKMANAGER_DEBUG) <<
"time out polling for icon of window" << uuid;
145 int n =
read(fd, buffer,
sizeof(buffer));
147 qCWarning(TASKMANAGER_DEBUG) <<
"error reading icon of window" << uuid;
153 QDataStream ds(data);
161 auto watcher =
new QFutureWatcher<QIcon>();
163 icon = watcher->future().result();
167 watcher->setFuture(future);
169 void org_kde_plasma_window_themed_icon_name_changed(
const QString &name)
override
174 void org_kde_plasma_window_state_changed(uint32_t flags)
override
176 auto diff = windowState ^ flags;
177 if (diff & state::state_active) {
178 windowState.setFlag(state::state_active, flags & state::state_active);
181 if (diff & state::state_minimized) {
182 windowState.setFlag(state::state_minimized, flags & state::state_minimized);
183 Q_EMIT minimizedChanged();
185 if (diff & state::state_maximized) {
186 windowState.setFlag(state::state_maximized, flags & state::state_maximized);
187 Q_EMIT maximizedChanged();
189 if (diff & state::state_fullscreen) {
190 windowState.setFlag(state::state_fullscreen, flags & state::state_fullscreen);
191 Q_EMIT fullscreenChanged();
193 if (diff & state::state_keep_above) {
194 windowState.setFlag(state::state_keep_above, flags & state::state_keep_above);
195 Q_EMIT keepAboveChanged();
197 if (diff & state::state_keep_below) {
198 windowState.setFlag(state::state_keep_below, flags & state::state_keep_below);
199 Q_EMIT keepBelowChanged();
201 if (diff & state::state_on_all_desktops) {
202 windowState.setFlag(state::state_on_all_desktops, flags & state::state_on_all_desktops);
203 Q_EMIT onAllDesktopsChanged();
205 if (diff & state::state_demands_attention) {
206 windowState.setFlag(state::state_demands_attention, flags & state::state_demands_attention);
207 Q_EMIT demandsAttentionChanged();
209 if (diff & state::state_closeable) {
210 windowState.setFlag(state::state_closeable, flags & state::state_closeable);
211 Q_EMIT closeableChanged();
213 if (diff & state::state_minimizable) {
214 windowState.setFlag(state::state_minimizable, flags & state::state_minimizable);
215 Q_EMIT minimizeableChanged();
217 if (diff & state::state_maximizable) {
218 windowState.setFlag(state::state_maximizable, flags & state::state_maximizable);
219 Q_EMIT maximizeableChanged();
221 if (diff & state::state_fullscreenable) {
222 windowState.setFlag(state::state_fullscreenable, flags & state::state_fullscreenable);
223 Q_EMIT fullscreenableChanged();
225 if (diff & state::state_skiptaskbar) {
226 windowState.setFlag(state::state_skiptaskbar, flags & state::state_skiptaskbar);
227 Q_EMIT skipTaskbarChanged();
229 if (diff & state::state_shadeable) {
230 windowState.setFlag(state::state_shadeable, flags & state::state_shadeable);
231 Q_EMIT shadeableChanged();
233 if (diff & state::state_shaded) {
234 windowState.setFlag(state::state_shaded, flags & state::state_shaded);
237 if (diff & state::state_movable) {
238 windowState.setFlag(state::state_movable, flags & state::state_movable);
241 if (diff & state::state_resizable) {
242 windowState.setFlag(state::state_resizable, flags & state::state_resizable);
243 Q_EMIT resizableChanged();
245 if (diff & state::state_virtual_desktop_changeable) {
246 windowState.setFlag(state::state_virtual_desktop_changeable, flags & state::state_virtual_desktop_changeable);
247 Q_EMIT virtualDesktopChangeableChanged();
249 if (diff & state::state_skipswitcher) {
250 windowState.setFlag(state::state_skipswitcher, flags & state::state_skipswitcher);
251 Q_EMIT skipSwitcherChanged();
254 void org_kde_plasma_window_virtual_desktop_entered(
const QString &
id)
override
256 virtualDesktops.push_back(
id);
257 Q_EMIT virtualDesktopEntered();
260 void org_kde_plasma_window_virtual_desktop_left(
const QString &
id)
override
262 virtualDesktops.removeAll(
id);
263 Q_EMIT virtualDesktopLeft();
265 void org_kde_plasma_window_geometry(int32_t x, int32_t y, uint32_t width, uint32_t height)
override
267 geometry = QRect(x, y, width, height);
270 void org_kde_plasma_window_application_menu(
const QString &service_name,
const QString &object_path)
override
273 applicationMenuService = service_name;
274 applicationMenuObjectPath = object_path;
275 Q_EMIT applicationMenuChanged();
277 void org_kde_plasma_window_activity_entered(
const QString &
id)
override
279 activities.push_back(
id);
280 Q_EMIT activitiesChanged();
282 void org_kde_plasma_window_activity_left(
const QString &
id)
override
284 activities.removeAll(
id);
285 Q_EMIT activitiesChanged();
287 void org_kde_plasma_window_pid_changed(uint32_t pid)
override
291 void org_kde_plasma_window_resource_name_changed(
const QString &resource_name)
override
293 resourceName = resource_name;
295 void org_kde_plasma_window_parent_window(::org_kde_plasma_window *
parent)
override
297 PlasmaWindow *parentWindow =
nullptr;
299 parentWindow =
dynamic_cast<PlasmaWindow *
>(PlasmaWindow::fromObject(
parent));
301 setParentWindow(parentWindow);
303 void org_kde_plasma_window_initial_state()
override
305 Q_EMIT initialStateDone();
309 void setParentWindow(PlasmaWindow *
parent)
311 const auto old = parentWindow;
316 parentWindow = QPointer<PlasmaWindow>(
parent);
318 setParentWindow(
nullptr);
323 parentWindow = QPointer<PlasmaWindow>();
324 parentWindowUnmappedConnection = QMetaObject::Connection();
325 parentWindowDestroyedConnection = QMetaObject::Connection();
328 if (parentWindow.data() != old.data()) {
329 Q_EMIT parentWindowChanged();
333 QMetaObject::Connection parentWindowUnmappedConnection;
334 QMetaObject::Connection parentWindowDestroyedConnection;
337class PlasmaStackingOrder;
339class PlasmaWindowManagement :
public QWaylandClientExtensionTemplate<PlasmaWindowManagement>,
public QtWayland::org_kde_plasma_window_management
343 static constexpr int s_version = 17;
344 PlasmaWindowManagement()
345 : QWaylandClientExtensionTemplate(s_version)
347 connect(
this, &QWaylandClientExtension::activeChanged,
this, [
this] {
349 wl_proxy_destroy(
reinterpret_cast<wl_proxy *
>(
object()));
350 }
else if (QtWayland::org_kde_plasma_window_management::version() >= ORG_KDE_PLASMA_WINDOW_MANAGEMENT_GET_STACKING_ORDER_SINCE_VERSION) {
352 org_kde_plasma_window_management_stacking_order_changed_2();
357 qCWarning(TASKMANAGER_DEBUG)
358 <<
"The PlasmaWindowManagement protocol hasn't activated in time. The client possibly got denied by kwin? Check kwin output.";
361 ~PlasmaWindowManagement()
364 wl_proxy_destroy(
reinterpret_cast<wl_proxy *
>(
object()));
367 void org_kde_plasma_window_management_window_with_uuid(uint32_t
id,
const QString &uuid)
override
370 Q_EMIT windowCreated(
new PlasmaWindow(uuid, get_window_by_uuid(uuid)));
372 void org_kde_plasma_window_management_stacking_order_uuid_changed(
const QString &uuids)
override
374 Q_EMIT stackingOrderChanged(uuids.
split(QLatin1Char(
';')));
376 void org_kde_plasma_window_management_stacking_order_changed_2()
override;
377 void stackingOrderDone(
const QList<QString> &uuids)
379 Q_EMIT stackingOrderChanged(uuids);
380 m_pendingStackingOrder.reset();
383 void windowCreated(PlasmaWindow *window);
384 void stackingOrderChanged(
const QList<QString> &uuids);
387 std::unique_ptr<PlasmaStackingOrder> m_pendingStackingOrder;
390class PlasmaStackingOrder :
public QtWayland::org_kde_plasma_stacking_order
393 explicit PlasmaStackingOrder(PlasmaWindowManagement *windowManagement, ::org_kde_plasma_stacking_order *
id)
394 : QtWayland::org_kde_plasma_stacking_order(id)
395 , m_windowManagement(windowManagement)
398 ~PlasmaStackingOrder()
400 org_kde_plasma_stacking_order_destroy(
object());
403 void org_kde_plasma_stacking_order_window(
const QString &uuid)
override
405 m_uuids.push_back(uuid);
408 void org_kde_plasma_stacking_order_done()
override
410 m_windowManagement->stackingOrderDone(m_uuids);
413 PlasmaWindowManagement *
const m_windowManagement;
414 QList<QString> m_uuids;
417void PlasmaWindowManagement::org_kde_plasma_window_management_stacking_order_changed_2()
419 m_pendingStackingOrder.reset(
new PlasmaStackingOrder(
this, org_kde_plasma_window_management_get_stacking_order(
object())));
425 Private(WaylandTasksModel *q);
426 QHash<PlasmaWindow *, AppData> appDataCache;
427 QHash<PlasmaWindow *, QDateTime> lastActivated;
428 PlasmaWindow *activeWindow =
nullptr;
429 std::vector<std::unique_ptr<PlasmaWindow>> windows;
431 QHash<PlasmaWindow *, PlasmaWindow *> transients;
433 QMultiHash<PlasmaWindow *, PlasmaWindow *> transientsDemandingAttention;
434 std::unique_ptr<PlasmaWindowManagement> windowManagement;
435 KSharedConfig::Ptr rulesConfig;
436 KDirWatch *configWatcher =
nullptr;
437 VirtualDesktopInfo *virtualDesktopInfo =
nullptr;
439 QList<QString> stackingOrder;
443 auto findWindow(PlasmaWindow *window)
const;
444 void addWindow(PlasmaWindow *window);
446 const AppData &appData(PlasmaWindow *window);
448 QIcon icon(PlasmaWindow *window);
451 static QString groupMimeType();
453 void dataChanged(PlasmaWindow *window,
int role);
454 void dataChanged(PlasmaWindow *window,
const QList<int> &roles);
457 WaylandTasksModel *
const q;
467void WaylandTasksModel::Private::init()
469 auto clearCacheAndRefresh = [
this] {
470 if (windows.empty()) {
474 appDataCache.clear();
477 Q_EMIT q->dataChanged(q->index(0, 0),
478 q->index(windows.size() - 1, 0),
480 AbstractTasksModel::AppId,
481 AbstractTasksModel::AppName,
482 AbstractTasksModel::GenericName,
483 AbstractTasksModel::LauncherUrl,
484 AbstractTasksModel::LauncherUrlWithoutIcon,
485 AbstractTasksModel::CanLaunchNewInstance,
486 AbstractTasksModel::SkipTaskbar});
493 configWatcher->addFile(location +
QLatin1String(
"/taskmanagerrulesrc"));
496 auto rulesConfigChange = [
this, clearCacheAndRefresh] {
497 rulesConfig->reparseConfiguration();
498 clearCacheAndRefresh();
505 virtualDesktopInfo =
new VirtualDesktopInfo(q);
510void WaylandTasksModel::Private::initWayland()
516 windowManagement = std::make_unique<PlasmaWindowManagement>();
518 QObject::connect(windowManagement.get(), &PlasmaWindowManagement::activeChanged, q, [
this] {
519 q->beginResetModel();
524 QObject::connect(windowManagement.get(), &PlasmaWindowManagement::windowCreated, q, [
this](PlasmaWindow *window) {
525 connect(window, &PlasmaWindow::initialStateDone, q, [this, window] {
531 stackingOrder = order;
532 for (const auto &window : std::as_const(windows)) {
533 this->dataChanged(window.get(), StackingOrder);
538auto WaylandTasksModel::Private::findWindow(PlasmaWindow *window)
const
540 return std::find_if(windows.begin(), windows.end(), [window](
const std::unique_ptr<PlasmaWindow> &candidate) {
541 return candidate.get() == window;
545void WaylandTasksModel::Private::addWindow(PlasmaWindow *window)
547 if (findWindow(window) != windows.end()) {
551 auto removeWindow = [
window,
this] {
553 auto it = std::find_if(windows.begin(), windows.end(), [window](
const std::unique_ptr<PlasmaWindow> &candidate) {
554 return candidate.get() == window;
557 if (it != windows.end()) {
558 const int row = it - windows.begin();
564 const std::unique_ptr<PlasmaWindow> removedWindow = std::move(*it);
567 transientsDemandingAttention.remove(window);
568 appDataCache.remove(window);
569 lastActivated.remove(window);
572 if (transients.remove(window)) {
573 if (PlasmaWindow *leader = transientsDemandingAttention.key(window)) {
574 transientsDemandingAttention.remove(leader, window);
575 dataChanged(leader,
QList<int>{IsDemandingAttention});
580 if (activeWindow == window) {
581 activeWindow =
nullptr;
597 appDataCache.remove(window);
605 appDataCache.remove(window);
608 this->dataChanged(window,
613 PlasmaWindow *effectiveActive =
window;
614 while (effectiveActive->parentWindow) {
615 effectiveActive = effectiveActive->parentWindow;
619 activeWindow = effectiveActive;
625 PlasmaWindow *effectiveWindow =
window;
627 while (effectiveWindow->parentWindow) {
628 effectiveWindow = effectiveWindow->parentWindow;
634 if (activeWindow != effectiveWindow) {
635 activeWindow = effectiveWindow;
636 this->dataChanged(effectiveWindow, IsActive);
639 if (activeWindow == effectiveWindow) {
640 activeWindow =
nullptr;
641 this->dataChanged(effectiveWindow, IsActive);
646 QObject::connect(window, &PlasmaWindow::parentWindowChanged, q, [window,
this] {
647 PlasmaWindow *leader =
window->parentWindow.data();
650 if (
window->
windowState.testFlag(PlasmaWindow::state::state_demands_attention)) {
651 if (
auto *oldLeader = transientsDemandingAttention.key(window)) {
652 if (
window->parentWindow != oldLeader) {
653 transientsDemandingAttention.remove(oldLeader, window);
654 transientsDemandingAttention.insert(leader, window);
655 dataChanged(oldLeader,
QList<int>{IsDemandingAttention});
656 dataChanged(leader,
QList<int>{IsDemandingAttention});
661 if (transients.remove(window)) {
663 transients.insert(window, leader);
665 dataChanged(window, SkipTaskbar);
668 transients.insert(window, leader);
669 dataChanged(window, SkipTaskbar);
673 QObject::connect(window, &PlasmaWindow::closeableChanged, q, [window,
this] {
674 this->dataChanged(window, IsClosable);
678 this->dataChanged(window, IsMovable);
681 QObject::connect(window, &PlasmaWindow::resizableChanged, q, [window,
this] {
682 this->dataChanged(window, IsResizable);
685 QObject::connect(window, &PlasmaWindow::fullscreenableChanged, q, [window,
this] {
686 this->dataChanged(window, IsFullScreenable);
689 QObject::connect(window, &PlasmaWindow::fullscreenChanged, q, [window,
this] {
690 this->dataChanged(window, IsFullScreen);
693 QObject::connect(window, &PlasmaWindow::maximizeableChanged, q, [window,
this] {
694 this->dataChanged(window, IsMaximizable);
697 QObject::connect(window, &PlasmaWindow::maximizedChanged, q, [window,
this] {
698 this->dataChanged(window, IsMaximized);
701 QObject::connect(window, &PlasmaWindow::minimizeableChanged, q, [window,
this] {
702 this->dataChanged(window, IsMinimizable);
705 QObject::connect(window, &PlasmaWindow::minimizedChanged, q, [window,
this] {
706 this->dataChanged(window, IsMinimized);
709 QObject::connect(window, &PlasmaWindow::keepAboveChanged, q, [window,
this] {
710 this->dataChanged(window, IsKeepAbove);
713 QObject::connect(window, &PlasmaWindow::keepBelowChanged, q, [window,
this] {
714 this->dataChanged(window, IsKeepBelow);
717 QObject::connect(window, &PlasmaWindow::shadeableChanged, q, [window,
this] {
718 this->dataChanged(window, IsShadeable);
721 QObject::connect(window, &PlasmaWindow::virtualDesktopChangeableChanged, q, [window,
this] {
722 this->dataChanged(window, IsVirtualDesktopsChangeable);
725 QObject::connect(window, &PlasmaWindow::virtualDesktopEntered, q, [window,
this] {
726 this->dataChanged(window, VirtualDesktops);
730 if (!
window->virtualDesktops.isEmpty()) {
731 this->dataChanged(window, IsOnAllVirtualDesktops);
735 QObject::connect(window, &PlasmaWindow::virtualDesktopLeft, q, [window,
this] {
736 this->dataChanged(window, VirtualDesktops);
739 if (
window->virtualDesktops.isEmpty()) {
740 this->dataChanged(window, IsOnAllVirtualDesktops);
744 QObject::connect(window, &PlasmaWindow::geometryChanged, q, [window,
this] {
745 this->dataChanged(window,
QList<int>{Geometry, ScreenGeometry});
748 QObject::connect(window, &PlasmaWindow::demandsAttentionChanged, q, [window,
this] {
750 if (
auto *leader = transients.value(window)) {
751 if (
window->
windowState.testFlag(PlasmaWindow::state::state_demands_attention)) {
752 if (!transientsDemandingAttention.values(leader).contains(window)) {
753 transientsDemandingAttention.insert(leader, window);
754 this->dataChanged(leader,
QList<int>{IsDemandingAttention});
756 }
else if (transientsDemandingAttention.remove(leader, window)) {
757 this->dataChanged(leader,
QList<int>{IsDemandingAttention});
760 this->dataChanged(window,
QList<int>{IsDemandingAttention});
764 QObject::connect(window, &PlasmaWindow::skipTaskbarChanged, q, [window,
this] {
765 this->dataChanged(window, SkipTaskbar);
768 QObject::connect(window, &PlasmaWindow::applicationMenuChanged, q, [window,
this] {
769 this->dataChanged(window,
QList<int>{ApplicationMenuServiceName, ApplicationMenuObjectPath});
772 QObject::connect(window, &PlasmaWindow::activitiesChanged, q, [window,
this] {
773 this->dataChanged(window, Activities);
777 if (PlasmaWindow *leader =
window->parentWindow.data()) {
778 transients.insert(window, leader);
781 if (
window->
windowState.testFlag(PlasmaWindow::state::state_demands_attention)) {
782 transientsDemandingAttention.insert(leader, window);
783 dataChanged(leader,
QList<int>{IsDemandingAttention});
787 const int count = windows.size();
791 windows.emplace_back(window);
796const AppData &WaylandTasksModel::Private::appData(PlasmaWindow *window)
798 static_assert(!std::is_trivially_copy_assignable_v<AppData>);
799 if (
auto it = appDataCache.constFind(window); it != appDataCache.constEnd()) {
803 return *appDataCache.emplace(window, appDataFromUrl(windowUrlFromMetadata(
window->appId,
window->pid, rulesConfig,
window->resourceName)));
806QIcon WaylandTasksModel::Private::icon(PlasmaWindow *window)
808 const AppData &app = appData(window);
810 if (!app.icon.isNull()) {
819QString WaylandTasksModel::Private::mimeType()
823 return u
"windowsystem/winid+" + uuid.toString();
826QString WaylandTasksModel::Private::groupMimeType()
830 return u
"windowsystem/multiple-winids+" + uuid.toString();
833void WaylandTasksModel::Private::dataChanged(PlasmaWindow *window,
int role)
835 auto it = findWindow(window);
836 if (it == windows.end()) {
840 Q_EMIT q->dataChanged(idx, idx,
QList<int>{role});
843void WaylandTasksModel::Private::dataChanged(PlasmaWindow *window,
const QList<int> &roles)
845 auto it = findWindow(window);
846 if (it == windows.end()) {
850 Q_EMIT q->dataChanged(idx, idx, roles);
853WaylandTasksModel::WaylandTasksModel(
QObject *parent)
854 : AbstractWindowTasksModel(parent)
855 , d(new Private(this))
860WaylandTasksModel::~WaylandTasksModel()
862 for (
auto &window : d->windows) {
870 if (!index.
isValid() ||
static_cast<size_t>(index.
row()) >= d->windows.size()) {
874 PlasmaWindow *
window = d->windows.at(index.
row()).get();
879 return d->icon(window);
880 }
else if (role == AppId) {
881 const QString &
id = d->appData(window).id;
888 }
else if (role == AppName) {
889 return d->appData(window).name;
890 }
else if (role == GenericName) {
891 return d->appData(window).genericName;
892 }
else if (role == LauncherUrl || role == LauncherUrlWithoutIcon) {
893 return d->appData(window).url;
894 }
else if (role == WinIdList) {
895 return QVariantList{
window->uuid};
896 }
else if (role == MimeType) {
897 return d->mimeType();
898 }
else if (role == MimeData) {
900 }
else if (role == IsWindow) {
902 }
else if (role == IsActive) {
903 return (window == d->activeWindow);
904 }
else if (role == IsClosable) {
906 }
else if (role == IsMovable) {
908 }
else if (role == IsResizable) {
910 }
else if (role == IsMaximizable) {
912 }
else if (role == IsMaximized) {
914 }
else if (role == IsMinimizable) {
916 }
else if (role == IsMinimized || role == IsHidden) {
918 }
else if (role == IsKeepAbove) {
920 }
else if (role == IsKeepBelow) {
922 }
else if (role == IsFullScreenable) {
924 }
else if (role == IsFullScreen) {
926 }
else if (role == IsShadeable) {
928 }
else if (role == IsShaded) {
930 }
else if (role == IsVirtualDesktopsChangeable) {
931 return window->
windowState.testFlag(PlasmaWindow::state::state_virtual_desktop_changeable);
932 }
else if (role == VirtualDesktops) {
933 return window->virtualDesktops;
934 }
else if (role == IsOnAllVirtualDesktops) {
935 return window->virtualDesktops.isEmpty();
936 }
else if (role == Geometry) {
938 }
else if (role == ScreenGeometry) {
940 }
else if (role == Activities) {
941 return window->activities;
942 }
else if (role == IsDemandingAttention) {
943 return window->
windowState.testFlag(PlasmaWindow::state::state_demands_attention) || d->transientsDemandingAttention.contains(window);
944 }
else if (role == SkipTaskbar) {
945 return window->
windowState.testFlag(PlasmaWindow::state::state_skiptaskbar) || d->appData(window).skipTaskbar || d->transients.contains(window);
946 }
else if (role == SkipPager) {
948 }
else if (role == AppPid) {
950 }
else if (role == StackingOrder) {
951 return d->stackingOrder.indexOf(
window->uuid);
952 }
else if (role == LastActivated) {
953 if (d->lastActivated.contains(window)) {
954 return d->lastActivated.value(window);
956 }
else if (role == ApplicationMenuObjectPath) {
957 return window->applicationMenuObjectPath;
958 }
else if (role == ApplicationMenuServiceName) {
959 return window->applicationMenuService;
960 }
else if (role == CanLaunchNewInstance) {
961 return canLauchNewInstance(d->appData(window));
964 return AbstractTasksModel::data(index, role);
967int WaylandTasksModel::rowCount(
const QModelIndex &parent)
const
969 return parent.
isValid() ? 0 : d->windows.size();
974 return hasIndex(row, column, parent) ? createIndex(row, column, d->windows.at(row).get()) :
QModelIndex();
979 if (!
checkIndex(index, QAbstractItemModel::CheckIndexOption::IndexIsValid | QAbstractItemModel::CheckIndexOption::DoNotUseParent)) {
983 PlasmaWindow *window = d->windows.at(index.row()).get();
986 if (
auto *transientDemandingAttention = d->transientsDemandingAttention.value(window)) {
987 window = transientDemandingAttention;
994 while (d->transients.key(window)) {
995 window = d->transients.key(window);
999 window->set_state(PlasmaWindow::state::state_active, PlasmaWindow::state::state_active);
1004 if (!
checkIndex(index, QAbstractItemModel::CheckIndexOption::IndexIsValid | QAbstractItemModel::CheckIndexOption::DoNotUseParent)) {
1008 runApp(d->appData(d->windows.at(index.row()).get()));
1013 if (!
checkIndex(index, QAbstractItemModel::CheckIndexOption::IndexIsValid | QAbstractItemModel::CheckIndexOption::DoNotUseParent) || urls.
isEmpty()) {
1017 runApp(d->appData(d->windows.at(index.row()).get()), urls);
1022 if (!
checkIndex(index, QAbstractItemModel::CheckIndexOption::IndexIsValid | QAbstractItemModel::CheckIndexOption::DoNotUseParent)) {
1026 d->windows.at(index.row())->close();
1031 if (!
checkIndex(index, QAbstractItemModel::CheckIndexOption::IndexIsValid | QAbstractItemModel::CheckIndexOption::DoNotUseParent)) {
1035 auto &window = d->windows.at(index.row());
1037 window->set_state(PlasmaWindow::state::state_active, PlasmaWindow::state::state_active);
1038 window->request_move();
1043 if (!
checkIndex(index, QAbstractItemModel::CheckIndexOption::IndexIsValid | QAbstractItemModel::CheckIndexOption::DoNotUseParent)) {
1047 auto &window = d->windows.at(index.row());
1049 window->set_state(PlasmaWindow::state::state_active, PlasmaWindow::state::state_active);
1050 window->request_resize();
1055 if (!
checkIndex(index, QAbstractItemModel::CheckIndexOption::IndexIsValid | QAbstractItemModel::CheckIndexOption::DoNotUseParent)) {
1059 auto &window = d->windows.at(index.row());
1061 if (window->
windowState & PlasmaWindow::state::state_minimized) {
1062 window->set_state(PlasmaWindow::state::state_minimized, 0);
1064 window->set_state(PlasmaWindow::state::state_minimized, PlasmaWindow::state::state_minimized);
1070 if (!
checkIndex(index, QAbstractItemModel::CheckIndexOption::IndexIsValid | QAbstractItemModel::CheckIndexOption::DoNotUseParent)) {
1074 auto &window = d->windows.at(index.row());
1076 if (window->
windowState & PlasmaWindow::state::state_maximized) {
1077 window->set_state(PlasmaWindow::state::state_maximized | PlasmaWindow::state::state_active, PlasmaWindow::state::state_active);
1079 window->set_state(PlasmaWindow::state::state_maximized | PlasmaWindow::state::state_active,
1080 PlasmaWindow::state::state_maximized | PlasmaWindow::state::state_active);
1086 if (!
checkIndex(index, QAbstractItemModel::CheckIndexOption::IndexIsValid | QAbstractItemModel::CheckIndexOption::DoNotUseParent)) {
1090 auto &window = d->windows.at(index.row());
1092 if (window->
windowState & PlasmaWindow::state::state_keep_above) {
1093 window->set_state(PlasmaWindow::state::state_keep_above, 0);
1095 window->set_state(PlasmaWindow::state::state_keep_above, PlasmaWindow::state::state_keep_above);
1101 if (!
checkIndex(index, QAbstractItemModel::CheckIndexOption::IndexIsValid | QAbstractItemModel::CheckIndexOption::DoNotUseParent)) {
1104 auto &window = d->windows.at(index.row());
1106 if (window->
windowState & PlasmaWindow::state::state_keep_below) {
1107 window->set_state(PlasmaWindow::state::state_keep_below, 0);
1109 window->set_state(PlasmaWindow::state::state_keep_below, PlasmaWindow::state::state_keep_below);
1115 if (!
checkIndex(index, QAbstractItemModel::CheckIndexOption::IndexIsValid | QAbstractItemModel::CheckIndexOption::DoNotUseParent)) {
1119 auto &window = d->windows.at(index.row());
1121 if (window->
windowState & PlasmaWindow::state::state_fullscreen) {
1122 window->set_state(PlasmaWindow::state::state_fullscreen, 0);
1124 window->set_state(PlasmaWindow::state::state_fullscreen, PlasmaWindow::state::state_fullscreen);
1130 if (!
checkIndex(index, QAbstractItemModel::CheckIndexOption::IndexIsValid | QAbstractItemModel::CheckIndexOption::DoNotUseParent)) {
1134 auto &window = d->windows.at(index.row());
1136 if (window->
windowState & PlasmaWindow::state::state_shaded) {
1137 window->set_state(PlasmaWindow::state::state_shaded, 0);
1139 window->set_state(PlasmaWindow::state::state_shaded, PlasmaWindow::state::state_shaded);
1149 if (!
checkIndex(index, QAbstractItemModel::CheckIndexOption::IndexIsValid | QAbstractItemModel::CheckIndexOption::DoNotUseParent)) {
1153 auto &window = d->windows.at(index.row());
1155 if (desktops.isEmpty()) {
1156 const QStringList virtualDesktops = window->virtualDesktops;
1157 for (
const QString &desktop : virtualDesktops) {
1158 window->request_leave_virtual_desktop(desktop);
1164 for (
const QVariant &desktop : desktops) {
1165 const QString &desktopId = desktop.toString();
1171 window->request_enter_virtual_desktop(desktopId);
1176 for (
const QString &desktop : now) {
1177 if (!next.contains(desktop)) {
1178 window->request_leave_virtual_desktop(desktop);
1186 if (!
checkIndex(index, QAbstractItemModel::CheckIndexOption::IndexIsValid | QAbstractItemModel::CheckIndexOption::DoNotUseParent)) {
1190 d->windows.at(index.row())->request_enter_new_virtual_desktop();
1195 if (!
checkIndex(index, QAbstractItemModel::CheckIndexOption::IndexIsValid | QAbstractItemModel::CheckIndexOption::DoNotUseParent)) {
1199 auto &window = d->windows.at(index.row());
1200 const auto newActivities =
QSet(activities.
begin(), activities.
end());
1201 const auto plasmaActivities = window->activities;
1202 const auto oldActivities =
QSet(plasmaActivities.begin(), plasmaActivities.end());
1204 const auto activitiesToAdd = newActivities - oldActivities;
1205 for (
const auto &activity : activitiesToAdd) {
1206 window->request_enter_activity(activity);
1209 const auto activitiesToRemove = oldActivities - newActivities;
1210 for (
const auto &activity : activitiesToRemove) {
1211 window->request_leave_activity(activity);
1227 if (!
checkIndex(index, QAbstractItemModel::CheckIndexOption::IndexIsValid | QAbstractItemModel::CheckIndexOption::DoNotUseParent)) {
1243 auto waylandWindow = itemWindow->nativeInterface<QNativeInterface::Private::QWaylandWindow>();
1245 if (!waylandWindow || !waylandWindow->surface()) {
1252 auto &window = d->windows.at(index.row());
1254 window->set_minimized_geometry(waylandWindow->surface(), rect.
x(), rect.
y(), rect.
width(), rect.
height());
1265 if (!
mimeData->hasFormat(Private::mimeType())) {
1284 if (!
mimeData->hasFormat(Private::groupMimeType())) {
1309#include "waylandtasksmodel.moc"
1311#include "moc_waylandtasksmodel.cpp"
void deleted(const QString &path)
void dirty(const QString &path)
void created(const QString &path)
static KSharedConfig::Ptr openConfig(const QString &fileName=QString(), OpenFlags mode=FullConfig, QStandardPaths::StandardLocation type=QStandardPaths::GenericConfigLocation)
static bool isPlatformWayland()
A tasks model for Wayland windows.
void requestActivities(const QModelIndex &index, const QStringList &activities) override
Request moving the window at the given index to the specified activities.
void requestToggleKeepBelow(const QModelIndex &index) override
Request toggling the keep-below state of the task at the given index.
void requestToggleMinimized(const QModelIndex &index) override
Request toggling the minimized state of the window at the given index.
void requestClose(const QModelIndex &index) override
Request the window at the given index be closed.
void requestActivate(const QModelIndex &index) override
Request activation of the window at the given index.
void requestNewInstance(const QModelIndex &index) override
Request an additional instance of the application owning the window at the given index.
void requestOpenUrls(const QModelIndex &index, const QList< QUrl > &urls) override
Runs the application backing the launcher at the given index with the given URLs.
void requestMove(const QModelIndex &index) override
Request starting an interactive move for the window at the given index.
void requestToggleKeepAbove(const QModelIndex &index) override
Request toggling the keep-above state of the task at the given index.
void requestToggleMaximized(const QModelIndex &index) override
Request toggling the maximized state of the task at the given index.
static QList< QUuid > winIdsFromMimeData(const QMimeData *mimeData, bool *ok=nullptr)
Tries to extract process-internal Wayland window ids from supplied mime data.
void requestToggleShaded(const QModelIndex &index) override
Request toggling the shaded state of the task at the given index.
void requestToggleFullScreen(const QModelIndex &index) override
Request toggling the fullscreen state of the task at the given index.
static QUuid winIdFromMimeData(const QMimeData *mimeData, bool *ok=nullptr)
Tries to extract a process-internal Wayland window id from supplied mime data.
void requestResize(const QModelIndex &index) override
Request starting an interactive move for the window at the given index.
void requestNewVirtualDesktop(const QModelIndex &index) override
Request entering the window at the given index on a new virtual desktop, which is created in response...
void requestVirtualDesktops(const QModelIndex &index, const QVariantList &desktops) override
Request entering the window at the given index on the specified virtual desktops, leaving any other d...
void requestPublishDelegateGeometry(const QModelIndex &index, const QRect &geometry, QObject *delegate=nullptr) override
Request informing the window manager of new geometry for a visual delegate for the window at the give...
KCALUTILS_EXPORT QString mimeType()
KCRASH_EXPORT void initialize()
void init(KXmlGuiWindow *window, KGameDifficulty *difficulty=nullptr)
QVariant read(const QByteArray &data, int versionOverride=0)
bool checkIndex(const QModelIndex &index, CheckIndexOptions options) const const
virtual QMimeData * mimeData(const QModelIndexList &indexes) const const
QByteArray & append(QByteArrayView data)
QDateTime currentDateTime()
QIcon fromTheme(const QString &name)
bool isEmpty() const const
bool isValid() const const
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
void destroyed(QObject *obj)
bool disconnect(const QMetaObject::Connection &connection)
QObject * parent() const const
T qobject_cast(QObject *object)
QPoint toPoint() const const
QPointF mapToScene(const QPointF &point) const const
QQuickItem * parentItem() const const
QQuickWindow * window() const const
void moveTopLeft(const QPoint &position)
QPoint topLeft() const const
QStringList standardLocations(StandardLocation type)
bool isEmpty() const const
QStringList split(QChar sep, Qt::SplitBehavior behavior, Qt::CaseSensitivity cs) const const
bool contains(QLatin1StringView str, Qt::CaseSensitivity cs) const const
QFuture< T > run(Function function,...)
QFuture< ArgsType< Signal > > connect(Sender *sender, Signal signal)