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 canSetNoBorderChanged();
90 void hasNoBorderChanged();
91 void movableChanged();
92 void resizableChanged();
93 void virtualDesktopChangeableChanged();
94 void skipSwitcherChanged();
95 void virtualDesktopEntered();
96 void virtualDesktopLeft();
97 void geometryChanged();
98 void skipTaskbarChanged();
99 void applicationMenuChanged();
100 void activitiesChanged();
101 void parentWindowChanged();
102 void initialStateDone();
105 void org_kde_plasma_window_unmapped()
override
110 void org_kde_plasma_window_title_changed(
const QString &title)
override
115 void org_kde_plasma_window_app_id_changed(
const QString &app_id)
override
120 void org_kde_plasma_window_icon_changed()
override
123 if (pipe2(pipeFds, O_CLOEXEC) != 0) {
124 qCWarning(TASKMANAGER_DEBUG) <<
"failed creating pipe";
127 get_icon(pipeFds[1]);
129 auto readIcon = [uuid = uuid](
int fd) {
130 auto closeGuard = qScopeGuard([fd]() {
135 pollFd.events = POLLIN;
138 int ready = poll(&pollFd, 1, 1000);
139 if (ready < 0 && errno != EINTR) {
140 qCWarning(TASKMANAGER_DEBUG) <<
"polling for icon of window" << uuid <<
"failed";
142 }
else if (ready == 0) {
143 qCWarning(TASKMANAGER_DEBUG) <<
"time out polling for icon of window" << uuid;
147 int n =
read(fd, buffer,
sizeof(buffer));
149 qCWarning(TASKMANAGER_DEBUG) <<
"error reading icon of window" << uuid;
155 QDataStream ds(data);
163 auto watcher =
new QFutureWatcher<QIcon>();
165 icon = watcher->future().result();
169 watcher->setFuture(future);
171 void org_kde_plasma_window_themed_icon_name_changed(
const QString &name)
override
176 void org_kde_plasma_window_state_changed(uint32_t flags)
override
178 auto diff = windowState ^ flags;
179 if (diff & state::state_active) {
180 windowState.setFlag(state::state_active, flags & state::state_active);
183 if (diff & state::state_minimized) {
184 windowState.setFlag(state::state_minimized, flags & state::state_minimized);
185 Q_EMIT minimizedChanged();
187 if (diff & state::state_maximized) {
188 windowState.setFlag(state::state_maximized, flags & state::state_maximized);
189 Q_EMIT maximizedChanged();
191 if (diff & state::state_fullscreen) {
192 windowState.setFlag(state::state_fullscreen, flags & state::state_fullscreen);
193 Q_EMIT fullscreenChanged();
195 if (diff & state::state_keep_above) {
196 windowState.setFlag(state::state_keep_above, flags & state::state_keep_above);
197 Q_EMIT keepAboveChanged();
199 if (diff & state::state_keep_below) {
200 windowState.setFlag(state::state_keep_below, flags & state::state_keep_below);
201 Q_EMIT keepBelowChanged();
203 if (diff & state::state_on_all_desktops) {
204 windowState.setFlag(state::state_on_all_desktops, flags & state::state_on_all_desktops);
205 Q_EMIT onAllDesktopsChanged();
207 if (diff & state::state_demands_attention) {
208 windowState.setFlag(state::state_demands_attention, flags & state::state_demands_attention);
209 Q_EMIT demandsAttentionChanged();
211 if (diff & state::state_closeable) {
212 windowState.setFlag(state::state_closeable, flags & state::state_closeable);
213 Q_EMIT closeableChanged();
215 if (diff & state::state_minimizable) {
216 windowState.setFlag(state::state_minimizable, flags & state::state_minimizable);
217 Q_EMIT minimizeableChanged();
219 if (diff & state::state_maximizable) {
220 windowState.setFlag(state::state_maximizable, flags & state::state_maximizable);
221 Q_EMIT maximizeableChanged();
223 if (diff & state::state_fullscreenable) {
224 windowState.setFlag(state::state_fullscreenable, flags & state::state_fullscreenable);
225 Q_EMIT fullscreenableChanged();
227 if (diff & state::state_skiptaskbar) {
228 windowState.setFlag(state::state_skiptaskbar, flags & state::state_skiptaskbar);
229 Q_EMIT skipTaskbarChanged();
231 if (diff & state::state_shadeable) {
232 windowState.setFlag(state::state_shadeable, flags & state::state_shadeable);
233 Q_EMIT shadeableChanged();
235 if (diff & state::state_shaded) {
236 windowState.setFlag(state::state_shaded, flags & state::state_shaded);
239 if (diff & state::state_movable) {
240 windowState.setFlag(state::state_movable, flags & state::state_movable);
243 if (diff & state::state_resizable) {
244 windowState.setFlag(state::state_resizable, flags & state::state_resizable);
245 Q_EMIT resizableChanged();
247 if (diff & state::state_virtual_desktop_changeable) {
248 windowState.setFlag(state::state_virtual_desktop_changeable, flags & state::state_virtual_desktop_changeable);
249 Q_EMIT virtualDesktopChangeableChanged();
251 if (diff & state::state_skipswitcher) {
252 windowState.setFlag(state::state_skipswitcher, flags & state::state_skipswitcher);
253 Q_EMIT skipSwitcherChanged();
255 if (diff & state::state_can_set_no_border) {
256 windowState.setFlag(state::state_can_set_no_border, flags & state::state_can_set_no_border);
257 Q_EMIT canSetNoBorderChanged();
259 if (diff & state::state_no_border) {
260 windowState.setFlag(state::state_no_border, flags & state::state_no_border);
261 Q_EMIT hasNoBorderChanged();
264 void org_kde_plasma_window_virtual_desktop_entered(
const QString &
id)
override
266 virtualDesktops.push_back(
id);
267 Q_EMIT virtualDesktopEntered();
270 void org_kde_plasma_window_virtual_desktop_left(
const QString &
id)
override
272 virtualDesktops.removeAll(
id);
273 Q_EMIT virtualDesktopLeft();
275 void org_kde_plasma_window_geometry(int32_t x, int32_t y, uint32_t width, uint32_t height)
override
277 geometry = QRect(x, y, width, height);
280 void org_kde_plasma_window_application_menu(
const QString &service_name,
const QString &object_path)
override
283 applicationMenuService = service_name;
284 applicationMenuObjectPath = object_path;
285 Q_EMIT applicationMenuChanged();
287 void org_kde_plasma_window_activity_entered(
const QString &
id)
override
289 activities.push_back(
id);
290 Q_EMIT activitiesChanged();
292 void org_kde_plasma_window_activity_left(
const QString &
id)
override
294 activities.removeAll(
id);
295 Q_EMIT activitiesChanged();
297 void org_kde_plasma_window_pid_changed(uint32_t pid)
override
301 void org_kde_plasma_window_resource_name_changed(
const QString &resource_name)
override
303 resourceName = resource_name;
305 void org_kde_plasma_window_parent_window(::org_kde_plasma_window *
parent)
override
307 PlasmaWindow *parentWindow =
nullptr;
309 parentWindow =
dynamic_cast<PlasmaWindow *
>(PlasmaWindow::fromObject(
parent));
311 setParentWindow(parentWindow);
313 void org_kde_plasma_window_initial_state()
override
315 Q_EMIT initialStateDone();
319 void setParentWindow(PlasmaWindow *
parent)
321 const auto old = parentWindow;
326 parentWindow = QPointer<PlasmaWindow>(
parent);
328 setParentWindow(
nullptr);
333 parentWindow = QPointer<PlasmaWindow>();
334 parentWindowUnmappedConnection = QMetaObject::Connection();
335 parentWindowDestroyedConnection = QMetaObject::Connection();
338 if (parentWindow.data() != old.data()) {
339 Q_EMIT parentWindowChanged();
343 QMetaObject::Connection parentWindowUnmappedConnection;
344 QMetaObject::Connection parentWindowDestroyedConnection;
347class PlasmaStackingOrder;
349class PlasmaWindowManagement :
public QWaylandClientExtensionTemplate<PlasmaWindowManagement>,
public QtWayland::org_kde_plasma_window_management
353 static constexpr int s_version = 17;
354 PlasmaWindowManagement()
355 : QWaylandClientExtensionTemplate(s_version)
357 connect(
this, &QWaylandClientExtension::activeChanged,
this, [
this] {
359 wl_proxy_destroy(
reinterpret_cast<wl_proxy *
>(
object()));
360 }
else if (QtWayland::org_kde_plasma_window_management::version() >= ORG_KDE_PLASMA_WINDOW_MANAGEMENT_GET_STACKING_ORDER_SINCE_VERSION) {
362 org_kde_plasma_window_management_stacking_order_changed_2();
367 qCWarning(TASKMANAGER_DEBUG)
368 <<
"The PlasmaWindowManagement protocol hasn't activated in time. The client possibly got denied by kwin? Check kwin output.";
371 ~PlasmaWindowManagement()
374 wl_proxy_destroy(
reinterpret_cast<wl_proxy *
>(
object()));
377 void org_kde_plasma_window_management_window_with_uuid(uint32_t
id,
const QString &uuid)
override
380 Q_EMIT windowCreated(
new PlasmaWindow(uuid, get_window_by_uuid(uuid)));
382 void org_kde_plasma_window_management_stacking_order_uuid_changed(
const QString &uuids)
override
384 Q_EMIT stackingOrderChanged(uuids.
split(QLatin1Char(
';')));
386 void org_kde_plasma_window_management_stacking_order_changed_2()
override;
387 void stackingOrderDone(
const QList<QString> &uuids)
389 Q_EMIT stackingOrderChanged(uuids);
390 m_pendingStackingOrder.reset();
393 void windowCreated(PlasmaWindow *window);
394 void stackingOrderChanged(
const QList<QString> &uuids);
397 std::unique_ptr<PlasmaStackingOrder> m_pendingStackingOrder;
400class PlasmaStackingOrder :
public QtWayland::org_kde_plasma_stacking_order
403 explicit PlasmaStackingOrder(PlasmaWindowManagement *windowManagement, ::org_kde_plasma_stacking_order *
id)
404 : QtWayland::org_kde_plasma_stacking_order(id)
405 , m_windowManagement(windowManagement)
408 ~PlasmaStackingOrder()
410 org_kde_plasma_stacking_order_destroy(
object());
413 void org_kde_plasma_stacking_order_window(
const QString &uuid)
override
415 m_uuids.push_back(uuid);
418 void org_kde_plasma_stacking_order_done()
override
420 m_windowManagement->stackingOrderDone(m_uuids);
423 PlasmaWindowManagement *
const m_windowManagement;
424 QList<QString> m_uuids;
427void PlasmaWindowManagement::org_kde_plasma_window_management_stacking_order_changed_2()
429 m_pendingStackingOrder.reset(
new PlasmaStackingOrder(
this, org_kde_plasma_window_management_get_stacking_order(
object())));
435 Private(WaylandTasksModel *q);
436 QHash<PlasmaWindow *, AppData> appDataCache;
437 QHash<PlasmaWindow *, QDateTime> lastActivated;
438 PlasmaWindow *activeWindow =
nullptr;
439 std::vector<std::unique_ptr<PlasmaWindow>> windows;
441 QHash<PlasmaWindow *, PlasmaWindow *> transients;
443 QMultiHash<PlasmaWindow *, PlasmaWindow *> transientsDemandingAttention;
444 std::unique_ptr<PlasmaWindowManagement> windowManagement;
445 KSharedConfig::Ptr rulesConfig;
446 KDirWatch *configWatcher =
nullptr;
447 VirtualDesktopInfo *virtualDesktopInfo =
nullptr;
449 QList<QString> stackingOrder;
453 auto findWindow(PlasmaWindow *window)
const;
454 void addWindow(PlasmaWindow *window);
456 const AppData &appData(PlasmaWindow *window);
458 QIcon icon(PlasmaWindow *window);
461 static QString groupMimeType();
463 void dataChanged(PlasmaWindow *window,
int role);
464 void dataChanged(PlasmaWindow *window,
const QList<int> &roles);
467 WaylandTasksModel *
const q;
477void WaylandTasksModel::Private::init()
479 auto clearCacheAndRefresh = [
this] {
480 if (windows.empty()) {
484 appDataCache.clear();
487 Q_EMIT q->dataChanged(q->index(0, 0),
488 q->index(windows.size() - 1, 0),
490 AbstractTasksModel::AppId,
491 AbstractTasksModel::AppName,
492 AbstractTasksModel::GenericName,
493 AbstractTasksModel::LauncherUrl,
494 AbstractTasksModel::LauncherUrlWithoutIcon,
495 AbstractTasksModel::CanLaunchNewInstance,
496 AbstractTasksModel::SkipTaskbar});
503 configWatcher->addFile(location +
QLatin1String(
"/taskmanagerrulesrc"));
506 auto rulesConfigChange = [
this, clearCacheAndRefresh] {
507 rulesConfig->reparseConfiguration();
508 clearCacheAndRefresh();
515 virtualDesktopInfo =
new VirtualDesktopInfo(q);
520void WaylandTasksModel::Private::initWayland()
526 windowManagement = std::make_unique<PlasmaWindowManagement>();
528 QObject::connect(windowManagement.get(), &PlasmaWindowManagement::activeChanged, q, [
this] {
529 q->beginResetModel();
534 QObject::connect(windowManagement.get(), &PlasmaWindowManagement::windowCreated, q, [
this](PlasmaWindow *window) {
535 connect(window, &PlasmaWindow::initialStateDone, q, [this, window] {
541 stackingOrder = order;
542 for (const auto &window : std::as_const(windows)) {
543 this->dataChanged(window.get(), StackingOrder);
548auto WaylandTasksModel::Private::findWindow(PlasmaWindow *window)
const
550 return std::find_if(windows.begin(), windows.end(), [window](
const std::unique_ptr<PlasmaWindow> &candidate) {
551 return candidate.get() == window;
555void WaylandTasksModel::Private::addWindow(PlasmaWindow *window)
557 if (findWindow(window) != windows.end()) {
561 auto removeWindow = [
window,
this] {
563 auto it = std::find_if(windows.begin(), windows.end(), [window](
const std::unique_ptr<PlasmaWindow> &candidate) {
564 return candidate.get() == window;
567 if (it != windows.end()) {
568 const int row = it - windows.begin();
574 const std::unique_ptr<PlasmaWindow> removedWindow = std::move(*it);
577 transientsDemandingAttention.remove(window);
578 appDataCache.remove(window);
579 lastActivated.remove(window);
582 if (transients.remove(window)) {
583 if (PlasmaWindow *leader = transientsDemandingAttention.key(window)) {
584 transientsDemandingAttention.remove(leader, window);
585 dataChanged(leader,
QList<int>{IsDemandingAttention});
590 if (activeWindow == window) {
591 activeWindow =
nullptr;
607 appDataCache.remove(window);
615 appDataCache.remove(window);
618 this->dataChanged(window,
623 PlasmaWindow *effectiveActive =
window;
624 while (effectiveActive->parentWindow) {
625 effectiveActive = effectiveActive->parentWindow;
629 activeWindow = effectiveActive;
635 PlasmaWindow *effectiveWindow =
window;
637 while (effectiveWindow->parentWindow) {
638 effectiveWindow = effectiveWindow->parentWindow;
644 if (activeWindow != effectiveWindow) {
645 activeWindow = effectiveWindow;
646 this->dataChanged(effectiveWindow, IsActive);
649 if (activeWindow == effectiveWindow) {
650 activeWindow =
nullptr;
651 this->dataChanged(effectiveWindow, IsActive);
656 QObject::connect(window, &PlasmaWindow::parentWindowChanged, q, [window,
this] {
657 PlasmaWindow *leader =
window->parentWindow.data();
660 if (
window->
windowState.testFlag(PlasmaWindow::state::state_demands_attention)) {
661 if (
auto *oldLeader = transientsDemandingAttention.key(window)) {
662 if (
window->parentWindow != oldLeader) {
663 transientsDemandingAttention.remove(oldLeader, window);
664 transientsDemandingAttention.insert(leader, window);
665 dataChanged(oldLeader,
QList<int>{IsDemandingAttention});
666 dataChanged(leader,
QList<int>{IsDemandingAttention});
671 if (transients.remove(window)) {
673 transients.insert(window, leader);
675 dataChanged(window, SkipTaskbar);
678 transients.insert(window, leader);
679 dataChanged(window, SkipTaskbar);
683 QObject::connect(window, &PlasmaWindow::closeableChanged, q, [window,
this] {
684 this->dataChanged(window, IsClosable);
688 this->dataChanged(window, IsMovable);
691 QObject::connect(window, &PlasmaWindow::resizableChanged, q, [window,
this] {
692 this->dataChanged(window, IsResizable);
695 QObject::connect(window, &PlasmaWindow::fullscreenableChanged, q, [window,
this] {
696 this->dataChanged(window, IsFullScreenable);
699 QObject::connect(window, &PlasmaWindow::fullscreenChanged, q, [window,
this] {
700 this->dataChanged(window, IsFullScreen);
703 QObject::connect(window, &PlasmaWindow::maximizeableChanged, q, [window,
this] {
704 this->dataChanged(window, IsMaximizable);
707 QObject::connect(window, &PlasmaWindow::maximizedChanged, q, [window,
this] {
708 this->dataChanged(window, IsMaximized);
711 QObject::connect(window, &PlasmaWindow::minimizeableChanged, q, [window,
this] {
712 this->dataChanged(window, IsMinimizable);
715 QObject::connect(window, &PlasmaWindow::minimizedChanged, q, [window,
this] {
716 this->dataChanged(window, IsMinimized);
719 QObject::connect(window, &PlasmaWindow::keepAboveChanged, q, [window,
this] {
720 this->dataChanged(window, IsKeepAbove);
723 QObject::connect(window, &PlasmaWindow::keepBelowChanged, q, [window,
this] {
724 this->dataChanged(window, IsKeepBelow);
727 QObject::connect(window, &PlasmaWindow::shadeableChanged, q, [window,
this] {
728 this->dataChanged(window, IsShadeable);
731 QObject::connect(window, &PlasmaWindow::canSetNoBorderChanged, q, [window,
this] {
732 this->dataChanged(window, CanSetNoBorder);
735 QObject::connect(window, &PlasmaWindow::hasNoBorderChanged, q, [window,
this] {
736 this->dataChanged(window, HasNoBorder);
739 QObject::connect(window, &PlasmaWindow::virtualDesktopChangeableChanged, q, [window,
this] {
740 this->dataChanged(window, IsVirtualDesktopsChangeable);
743 QObject::connect(window, &PlasmaWindow::virtualDesktopEntered, q, [window,
this] {
744 this->dataChanged(window, VirtualDesktops);
748 if (!
window->virtualDesktops.isEmpty()) {
749 this->dataChanged(window, IsOnAllVirtualDesktops);
753 QObject::connect(window, &PlasmaWindow::virtualDesktopLeft, q, [window,
this] {
754 this->dataChanged(window, VirtualDesktops);
757 if (
window->virtualDesktops.isEmpty()) {
758 this->dataChanged(window, IsOnAllVirtualDesktops);
762 QObject::connect(window, &PlasmaWindow::geometryChanged, q, [window,
this] {
763 this->dataChanged(window,
QList<int>{Geometry, ScreenGeometry});
766 QObject::connect(window, &PlasmaWindow::demandsAttentionChanged, q, [window,
this] {
768 if (
auto *leader = transients.value(window)) {
769 if (
window->
windowState.testFlag(PlasmaWindow::state::state_demands_attention)) {
770 if (!transientsDemandingAttention.values(leader).contains(window)) {
771 transientsDemandingAttention.insert(leader, window);
772 this->dataChanged(leader,
QList<int>{IsDemandingAttention});
774 }
else if (transientsDemandingAttention.remove(leader, window)) {
775 this->dataChanged(leader,
QList<int>{IsDemandingAttention});
778 this->dataChanged(window,
QList<int>{IsDemandingAttention});
782 QObject::connect(window, &PlasmaWindow::skipTaskbarChanged, q, [window,
this] {
783 this->dataChanged(window, SkipTaskbar);
786 QObject::connect(window, &PlasmaWindow::applicationMenuChanged, q, [window,
this] {
787 this->dataChanged(window,
QList<int>{ApplicationMenuServiceName, ApplicationMenuObjectPath});
790 QObject::connect(window, &PlasmaWindow::activitiesChanged, q, [window,
this] {
791 this->dataChanged(window, Activities);
795 if (PlasmaWindow *leader =
window->parentWindow.data()) {
796 transients.insert(window, leader);
799 if (
window->
windowState.testFlag(PlasmaWindow::state::state_demands_attention)) {
800 transientsDemandingAttention.insert(leader, window);
801 dataChanged(leader,
QList<int>{IsDemandingAttention});
805 const int count = windows.size();
809 windows.emplace_back(window);
814const AppData &WaylandTasksModel::Private::appData(PlasmaWindow *window)
816 static_assert(!std::is_trivially_copy_assignable_v<AppData>);
817 if (
auto it = appDataCache.constFind(window); it != appDataCache.constEnd()) {
821 return *appDataCache.emplace(window, appDataFromUrl(windowUrlFromMetadata(
window->appId,
window->pid, rulesConfig,
window->resourceName)));
824QIcon WaylandTasksModel::Private::icon(PlasmaWindow *window)
826 const AppData &app = appData(window);
828 if (!app.icon.isNull()) {
837QString WaylandTasksModel::Private::mimeType()
841 return u
"windowsystem/winid+" + uuid.toString();
844QString WaylandTasksModel::Private::groupMimeType()
848 return u
"windowsystem/multiple-winids+" + uuid.toString();
851void WaylandTasksModel::Private::dataChanged(PlasmaWindow *window,
int role)
853 auto it = findWindow(window);
854 if (it == windows.end()) {
858 Q_EMIT q->dataChanged(idx, idx,
QList<int>{role});
861void WaylandTasksModel::Private::dataChanged(PlasmaWindow *window,
const QList<int> &roles)
863 auto it = findWindow(window);
864 if (it == windows.end()) {
868 Q_EMIT q->dataChanged(idx, idx, roles);
871WaylandTasksModel::WaylandTasksModel(
QObject *parent)
872 : AbstractWindowTasksModel(parent)
873 , d(new Private(this))
878WaylandTasksModel::~WaylandTasksModel()
880 for (
auto &window : d->windows) {
888 if (!index.
isValid() ||
static_cast<size_t>(index.
row()) >= d->windows.size()) {
892 PlasmaWindow *
window = d->windows.at(index.
row()).get();
897 return d->icon(window);
898 }
else if (role == AppId) {
899 const QString &
id = d->appData(window).id;
906 }
else if (role == AppName) {
907 return d->appData(window).name;
908 }
else if (role == GenericName) {
909 return d->appData(window).genericName;
910 }
else if (role == LauncherUrl || role == LauncherUrlWithoutIcon) {
911 return d->appData(window).url;
912 }
else if (role == WinIdList) {
913 return QVariantList{
window->uuid};
914 }
else if (role == MimeType) {
915 return d->mimeType();
916 }
else if (role == MimeData) {
918 }
else if (role == IsWindow) {
920 }
else if (role == IsActive) {
921 return (window == d->activeWindow);
922 }
else if (role == IsClosable) {
924 }
else if (role == IsMovable) {
926 }
else if (role == IsResizable) {
928 }
else if (role == IsMaximizable) {
930 }
else if (role == IsMaximized) {
932 }
else if (role == IsMinimizable) {
934 }
else if (role == IsMinimized || role == IsHidden) {
936 }
else if (role == IsKeepAbove) {
938 }
else if (role == IsKeepBelow) {
940 }
else if (role == IsFullScreenable) {
942 }
else if (role == IsFullScreen) {
944 }
else if (role == IsShadeable) {
946 }
else if (role == IsShaded) {
948 }
else if (role == CanSetNoBorder) {
949 return window->
windowState.testFlag(PlasmaWindow::state::state_can_set_no_border);
950 }
else if (role == HasNoBorder) {
952 }
else if (role == IsVirtualDesktopsChangeable) {
953 return window->
windowState.testFlag(PlasmaWindow::state::state_virtual_desktop_changeable);
954 }
else if (role == VirtualDesktops) {
955 return window->virtualDesktops;
956 }
else if (role == IsOnAllVirtualDesktops) {
957 return window->virtualDesktops.isEmpty();
958 }
else if (role == Geometry) {
960 }
else if (role == ScreenGeometry) {
962 }
else if (role == Activities) {
963 return window->activities;
964 }
else if (role == IsDemandingAttention) {
965 return window->
windowState.testFlag(PlasmaWindow::state::state_demands_attention) || d->transientsDemandingAttention.contains(window);
966 }
else if (role == SkipTaskbar) {
967 return window->
windowState.testFlag(PlasmaWindow::state::state_skiptaskbar) || d->appData(window).skipTaskbar || d->transients.contains(window);
968 }
else if (role == SkipPager) {
970 }
else if (role == AppPid) {
972 }
else if (role == StackingOrder) {
973 return d->stackingOrder.indexOf(
window->uuid);
974 }
else if (role == LastActivated) {
975 if (d->lastActivated.contains(window)) {
976 return d->lastActivated.value(window);
978 }
else if (role == ApplicationMenuObjectPath) {
979 return window->applicationMenuObjectPath;
980 }
else if (role == ApplicationMenuServiceName) {
981 return window->applicationMenuService;
982 }
else if (role == CanLaunchNewInstance) {
983 return canLauchNewInstance(d->appData(window));
986 return AbstractTasksModel::data(index, role);
989int WaylandTasksModel::rowCount(
const QModelIndex &parent)
const
991 return parent.
isValid() ? 0 : d->windows.size();
996 return hasIndex(row, column, parent) ? createIndex(row, column, d->windows.at(row).get()) :
QModelIndex();
1001 if (!
checkIndex(index, QAbstractItemModel::CheckIndexOption::IndexIsValid | QAbstractItemModel::CheckIndexOption::DoNotUseParent)) {
1005 PlasmaWindow *window = d->windows.at(index.row()).get();
1008 if (
auto *transientDemandingAttention = d->transientsDemandingAttention.value(window)) {
1009 window = transientDemandingAttention;
1016 while (d->transients.key(window)) {
1017 window = d->transients.key(window);
1021 window->set_state(PlasmaWindow::state::state_active, PlasmaWindow::state::state_active);
1026 if (!
checkIndex(index, QAbstractItemModel::CheckIndexOption::IndexIsValid | QAbstractItemModel::CheckIndexOption::DoNotUseParent)) {
1030 runApp(d->appData(d->windows.at(index.row()).get()));
1035 if (!
checkIndex(index, QAbstractItemModel::CheckIndexOption::IndexIsValid | QAbstractItemModel::CheckIndexOption::DoNotUseParent) || urls.
isEmpty()) {
1039 runApp(d->appData(d->windows.at(index.row()).get()), urls);
1044 if (!
checkIndex(index, QAbstractItemModel::CheckIndexOption::IndexIsValid | QAbstractItemModel::CheckIndexOption::DoNotUseParent)) {
1048 d->windows.at(index.row())->close();
1053 if (!
checkIndex(index, QAbstractItemModel::CheckIndexOption::IndexIsValid | QAbstractItemModel::CheckIndexOption::DoNotUseParent)) {
1057 auto &window = d->windows.at(index.row());
1059 window->set_state(PlasmaWindow::state::state_active, PlasmaWindow::state::state_active);
1060 window->request_move();
1065 if (!
checkIndex(index, QAbstractItemModel::CheckIndexOption::IndexIsValid | QAbstractItemModel::CheckIndexOption::DoNotUseParent)) {
1069 auto &window = d->windows.at(index.row());
1071 window->set_state(PlasmaWindow::state::state_active, PlasmaWindow::state::state_active);
1072 window->request_resize();
1077 if (!
checkIndex(index, QAbstractItemModel::CheckIndexOption::IndexIsValid | QAbstractItemModel::CheckIndexOption::DoNotUseParent)) {
1081 auto &window = d->windows.at(index.row());
1083 if (window->
windowState & PlasmaWindow::state::state_minimized) {
1084 window->set_state(PlasmaWindow::state::state_minimized, 0);
1086 window->set_state(PlasmaWindow::state::state_minimized, PlasmaWindow::state::state_minimized);
1092 if (!
checkIndex(index, QAbstractItemModel::CheckIndexOption::IndexIsValid | QAbstractItemModel::CheckIndexOption::DoNotUseParent)) {
1096 auto &window = d->windows.at(index.row());
1098 if (window->
windowState & PlasmaWindow::state::state_maximized) {
1099 window->set_state(PlasmaWindow::state::state_maximized | PlasmaWindow::state::state_active, PlasmaWindow::state::state_active);
1101 window->set_state(PlasmaWindow::state::state_maximized | PlasmaWindow::state::state_active,
1102 PlasmaWindow::state::state_maximized | PlasmaWindow::state::state_active);
1108 if (!
checkIndex(index, QAbstractItemModel::CheckIndexOption::IndexIsValid | QAbstractItemModel::CheckIndexOption::DoNotUseParent)) {
1112 auto &window = d->windows.at(index.row());
1114 if (window->
windowState & PlasmaWindow::state::state_keep_above) {
1115 window->set_state(PlasmaWindow::state::state_keep_above, 0);
1117 window->set_state(PlasmaWindow::state::state_keep_above, PlasmaWindow::state::state_keep_above);
1123 if (!
checkIndex(index, QAbstractItemModel::CheckIndexOption::IndexIsValid | QAbstractItemModel::CheckIndexOption::DoNotUseParent)) {
1126 auto &window = d->windows.at(index.row());
1128 if (window->
windowState & PlasmaWindow::state::state_keep_below) {
1129 window->set_state(PlasmaWindow::state::state_keep_below, 0);
1131 window->set_state(PlasmaWindow::state::state_keep_below, PlasmaWindow::state::state_keep_below);
1137 if (!
checkIndex(index, QAbstractItemModel::CheckIndexOption::IndexIsValid | QAbstractItemModel::CheckIndexOption::DoNotUseParent)) {
1141 auto &window = d->windows.at(index.row());
1143 if (window->
windowState & PlasmaWindow::state::state_fullscreen) {
1144 window->set_state(PlasmaWindow::state::state_fullscreen, 0);
1146 window->set_state(PlasmaWindow::state::state_fullscreen, PlasmaWindow::state::state_fullscreen);
1152 if (!
checkIndex(index, QAbstractItemModel::CheckIndexOption::IndexIsValid | QAbstractItemModel::CheckIndexOption::DoNotUseParent)) {
1156 auto &window = d->windows.at(index.row());
1158 if (window->
windowState & PlasmaWindow::state::state_shaded) {
1159 window->set_state(PlasmaWindow::state::state_shaded, 0);
1161 window->set_state(PlasmaWindow::state::state_shaded, PlasmaWindow::state::state_shaded);
1167 if (!
checkIndex(index, QAbstractItemModel::CheckIndexOption::IndexIsValid | QAbstractItemModel::CheckIndexOption::DoNotUseParent)) {
1171 auto &window = d->windows.at(index.row());
1173 if (window->
windowState & PlasmaWindow::state::state_no_border) {
1174 window->set_state(PlasmaWindow::state::state_no_border, 0);
1176 window->set_state(PlasmaWindow::state::state_no_border, PlasmaWindow::state::state_no_border);
1186 if (!
checkIndex(index, QAbstractItemModel::CheckIndexOption::IndexIsValid | QAbstractItemModel::CheckIndexOption::DoNotUseParent)) {
1190 auto &window = d->windows.at(index.row());
1192 if (desktops.isEmpty()) {
1193 const QStringList virtualDesktops = window->virtualDesktops;
1194 for (
const QString &desktop : virtualDesktops) {
1195 window->request_leave_virtual_desktop(desktop);
1201 for (
const QVariant &desktop : desktops) {
1202 const QString &desktopId = desktop.toString();
1208 window->request_enter_virtual_desktop(desktopId);
1213 for (
const QString &desktop : now) {
1214 if (!next.contains(desktop)) {
1215 window->request_leave_virtual_desktop(desktop);
1223 if (!
checkIndex(index, QAbstractItemModel::CheckIndexOption::IndexIsValid | QAbstractItemModel::CheckIndexOption::DoNotUseParent)) {
1227 d->windows.at(index.row())->request_enter_new_virtual_desktop();
1232 if (!
checkIndex(index, QAbstractItemModel::CheckIndexOption::IndexIsValid | QAbstractItemModel::CheckIndexOption::DoNotUseParent)) {
1236 auto &window = d->windows.at(index.row());
1237 const auto newActivities =
QSet(activities.
begin(), activities.
end());
1238 const auto plasmaActivities = window->activities;
1239 const auto oldActivities =
QSet(plasmaActivities.begin(), plasmaActivities.end());
1241 const auto activitiesToAdd = newActivities - oldActivities;
1242 for (
const auto &activity : activitiesToAdd) {
1243 window->request_enter_activity(activity);
1246 const auto activitiesToRemove = oldActivities - newActivities;
1247 for (
const auto &activity : activitiesToRemove) {
1248 window->request_leave_activity(activity);
1264 if (!
checkIndex(index, QAbstractItemModel::CheckIndexOption::IndexIsValid | QAbstractItemModel::CheckIndexOption::DoNotUseParent)) {
1280 auto waylandWindow = itemWindow->nativeInterface<QNativeInterface::Private::QWaylandWindow>();
1282 if (!waylandWindow || !waylandWindow->surface()) {
1289 auto &window = d->windows.at(index.row());
1291 window->set_minimized_geometry(waylandWindow->surface(), rect.
x(), rect.
y(), rect.
width(), rect.
height());
1302 if (!
mimeData->hasFormat(Private::mimeType())) {
1321 if (!
mimeData->hasFormat(Private::groupMimeType())) {
1346#include "waylandtasksmodel.moc"
1348#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...
void requestToggleNoBorder(const QModelIndex &index) override
Request toggling the no border state of the task at given index.
KCALUTILS_EXPORT QString mimeType()
void init(KXmlGuiWindow *window, KGameDifficulty *difficulty=nullptr)
QVariant read(const QByteArray &data, int versionOverride=0)
void initialize(StandardShortcut id)
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)