@@ -206,6 +206,10 @@ ifeq ($(HAVE_JUCE),true) | |||
BASE_FLAGS += -DHAVE_JUCE | |||
endif | |||
ifeq ($(HAVE_X11),true) | |||
BASE_FLAGS += -DHAVE_X11 | |||
endif | |||
# -------------------------------------------------------------- | |||
# Set libs stuff (part 1) | |||
@@ -0,0 +1,168 @@ | |||
/* | |||
* Carla Plugin UI | |||
* Copyright (C) 2014 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 | |||
* published by the Free Software Foundation; either version 2 of | |||
* the License, or 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. | |||
* | |||
* For a full copy of the GNU General Public License see the doc/GPL.txt file. | |||
*/ | |||
#include "CarlaPluginUi.hpp" | |||
#ifdef HAVE_X11 | |||
# include <X11/Xatom.h> | |||
# include <X11/Xlib.h> | |||
# include <X11/Xutil.h> | |||
#endif | |||
#ifdef HAVE_X11 | |||
// ----------------------------------------------------- | |||
// X11 | |||
class X11PluginUi : public CarlaPluginUi | |||
{ | |||
public: | |||
X11PluginUi() noexcept | |||
: fDisplay(nullptr), | |||
fWindow(0) | |||
{ | |||
fDisplay = XOpenDisplay(0); | |||
CARLA_SAFE_ASSERT_RETURN(fDisplay != nullptr,); | |||
const int screen = DefaultScreen(fDisplay); | |||
XSetWindowAttributes attr; | |||
carla_zeroStruct<XSetWindowAttributes>(attr); | |||
fWindow = XCreateWindow(fDisplay, RootWindow(fDisplay, screen), | |||
0, 0, 300, 300, 0, | |||
DefaultDepth(fDisplay, screen), | |||
InputOutput, | |||
DefaultVisual(fDisplay, screen), | |||
CWBorderPixel | CWColormap | CWEventMask, &attr); | |||
CARLA_SAFE_ASSERT_RETURN(fWindow != 0,); | |||
Atom wmDelete = XInternAtom(fDisplay, "WM_DELETE_WINDOW", True); | |||
XSetWMProtocols(fDisplay, fWindow, &wmDelete, 1); | |||
} | |||
~X11PluginUi() override | |||
{ | |||
if (fWindow != 0) | |||
{ | |||
XDestroyWindow(fDisplay, fWindow); | |||
fWindow = 0; | |||
} | |||
if (fDisplay != nullptr) | |||
{ | |||
XCloseDisplay(fDisplay); | |||
fDisplay = nullptr; | |||
} | |||
} | |||
void show() override | |||
{ | |||
CARLA_SAFE_ASSERT_RETURN(fDisplay != nullptr,); | |||
CARLA_SAFE_ASSERT_RETURN(fWindow != 0,); | |||
XMapRaised(fDisplay, fWindow); | |||
XFlush(fDisplay); | |||
} | |||
void hide() override | |||
{ | |||
CARLA_SAFE_ASSERT_RETURN(fDisplay != nullptr,); | |||
CARLA_SAFE_ASSERT_RETURN(fWindow != 0,); | |||
XUnmapWindow(fDisplay, fWindow); | |||
XFlush(fDisplay); | |||
} | |||
void idle() override | |||
{ | |||
} | |||
void focus() override | |||
{ | |||
CARLA_SAFE_ASSERT_RETURN(fDisplay != nullptr,); | |||
CARLA_SAFE_ASSERT_RETURN(fWindow != 0,); | |||
XRaiseWindow(fDisplay, fWindow); | |||
XSetInputFocus(fDisplay, fWindow, RevertToPointerRoot, CurrentTime); | |||
XFlush(fDisplay); | |||
} | |||
void setSize(const uint width, const uint height, const bool forceUpdate) override | |||
{ | |||
CARLA_SAFE_ASSERT_RETURN(fDisplay != nullptr,); | |||
CARLA_SAFE_ASSERT_RETURN(fWindow != 0,); | |||
XResizeWindow(fDisplay, fWindow, width, height); | |||
XSizeHints sizeHints; | |||
carla_zeroStruct<XSizeHints>(sizeHints); | |||
sizeHints.flags = PMinSize|PMaxSize; | |||
sizeHints.min_width = width; | |||
sizeHints.min_height = height; | |||
sizeHints.max_width = width; | |||
sizeHints.max_height = height; | |||
XSetNormalHints(fDisplay, fWindow, &sizeHints); | |||
if (forceUpdate) | |||
XFlush(fDisplay); | |||
} | |||
void setTitle(const char* const title) override | |||
{ | |||
CARLA_SAFE_ASSERT_RETURN(fDisplay != nullptr,); | |||
CARLA_SAFE_ASSERT_RETURN(fWindow != 0,); | |||
XStoreName(fDisplay, fWindow, title); | |||
} | |||
void* getPtr() const noexcept | |||
{ | |||
return (void*)fWindow; | |||
} | |||
private: | |||
Display* fDisplay; | |||
Window fWindow; | |||
}; | |||
#endif | |||
// ----------------------------------------------------- | |||
#ifdef CARLA_OS_MAC | |||
CarlaPluginUi* CarlaPluginUi::newCocoa() | |||
{ | |||
return new CocoaPluginUi(); | |||
} | |||
#endif | |||
#ifdef CARLA_OS_WIN | |||
CarlaPluginUi* CarlaPluginUi::newWindows() | |||
{ | |||
return new WindowsPluginUi(); | |||
} | |||
#endif | |||
#ifdef HAVE_X11 | |||
CarlaPluginUi* CarlaPluginUi::newX11() | |||
{ | |||
return new X11PluginUi(); | |||
} | |||
#endif | |||
// ----------------------------------------------------- |
@@ -0,0 +1,52 @@ | |||
/* | |||
* Carla Plugin UI | |||
* Copyright (C) 2014 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 | |||
* published by the Free Software Foundation; either version 2 of | |||
* the License, or 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. | |||
* | |||
* For a full copy of the GNU General Public License see the doc/GPL.txt file. | |||
*/ | |||
#ifndef CARLA_PLUGIN_UI_HPP_INCLUDED | |||
#define CARLA_PLUGIN_UI_HPP_INCLUDED | |||
#include "CarlaUtils.hpp" | |||
// ----------------------------------------------------- | |||
class CarlaPluginUi | |||
{ | |||
protected: | |||
CarlaPluginUi() noexcept {} | |||
public: | |||
virtual ~CarlaPluginUi() {} | |||
virtual void show() = 0; | |||
virtual void hide() = 0; | |||
virtual void focus() = 0; | |||
virtual void idle() = 0; | |||
virtual void setSize(const uint with, const uint height, const bool forceUpdate) = 0; | |||
virtual void setTitle(const char* const title) = 0; | |||
virtual void* getPtr() const noexcept = 0; | |||
#ifdef CARLA_OS_MAC | |||
static CarlaPluginUi* newCocoa(); | |||
#endif | |||
#ifdef CARLA_OS_WIN | |||
static CarlaPluginUi* newWindows(); | |||
#endif | |||
#ifdef HAVE_X11 | |||
static CarlaPluginUi* newX11(); | |||
#endif | |||
}; | |||
// ----------------------------------------------------- | |||
#endif // CARLA_PLUGIN_UI_HPP_INCLUDED |
@@ -2092,7 +2092,7 @@ private: | |||
static bool addUniqueMultiSynth(const char* const label) | |||
{ | |||
CARLA_SAFE_ASSERT_RETURN(label != nullptr, true); | |||
CARLA_SAFE_ASSERT_RETURN(label != nullptr && label[0] != '\0', false); | |||
for (LinkedList<const char*>::Itenerator it = sMultiSynthList.begin(); it.valid(); it.next()) | |||
{ | |||
@@ -2108,17 +2108,17 @@ private: | |||
static void removeUniqueMultiSynth(const char* const label) | |||
{ | |||
CARLA_SAFE_ASSERT_RETURN(label != nullptr,); | |||
CARLA_SAFE_ASSERT_RETURN(label != nullptr && label[0] != '\0',); | |||
for (LinkedList<const char*>::Itenerator it = sMultiSynthList.begin(); it.valid(); it.next()) | |||
{ | |||
const char*& itLabel(it.getValue()); | |||
const char* const itLabel(it.getValue()); | |||
if (std::strcmp(label, itLabel) == 0) | |||
{ | |||
sMultiSynthList.remove(it); | |||
delete[] itLabel; | |||
return; | |||
break; | |||
} | |||
} | |||
} | |||
@@ -24,6 +24,7 @@ | |||
#include "CarlaMathUtils.hpp" | |||
#include "CarlaLv2Utils.hpp" | |||
#include "CarlaPluginUi.hpp" | |||
#include "Lv2AtomQueue.hpp" | |||
#include "../engine/CarlaEngineOsc.hpp" | |||
@@ -35,11 +36,6 @@ extern "C" { | |||
#include <QtCore/QDir> | |||
#include <QtCore/QUrl> | |||
#ifdef HAVE_DGL | |||
# include "dgl/App.hpp" | |||
# include "dgl/Window.hpp" | |||
#endif | |||
// ----------------------------------------------------- | |||
CARLA_BACKEND_START_NAMESPACE | |||
@@ -424,6 +420,12 @@ public: | |||
fUi.title = nullptr; | |||
} | |||
if (fUi.window != nullptr) | |||
{ | |||
delete fUi.window; | |||
fUi.window = nullptr; | |||
} | |||
fUi.rdfDescriptor = nullptr; | |||
} | |||
@@ -918,7 +920,8 @@ public: | |||
delete[] fUi.title; | |||
fUi.title = carla_strdup(guiTitle.toUtf8().constData()); | |||
fUi.glWindow.setTitle(fUi.title); | |||
if (fUi.window != nullptr) | |||
fUi.window->setTitle(fUi.title); | |||
if (fFeatures[kFeatureIdExternalUi] != nullptr && fFeatures[kFeatureIdExternalUi]->data != nullptr) | |||
((LV2_External_UI_Host*)fFeatures[kFeatureIdExternalUi]->data)->plugin_human_id = fUi.title; | |||
@@ -1109,6 +1112,64 @@ public: | |||
{ | |||
if (fUi.handle == nullptr) | |||
{ | |||
const char* msg = nullptr; | |||
switch (fUi.rdfDescriptor->Type) | |||
{ | |||
case LV2_UI_GTK2: | |||
case LV2_UI_GTK3: | |||
case LV2_UI_QT4: | |||
case LV2_UI_QT5: | |||
case LV2_UI_EXTERNAL: | |||
case LV2_UI_OLD_EXTERNAL: | |||
msg = "Invalid UI type"; | |||
break; | |||
case LV2_UI_COCOA: | |||
#ifdef CARLA_OS_MAC | |||
fUi.window = CarlaPluginUi::newCocoa(); | |||
#else | |||
msg = "UI is for MacOS only"; | |||
#endif | |||
break; | |||
case LV2_UI_WINDOWS: | |||
#ifdef CARLA_OS_WIN | |||
fUi.window = CarlaPluginUi::newWindows(); | |||
#else | |||
msg = "UI is for Windows only"; | |||
#endif | |||
break; | |||
case LV2_UI_X11: | |||
#ifdef HAVE_X11 | |||
fUi.window = CarlaPluginUi::newX11(); | |||
#else | |||
msg = "UI is only for systems with X11"; | |||
#endif | |||
break; | |||
default: | |||
msg = "Unknown UI type"; | |||
break; | |||
} | |||
if (fUi.window == nullptr) | |||
return pData->engine->callback(ENGINE_CALLBACK_UI_STATE_CHANGED, pData->id, -1, 0, 0.0f, msg); | |||
fUi.window->setTitle(fUi.title); | |||
#if 0 | |||
if (const char* const win = getenv("CARLA_TRANSIENT_WINDOW")) | |||
{ | |||
const long winl = std::atol(win); | |||
carla_stderr2("got transient, %s vs %li", win, winl); | |||
fUi.window->setTransient(winl); | |||
} | |||
#endif | |||
fFeatures[kFeatureIdUiParent]->data = fUi.window->getPtr(); | |||
fUi.widget = nullptr; | |||
fUi.handle = fUi.descriptor->instantiate(fUi.descriptor, fRdfDescriptor->URI, fUi.rdfDescriptor->Bundle, | |||
carla_lv2_ui_write_function, this, &fUi.widget, fFeatures); | |||
@@ -1127,14 +1188,15 @@ public: | |||
fUi.handle = nullptr; | |||
} | |||
pData->engine->callback(ENGINE_CALLBACK_UI_STATE_CHANGED, pData->id, -1, 0, 0.0f, "Plugin refused to open its own UI"); | |||
return; | |||
return pData->engine->callback(ENGINE_CALLBACK_UI_STATE_CHANGED, pData->id, -1, 0, 0.0f, "Plugin refused to open its own UI"); | |||
} | |||
updateUi(); | |||
if (fUi.type == UI::TYPE_EMBED) | |||
fUi.glWindow.show(); | |||
{ | |||
fUi.window->show(); | |||
} | |||
else | |||
LV2_EXTERNAL_UI_SHOW((LV2_External_UI_Widget*)fUi.widget); | |||
} | |||
@@ -1142,7 +1204,10 @@ public: | |||
{ | |||
if (fUi.type == UI::TYPE_EMBED) | |||
{ | |||
fUi.glWindow.hide(); | |||
CARLA_SAFE_ASSERT(fUi.window != nullptr); | |||
if (fUi.window != nullptr) | |||
fUi.window->hide(); | |||
} | |||
else | |||
{ | |||
@@ -1155,9 +1220,6 @@ public: | |||
fUi.descriptor->cleanup(fUi.handle); | |||
fUi.handle = nullptr; | |||
fUi.widget = nullptr; | |||
if (fUi.type == UI::TYPE_EMBED) | |||
fUi.glWindow.close(); | |||
} | |||
} | |||
@@ -3990,11 +4052,12 @@ public: | |||
int handleUiResize(const int width, const int height) | |||
{ | |||
CARLA_SAFE_ASSERT_RETURN(fUi.window != nullptr, 1); | |||
CARLA_SAFE_ASSERT_RETURN(width > 0, 1); | |||
CARLA_SAFE_ASSERT_RETURN(height > 0, 1); | |||
carla_debug("Lv2Plugin::handleUiResize(%i, %i)", width, height); | |||
fUi.glWindow.setSize(static_cast<uint>(width), static_cast<uint>(height)); | |||
fUi.window->setSize(static_cast<uint>(width), static_cast<uint>(height), true); | |||
return 0; | |||
} | |||
@@ -4682,16 +4745,6 @@ public: | |||
QString guiTitle(QString("%1 (GL GUI)").arg(pData->name)); | |||
fUi.title = carla_strdup(guiTitle.toUtf8().constData()); | |||
fUi.glWindow.setResizable(isUiResizable()); | |||
fUi.glWindow.setTitle(fUi.title); | |||
if (const char* const win = getenv("CARLA_TRANSIENT_WINDOW")) | |||
{ | |||
const long winl = std::atol(win); | |||
carla_stderr2("got transient, %s vs %li", win, winl); | |||
fUi.glWindow.setTransient(winl); | |||
} | |||
// --------------------------------------------------------------- | |||
// initialize ui features (part 1) | |||
@@ -4735,7 +4788,7 @@ public: | |||
fFeatures[kFeatureIdUiNoUserResize]->data = nullptr; | |||
fFeatures[kFeatureIdUiParent]->URI = LV2_UI__parent; | |||
fFeatures[kFeatureIdUiParent]->data = (void*)fUi.glWindow.getWindowId(); | |||
fFeatures[kFeatureIdUiParent]->data = nullptr; | |||
fFeatures[kFeatureIdUiPortMap]->URI = LV2_UI__portMap; | |||
fFeatures[kFeatureIdUiPortMap]->data = uiPortMapFt; | |||
@@ -4839,8 +4892,7 @@ private: | |||
const LV2_RDF_UI* rdfDescriptor; | |||
const char* title; | |||
DGL::App glApp; | |||
DGL::Window glWindow; | |||
CarlaPluginUi* window; | |||
UI() | |||
: type(TYPE_NULL), | |||
@@ -4849,8 +4901,7 @@ private: | |||
descriptor(nullptr), | |||
rdfDescriptor(nullptr), | |||
title(nullptr), | |||
glApp(), | |||
glWindow(glApp) {} | |||
window(nullptr) {} | |||
~UI() | |||
{ | |||
@@ -4859,6 +4910,7 @@ private: | |||
CARLA_ASSERT(descriptor == nullptr); | |||
CARLA_ASSERT(rdfDescriptor == nullptr); | |||
CARLA_ASSERT(title == nullptr); | |||
CARLA_ASSERT(window == nullptr); | |||
} | |||
} fUi; | |||
@@ -9,6 +9,7 @@ include ../Makefile.mk | |||
# ---------------------------------------------------------------------------------------------------------------------------- | |||
CARLA_ENGINE_OSC_HPP = ../engine/CarlaEngineOsc.hpp $(CARLA_BACKEND_H) $(CARLA_OSC_UTILS_HPP) $(CARLA_STRING_HPP) | |||
CARLA_PLUGIN_UI_HPP = CarlaPluginUi.hpp $(CARLA_UTILS_HPP) | |||
CARLA_PLUGIN_THREAD_HPP = CarlaPluginThread.hpp $(CARLA_BACKEND_H) $(CARLA_THREAD_HPP) | |||
CARLA_PLUGIN_INTERNAL_HPP = CarlaPluginInternal.hpp $(CARLA_PLUGIN_HPP) $(CARLA_PLUGIN_THREAD_HPP) $(CARLA_OSC_UTILS_HPP) $(CARLA_STATE_UTILS_HPP) $(CARLA_MUTEX_HPP) $(RT_LINKED_LIST_HPP) $(CARLA_MIDI_H) | |||
@@ -18,6 +19,7 @@ OBJS = \ | |||
CarlaPlugin.cpp.o \ | |||
CarlaPluginInternal.cpp.o \ | |||
CarlaPluginThread.cpp.o \ | |||
CarlaPluginUi.cpp.o \ | |||
NativePlugin.cpp.o \ | |||
BridgePlugin.cpp.o \ | |||
LadspaPlugin.cpp.o \ | |||
@@ -61,6 +63,9 @@ CarlaPluginInternal.cpp.o: CarlaPluginInternal.cpp $(CARLA_PLUGIN_INTERNAL_HPP) | |||
CarlaPluginThread.cpp.o: CarlaPluginThread.cpp $(CARLA_PLUGIN_HPP) $(CARLA_PLUGIN_THREAD_HPP) $(CARLA_ENGINE_HPP) | |||
$(CXX) $< $(BUILD_CXX_FLAGS) $(QTCORE_FLAGS) -c -o $@ | |||
CarlaPluginUi.cpp.o: CarlaPluginUi.cpp $(CARLA_PLUGIN_UI_HPP) $(CARLA_UTILS_HPP) | |||
$(CXX) $< $(BUILD_CXX_FLAGS) -c -o $@ | |||
NativePlugin.cpp.o: NativePlugin.cpp $(CARLA_PLUGIN_INTERNAL_HPP) $(CARLA_ENGINE_HPP) $(CARLA_MATH_UTILS_HPP) $(CARLA_NATIVE_H) $(CARLA_HOST_H) | |||
$(CXX) $< $(BUILD_CXX_FLAGS) $(QTCORE_FLAGS) -c -o $@ | |||
@@ -73,7 +78,7 @@ LadspaPlugin.cpp.o: LadspaPlugin.cpp $(CARLA_PLUGIN_INTERNAL_HPP) $(CARLA_ENGINE | |||
DssiPlugin.cpp.o: DssiPlugin.cpp $(CARLA_PLUGIN_INTERNAL_HPP) $(CARLA_ENGINE_HPP) $(CARLA_DSSI_UTILS_HPP) $(CARLA_MATH_UTILS_HPP) | |||
$(CXX) $< $(BUILD_CXX_FLAGS) $(QTCORE_FLAGS) -c -o $@ | |||
Lv2Plugin.cpp.o: Lv2Plugin.cpp $(CARLA_PLUGIN_INTERNAL_HPP) $(CARLA_ENGINE_HPP) $(CARLA_LV2_UTILS_HPP) $(CARLA_MATH_UTILS_HPP) $(LV2_ATOM_QUEUE_HPP) $(CARLA_ENGINE_OSC_HPP) | |||
Lv2Plugin.cpp.o: Lv2Plugin.cpp $(CARLA_PLUGIN_INTERNAL_HPP) $(CARLA_ENGINE_HPP) $(CARLA_MATH_UTILS_HPP) $(CARLA_LV2_UTILS_HPP) $(CARLA_PLUGIN_UI_HPP) $(LV2_ATOM_QUEUE_HPP) $(CARLA_ENGINE_OSC_HPP) | |||
$(CXX) $< $(BUILD_CXX_FLAGS) $(QTCORE_FLAGS) -c -o $@ | |||
VstPlugin.cpp.o: VstPlugin.cpp $(CARLA_PLUGIN_INTERNAL_HPP) $(CARLA_ENGINE_HPP) $(CARLA_VST_UTILS_HPP) $(CARLA_MATH_UTILS_HPP) | |||