| @@ -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) | |||