2022-04-24 14:52:13 +08:00
|
|
|
/*
|
2022-05-15 12:10:42 +08:00
|
|
|
* Copyright (C) 2021 ~ 2022 Deepin Technology Co., Ltd.
|
2022-04-24 14:52:13 +08:00
|
|
|
*
|
|
|
|
* Author: weizhixiang <weizhixiang@uniontech.com>
|
|
|
|
*
|
|
|
|
* Maintainer: weizhixiang <weizhixiang@uniontech.com>
|
|
|
|
*
|
|
|
|
* This program is free software: you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
|
|
* any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "entry.h"
|
|
|
|
#include "dock.h"
|
|
|
|
#include "processinfo.h"
|
|
|
|
#include "dbusadaptorentry.h"
|
2022-05-24 21:49:47 +08:00
|
|
|
#include "xcbutils.h"
|
2022-04-24 14:52:13 +08:00
|
|
|
|
|
|
|
#include <QDebug>
|
|
|
|
#include <QDBusInterface>
|
|
|
|
|
2022-05-24 21:49:47 +08:00
|
|
|
#include <signal.h>
|
|
|
|
|
|
|
|
#define XCB XCBUtils::instance()
|
2022-04-24 14:52:13 +08:00
|
|
|
|
|
|
|
Entry::Entry(Dock *_dock, AppInfo *_app, QString _innerId, QObject *parent)
|
2022-05-26 18:10:53 +08:00
|
|
|
: QObject(parent)
|
|
|
|
, dock(_dock)
|
|
|
|
, app(nullptr)
|
|
|
|
, menu(nullptr)
|
|
|
|
, isActive(false)
|
|
|
|
, isDocked(false)
|
|
|
|
, innerId(_innerId)
|
|
|
|
, current(nullptr)
|
|
|
|
, currentWindow(0)
|
|
|
|
, winIconPreferred(false)
|
2022-04-24 14:52:13 +08:00
|
|
|
{
|
|
|
|
setApp(_app);
|
|
|
|
id = dock->allocEntryId();
|
|
|
|
name = getName();
|
|
|
|
icon = getIcon();
|
|
|
|
}
|
|
|
|
|
|
|
|
Entry::~Entry()
|
|
|
|
{
|
2022-05-31 17:20:39 +08:00
|
|
|
for (auto winInfo : windowInfoMap) {
|
2022-04-24 14:52:13 +08:00
|
|
|
if (winInfo)
|
|
|
|
delete winInfo;
|
|
|
|
}
|
2022-05-31 17:20:39 +08:00
|
|
|
windowInfoMap.clear();
|
2022-04-24 14:52:13 +08:00
|
|
|
|
|
|
|
if (app) {
|
|
|
|
delete app;
|
|
|
|
app = nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (menu) {
|
|
|
|
delete menu;
|
|
|
|
menu = nullptr;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Entry::isValid()
|
|
|
|
{
|
2022-05-31 20:37:01 +08:00
|
|
|
return app ? app->isValidApp() : false;
|
2022-04-24 14:52:13 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
QString Entry::getId()
|
|
|
|
{
|
|
|
|
return id;
|
|
|
|
}
|
|
|
|
|
|
|
|
QString Entry::getName()
|
|
|
|
{
|
|
|
|
QString ret;
|
2022-05-31 20:37:01 +08:00
|
|
|
if (app) {
|
2022-04-24 14:52:13 +08:00
|
|
|
ret = app->getName();
|
2022-05-31 20:37:01 +08:00
|
|
|
}
|
2022-04-24 14:52:13 +08:00
|
|
|
|
2022-05-31 20:37:01 +08:00
|
|
|
if (ret.isEmpty() && !!current) {
|
2022-04-24 14:52:13 +08:00
|
|
|
ret = current->getDisplayName();
|
2022-05-31 20:37:01 +08:00
|
|
|
}
|
2022-04-24 14:52:13 +08:00
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Entry::updateName()
|
|
|
|
{
|
|
|
|
setPropName(getName());
|
|
|
|
}
|
|
|
|
|
|
|
|
QString Entry::getIcon()
|
|
|
|
{
|
|
|
|
QString ret;
|
|
|
|
if (hasWindow()) {
|
2022-05-31 20:37:01 +08:00
|
|
|
if (!current) {
|
2022-04-24 14:52:13 +08:00
|
|
|
return ret;
|
2022-05-31 20:37:01 +08:00
|
|
|
}
|
2022-04-24 14:52:13 +08:00
|
|
|
|
|
|
|
// has window && current not nullptr
|
|
|
|
if (winIconPreferred) {
|
|
|
|
// try current window icon first
|
|
|
|
ret = current->getIcon();
|
2022-05-31 20:37:01 +08:00
|
|
|
if (ret.size() > 0) {
|
2022-04-24 14:52:13 +08:00
|
|
|
return ret;
|
2022-05-31 20:37:01 +08:00
|
|
|
}
|
2022-04-24 14:52:13 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
if (app) {
|
|
|
|
icon = app->getIcon();
|
2022-05-31 20:37:01 +08:00
|
|
|
if (icon.size() > 0) {
|
2022-05-24 21:49:47 +08:00
|
|
|
return icon;
|
2022-05-31 20:37:01 +08:00
|
|
|
}
|
2022-04-24 14:52:13 +08:00
|
|
|
}
|
2022-05-31 20:37:01 +08:00
|
|
|
|
2022-05-24 21:49:47 +08:00
|
|
|
return current->getIcon();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (app) {
|
2022-04-24 14:52:13 +08:00
|
|
|
// no window
|
2022-05-24 21:49:47 +08:00
|
|
|
return app->getIcon();
|
2022-04-24 14:52:13 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
QString Entry::getInnerId()
|
|
|
|
{
|
|
|
|
return innerId;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Entry::setInnerId(QString _innerId)
|
|
|
|
{
|
|
|
|
innerId = _innerId;
|
|
|
|
}
|
|
|
|
|
|
|
|
QString Entry::getFileName()
|
|
|
|
{
|
2022-05-31 20:37:01 +08:00
|
|
|
return app ? app->getFileName() : QString();
|
2022-04-24 14:52:13 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
AppInfo *Entry::getApp()
|
|
|
|
{
|
|
|
|
return app;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Entry::setApp(AppInfo *appinfo)
|
|
|
|
{
|
2022-05-31 20:37:01 +08:00
|
|
|
if (app == appinfo) {
|
2022-04-24 14:52:13 +08:00
|
|
|
return;
|
2022-05-31 20:37:01 +08:00
|
|
|
}
|
2022-04-24 14:52:13 +08:00
|
|
|
|
2022-05-31 20:37:01 +08:00
|
|
|
if (app) {
|
2022-04-24 14:52:13 +08:00
|
|
|
delete app;
|
2022-05-31 20:37:01 +08:00
|
|
|
}
|
2022-04-24 14:52:13 +08:00
|
|
|
|
|
|
|
app = appinfo;
|
|
|
|
if (!appinfo) {
|
|
|
|
winIconPreferred = true;
|
|
|
|
setPropDesktopFile("");
|
|
|
|
} else {
|
|
|
|
winIconPreferred = false;
|
|
|
|
setPropDesktopFile(appinfo->getFileName());
|
|
|
|
QString id = app->getId();
|
|
|
|
auto perferredApps = dock->getWinIconPreferredApps();
|
|
|
|
if (perferredApps.contains(id)) {
|
|
|
|
winIconPreferred = true;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (appinfo->getIcon().size() == 0) {
|
|
|
|
winIconPreferred = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Entry::getIsDocked()
|
|
|
|
{
|
|
|
|
return isDocked;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Entry::setIsDocked(bool value)
|
|
|
|
{
|
|
|
|
if (value != isDocked) {
|
|
|
|
isDocked = value;
|
|
|
|
Q_EMIT isDockedChanged(value);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-05-31 17:20:39 +08:00
|
|
|
// 导出DBus服务
|
2022-04-24 14:52:13 +08:00
|
|
|
void Entry::startExport()
|
|
|
|
{
|
|
|
|
if (getId().isEmpty()) {
|
|
|
|
qWarning() << "startExport Entry " << getName() << " id is Empty";
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
new DBusAdaptorEntry(this); // export dbus by Adaptor
|
|
|
|
QDBusConnection con = QDBusConnection::sessionBus();
|
|
|
|
if (!con.registerService(dbusService)) {
|
|
|
|
qWarning() << "register service Dock1 error:" << con.lastError().message();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
objctPath = entryDBusObjPathPrefix + getId();
|
2022-05-31 20:37:01 +08:00
|
|
|
if (!con.registerObject(objctPath, this)) {
|
2022-04-24 14:52:13 +08:00
|
|
|
qWarning() << "register object Dock1 error:" << con.lastError().message();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-05-31 17:20:39 +08:00
|
|
|
// 停止导出DBus服务
|
2022-04-24 14:52:13 +08:00
|
|
|
void Entry::stopExport()
|
|
|
|
{
|
|
|
|
if (getId().isEmpty()) {
|
|
|
|
qWarning() << "stopExport Entry " << getName() << " id is Empty";
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
QDBusConnection con = QDBusConnection::sessionBus();
|
|
|
|
objctPath.clear();
|
|
|
|
con.unregisterObject(entryDBusObjPathPrefix + getId());
|
|
|
|
}
|
|
|
|
|
|
|
|
void Entry::setMenu(AppMenu *_menu)
|
|
|
|
{
|
|
|
|
_menu->setDirtyStatus(true);
|
|
|
|
if (menu)
|
|
|
|
delete menu;
|
|
|
|
|
|
|
|
menu = _menu;
|
|
|
|
Q_EMIT menuChanged(menu->getMenuJsonStr());
|
|
|
|
}
|
|
|
|
|
|
|
|
void Entry::updateMenu()
|
|
|
|
{
|
|
|
|
qInfo() <<"Entry: updateMenu";
|
|
|
|
AppMenu *appMenu = new AppMenu();
|
|
|
|
appMenu->appendItem(getMenuItemLaunch());
|
|
|
|
|
|
|
|
for (auto &item :getMenuItemDesktopActions())
|
|
|
|
appMenu->appendItem(item);
|
|
|
|
|
2022-05-31 20:37:01 +08:00
|
|
|
if (hasWindow())
|
2022-04-24 14:52:13 +08:00
|
|
|
appMenu->appendItem(getMenuItemAllWindows());
|
|
|
|
|
|
|
|
// menu item dock or undock
|
|
|
|
qInfo() << "entry " << id << " docked? " << isDocked;
|
|
|
|
if (isDocked)
|
|
|
|
appMenu->appendItem(getMenuItemUndock());
|
|
|
|
else
|
|
|
|
appMenu->appendItem(getMenuItemDock());
|
|
|
|
|
|
|
|
if (hasWindow()) {
|
|
|
|
if (dock->getForceQuitAppStatus() != ForceQuitAppMode::Disabled) {
|
|
|
|
if (app && app->getIdentifyMethod() == "Andriod")
|
|
|
|
appMenu->appendItem(getMenuItemForceQuitAndroid());
|
|
|
|
else
|
|
|
|
appMenu->appendItem(getMenuItemForceQuit());
|
|
|
|
}
|
|
|
|
|
|
|
|
if (getAllowedCloseWindows().size() > 0)
|
|
|
|
appMenu->appendItem(getMenuItemCloseAll());
|
|
|
|
}
|
2022-05-31 20:37:01 +08:00
|
|
|
|
2022-04-24 14:52:13 +08:00
|
|
|
setMenu(appMenu);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Entry::updateIcon()
|
|
|
|
{
|
|
|
|
setPropIcon(getIcon());
|
|
|
|
}
|
|
|
|
|
|
|
|
void Entry::forceUpdateIcon()
|
|
|
|
{
|
|
|
|
icon = getIcon();
|
|
|
|
Q_EMIT iconChanged(icon);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Entry::updateIsActive()
|
|
|
|
{
|
|
|
|
bool isActive = false;
|
|
|
|
auto activeWin = dock->getActiveWindow();
|
2022-05-31 17:20:39 +08:00
|
|
|
if (activeWin) {
|
|
|
|
// 判断活跃窗口是否属于当前应用
|
|
|
|
isActive = windowInfoMap.find(activeWin->getXid()) != windowInfoMap.end();
|
|
|
|
}
|
2022-04-24 14:52:13 +08:00
|
|
|
|
|
|
|
setPropIsActive(isActive);
|
|
|
|
}
|
|
|
|
|
|
|
|
WindowInfoBase *Entry::getWindowInfoByPid(int pid)
|
|
|
|
{
|
2022-05-31 17:20:39 +08:00
|
|
|
for (const auto &windowInfo : windowInfoMap) {
|
2022-05-31 20:37:01 +08:00
|
|
|
if (windowInfo->getPid() == pid)
|
|
|
|
return windowInfo;
|
2022-04-24 14:52:13 +08:00
|
|
|
}
|
|
|
|
|
2022-05-31 20:37:01 +08:00
|
|
|
return nullptr;
|
2022-04-24 14:52:13 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
WindowInfoBase *Entry::getWindowInfoByWinId(XWindow windowId)
|
|
|
|
{
|
2022-05-31 20:37:01 +08:00
|
|
|
if (windowInfoMap.find(windowId) != windowInfoMap.end())
|
|
|
|
return windowInfoMap[windowId];
|
2022-04-24 14:52:13 +08:00
|
|
|
|
2022-05-31 20:37:01 +08:00
|
|
|
return nullptr;
|
2022-04-24 14:52:13 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void Entry::setPropIsDocked(bool docked)
|
|
|
|
{
|
|
|
|
if (isDocked != docked) {
|
|
|
|
isDocked = docked;
|
|
|
|
Q_EMIT isDockedChanged(docked);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Entry::setPropIcon(QString value)
|
|
|
|
{
|
|
|
|
if (value != icon) {
|
|
|
|
icon = value;
|
|
|
|
Q_EMIT iconChanged(value);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Entry::setPropName(QString value)
|
|
|
|
{
|
|
|
|
if (value != name) {
|
|
|
|
name = value;
|
|
|
|
Q_EMIT nameChanged(value);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Entry::setPropIsActive(bool active)
|
|
|
|
{
|
|
|
|
if (isActive != active) {
|
|
|
|
isActive = active;
|
|
|
|
Q_EMIT isActiveChanged(active);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Entry::setCurrentWindowInfo(WindowInfoBase *windowInfo)
|
|
|
|
{
|
|
|
|
current = windowInfo;
|
|
|
|
setPropCurrentWindow(current ? current->getXid() : 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Entry::setPropCurrentWindow(XWindow value)
|
|
|
|
{
|
|
|
|
if (value != currentWindow) {
|
|
|
|
currentWindow = value;
|
|
|
|
Q_EMIT currentWindowChanged(value);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
WindowInfoBase *Entry::getCurrentWindowInfo()
|
|
|
|
{
|
|
|
|
return current;
|
|
|
|
}
|
|
|
|
|
2022-05-24 21:49:47 +08:00
|
|
|
/**
|
|
|
|
* @brief Entry::findNextLeader
|
|
|
|
* @return
|
|
|
|
*/
|
|
|
|
WindowInfoBase *Entry::findNextLeader()
|
|
|
|
{
|
2022-05-31 17:20:39 +08:00
|
|
|
auto xids = windowInfoMap.keys();
|
2022-05-24 21:49:47 +08:00
|
|
|
qSort(xids);
|
|
|
|
XWindow curWinId = current->getXid();
|
|
|
|
int index = xids.indexOf(curWinId);
|
|
|
|
if (index < 0)
|
|
|
|
return nullptr;
|
|
|
|
|
|
|
|
// 如果当前窗口是最大, 返回xids[0], 否则返回xids[index + 1]
|
|
|
|
int nextIndex = 0;
|
|
|
|
if (index < xids.size() - 1)
|
|
|
|
nextIndex = index + 1;
|
|
|
|
|
2022-05-31 17:20:39 +08:00
|
|
|
return windowInfoMap[xids[nextIndex]];
|
2022-05-24 21:49:47 +08:00
|
|
|
}
|
|
|
|
|
2022-04-24 14:52:13 +08:00
|
|
|
QString Entry::getExec(bool oneLine)
|
|
|
|
{
|
|
|
|
if (!current)
|
2022-05-24 21:49:47 +08:00
|
|
|
return "";
|
2022-04-24 14:52:13 +08:00
|
|
|
|
|
|
|
ProcessInfo *process = current->getProcess();
|
|
|
|
if (process) {
|
|
|
|
if (oneLine)
|
2022-05-24 21:49:47 +08:00
|
|
|
return process->getOneCommandLine().c_str();
|
2022-05-31 20:37:01 +08:00
|
|
|
|
|
|
|
return process->getShellScriptLines().c_str();
|
2022-04-24 14:52:13 +08:00
|
|
|
}
|
|
|
|
|
2022-05-24 21:49:47 +08:00
|
|
|
return "";
|
2022-04-24 14:52:13 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
bool Entry::hasWindow()
|
|
|
|
{
|
2022-05-31 17:20:39 +08:00
|
|
|
return windowInfoMap.size() > 0;
|
2022-04-24 14:52:13 +08:00
|
|
|
}
|
|
|
|
|
2022-05-26 18:10:53 +08:00
|
|
|
/**
|
|
|
|
* @brief Entry::updateExportWindowInfos 同步更新导出窗口信息
|
|
|
|
*/
|
|
|
|
void Entry::updateExportWindowInfos()
|
2022-04-24 14:52:13 +08:00
|
|
|
{
|
2022-05-31 17:20:39 +08:00
|
|
|
WindowInfoMap infos;
|
|
|
|
for (auto info : windowInfoMap) {
|
|
|
|
WindowInfo winInfo;
|
2022-04-24 14:52:13 +08:00
|
|
|
XWindow xid = info->getXid();
|
2022-05-31 17:20:39 +08:00
|
|
|
winInfo.title = info->getTitle();
|
|
|
|
winInfo.attention = info->isDemandingAttention();
|
|
|
|
infos[xid] = winInfo;
|
2022-05-26 18:10:53 +08:00
|
|
|
}
|
|
|
|
|
2022-05-31 20:37:01 +08:00
|
|
|
bool changed = true;
|
2022-05-26 18:10:53 +08:00
|
|
|
if (infos.size() == exportWindowInfos.size()) {
|
2022-05-31 20:37:01 +08:00
|
|
|
changed = false;
|
2022-05-31 17:20:39 +08:00
|
|
|
for (auto iter = infos.begin(); iter != infos.end(); iter++) {
|
|
|
|
XWindow xid = iter.key();
|
|
|
|
if (infos[xid].title != exportWindowInfos[xid].title ||
|
|
|
|
infos[xid].attention != exportWindowInfos[xid].attention) {
|
2022-05-26 18:10:53 +08:00
|
|
|
changed = true;
|
|
|
|
break;
|
2022-04-24 14:52:13 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (changed) {
|
2022-05-26 18:10:53 +08:00
|
|
|
Q_EMIT windowInfosChanged(infos);
|
2022-04-24 14:52:13 +08:00
|
|
|
}
|
2022-05-26 18:10:53 +08:00
|
|
|
|
|
|
|
exportWindowInfos = infos;
|
2022-04-24 14:52:13 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// 分离窗口, 返回是否需要从任务栏remove
|
|
|
|
bool Entry::detachWindow(WindowInfoBase *info)
|
|
|
|
{
|
|
|
|
info->setEntry(nullptr);
|
|
|
|
XWindow winId = info->getXid();
|
|
|
|
deleteWindow(winId);
|
|
|
|
|
2022-05-31 20:37:01 +08:00
|
|
|
if (windowInfoMap.isEmpty()) {
|
|
|
|
if (!isDocked) {
|
|
|
|
// 既无窗口也非驻留应用,无需在任务栏显示
|
2022-04-24 14:52:13 +08:00
|
|
|
return true;
|
2022-05-31 20:37:01 +08:00
|
|
|
}
|
2022-04-24 14:52:13 +08:00
|
|
|
|
|
|
|
setCurrentWindowInfo(nullptr);
|
|
|
|
} else {
|
2022-05-31 17:20:39 +08:00
|
|
|
for (auto window : windowInfoMap) {
|
2022-04-24 14:52:13 +08:00
|
|
|
if (window) { // 选择第一个窗口作为当前窗口
|
|
|
|
setCurrentWindowInfo(window);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-05-26 18:10:53 +08:00
|
|
|
updateExportWindowInfos();
|
2022-04-24 14:52:13 +08:00
|
|
|
updateIcon();
|
|
|
|
updateIsActive();
|
|
|
|
updateMenu();
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Entry::attachWindow(WindowInfoBase *info)
|
|
|
|
{
|
|
|
|
XWindow winId = info->getXid();
|
|
|
|
qInfo() << "attatchWindow: window id:" << winId;
|
|
|
|
info->setEntry(this);
|
|
|
|
|
2022-05-31 17:20:39 +08:00
|
|
|
if (windowInfoMap.find(winId) != windowInfoMap.end()) {
|
2022-04-24 14:52:13 +08:00
|
|
|
qInfo() << "attachWindow: window " << winId << " is already attached";
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2022-05-31 17:20:39 +08:00
|
|
|
windowInfoMap[winId] = info;
|
2022-05-26 18:10:53 +08:00
|
|
|
updateExportWindowInfos();
|
2022-04-24 14:52:13 +08:00
|
|
|
updateIsActive();
|
|
|
|
|
|
|
|
if (!current) {
|
|
|
|
// from no window to has window
|
|
|
|
setCurrentWindowInfo(info);
|
|
|
|
}
|
|
|
|
|
|
|
|
updateIcon();
|
|
|
|
updateMenu();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Entry::launchApp(uint32_t timestamp)
|
|
|
|
{
|
2022-05-24 21:49:47 +08:00
|
|
|
dock->launchApp(app->getFileName(), timestamp, QStringList());
|
2022-04-24 14:52:13 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
bool Entry::containsWindow(XWindow xid)
|
|
|
|
{
|
2022-05-31 17:20:39 +08:00
|
|
|
return windowInfoMap.find(xid) != windowInfoMap.end();
|
2022-04-24 14:52:13 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void Entry::deleteWindow(XWindow xid)
|
2022-05-31 20:37:01 +08:00
|
|
|
{
|
|
|
|
if (windowInfoMap.contains(xid)) {
|
|
|
|
WindowInfoBase *info = windowInfoMap[xid];
|
|
|
|
windowInfoMap.remove(xid);
|
|
|
|
exportWindowInfos.remove(xid);
|
2022-04-24 14:52:13 +08:00
|
|
|
delete info;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// 处理菜单项
|
|
|
|
void Entry::handleMenuItem(uint32_t timestamp, QString itemId)
|
|
|
|
{
|
|
|
|
menu->handleAction(timestamp, itemId);
|
|
|
|
}
|
|
|
|
|
|
|
|
// 处理拖拽事件
|
|
|
|
void Entry::handleDragDrop(uint32_t timestamp, QStringList files)
|
|
|
|
{
|
2022-05-24 21:49:47 +08:00
|
|
|
dock->launchApp(app->getFileName(), timestamp, files);
|
2022-04-24 14:52:13 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// 驻留
|
|
|
|
void Entry::requestDock()
|
|
|
|
{
|
|
|
|
if (dock->dockEntry(this)) {
|
|
|
|
dock->saveDockedApps();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// 取消驻留
|
|
|
|
void Entry::requestUndock()
|
|
|
|
{
|
|
|
|
dock->undockEntry(this);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Entry::newInstance(uint32_t timestamp)
|
|
|
|
{
|
|
|
|
QStringList files;
|
2022-05-24 21:49:47 +08:00
|
|
|
dock->launchApp(app->getFileName(), timestamp, files);
|
2022-04-24 14:52:13 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// 检查应用窗口分离、合并状态
|
|
|
|
void Entry::check()
|
|
|
|
{
|
2022-05-31 17:20:39 +08:00
|
|
|
for (auto iter = windowInfoMap.begin(); iter != windowInfoMap.end(); iter++) {
|
2022-04-24 14:52:13 +08:00
|
|
|
dock->attachOrDetachWindow(iter.value());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// 强制退出
|
|
|
|
void Entry::forceQuit()
|
|
|
|
{
|
|
|
|
QMap<int, QVector<WindowInfoBase*>> pidWinInfoMap;
|
2022-05-31 17:20:39 +08:00
|
|
|
for (auto iter = windowInfoMap.begin(); iter != windowInfoMap.end(); iter++) {
|
2022-04-24 14:52:13 +08:00
|
|
|
int pid = iter.value()->getPid();
|
|
|
|
if (pid != 0) {
|
|
|
|
pidWinInfoMap[pid].push_back(iter.value());
|
|
|
|
} else {
|
|
|
|
iter.value()->killClient();
|
|
|
|
}
|
2022-05-31 17:20:39 +08:00
|
|
|
}
|
2022-04-24 14:52:13 +08:00
|
|
|
|
2022-05-31 17:20:39 +08:00
|
|
|
for (auto iter = pidWinInfoMap.begin(); iter != pidWinInfoMap.end(); iter++) {
|
|
|
|
if (!killProcess(iter.key())) { // kill pid
|
|
|
|
for (auto &info : iter.value()) { // kill window
|
|
|
|
info->killClient();
|
2022-04-24 14:52:13 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2022-05-31 17:20:39 +08:00
|
|
|
|
2022-04-24 14:52:13 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void Entry::presentWindows()
|
|
|
|
{
|
|
|
|
QList<uint> windows;
|
2022-05-31 20:37:01 +08:00
|
|
|
for (auto iter = windowInfoMap.begin(); iter != windowInfoMap.end(); iter++) {
|
2022-04-24 14:52:13 +08:00
|
|
|
windows.push_back(iter.key());
|
2022-05-31 20:37:01 +08:00
|
|
|
}
|
2022-04-24 14:52:13 +08:00
|
|
|
|
|
|
|
dock->presentWindows(windows);
|
|
|
|
}
|
|
|
|
|
2022-05-24 21:49:47 +08:00
|
|
|
/**
|
|
|
|
* @brief Entry::active 激活窗口
|
|
|
|
* @param timestamp
|
|
|
|
*/
|
2022-04-24 14:52:13 +08:00
|
|
|
void Entry::active(uint32_t timestamp)
|
|
|
|
{
|
2022-05-24 21:49:47 +08:00
|
|
|
if (dock->getHideMode() == HideMode::SmartHide) {
|
|
|
|
dock->setPropHideState(HideState::Show);
|
|
|
|
dock->updateHideState(true);
|
|
|
|
}
|
|
|
|
|
|
|
|
// 无窗口则直接启动
|
|
|
|
if (!hasWindow()) {
|
|
|
|
launchApp(timestamp);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!current) {
|
|
|
|
qWarning() << "active: current window is nullptr";
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
WindowInfoBase *winInfo = current;
|
|
|
|
if (dock->isWaylandEnv()) {
|
|
|
|
// wayland环境
|
|
|
|
if (!dock->isActiveWindow(winInfo)) {
|
|
|
|
winInfo->activate();
|
|
|
|
} else {
|
|
|
|
bool showing = dock->isShowingDesktop();
|
|
|
|
if (showing || winInfo->isMinimized()) {
|
|
|
|
winInfo->activate();
|
2022-05-31 20:37:01 +08:00
|
|
|
} else if (windowInfoMap.size() == 1) {
|
|
|
|
winInfo->minimize();
|
2022-05-24 21:49:47 +08:00
|
|
|
} else {
|
2022-05-31 20:37:01 +08:00
|
|
|
WindowInfoBase *nextWin = findNextLeader();
|
|
|
|
if (nextWin) {
|
|
|
|
nextWin->activate();
|
2022-05-24 21:49:47 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// X11环境
|
|
|
|
XWindow xid = winInfo->getXid();
|
|
|
|
WindowInfoBase *activeWin = dock->getActiveWindow();
|
|
|
|
if (xid != activeWin->getXid()) {
|
|
|
|
dock->doActiveWindow(xid);
|
|
|
|
} else {
|
|
|
|
bool found = false;
|
|
|
|
bool hiddenAtom = XCB->getAtom("_NET_WM_STATE_HIDDEN");
|
|
|
|
for (auto state : XCB->getWMState(xid)) {
|
|
|
|
if (hiddenAtom == state) {
|
|
|
|
found = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2022-04-24 14:52:13 +08:00
|
|
|
|
2022-05-24 21:49:47 +08:00
|
|
|
if (found) {
|
|
|
|
// 激活隐藏窗口
|
|
|
|
dock->doActiveWindow(xid);
|
2022-05-31 20:37:01 +08:00
|
|
|
} else if (windowInfoMap.size() == 1) {
|
|
|
|
XCB->minimizeWindow(xid);
|
|
|
|
} else if (dock->getActiveWindow()->getXid() == xid) {
|
|
|
|
WindowInfoBase *nextWin = findNextLeader();
|
|
|
|
if (nextWin) {
|
|
|
|
nextWin->activate();
|
2022-05-24 21:49:47 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2022-04-24 14:52:13 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
XWindow Entry::getCurrentWindow()
|
|
|
|
{
|
|
|
|
return currentWindow;
|
|
|
|
}
|
|
|
|
|
|
|
|
QString Entry::getDesktopFile()
|
|
|
|
{
|
|
|
|
return desktopFile;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Entry::getIsActive()
|
|
|
|
{
|
|
|
|
return isActive;
|
|
|
|
}
|
|
|
|
|
|
|
|
QString Entry::getMenu()
|
|
|
|
{
|
|
|
|
return menu->getMenuJsonStr();
|
|
|
|
}
|
|
|
|
|
|
|
|
QVector<XWindow> Entry::getAllowedClosedWindowIds()
|
|
|
|
{
|
|
|
|
QVector<XWindow> ret;
|
2022-05-31 17:20:39 +08:00
|
|
|
for (auto iter = windowInfoMap.begin(); iter != windowInfoMap.end(); iter++) {
|
2022-04-24 14:52:13 +08:00
|
|
|
WindowInfoBase *info = iter.value();
|
|
|
|
if (info && info->allowClose())
|
|
|
|
ret.push_back(iter.key());
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2022-05-31 17:20:39 +08:00
|
|
|
WindowInfoMap Entry::getExportWindowInfos()
|
2022-04-24 14:52:13 +08:00
|
|
|
{
|
|
|
|
return exportWindowInfos;
|
|
|
|
}
|
|
|
|
|
|
|
|
QVector<WindowInfoBase *> Entry::getAllowedCloseWindows()
|
|
|
|
{
|
|
|
|
QVector<WindowInfoBase *> ret;
|
2022-05-31 17:20:39 +08:00
|
|
|
for (auto iter = windowInfoMap.begin(); iter != windowInfoMap.end(); iter++) {
|
2022-04-24 14:52:13 +08:00
|
|
|
WindowInfoBase *info = iter.value();
|
2022-05-31 20:37:01 +08:00
|
|
|
if (info && info->allowClose()) {
|
2022-04-24 14:52:13 +08:00
|
|
|
ret.push_back(info);
|
2022-05-31 20:37:01 +08:00
|
|
|
}
|
2022-04-24 14:52:13 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
QVector<AppMenuItem> Entry::getMenuItemDesktopActions()
|
|
|
|
{
|
|
|
|
QVector<AppMenuItem> ret;
|
2022-05-31 20:37:01 +08:00
|
|
|
if (!app) {
|
2022-04-24 14:52:13 +08:00
|
|
|
return ret;
|
2022-05-31 20:37:01 +08:00
|
|
|
}
|
2022-04-24 14:52:13 +08:00
|
|
|
|
|
|
|
for (auto action : app->getActions()) {
|
2022-05-24 21:49:47 +08:00
|
|
|
AppMenuAction fn = [=](uint32_t timestamp) {
|
2022-04-24 14:52:13 +08:00
|
|
|
qInfo() << "do MenuItem: " << action.name.c_str();
|
2022-05-24 21:49:47 +08:00
|
|
|
dock->launchAppAction(app->getFileName(), action.section.c_str(), timestamp);
|
2022-04-24 14:52:13 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
AppMenuItem item;
|
|
|
|
item.text = action.name.c_str();
|
|
|
|
item.action = fn;
|
|
|
|
item.isActive = true;
|
|
|
|
ret.push_back(item);
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
AppMenuItem Entry::getMenuItemLaunch()
|
|
|
|
{
|
|
|
|
QString itemName;
|
2022-05-31 20:37:01 +08:00
|
|
|
if (hasWindow()) {
|
2022-04-24 14:52:13 +08:00
|
|
|
itemName = getName();
|
2022-05-31 20:37:01 +08:00
|
|
|
} else {
|
2022-04-24 14:52:13 +08:00
|
|
|
itemName = "Open";
|
2022-05-31 20:37:01 +08:00
|
|
|
}
|
2022-04-24 14:52:13 +08:00
|
|
|
|
2022-05-31 20:37:01 +08:00
|
|
|
AppMenuAction fn = [this](uint32_t timestamp) {
|
2022-04-24 14:52:13 +08:00
|
|
|
qInfo() << "do MenuItem: Open";
|
|
|
|
this->launchApp(timestamp);
|
|
|
|
};
|
|
|
|
|
|
|
|
AppMenuItem item;
|
|
|
|
item.text = itemName;
|
|
|
|
item.action = fn;
|
|
|
|
item.isActive = true;
|
|
|
|
return item;
|
|
|
|
}
|
|
|
|
|
|
|
|
AppMenuItem Entry::getMenuItemCloseAll()
|
|
|
|
{
|
2022-05-31 20:37:01 +08:00
|
|
|
AppMenuAction fn = [this](uint32_t timestamp) {
|
2022-04-24 14:52:13 +08:00
|
|
|
qInfo() << "do MenuItem: Close All";
|
|
|
|
auto winInfos = getAllowedCloseWindows();
|
|
|
|
|
2022-05-31 17:20:39 +08:00
|
|
|
// 根据创建时间从大到小排序, 方便后续关闭窗口
|
2022-04-24 14:52:13 +08:00
|
|
|
for (int i = 0; i < winInfos.size() - 1; i++) {
|
|
|
|
for (int j = i + 1; j < winInfos.size(); j++) {
|
|
|
|
if (winInfos[i]->getCreatedTime() < winInfos[j]->getCreatedTime()) {
|
|
|
|
auto info = winInfos[i];
|
|
|
|
winInfos[i] = winInfos[j];
|
|
|
|
winInfos[j] = info;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for (auto info : winInfos) {
|
|
|
|
qInfo() << "close WindowId " << info->getXid();
|
|
|
|
info->close(timestamp);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
AppMenuItem item;
|
|
|
|
item.text = "Close All";
|
|
|
|
item.action = fn;
|
|
|
|
item.isActive = true;
|
|
|
|
return item;
|
|
|
|
}
|
|
|
|
|
|
|
|
AppMenuItem Entry::getMenuItemForceQuit()
|
|
|
|
{
|
|
|
|
bool active = dock->getForceQuitAppStatus() != ForceQuitAppMode::Deactivated;
|
2022-05-31 20:37:01 +08:00
|
|
|
AppMenuAction fn = [this](uint32_t) {
|
2022-04-24 14:52:13 +08:00
|
|
|
qInfo() << "do MenuItem: Force Quit";
|
|
|
|
forceQuit();
|
|
|
|
};
|
|
|
|
|
|
|
|
AppMenuItem item;
|
|
|
|
item.text = "Force Quit";
|
|
|
|
item.action = fn;
|
|
|
|
item.isActive = active;
|
|
|
|
return item;
|
|
|
|
}
|
|
|
|
|
|
|
|
//dock栏上Android程序的Force Quit功能
|
|
|
|
AppMenuItem Entry::getMenuItemForceQuitAndroid()
|
|
|
|
{
|
|
|
|
bool active = dock->getForceQuitAppStatus() != ForceQuitAppMode::Deactivated;
|
|
|
|
auto allowedCloseWindows = getAllowedCloseWindows();
|
|
|
|
AppMenuAction fn = [](uint32_t){};
|
|
|
|
if (allowedCloseWindows.size() > 0) {
|
|
|
|
qInfo() << "do MenuItem: Force Quit";
|
|
|
|
AppMenuAction fn = [&](uint32_t timestamp) {
|
|
|
|
for (auto info : allowedCloseWindows) {
|
|
|
|
info->close(timestamp);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
AppMenuItem item;
|
|
|
|
item.text = "Force Quit";
|
|
|
|
item.action = fn;
|
|
|
|
item.isActive = active;
|
|
|
|
return item;
|
|
|
|
}
|
|
|
|
|
|
|
|
AppMenuItem Entry::getMenuItemDock()
|
|
|
|
{
|
|
|
|
AppMenuItem item;
|
|
|
|
item.text = "Dock";
|
2022-05-31 20:37:01 +08:00
|
|
|
item.action = [this](uint32_t) {
|
2022-04-24 14:52:13 +08:00
|
|
|
qInfo() << "do MenuItem: Dock";
|
|
|
|
requestDock();
|
|
|
|
};
|
2022-05-31 20:37:01 +08:00
|
|
|
|
2022-04-24 14:52:13 +08:00
|
|
|
item.isActive = true;
|
|
|
|
return item;
|
|
|
|
}
|
|
|
|
|
|
|
|
AppMenuItem Entry::getMenuItemUndock()
|
|
|
|
{
|
|
|
|
AppMenuItem item;
|
|
|
|
item.text = "Undock";
|
2022-05-31 20:37:01 +08:00
|
|
|
item.action = [this](uint32_t) {
|
2022-04-24 14:52:13 +08:00
|
|
|
qInfo() << "do MenuItem: Undock";
|
|
|
|
requestUndock();
|
|
|
|
};
|
2022-05-31 20:37:01 +08:00
|
|
|
|
2022-04-24 14:52:13 +08:00
|
|
|
item.isActive = true;
|
|
|
|
return item;
|
|
|
|
}
|
|
|
|
|
|
|
|
AppMenuItem Entry::getMenuItemAllWindows()
|
|
|
|
{
|
|
|
|
AppMenuItem item;
|
|
|
|
item.text = "All Windows";
|
2022-05-31 20:37:01 +08:00
|
|
|
item.action = [this](uint32_t) {
|
2022-04-24 14:52:13 +08:00
|
|
|
qInfo() << "do MenuItem: All Windows";
|
|
|
|
presentWindows();
|
|
|
|
};
|
2022-05-31 20:37:01 +08:00
|
|
|
|
2022-04-24 14:52:13 +08:00
|
|
|
item.isActive = true;
|
|
|
|
item.hint = menuItemHintShowAllWindows;
|
|
|
|
return item;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Entry::killProcess(int pid)
|
|
|
|
{
|
|
|
|
bool ret = true;
|
|
|
|
Process p(pid);
|
|
|
|
if (p.isExist()) {
|
|
|
|
ret = !kill(pid, SIGTERM);
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Entry::setPropDesktopFile(QString value)
|
|
|
|
{
|
|
|
|
if (value != desktopFile) {
|
|
|
|
desktopFile = value;
|
|
|
|
Q_EMIT desktopFileChanged(value);
|
2022-05-31 20:37:01 +08:00
|
|
|
return true;
|
2022-04-24 14:52:13 +08:00
|
|
|
}
|
2022-05-31 20:37:01 +08:00
|
|
|
|
|
|
|
return false;
|
2022-04-24 14:52:13 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|