/* SPDX-FileCopyrightText: 2012-2016 Eike Hein SPDX-FileCopyrightText: 2020 Nate Graham SPDX-License-Identifier: GPL-2.0-or-later */ .pragma library .import org.kde.taskmanager as TaskManager .import org.kde.plasma.core as PlasmaCore // Needed by TaskManager // Can't be `let`, or else QML counterpart won't be able to assign to it. var taskManagerInstanceCount = 0; function activateNextPrevTask(anchor, next, wheelSkipMinimized, wheelEnabled, tasks) { // FIXME TODO: Unnecessarily convoluted and costly; optimize. if (wheelEnabled === 2) { // TaskOnly // anchor can be undefined if scrolling on an empty area if (!anchor) return; // Get the number of open windows for the application const anchorModelIndex = anchor.modelIndex(anchor.index); const winIdList = tasks.tasksModel.data(anchorModelIndex, TaskManager.AbstractTasksModel.WinIdList); const windowCount = winIdList ? winIdList.length : 0; // No windows if (windowCount === 0) { return; } // Single window if (windowCount === 1) { const isHidden = tasks.tasksModel.data(anchorModelIndex, TaskManager.AbstractTasksModel.IsHidden); if (!wheelSkipMinimized || !isHidden) { tasks.tasksModel.requestActivate(anchorModelIndex); } return; } } // Multiple windows let taskIndexList = []; const activeTaskIndex = tasks.tasksModel.activeTask; for (let i = 0; i < tasks.taskList.children.length - 1; ++i) { const task = tasks.taskList.children[i]; const modelIndex = task.modelIndex(i); if (!task.model.IsLauncher && !task.model.IsStartup) { if (task.model.IsGroupParent) { if (wheelEnabled === 2 && task === anchor) { // If TaskOnly mode and the anchor is a group parent, collect only windows within the group. taskIndexList = []; } for (let j = 0; j < tasks.tasksModel.rowCount(modelIndex); ++j) { const childModelIndex = tasks.tasksModel.makeModelIndex(i, j); const childHidden = tasks.tasksModel.data(childModelIndex, TaskManager.AbstractTasksModel.IsHidden); if (!wheelSkipMinimized || !childHidden) { taskIndexList.push(childModelIndex); } } if (wheelEnabled === 2 && task === anchor) { // If TaskOnly mode, break after processing the anchor group. break; } } else { if (!wheelSkipMinimized || !task.model.IsHidden) { taskIndexList.push(modelIndex); } } } } if (!taskIndexList.length) { return; } let target = taskIndexList[0]; for (let i = 0; i < taskIndexList.length; ++i) { if (taskIndexList[i] === activeTaskIndex) { if (next && i < (taskIndexList.length - 1)) { target = taskIndexList[i + 1]; } else if (!next) { if (i) { target = taskIndexList[i - 1]; } else { target = taskIndexList[taskIndexList.length - 1]; } } break; } } tasks.tasksModel.requestActivate(target); } // Get the model index of the task with the maximum value for `attribute`, // or `undefined` if the attribute is undefined for all tasks in the group (for instance LastActivated may be undefined) function groupTopTask(childTaskList, attribute, tasks) { let topAttribute = -1; let topTaskIndex = undefined; for (let task = 0; task < childTaskList.length; ++task) { const childTaskModelIndex = childTaskList[task]; const taskAttribute = tasks.tasksModel.data(childTaskModelIndex, attribute); if (taskAttribute !== undefined && taskAttribute > topAttribute) { topAttribute = taskAttribute; topTaskIndex = childTaskModelIndex; } } return topTaskIndex; } function activateTask(index, model, modifiers, task, plasmoid, tasks, windowViewAvailable) { if (modifiers & Qt.ShiftModifier) { tasks.tasksModel.requestNewInstance(index); return; } // Publish delegate geometry again if there are more than one task manager instance if (taskManagerInstanceCount >= 2) { tasks.tasksModel.requestPublishDelegateGeometry(task.modelIndex(), tasks.backend.globalRect(task), task); } if (model.IsGroupParent) { // Option 1 (default): Cycle through this group's tasks // ==================================================== // If the grouped task does not include the currently active task, bring // forward the most recently used task in the group. // Otherwise cycle through all tasks in the group without paying attention // to the last activation time, which otherwise would change with every click if (plasmoid.configuration.groupedTaskVisualization === 0) { let childTaskList = []; for (let i = 0; i < tasks.tasksModel.rowCount(task.modelIndex(index)); ++i) { const childTaskModelIndex = tasks.tasksModel.makeModelIndex(task.index, i); childTaskList.push(childTaskModelIndex); } // If the active task is already among in the group that was // activated, cycle through all tasks according to the order of // the immutable model index so the order doesn't change with // every click. if (childTaskList.some(index => tasks.tasksModel.data(index, TaskManager.AbstractTasksModel.IsActive))) { for (let j = 0; j < childTaskList.length; ++j) { const childTask = childTaskList[j]; if (tasks.tasksModel.data(childTask, TaskManager.AbstractTasksModel.IsActive)) { // Found the current task. Activate the next one let nextTask = j + 1; if (nextTask >= childTaskList.length) { nextTask = 0; } tasks.tasksModel.requestActivate(childTaskList[nextTask]); break; } } } else { // If the active task is from a different app from the group that // was clicked on switch to the last-used task from that app. let topTaskIndex = groupTopTask(childTaskList, TaskManager.AbstractTasksModel.LastActivated, tasks); // If no task in the group was ever active, the LastActivated property is not set on any task // -> default to the stacking order if (topTaskIndex === undefined) { topTaskIndex = groupTopTask(childTaskList, TaskManager.AbstractTasksModel.StackingOrder, tasks) } tasks.tasksModel.requestActivate(topTaskIndex); } } // Option 2: show tooltips for all child tasks // =========================================== else if (plasmoid.configuration.groupedTaskVisualization === 1) { if (tasks.toolTipOpenedByClick) { task.hideImmediately(); } else { tasks.toolTipOpenedByClick = task; task.updateMainItemBindings(); // BUG 452187 task.showToolTip(); } } // Option 3: show Window View for all child tasks // ================================================== // Make sure the Window View effect is are actually enabled though; // if not, fall through to the next option. else if (plasmoid.configuration.groupedTaskVisualization === 2 && windowViewAvailable) { task.hideToolTip(); tasks.activateWindowView(model.WinIdList); } // Option 4: show group dialog/textual list // ======================================== // This is also the final fallback option if Window View // is chosen but not actually available else { if (tasks.groupDialog) { task.hideToolTip(); tasks.groupDialog.visible = false; } else { createGroupDialog(task, tasks); } } } else { if (model.IsMinimized) { tasks.tasksModel.requestToggleMinimized(index); tasks.tasksModel.requestActivate(index); } else if (model.IsActive && plasmoid.configuration.minimizeActiveTaskOnClick) { tasks.tasksModel.requestToggleMinimized(index); } else { tasks.tasksModel.requestActivate(index); } } } function taskPrefix(prefix, location) { let effectivePrefix; switch (location) { case PlasmaCore.Types.LeftEdge: effectivePrefix = "west-" + prefix; break; case PlasmaCore.Types.TopEdge: effectivePrefix = "north-" + prefix; break; case PlasmaCore.Types.RightEdge: effectivePrefix = "east-" + prefix; break; default: effectivePrefix = "south-" + prefix; } return [effectivePrefix, prefix]; } function taskPrefixHovered(prefix, location) { return [ ...taskPrefix((prefix || "launcher") + "-hover", location), ...prefix ? taskPrefix("hover", location) : [], ...taskPrefix(prefix, location), ]; } function createGroupDialog(visualParent, tasks) { if (!visualParent) { return; } if (tasks.groupDialog) { tasks.groupDialog.visualParent = visualParent; return; } tasks.groupDialog = tasks.groupDialogComponent.createObject(tasks, { visualParent }); } function foreachChildTask(callback, modelIndex, tasksModel) { const childCount = tasksModel.rowCount(modelIndex); if (childCount > 0) { for (let i = 0; i < childCount; ++i) { const childIndex = tasksModel.index(i, 0, modelIndex); callback(childIndex); } } else { callback(modelIndex); } }