Browse Source

Experimental Carla-VST with Qt5

tags/1.9.7
falkTX 10 years ago
parent
commit
91cbc6325f
7 changed files with 240 additions and 100 deletions
  1. +0
    -6
      Makefile
  2. +59
    -0
      source/backend/CarlaUtils.cpp
  3. +9
    -0
      source/backend/CarlaUtils.h
  4. +4
    -0
      source/backend/Makefile
  5. +19
    -0
      source/carla_utils.py
  6. +149
    -92
      source/native-plugins/resources/carla-plugin
  7. +0
    -2
      source/plugin/Makefile

+ 0
- 6
Makefile View File

@@ -725,7 +725,6 @@ endif

ifeq ($(LINUX),true)
ifeq ($(HAVE_X11),true)
ifeq ($(DEFAULT_QT),4)
# Install vst plugin
install -d $(DESTDIR)$(LIBDIR)/vst/carla.vst

@@ -748,7 +747,6 @@ ifeq ($(DEFAULT_QT),4)
rm -rf $(DESTDIR)$(LIBDIR)/vst/carla.vst/styles
$(LINK) $(LIBDIR)/carla/styles $(DESTDIR)$(LIBDIR)/vst/carla.vst/styles
endif
endif
endif

# --------------------------------------------------------------------------------------------------------------------
@@ -814,15 +812,11 @@ else
@echo "LV2 plugin: $(ANS_NO) $(mZ)Not available for Windows$(mE)"
endif
ifeq ($(LINUX),true)
ifeq ($(DEFAULT_QT),4)
ifeq ($(HAVE_X11),true)
@echo "VST plugin: $(ANS_YES)"
else # HAVE_X11
@echo "VST plugin: $(ANS_NO) $(mS)X11 missing$(mE)"
endif
else # DEFAULT_QT
@echo "VST plugin: $(ANS_NO) $(mZ)Qt4 only$(mE)"
endif
else # LINUX
@echo "VST plugin: $(ANS_NO) $(mZ)Linux only$(mE)"
endif


+ 59
- 0
source/backend/CarlaUtils.cpp View File

@@ -33,6 +33,10 @@
# include "juce_audio_processors/juce_audio_processors.h"
#endif

#ifdef HAVE_X11
# include <X11/Xlib.h>
#endif

#include "../native-plugins/_data.cpp"

namespace CB = CarlaBackend;
@@ -821,6 +825,61 @@ const char* carla_get_library_folder()

// -------------------------------------------------------------------------------------------------------------------

void carla_x11_reparent_window(uintptr_t winId1, uintptr_t winId2)
{
carla_debug("carla_x11_reparent_window()");

#ifdef HAVE_X11
if (::Display* const disp = XOpenDisplay(nullptr))
{
XReparentWindow(disp, winId1, winId2, 0, 0);
XMapWindow(disp, winId1);
XCloseDisplay(disp);
}
#endif
}

void carla_x11_move_window(uintptr_t winId, int x, int y)
{
#ifdef HAVE_X11
if (::Display* const disp = XOpenDisplay(nullptr))
{
XMoveWindow(disp, winId, x, y);
XCloseDisplay(disp);
}
#endif
}

int* carla_x11_get_window_pos(uintptr_t winId)
{
carla_debug("carla_x11_get_window_pos()");

static int pos[2];

#ifdef HAVE_X11
if (::Display* const disp = XOpenDisplay(nullptr))
{
int x, y;
Window child;
XWindowAttributes xwa;
XTranslateCoordinates(disp, winId, XRootWindow(disp, 0), 0, 0, &x, &y, &child);
XGetWindowAttributes(disp, winId, &xwa);
XCloseDisplay(disp);
pos[0] = x - xwa.x;
pos[1] = y - xwa.y;
}
else
#endif
{
pos[0] = 0;
pos[1] = 0;
}

return pos;
}

// -------------------------------------------------------------------------------------------------------------------

#include "CarlaPipeUtils.cpp"

// -------------------------------------------------------------------------------------------------------------------


+ 9
- 0
source/backend/CarlaUtils.h View File

@@ -234,6 +234,15 @@ CARLA_EXPORT const char* carla_get_library_filename();
*/
CARLA_EXPORT const char* carla_get_library_folder();

// -------------------------------------------------------------------------------------------------------------------
// TESTING

CARLA_EXPORT void carla_x11_reparent_window(uintptr_t winId1, uintptr_t winId2);

CARLA_EXPORT void carla_x11_move_window(uintptr_t winId, int x, int y);

CARLA_EXPORT int* carla_x11_get_window_pos(uintptr_t winId);

// -------------------------------------------------------------------------------------------------------------------

/** @} */


+ 4
- 0
source/backend/Makefile View File

@@ -116,6 +116,10 @@ UTILS_LINK_FLAGS += $(JUCE_AUDIO_FORMATS_LIBS)
UTILS_LINK_FLAGS += $(JUCE_CORE_LIBS)
UTILS_LINK_FLAGS += $(LILV_LIBS)

ifeq ($(HAVE_X11),true)
UTILS_LINK_FLAGS += $(X11_LIBS)
endif

ifeq ($(MACOS),true)
UTILS_LINK_FLAGS += $(JUCE_AUDIO_PROCESSORS_LIBS)
UTILS_LINK_FLAGS += $(JUCE_DATA_STRUCTURES_LIBS)


+ 19
- 0
source/carla_utils.py View File

@@ -215,6 +215,15 @@ class CarlaUtils(object):
self.lib.carla_pipe_client_destroy.argtypes = [CarlaPipeClientHandle]
self.lib.carla_pipe_client_destroy.restype = None

self.lib.carla_x11_reparent_window.argtypes = [c_uintptr, c_uintptr]
self.lib.carla_x11_reparent_window.restype = None

self.lib.carla_x11_move_window.argtypes = [c_uintptr, c_int, c_int]
self.lib.carla_x11_move_window.restype = None

self.lib.carla_x11_get_window_pos.argtypes = [c_uintptr]
self.lib.carla_x11_get_window_pos.restype = POINTER(c_int)

# use _putenv on windows
if not WINDOWS:
self.msvcrt = None
@@ -314,4 +323,14 @@ class CarlaUtils(object):
def pipe_client_destroy(self, handle):
self.lib.carla_pipe_client_destroy(handle)

def x11_reparent_window(self, winId1, winId2):
self.lib.carla_x11_reparent_window(winId1, winId2)

def x11_move_window(self, winId, x, y):
self.lib.carla_x11_move_window(winId, x, y)

def x11_get_window_pos(self, winId):
data = self.lib.carla_x11_get_window_pos(winId)
return (int(data[0]), int(data[1]))

# ------------------------------------------------------------------------------------------------------------

+ 149
- 92
source/native-plugins/resources/carla-plugin View File

@@ -2,7 +2,7 @@
# -*- coding: utf-8 -*-

# Carla plugin host (plugin UI)
# Copyright (C) 2013-2014 Filipe Coelho <falktx@falktx.com>
# Copyright (C) 2013-2016 Filipe Coelho <falktx@falktx.com>
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License as
@@ -16,6 +16,20 @@
#
# For a full copy of the GNU General Public License see the GPL.txt file

# ------------------------------------------------------------------------------------------------------------
# Imports (Config)

from carla_config import *

# ------------------------------------------------------------------------------------------------------------
# Imports (Global)

if config_UseQt5:
from PyQt5.QtGui import QKeySequence
from PyQt5.QtWidgets import QHBoxLayout
else:
from PyQt4.QtGui import QHBoxLayout, QKeySequence

# ------------------------------------------------------------------------------------------------------------
# Imports (Custom Stuff)

@@ -381,117 +395,160 @@ class CarlaMiniW(ExternalUI, HostWindow):
print("unknown message: \"" + msg + "\"")

# ------------------------------------------------------------------------------------------------------------
# Embed plugin UI
# Embed Widget

if LINUX and config_UseQt5:
from PyQt5.QtGui import QMouseEvent, QWindow

if LINUX and not config_UseQt5:
from PyQt4.QtGui import QHBoxLayout, QKeySequence, QX11EmbedWidget
class QEmbedWidget(QWidget):
def __init__(self):
QWidget.__init__(self)
self.setAttribute(Qt.WA_LayoutUsesWidgetRect)

class CarlaEmbedW(QX11EmbedWidget):
def __init__(self, host, winId):
self.fPos = (0, 0)
self.move(0, 0)

self.fWinId = 0

def eventFilter(self, obj, ev):
if isinstance(ev, QMouseEvent):
pos = gCarla.utils.x11_get_window_pos(self.fWinId)
if self.fPos != pos:
self.fPos = pos
self.move(pos[0], pos[1])
gCarla.utils.x11_move_window(self.fWinId, 0, 0)
return False

def finalSetup(self, gui, winId):
self.fWinId = int(self.winId())
gui.ui.menubar.installEventFilter(self)
gCarla.utils.x11_reparent_window(self.fWinId, winId)
self.show()

elif LINUX and not config_UseQt5:
from PyQt4.QtGui import QX11EmbedWidget

class QEmbedWidget(QX11EmbedWidget):
def __init__(self):
QX11EmbedWidget.__init__(self)
self.host = host

self.fWinId = winId
def finalSetup(self, gui, winId):
self.embedInto(winId)
self.show()

self.fLayout = QVBoxLayout(self)
self.fLayout.setContentsMargins(0, 0, 0, 0)
self.fLayout.setSpacing(0)
self.setLayout(self.fLayout)
else:
class QEmbedWidget(object):
def __init__(self, winId, width, height):
print("Cannot use embed UI with this configuration")
raise Exception

self.gui = CarlaMiniW(host, self)
self.gui.hide()
# ------------------------------------------------------------------------------------------------------------
# Embed plugin UI

self.gui.ui.act_file_quit.setEnabled(False)
self.gui.ui.act_file_quit.setVisible(False)
class CarlaEmbedW(QEmbedWidget):
def __init__(self, host, winId):
QEmbedWidget.__init__(self)
self.setFixedSize(740, 512)

self.fShortcutActions = []
self.addShortcutActions(self.gui.ui.menu_File.actions())
self.addShortcutActions(self.gui.ui.menu_Plugin.actions())
self.addShortcutActions(self.gui.ui.menu_PluginMacros.actions())
self.addShortcutActions(self.gui.ui.menu_Settings.actions())
self.addShortcutActions(self.gui.ui.menu_Help.actions())
self.host = host
self.fWinId = winId

if self.host.processMode == ENGINE_PROCESS_MODE_PATCHBAY:
self.addShortcutActions(self.gui.ui.menu_Canvas.actions())
self.addShortcutActions(self.gui.ui.menu_Canvas_Zoom.actions())
self.fLayout = QVBoxLayout(self)
self.fLayout.setContentsMargins(0, 0, 0, 0)
self.fLayout.setSpacing(0)
self.setLayout(self.fLayout)

self.addWidget(self.gui.ui.menubar)
self.addLine()
self.addWidget(self.gui.ui.toolBar)
self.gui = CarlaMiniW(host, self)
self.gui.hide()

if self.host.processMode == ENGINE_PROCESS_MODE_PATCHBAY:
self.addLine()
self.gui.ui.act_file_quit.setEnabled(False)
self.gui.ui.act_file_quit.setVisible(False)

self.addWidget(self.gui.centralWidget())
self.fShortcutActions = []
self.addShortcutActions(self.gui.ui.menu_File.actions())
self.addShortcutActions(self.gui.ui.menu_Plugin.actions())
self.addShortcutActions(self.gui.ui.menu_PluginMacros.actions())
self.addShortcutActions(self.gui.ui.menu_Settings.actions())
self.addShortcutActions(self.gui.ui.menu_Help.actions())

self.setFixedSize(740, 512)
self.embedInto(winId)
self.show()
if self.host.processMode == ENGINE_PROCESS_MODE_PATCHBAY:
self.addShortcutActions(self.gui.ui.menu_Canvas.actions())
self.addShortcutActions(self.gui.ui.menu_Canvas_Zoom.actions())

def addShortcutActions(self, actions):
for action in actions:
if not action.shortcut().isEmpty():
self.fShortcutActions.append(action)

def addWidget(self, widget):
widget.setParent(self)
self.fLayout.addWidget(widget)

def addLine(self):
line = QFrame(self)
line.setFrameShadow(QFrame.Sunken)
line.setFrameShape(QFrame.HLine)
line.setLineWidth(0)
line.setMidLineWidth(1)
self.fLayout.addWidget(line)

def keyPressEvent(self, event):
modifiers = event.modifiers()
modifiersStr = ""

if modifiers & Qt.ShiftModifier:
modifiersStr += "Shift+"
if modifiers & Qt.ControlModifier:
modifiersStr += "Ctrl+"
if modifiers & Qt.AltModifier:
modifiersStr += "Alt+"
if modifiers & Qt.MetaModifier:
modifiersStr += "Meta+"

keyStr = QKeySequence(event.key()).toString()
keySeq = QKeySequence(modifiersStr + keyStr)

for action in self.fShortcutActions:
if not action.isEnabled():
continue
if keySeq.matches(action.shortcut()) != QKeySequence.ExactMatch:
continue
event.accept()
action.trigger()
return
self.addWidget(self.gui.ui.menubar)
self.addLine()
self.addWidget(self.gui.ui.toolBar)

if self.host.processMode == ENGINE_PROCESS_MODE_PATCHBAY:
self.addLine()

self.addWidget(self.gui.centralWidget())
self.finalSetup(self.gui, winId)

def addShortcutActions(self, actions):
for action in actions:
if not action.shortcut().isEmpty():
self.fShortcutActions.append(action)

def addWidget(self, widget):
widget.setParent(self)
self.fLayout.addWidget(widget)

def addLine(self):
line = QFrame(self)
line.setFrameShadow(QFrame.Sunken)
line.setFrameShape(QFrame.HLine)
line.setLineWidth(0)
line.setMidLineWidth(1)
self.fLayout.addWidget(line)

def keyPressEvent(self, event):
modifiers = event.modifiers()
modifiersStr = ""

if modifiers & Qt.ShiftModifier:
modifiersStr += "Shift+"
if modifiers & Qt.ControlModifier:
modifiersStr += "Ctrl+"
if modifiers & Qt.AltModifier:
modifiersStr += "Alt+"
if modifiers & Qt.MetaModifier:
modifiersStr += "Meta+"

keyStr = QKeySequence(event.key()).toString()
keySeq = QKeySequence(modifiersStr + keyStr)

for action in self.fShortcutActions:
if not action.isEnabled():
continue
if keySeq.matches(action.shortcut()) != QKeySequence.ExactMatch:
continue
event.accept()
action.trigger()
return

QX11EmbedWidget.keyPressEvent(self, event)
QEmbedWidget.keyPressEvent(self, event)

def showEvent(self, event):
QX11EmbedWidget.showEvent(self, event)
def showEvent(self, event):
QEmbedWidget.showEvent(self, event)

# set our gui as parent for all plugins UIs
winIdStr = "%x" % self.fWinId
self.host.set_engine_option(ENGINE_OPTION_FRONTEND_WIN_ID, 0, winIdStr)
# set our gui as parent for all plugins UIs
winIdStr = "%x" % self.fWinId
self.host.set_engine_option(ENGINE_OPTION_FRONTEND_WIN_ID, 0, winIdStr)

def hideEvent(self, event):
# disable parent
self.host.set_engine_option(ENGINE_OPTION_FRONTEND_WIN_ID, 0, "0")
def hideEvent(self, event):
# disable parent
self.host.set_engine_option(ENGINE_OPTION_FRONTEND_WIN_ID, 0, "0")

QX11EmbedWidget.hideEvent(self, event)
QEmbedWidget.hideEvent(self, event)

def closeEvent(self, event):
self.gui.close()
self.gui.closeExternalUI()
QX11EmbedWidget.closeEvent(self, event)
def closeEvent(self, event):
self.gui.close()
self.gui.closeExternalUI()
QEmbedWidget.closeEvent(self, event)

# there might be other qt windows open which will block carla-plugin from quitting
app.quit()
# there might be other qt windows open which will block carla-plugin from quitting
app.quit()

# ------------------------------------------------------------------------------------------------------------
# Main
@@ -526,7 +583,7 @@ if __name__ == '__main__':

gCarla.utils.setenv("CARLA_PLUGIN_EMBED_WINID", "0")

if LINUX and winId != 0 and not config_UseQt5:
if LINUX and winId != 0:
gui = CarlaEmbedW(host, winId)
else:
gui = CarlaMiniW(host)


+ 0
- 2
source/plugin/Makefile View File

@@ -104,7 +104,6 @@ TARGETS = \

ifeq ($(LINUX),true)
ifeq ($(HAVE_X11),true)
ifeq ($(DEFAULT_QT),4)
TARGETS += \
$(BINDIR)/CarlaRack$(LIB_EXT) \
$(BINDIR)/CarlaRackFX$(LIB_EXT) \
@@ -113,7 +112,6 @@ TARGETS += \
$(BINDIR)/CarlaPatchbayFX$(LIB_EXT)
endif
endif
endif

# ----------------------------------------------------------------------------------------------------------------------------



Loading…
Cancel
Save