All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.qt.internal.NativeUtility Maven / Gradle / Ivy

/****************************************************************************
**
** Copyright (C) 2009-2024 Dr. Peter Droste, Omix Visualization GmbH & Co. KG. All rights reserved.
**
** This file is part of Qt Jambi.
**
** $BEGIN_LICENSE$
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
** 
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3.0 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU General Public License version 3.0 requirements will be
** met: http://www.gnu.org/copyleft/gpl.html.
** $END_LICENSE$

**
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
**
****************************************************************************/
package io.qt.internal;

import java.io.File;
import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.logging.Level;

import io.qt.InternalAccess.Cleanable;
import io.qt.NativeAccess;
import io.qt.QNoNativeResourcesException;
import io.qt.QtObject;
import io.qt.QtObjectInterface;
import io.qt.QtUninvokable;
import io.qt.QtUtilities;
import io.qt.QtUtilities.LibraryRequirementMode;
import io.qt.core.QMetaObject;
import io.qt.core.QObject;

/**
 * @hidden
 */
public abstract class NativeUtility {
	private static final java.util.logging.Logger CLEANUP_LOGGER = java.util.logging.Logger.getLogger("io.qt.cleanup");
	private static Function disposedSignalFactory;
	private static final Map interfaceLinks;
	private static final Map disposedSignals;
	private static final Thread cleanupRegistrationThread;
	static {
		interfaceLinks = Collections.synchronizedMap(new HashMap<>());
		disposedSignals = Collections.synchronizedMap(new TreeMap<>());
		cleanupRegistrationThread = new Thread(QueuedCleaner::cleanup);
		cleanupRegistrationThread.setName("QtJambiCleanupThread");
		cleanupRegistrationThread.setDaemon(true);
		QtJambi_LibraryUtilities.initialize();
		cleanupRegistrationThread.start();
	}

	@NativeAccess
	@QtUninvokable
	private static void terminateCleanupThread() throws Throwable {
		switch (cleanupRegistrationThread.getState()) {
		case TERMINATED:
			break;
		default:
			cleanupRegistrationThread.interrupt();
			cleanupRegistrationThread.join();
			break;
		}
	}
	
	static abstract class QueuedCleaner extends WeakReference implements Cleanable {
		private static final ReferenceQueue referenceQueue = new ReferenceQueue<>();
		
		QueuedCleaner(Ref object) {
			super(object, referenceQueue);
		}
		
		static void cleanup() {
			while (true) {
				if(Thread.interrupted())
					break;
				try {
					Reference ref = referenceQueue.remove();
					try {
						if(Thread.interrupted())
							break;
						if (ref instanceof Cleanable) {
							((Cleanable) ref).clean();
							if(Thread.interrupted())
								break;
						}
					} finally {
						ref = null;
					}
				} catch (InterruptedException e) {
					break;
				} catch (Throwable e) {
					e.printStackTrace();
				}
				if(Thread.interrupted())
					break;
			}
		}
	}
	
	static final class Factories{
		static final Function new_NativeLink;
		static final Function new_PureInterfaceNativeLink;
		static final Function new_ReferenceCountingNativeLink;
		static final BiFunction, io.qt.MemberAccess>, MemberAccessReferenceCountingNativeLink> new_MemberAccessReferenceCountingNativeLink;
		static final BiFunction, io.qt.MemberAccess>, MemberAccessPureInterfaceNativeLink> new_MemberAccessPureInterfaceNativeLink;
		static {
			if(Boolean.getBoolean("io.qt.enable-cleanup-logs")) {
				new_NativeLink = LoggingNativeLink::new;
				new_ReferenceCountingNativeLink = ReferenceCountingLoggingNativeLink::new;
				new_MemberAccessPureInterfaceNativeLink = MemberAccessPureInterfaceLoggingNativeLink::new;
				new_PureInterfaceNativeLink = PureInterfaceLoggingNativeLink::new;
				new_MemberAccessReferenceCountingNativeLink = MemberAccessReferenceCountingLoggingNativeLink::new;
			}else {
				new_NativeLink = NativeLink::new;
				new_ReferenceCountingNativeLink = ReferenceCountingNativeLink::new;
				new_MemberAccessPureInterfaceNativeLink = MemberAccessPureInterfaceNativeLink::new;
				new_PureInterfaceNativeLink = PureInterfaceNativeLink::new;
				new_MemberAccessReferenceCountingNativeLink = MemberAccessReferenceCountingNativeLink::new;
			}
		}		
	}

	static class NativeLink extends QueuedCleaner {

		private NativeLink(QtObjectInterface object) {
			super(object);
		}

		private long native__id = 0;
		private QtObjectInterface referent__strong;

		@NativeAccess
		private final void detach(long native__id, boolean hasDisposedSignal) {
			synchronized (this) {
				if (this.native__id == native__id) {
					this.native__id = 0;
					this.referent__strong = null;
				}else {
					return;
				}
			}
			if (hasDisposedSignal) {
				QMetaObject.DisposedSignal disposed = takeSignalOnDispose(native__id);
				if (disposed != null) {
					try {
						disposed.emitSignal();
					} catch (Throwable e) {
						CLEANUP_LOGGER.log(Level.WARNING, "Exception occurred during DisposedSignal emit.", e);
					}
					disposed.disconnect();
				}
			}
			enqueue();
		}

		@Override
		public synchronized void clean() {
			if (native__id != 0) {
				clean(native__id);
			}
		}
		
		@Override
		public void dismiss() {
		}

		@NativeAccess
		private final void reset(long native__id, boolean hasDisposedSignal) {
			synchronized (this) {
				if (this.native__id == native__id) {
					this.native__id = 0;
					this.referent__strong = null;
				}else {
					return;
				}
			}
			if (hasDisposedSignal) {
				QMetaObject.DisposedSignal disposed = takeSignalOnDispose(native__id);
				if (disposed != null)
					disposed.disconnect();
			}
		}

		private static native void clean(long native__id);
		private static native void setHasDisposedSignal(long native__id);

		synchronized void dispose() {
			if (native__id != 0) {
				dispose(native__id);
			}
		}

		final synchronized boolean isDisposed() {
			return native__id == 0;
		}

		private static native void dispose(long native__id);

		private static native String qtTypeName(long native__id);

		io.qt.MemberAccess getMemberAccess(Class interfaceClass) {
			throw new RuntimeException("Requesting member access of non-interface object is not permitted.");
		}

		void initialize(NativeUtility.Object obj) {
		}

		@Override
		public final String toString() {
			QtObjectInterface o = super.get();
			if (o != null) {
				return AccessUtility.instance.getClass(o).getName() + "@" + Integer.toHexString(System.identityHashCode(o));
			} else {
				String qtTypeName = null;
				synchronized (this) {
					if (native__id != 0) {
						qtTypeName = qtTypeName(native__id);
					}
				}
				if (qtTypeName != null)
					return qtTypeName + "[disposed]";
				return super.toString();
			}
		}

		@Override
		public synchronized int hashCode() {
			return Long.hashCode(native__id);
		}

		@Override
		public boolean equals(java.lang.Object obj) {
			if (this == obj)
				return true;
			if (obj instanceof NativeLink)
				return equals((NativeLink) obj);
			return false;
		}
		
		synchronized boolean equals(NativeLink other) {
			return native__id == other.native__id;
		}

		@NativeAccess
		public final synchronized long nativeId() {
			return native__id;
		}
		
		@NativeAccess
		public final synchronized void assignNativeId(long ptr) {
			assignNativeId(native__id, ptr);
		}
		
		private static native void assignNativeId(long native__id, long ptr);

		@Override
		@NativeAccess
		public final synchronized QtObjectInterface get() {
			return referent__strong==null ? super.get() : referent__strong;
		}
		
		final synchronized QtObjectInterface weak() {
			return super.get();
		}

		@NativeAccess
		private final synchronized void releaseOwnership() {
			this.referent__strong = null;
		}
		
		@NativeAccess
		private final synchronized void takeOwnership() {
			this.referent__strong = super.get();
		}
		
		@NativeAccess
		private final void initialize(long nativeId){
			if(native__id==0)
				this.native__id = nativeId;
		}
	}
	
	private static class LoggingNativeLink extends NativeLink {
		
		private final Class cls;
		private final int hashCode;
		private LoggingNativeLink(QtObjectInterface object) {
			super(object);
			cls = AccessUtility.instance.getClass(object);
			hashCode = System.identityHashCode(object);
		}
		
		@Override
		public synchronized void clean() {
			if (nativeId() != 0) {
				NativeUtility.CLEANUP_LOGGER.log(Level.FINE, ()->String.format("Begin cleanup of 0x%1$s@%2$s...", Integer.toHexString(hashCode), cls.getName()));
				super.clean();
				NativeUtility.CLEANUP_LOGGER.log(Level.FINE, ()->String.format("Cleanup of 0x%1$s@%2$s finished.", Integer.toHexString(hashCode), cls.getName()));
			}
		}
	}
	
	static class ReferenceCountingNativeLink extends NativeLink {
		private ReferenceCountingNativeLink(QtObjectInterface object) {
			super(object);
		}
		
		private Map, Map> referenceCounts;

		public void setReferenceCount(Class declaringClass, String fieldName,
				java.lang.Object newValue) {
			if (referenceCounts == null) {
				referenceCounts = Collections.synchronizedMap(new HashMap<>());
			}
			Map referenceCountsVariables = referenceCounts.computeIfAbsent(declaringClass,
					c -> Collections.synchronizedMap(new HashMap<>()));
			referenceCountsVariables.put(fieldName, newValue);
		}
		
		public java.lang.Object getReferenceCount(Class declaringClass, String fieldName) {
			if (referenceCounts != null) {
				Map referenceCountsVariables = referenceCounts.get(declaringClass);
				if(referenceCountsVariables!=null)
					return referenceCountsVariables.get(fieldName);
			}return null;
		}

		public java.lang.Object getReferenceCountCollection(Class declaringClass, String fieldName,
				Supplier collectionSupplier) {
			if (referenceCounts == null) {
				if (collectionSupplier != null) {
					referenceCounts = Collections.synchronizedMap(new HashMap<>());
					Map referenceCountsVariables = referenceCounts.computeIfAbsent(declaringClass,
							c -> Collections.synchronizedMap(new HashMap<>()));
					java.lang.Object result = collectionSupplier.get();
					referenceCountsVariables.put(fieldName, result);
					return result;
				} else {
					return null;
				}
			} else {
				if (collectionSupplier != null) {
					return referenceCounts
							.computeIfAbsent(declaringClass, c -> Collections.synchronizedMap(new HashMap<>()))
							.computeIfAbsent(fieldName, _fieldName -> collectionSupplier.get());
				} else {
					return referenceCounts
							.computeIfAbsent(declaringClass, c -> Collections.synchronizedMap(new HashMap<>()))
							.get(fieldName);
				}
			}
		}

		@Override
		public synchronized void clean() {
			referenceCounts = null;
			super.clean();
		}

		void initialize(NativeUtility.Object obj) {
			initializeNativeObject(obj, this);
		}
	}
	
	private static class ReferenceCountingLoggingNativeLink extends ReferenceCountingNativeLink {
		private final Class cls;
		private final int hashCode;
		private ReferenceCountingLoggingNativeLink(QtObjectInterface object) {
			super(object);
			cls = AccessUtility.instance.getClass(object);
			hashCode = System.identityHashCode(object);
		}
		
		@Override
		public synchronized void clean() {
			if (nativeId() != 0) {
				NativeUtility.CLEANUP_LOGGER.log(Level.FINE, ()->String.format("Begin cleanup of 0x%1$s@%2$s...", Integer.toHexString(hashCode), cls.getName()));
				super.clean();
				NativeUtility.CLEANUP_LOGGER.log(Level.FINE, ()->String.format("Cleanup of 0x%1$s@%2$s finished.", Integer.toHexString(hashCode), cls.getName()));
			}
		}
	}

	private static class MemberAccessReferenceCountingNativeLink extends ReferenceCountingNativeLink {

		private final Map, io.qt.MemberAccess> memberAccesses;

		private MemberAccessReferenceCountingNativeLink(QtObjectInterface object, Map, io.qt.MemberAccess> memberAccesses) {
			super(object);
			this.memberAccesses = memberAccesses;
		}

		io.qt.MemberAccess getMemberAccess(Class interfaceClass) {
			return memberAccesses.get(interfaceClass);
		}
	}
	
	private static final class MemberAccessReferenceCountingLoggingNativeLink extends MemberAccessReferenceCountingNativeLink {
		private final Class cls;
		private final int hashCode;
		private MemberAccessReferenceCountingLoggingNativeLink(QtObjectInterface object, Map, io.qt.MemberAccess> memberAccesses) {
			super(object, memberAccesses);
			cls = AccessUtility.instance.getClass(object);
			hashCode = System.identityHashCode(object);
		}
		
		@Override
		public synchronized void clean() {
			if (nativeId() != 0) {
				NativeUtility.CLEANUP_LOGGER.log(Level.FINE, ()->String.format("Begin cleanup of 0x%1$s@%2$s...", Integer.toHexString(hashCode), cls.getName()));
				super.clean();
				NativeUtility.CLEANUP_LOGGER.log(Level.FINE, ()->String.format("Cleanup of 0x%1$s@%2$s finished.", Integer.toHexString(hashCode), cls.getName()));
			}
		}
	}

	private static class MemberAccessPureInterfaceNativeLink extends MemberAccessReferenceCountingNativeLink {
		final int ownerHashCode;

		private MemberAccessPureInterfaceNativeLink(QtObjectInterface object, Map, io.qt.MemberAccess> memberAccesses) {
			super(object, memberAccesses);
			ownerHashCode = System.identityHashCode(object);
			interfaceLinks.put(ownerHashCode, this);
		}

		@Override
		public synchronized void clean() {
			super.clean();
			interfaceLinks.remove(ownerHashCode);
		}
		
		@Override
		synchronized void dispose() {
			super.dispose();
			interfaceLinks.remove(ownerHashCode);
		}
	}
	
	private static class MemberAccessPureInterfaceLoggingNativeLink extends MemberAccessPureInterfaceNativeLink {
		private final Class cls;
		private MemberAccessPureInterfaceLoggingNativeLink(QtObjectInterface object, Map, io.qt.MemberAccess> memberAccesses) {
			super(object, memberAccesses);
			cls = AccessUtility.instance.getClass(object);
		}
		
		@Override
		public synchronized void clean() {
			if (nativeId() != 0) {
				NativeUtility.CLEANUP_LOGGER.log(Level.FINE, ()->String.format("Begin cleanup of 0x%1$s@%2$s...", Integer.toHexString(ownerHashCode), cls.getName()));
				super.clean();
				NativeUtility.CLEANUP_LOGGER.log(Level.FINE, ()->String.format("Cleanup of 0x%1$s@%2$s finished.", Integer.toHexString(ownerHashCode), cls.getName()));
			}
		}
	}
	
	private static class PureInterfaceNativeLink extends ReferenceCountingNativeLink {
		final int ownerHashCode;

		private PureInterfaceNativeLink(QtObjectInterface object) {
			super(object);
			ownerHashCode = System.identityHashCode(object);
			interfaceLinks.put(ownerHashCode, this);
		}

		@Override
		public synchronized void clean() {
			super.clean();
			interfaceLinks.remove(ownerHashCode);
		}
		
		@Override
		synchronized void dispose() {
			super.dispose();
			interfaceLinks.remove(ownerHashCode);
		}
	}
	
	private static class PureInterfaceLoggingNativeLink extends PureInterfaceNativeLink {
		private final Class cls;
		private PureInterfaceLoggingNativeLink(QtObjectInterface object) {
			super(object);
			cls = AccessUtility.instance.getClass(object);
		}
		
		@Override
		public synchronized void clean() {
			if (nativeId() != 0) {
				NativeUtility.CLEANUP_LOGGER.log(Level.FINE, ()->String.format("Begin cleanup of 0x%1$s@%2$s...", Integer.toHexString(ownerHashCode), cls.getName()));
				super.clean();
				NativeUtility.CLEANUP_LOGGER.log(Level.FINE, ()->String.format("Cleanup of 0x%1$s@%2$s finished.", Integer.toHexString(ownerHashCode), cls.getName()));
			}
		}
	}

	static NativeLink findInterfaceLink(QtObjectInterface iface, boolean forceCreation) {
		return findInterfaceLink(iface, forceCreation, forceCreation);
	}

	@NativeAccess
	private static NativeLink findInterfaceLink(QtObjectInterface iface, boolean forceCreation, boolean initialize) {
		if (iface instanceof NativeUtility.Object) {
			return ((NativeUtility.Object) iface).nativeLink;
		} else if (iface!=null){
			NativeLink link = interfaceLinks.get(System.identityHashCode(iface));
			if (link == null && forceCreation) {
				link = createNativeLink(iface);
				if (link == null) {
					link = Factories.new_PureInterfaceNativeLink.apply(iface);
				}else if (initialize) {
					initializeNativeObject(iface, link);
				}
			}
			return link;
		}else return null;
	}
	
	@NativeAccess
	private static void findAndAssignInterfaceLink(QtObjectInterface iface, boolean forceCreation, boolean initialize, long ptr) {
		NativeLink nl = findInterfaceLink(iface, forceCreation, initialize);
		if(nl!=null)
			nl.assignNativeId(ptr);
	}

	/**
	 * Emitted either as the native resources that belong to the object are being
	 * cleaned up or directly before the object is finalized. Connect to this signal
	 * to do clean up when the object is destroyed. The signal will never be emitted
	 * more than once per object, and the object is guaranteed to be unusable after
	 * this signal has returned.
	 */
	protected static QMetaObject.DisposedSignal getSignalOnDispose(QtObjectInterface object, boolean forceCreation) {
		return getSignalOnDispose(findInterfaceLink(object, forceCreation), forceCreation);
	}

	private static QMetaObject.DisposedSignal getSignalOnDispose(NativeLink nativeLink, boolean forceCreation) {
		if (nativeLink != null) {
			long native__id = nativeLink.nativeId();
			if(native__id!=0) {
				if (forceCreation) {
					NativeLink.setHasDisposedSignal(native__id);
					try {
						return disposedSignals.computeIfAbsent(native__id, id -> {
							Class declaringClass;
							if(nativeLink instanceof LoggingNativeLink) {
								declaringClass = ((LoggingNativeLink) nativeLink).cls;
							}else {
								QtObjectInterface object = nativeLink.weak();
								declaringClass = AccessUtility.instance.getClass(object);
								object = null;
							}
							if(disposedSignalFactory==null)
								disposedSignalFactory = SignalUtility.getSignalFactory(QMetaObject.DisposedSignal.class);
							return disposedSignalFactory.apply(declaringClass);
						});
					} catch (NullPointerException e) {
						e.printStackTrace();
					}
				} else
					return disposedSignals.get(native__id);
			}
		}
		return null;
	}

	private static QMetaObject.DisposedSignal takeSignalOnDispose(long native__id) {
		return disposedSignals.remove(native__id);
	}

	private static Map, io.qt.MemberAccess> findMemberAccesses(QtObjectInterface object){
		Map, Function>> interfaceInfos = getInterfaceInfos(object);
		Map, io.qt.MemberAccess> memberAccesses;
		if (interfaceInfos != null) {
			memberAccesses = new HashMap<>();
			for (Map.Entry, Function>> entry : interfaceInfos.entrySet()) {
				Function> factory = entry.getValue();
				if (factory != null) {
					try {
						io.qt.MemberAccess memberAccess = factory.apply(object);
						if(memberAccess!=null)
							memberAccesses.put(entry.getKey(), memberAccess);
					} catch (Throwable e) {
						e.printStackTrace();
					}
				}
			}
		}else {
			memberAccesses = null;
		}
		return memberAccesses;
	}

	private static NativeLink createNativeLink(NativeUtility.Object object) {
		Map, io.qt.MemberAccess> memberAccesses = findMemberAccesses(object);
		if (memberAccesses != null) {
			if(memberAccesses.isEmpty())
				return Factories.new_ReferenceCountingNativeLink.apply(object);
			else
				return Factories.new_MemberAccessReferenceCountingNativeLink.apply(object, Collections.unmodifiableMap(memberAccesses));
		} else {
			return Factories.new_NativeLink.apply(object);
		}
	}

	private static NativeLink createNativeLink(QtObjectInterface iface) {
		Map, io.qt.MemberAccess> memberAccesses = findMemberAccesses(iface);
		if (memberAccesses != null) {
			if(memberAccesses.isEmpty())
				return Factories.new_PureInterfaceNativeLink.apply(iface);
			else
				return Factories.new_MemberAccessPureInterfaceNativeLink.apply(iface, Collections.unmodifiableMap(memberAccesses));
		} else {
			return null;
		}
	}

	protected static void initializeNativeObject(Class declaringClass, QtObjectInterface object, Map, List> arguments) throws IllegalArgumentException {
		initializeNativeObject(declaringClass, object, NativeUtility.findInterfaceLink(object, true, false), arguments);
	}

	private native static void initializeNativeObject(Class callingClass, QtObjectInterface object, NativeLink link, Map, List> arguments) throws IllegalArgumentException;

	static void initializeNativeObject(QtObjectInterface object, NativeLink link) throws IllegalArgumentException {
		Class cls = AccessUtility.instance.getClass(object);
		QtUtilities.initializePackage(cls);
		initializeNativeObject(cls, object, link, Collections.emptyMap());
	}
	
	/**
	 * @hidden
	 */
	protected static abstract class Object implements QtObjectInterface
	{
	    static {
	    	QtJambi_LibraryUtilities.initialize();
	    }

	    protected Object(){
	    	nativeLink = createNativeLink(this);
			nativeLink.initialize(this);
	    }
	    
	    protected Object(java.lang.Object privateConstructor){
	    	nativeLink = createNativeLink(this);
	    }
	    
		@Override
	    public void dispose() {
	    	nativeLink.dispose();
	    }
	    
	    @QtUninvokable
		@Override
	    public boolean isDisposed() {
	    	return nativeLink.isDisposed();
	    }
	    
	    @Override
	    public boolean equals(java.lang.Object other) {
	    	Boolean result = NativeUtility.areObjectsEquals(this, other);
	    	return result!=null ? result : super.equals(other);
	    }

	    final @NativeAccess NativeLink nativeLink;
	    
	    @NativeAccess
		private void assignNativeLink(long ptr) {
	    	nativeLink.assignNativeId(ptr);
	    }
	}

	protected static void disposeObject(NativeUtility.Object object) {
		object.nativeLink.dispose();
	}

	protected static boolean isObjectDisposed(NativeUtility.Object object) {
		return object.nativeLink.isDisposed();
	}
	
	protected static void disposeObject(QtObjectInterface object) {
		NativeLink lnk = findInterfaceLink(object, false);
		if (lnk != null) {
			lnk.dispose();
		}
	}

	protected static boolean isObjectDisposed(QtObjectInterface object) {
		NativeLink lnk = findInterfaceLink(object, true);
		return lnk == null || lnk.isDisposed();
	}

	protected static Boolean areObjectsEquals(NativeUtility.Object object, java.lang.Object other) {
		if (other instanceof NativeUtility.Object)
			return object.nativeLink.equals(((NativeUtility.Object) other).nativeLink);
		else
			return null;
	}

	private static class AssociativeReference extends QueuedCleaner {
		
		private static final List associativeReferences = new ArrayList<>();
		
		private java.lang.Object association;

		AssociativeReference(java.lang.Object reference, java.lang.Object association) {
			super(reference);
			this.association = association;
			if(association!=null) {
				synchronized(associativeReferences) {
					associativeReferences.add(this);
				}
				if(reference instanceof QtObjectInterface) {
					QMetaObject.DisposedSignal disposed = getSignalOnDispose((QtObjectInterface)reference, true);
					if (disposed != null) {
						if(LibraryUtility.operatingSystem==LibraryUtility.OperatingSystem.Android) {
							WeakReference weakThis = new WeakReference<>(this);
							disposed.connect(()->{
								AssociativeReference _this = weakThis.get();
								if(_this!=null)
									_this.enqueue();
							});
						}else {
							disposed.connect(this::enqueue);
						}
					}
				}
				if(association instanceof QtObjectInterface) {
					QMetaObject.DisposedSignal disposed = getSignalOnDispose((QtObjectInterface)association, true);
					if (disposed != null) {
						if(LibraryUtility.operatingSystem==LibraryUtility.OperatingSystem.Android) {
							WeakReference weakThis = new WeakReference<>(this);
							disposed.connect(()->{
								AssociativeReference _this = weakThis.get();
								if(_this!=null)
									_this.enqueue();
							});
						}else {
							disposed.connect(this::enqueue);
						}
					}
				}
			}
		}

		@Override
		public void clean() {
			if(this.association!=null) {
				this.association = null;
				synchronized(associativeReferences) {
					associativeReferences.remove(this);
				}
			}
		}
		
		@Override
		public boolean enqueue() {
			clean();
			return super.enqueue();
		}
		
		@Override
		public void dismiss() {
			enqueue();
		}

		java.lang.Object association() {
			return association;
		}
		
		static List findAll(java.lang.Object reference) {
			List result = new ArrayList<>();
			synchronized(associativeReferences) {
				for (AssociativeReference ref : associativeReferences) {
					if(ref.get() == reference) {
						result.add(ref);
					}
				}
			}
			return result;
		}
		
		static AssociativeReference findAllByHashCode(int hashCode) {
			synchronized(associativeReferences) {
				for (AssociativeReference ref : associativeReferences) {
					if(System.identityHashCode(ref) == hashCode) {
						return ref;
					}
				}
			}
			return null;
		}
	}

	@NativeAccess
	private static int createAssociation(java.lang.Object o1, java.lang.Object o2) {
		return System.identityHashCode(new AssociativeReference(o1, o2));
	}

	@NativeAccess
	private static boolean deleteAssociation(java.lang.Object o1) {
		boolean result = false;
		for(AssociativeReference matchingReference : AssociativeReference.findAll(o1)) {
			if (matchingReference != null) {
				matchingReference.enqueue();
				result = true;
			}
		}
		return result;
	}
	
	@NativeAccess
	private static java.lang.Object deleteAssociationByHashCode(int hashCode) {
		java.lang.Object result = null;
		AssociativeReference matchingReference = AssociativeReference.findAllByHashCode(hashCode);
		if (matchingReference != null) {
			result = matchingReference.association;
			matchingReference.enqueue();
		}
		return result;
	}
	
	@NativeAccess
	private static java.lang.Object findAssociation(java.lang.Object o1) {
		List matchingReferences = AssociativeReference.findAll(o1);
		return matchingReferences.isEmpty() ? null : matchingReferences.get(0).association();
	}

	static class FinalizerReference extends QueuedCleaner {
		private final AtomicReference runnableRef = new AtomicReference();
	
		FinalizerReference(Ref referent) {
			super(referent);
		}
		
		FinalizerReference(Ref referent, Runnable runnable) {
			super(referent);
			runnableRef.set(runnable);
		}
	
		@Override
		public void clean() {
			Runnable runnable = runnableRef.getAndSet(null);
			if(runnable!=null)
				runnable.run();
		}
		
		void setFinally(Runnable runnable) {
			runnableRef.set(runnable);
		}
		
		@Override
		public boolean enqueue() {
			runnableRef.set(null);
			return super.enqueue();
		}
		
		@Override
		public void dismiss() {
			enqueue();
		}
	}
	
	private static class CleaningReference extends FinalizerReference {
		private static final List cleaningReferences = new ArrayList<>();
		
		CleaningReference(java.lang.Object referent, Runnable runnable) {
			super(referent, runnable);
			synchronized (cleaningReferences) {
				cleaningReferences.add(this);
			}
		}
		
		@Override
		public void clean() {
			super.clean();
			synchronized (cleaningReferences) {
				cleaningReferences.remove(this);
			}
		}
		
		@Override
		public boolean enqueue() {
			synchronized (cleaningReferences) {
				cleaningReferences.remove(this);
			}
			return super.enqueue();
		}
	}

	static Cleanable registerCleaner(java.lang.Object object, Runnable action) {
		return new CleaningReference(object, action);
	}

	protected static void loadQtJambiLibrary(Class callerClass, String library) {
		LibraryUtility.loadQtJambiLibrary(callerClass, library);
	}
	
	protected static void loadJambiLibrary(Class callerClass, String library) {
		LibraryUtility.loadJambiLibrary(callerClass, library);
	}

	protected static boolean isAvailableQtLibrary(Class callerClass, String library) {
		return LibraryUtility.isAvailableQtLibrary(callerClass, library);
	}

	protected static boolean isAvailableLibrary(String library, String version) {
		return LibraryUtility.isAvailableLibrary(library, version);
	}

	protected static void loadQtLibrary(Class callerClass, String library, LibraryRequirementMode libraryRequirementMode, String...platforms) {
		LibraryUtility.loadQtLibrary(callerClass, library, libraryRequirementMode, platforms);
	}

	protected static void loadUtilityLibrary(String library, String version, LibraryRequirementMode libraryRequirementMode, String...platforms) {
		LibraryUtility.loadUtilityLibrary(library, version, libraryRequirementMode, platforms);
	}

	protected static void loadLibrary(String lib) {
		LibraryUtility.loadLibrary(lib);
	}
	
	protected static void useAsGadget(Class clazz) {
		MetaObjectUtility.useAsGadget(clazz);
    }
    
	protected static void usePackageContentAsGadgets(String _package) {
    	MetaObjectUtility.usePackageContentAsGadgets(_package);
    }
	
	protected static File jambiDeploymentDir() {
		return LibraryUtility.jambiDeploymentDir();
	}

	protected static Supplier> callerClassProvider() {
		return RetroHelper.callerClassProvider();
	}

	protected static int majorVersion() {
		return QtJambi_LibraryUtilities.qtMajorVersion;
	}
	
	protected static int minorVersion() {
		return QtJambi_LibraryUtilities.qtMinorVersion;
	}
	
	protected static int qtjambiPatchVersion() {
		return QtJambi_LibraryUtilities.qtJambiPatch;
	}

	static boolean isSplitOwnership(Object object) {
		return isSplitOwnership(nativeId(object));
	}
	
	static boolean isCppOwnership(Object object) {
		return isCppOwnership(nativeId(object));
	}
	
	static boolean isJavaOwnership(Object object) {
		return isJavaOwnership(nativeId(object));
	}
	
	static boolean isSplitOwnership(QtObjectInterface object) {
		return isSplitOwnership(nativeId(object));
	}
	
	static boolean isCppOwnership(QtObjectInterface object) {
		return isCppOwnership(nativeId(object));
	}
	
	static boolean isJavaOwnership(QtObjectInterface object) {
		return isJavaOwnership(nativeId(object));
	}
	
	static void setCppOwnership(QtObjectInterface object) {
		setCppOwnership(nativeId(object));
	}
	
	static void setCppOwnership(Object object) {
		setCppOwnership(nativeId(object));
	}
	
	static void setJavaOwnership(QtObjectInterface object) {
		setJavaOwnership(nativeId(object));
	}
	
	static void setJavaOwnership(Object object) {
		setJavaOwnership(nativeId(object));
	}
	
	static void setDefaultOwnership(QtObjectInterface object) {
		setDefaultOwnership(nativeId(object));
	}
	
	static void setDefaultOwnership(Object object) {
		setDefaultOwnership(nativeId(object));
	}
	
	static void invalidateObject(QtObjectInterface object) {
		invalidateObject(nativeId(object));
	}
	
	static void invalidateObject(Object object) {
		invalidateObject(nativeId(object));
	}
	
	static boolean hasOwnerFunction(Object object) {
		return hasOwnerFunction(nativeId(object));
	}
	
	static boolean hasOwnerFunction(QtObjectInterface object) {
		return hasOwnerFunction(nativeId(object));
	}
	
	static QObject owner(Object object) {
		return owner(nativeId(object));
	}
	
	static QObject owner(QtObjectInterface object) {
		return owner(nativeId(object));
	}
	
	static long nativeId(QtObjectInterface object) {
		NativeLink nativeLink = NativeUtility.findInterfaceLink(object, true);
		if (nativeLink != null) {
			return nativeLink.nativeId();
		}
		return 0;
	}
	
	static long nativeId(Object obj) {
		if (obj != null && obj.nativeLink != null) {
			return obj.nativeLink.nativeId();
		}
		return 0;
	}

	static long checkedNativeId(QtObject object) {
		if(object==null)
			return 0;
		try {
			long nid = nativeId(object);
			if (nid == 0) {
				QNoNativeResourcesException e = new QNoNativeResourcesException(
						"Function call on incomplete object of type: " + AccessUtility.instance.getClass(object).getName());
				StackTraceElement[] st = e.getStackTrace();
				st = Arrays.copyOfRange(st, 1, st.length);
				e.setStackTrace(st);
				throw e;
			}
			return nid;
		} catch (NullPointerException e) {
			StackTraceElement[] st = e.getStackTrace();
			st = Arrays.copyOfRange(st, 1, st.length);
			e.setStackTrace(st);
			throw e;
		}
	}

	static long checkedNativeId(QtObjectInterface object) {
		if(object==null)
			return 0;
		long nid = nativeId(object);
		if (nid == 0) {
			QNoNativeResourcesException e = new QNoNativeResourcesException(
					"Function call on incomplete object of type: " + AccessUtility.instance.getClass(object).getName());
			StackTraceElement[] st = e.getStackTrace();
			st = Arrays.copyOfRange(st, 1, st.length);
			e.setStackTrace(st);
			throw e;
		}
		return nid;
	}
	
	private native static java.nio.ByteBuffer mutableByteArrayData(long nid);
	
	private native static java.nio.CharBuffer mutableStringData(long nid);
	
	private native static java.nio.ByteBuffer mutableDataB(io.qt.QtObject iter, long nid);
	
	private native static java.nio.ShortBuffer mutableDataS(io.qt.QtObject iter, long nid);
	
	private native static java.nio.IntBuffer mutableDataI(io.qt.QtObject iter, long nid);
	
	private native static java.nio.LongBuffer mutableDataJ(io.qt.QtObject iter, long nid);
	
	private native static java.nio.CharBuffer mutableDataC(io.qt.QtObject iter, long nid);
	
	private native static java.nio.FloatBuffer mutableDataF(io.qt.QtObject iter, long nid);
	
	private native static java.nio.DoubleBuffer mutableDataD(io.qt.QtObject iter, long nid);
	
	private native static void truncateBuffer(long nid, java.nio.Buffer buffer);
	
	static void truncateBuffer(io.qt.QtObjectInterface owner, java.nio.Buffer buffer){
		truncateBuffer(checkedNativeId(owner), buffer);
	}
	
	static void truncateBuffer(io.qt.QtObject owner, java.nio.Buffer buffer){
		truncateBuffer(checkedNativeId(owner), buffer);
	}
	
	static java.nio.ByteBuffer mutableData(io.qt.core.QByteArray byteArray){
		return mutableByteArrayData(checkedNativeId(byteArray));
	}
	
	static java.nio.CharBuffer mutableData(io.qt.core.QString string){
		return mutableStringData(checkedNativeId(string));
	}
	
	static > java.nio.CharBuffer mutableDataC(C list){
		return mutableDataC(list, checkedNativeId(list));
	}
    
	static > java.nio.ByteBuffer mutableDataB(C list){
		return mutableDataB(list, checkedNativeId(list));
	}
    
	static > java.nio.ShortBuffer mutableDataS(C list){
		return mutableDataS(list, checkedNativeId(list));
	}
    
	static > java.nio.IntBuffer mutableDataI(C list){
		return mutableDataI(list, checkedNativeId(list));
	}
    
	static > java.nio.LongBuffer mutableDataJ(C list){
		return mutableDataJ(list, checkedNativeId(list));
	}
    
	static > java.nio.FloatBuffer mutableDataF(C list){
		return mutableDataF(list, checkedNativeId(list));
	}
    
	static > java.nio.DoubleBuffer mutableDataD(C list){
		return mutableDataD(list, checkedNativeId(list));
	}

	static void registerDependentObject(QtObjectInterface dependentObject, QtObjectInterface owner) {
		registerDependentObject(nativeId(dependentObject), nativeId(owner));
	}

	static void registerDependentObject(Object dependentObject, QtObjectInterface owner) {
		registerDependentObject(nativeId(dependentObject), nativeId(owner));
	}

	static void registerDependentObject(QtObjectInterface dependentObject, Object owner) {
		registerDependentObject(nativeId(dependentObject), nativeId(owner));
	}

	static void registerDependentObject(QtObject dependentObject, Object owner) {
		registerDependentObject(nativeId(dependentObject), nativeId(owner));
	}

	static void unregisterDependentObject(QtObjectInterface dependentObject, QtObjectInterface owner) {
		unregisterDependentObject(nativeId(dependentObject), nativeId(owner));
	}

	static void unregisterDependentObject(Object dependentObject, QtObjectInterface owner) {
		unregisterDependentObject(nativeId(dependentObject), nativeId(owner));
	}

	static void unregisterDependentObject(QtObjectInterface dependentObject, Object owner) {
		unregisterDependentObject(nativeId(dependentObject), nativeId(owner));
	}

	static void unregisterDependentObject(QtObject dependentObject, Object owner) {
		unregisterDependentObject(nativeId(dependentObject), nativeId(owner));
	}

	private static native void setCppOwnership(long native__id);

	private static native void setDefaultOwnership(long native__id);

	private static native void setJavaOwnership(long native__id);
	
	private static native boolean isCppOwnership(long native__id);

	private static native boolean isSplitOwnership(long native__id);

	static native boolean isJavaOwnership(long native__id);

	private static native void invalidateObject(long native__id);
	
	private static native QObject owner(long native__id);

	private static native boolean hasOwnerFunction(long native__id);

	private native static void registerDependentObject(long dependentObject, long owner);

	private native static void unregisterDependentObject(long dependentObject, long owner);
	
	private native static Map, Function>> getInterfaceInfos(QtObjectInterface object);
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy