| @@ -27,6 +27,10 @@ | |||
| #include "water/files/File.h" | |||
| #ifdef CARLA_OS_MAC | |||
| # import <Cocoa/Cocoa.h> | |||
| #endif | |||
| #ifndef CARLA_UTILS_CACHED_PLUGINS_ONLY | |||
| # include "rtaudio/RtAudio.h" | |||
| # include "rtmidi/RtMidi.h" | |||
| @@ -711,7 +715,8 @@ const char* carla_get_library_folder() | |||
| void carla_x11_reparent_window(uintptr_t winId1, uintptr_t winId2) | |||
| { | |||
| carla_debug("carla_x11_reparent_window()"); | |||
| CARLA_SAFE_ASSERT_RETURN(winId1 != 0,); | |||
| CARLA_SAFE_ASSERT_RETURN(winId2 != 0,); | |||
| #ifdef HAVE_X11 | |||
| if (::Display* const disp = XOpenDisplay(nullptr)) | |||
| @@ -725,6 +730,8 @@ void carla_x11_reparent_window(uintptr_t winId1, uintptr_t winId2) | |||
| void carla_x11_move_window(uintptr_t winId, int x, int y) | |||
| { | |||
| CARLA_SAFE_ASSERT_RETURN(winId != 0,); | |||
| #ifdef HAVE_X11 | |||
| if (::Display* const disp = XOpenDisplay(nullptr)) | |||
| { | |||
| @@ -736,12 +743,15 @@ void carla_x11_move_window(uintptr_t winId, int x, int y) | |||
| int* carla_x11_get_window_pos(uintptr_t winId) | |||
| { | |||
| carla_debug("carla_x11_get_window_pos()"); | |||
| static int pos[2]; | |||
| if (winId == 0) | |||
| { | |||
| pos[0] = 0; | |||
| pos[1] = 0; | |||
| } | |||
| #ifdef HAVE_X11 | |||
| if (::Display* const disp = XOpenDisplay(nullptr)) | |||
| else if (::Display* const disp = XOpenDisplay(nullptr)) | |||
| { | |||
| int x, y; | |||
| Window child; | |||
| @@ -752,8 +762,8 @@ int* carla_x11_get_window_pos(uintptr_t winId) | |||
| pos[0] = x - xwa.x; | |||
| pos[1] = y - xwa.y; | |||
| } | |||
| else | |||
| #endif | |||
| else | |||
| { | |||
| pos[0] = 0; | |||
| pos[1] = 0; | |||
| @@ -762,6 +772,18 @@ int* carla_x11_get_window_pos(uintptr_t winId) | |||
| return pos; | |||
| } | |||
| int carla_cocoa_get_window(void* nsViewPtr) | |||
| { | |||
| CARLA_SAFE_ASSERT_RETURN(nsViewPtr != nullptr, 0); | |||
| #ifdef CARLA_OS_MAC | |||
| NSView* nsView = (NSView*)nsViewPtr; | |||
| return [[nsView window] windowNumber]; | |||
| #else | |||
| return 0; | |||
| #endif | |||
| } | |||
| // ------------------------------------------------------------------------------------------------------------------- | |||
| #include "CarlaPipeUtils.cpp" | |||
| @@ -248,6 +248,8 @@ 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); | |||
| CARLA_EXPORT int carla_cocoa_get_window(void* nsViewPtr); | |||
| // ------------------------------------------------------------------------------------------------------------------- | |||
| /** @} */ | |||
| @@ -110,6 +110,11 @@ $(OBJDIR)/CarlaStandalone.cpp.o: CarlaStandalone.cpp | |||
| -@mkdir -p $(OBJDIR) | |||
| @echo "Compiling $<" | |||
| @$(CXX) $< $(BUILD_CXX_FLAGS) -ObjC++ -c -o $@ | |||
| $(OBJDIR)/CarlaUtils.cpp.o: CarlaUtils.cpp | |||
| -@mkdir -p $(OBJDIR) | |||
| @echo "Compiling $<" | |||
| @$(CXX) $< $(BUILD_CXX_FLAGS) -ObjC++ -c -o $@ | |||
| endif | |||
| $(OBJDIR)/%.cpp.o: %.cpp | |||
| @@ -496,7 +496,7 @@ private: | |||
| // ------------------------------------------------------------------------------------------------------------------- | |||
| class CarlaPluginLV2 : public CarlaPlugin, | |||
| private CarlaPluginUI::CloseCallback | |||
| private CarlaPluginUI::Callback | |||
| { | |||
| public: | |||
| CarlaPluginLV2(CarlaEngine* const engine, const uint id) | |||
| @@ -49,7 +49,7 @@ static const int32_t kVstMidiEventSize = static_cast<int32_t>(sizeof(VstMidiEven | |||
| // ----------------------------------------------------- | |||
| class CarlaPluginVST2 : public CarlaPlugin, | |||
| private CarlaPluginUI::CloseCallback | |||
| private CarlaPluginUI::Callback | |||
| { | |||
| public: | |||
| CarlaPluginVST2(CarlaEngine* const engine, const uint id) | |||
| @@ -435,7 +435,7 @@ public: | |||
| const char* msg = nullptr; | |||
| const uintptr_t frontendWinId(pData->engine->getOptions().frontendWinId); | |||
| #if defined(CARLA_OS_MAC) && defined(__LP64__) | |||
| #if defined(CARLA_OS_MAC) && defined(CARLA_OS_64BIT) | |||
| fUI.window = CarlaPluginUI::newCocoa(this, frontendWinId, false); | |||
| #elif defined(CARLA_OS_WIN) | |||
| fUI.window = CarlaPluginUI::newWindows(this, frontendWinId, false); | |||
| @@ -178,7 +178,12 @@ public: | |||
| for (; runMainLoopOnce() && ! gCloseNow;) | |||
| { | |||
| gIdle(); | |||
| #if defined(CARLA_OS_MAC) || defined(CARLA_OS_WIN) | |||
| // MacOS and Win32 have event-loops to run, so minimize sleep time | |||
| carla_msleep(1); | |||
| #else | |||
| carla_msleep(5); | |||
| #endif | |||
| } | |||
| carla_set_engine_about_to_close(); | |||
| @@ -17,15 +17,17 @@ | |||
| #include "CarlaBridgeUI.hpp" | |||
| #include "CarlaBridgeToolkit.hpp" | |||
| #include "CarlaMainLoop.hpp" | |||
| #include "CarlaPluginUI.hpp" | |||
| CARLA_BRIDGE_START_NAMESPACE | |||
| using CarlaBackend::runMainLoopOnce; | |||
| // ------------------------------------------------------------------------- | |||
| class CarlaBridgeToolkitPlugin : public CarlaBridgeToolkit, | |||
| private CarlaPluginUI::CloseCallback | |||
| private CarlaPluginUI::Callback | |||
| { | |||
| public: | |||
| CarlaBridgeToolkitPlugin(CarlaBridgeUI* const u) | |||
| @@ -50,9 +52,9 @@ public: | |||
| const CarlaBridgeUI::Options& options(ui->getOptions()); | |||
| #if defined(CARLA_OS_MAC) && defined(BRIDGE_COCOA) | |||
| fUI = nullptr; | |||
| fUI = CarlaPluginUI::newCocoa(this, 0, options.isResizable); | |||
| #elif defined(CARLA_OS_WIN) && defined(BRIDGE_HWND) | |||
| fUI = nullptr; | |||
| fUI = CarlaPluginUI::newWindows(this, 0, options.isResizable); | |||
| #elif defined(HAVE_X11) && defined(BRIDGE_X11) | |||
| fUI = CarlaPluginUI::newX11(this, 0, options.isResizable); | |||
| #endif | |||
| @@ -60,8 +62,11 @@ public: | |||
| fUI->setTitle(options.windowTitle.buffer()); | |||
| #ifdef HAVE_X11 | |||
| // Out-of-process reparenting only possible on X11 | |||
| if (options.transientWindowId != 0) | |||
| fUI->setTransientWinId(options.transientWindowId); | |||
| #endif | |||
| return true; | |||
| } | |||
| @@ -83,14 +88,19 @@ public: | |||
| fIdling = true; | |||
| for (; fIdling;) | |||
| for (; runMainLoopOnce() && fIdling;) | |||
| { | |||
| if (ui->isPipeRunning()) | |||
| ui->idlePipe(); | |||
| ui->idleUI(); | |||
| fUI->idle(); | |||
| #if defined(CARLA_OS_MAC) || defined(CARLA_OS_WIN) | |||
| // MacOS and Win32 have event-loops to run, so minimize sleep time | |||
| carla_msleep(1); | |||
| #else | |||
| carla_msleep(20); | |||
| #endif | |||
| } | |||
| } | |||
| @@ -2129,7 +2129,11 @@ class HostWindow(QMainWindow): | |||
| # set our gui as parent for all plugins UIs | |||
| if self.host.manageUIs and not (self.host.isControl or self.host.isPlugin): | |||
| winIdStr = "%x" % int(self.winId()) | |||
| if MACOS: | |||
| nsViewPtr = int(self.winId()) | |||
| winIdStr = "%x" % gCarla.utils.cocoa_get_window(nsViewPtr) | |||
| else: | |||
| winIdStr = "%x" % int(self.winId()) | |||
| self.host.set_engine_option(ENGINE_OPTION_FRONTEND_WIN_ID, 0, winIdStr) | |||
| def hideEvent(self, event): | |||
| @@ -243,7 +243,7 @@ class CarlaSettingsW(QDialog): | |||
| self.ui.ch_main_show_logs.setEnabled(False) | |||
| self.ui.ch_main_show_logs.setVisible(False) | |||
| if MACOS or WINDOWS: | |||
| if WINDOWS: | |||
| self.ui.ch_engine_manage_uis.setEnabled(False) | |||
| self.ui.ch_engine_manage_uis.setVisible(False) | |||
| @@ -224,6 +224,9 @@ class CarlaUtils(object): | |||
| self.lib.carla_x11_get_window_pos.argtypes = [c_uintptr] | |||
| self.lib.carla_x11_get_window_pos.restype = POINTER(c_int) | |||
| self.lib.carla_cocoa_get_window.argtypes = [c_uintptr] | |||
| self.lib.carla_cocoa_get_window.restype = c_int | |||
| # use _putenv on windows | |||
| if not WINDOWS: | |||
| self.msvcrt = None | |||
| @@ -338,4 +341,7 @@ class CarlaUtils(object): | |||
| data = self.lib.carla_x11_get_window_pos(winId) | |||
| return (int(data[0]), int(data[1])) | |||
| def cocoa_get_window(self, winId): | |||
| return self.lib.carla_cocoa_get_window(winId) | |||
| # ------------------------------------------------------------------------------------------------------------ | |||
| @@ -403,11 +403,7 @@ struct Window::PrivateData { | |||
| SetFocus(hwnd); | |||
| #elif defined(DISTRHO_OS_MAC) | |||
| if (mWindow != nullptr) | |||
| { | |||
| // TODO | |||
| //[NSApp activateIgnoringOtherApps:YES]; | |||
| //[mWindow makeKeyAndOrderFront:mWindow]; | |||
| } | |||
| [mWindow makeKeyWindow]; | |||
| #elif defined(DISTRHO_OS_LINUX) | |||
| XRaiseWindow(xDisplay, xWindow); | |||
| XSetInputFocus(xDisplay, xWindow, RevertToPointerRoot, CurrentTime); | |||
| @@ -626,12 +622,17 @@ struct Window::PrivateData { | |||
| void setTransientWinId(const uintptr_t winId) | |||
| { | |||
| #if defined(DISTRHO_OS_LINUX) | |||
| DISTRHO_SAFE_ASSERT_RETURN(winId != 0,); | |||
| #if defined(DISTRHO_OS_MAC) | |||
| NSWindow* window = [NSApp windowWithWindowNumber:winId]; | |||
| DISTRHO_SAFE_ASSERT_RETURN(window != nullptr,); | |||
| [window addChildWindow:mWindow | |||
| ordered:NSWindowAbove]; | |||
| [mWindow makeKeyWindow]; | |||
| #elif defined(DISTRHO_OS_LINUX) | |||
| XSetTransientForHint(xDisplay, xWindow, static_cast< ::Window>(winId)); | |||
| #else | |||
| return; | |||
| // unused | |||
| (void)winId; | |||
| #endif | |||
| } | |||
| @@ -53,7 +53,7 @@ static int temporaryErrorHandler(Display*, XErrorEvent*) | |||
| class X11PluginUI : public CarlaPluginUI | |||
| { | |||
| public: | |||
| X11PluginUI(CloseCallback* const cb, const uintptr_t parentId, const bool isResizable) noexcept | |||
| X11PluginUI(Callback* const cb, const uintptr_t parentId, const bool isResizable) noexcept | |||
| : CarlaPluginUI(cb, isResizable), | |||
| fDisplay(nullptr), | |||
| fWindow(0), | |||
| @@ -330,16 +330,18 @@ private: | |||
| @interface CarlaPluginWindow : NSWindow | |||
| { | |||
| @public | |||
| CarlaPluginUI::CloseCallback* callback; | |||
| CarlaPluginUI::Callback* callback; | |||
| NSView* view; | |||
| } | |||
| - (id) initWithContentRect:(NSRect)contentRect | |||
| styleMask:(unsigned int)aStyle | |||
| backing:(NSBackingStoreType)bufferingType | |||
| defer:(BOOL)flag; | |||
| - (void) setCloseCallback:(CarlaPluginUI::CloseCallback*)cb; | |||
| - (void) setup:(CarlaPluginUI::Callback*)cb view:(NSView*)v; | |||
| - (BOOL) canBecomeKeyWindow; | |||
| - (BOOL) windowShouldClose:(id)sender; | |||
| - (NSSize) windowWillResize:(NSWindow*)sender toSize:(NSSize)frameSize; | |||
| @end | |||
| @implementation CarlaPluginWindow | |||
| @@ -350,6 +352,7 @@ private: | |||
| defer:(BOOL)flag | |||
| { | |||
| callback = nil; | |||
| view = nil; | |||
| NSWindow* result = [super initWithContentRect:contentRect | |||
| styleMask:(NSClosableWindowMask | | |||
| @@ -367,9 +370,10 @@ private: | |||
| (void)aStyle; (void)bufferingType; (void)flag; | |||
| } | |||
| - (void)setCloseCallback:(CarlaPluginUI::CloseCallback*)cb | |||
| - (void)setup:(CarlaPluginUI::Callback*)cb view:(NSView*)v | |||
| { | |||
| callback = cb; | |||
| view = v; | |||
| } | |||
| - (BOOL)canBecomeKeyWindow | |||
| @@ -379,23 +383,36 @@ private: | |||
| - (BOOL)windowShouldClose:(id)sender | |||
| { | |||
| if (callback) | |||
| if (callback != nil) | |||
| callback->handlePluginUIClosed(); | |||
| return NO; | |||
| // unused | |||
| (void)sender; | |||
| } | |||
| - (NSSize) windowWillResize:(NSWindow*)sender toSize:(NSSize)frameSize | |||
| { | |||
| if (callback != nil) | |||
| callback->handlePluginUIResized(frameSize.width, frameSize.height); | |||
| return frameSize; | |||
| // unused | |||
| (void)sender; | |||
| } | |||
| @end | |||
| class CocoaPluginUI : public CarlaPluginUI | |||
| { | |||
| public: | |||
| CocoaPluginUI(CloseCallback* const cb, const uintptr_t parentId, const bool isResizable) noexcept | |||
| CocoaPluginUI(Callback* const cb, const uintptr_t parentId, const bool isResizable) noexcept | |||
| : CarlaPluginUI(cb, isResizable), | |||
| fView(nullptr), | |||
| fWindow(0) | |||
| fWindow(0), | |||
| fParentId(parentId) | |||
| { | |||
| [NSAutoreleasePool new]; | |||
| [NSApplication sharedApplication]; | |||
| @@ -418,13 +435,16 @@ public: | |||
| if (! isResizable) | |||
| [[fWindow standardWindowButton:NSWindowZoomButton] setHidden:YES]; | |||
| [fWindow setCloseCallback:cb]; | |||
| [fWindow setup:cb view:fView]; | |||
| [fWindow setContentView:fView]; | |||
| [fWindow makeFirstResponder:fView]; | |||
| [fWindow makeKeyAndOrderFront:fWindow]; | |||
| [NSApp activateIgnoringOtherApps:YES]; | |||
| [fWindow center]; | |||
| if (parentId != 0) | |||
| setTransientWinId(parentId); | |||
| } | |||
| ~CocoaPluginUI() override | |||
| @@ -443,6 +463,9 @@ public: | |||
| [fView setHidden:NO]; | |||
| [fWindow setIsVisible:YES]; | |||
| if (fParentId != 0) | |||
| setTransientWinId(fParentId); | |||
| } | |||
| void hide() override | |||
| @@ -459,14 +482,14 @@ public: | |||
| void focus() override | |||
| { | |||
| CARLA_SAFE_ASSERT_RETURN(fWindow != nullptr,); | |||
| CARLA_SAFE_ASSERT_RETURN(fWindow != 0,); | |||
| // TODO | |||
| [fWindow makeKeyWindow]; | |||
| } | |||
| void setSize(const uint width, const uint height, const bool forceUpdate) override | |||
| { | |||
| CARLA_SAFE_ASSERT_RETURN(fWindow != nullptr,); | |||
| CARLA_SAFE_ASSERT_RETURN(fWindow != 0,); | |||
| CARLA_SAFE_ASSERT_RETURN(fView != nullptr,); | |||
| [fView setFrame:NSMakeRect(0, 0, width, height)]; | |||
| @@ -504,7 +527,12 @@ public: | |||
| { | |||
| CARLA_SAFE_ASSERT_RETURN(fWindow != 0,); | |||
| // TODO | |||
| NSWindow* window = [NSApp windowWithWindowNumber:winId]; | |||
| CARLA_SAFE_ASSERT_RETURN(window != nullptr,); | |||
| [window addChildWindow:fWindow | |||
| ordered:NSWindowAbove]; | |||
| [fWindow makeKeyWindow]; | |||
| } | |||
| void* getPtr() const noexcept override | |||
| @@ -520,6 +548,7 @@ public: | |||
| private: | |||
| NSView* fView; | |||
| id fWindow; | |||
| uintptr_t fParentId; | |||
| CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(CocoaPluginUI) | |||
| }; | |||
| @@ -538,7 +567,7 @@ static LRESULT CALLBACK wndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM l | |||
| class WindowsPluginUI : public CarlaPluginUI | |||
| { | |||
| public: | |||
| WindowsPluginUI(CloseCallback* const cb, const uintptr_t parentId, const bool isResizable) noexcept | |||
| WindowsPluginUI(Callback* const cb, const uintptr_t parentId, const bool isResizable) noexcept | |||
| : CarlaPluginUI(cb, isResizable), | |||
| fWindow(0), | |||
| fIsVisible(false), | |||
| @@ -582,6 +611,9 @@ public: | |||
| } | |||
| SetWindowLongPtr(fWindow, GWLP_USERDATA, (LONG_PTR)this); | |||
| if (parentId != 0) | |||
| setTransientWinId(parentId); | |||
| } | |||
| ~WindowsPluginUI() override | |||
| @@ -963,21 +995,21 @@ bool CarlaPluginUI::tryTransientWinIdMatch(const uintptr_t pid, const char* cons | |||
| // ----------------------------------------------------- | |||
| #ifdef HAVE_X11 | |||
| CarlaPluginUI* CarlaPluginUI::newX11(CloseCallback* cb, uintptr_t parentId, bool isResizable) | |||
| CarlaPluginUI* CarlaPluginUI::newX11(Callback* cb, uintptr_t parentId, bool isResizable) | |||
| { | |||
| return new X11PluginUI(cb, parentId, isResizable); | |||
| } | |||
| #endif | |||
| #ifdef CARLA_OS_MAC | |||
| CarlaPluginUI* CarlaPluginUI::newCocoa(CloseCallback* cb, uintptr_t parentId, bool isResizable) | |||
| CarlaPluginUI* CarlaPluginUI::newCocoa(Callback* cb, uintptr_t parentId, bool isResizable) | |||
| { | |||
| return new CocoaPluginUI(cb, parentId, isResizable); | |||
| } | |||
| #endif | |||
| #ifdef CARLA_OS_WIN | |||
| CarlaPluginUI* CarlaPluginUI::newWindows(CloseCallback* cb, uintptr_t parentId, bool isResizable) | |||
| CarlaPluginUI* CarlaPluginUI::newWindows(Callback* cb, uintptr_t parentId, bool isResizable) | |||
| { | |||
| return new WindowsPluginUI(cb, parentId, isResizable); | |||
| } | |||
| @@ -25,9 +25,9 @@ | |||
| class CarlaPluginUI | |||
| { | |||
| public: | |||
| class CloseCallback { | |||
| class Callback { | |||
| public: | |||
| virtual ~CloseCallback() {} | |||
| virtual ~Callback() {} | |||
| virtual void handlePluginUIClosed() = 0; | |||
| virtual void handlePluginUIResized(const uint width, const uint height) = 0; | |||
| }; | |||
| @@ -48,21 +48,21 @@ public: | |||
| static bool tryTransientWinIdMatch(const uintptr_t pid, const char* const uiTitle, const uintptr_t winId, const bool centerUI); | |||
| #ifdef CARLA_OS_MAC | |||
| static CarlaPluginUI* newCocoa(CloseCallback*, uintptr_t, bool); | |||
| static CarlaPluginUI* newCocoa(Callback*, uintptr_t, bool); | |||
| #endif | |||
| #ifdef CARLA_OS_WIN | |||
| static CarlaPluginUI* newWindows(CloseCallback*, uintptr_t, bool); | |||
| static CarlaPluginUI* newWindows(Callback*, uintptr_t, bool); | |||
| #endif | |||
| #ifdef HAVE_X11 | |||
| static CarlaPluginUI* newX11(CloseCallback*, uintptr_t, bool); | |||
| static CarlaPluginUI* newX11(Callback*, uintptr_t, bool); | |||
| #endif | |||
| protected: | |||
| bool fIsIdling; | |||
| bool fIsResizable; | |||
| CloseCallback* fCallback; | |||
| Callback* fCallback; | |||
| CarlaPluginUI(CloseCallback* const cb, const bool isResizable) noexcept | |||
| CarlaPluginUI(Callback* const cb, const bool isResizable) noexcept | |||
| : fIsIdling(false), | |||
| fIsResizable(isResizable), | |||
| fCallback(cb) {} | |||