mirror of
https://github.com/zhuzichu520/FluentUI.git
synced 2025-07-03 08:35:28 +08:00
update
This commit is contained in:
24
example/src/AppInfo.cpp
Normal file
24
example/src/AppInfo.cpp
Normal file
@ -0,0 +1,24 @@
|
||||
#include "AppInfo.h"
|
||||
#include "lang/En.h"
|
||||
#include "lang/Zh.h"
|
||||
|
||||
AppInfo::AppInfo(QObject *parent)
|
||||
: QObject{parent}
|
||||
{
|
||||
version("1.2.7");
|
||||
lang(new En());
|
||||
}
|
||||
|
||||
void AppInfo::changeLang(const QString& locale){
|
||||
if(_lang){
|
||||
_lang->deleteLater();
|
||||
}
|
||||
if(locale=="Zh"){
|
||||
lang(new Zh());
|
||||
}else if(locale=="En"){
|
||||
lang(new En());
|
||||
}else {
|
||||
lang(new En());
|
||||
}
|
||||
|
||||
}
|
19
example/src/AppInfo.h
Normal file
19
example/src/AppInfo.h
Normal file
@ -0,0 +1,19 @@
|
||||
#ifndef APPINFO_H
|
||||
#define APPINFO_H
|
||||
|
||||
#include <QObject>
|
||||
#include "lang/Lang.h"
|
||||
#include "stdafx.h"
|
||||
|
||||
class AppInfo : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY_AUTO(QString,version)
|
||||
Q_PROPERTY_AUTO(Lang*,lang)
|
||||
public:
|
||||
explicit AppInfo(QObject *parent = nullptr);
|
||||
Q_INVOKABLE void changeLang(const QString& locale);
|
||||
Q_SIGNAL void activeWindow();
|
||||
};
|
||||
|
||||
#endif // APPINFO_H
|
56
example/src/controller/ChatController.cpp
Normal file
56
example/src/controller/ChatController.cpp
Normal file
@ -0,0 +1,56 @@
|
||||
#include "ChatController.h"
|
||||
|
||||
ChatController::ChatController(QObject *parent)
|
||||
: QObject{parent}
|
||||
{
|
||||
isLoading(false);
|
||||
networkManager = new QNetworkAccessManager(this);
|
||||
}
|
||||
|
||||
|
||||
void ChatController::sendMessage(const QString& text){
|
||||
isLoading(true);
|
||||
QUrl apiUrl("https://api.openai.com/v1/chat/completions");
|
||||
QNetworkRequest request(apiUrl);
|
||||
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
|
||||
request.setRawHeader("Authorization", QString::fromStdString("Bearer %1").arg(QString::fromUtf8(QByteArray::fromBase64(baseKey.toUtf8()))).toUtf8());
|
||||
QJsonObject requestData;
|
||||
requestData.insert("model", "gpt-3.5-turbo");
|
||||
messages.append(createMessage("user",text));
|
||||
requestData.insert("messages", messages);
|
||||
QJsonDocument requestDoc(requestData);
|
||||
QByteArray requestDataBytes = requestDoc.toJson();
|
||||
QNetworkReply* reply = networkManager->post(request, requestDataBytes);
|
||||
connect(reply, &QNetworkReply::finished,this, [=]() {
|
||||
if (reply->error() == QNetworkReply::NoError) {
|
||||
QString responseString = QString::fromUtf8(reply->readAll());
|
||||
qDebug() << responseString;
|
||||
QJsonDocument doc = QJsonDocument::fromJson(responseString.toUtf8());
|
||||
QJsonObject jsonObj = doc.object();
|
||||
QString text = jsonObj.value("choices").toArray().at(0).toObject().value("message").toObject().value("content").toString();
|
||||
if(text.isEmpty()){
|
||||
text = "响应错误:content为空数据";
|
||||
}else{
|
||||
messages.append(createMessage("assistant",text));
|
||||
}
|
||||
responseData(text.trimmed());
|
||||
} else {
|
||||
responseData("网络错误:"+reply->errorString());
|
||||
}
|
||||
isLoading(false);
|
||||
reply->deleteLater();
|
||||
});
|
||||
}
|
||||
|
||||
QJsonObject ChatController::createMessage(const QString& role,const QString& content){
|
||||
QJsonObject message;
|
||||
message.insert("role",role);
|
||||
message.insert("content",content);
|
||||
return message;
|
||||
}
|
||||
|
||||
void ChatController::clipText(const QString& text){
|
||||
qDebug()<<text;
|
||||
QClipboard *clipboard = QGuiApplication::clipboard();
|
||||
clipboard->setText(text);
|
||||
}
|
35
example/src/controller/ChatController.h
Normal file
35
example/src/controller/ChatController.h
Normal file
@ -0,0 +1,35 @@
|
||||
#ifndef CHATCONTROLLER_H
|
||||
#define CHATCONTROLLER_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QNetworkAccessManager>
|
||||
#include <QNetworkReply>
|
||||
#include <QJsonObject>
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonArray>
|
||||
#include <QGuiApplication>
|
||||
#include <QClipboard>
|
||||
#include <QByteArray>
|
||||
#include <QFile>
|
||||
#include "../stdafx.h"
|
||||
|
||||
class ChatController : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY_AUTO(bool,isLoading)
|
||||
Q_PROPERTY_AUTO(QString,responseData);
|
||||
public:
|
||||
explicit ChatController(QObject *parent = nullptr);
|
||||
|
||||
Q_INVOKABLE void sendMessage(const QString& text);
|
||||
Q_INVOKABLE void clipText(const QString& text);
|
||||
private:
|
||||
QJsonObject createMessage(const QString& role,const QString& content);
|
||||
|
||||
private:
|
||||
QNetworkAccessManager* networkManager;
|
||||
QJsonArray messages;
|
||||
QString baseKey = "c2stbXgxWm5MQkZ5TzhNYzNmRWl6eDZUM0JsYmtGSnNBWjNiakJjSXB6WGN3QW9KSk11";
|
||||
};
|
||||
|
||||
#endif // CHATCONTROLLER_H
|
22
example/src/lang/En.cpp
Normal file
22
example/src/lang/En.cpp
Normal file
@ -0,0 +1,22 @@
|
||||
#include "En.h"
|
||||
|
||||
En::En(QObject *parent)
|
||||
: Lang{parent}
|
||||
{
|
||||
setObjectName("En");
|
||||
home("Home");
|
||||
basic_input("Basic Input");
|
||||
form("Form");
|
||||
surface("Surfaces");
|
||||
popus("Popus");
|
||||
navigation("Navigation");
|
||||
theming("Theming");
|
||||
media("Media");
|
||||
dark_mode("Dark Mode");
|
||||
sys_dark_mode("Sync with system");
|
||||
search("Search");
|
||||
about("About");
|
||||
settings("Settings");
|
||||
locale("Locale");
|
||||
navigation_view_display_mode("NavigationView Display Mode");
|
||||
}
|
17
example/src/lang/En.h
Normal file
17
example/src/lang/En.h
Normal file
@ -0,0 +1,17 @@
|
||||
#ifndef EN_H
|
||||
#define EN_H
|
||||
|
||||
#include <QObject>
|
||||
#include "Lang.h"
|
||||
|
||||
class En : public Lang
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit En(QObject *parent = nullptr);
|
||||
|
||||
signals:
|
||||
|
||||
};
|
||||
|
||||
#endif // EN_H
|
7
example/src/lang/Lang.cpp
Normal file
7
example/src/lang/Lang.cpp
Normal file
@ -0,0 +1,7 @@
|
||||
#include "Lang.h"
|
||||
|
||||
Lang::Lang(QObject *parent)
|
||||
: QObject{parent}
|
||||
{
|
||||
|
||||
}
|
30
example/src/lang/Lang.h
Normal file
30
example/src/lang/Lang.h
Normal file
@ -0,0 +1,30 @@
|
||||
#ifndef LANG_H
|
||||
#define LANG_H
|
||||
|
||||
#include <QObject>
|
||||
#include "../stdafx.h"
|
||||
|
||||
class Lang : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY_AUTO(QString,home);
|
||||
Q_PROPERTY_AUTO(QString,basic_input);
|
||||
Q_PROPERTY_AUTO(QString,form);
|
||||
Q_PROPERTY_AUTO(QString,surface);
|
||||
Q_PROPERTY_AUTO(QString,popus);
|
||||
Q_PROPERTY_AUTO(QString,navigation);
|
||||
Q_PROPERTY_AUTO(QString,theming);
|
||||
Q_PROPERTY_AUTO(QString,media);
|
||||
Q_PROPERTY_AUTO(QString,dark_mode);
|
||||
Q_PROPERTY_AUTO(QString,sys_dark_mode);
|
||||
Q_PROPERTY_AUTO(QString,search);
|
||||
Q_PROPERTY_AUTO(QString,about);
|
||||
Q_PROPERTY_AUTO(QString,settings);
|
||||
Q_PROPERTY_AUTO(QString,navigation_view_display_mode);
|
||||
Q_PROPERTY_AUTO(QString,locale);
|
||||
public:
|
||||
explicit Lang(QObject *parent = nullptr);
|
||||
|
||||
};
|
||||
|
||||
#endif // LANG_H
|
22
example/src/lang/Zh.cpp
Normal file
22
example/src/lang/Zh.cpp
Normal file
@ -0,0 +1,22 @@
|
||||
#include "Zh.h"
|
||||
|
||||
Zh::Zh(QObject *parent)
|
||||
: Lang{parent}
|
||||
{
|
||||
setObjectName("Zh");
|
||||
home("首页");
|
||||
basic_input("基本输入");
|
||||
form("表单");
|
||||
surface("表面");
|
||||
popus("弹窗");
|
||||
navigation("导航");
|
||||
theming("主题");
|
||||
media("媒体");
|
||||
dark_mode("夜间模式");
|
||||
sys_dark_mode("跟随系统");
|
||||
search("查找");
|
||||
about("关于");
|
||||
settings("设置");
|
||||
locale("语言环境");
|
||||
navigation_view_display_mode("导航视图显示模式");
|
||||
}
|
17
example/src/lang/Zh.h
Normal file
17
example/src/lang/Zh.h
Normal file
@ -0,0 +1,17 @@
|
||||
#ifndef ZH_H
|
||||
#define ZH_H
|
||||
|
||||
#include <QObject>
|
||||
#include "Lang.h"
|
||||
|
||||
class Zh : public Lang
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit Zh(QObject *parent = nullptr);
|
||||
|
||||
signals:
|
||||
|
||||
};
|
||||
|
||||
#endif // ZH_H
|
57
example/src/main.cpp
Normal file
57
example/src/main.cpp
Normal file
@ -0,0 +1,57 @@
|
||||
#include <QGuiApplication>
|
||||
#include <QQmlApplicationEngine>
|
||||
#include <QQmlContext>
|
||||
#include <QDir>
|
||||
#include <QQuickWindow>
|
||||
#include <QProcess>
|
||||
#include "lang/Lang.h"
|
||||
#include "AppInfo.h"
|
||||
#include "controller/ChatController.h"
|
||||
#include "tool/IPC.h"
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
//将样式设置为Basic,不然会导致组件显示异常
|
||||
qputenv("QT_QUICK_CONTROLS_STYLE","Basic");
|
||||
//6.4及以下监听系统深色模式变化
|
||||
#ifdef Q_OS_WIN
|
||||
qputenv("QT_QPA_PLATFORM","windows:darkmode=2");
|
||||
#endif
|
||||
QGuiApplication::setOrganizationName("ZhuZiChu");
|
||||
QGuiApplication::setOrganizationDomain("https://zhuzichu520.github.io");
|
||||
QGuiApplication::setApplicationName("FluentUI");
|
||||
// QQuickWindow::setGraphicsApi(QSGRendererInterface::Software);
|
||||
QGuiApplication app(argc, argv);
|
||||
AppInfo* appInfo = new AppInfo();
|
||||
IPC ipc(0);
|
||||
QString activeWindowEvent = "activeWindow";
|
||||
if(!ipc.isCurrentOwner()){
|
||||
ipc.postEvent(activeWindowEvent,QString().toUtf8(),0);
|
||||
delete appInfo;
|
||||
return 0;
|
||||
}
|
||||
if(ipc.isAttached()){
|
||||
ipc.registerEventHandler(activeWindowEvent,[&appInfo](const QByteArray& data){
|
||||
Q_EMIT appInfo->activeWindow();
|
||||
return true;
|
||||
});
|
||||
}
|
||||
app.setQuitOnLastWindowClosed(false);
|
||||
QQmlApplicationEngine engine;
|
||||
qmlRegisterType<ChatController>("Controller",1,0,"ChatController");
|
||||
QQmlContext * context = engine.rootContext();
|
||||
Lang* lang = appInfo->lang();
|
||||
context->setContextProperty("lang",lang);
|
||||
QObject::connect(appInfo,&AppInfo::langChanged,&app,[context,appInfo]{
|
||||
context->setContextProperty("lang",appInfo->lang());
|
||||
});
|
||||
context->setContextProperty("appInfo",appInfo);
|
||||
const QUrl url(QStringLiteral("qrc:/qml/App.qml"));
|
||||
QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,
|
||||
&app, [url](QObject *obj, const QUrl &objUrl) {
|
||||
if (!obj && url == objUrl)
|
||||
QCoreApplication::exit(-1);
|
||||
}, Qt::QueuedConnection);
|
||||
engine.load(url);
|
||||
return app.exec();
|
||||
}
|
25
example/src/stdafx.h
Normal file
25
example/src/stdafx.h
Normal file
@ -0,0 +1,25 @@
|
||||
#if defined(_MSC_VER) && (_MSC_VER >= 1600)
|
||||
#pragma execution_character_set("utf-8")
|
||||
#endif
|
||||
|
||||
#ifndef STDAFX_H
|
||||
#define STDAFX_H
|
||||
|
||||
#define Q_PROPERTY_AUTO(TYPE, M) \
|
||||
Q_PROPERTY(TYPE M MEMBER _##M NOTIFY M##Changed) \
|
||||
public: \
|
||||
Q_SIGNAL void M##Changed(); \
|
||||
void M(TYPE in_##M) \
|
||||
{ \
|
||||
_##M = in_##M; \
|
||||
Q_EMIT M##Changed(); \
|
||||
} \
|
||||
TYPE M() \
|
||||
{ \
|
||||
return _##M; \
|
||||
} \
|
||||
\
|
||||
private: \
|
||||
TYPE _##M;
|
||||
|
||||
#endif // STDAFX_H
|
255
example/src/tool/IPC.cpp
Normal file
255
example/src/tool/IPC.cpp
Normal file
@ -0,0 +1,255 @@
|
||||
#include "IPC.h"
|
||||
|
||||
#include <QCoreApplication>
|
||||
#include <QDebug>
|
||||
#include <QThread>
|
||||
#include <ctime>
|
||||
#include <random>
|
||||
|
||||
#ifdef WIN32
|
||||
#include <windows.h>
|
||||
#else
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
IPC::IPC(uint32_t profileId)
|
||||
: profileId{profileId}
|
||||
, globalMemory{"ipc-" IPC_PROTOCOL_VERSION}
|
||||
{
|
||||
qRegisterMetaType<IPCEventHandler>("IPCEventHandler");
|
||||
timer.setInterval(EVENT_TIMER_MS);
|
||||
timer.setSingleShot(true);
|
||||
connect(&timer, &QTimer::timeout, this, &IPC::processEvents);
|
||||
std::default_random_engine randEngine((std::random_device())());
|
||||
std::uniform_int_distribution<uint64_t> distribution;
|
||||
globalId = distribution(randEngine);
|
||||
qDebug() << "Our global IPC ID is " << globalId;
|
||||
if (globalMemory.create(sizeof(IPCMemory))) {
|
||||
if (globalMemory.lock()) {
|
||||
IPCMemory* mem = global();
|
||||
memset(mem, 0, sizeof(IPCMemory));
|
||||
mem->globalId = globalId;
|
||||
mem->lastProcessed = time(nullptr);
|
||||
globalMemory.unlock();
|
||||
} else {
|
||||
qWarning() << "Couldn't lock to take ownership";
|
||||
}
|
||||
} else if (globalMemory.attach()) {
|
||||
qDebug() << "Attaching to the global shared memory";
|
||||
} else {
|
||||
qDebug() << "Failed to attach to the global shared memory, giving up. Error:"
|
||||
<< globalMemory.error();
|
||||
return;
|
||||
}
|
||||
|
||||
processEvents();
|
||||
}
|
||||
|
||||
IPC::~IPC()
|
||||
{
|
||||
if (!globalMemory.lock()) {
|
||||
qWarning() << "Failed to lock in ~IPC";
|
||||
return;
|
||||
}
|
||||
|
||||
if (isCurrentOwnerNoLock()) {
|
||||
global()->globalId = 0;
|
||||
}
|
||||
globalMemory.unlock();
|
||||
}
|
||||
|
||||
time_t IPC::postEvent(const QString& name, const QByteArray& data, uint32_t dest)
|
||||
{
|
||||
QByteArray binName = name.toUtf8();
|
||||
if (binName.length() > (int32_t)sizeof(IPCEvent::name)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (data.length() > (int32_t)sizeof(IPCEvent::data)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!globalMemory.lock()) {
|
||||
qDebug() << "Failed to lock in postEvent()";
|
||||
return 0;
|
||||
}
|
||||
|
||||
IPCEvent* evt = nullptr;
|
||||
IPCMemory* mem = global();
|
||||
time_t result = 0;
|
||||
|
||||
for (uint32_t i = 0; !evt && i < EVENT_QUEUE_SIZE; ++i) {
|
||||
if (mem->events[i].posted == 0) {
|
||||
evt = &mem->events[i];
|
||||
}
|
||||
}
|
||||
|
||||
if (evt) {
|
||||
memset(evt, 0, sizeof(IPCEvent));
|
||||
memcpy(evt->name, binName.constData(), binName.length());
|
||||
memcpy(evt->data, data.constData(), data.length());
|
||||
mem->lastEvent = evt->posted = result = qMax(mem->lastEvent + 1, time(nullptr));
|
||||
evt->dest = dest;
|
||||
evt->sender = GetCurrentProcessId();
|
||||
qDebug() << "postEvent " << name << "to" << dest;
|
||||
}
|
||||
globalMemory.unlock();
|
||||
return result;
|
||||
}
|
||||
|
||||
bool IPC::isCurrentOwner()
|
||||
{
|
||||
if (globalMemory.lock()) {
|
||||
const bool isOwner = isCurrentOwnerNoLock();
|
||||
globalMemory.unlock();
|
||||
return isOwner;
|
||||
} else {
|
||||
qWarning() << "isCurrentOwner failed to lock, returning false";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void IPC::registerEventHandler(const QString& name, IPCEventHandler handler)
|
||||
{
|
||||
eventHandlers[name] = handler;
|
||||
}
|
||||
|
||||
bool IPC::isEventAccepted(time_t time)
|
||||
{
|
||||
bool result = false;
|
||||
if (!globalMemory.lock()) {
|
||||
return result;
|
||||
}
|
||||
|
||||
if (difftime(global()->lastProcessed, time) > 0) {
|
||||
IPCMemory* mem = global();
|
||||
for (uint32_t i = 0; i < EVENT_QUEUE_SIZE; ++i) {
|
||||
if (mem->events[i].posted == time && mem->events[i].processed) {
|
||||
result = mem->events[i].accepted;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
globalMemory.unlock();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool IPC::waitUntilAccepted(time_t postTime, int32_t timeout /*=-1*/)
|
||||
{
|
||||
bool result = false;
|
||||
time_t start = time(nullptr);
|
||||
forever
|
||||
{
|
||||
result = isEventAccepted(postTime);
|
||||
if (result || (timeout > 0 && difftime(time(nullptr), start) >= timeout)) {
|
||||
break;
|
||||
}
|
||||
|
||||
qApp->processEvents();
|
||||
QThread::msleep(0);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
bool IPC::isAttached() const
|
||||
{
|
||||
return globalMemory.isAttached();
|
||||
}
|
||||
|
||||
void IPC::setProfileId(uint32_t profileId)
|
||||
{
|
||||
this->profileId = profileId;
|
||||
}
|
||||
|
||||
IPC::IPCEvent* IPC::fetchEvent()
|
||||
{
|
||||
IPCMemory* mem = global();
|
||||
for (uint32_t i = 0; i < EVENT_QUEUE_SIZE; ++i) {
|
||||
IPCEvent* evt = &mem->events[i];
|
||||
if ((evt->processed && difftime(time(nullptr), evt->processed) > EVENT_GC_TIMEOUT)
|
||||
|| (!evt->processed && difftime(time(nullptr), evt->posted) > EVENT_GC_TIMEOUT)) {
|
||||
memset(evt, 0, sizeof(IPCEvent));
|
||||
}
|
||||
|
||||
if (evt->posted && !evt->processed && evt->sender != GetCurrentProcessId()
|
||||
&& (evt->dest == profileId || (evt->dest == 0 && isCurrentOwnerNoLock()))) {
|
||||
return evt;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool IPC::runEventHandler(IPCEventHandler handler, const QByteArray& arg)
|
||||
{
|
||||
bool result = false;
|
||||
if (QThread::currentThread() == qApp->thread()) {
|
||||
result = handler(arg);
|
||||
} else {
|
||||
QMetaObject::invokeMethod(this, "runEventHandler", Qt::BlockingQueuedConnection,
|
||||
Q_RETURN_ARG(bool, result), Q_ARG(IPCEventHandler, handler),
|
||||
Q_ARG(const QByteArray&, arg));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void IPC::processEvents()
|
||||
{
|
||||
if (!globalMemory.lock()) {
|
||||
timer.start();
|
||||
return;
|
||||
}
|
||||
|
||||
IPCMemory* mem = global();
|
||||
|
||||
if (mem->globalId == globalId) {
|
||||
mem->lastProcessed = time(nullptr);
|
||||
} else {
|
||||
if (difftime(time(nullptr), mem->lastProcessed) >= OWNERSHIP_TIMEOUT_S) {
|
||||
qDebug() << "Previous owner timed out, taking ownership" << mem->globalId << "->"
|
||||
<< globalId;
|
||||
memset(mem, 0, sizeof(IPCMemory));
|
||||
mem->globalId = globalId;
|
||||
mem->lastProcessed = time(nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
while (IPCEvent* evt = fetchEvent()) {
|
||||
QString name = QString::fromUtf8(evt->name);
|
||||
auto it = eventHandlers.find(name);
|
||||
if (it != eventHandlers.end()) {
|
||||
evt->accepted = runEventHandler(it.value(), evt->data);
|
||||
qDebug() << "Processed event:" << name << "posted:" << evt->posted
|
||||
<< "accepted:" << evt->accepted;
|
||||
if (evt->dest == 0) {
|
||||
if (evt->accepted) {
|
||||
evt->processed = time(nullptr);
|
||||
}
|
||||
} else {
|
||||
evt->processed = time(nullptr);
|
||||
}
|
||||
} else {
|
||||
qDebug() << "Received event:" << name << "without handler";
|
||||
qDebug() << "Available handlers:" << eventHandlers.keys();
|
||||
}
|
||||
}
|
||||
|
||||
globalMemory.unlock();
|
||||
timer.start();
|
||||
}
|
||||
|
||||
bool IPC::isCurrentOwnerNoLock()
|
||||
{
|
||||
const void* const data = globalMemory.data();
|
||||
if (!data) {
|
||||
qWarning() << "isCurrentOwnerNoLock failed to access the memory, returning false";
|
||||
return false;
|
||||
}
|
||||
return (*static_cast<const uint64_t*>(data) == globalId);
|
||||
}
|
||||
|
||||
IPC::IPCMemory* IPC::global()
|
||||
{
|
||||
return static_cast<IPCMemory*>(globalMemory.data());
|
||||
}
|
75
example/src/tool/IPC.h
Normal file
75
example/src/tool/IPC.h
Normal file
@ -0,0 +1,75 @@
|
||||
#ifndef IPC_H
|
||||
#define IPC_H
|
||||
|
||||
#include <QMap>
|
||||
#include <QObject>
|
||||
#include <QSharedMemory>
|
||||
#include <QTimer>
|
||||
#include <ctime>
|
||||
#include <functional>
|
||||
|
||||
using IPCEventHandler = std::function<bool(const QByteArray&)>;
|
||||
|
||||
#define IPC_PROTOCOL_VERSION "1"
|
||||
|
||||
class IPC : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
protected:
|
||||
static const int EVENT_TIMER_MS = 1000;
|
||||
static const int EVENT_GC_TIMEOUT = 5;
|
||||
static const int EVENT_QUEUE_SIZE = 32;
|
||||
static const int OWNERSHIP_TIMEOUT_S = 5;
|
||||
|
||||
public:
|
||||
IPC(uint32_t profileId);
|
||||
~IPC();
|
||||
|
||||
struct IPCEvent
|
||||
{
|
||||
uint32_t dest;
|
||||
int32_t sender;
|
||||
char name[16];
|
||||
char data[128];
|
||||
time_t posted;
|
||||
time_t processed;
|
||||
uint32_t flags;
|
||||
bool accepted;
|
||||
bool global;
|
||||
};
|
||||
|
||||
struct IPCMemory
|
||||
{
|
||||
uint64_t globalId;
|
||||
time_t lastEvent;
|
||||
time_t lastProcessed;
|
||||
IPCEvent events[IPC::EVENT_QUEUE_SIZE];
|
||||
};
|
||||
|
||||
time_t postEvent(const QString& name, const QByteArray& data = QByteArray(), uint32_t dest = 0);
|
||||
bool isCurrentOwner();
|
||||
void registerEventHandler(const QString& name, IPCEventHandler handler);
|
||||
bool isEventAccepted(time_t time);
|
||||
bool waitUntilAccepted(time_t time, int32_t timeout = -1);
|
||||
bool isAttached() const;
|
||||
|
||||
public slots:
|
||||
void setProfileId(uint32_t profileId);
|
||||
|
||||
private:
|
||||
IPCMemory* global();
|
||||
bool runEventHandler(IPCEventHandler handler, const QByteArray& arg);
|
||||
IPCEvent* fetchEvent();
|
||||
void processEvents();
|
||||
bool isCurrentOwnerNoLock();
|
||||
|
||||
private:
|
||||
QTimer timer;
|
||||
uint64_t globalId;
|
||||
uint32_t profileId;
|
||||
QSharedMemory globalMemory;
|
||||
QMap<QString, IPCEventHandler> eventHandlers;
|
||||
};
|
||||
|
||||
#endif // IPC_H
|
Reference in New Issue
Block a user