mirror of
https://github.com/LMMS/lmms.git
synced 2026-01-25 06:48:55 -05:00
made VST support layer work on native win32
git-svn-id: https://lmms.svn.sf.net/svnroot/lmms/trunk/lmms@1546 0778d3d1-df1d-0410-868b-ea421aaaa00d
This commit is contained in:
@@ -258,7 +258,7 @@ ENDIF(WANT_SF2)
|
||||
|
||||
|
||||
# check for WINE
|
||||
if(WANT_VST)
|
||||
IF(WANT_VST)
|
||||
INCLUDE(CheckLibraryExists)
|
||||
INCLUDE(CheckIncludeFileCXX)
|
||||
SET(CMAKE_REQUIRED_FLAGS_ORIG ${CMAKE_REQUIRED_FLAGS})
|
||||
@@ -276,11 +276,15 @@ if(WANT_VST)
|
||||
SET(CMAKE_REQUIRED_INCLUDES ${CMAKE_REQUIRED_INCLUDES_ORIG})
|
||||
IF(HAVE_LIBWINE AND HAVE_WINDOWS_H)
|
||||
SET(LMMS_HAVE_VST TRUE)
|
||||
SET(STATUS_WINE "OK")
|
||||
SET(STATUS_VST "OK")
|
||||
ELSE(HAVE_LIBWINE AND HAVE_WINDOWS_H)
|
||||
SET(STATUS_WINE "not found, please install (lib)wine-dev (or similiar) - 64 bit systems additionally need gcc-multilib and g++-multilib")
|
||||
SET(STATUS_VST "not found, please install (lib)wine-dev (or similiar) - 64 bit systems additionally need gcc-multilib and g++-multilib")
|
||||
ENDIF(HAVE_LIBWINE AND HAVE_WINDOWS_H)
|
||||
ENDIF(WANT_VST)
|
||||
IF(LMMS_BUILD_WIN32)
|
||||
SET(LMMS_HAVE_VST TRUE)
|
||||
SET(STATUS_VST "OK")
|
||||
ENDIF(LMMS_BUILD_WIN32)
|
||||
|
||||
|
||||
# check for libsamplerate
|
||||
@@ -515,8 +519,8 @@ MESSAGE(
|
||||
"----------------\n"
|
||||
"* SoundFont2 player : ${STATUS_FLUIDSYNTH}\n"
|
||||
"* Stk Mallets : ${STATUS_STK}\n"
|
||||
"* VST-instrument hoster : ${STATUS_WINE}\n"
|
||||
"* VST-effect hoster : ${STATUS_WINE}\n"
|
||||
"* VST-instrument hoster : ${STATUS_VST}\n"
|
||||
"* VST-effect hoster : ${STATUS_VST}\n"
|
||||
"* SpectrumAnalyzer : ${STATUS_FFTW3F}\n"
|
||||
"* CAPS LADSPA plugins : ${STATUS_CAPS}\n"
|
||||
"* TAP LADSPA plugins : ${STATUS_TAP}\n"
|
||||
|
||||
12
ChangeLog
12
ChangeLog
@@ -1,3 +1,15 @@
|
||||
2008-09-04 Tobias Doerffel <tobydox/at/users/dot/sourceforge/dot/net>
|
||||
|
||||
* plugins/vst_base/vst_plugin.h:
|
||||
* plugins/vst_base/remote_vst_plugin.cpp:
|
||||
* plugins/vst_base/communication.h:
|
||||
* plugins/vst_base/vst_plugin.cpp:
|
||||
* plugins/vst_base/CMakeLists.txt:
|
||||
* include/text_float.h:
|
||||
* include/remote_plugin.h:
|
||||
* CMakeLists.txt:
|
||||
made VST support layer work on native win32
|
||||
|
||||
2008-09-03 Tobias Doerffel <tobydox/at/users/dot/sourceforge/dot/net>
|
||||
|
||||
* plugins/vst_base/communication.h:
|
||||
|
||||
@@ -40,6 +40,8 @@
|
||||
#include <process.h>
|
||||
#endif
|
||||
|
||||
#include <Qt/qglobal.h>
|
||||
|
||||
#if QT_VERSION >= 0x040400
|
||||
#include <QtCore/QSharedMemory>
|
||||
#include <QtCore/QSystemSemaphore>
|
||||
|
||||
@@ -29,8 +29,10 @@
|
||||
#include <QtGui/QWidget>
|
||||
#include <QtGui/QPixmap>
|
||||
|
||||
#include "export.h"
|
||||
|
||||
class textFloat : public QWidget
|
||||
|
||||
class EXPORT textFloat : public QWidget
|
||||
{
|
||||
public:
|
||||
textFloat( void );
|
||||
|
||||
@@ -4,6 +4,18 @@ INCLUDE(BuildPlugin)
|
||||
|
||||
BUILD_PLUGIN(vstbase vst_base.cpp vst_plugin.cpp vst_plugin.h communication.h MOCFILES vst_plugin.h)
|
||||
|
||||
|
||||
IF(LMMS_BUILD_WIN32)
|
||||
|
||||
ADD_DEFINITIONS(-DPTW32_STATIC_LIB)
|
||||
LINK_LIBRARIES(-lQtCore4 -lpthread -lgdi32 -lwsock32)
|
||||
ADD_EXECUTABLE(remote_vst_plugin ${CMAKE_CURRENT_SOURCE_DIR}/remote_vst_plugin.cpp)
|
||||
|
||||
ENDIF(LMMS_BUILD_WIN32)
|
||||
|
||||
|
||||
IF(LMMS_BUILD_LINUX)
|
||||
|
||||
IF(LMMS_HOST_X86_64)
|
||||
SET(EXTRA_FLAGS -m32 -Wb,--as-cmd='as --32',--ld-cmd='ld -melf_i386' -L/usr/lib32)
|
||||
ENDIF(LMMS_HOST_X86_64)
|
||||
@@ -19,4 +31,7 @@ SET_DIRECTORY_PROPERTIES(PROPERTIES ADDITIONAL_MAKE_CLEAN_FILES remote_vst_plugi
|
||||
|
||||
INSTALL(PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/remote_vst_plugin ${CMAKE_CURRENT_BINARY_DIR}/remote_vst_plugin.exe.so DESTINATION ${PLUGIN_DIR})
|
||||
|
||||
ENDIF(LMMS_BUILD_LINUX)
|
||||
|
||||
|
||||
ENDIF(LMMS_HAVE_VST)
|
||||
|
||||
@@ -55,6 +55,7 @@ enum VstRemoteMessageIDs
|
||||
{
|
||||
// vstPlugin -> remoteVstPlugin
|
||||
IdVstLoadPlugin = IdUserBase,
|
||||
IdVstPluginWindowInformation,
|
||||
IdVstClosePlugin,
|
||||
IdVstSetTempo,
|
||||
IdVstSetLanguage,
|
||||
|
||||
@@ -38,13 +38,22 @@
|
||||
#include <pthread.h>
|
||||
#endif
|
||||
|
||||
#ifdef LMMS_BUILD_LINUX
|
||||
|
||||
#ifdef LMMS_HAVE_SCHED_H
|
||||
#include <sched.h>
|
||||
#endif
|
||||
|
||||
#include <wine/exception.h>
|
||||
|
||||
#endif
|
||||
|
||||
#include <windows.h>
|
||||
#include <wine/exception.h>
|
||||
|
||||
#ifdef LMMS_BUILD_WIN32
|
||||
#include <libgen.h>
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#include <list>
|
||||
@@ -76,6 +85,7 @@ struct ERect
|
||||
#include "communication.h"
|
||||
|
||||
|
||||
#if 0
|
||||
#ifdef LMMS_HAVE_TLS
|
||||
static __thread int ejmpbuf_valid = false;
|
||||
static __thread jmp_buf ejmpbuf;
|
||||
@@ -83,6 +93,7 @@ static __thread jmp_buf ejmpbuf;
|
||||
static pthread_key_t ejmpbuf_valid_key;
|
||||
static pthread_key_t ejmpbuf_key;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
static VstHostLanguages hlang = LanguageEnglish;
|
||||
@@ -105,15 +116,6 @@ public:
|
||||
|
||||
void init( const std::string & _plugin_file );
|
||||
|
||||
void showEditor( void )
|
||||
{
|
||||
if( m_window != NULL )
|
||||
{
|
||||
PostThreadMessageA( m_guiThreadID, WM_USER, ShowEditor,
|
||||
0 );
|
||||
}
|
||||
}
|
||||
|
||||
virtual bool process( const sampleFrame * _in, sampleFrame * _out );
|
||||
|
||||
|
||||
@@ -190,9 +192,9 @@ public:
|
||||
|
||||
|
||||
private:
|
||||
enum guiThreadMessages
|
||||
enum GuiThreadMessages
|
||||
{
|
||||
None, ShowEditor, ClosePlugin
|
||||
None, ClosePlugin
|
||||
} ;
|
||||
|
||||
// callback used by plugin for being able to communicate with it's host
|
||||
@@ -252,6 +254,8 @@ remoteVstPlugin::remoteVstPlugin( key_t _shm_in, key_t _shm_out ) :
|
||||
m_bpm( 0 ),
|
||||
m_currentSamplePos( 0 )
|
||||
{
|
||||
pthread_mutex_init( &m_lock, NULL );
|
||||
pthread_cond_init( &m_windowStatusChange, NULL );
|
||||
}
|
||||
|
||||
|
||||
@@ -266,9 +270,12 @@ remoteVstPlugin::~remoteVstPlugin()
|
||||
{
|
||||
//lvsMessage( "could not post message to gui thread" );
|
||||
}
|
||||
pthread_mutex_lock( &m_lock );
|
||||
pthread_cond_wait( &m_windowStatusChange, &m_lock );
|
||||
m_plugin->dispatcher( m_plugin, effEditClose, 0, 0, NULL, 0.0 );
|
||||
#ifdef LMMS_BUILD_LINUX
|
||||
CloseWindow( m_window );
|
||||
#endif
|
||||
m_window = NULL;
|
||||
}
|
||||
|
||||
@@ -280,6 +287,9 @@ remoteVstPlugin::~remoteVstPlugin()
|
||||
|
||||
delete[] m_inputs;
|
||||
delete[] m_outputs;
|
||||
|
||||
pthread_mutex_destroy( &m_lock );
|
||||
pthread_cond_destroy( &m_windowStatusChange );
|
||||
}
|
||||
|
||||
|
||||
@@ -293,9 +303,15 @@ bool remoteVstPlugin::processMessage( const message & _m )
|
||||
init( _m.getString() );
|
||||
break;
|
||||
|
||||
case IdShowUI:
|
||||
showEditor();
|
||||
#ifdef LMMS_BUILD_WIN32
|
||||
case IdVstPluginWindowInformation:
|
||||
{
|
||||
HWND top = FindWindowEx( NULL, NULL, NULL,
|
||||
_m.getString().c_str() );
|
||||
m_window = FindWindowEx( top, NULL, NULL, NULL );
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
case IdVstSetTempo:
|
||||
setBPM( _m.getInt() );
|
||||
@@ -350,18 +366,16 @@ void remoteVstPlugin::init( const std::string & _plugin_file )
|
||||
fprintf( stderr, "could not create GUI-thread\n" );
|
||||
return;
|
||||
}
|
||||
pthread_cond_wait( &m_windowStatusChange, &m_lock);
|
||||
pthread_mutex_lock( &m_lock );
|
||||
pthread_cond_wait( &m_windowStatusChange, &m_lock );
|
||||
|
||||
|
||||
// now post some information about our plugin
|
||||
sendMessage( message( IdVstPluginWindowID ).addInt( m_windowID ) );
|
||||
|
||||
if( m_windowID != 0 )
|
||||
{
|
||||
sendMessage( message( IdVstPluginEditorGeometry ).
|
||||
sendMessage( message( IdVstPluginEditorGeometry ).
|
||||
addInt( m_windowWidth ).
|
||||
addInt( m_windowHeight ) );
|
||||
}
|
||||
|
||||
sendMessage( message( IdVstPluginName ).addString( pluginName() ) );
|
||||
sendMessage( message( IdVstPluginVersion ).addInt( pluginVersion() ) );
|
||||
@@ -480,9 +494,6 @@ bool remoteVstPlugin::process( const sampleFrame * _in, sampleFrame * _out )
|
||||
|
||||
m_currentSamplePos += bufferSize();
|
||||
|
||||
// give plugin some idle-time for GUI-update and so on...
|
||||
m_plugin->dispatcher( m_plugin, effEditIdle, 0, 0, NULL, 0 );
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -984,6 +995,7 @@ DWORD WINAPI remoteVstPlugin::guiEventLoop( LPVOID _param )
|
||||
remoteVstPlugin * _this = static_cast<remoteVstPlugin *>( _param );
|
||||
_this->m_guiThreadID = GetCurrentThreadId();
|
||||
|
||||
#if 0
|
||||
// "guard point" to trap errors that occur during plugin loading
|
||||
#ifdef LMMS_HAVE_TLS
|
||||
if( sigsetjmp( ejmpbuf, 1 ) )
|
||||
@@ -1005,12 +1017,17 @@ DWORD WINAPI remoteVstPlugin::guiEventLoop( LPVOID _param )
|
||||
pthread_key_create( &ejmpbuf_valid_key, NULL );
|
||||
pthread_setspecific( ejmpbuf_valid_key, ejmpbuf_valid );
|
||||
|
||||
#ifdef LMMS_BUILD_WIN32
|
||||
if( setjmp( *ejmpbuf ) )
|
||||
#else
|
||||
if( sigsetjmp( *ejmpbuf, 1 ) )
|
||||
#endif
|
||||
{
|
||||
exit( 1 );
|
||||
}
|
||||
|
||||
*ejmpbuf_valid = true;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Note: m_lock is held while this function is called
|
||||
@@ -1029,21 +1046,27 @@ DWORD WINAPI remoteVstPlugin::guiEventLoop( LPVOID _param )
|
||||
return( 1 );
|
||||
}
|
||||
|
||||
#ifdef LMMS_BUILD_LINUX
|
||||
if( ( _this->m_window = CreateWindowExA(
|
||||
0, "LVSL", _this->m_shortName.c_str(),
|
||||
( WS_OVERLAPPEDWINDOW & ~WS_THICKFRAME &
|
||||
( WS_OVERLAPPEDWINDOW | WS_THICKFRAME &
|
||||
~WS_MAXIMIZEBOX ),
|
||||
0, 0, 1, 1, NULL, NULL, hInst, NULL ) ) == NULL )
|
||||
0, 0, 10, 10,
|
||||
NULL, NULL, hInst, NULL ) ) == NULL )
|
||||
{
|
||||
fprintf( stderr, "cannot create editor window\n" );
|
||||
pthread_cond_signal( &_this->m_windowStatusChange );
|
||||
return( 1 );
|
||||
}
|
||||
ShowWindow( _this->m_window, SW_SHOWMINIMIZED );
|
||||
ShowWindow( _this->m_window, SW_HIDE );
|
||||
|
||||
ShowWindow( _this->m_window, SW_SHOWNORMAL );
|
||||
|
||||
_this->m_windowID = (Sint32) GetPropA( _this->m_window,
|
||||
"__wine_x11_whole_window" );
|
||||
#else
|
||||
_this->m_windowID = 1; // arbitrary value on win32 to signal
|
||||
// vstPlugin-class that we have an editor
|
||||
#endif
|
||||
|
||||
|
||||
_this->m_plugin->dispatcher( _this->m_plugin, effEditOpen, 0, 0,
|
||||
@@ -1055,23 +1078,28 @@ DWORD WINAPI remoteVstPlugin::guiEventLoop( LPVOID _param )
|
||||
|
||||
_this->m_windowWidth = er->right - er->left;
|
||||
_this->m_windowHeight = er->bottom - er->top;
|
||||
|
||||
|
||||
SetWindowPos( _this->m_window, 0, 0, 0, _this->m_windowWidth + 8,
|
||||
_this->m_windowHeight + 26, 0
|
||||
_this->m_windowHeight + 26, SWP_SHOWWINDOW );
|
||||
|
||||
UpdateWindow( _this->m_window );
|
||||
|
||||
#if 0
|
||||
SWP_NOACTIVATE /*| SWP_NOREDRAW*/ | SWP_NOMOVE |
|
||||
SWP_NOOWNERZORDER | SWP_NOZORDER
|
||||
#endif
|
||||
);
|
||||
#ifdef LMMS_HAVE_TLS
|
||||
ejmpbuf_valid = false;
|
||||
#else
|
||||
*ejmpbuf_valid = false;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
pthread_cond_signal( &_this->m_windowStatusChange );
|
||||
|
||||
|
||||
HWND timer_window = CreateWindowEx( 0, "LVSL", "dummy",
|
||||
0, 0, 0, 0, 0, NULL, NULL, hInst, NULL );
|
||||
// install GUI update timer
|
||||
SetTimer( timer_window, 1000, 50, NULL );
|
||||
|
||||
MSG msg;
|
||||
|
||||
bool quit = false;
|
||||
@@ -1080,16 +1108,17 @@ DWORD WINAPI remoteVstPlugin::guiEventLoop( LPVOID _param )
|
||||
TranslateMessage( &msg );
|
||||
DispatchMessageA( &msg );
|
||||
|
||||
if( msg.message == WM_USER )
|
||||
if( msg.message == WM_TIMER )
|
||||
{
|
||||
// give plugin some idle-time for GUI-update
|
||||
_this->m_plugin->dispatcher( _this->m_plugin,
|
||||
effEditIdle, 0, 0,
|
||||
NULL, 0 );
|
||||
}
|
||||
else if( msg.message == WM_USER )
|
||||
{
|
||||
switch( msg.wParam )
|
||||
{
|
||||
case ShowEditor:
|
||||
ShowWindow( _this->m_window,
|
||||
SW_SHOWNORMAL );
|
||||
UpdateWindow( _this->m_window );
|
||||
break;
|
||||
|
||||
case ClosePlugin:
|
||||
quit = true;
|
||||
break;
|
||||
@@ -1108,7 +1137,7 @@ DWORD WINAPI remoteVstPlugin::guiEventLoop( LPVOID _param )
|
||||
|
||||
|
||||
|
||||
int main( int _argc, char * * _argv )
|
||||
int main( int _argc, char * * _argv )
|
||||
{
|
||||
if( _argc < 3 )
|
||||
{
|
||||
@@ -1147,6 +1176,7 @@ int main( int _argc, char * * _argv )
|
||||
return( -1 );
|
||||
}
|
||||
|
||||
#ifdef LMMS_BUILD_LINUX
|
||||
#ifdef LMMS_HAVE_SCHED_H
|
||||
// try to set realtime-priority
|
||||
struct sched_param sparam;
|
||||
@@ -1157,6 +1187,7 @@ int main( int _argc, char * * _argv )
|
||||
fprintf( stderr, "could not set realtime priority for "
|
||||
"remoteVstPlugin\n" );
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
__plugin = new remoteVstPlugin( atoi( _argv[1] ), atoi( _argv[2] ) );
|
||||
|
||||
@@ -30,11 +30,20 @@
|
||||
#include <QtCore/QLocale>
|
||||
#include <QtGui/QMdiArea>
|
||||
#include <QtGui/QMdiSubWindow>
|
||||
#ifdef LMMS_BUILD_LINUX
|
||||
#include <QtGui/QX11EmbedContainer>
|
||||
#include <QtGui/QX11Info>
|
||||
#else
|
||||
#include <QtGui/QLayout>
|
||||
#endif
|
||||
#include <QtXml/QDomDocument>
|
||||
|
||||
|
||||
#ifdef LMMS_BUILD_WIN32
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
|
||||
#include "config_mgr.h"
|
||||
#include "engine.h"
|
||||
#include "main_window.h"
|
||||
@@ -42,7 +51,6 @@
|
||||
|
||||
|
||||
|
||||
|
||||
vstPlugin::vstPlugin( const QString & _plugin ) :
|
||||
QObject(),
|
||||
journallingObject(),
|
||||
@@ -58,6 +66,26 @@ vstPlugin::vstPlugin( const QString & _plugin ) :
|
||||
setSplittedChannels( true );
|
||||
|
||||
lock();
|
||||
#ifdef LMMS_BUILD_WIN32
|
||||
QWidget * helper = new QWidget;
|
||||
QWidget * target = new QWidget( helper );
|
||||
QHBoxLayout * l = new QHBoxLayout;
|
||||
l->setMargin( 0 );
|
||||
l->addWidget( target );
|
||||
helper->setLayout( l );
|
||||
|
||||
static int k = 0;
|
||||
const QString t = QString( "vst%1%2" ).arg( GetCurrentProcessId()<<10 ).
|
||||
arg( ++k );
|
||||
helper->setWindowTitle( t );
|
||||
|
||||
// we've to call that for making sure, Qt created the windows
|
||||
(void) helper->winId();
|
||||
(void) target->winId();
|
||||
|
||||
sendMessage( message( IdVstPluginWindowInformation ).
|
||||
addString( t.toStdString() ) );
|
||||
#endif
|
||||
|
||||
VstHostLanguages hlang = LanguageEnglish;
|
||||
switch( QLocale::system().language() )
|
||||
@@ -83,6 +111,21 @@ vstPlugin::vstPlugin( const QString & _plugin ) :
|
||||
waitForInitDone();
|
||||
|
||||
unlock();
|
||||
|
||||
#ifdef LMMS_BUILD_WIN32
|
||||
if( m_pluginWindowID )
|
||||
{
|
||||
target->setFixedSize( m_pluginGeometry );
|
||||
engine::getMainWindow()->workspace()->addSubWindow( helper )
|
||||
->setAttribute( Qt::WA_DeleteOnClose, FALSE );
|
||||
helper->setWindowTitle( name() );
|
||||
m_pluginWidget = helper;
|
||||
}
|
||||
else
|
||||
{
|
||||
delete helper;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -112,7 +155,7 @@ QWidget * vstPlugin::showEditor( QWidget * _parent )
|
||||
}
|
||||
return( m_pluginWidget );
|
||||
}
|
||||
|
||||
#ifdef LMMS_BUILD_LINUX
|
||||
if( m_pluginWindowID == 0 )
|
||||
{
|
||||
return( NULL );
|
||||
@@ -128,7 +171,6 @@ QWidget * vstPlugin::showEditor( QWidget * _parent )
|
||||
->setAttribute( Qt::WA_DeleteOnClose, FALSE );
|
||||
}
|
||||
|
||||
#ifdef LMMS_BUILD_LINUX
|
||||
QX11EmbedContainer * xe = new QX11EmbedContainer( m_pluginWidget );
|
||||
xe->embedClient( m_pluginWindowID );
|
||||
xe->setFixedSize( m_pluginGeometry );
|
||||
@@ -148,6 +190,9 @@ QWidget * vstPlugin::showEditor( QWidget * _parent )
|
||||
|
||||
void vstPlugin::hideEditor( void )
|
||||
{
|
||||
if( m_pluginWidget )
|
||||
m_pluginWidget->hide();
|
||||
return;
|
||||
if( m_pluginWidget != NULL && m_pluginWidget->parentWidget() )
|
||||
{
|
||||
m_pluginWidget->parentWidget()->hide();
|
||||
@@ -275,7 +320,7 @@ bool vstPlugin::processMessage( const message & _m )
|
||||
const int w = _m.getInt( 0 );
|
||||
const int h = _m.getInt( 1 );
|
||||
m_pluginGeometry = QSize( w, h );
|
||||
if( m_pluginWidget != NULL )
|
||||
/* if( m_pluginWidget != NULL )
|
||||
{
|
||||
m_pluginWidget->setFixedSize(
|
||||
m_pluginGeometry );
|
||||
@@ -285,7 +330,7 @@ bool vstPlugin::processMessage( const message & _m )
|
||||
)->setFixedSize(
|
||||
m_pluginGeometry );
|
||||
}
|
||||
}
|
||||
}*/
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
@@ -37,7 +37,8 @@
|
||||
|
||||
|
||||
|
||||
class vstPlugin : public QObject, public journallingObject, public remotePlugin
|
||||
class PLUGIN_EXPORT vstPlugin : public QObject, public journallingObject,
|
||||
public remotePlugin
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
|
||||
Reference in New Issue
Block a user