Embed in a separate window

This commit is contained in:
Javier Serrano Polo
2016-10-02 05:13:17 +02:00
committed by Lukas W
parent a81f4ca8e9
commit 878dd94e8d
10 changed files with 725 additions and 190 deletions

View File

@@ -414,6 +414,7 @@ private:
enum RemoteMessageIDs
{
IdUndefined,
IdHostInfoGotten,
IdInitDone,
IdQuit,
IdSampleRateInformation,
@@ -426,6 +427,7 @@ enum RemoteMessageIDs
IdChangeOutputCount,
IdShowUI,
IdHideUI,
IdToggleUI,
IdSaveSettingsToString,
IdSaveSettingsToFile,
IdLoadSettingsFromString,
@@ -769,6 +771,12 @@ public:
bool init( const QString &pluginExecutable, bool waitForInitDoneMsg );
inline void waitForHostInfoGotten()
{
m_failed = waitForMessage( IdHostInfoGotten ).id
!= IdHostInfoGotten;
}
inline void waitForInitDone( bool _busyWaiting = true )
{
m_failed = waitForMessage( IdInitDone, _busyWaiting ).id != IdInitDone;
@@ -801,6 +809,13 @@ public:
unlock();
}
void toggleUI()
{
lock();
sendMessage( IdToggleUI );
unlock();
}
inline bool failed() const
{
return m_failed;
@@ -1155,6 +1170,7 @@ RemotePluginClient::RemotePluginClient( const char * socketPath ) :
m_vstSyncData = (VstSyncData *) m_shmQtID.data();
m_bufferSize = m_vstSyncData->m_bufferSize;
m_sampleRate = m_vstSyncData->m_sampleRate;
sendMessage( IdHostInfoGotten );
return;
}
#else
@@ -1182,6 +1198,7 @@ RemotePluginClient::RemotePluginClient( const char * socketPath ) :
{
m_bufferSize = m_vstSyncData->m_bufferSize;
m_sampleRate = m_vstSyncData->m_sampleRate;
sendMessage( IdHostInfoGotten );
// detach segment
if( shmdt(m_vstSyncData) == -1 )
@@ -1197,6 +1214,12 @@ RemotePluginClient::RemotePluginClient( const char * socketPath ) :
// if attaching shared memory fails
sendMessage( IdSampleRateInformation );
sendMessage( IdBufferSizeInformation );
if( waitForMessage( IdBufferSizeInformation ).id
!= IdBufferSizeInformation )
{
fprintf( stderr, "Could not get buffer size information.\n" );
}
sendMessage( IdHostInfoGotten );
}

View File

@@ -76,7 +76,7 @@ VstEffectControlDialog::VstEffectControlDialog( VstEffectControls * _ctl ) :
QPushButton * btn = new QPushButton( tr( "Show/hide" ) );
btn->setCheckable( true );
connect( btn, SIGNAL( toggled( bool ) ),
m_pluginWidget, SLOT( setVisible( bool ) ) );
SLOT( togglePluginUI( bool ) ) );
emit btn->click();
btn->setMinimumWidth( 78 );
@@ -264,3 +264,21 @@ VstEffectControlDialog::~VstEffectControlDialog()
//delete m_pluginWidget;
}
void VstEffectControlDialog::togglePluginUI( bool checked )
{
if( m_plugin )
{
if( checked )
{
m_plugin->showUI();
}
else
{
m_plugin->hideUI();
}
}
}

View File

@@ -62,6 +62,9 @@ private:
VstPlugin * m_plugin;
QLabel * tbLabel;
private slots:
void togglePluginUI( bool checked );
} ;
#endif

View File

@@ -261,7 +261,7 @@ void vestigeInstrument::loadFile( const QString & _file )
return;
}
m_plugin->showEditor( NULL, false );
m_plugin->showUI();
if( set_ch_name )
{
@@ -735,19 +735,7 @@ void VestigeInstrumentView::toggleGUI( void )
{
return;
}
QWidget * w = m_vi->m_plugin->pluginWidget();
if( w == NULL )
{
return;
}
if( w->isHidden() )
{
w->show();
}
else
{
w->hide();
}
m_vi->m_plugin->toggleUI();
}

View File

@@ -58,6 +58,18 @@ ADD_CUSTOM_COMMAND(
OUTPUTS ../RemoteVstPlugin
)
IF(QT5)
QT5_WRAP_CPP(embed-window_MOC_out EmbedderApplication.h)
ELSE()
QT4_WRAP_CPP(embed-window_MOC_out EmbedderApplication.h)
ENDIF()
ADD_EXECUTABLE(embed-window embed-window.cpp ${embed-window_MOC_out})
TARGET_LINK_LIBRARIES(embed-window ${QT_LIBRARIES})
IF(NOT QT5)
TARGET_LINK_LIBRARIES(embed-window ${X11_X11_LIB})
ENDIF()
SET_DIRECTORY_PROPERTIES(PROPERTIES ADDITIONAL_MAKE_CLEAN_FILES ../RemoteVstPlugin.exe.so)
INSTALL(PROGRAMS "${CMAKE_CURRENT_BINARY_DIR}/../RemoteVstPlugin" "${CMAKE_CURRENT_BINARY_DIR}/../RemoteVstPlugin.exe.so" DESTINATION "${PLUGIN_DIR}")
ENDIF(LMMS_BUILD_LINUX AND NOT WANT_VST_NOWINE)

View File

@@ -0,0 +1,82 @@
/*
* EmbedderApplication.h - simple application that embeds an external window
*
* Copyright (c) 2016 Javier Serrano Polo <javier@jasp.net>
*
* This file is part of LMMS - http://lmms.io
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this program (see COPYING); if not, write to the
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301 USA.
*
*/
#ifndef EMBEDDER_APPLICATION_H
#define EMBEDDER_APPLICATION_H
#include <QApplication>
#include <QMainWindow>
#if QT_VERSION < 0x050000
class QX11EmbedContainer;
#endif
class MainWindow : public QMainWindow
{
public:
void init( const char * title, unsigned int windowId, int width,
int height );
protected:
virtual void closeEvent( QCloseEvent *event );
private:
#if QT_VERSION < 0x050000
QX11EmbedContainer * m_window;
#else
QWindow * m_window;
#endif
} ;
class EmbedderApplication : public QApplication
{
Q_OBJECT
public:
EmbedderApplication( int & argc, char * * argv );
virtual ~EmbedderApplication();
void init( const char * title, unsigned int windowId, int width,
int height );
private:
MainWindow m_mainWindow;
private slots:
void applicationReady();
void readCommand();
} ;
#endif

View File

@@ -52,6 +52,7 @@
#include <sched.h>
#endif
#include <sys/wait.h>
#include <wine/exception.h>
#endif
@@ -106,6 +107,12 @@ struct ERect
#include <sys/shm.h>
#endif
#define EMBEDDER_NAME "embed-window"
#ifdef LMMS_BUILD_LINUX
#define USE_LINUX_EMBEDDER
#endif
static VstHostLanguages hlang = LanguageEnglish;
@@ -115,6 +122,10 @@ RemoteVstPlugin * __plugin = NULL;
DWORD __GuiThreadID = 0;
#ifdef USE_LINUX_EMBEDDER
static char * s_embedderPath;
#endif
class RemoteVstPlugin : public RemotePluginClient
@@ -131,6 +142,7 @@ public:
void init( const std::string & _plugin_file );
void initEditor();
void destroyEditor();
virtual void process( const sampleFrame * _in, sampleFrame * _out );
@@ -299,8 +311,16 @@ private:
intptr_t m_windowID;
int m_windowWidth;
int m_windowHeight;
#ifdef USE_LINUX_EMBEDDER
pid_t m_embedderPid;
int m_embedderStdin;
int m_embedderStdout;
#else
PROCESS_INFORMATION m_processInfo;
#endif
bool m_initialized;
bool m_registeredWindowClass;
pthread_mutex_t m_pluginLock;
@@ -347,6 +367,7 @@ RemoteVstPlugin::RemoteVstPlugin( const char * socketPath ) :
m_windowWidth( 0 ),
m_windowHeight( 0 ),
m_initialized( false ),
m_registeredWindowClass( false ),
m_pluginLock(),
m_inputs( NULL ),
m_outputs( NULL ),
@@ -357,7 +378,6 @@ RemoteVstPlugin::RemoteVstPlugin( const char * socketPath ) :
m_in( NULL ),
m_shmID( -1 ),
m_vstSyncData( NULL )
{
pthread_mutex_init( &m_pluginLock, NULL );
@@ -423,14 +443,7 @@ RemoteVstPlugin::RemoteVstPlugin( const char * socketPath ) :
RemoteVstPlugin::~RemoteVstPlugin()
{
if( m_window != NULL )
{
pluginDispatch( effEditClose );
#ifdef LMMS_BUILD_LINUX
CloseWindow( m_window );
#endif
m_window = NULL;
}
destroyEditor();
pluginDispatch( effMainsChanged, 0, 0 );
pluginDispatch( effClose );
#ifndef USE_QT_SHMEM
@@ -464,24 +477,103 @@ RemoteVstPlugin::~RemoteVstPlugin()
#ifdef USE_LINUX_EMBEDDER
static void checkExitStatus( int status )
{
if( WIFEXITED( status ) && WEXITSTATUS( status ) == EXIT_SUCCESS )
{
return;
}
fprintf( stderr, "Child process did not exit properly\n" );
}
#endif
bool RemoteVstPlugin::processMessage( const message & _m )
{
switch( _m.id )
{
case IdShowUI:
#ifdef USE_LINUX_EMBEDDER
if( m_window )
{
int status;
pid_t pid = waitpid( m_embedderPid, &status,
WNOHANG );
switch( pid )
{
case -1:
perror( "waitpid" );
break;
case 0:
break;
default:
checkExitStatus( status );
m_embedderPid = -1;
destroyEditor();
}
}
#endif
initEditor();
break;
case IdHideUI:
destroyEditor();
break;
case IdToggleUI:
#ifdef USE_LINUX_EMBEDDER
if( m_window )
{
bool restart = false;
int status;
pid_t pid = waitpid( m_embedderPid, &status,
WNOHANG );
switch( pid )
{
case -1:
perror( "waitpid" );
break;
case 0:
break;
default:
checkExitStatus( status );
m_embedderPid = -1;
restart = true;
}
destroyEditor();
if( !restart )
{
break;
}
}
initEditor();
break;
#else
// Temporary implementation, not using an embedder
if( m_window )
{
destroyEditor();
}
else
{
initEditor();
}
break;
#endif
case IdVstLoadPlugin:
init( _m.getString() );
break;
#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() );
break;
@@ -619,9 +711,32 @@ void RemoteVstPlugin::init( const std::string & _plugin_file )
static void assert_dup2( int oldfd, int newfd )
{
if( dup2( oldfd, newfd ) == -1 )
{
perror( "dup2" );
exit( EXIT_FAILURE );
}
}
static void close_check( int fd )
{
if( close( fd ) )
{
perror( "close" );
}
}
void RemoteVstPlugin::initEditor()
{
if( !( m_plugin->flags & effFlagsHasEditor ) )
if( m_window || !( m_plugin->flags & effFlagsHasEditor ) )
{
return;
}
@@ -635,45 +750,40 @@ void RemoteVstPlugin::initEditor()
}
WNDCLASS wc;
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = DefWindowProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInst;
wc.hIcon = LoadIcon( NULL, IDI_APPLICATION );
wc.hCursor = LoadCursor( NULL, IDC_ARROW );
wc.hbrBackground = (HBRUSH) GetStockObject( BLACK_BRUSH );
wc.lpszMenuName = NULL;
wc.lpszClassName = "LVSL";
if( !RegisterClass( &wc ) )
if( !m_registeredWindowClass )
{
return;
WNDCLASS wc;
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = DefWindowProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInst;
wc.hIcon = LoadIcon( NULL, IDI_APPLICATION );
wc.hCursor = LoadCursor( NULL, IDC_ARROW );
wc.hbrBackground = (HBRUSH) GetStockObject( BLACK_BRUSH );
wc.lpszMenuName = NULL;
wc.lpszClassName = "LVSL";
if( !RegisterClass( &wc ) )
{
return;
}
m_registeredWindowClass = true;
}
#ifdef LMMS_BUILD_LINUX
//m_window = CreateWindowEx( 0, "LVSL", m_shortName.c_str(),
// ( WS_OVERLAPPEDWINDOW | WS_THICKFRAME ) & ~WS_MAXIMIZEBOX,
// 0, 0, 10, 10, NULL, NULL, hInst, NULL );
m_window = CreateWindowEx( 0 , "LVSL", m_shortName.c_str(),
WS_POPUP | WS_SYSMENU | WS_BORDER , 0, 0, 10, 10, NULL, NULL, hInst, NULL);
#else
m_windowID = 1; // arbitrary value on win32 to signal
// vstPlugin-class that we have an editor
m_window = CreateWindowEx( 0, "LVSL", m_shortName.c_str(),
WS_CHILD, 0, 0, 10, 10,
m_window, NULL, hInst, NULL );
#if QT_VERSION < 0x050000 && defined( LMMS_BUILD_LINUX )
WS_POPUP | WS_SYSMENU | WS_BORDER,
#else
( WS_OVERLAPPEDWINDOW | WS_THICKFRAME ) & ~WS_MAXIMIZEBOX,
#endif
0, 0, 10, 10, NULL, NULL, hInst, NULL );
if( m_window == NULL )
{
debugMessage( "initEditor(): cannot create editor window\n" );
return;
}
pluginDispatch( effEditOpen, 0, 0, m_window );
ERect * er;
@@ -682,17 +792,202 @@ void RemoteVstPlugin::initEditor()
m_windowWidth = er->right - er->left;
m_windowHeight = er->bottom - er->top;
#ifdef USE_LINUX_EMBEDDER
m_windowID = (intptr_t) GetProp( m_window, "__wine_x11_whole_window" );
m_embedderPid = -1;
m_embedderStdin = -1;
m_embedderStdout = -1;
int infd[2];
int outfd[2];
if( pipe( infd ) )
{
perror( "pipe" );
destroyEditor();
return;
}
if( pipe( outfd ) )
{
perror( "pipe" );
close_check( infd[0] );
close_check( infd[1] );
destroyEditor();
return;
}
m_embedderPid = fork();
switch ( m_embedderPid )
{
case -1:
perror( "fork" );
close_check( infd[0] );
close_check( infd[1] );
close_check( outfd[0] );
close_check( outfd[1] );
destroyEditor();
return;
case 0:
assert_dup2( infd[0], STDIN_FILENO );
assert_dup2( outfd[1], STDOUT_FILENO );
close_check( infd[0] );
close_check( infd[1] );
close_check( outfd[0] );
close_check( outfd[1] );
char * widStr = new char[2 * sizeof m_windowID + 1];
sprintf( widStr, "%x", m_windowID );
char * widthStr
= new char[2 * sizeof m_windowWidth + 1];
sprintf( widthStr, "%x", m_windowWidth );
char * heightStr
= new char[2 * sizeof m_windowHeight + 1];
sprintf( heightStr, "%x", m_windowHeight );
execl( s_embedderPath, s_embedderPath,
m_shortName.c_str(), widStr, widthStr,
heightStr, (char *) NULL );
perror( "execl" );
exit( EXIT_FAILURE );
}
close_check( infd[0] );
close_check( outfd[1] );
m_embedderStdin = infd[1];
m_embedderStdout = outfd[0];
#else
// Pending: Check that Qt 5 embedding works on Windows
// Should wait until Qt 4 support is dropped
// TODO: Set to native window ID
m_windowID = 1;
const char * name = m_shortName.c_str();
char * commandLine = new char[sizeof EMBEDDER_NAME " " + strlen( name )
+ 1 + 2 * sizeof m_windowID + 1 + 2 * sizeof m_windowWidth + 1
+ 2 * sizeof m_windowHeight];
sprintf( commandLine, EMBEDDER_NAME " %s %x %x %x", name, m_windowID,
m_windowWidth, m_windowHeight );
// Set up the pipes
/*
SECURITY_ATTRIBUTES saAttr;
saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
saAttr.bInheritHandle = TRUE;
saAttr.lpSecurityDescriptor = NULL;
if ( !CreatePipe(&g_hChildStd_OUT_Rd, &g_hChildStd_OUT_Wr, &saAttr, 0) )
ErrorExit(TEXT("StdoutRd CreatePipe"));
if ( !SetHandleInformation(g_hChildStd_OUT_Rd, HANDLE_FLAG_INHERIT, 0) )
ErrorExit(TEXT("Stdout SetHandleInformation"));
if (! CreatePipe(&g_hChildStd_IN_Rd, &g_hChildStd_IN_Wr, &saAttr, 0))
ErrorExit(TEXT("Stdin CreatePipe"));
if ( ! SetHandleInformation(g_hChildStd_IN_Wr, HANDLE_FLAG_INHERIT, 0) )
ErrorExit(TEXT("Stdin SetHandleInformation"));
*/
STARTUPINFO si;
ZeroMemory( &si, sizeof si );
si.cb = sizeof si;
// si.hStdOutput = g_hChildStd_OUT_Wr;
// si.hStdInput = g_hChildStd_IN_Rd;
// si.dwFlags |= STARTF_USESTDHANDLES;
ZeroMemory( &m_processInfo, sizeof m_processInfo );
// Pending: Create new process when the embedder is ready
// bool ok = CreateProcess( NULL, commandLine, NULL, NULL, TRUE, 0, NULL,
// NULL, &si, &m_processInfo );
delete[] commandLine;
/*
if ( !ok )
{
fprintf( stderr, "CreateProcess failed (%d)\n",
GetLastError() );
destroyEditor();
return;
}
*/
// close unused pipe handles if possible
// if ( ! CloseHandle(g_hChildStd_IN_Rd) ) error
#endif
SetWindowPos( m_window, 0, 0, 0, m_windowWidth + 8,
m_windowHeight + 26, SWP_NOACTIVATE |
SWP_NOMOVE | SWP_NOZORDER );
pluginDispatch( effEditTop );
ShowWindow( m_window, SW_SHOWNORMAL );
UpdateWindow( m_window );
#ifdef LMMS_BUILD_LINUX
m_windowID = (intptr_t) GetProp( m_window, "__wine_x11_whole_window" );
#ifdef USE_LINUX_EMBEDDER
char c;
if( ::read( m_embedderStdout, &c, 1 ) != 1 )
{
fprintf( stderr, "Could not read from embedder\n" );
destroyEditor();
return;
}
#else
// bSuccess = ReadFile(g_hChildStd_OUT_Rd, chBuf, BUFSIZE, &dwRead, NULL);
// if ( ! bSuccess || dwRead == 0 ) break;
#endif
ShowWindow( m_window, SW_SHOWNORMAL );
#ifdef USE_LINUX_EMBEDDER
if( ::write( m_embedderStdin, "", 1 ) != 1 )
{
fprintf( stderr, "Could not write to embedder\n" );
destroyEditor();
return;
}
#else
// bSuccess = WriteFile(g_hChildStd_IN_Wr, chBuf, dwRead, &dwWritten, NULL);
// if ( ! bSuccess ) break;
#endif
}
void RemoteVstPlugin::destroyEditor()
{
if( m_window == NULL )
{
return;
}
#ifdef USE_LINUX_EMBEDDER
close_check( m_embedderStdin );
close_check( m_embedderStdout );
if( m_embedderPid != -1 )
{
int status;
pid_t pid = waitpid( m_embedderPid, &status, 0 );
if( pid == -1 )
{
perror( "waitpid" );
}
else
{
checkExitStatus( status );
}
}
#else
// Close pipes
// Wait until child process exits.
// WaitForSingleObject( m_processInfo.hProcess, INFINITE );
// Close process and thread handles.
// CloseHandle( m_processInfo.hProcess );
// CloseHandle( m_processInfo.hThread );
#endif
pluginDispatch( effEditClose );
// Destroying the window takes some time in Wine 1.8.5
DestroyWindow( m_window );
m_window = NULL;
}
@@ -989,7 +1284,7 @@ void RemoteVstPlugin::saveChunkToFile( const std::string & _file )
fprintf( stderr,
"Error saving chunk to file.\n" );
}
close( fd );
close_check( fd );
}
}
}
@@ -1327,7 +1622,7 @@ void RemoteVstPlugin::loadChunkFromFile( const std::string & _file, int _len )
{
fprintf( stderr, "Error loading chunk from file.\n" );
}
close( fd );
close_check( fd );
pluginDispatch( 24, 0, _len, chunk );
delete[] buf;
@@ -1807,6 +2102,13 @@ DWORD WINAPI RemoteVstPlugin::guiEventLoop( LPVOID _param )
while( quit == false && GetMessage( &msg, NULL, 0, 0 ) )
{
TranslateMessage( &msg );
if( msg.message == WM_SYSCOMMAND && msg.wParam == SC_CLOSE )
{
_this->destroyEditor();
continue;
}
DispatchMessage( &msg );
if( msg.message == WM_TIMER && _this->isInitialized() )
@@ -1846,6 +2148,63 @@ DWORD WINAPI RemoteVstPlugin::guiEventLoop( LPVOID _param )
#ifdef USE_LINUX_EMBEDDER
static char * findMyPath( const char * argv0 )
{
// TODO: escape ' or use execlp
std::string command = "winepath '";
command += argv0;
command += '\'';
FILE * stream = popen( command.c_str(), "r" );
if( !stream )
{
perror( "popen" );
return NULL;
}
char * unixPath = (char *) malloc( BUFSIZ );
char * s = fgets( unixPath, BUFSIZ, stream );
if( !s )
{
perror( "fgets" );
free( unixPath );
return NULL;
}
if( strlen( s ) == BUFSIZ - 1 )
{
//TODO: Read a longer line
fprintf( stderr, "findMyPath: Buffer too small\n" );
}
char * eol = strchr( unixPath, '\n' );
if( eol )
{
*eol = '\0';
}
if( pclose( stream ) == -1 )
{
perror( "pclose" );
}
return unixPath;
}
static char * findEmbedderPath( const char * argv0 )
{
char * myPath = findMyPath( argv0 );
const char * slash = myPath ? strrchr( myPath, '/' ) : NULL;
size_t prefixLength = slash ? slash - myPath + 1 : 0;
char * path = new char[prefixLength + sizeof EMBEDDER_NAME];
memcpy( path, myPath, prefixLength );
memcpy( path + prefixLength, EMBEDDER_NAME, sizeof EMBEDDER_NAME );
free( myPath );
return path;
}
#endif
int main( int _argc, char * * _argv )
{
#ifdef SYNC_WITH_SHM_FIFO
@@ -1883,6 +2242,10 @@ int main( int _argc, char * * _argv )
}
#endif
#ifdef USE_LINUX_EMBEDDER
s_embedderPath = findEmbedderPath( _argv[0] );
#endif
// constructor automatically will process messages until it receives
// a IdVstLoadPlugin message and processes it
#ifdef SYNC_WITH_SHM_FIFO
@@ -1907,6 +2270,10 @@ int main( int _argc, char * * _argv )
delete __plugin;
#ifdef USE_LINUX_EMBEDDER
delete[] s_embedderPath;
#endif
#ifdef LMMS_BUILD_WIN32
#ifndef __WINPTHREADS_VERSION

View File

@@ -31,16 +31,6 @@
#include <QCloseEvent>
#include <QMdiArea>
#include <QMdiSubWindow>
#ifdef LMMS_BUILD_LINUX
#if QT_VERSION < 0x050000
#include <QX11EmbedContainer>
#include <QX11Info>
#else
#include <QWindow>
#endif
#else
#include <QLayout>
#endif
#include <QDomDocument>
#ifdef LMMS_BUILD_WIN32
@@ -54,32 +44,6 @@
#include "Song.h"
#include "templates.h"
#include "FileDialog.h"
#include <QLayout>
class vstSubWin : public QMdiSubWindow
{
public:
vstSubWin( QWidget * _parent ) :
QMdiSubWindow( _parent )
{
setAttribute( Qt::WA_DeleteOnClose, false );
}
virtual ~vstSubWin()
{
}
virtual void closeEvent( QCloseEvent * e )
{
// ignore close-events - for some reason otherwise the VST GUI
// remains hidden when re-opening
hide();
e->ignore();
}
} ;
VstPlugin::VstPlugin( const QString & _plugin ) :
@@ -137,27 +101,13 @@ void VstPlugin::tryLoad( const QString &remoteVstPluginExecutable )
{
init( remoteVstPluginExecutable, false );
waitForHostInfoGotten();
if( failed() )
{
return;
}
lock();
#ifdef LMMS_BUILD_WIN32
QWidget * helper = new QWidget;
QHBoxLayout * l = new QHBoxLayout( helper );
QWidget * target = new QWidget( helper );
l->setSpacing( 0 );
l->setMargin( 0 );
l->addWidget( target );
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( QSTR_TO_STDSTR( t ) ) );
#endif
VstHostLanguages hlang = LanguageEnglish;
switch( QLocale::system().language() )
@@ -185,22 +135,6 @@ void VstPlugin::tryLoad( const QString &remoteVstPluginExecutable )
waitForInitDone();
unlock();
#ifdef LMMS_BUILD_WIN32
if( !failed() && m_pluginWindowID )
{
target->setFixedSize( m_pluginGeometry );
vstSubWin * sw = new vstSubWin(
gui->mainWindow()->workspace() );
sw->setWidget( helper );
helper->setWindowTitle( name() );
m_pluginWidget = helper;
}
else
{
delete helper;
}
#endif
}
@@ -237,53 +171,6 @@ void VstPlugin::showEditor( QWidget * _parent, bool isEffect )
m_pluginWidget = new QWidget( _parent );
m_pluginWidget->setFixedSize( m_pluginGeometry );
m_pluginWidget->setWindowTitle( name() );
if( _parent == NULL )
{
vstSubWin * sw = new vstSubWin(
gui->mainWindow()->workspace() );
if( isEffect )
{
sw->setAttribute( Qt::WA_TranslucentBackground );
sw->setWindowFlags( Qt::FramelessWindowHint );
sw->setWidget( m_pluginWidget );
#if QT_VERSION < 0x050000
QX11EmbedContainer * xe = new QX11EmbedContainer( sw );
xe->embedClient( m_pluginWindowID );
xe->setFixedSize( m_pluginGeometry );
xe->show();
#else
QWindow * window = QWindow::fromWinId(
m_pluginWindowID );
QWidget * container = QWidget::createWindowContainer(
window, sw );
container->setFixedSize( m_pluginGeometry );
container->show();
#endif
}
else
{
sw->setWindowFlags( Qt::WindowCloseButtonHint );
sw->setWidget( m_pluginWidget );
#if QT_VERSION < 0x050000
QX11EmbedContainer * xe = new QX11EmbedContainer( sw );
xe->embedClient( m_pluginWindowID );
xe->setFixedSize( m_pluginGeometry );
xe->move( 4, 24 );
xe->show();
#else
QWindow * window = QWindow::fromWinId(
m_pluginWindowID );
QWidget * container = QWidget::createWindowContainer(
window, sw );
container->setAttribute( Qt::WA_NoMousePropagation );
container->setFixedSize( m_pluginGeometry );
container->move( 4, 24 );
container->show();
#endif
}
}
#endif
if( m_pluginWidget )
@@ -297,6 +184,7 @@ void VstPlugin::showEditor( QWidget * _parent, bool isEffect )
void VstPlugin::hideEditor()
{
//TODO: Drop m_pluginWidget, showEditor(), hideEditor()
QWidget * w = pluginWidget();
if( w )
{
@@ -352,6 +240,7 @@ void VstPlugin::loadSettings( const QDomElement & _this )
void VstPlugin::saveSettings( QDomDocument & _doc, QDomElement & _this )
{
//TODO: Replace with m_plugin->isVisible(), add IdIsUIVisble message
if( pluginWidget() != NULL )
{
_this.setAttribute( "guivisible", pluginWidget()->isVisible() );

View File

@@ -56,7 +56,6 @@ enum VstRemoteMessageIDs
{
// vstPlugin -> remoteVstPlugin
IdVstLoadPlugin = IdUserBase,
IdVstPluginWindowInformation,
IdVstClosePlugin,
IdVstSetTempo,
IdVstSetLanguage,
@@ -73,6 +72,9 @@ enum VstRemoteMessageIDs
// remoteVstPlugin -> vstPlugin
IdVstFailedLoadingPlugin,
IdVstBadDllFormat,
// Window ID and geometry are only useful if external windows can be
// embedded in LMMS, which is not the case in Qt 5 because there are
// glitches. If Qt is not fixed, then drop these messages.
IdVstPluginWindowID,
IdVstPluginEditorGeometry,
IdVstPluginName,

View File

@@ -0,0 +1,151 @@
/*
* embed-window.cpp - simple application that embeds an external window
*
* Copyright (c) 2016 Javier Serrano Polo <javier@jasp.net>
*
* This file is part of LMMS - http://lmms.io
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this program (see COPYING); if not, write to the
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301 USA.
*
*/
#include "EmbedderApplication.h"
#include <QSocketNotifier>
#include <QTimer>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#if QT_VERSION < 0x050000
#include <QX11EmbedContainer>
#include <QX11Info>
#include <X11/Xlib.h>
#else
#include <QWindow>
#endif
void MainWindow::init( const char * title, unsigned int windowId, int width,
int height )
{
setWindowTitle( title );
#if QT_VERSION < 0x050000
m_window = new QX11EmbedContainer( this );
QX11EmbedContainer * container = m_window;
container->embedClient( windowId );
#else
m_window = QWindow::fromWinId( windowId );
QWidget * container = QWidget::createWindowContainer( m_window, this );
#endif
container->setFixedSize( width, height );
container->show();
setFixedSize( width, height );
}
void MainWindow::closeEvent( QCloseEvent *event )
{
hide();
#if QT_VERSION < 0x050000
XUnmapWindow( QX11Info::display(), m_window->clientWinId() );
m_window->discardClient();
#else
m_window->setParent( 0 );
#endif
QMainWindow::closeEvent( event );
}
EmbedderApplication::EmbedderApplication( int & argc, char * * argv ) :
QApplication( argc, argv )
{
QSocketNotifier * notifier = new QSocketNotifier( STDIN_FILENO,
QSocketNotifier::Read );
connect( notifier, SIGNAL( activated( int ) ), SLOT( readCommand() ) );
}
EmbedderApplication::~EmbedderApplication()
{
}
void EmbedderApplication::init( const char * title, unsigned int windowId,
int width, int height )
{
m_mainWindow.init( title, windowId, width, height );
}
void EmbedderApplication::applicationReady()
{
putchar( 0 );
fflush( stdout );
}
void EmbedderApplication::readCommand()
{
int c = getchar();
if( c == EOF )
{
m_mainWindow.close();
quit();
return;
}
m_mainWindow.show();
}
int main( int argc, char * * argv )
{
if( argc < 5 )
{
fputs( "Missing arguments\n", stderr );
return EXIT_FAILURE;
}
EmbedderApplication * app = new EmbedderApplication( argc, argv );
const char * title = argv[1];
unsigned int windowId = strtol( argv[2], NULL, 16 );
int width = strtol( argv[3], NULL, 16 );
int height = strtol( argv[4], NULL, 16 );
app->init( title, windowId, width, height );
QTimer::singleShot( 0, app, SLOT( applicationReady() ) );
int ret = app->exec();
delete app;
return ret;
}