Files
gxde-ai-see/src/app.cpp
T
shenmo 630ca6cadc fix(panel): 暂存优先模式;工厂自身接收拖拽;去掉 drop 提示
- 暂存区非空且未拖拽时只显示暂存列表,隐藏传送门与内容工厂并收窄窗口
- 内容工厂自身区域拖入也会展开动作
- 面板矩形改用屏幕可用区 + 边距计算(layer-shell 下 mapToGlobal 不可靠)
- 离开概览只复位传送门状态,不关闭面板;125ms
- 移除“在哪里 drop”提示
2026-10-30 22:00:39 +08:00

177 lines
5.3 KiB
C++

// SPDX-FileCopyrightText: 2026 GXDE OS Team
// SPDX-License-Identifier: GPL-3.0-or-later
#include "app.h"
#include "chat/chatwindow.h"
#include "config.h"
#include "portal/portalclient.h"
#include "staging/stagingmodel.h"
#include "todo/todomodel.h"
#include "todo/todowindow.h"
#include "ui/portalpanel.h"
#include <QDBusConnection>
#include <QDBusMessage>
#include <QLocalServer>
#include <QTimer>
#include <QLocalSocket>
#include <unistd.h>
App::App(QObject *parent)
: QObject(parent)
{
}
bool App::init(bool daemon, bool forceShow, bool showTodo, bool showChat)
{
Config::instance()->init();
m_daemon = daemon;
const QString serverName = QStringLiteral("gxde-ai-see-%1").arg(getuid());
QLocalSocket probe;
probe.connectToServer(serverName);
if (probe.waitForConnected(200)) {
probe.write(showChat ? "chat" : (showTodo ? "todo" : "show"));
probe.waitForBytesWritten(200);
probe.disconnectFromServer();
return false;
}
QLocalServer::removeServer(serverName);
m_server = new QLocalServer(this);
m_server->listen(serverName);
connect(m_server, &QLocalServer::newConnection, this, [this]() {
while (QLocalSocket *socket = m_server->nextPendingConnection()) {
connect(socket, &QLocalSocket::readyRead, this, [this, socket]() {
const QByteArray data = socket->readAll();
if (data.contains("chat")) {
showChatWindow();
} else if (data.contains("todo")) {
showTodoWindow();
} else if (data.contains("show")) {
showPanel();
}
});
connect(socket, &QLocalSocket::disconnected, socket,
&QLocalSocket::deleteLater);
}
});
m_model = new StagingModel(this);
/* gxde-k9 keeps restarting us; when the compositor has no portal support we
* warn once and then stay idle instead of exiting (which would make k9
* relaunch us every few seconds). */
if (daemon && !PortalClient::instance()->available() &&
!Config::instance()->getBool(QStringLiteral("warned/unsupportedEnv"), false)) {
QDBusMessage notification = QDBusMessage::createMethodCall(
QStringLiteral("org.freedesktop.Notifications"),
QStringLiteral("/org/freedesktop/Notifications"),
QStringLiteral("org.freedesktop.Notifications"), QStringLiteral("Notify"));
notification << QStringLiteral("gxde-ai-see") << 0u
<< QStringLiteral("gxde-ai-see")
<< tr("小埃同学")
<< tr("当前桌面不支持传送门(需要 GXDE Wayland 合成器)。"
"小埃同学会继续在后台待命,暂存区、内容工厂和对话仍然可用。")
<< QStringList() << QVariantMap() << 6000;
QDBusConnection::sessionBus().send(notification);
Config::instance()->set(QStringLiteral("warned/unsupportedEnv"), true);
Config::instance()->sync();
}
PortalClient *portal = PortalClient::instance();
connect(portal, &PortalClient::dragStarted, this, [this](const QString &mimeTypes) {
if (!PortalClient::mimeInteresting(mimeTypes)) {
return;
}
m_dragging = true;
if (m_panel) {
m_panel->setDragging(true);
}
if (!m_model->isEmpty()) {
if (m_panel && m_panel->isVisible()) {
m_panel->suppressPortalIfUnderCursor();
}
return;
}
QTimer::singleShot(120, this, [this]() {
if (m_dragging && m_model->isEmpty()) {
showPanel();
if (m_panel) {
m_panel->suppressPortalIfUnderCursor();
}
}
});
});
connect(portal, &PortalClient::dragEnded, this, [this]() {
m_dragging = false;
if (m_panel) {
m_panel->stopPortalSuppression();
m_panel->setDragging(false);
}
if (m_model->isEmpty() && m_panel && m_panel->isVisible()) {
m_panel->dismiss();
}
});
connect(m_model, &StagingModel::countChanged, this, [this]() {
if (!m_daemon && !m_model->isEmpty() && m_panel) {
m_panel->popup();
}
});
if (showChat) {
showChatWindow();
}
if (showTodo) {
showTodoWindow();
}
if (!daemon || forceShow || !m_model->isEmpty()) {
showPanel();
}
return true;
}
void App::ensurePanel()
{
if (m_panel) {
return;
}
m_panel = new PortalPanel(m_model);
connect(m_panel, &PortalPanel::openChatRequested, this, &App::showChatWindow);
connect(m_panel, &PortalPanel::askWithContent, this,
[this](const QString &text, const QStringList &files) {
showChatWindow();
if (m_chatWindow) {
m_chatWindow->startConversationWith(text, files);
}
});
}
void App::showPanel()
{
ensurePanel();
m_panel->popup();
}
void App::showChatWindow()
{
if (!m_chatWindow) {
m_chatWindow = new ChatWindow;
}
m_chatWindow->activateForAsk();
}
void App::showTodoWindow()
{
if (!m_todoWindow) {
m_todoWindow = new TodoWindow(TodoModel::instance());
}
m_todoWindow->popup();
}