mirror of
https://github.com/qmlnet/qmlnet.git
synced 2026-05-21 06:45:32 -06:00
Support for QCoreApplication, QGuiApplication, and QApplication.
This commit is contained in:
parent
28a2ae29b7
commit
72bee3f7af
10 changed files with 391 additions and 247 deletions
|
|
@ -1,4 +1,4 @@
|
|||
QT += gui qml core-private quickcontrols2
|
||||
QT += gui qml core-private quickcontrols2 widgets
|
||||
|
||||
CONFIG(enable-webengine) {
|
||||
QT += webengine
|
||||
|
|
|
|||
132
src/native/QmlNet/QmlNet/qml/QCoreApplication.cpp
Normal file
132
src/native/QmlNet/QmlNet/qml/QCoreApplication.cpp
Normal file
|
|
@ -0,0 +1,132 @@
|
|||
#include <QmlNet/qml/QCoreApplication.h>
|
||||
#include <QmlNet/qml/NetVariantList.h>
|
||||
#include <QGuiApplication>
|
||||
#include <QApplication>
|
||||
|
||||
GuiThreadContextTriggerCallback::GuiThreadContextTriggerCallback() :
|
||||
callback(nullptr) {
|
||||
}
|
||||
|
||||
void GuiThreadContextTriggerCallback::trigger() {
|
||||
if (callback) {
|
||||
callback();
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
|
||||
Q_DECL_EXPORT QGuiApplicationContainer* qapp_fromExisting(QCoreApplication* rawPointer)
|
||||
{
|
||||
QGuiApplicationContainer* result = new QGuiApplicationContainer();
|
||||
result->ownsApp = false;
|
||||
result->app = rawPointer;
|
||||
|
||||
result->callback = QSharedPointer<GuiThreadContextTriggerCallback>(new GuiThreadContextTriggerCallback());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
Q_DECL_EXPORT QGuiApplicationContainer* qapp_create(NetVariantListContainer* argsContainer, int flags, int type)
|
||||
{
|
||||
QGuiApplicationContainer* result = new QGuiApplicationContainer();
|
||||
|
||||
// Build our args
|
||||
if(argsContainer != nullptr) {
|
||||
QSharedPointer<NetVariantList> args = argsContainer->list;
|
||||
for(int x = 0; x < args->count(); x++) {
|
||||
QByteArray arg = args->get(x)->getString().toLatin1();
|
||||
result->args.append(arg);
|
||||
char* cstr = new char [size_t(arg.size())+1];
|
||||
memcpy(cstr, arg.data(), size_t(arg.size())+1);
|
||||
result->argsPointer.push_back(cstr);
|
||||
}
|
||||
result->argCount = result->args.size();
|
||||
} else {
|
||||
result->argCount = 0;
|
||||
}
|
||||
|
||||
result->ownsApp = true;
|
||||
|
||||
switch(type)
|
||||
{
|
||||
case 0:
|
||||
result->app = new QCoreApplication(result->argCount, &result->argsPointer[0], flags);
|
||||
break;
|
||||
case 1:
|
||||
result->app = new QGuiApplication(result->argCount, &result->argsPointer[0], flags);
|
||||
break;
|
||||
case 2:
|
||||
result->app = new QApplication(result->argCount, &result->argsPointer[0], flags);
|
||||
break;
|
||||
default:
|
||||
qCritical("invalid app type %d", type);
|
||||
delete result;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
result->callback = QSharedPointer<GuiThreadContextTriggerCallback>(new GuiThreadContextTriggerCallback());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
Q_DECL_EXPORT void qapp_destroy(QGuiApplicationContainer* container)
|
||||
{
|
||||
for (auto i : container->argsPointer) {
|
||||
delete[] i;
|
||||
}
|
||||
container->callback.clear();
|
||||
if(container->ownsApp) {
|
||||
delete container->app;
|
||||
}
|
||||
delete container;
|
||||
}
|
||||
|
||||
Q_DECL_EXPORT int qapp_getType(QGuiApplicationContainer* container, QCoreApplication* rawPointer)
|
||||
{
|
||||
if (!container && !rawPointer) {
|
||||
qCritical("invalid container and/or rawPointer");
|
||||
return -1;
|
||||
}
|
||||
if (container && rawPointer) {
|
||||
qCritical("invalid container and/or rawPointer");
|
||||
return -1;
|
||||
}
|
||||
if(!rawPointer && container) {
|
||||
rawPointer = container->app;
|
||||
}
|
||||
if (qobject_cast<QApplication*>(rawPointer) != nullptr){
|
||||
return 2;
|
||||
}
|
||||
if (qobject_cast<QGuiApplication*>(rawPointer) != nullptr){
|
||||
return 1;
|
||||
}
|
||||
// QCoreApplication
|
||||
return 0;
|
||||
}
|
||||
|
||||
Q_DECL_EXPORT int qapp_exec()
|
||||
{
|
||||
return QGuiApplication::exec();
|
||||
}
|
||||
|
||||
Q_DECL_EXPORT void qapp_addTriggerCallback(QGuiApplicationContainer* container, guiThreadTriggerCb callback)
|
||||
{
|
||||
container->callback->callback = callback;
|
||||
}
|
||||
|
||||
Q_DECL_EXPORT void qapp_requestTrigger(QGuiApplicationContainer* container)
|
||||
{
|
||||
QMetaObject::invokeMethod(container->callback.data(), "trigger", Qt::QueuedConnection);
|
||||
}
|
||||
|
||||
Q_DECL_EXPORT void qapp_exit(int returnCode)
|
||||
{
|
||||
QGuiApplication::exit(returnCode);
|
||||
}
|
||||
|
||||
Q_DECL_EXPORT QCoreApplication* qapp_internalPointer(QGuiApplicationContainer* container)
|
||||
{
|
||||
return container->app;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -20,8 +20,8 @@ struct QGuiApplicationContainer {
|
|||
int argCount;
|
||||
QList<QString> args;
|
||||
std::vector<char*> argsPointer;
|
||||
QGuiApplication* guiApp;
|
||||
bool ownsGuiApp;
|
||||
QCoreApplication* app;
|
||||
bool ownsApp;
|
||||
QSharedPointer<GuiThreadContextTriggerCallback> callback;
|
||||
};
|
||||
|
||||
|
|
@ -1,78 +0,0 @@
|
|||
#include <QmlNet/qml/QGuiApplication.h>
|
||||
#include <QmlNet/qml/NetVariantList.h>
|
||||
#include <QGuiApplication>
|
||||
|
||||
GuiThreadContextTriggerCallback::GuiThreadContextTriggerCallback() :
|
||||
callback(nullptr) {
|
||||
}
|
||||
|
||||
void GuiThreadContextTriggerCallback::trigger() {
|
||||
if (callback) {
|
||||
callback();
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
|
||||
Q_DECL_EXPORT QGuiApplicationContainer* qguiapplication_create(NetVariantListContainer* argsContainer, QGuiApplication* existingApp) {
|
||||
QGuiApplicationContainer* result = new QGuiApplicationContainer();
|
||||
|
||||
if (existingApp != nullptr) {
|
||||
result->ownsGuiApp = false;
|
||||
result->guiApp = existingApp;
|
||||
} else {
|
||||
result->ownsGuiApp = true;
|
||||
// Build our args
|
||||
if(argsContainer != nullptr) {
|
||||
QSharedPointer<NetVariantList> args = argsContainer->list;
|
||||
for(int x = 0; x < args->count(); x++) {
|
||||
QByteArray arg = args->get(x)->getString().toLatin1();
|
||||
result->args.append(arg);
|
||||
char* cstr = new char [size_t(arg.size())+1];
|
||||
memcpy(cstr, arg.data(), size_t(arg.size())+1);
|
||||
result->argsPointer.push_back(cstr);
|
||||
}
|
||||
result->argCount = result->args.size();
|
||||
} else {
|
||||
result->argCount = 0;
|
||||
}
|
||||
result->guiApp = new QGuiApplication(result->argCount, &result->argsPointer[0], 0);
|
||||
}
|
||||
|
||||
result->callback = QSharedPointer<GuiThreadContextTriggerCallback>(new GuiThreadContextTriggerCallback());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
Q_DECL_EXPORT void qguiapplication_destroy(QGuiApplicationContainer* container) {
|
||||
for (auto i : container->argsPointer) {
|
||||
delete[] i;
|
||||
}
|
||||
container->callback.clear();
|
||||
if(container->ownsGuiApp) {
|
||||
delete container->guiApp;
|
||||
}
|
||||
delete container;
|
||||
}
|
||||
|
||||
Q_DECL_EXPORT int qguiapplication_exec() {
|
||||
return QGuiApplication::exec();
|
||||
}
|
||||
|
||||
Q_DECL_EXPORT void qguiapplication_addTriggerCallback(QGuiApplicationContainer* container, guiThreadTriggerCb callback) {
|
||||
container->callback->callback = callback;
|
||||
}
|
||||
|
||||
Q_DECL_EXPORT void qguiapplication_requestTrigger(QGuiApplicationContainer* container) {
|
||||
QMetaObject::invokeMethod(container->callback.data(), "trigger", Qt::QueuedConnection);
|
||||
}
|
||||
|
||||
Q_DECL_EXPORT void qguiapplication_exit(int returnCode) {
|
||||
QGuiApplication::exit(returnCode);
|
||||
}
|
||||
|
||||
Q_DECL_EXPORT QGuiApplication* qguiapplication_internalPointer(QGuiApplicationContainer* container) {
|
||||
return container->guiApp;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,5 +1,4 @@
|
|||
HEADERS += \
|
||||
$$PWD/QGuiApplication.h \
|
||||
$$PWD/QQmlApplicationEngine.h \
|
||||
$$PWD/NetVariant.h \
|
||||
$$PWD/NetValue.h \
|
||||
|
|
@ -14,10 +13,10 @@ HEADERS += \
|
|||
$$PWD/NetValueMetaObjectPacker.h \
|
||||
$$PWD/QCommon.h \
|
||||
$$PWD/NetListModel.h \
|
||||
$$PWD/QtWebEngine.h
|
||||
$$PWD/QtWebEngine.h \
|
||||
$$PWD/QCoreApplication.h
|
||||
|
||||
SOURCES += \
|
||||
$$PWD/QGuiApplication.cpp \
|
||||
$$PWD/QQmlApplicationEngine.cpp \
|
||||
$$PWD/NetVariant.cpp \
|
||||
$$PWD/NetValue.cpp \
|
||||
|
|
@ -32,4 +31,5 @@ SOURCES += \
|
|||
$$PWD/NetValueMetaObjectPacker.cpp \
|
||||
$$PWD/QCommon.cpp \
|
||||
$$PWD/NetListModel.cpp \
|
||||
$$PWD/QtWebEngine.cpp
|
||||
$$PWD/QtWebEngine.cpp \
|
||||
$$PWD/QCoreApplication.cpp
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ using System.Linq;
|
|||
using System.Runtime.InteropServices;
|
||||
using NetNativeLibLoader.Loader;
|
||||
using NetNativeLibLoader.PathResolver;
|
||||
using Qml.Net.Internal;
|
||||
|
||||
namespace Qml.Net
|
||||
{
|
||||
|
|
@ -47,7 +48,7 @@ namespace Qml.Net
|
|||
|
||||
public delegate int NetRunCallbackDelegate();
|
||||
|
||||
public static int Run(string[] args, Func<string[], QGuiApplication, QQmlApplicationEngine, NetRunCallbackDelegate, int> action)
|
||||
public static int Run(string[] args, Func<string[], QCoreApplication, QQmlApplicationEngine, NetRunCallbackDelegate, int> action)
|
||||
{
|
||||
if (args.Length < 4)
|
||||
{
|
||||
|
|
@ -60,7 +61,23 @@ namespace Qml.Net
|
|||
var exportedSymbolPtr = new IntPtr((long)ulong.Parse(args[3]));
|
||||
GetExportedSymbol = Marshal.GetDelegateForFunctionPointer<GetExportedSymbolDelegate>(exportedSymbolPtr);
|
||||
|
||||
using (var app = new QGuiApplication(appPtr))
|
||||
QCoreApplication app = null;
|
||||
switch (Interop.QCoreApplication.GetAppType(IntPtr.Zero, appPtr))
|
||||
{
|
||||
case 0:
|
||||
app = new QCoreApplication(appPtr);
|
||||
break;
|
||||
case 1:
|
||||
app = new QGuiApplication(appPtr);
|
||||
break;
|
||||
case 2:
|
||||
app = new QApplication(appPtr);
|
||||
break;
|
||||
default:
|
||||
throw new Exception("Invalid app type");
|
||||
}
|
||||
|
||||
using (app)
|
||||
{
|
||||
using (var engine = new QQmlApplicationEngine(enginePtr))
|
||||
{
|
||||
|
|
|
|||
|
|
@ -99,7 +99,7 @@ namespace Qml.Net.Internal
|
|||
NetMethodInfo = LoadInteropType<NetMethodInfoInterop>(library, loader);
|
||||
NetPropertyInfo = LoadInteropType<NetPropertyInfoInterop>(library, loader);
|
||||
NetTypeManager = LoadInteropType<NetTypeManagerInterop>(library, loader);
|
||||
QGuiApplication = LoadInteropType<QGuiApplicationInterop>(library, loader);
|
||||
QCoreApplication = LoadInteropType<QCoreApplicationInterop>(library, loader);
|
||||
QQmlApplicationEngine = LoadInteropType<QQmlApplicationEngineInterop>(library, loader);
|
||||
NetVariant = LoadInteropType<NetVariantInterop>(library, loader);
|
||||
NetReference = LoadInteropType<NetReferenceInterop>(library, loader);
|
||||
|
|
@ -136,7 +136,7 @@ namespace Qml.Net.Internal
|
|||
|
||||
public static NetTypeManagerInterop NetTypeManager { get; }
|
||||
|
||||
public static QGuiApplicationInterop QGuiApplication { get; }
|
||||
public static QCoreApplicationInterop QCoreApplication { get; }
|
||||
|
||||
public static QQmlApplicationEngineInterop QQmlApplicationEngine { get; }
|
||||
|
||||
|
|
|
|||
25
src/net/Qml.Net/QApplication.cs
Normal file
25
src/net/Qml.Net/QApplication.cs
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Threading;
|
||||
using Qml.Net.Internal;
|
||||
|
||||
namespace Qml.Net
|
||||
{
|
||||
public class QApplication : QCoreApplication
|
||||
{
|
||||
public QApplication()
|
||||
: this(null)
|
||||
{
|
||||
}
|
||||
|
||||
public QApplication(string[] args, int flags = 0)
|
||||
: base(1, args, flags)
|
||||
{
|
||||
}
|
||||
|
||||
internal QApplication(IntPtr existingApp)
|
||||
: base(existingApp)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
202
src/net/Qml.Net/QCoreApplication.cs
Normal file
202
src/net/Qml.Net/QCoreApplication.cs
Normal file
|
|
@ -0,0 +1,202 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Threading;
|
||||
using Qml.Net.Internal;
|
||||
using Qml.Net.Internal.Qml;
|
||||
|
||||
namespace Qml.Net
|
||||
{
|
||||
public class QCoreApplication : BaseDisposable
|
||||
{
|
||||
private readonly Queue<Action> _actionQueue = new Queue<Action>();
|
||||
private readonly SynchronizationContext _oldSynchronizationContext;
|
||||
private GCHandle _triggerHandle;
|
||||
|
||||
protected QCoreApplication(IntPtr handle, bool ownsHandle)
|
||||
: base(handle, ownsHandle)
|
||||
{
|
||||
}
|
||||
|
||||
public QCoreApplication()
|
||||
: this(null)
|
||||
{
|
||||
}
|
||||
|
||||
public QCoreApplication(string[] args, int flags = 0)
|
||||
: this(0, args, flags)
|
||||
{
|
||||
}
|
||||
|
||||
internal QCoreApplication(int type, string[] args, int flags)
|
||||
: base(Create(type, args?.ToList(), flags))
|
||||
{
|
||||
TriggerDelegate triggerDelegate = Trigger;
|
||||
_triggerHandle = GCHandle.Alloc(triggerDelegate);
|
||||
|
||||
Interop.QCoreApplication.AddTriggerCallback(Handle, Marshal.GetFunctionPointerForDelegate(triggerDelegate));
|
||||
|
||||
_oldSynchronizationContext = SynchronizationContext.Current;
|
||||
SynchronizationContext.SetSynchronizationContext(new QtSynchronizationContext(this));
|
||||
}
|
||||
|
||||
internal QCoreApplication(IntPtr existingApp)
|
||||
: base(CreateFromExisting(existingApp))
|
||||
{
|
||||
TriggerDelegate triggerDelegate = Trigger;
|
||||
_triggerHandle = GCHandle.Alloc(triggerDelegate);
|
||||
|
||||
Interop.QCoreApplication.AddTriggerCallback(Handle, Marshal.GetFunctionPointerForDelegate(triggerDelegate));
|
||||
|
||||
_oldSynchronizationContext = SynchronizationContext.Current;
|
||||
SynchronizationContext.SetSynchronizationContext(new QtSynchronizationContext(this));
|
||||
}
|
||||
|
||||
public int Exec()
|
||||
{
|
||||
return Interop.QCoreApplication.Exec();
|
||||
}
|
||||
|
||||
public void Dispatch(Action action)
|
||||
{
|
||||
lock (_actionQueue)
|
||||
{
|
||||
_actionQueue.Enqueue(action);
|
||||
}
|
||||
RequestTrigger();
|
||||
}
|
||||
|
||||
public void Exit(int returnCode = 0)
|
||||
{
|
||||
Interop.QCoreApplication.Exit(returnCode);
|
||||
}
|
||||
|
||||
public void Quit()
|
||||
{
|
||||
Exit();
|
||||
}
|
||||
|
||||
private void RequestTrigger()
|
||||
{
|
||||
Interop.QCoreApplication.RequestTrigger(Handle);
|
||||
}
|
||||
|
||||
internal IntPtr InternalPointer => Interop.QCoreApplication.InternalPointer(Handle);
|
||||
|
||||
private void Trigger()
|
||||
{
|
||||
Action action;
|
||||
lock (_actionQueue)
|
||||
{
|
||||
action = _actionQueue.Dequeue();
|
||||
}
|
||||
action?.Invoke();
|
||||
}
|
||||
|
||||
protected override void DisposeUnmanaged(IntPtr ptr)
|
||||
{
|
||||
SynchronizationContext.SetSynchronizationContext(_oldSynchronizationContext);
|
||||
Interop.QCoreApplication.Destroy(ptr);
|
||||
_triggerHandle.Free();
|
||||
}
|
||||
|
||||
private static IntPtr CreateFromExisting(IntPtr app)
|
||||
{
|
||||
return Interop.QCoreApplication.FromExisting(app);
|
||||
}
|
||||
|
||||
private static IntPtr Create(int type, List<string> args, int flags)
|
||||
{
|
||||
if (args == null)
|
||||
{
|
||||
args = new List<string>();
|
||||
}
|
||||
|
||||
// By default, the argv[0] should be the process name.
|
||||
// .NET doesn't pass that name, but Qt should get it
|
||||
// since it does in a normal Qt environment.
|
||||
args.Insert(0, System.Diagnostics.Process.GetCurrentProcess().ProcessName);
|
||||
|
||||
using (var strings = new NetVariantList())
|
||||
{
|
||||
foreach (var arg in args)
|
||||
{
|
||||
using (var variant = new NetVariant())
|
||||
{
|
||||
variant.String = arg;
|
||||
strings.Add(variant);
|
||||
}
|
||||
}
|
||||
|
||||
return Interop.QCoreApplication.Create(strings.Handle, flags, type);
|
||||
}
|
||||
}
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
private delegate void TriggerDelegate();
|
||||
|
||||
private class QtSynchronizationContext : SynchronizationContext
|
||||
{
|
||||
readonly QCoreApplication _app;
|
||||
|
||||
public QtSynchronizationContext(QCoreApplication guiApp)
|
||||
{
|
||||
_app = guiApp;
|
||||
}
|
||||
|
||||
public override void Post(SendOrPostCallback d, object state)
|
||||
{
|
||||
_app.Dispatch(() => d.Invoke(state));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal class QCoreApplicationInterop
|
||||
{
|
||||
[NativeSymbol(Entrypoint = "qapp_fromExisting")]
|
||||
public FromExistingDel FromExisting { get; set; }
|
||||
|
||||
public delegate IntPtr FromExistingDel(IntPtr rawPointer);
|
||||
|
||||
[NativeSymbol(Entrypoint = "qapp_create")]
|
||||
public CreateDel Create { get; set; }
|
||||
|
||||
public delegate IntPtr CreateDel(IntPtr args, int flags, int type);
|
||||
|
||||
[NativeSymbol(Entrypoint = "qapp_destroy")]
|
||||
public DestroyDel Destroy { get; set; }
|
||||
|
||||
[NativeSymbol(Entrypoint = "qapp_getType")]
|
||||
public GetAppTypeDel GetAppType { get; set; }
|
||||
|
||||
public delegate int GetAppTypeDel(IntPtr container, IntPtr rawPointer);
|
||||
|
||||
public delegate void DestroyDel(IntPtr container);
|
||||
|
||||
[NativeSymbol(Entrypoint = "qapp_exec")]
|
||||
public ExecDel Exec { get; set; }
|
||||
|
||||
public delegate int ExecDel();
|
||||
|
||||
[NativeSymbol(Entrypoint = "qapp_addTriggerCallback")]
|
||||
public AddTriggerCallbackDel AddTriggerCallback { get; set; }
|
||||
|
||||
public delegate void AddTriggerCallbackDel(IntPtr app, IntPtr callback);
|
||||
|
||||
[NativeSymbol(Entrypoint = "qapp_requestTrigger")]
|
||||
public RequestTriggerDel RequestTrigger { get; set; }
|
||||
|
||||
public delegate void RequestTriggerDel(IntPtr app);
|
||||
|
||||
[NativeSymbol(Entrypoint = "qapp_exit")]
|
||||
public ExitDel Exit { get; set; }
|
||||
|
||||
public delegate void ExitDel(int returnCode);
|
||||
|
||||
[NativeSymbol(Entrypoint = "qapp_internalPointer")]
|
||||
public InternalPointerDel InternalPointer { get; set; }
|
||||
|
||||
public delegate IntPtr InternalPointerDel(IntPtr app);
|
||||
}
|
||||
}
|
||||
|
|
@ -8,175 +8,21 @@ using Qml.Net.Internal.Qml;
|
|||
|
||||
namespace Qml.Net
|
||||
{
|
||||
public sealed class QGuiApplication : BaseDisposable
|
||||
public class QGuiApplication : QCoreApplication
|
||||
{
|
||||
readonly Queue<Action> _actionQueue = new Queue<Action>();
|
||||
GCHandle _triggerHandle;
|
||||
readonly SynchronizationContext _oldSynchronizationContext;
|
||||
|
||||
public QGuiApplication()
|
||||
: this(null)
|
||||
{
|
||||
}
|
||||
|
||||
public QGuiApplication(string[] args)
|
||||
: base(Create(args?.ToList()))
|
||||
public QGuiApplication(string[] args, int flags = 0)
|
||||
: base(1, args, flags)
|
||||
{
|
||||
TriggerDelegate triggerDelegate = Trigger;
|
||||
_triggerHandle = GCHandle.Alloc(triggerDelegate);
|
||||
|
||||
Interop.QGuiApplication.AddTriggerCallback(Handle, Marshal.GetFunctionPointerForDelegate(triggerDelegate));
|
||||
|
||||
_oldSynchronizationContext = SynchronizationContext.Current;
|
||||
SynchronizationContext.SetSynchronizationContext(new QtSynchronizationContext(this));
|
||||
}
|
||||
|
||||
internal QGuiApplication(IntPtr existingApp)
|
||||
: base(CreateFromExisting(existingApp))
|
||||
: base(existingApp)
|
||||
{
|
||||
TriggerDelegate triggerDelegate = Trigger;
|
||||
_triggerHandle = GCHandle.Alloc(triggerDelegate);
|
||||
|
||||
Interop.QGuiApplication.AddTriggerCallback(Handle, Marshal.GetFunctionPointerForDelegate(triggerDelegate));
|
||||
|
||||
_oldSynchronizationContext = SynchronizationContext.Current;
|
||||
SynchronizationContext.SetSynchronizationContext(new QtSynchronizationContext(this));
|
||||
}
|
||||
|
||||
public int Exec()
|
||||
{
|
||||
return Interop.QGuiApplication.Exec();
|
||||
}
|
||||
|
||||
public void Dispatch(Action action)
|
||||
{
|
||||
lock (_actionQueue)
|
||||
{
|
||||
_actionQueue.Enqueue(action);
|
||||
}
|
||||
RequestTrigger();
|
||||
}
|
||||
|
||||
public void Exit(int returnCode = 0)
|
||||
{
|
||||
Interop.QGuiApplication.Exit(returnCode);
|
||||
}
|
||||
|
||||
public void Quit()
|
||||
{
|
||||
Exit();
|
||||
}
|
||||
|
||||
private void RequestTrigger()
|
||||
{
|
||||
Interop.QGuiApplication.RequestTrigger(Handle);
|
||||
}
|
||||
|
||||
internal IntPtr InternalPointer => Interop.QGuiApplication.InternalPointer(Handle);
|
||||
|
||||
private void Trigger()
|
||||
{
|
||||
Action action;
|
||||
lock (_actionQueue)
|
||||
{
|
||||
action = _actionQueue.Dequeue();
|
||||
}
|
||||
action?.Invoke();
|
||||
}
|
||||
|
||||
protected override void DisposeUnmanaged(IntPtr ptr)
|
||||
{
|
||||
SynchronizationContext.SetSynchronizationContext(_oldSynchronizationContext);
|
||||
Interop.QGuiApplication.Destroy(ptr);
|
||||
_triggerHandle.Free();
|
||||
}
|
||||
|
||||
private static IntPtr CreateFromExisting(IntPtr app)
|
||||
{
|
||||
return Interop.QGuiApplication.Create(IntPtr.Zero, app);
|
||||
}
|
||||
|
||||
private static IntPtr Create(List<string> args)
|
||||
{
|
||||
if (args == null)
|
||||
{
|
||||
args = new List<string>();
|
||||
}
|
||||
|
||||
// By default, the argv[0] should be the process name.
|
||||
// .NET doesn't pass that name, but Qt should get it
|
||||
// since it does in a normal Qt environment.
|
||||
args.Insert(0, System.Diagnostics.Process.GetCurrentProcess().ProcessName);
|
||||
|
||||
using (var strings = new NetVariantList())
|
||||
{
|
||||
foreach (var arg in args)
|
||||
{
|
||||
using (var variant = new NetVariant())
|
||||
{
|
||||
variant.String = arg;
|
||||
strings.Add(variant);
|
||||
}
|
||||
}
|
||||
|
||||
return Interop.QGuiApplication.Create(strings.Handle, IntPtr.Zero);
|
||||
}
|
||||
}
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
private delegate void TriggerDelegate();
|
||||
|
||||
private class QtSynchronizationContext : SynchronizationContext
|
||||
{
|
||||
readonly QGuiApplication _guiApp;
|
||||
|
||||
public QtSynchronizationContext(QGuiApplication guiApp)
|
||||
{
|
||||
_guiApp = guiApp;
|
||||
}
|
||||
|
||||
public override void Post(SendOrPostCallback d, object state)
|
||||
{
|
||||
_guiApp.Dispatch(() => d.Invoke(state));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal class QGuiApplicationInterop
|
||||
{
|
||||
[NativeSymbol(Entrypoint = "qguiapplication_create")]
|
||||
public CreateDel Create { get; set; }
|
||||
|
||||
public delegate IntPtr CreateDel(IntPtr args, IntPtr existingApp);
|
||||
|
||||
[NativeSymbol(Entrypoint = "qguiapplication_destroy")]
|
||||
public DestroyDel Destroy { get; set; }
|
||||
|
||||
public delegate void DestroyDel(IntPtr app);
|
||||
|
||||
[NativeSymbol(Entrypoint = "qguiapplication_exec")]
|
||||
public ExecDel Exec { get; set; }
|
||||
|
||||
public delegate int ExecDel();
|
||||
|
||||
[NativeSymbol(Entrypoint = "qguiapplication_addTriggerCallback")]
|
||||
public AddTriggerCallbackDel AddTriggerCallback { get; set; }
|
||||
|
||||
public delegate void AddTriggerCallbackDel(IntPtr app, IntPtr callback);
|
||||
|
||||
[NativeSymbol(Entrypoint = "qguiapplication_requestTrigger")]
|
||||
public RequestTriggerDel RequestTrigger { get; set; }
|
||||
|
||||
public delegate void RequestTriggerDel(IntPtr app);
|
||||
|
||||
[NativeSymbol(Entrypoint = "qguiapplication_exit")]
|
||||
public ExitDel Exit { get; set; }
|
||||
|
||||
public delegate void ExitDel(int returnCode);
|
||||
|
||||
[NativeSymbol(Entrypoint = "qguiapplication_internalPointer")]
|
||||
public InternalPointerDel InternalPointer { get; set; }
|
||||
|
||||
public delegate IntPtr InternalPointerDel(IntPtr app);
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue