diff --git a/source/Makefile.mk b/source/Makefile.mk index 0efe5f2f8..db8197aa2 100644 --- a/source/Makefile.mk +++ b/source/Makefile.mk @@ -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) diff --git a/source/backend/plugin/CarlaPluginUi.cpp b/source/backend/plugin/CarlaPluginUi.cpp new file mode 100644 index 000000000..8d909e728 --- /dev/null +++ b/source/backend/plugin/CarlaPluginUi.cpp @@ -0,0 +1,168 @@ +/* + * Carla Plugin UI + * Copyright (C) 2014 Filipe Coelho + * + * 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 +# include +# include +#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(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(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 + +// ----------------------------------------------------- diff --git a/source/backend/plugin/CarlaPluginUi.hpp b/source/backend/plugin/CarlaPluginUi.hpp new file mode 100644 index 000000000..60e7b9b55 --- /dev/null +++ b/source/backend/plugin/CarlaPluginUi.hpp @@ -0,0 +1,52 @@ +/* + * Carla Plugin UI + * Copyright (C) 2014 Filipe Coelho + * + * 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 diff --git a/source/backend/plugin/DssiPlugin.cpp b/source/backend/plugin/DssiPlugin.cpp index 887e7542d..69cf6655d 100644 --- a/source/backend/plugin/DssiPlugin.cpp +++ b/source/backend/plugin/DssiPlugin.cpp @@ -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::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::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; } } } diff --git a/source/backend/plugin/Lv2Plugin.cpp b/source/backend/plugin/Lv2Plugin.cpp index fe31653bd..d47e99aa7 100644 --- a/source/backend/plugin/Lv2Plugin.cpp +++ b/source/backend/plugin/Lv2Plugin.cpp @@ -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 #include -#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(width), static_cast(height)); + fUi.window->setSize(static_cast(width), static_cast(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; diff --git a/source/backend/plugin/Makefile b/source/backend/plugin/Makefile index 1c1cfcef4..a178765c2 100644 --- a/source/backend/plugin/Makefile +++ b/source/backend/plugin/Makefile @@ -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)