| @@ -1935,6 +1935,7 @@ const char* carla_get_host_osc_url_udp() | |||||
| #undef CARLA_PLUGIN_UI_CLASS_PREFIX | #undef CARLA_PLUGIN_UI_CLASS_PREFIX | ||||
| #include "CarlaDssiUtils.cpp" | #include "CarlaDssiUtils.cpp" | ||||
| #include "CarlaMacUtils.cpp" | |||||
| #include "CarlaPatchbayUtils.cpp" | #include "CarlaPatchbayUtils.cpp" | ||||
| #include "CarlaPipeUtils.cpp" | #include "CarlaPipeUtils.cpp" | ||||
| #include "CarlaStateUtils.cpp" | #include "CarlaStateUtils.cpp" | ||||
| @@ -190,7 +190,7 @@ public: | |||||
| shmNonRtClientDataSize != sizeof(BridgeNonRtClientData) || | shmNonRtClientDataSize != sizeof(BridgeNonRtClientData) || | ||||
| shmNonRtServerDataSize != sizeof(BridgeNonRtServerData)) | shmNonRtServerDataSize != sizeof(BridgeNonRtServerData)) | ||||
| { | { | ||||
| carla_stderr2("CarlaJackAppClient: data size mismatch"); | |||||
| carla_stderr2("CarlaEngineBridge: data size mismatch"); | |||||
| return false; | return false; | ||||
| } | } | ||||
| @@ -2348,6 +2348,7 @@ CARLA_BACKEND_END_NAMESPACE | |||||
| #include "CarlaHostCommon.cpp" | #include "CarlaHostCommon.cpp" | ||||
| #include "CarlaPluginUI.cpp" | #include "CarlaPluginUI.cpp" | ||||
| #include "CarlaDssiUtils.cpp" | #include "CarlaDssiUtils.cpp" | ||||
| #include "CarlaMacUtils.cpp" | |||||
| #include "CarlaPatchbayUtils.cpp" | #include "CarlaPatchbayUtils.cpp" | ||||
| #include "CarlaPipeUtils.cpp" | #include "CarlaPipeUtils.cpp" | ||||
| #include "CarlaStateUtils.cpp" | #include "CarlaStateUtils.cpp" | ||||
| @@ -481,14 +481,14 @@ public: | |||||
| const char* msg = nullptr; | const char* msg = nullptr; | ||||
| const uintptr_t frontendWinId(pData->engine->getOptions().frontendWinId); | const uintptr_t frontendWinId(pData->engine->getOptions().frontendWinId); | ||||
| #if defined(CARLA_OS_MAC) && defined(CARLA_OS_64BIT) | |||||
| #if defined(CARLA_OS_MAC) | |||||
| fUI.window = CarlaPluginUI::newCocoa(this, frontendWinId, false); | fUI.window = CarlaPluginUI::newCocoa(this, frontendWinId, false); | ||||
| #elif defined(CARLA_OS_WIN) | #elif defined(CARLA_OS_WIN) | ||||
| fUI.window = CarlaPluginUI::newWindows(this, frontendWinId, false); | fUI.window = CarlaPluginUI::newWindows(this, frontendWinId, false); | ||||
| #elif defined(HAVE_X11) | #elif defined(HAVE_X11) | ||||
| fUI.window = CarlaPluginUI::newX11(this, frontendWinId, false); | fUI.window = CarlaPluginUI::newX11(this, frontendWinId, false); | ||||
| #else | #else | ||||
| msg = "Unknown UI type"; | |||||
| msg = "Unsupported UI type"; | |||||
| // unused | // unused | ||||
| (void)frontendWinId; | (void)frontendWinId; | ||||
| #endif | #endif | ||||
| @@ -864,7 +864,13 @@ public: | |||||
| if (fEffect->flags & effFlagsHasEditor) | if (fEffect->flags & effFlagsHasEditor) | ||||
| { | { | ||||
| pData->hints |= PLUGIN_HAS_CUSTOM_UI; | |||||
| #ifndef CARLA_OS_64BIT | |||||
| if (static_cast<uintptr_t>(dispatcher(effCanDo, 0, 0, const_cast<char*>("hasCockosViewAsConfig")) & 0xffff0000) == 0xbeef0000) | |||||
| #endif | |||||
| { | |||||
| pData->hints |= PLUGIN_HAS_CUSTOM_UI; | |||||
| } | |||||
| pData->hints |= PLUGIN_NEEDS_UI_MAIN_THREAD; | pData->hints |= PLUGIN_NEEDS_UI_MAIN_THREAD; | ||||
| } | } | ||||
| @@ -874,7 +880,7 @@ public: | |||||
| if ((fEffect->flags & effFlagsCanReplacing) != 0 && fEffect->processReplacing != fEffect->process) | if ((fEffect->flags & effFlagsCanReplacing) != 0 && fEffect->processReplacing != fEffect->process) | ||||
| pData->hints |= PLUGIN_CAN_PROCESS_REPLACING; | pData->hints |= PLUGIN_CAN_PROCESS_REPLACING; | ||||
| if (static_cast<uintptr_t>(dispatcher(effCanDo, 0, 0, const_cast<char*>("hasCockosExtensions"), 0.0f)) == 0xbeef0000) | |||||
| if (static_cast<uintptr_t>(dispatcher(effCanDo, 0, 0, const_cast<char*>("hasCockosExtensions"))) == 0xbeef0000) | |||||
| pData->hints |= PLUGIN_HAS_COCKOS_EXTENSIONS; | pData->hints |= PLUGIN_HAS_COCKOS_EXTENSIONS; | ||||
| if (aOuts > 0 && (aIns == aOuts || aIns == 1)) | if (aOuts > 0 && (aIns == aOuts || aIns == 1)) | ||||
| @@ -226,5 +226,6 @@ CARLA_BRIDGE_UI_END_NAMESPACE | |||||
| #define CARLA_PLUGIN_UI_CLASS_PREFIX ToolkitNative | #define CARLA_PLUGIN_UI_CLASS_PREFIX ToolkitNative | ||||
| #include "CarlaPluginUI.cpp" | #include "CarlaPluginUI.cpp" | ||||
| #include "CarlaMacUtils.cpp" | |||||
| // ------------------------------------------------------------------------- | // ------------------------------------------------------------------------- | ||||
| @@ -281,19 +281,6 @@ class CarlaSettingsW(QDialog): | |||||
| self.ui.ch_exp_prevent_bad_behaviour.setVisible(False) | self.ui.ch_exp_prevent_bad_behaviour.setVisible(False) | ||||
| self.ui.lw_page.hideRow(self.TAB_INDEX_WINE) | self.ui.lw_page.hideRow(self.TAB_INDEX_WINE) | ||||
| if not MACOS: | |||||
| self.ui.label_engine_ui_bridges_mac_note.setVisible(False) | |||||
| # FIXME, pipes on win32 not working, and mis-behaving on macOS | |||||
| if MACOS or WINDOWS: | |||||
| self.ui.ch_engine_prefer_ui_bridges.setChecked(False) | |||||
| self.ui.ch_engine_prefer_ui_bridges.setEnabled(False) | |||||
| self.ui.ch_engine_prefer_ui_bridges.setVisible(False) | |||||
| self.ui.label_engine_ui_bridges_timeout.setEnabled(False) | |||||
| self.ui.label_engine_ui_bridges_timeout.setVisible(False) | |||||
| self.ui.sb_engine_ui_bridges_timeout.setEnabled(False) | |||||
| self.ui.sb_engine_ui_bridges_timeout.setVisible(False) | |||||
| # FIXME, not implemented yet | # FIXME, not implemented yet | ||||
| self.ui.ch_engine_uis_always_on_top.hide() | self.ui.ch_engine_uis_always_on_top.hide() | ||||
| @@ -273,7 +273,7 @@ CARLA_DEFAULT_CANVAS_HQ_ANTIALIASING = False | |||||
| # Engine | # Engine | ||||
| CARLA_DEFAULT_FORCE_STEREO = False | CARLA_DEFAULT_FORCE_STEREO = False | ||||
| CARLA_DEFAULT_PREFER_PLUGIN_BRIDGES = False | CARLA_DEFAULT_PREFER_PLUGIN_BRIDGES = False | ||||
| CARLA_DEFAULT_PREFER_UI_BRIDGES = bool(not (MACOS or WINDOWS)) | |||||
| CARLA_DEFAULT_PREFER_UI_BRIDGES = True | |||||
| CARLA_DEFAULT_MANAGE_UIS = True | CARLA_DEFAULT_MANAGE_UIS = True | ||||
| CARLA_DEFAULT_UIS_ALWAYS_ON_TOP = False | CARLA_DEFAULT_UIS_ALWAYS_ON_TOP = False | ||||
| CARLA_DEFAULT_MAX_PARAMETERS = MAX_DEFAULT_PARAMETERS | CARLA_DEFAULT_MAX_PARAMETERS = MAX_DEFAULT_PARAMETERS | ||||
| @@ -396,6 +396,7 @@ struct Window::PrivateData { | |||||
| #elif defined(DISTRHO_OS_MAC) | #elif defined(DISTRHO_OS_MAC) | ||||
| if (mWindow != nullptr) | if (mWindow != nullptr) | ||||
| [mWindow makeKeyWindow]; | [mWindow makeKeyWindow]; | ||||
| [NSApp activateIgnoringOtherApps:YES]; | |||||
| #else | #else | ||||
| XRaiseWindow(xDisplay, xWindow); | XRaiseWindow(xDisplay, xWindow); | ||||
| XSetInputFocus(xDisplay, xWindow, RevertToPointerRoot, CurrentTime); | XSetInputFocus(xDisplay, xWindow, RevertToPointerRoot, CurrentTime); | ||||
| @@ -1392,9 +1392,7 @@ static NSString* getFileLink (const String& path) | |||||
| bool File::isSymbolicLink() const | bool File::isSymbolicLink() const | ||||
| { | { | ||||
| // FIXME | |||||
| return false; | |||||
| //return getFileLink (fullPath) != nil; | |||||
| return getFileLink (fullPath) != nil; | |||||
| } | } | ||||
| File File::getLinkedTarget() const | File File::getLinkedTarget() const | ||||
| @@ -1425,43 +1423,44 @@ bool File::copyInternal (const File& dest) const | |||||
| File File::getSpecialLocation (const SpecialLocationType type) | File File::getSpecialLocation (const SpecialLocationType type) | ||||
| { | { | ||||
| //@autoreleasepool | |||||
| { | |||||
| String resultPath; | |||||
| const AutoNSAutoreleasePool arpool; | |||||
| switch (type) | |||||
| { | |||||
| case userHomeDirectory: resultPath = nsStringToWater (NSHomeDirectory()); break; | |||||
| String resultPath; | |||||
| case tempDirectory: | |||||
| { | |||||
| File tmp ("~/Library/Caches/" + water_getExecutableFile().getFileNameWithoutExtension()); | |||||
| tmp.createDirectory(); | |||||
| return File (tmp.getFullPathName()); | |||||
| } | |||||
| switch (type) | |||||
| { | |||||
| case userHomeDirectory: | |||||
| resultPath = nsStringToWater (NSHomeDirectory()); | |||||
| break; | |||||
| case currentExecutableFile: | |||||
| return water_getExecutableFile(); | |||||
| case tempDirectory: | |||||
| { | |||||
| File tmp ("~/Library/Caches/" + water_getExecutableFile().getFileNameWithoutExtension()); | |||||
| tmp.createDirectory(); | |||||
| return File (tmp.getFullPathName()); | |||||
| } | |||||
| case hostApplicationPath: | |||||
| { | |||||
| unsigned int size = 8192; | |||||
| HeapBlock<char> buffer; | |||||
| buffer.calloc (size + 8); | |||||
| case currentExecutableFile: | |||||
| return water_getExecutableFile(); | |||||
| _NSGetExecutablePath (buffer.getData(), &size); | |||||
| return File (String::fromUTF8 (buffer, (int) size)); | |||||
| } | |||||
| case hostApplicationPath: | |||||
| { | |||||
| unsigned int size = 8192; | |||||
| HeapBlock<char> buffer; | |||||
| buffer.calloc (size + 8); | |||||
| default: | |||||
| jassertfalse; // unknown type? | |||||
| break; | |||||
| _NSGetExecutablePath (buffer.getData(), &size); | |||||
| return File (String::fromUTF8 (buffer, (int) size)); | |||||
| } | } | ||||
| if (resultPath.isNotEmpty()) | |||||
| return File (resultPath.convertToPrecomposedUnicode()); | |||||
| default: | |||||
| jassertfalse; // unknown type? | |||||
| break; | |||||
| } | } | ||||
| if (resultPath.isNotEmpty()) | |||||
| return File (resultPath.convertToPrecomposedUnicode()); | |||||
| return File(); | return File(); | ||||
| } | } | ||||
| //============================================================================== | //============================================================================== | ||||
| @@ -1473,10 +1472,9 @@ public: | |||||
| wildCard (wildCard_), | wildCard (wildCard_), | ||||
| enumerator (nil) | enumerator (nil) | ||||
| { | { | ||||
| //@autoreleasepool | |||||
| { | |||||
| enumerator = [[[NSFileManager defaultManager] enumeratorAtPath: waterStringToNS (directory.getFullPathName())] retain]; | |||||
| } | |||||
| const AutoNSAutoreleasePool arpool; | |||||
| enumerator = [[[NSFileManager defaultManager] enumeratorAtPath: waterStringToNS (directory.getFullPathName())] retain]; | |||||
| } | } | ||||
| ~Pimpl() | ~Pimpl() | ||||
| @@ -1488,30 +1486,29 @@ public: | |||||
| bool* const isDir, int64* const fileSize, | bool* const isDir, int64* const fileSize, | ||||
| Time* const modTime, Time* const creationTime, bool* const isReadOnly) | Time* const modTime, Time* const creationTime, bool* const isReadOnly) | ||||
| { | { | ||||
| //@autoreleasepool | |||||
| { | |||||
| const char* wildcardUTF8 = nullptr; | |||||
| const AutoNSAutoreleasePool arpool; | |||||
| for (;;) | |||||
| { | |||||
| NSString* file; | |||||
| if (enumerator == nil || (file = [enumerator nextObject]) == nil) | |||||
| return false; | |||||
| const char* wildcardUTF8 = nullptr; | |||||
| [enumerator skipDescendents]; | |||||
| filenameFound = nsStringToWater (file).convertToPrecomposedUnicode(); | |||||
| for (;;) | |||||
| { | |||||
| NSString* file; | |||||
| if (enumerator == nil || (file = [enumerator nextObject]) == nil) | |||||
| return false; | |||||
| if (wildcardUTF8 == nullptr) | |||||
| wildcardUTF8 = wildCard.toUTF8(); | |||||
| [enumerator skipDescendents]; | |||||
| filenameFound = nsStringToWater (file).convertToPrecomposedUnicode(); | |||||
| if (fnmatch (wildcardUTF8, filenameFound.toUTF8(), FNM_CASEFOLD) != 0) | |||||
| continue; | |||||
| if (wildcardUTF8 == nullptr) | |||||
| wildcardUTF8 = wildCard.toUTF8(); | |||||
| const String fullPath (parentDir + filenameFound); | |||||
| updateStatInfoForFile (fullPath, isDir, fileSize, modTime, creationTime, isReadOnly); | |||||
| if (fnmatch (wildcardUTF8, filenameFound.toUTF8(), FNM_CASEFOLD) != 0) | |||||
| continue; | |||||
| return true; | |||||
| } | |||||
| const String fullPath (parentDir + filenameFound); | |||||
| updateStatInfoForFile (fullPath, isDir, fileSize, modTime, creationTime, isReadOnly); | |||||
| return true; | |||||
| } | } | ||||
| } | } | ||||
| @@ -83,9 +83,9 @@ LINK_FLAGS += $(MAGIC_LIBS) | |||||
| LINK_FLAGS += $(X11_LIBS) | LINK_FLAGS += $(X11_LIBS) | ||||
| ifeq ($(MACOS),true) | ifeq ($(MACOS),true) | ||||
| # NOTE: this assumes only LV2 version will be built | |||||
| SHARED += -Wl,-exported_symbol,_lv2_descriptor | |||||
| SHARED += -Wl,-exported_symbol,_lv2ui_descriptor | |||||
| SYMBOLS_LV2 = -Wl,-exported_symbol,_lv2_descriptor -Wl,-exported_symbol,_lv2ui_descriptor | |||||
| SYMBOLS_LV2_UI = -Wl,-exported_symbol,_lv2ui_descriptor | |||||
| SYMBOLS_VST = # TODO | |||||
| endif | endif | ||||
| # ---------------------------------------------------------------------------------------------------------------------------- | # ---------------------------------------------------------------------------------------------------------------------------- | ||||
| @@ -137,12 +137,12 @@ debug: | |||||
| $(BINDIR)/carla.lv2/carla$(LIB_EXT): $(OBJDIR)/carla-lv2.cpp.o $(LIBS) | $(BINDIR)/carla.lv2/carla$(LIB_EXT): $(OBJDIR)/carla-lv2.cpp.o $(LIBS) | ||||
| -@mkdir -p $(BINDIR)/carla.lv2 | -@mkdir -p $(BINDIR)/carla.lv2 | ||||
| @echo "Linking carla.lv2/carla$(LIB_EXT)" | @echo "Linking carla.lv2/carla$(LIB_EXT)" | ||||
| @$(CXX) $< $(LIBS_START) $(LIBS) $(LIBS_END) $(SHARED) $(LINK_FLAGS) -o $@ | |||||
| @$(CXX) $< $(LIBS_START) $(LIBS) $(LIBS_END) $(SHARED) $(SYMBOLS_LV2) $(LINK_FLAGS) -o $@ | |||||
| $(BINDIR)/carla.lv2/carla-ui$(LIB_EXT): $(OBJDIR)/carla-lv2-ui.cpp.o $(LIBS_ui) | $(BINDIR)/carla.lv2/carla-ui$(LIB_EXT): $(OBJDIR)/carla-lv2-ui.cpp.o $(LIBS_ui) | ||||
| -@mkdir -p $(BINDIR)/carla.lv2 | -@mkdir -p $(BINDIR)/carla.lv2 | ||||
| @echo "Linking carla.lv2/carla-ui$(LIB_EXT)" | @echo "Linking carla.lv2/carla-ui$(LIB_EXT)" | ||||
| @$(CXX) $< $(LIBS_START) $(LIBS_ui) $(LIBS_END) $(SHARED) $(LINK_FLAGS) -o $@ | |||||
| @$(CXX) $< $(LIBS_START) $(LIBS_ui) $(LIBS_END) $(SHARED) $(SYMBOLS_LV2_UI) $(LINK_FLAGS) -o $@ | |||||
| $(BINDIR)/CarlaRack$(LIB_EXT): $(OBJDIR)/carla-vst.cpp.rack-syn.o $(LIBS) | $(BINDIR)/CarlaRack$(LIB_EXT): $(OBJDIR)/carla-vst.cpp.rack-syn.o $(LIBS) | ||||
| -@mkdir -p $(BINDIR) | -@mkdir -p $(BINDIR) | ||||
| @@ -25,6 +25,9 @@ | |||||
| #ifdef HAVE_LIBMAGIC | #ifdef HAVE_LIBMAGIC | ||||
| # include <magic.h> | # include <magic.h> | ||||
| # ifdef CARLA_OS_MAC | |||||
| # include "CarlaMacUtils.hpp" | |||||
| # endif | |||||
| #endif | #endif | ||||
| CARLA_BACKEND_START_NAMESPACE | CARLA_BACKEND_START_NAMESPACE | ||||
| @@ -95,6 +98,26 @@ BinaryType getBinaryTypeFromFile(const char* const filename) | |||||
| ? BINARY_POSIX64 | ? BINARY_POSIX64 | ||||
| : BINARY_POSIX32; | : BINARY_POSIX32; | ||||
| # ifdef CARLA_OS_MAC | |||||
| if (std::strcmp(output, "directory") == 0) | |||||
| if (const char* const binary = findBinaryInBundle(filename)) | |||||
| return getBinaryTypeFromFile(binary); | |||||
| if (std::strstr(output, "Mach-O universal binary") != nullptr) | |||||
| { | |||||
| // This is tricky, binary actually contains multiple architectures | |||||
| // We just assume what architectures are more important, and check for them first | |||||
| if (std::strstr(output, "x86_64") != nullptr) | |||||
| return BINARY_POSIX64; | |||||
| if (std::strstr(output, "i386")) | |||||
| return BINARY_POSIX32; | |||||
| if (std::strstr(output, "ppc")) | |||||
| return BINARY_OTHER; | |||||
| } | |||||
| carla_stdout("getBinaryTypeFromFile(\"%s\") - have output:\n%s", filename, output); | |||||
| # endif | |||||
| return BINARY_NATIVE; | return BINARY_NATIVE; | ||||
| } | } | ||||
| #endif | #endif | ||||
| @@ -0,0 +1,72 @@ | |||||
| /* | |||||
| * Carla macOS utils | |||||
| * Copyright (C) 2018 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. | |||||
| */ | |||||
| #ifdef CARLA_OS_MAC | |||||
| #include "CarlaMacUtils.hpp" | |||||
| #include "CarlaString.hpp" | |||||
| #import <Foundation/Foundation.h> | |||||
| CARLA_BACKEND_START_NAMESPACE | |||||
| // -------------------------------------------------------------------------------------------------------------------- | |||||
| const char* findBinaryInBundle(const char* const bundleDir) | |||||
| { | |||||
| const CFURLRef urlRef = CFURLCreateFromFileSystemRepresentation(0, (const UInt8*)bundleDir, (CFIndex)strlen(bundleDir), true); | |||||
| CARLA_SAFE_ASSERT_RETURN(urlRef != nullptr, nullptr); | |||||
| const CFBundleRef bundleRef = CFBundleCreate(kCFAllocatorDefault, urlRef); | |||||
| CARLA_SAFE_ASSERT_RETURN(bundleRef != nullptr, nullptr); | |||||
| const CFURLRef exeRef = CFBundleCopyExecutableURL(bundleRef); | |||||
| CARLA_SAFE_ASSERT_RETURN(exeRef != nullptr, nullptr); | |||||
| const CFURLRef absoluteURL = CFURLCopyAbsoluteURL(exeRef); | |||||
| CARLA_SAFE_ASSERT_RETURN(absoluteURL != nullptr, nullptr); | |||||
| const NSString* strRef = (NSString*)CFURLCopyFileSystemPath(absoluteURL, nil); | |||||
| CARLA_SAFE_ASSERT_RETURN(strRef != nullptr, nullptr); | |||||
| static CarlaString ret; | |||||
| ret = [strRef UTF8String]; | |||||
| CFRelease(absoluteURL); | |||||
| CFRelease(exeRef); | |||||
| CFRelease(bundleRef); | |||||
| CFRelease(urlRef); | |||||
| return ret.buffer(); | |||||
| } | |||||
| // -------------------------------------------------------------------------------------------------------------------- | |||||
| AutoNSAutoreleasePool::AutoNSAutoreleasePool() | |||||
| : pool([NSAutoreleasePool new]) {} | |||||
| AutoNSAutoreleasePool::~AutoNSAutoreleasePool() | |||||
| { | |||||
| NSAutoreleasePool* rpool = (NSAutoreleasePool*)pool; | |||||
| [rpool drain]; | |||||
| } | |||||
| // -------------------------------------------------------------------------------------------------------------------- | |||||
| CARLA_BACKEND_END_NAMESPACE | |||||
| #endif // CARLA_OS_MAC | |||||
| @@ -0,0 +1,52 @@ | |||||
| /* | |||||
| * Carla macOS utils | |||||
| * Copyright (C) 2018 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_MAC_UTILS_HPP_INCLUDED | |||||
| #define CARLA_MAC_UTILS_HPP_INCLUDED | |||||
| #ifndef CARLA_OS_MAC | |||||
| # error wrong include | |||||
| #endif | |||||
| #include "CarlaBackend.h" | |||||
| CARLA_BACKEND_START_NAMESPACE | |||||
| // -------------------------------------------------------------------------------------------------------------------- | |||||
| /* | |||||
| * ... | |||||
| */ | |||||
| const char* findBinaryInBundle(const char* const bundleDir); | |||||
| /* | |||||
| * ... | |||||
| */ | |||||
| class AutoNSAutoreleasePool { | |||||
| public: | |||||
| AutoNSAutoreleasePool(); | |||||
| ~AutoNSAutoreleasePool(); | |||||
| private: | |||||
| void* const pool; | |||||
| }; | |||||
| // -------------------------------------------------------------------------------------------------------------------- | |||||
| CARLA_BACKEND_END_NAMESPACE | |||||
| #endif // CARLA_MAC_UTILS_HPP_INCLUDED | |||||
| @@ -23,9 +23,11 @@ | |||||
| # include <X11/Xatom.h> | # include <X11/Xatom.h> | ||||
| # include <X11/Xlib.h> | # include <X11/Xlib.h> | ||||
| # include <X11/Xutil.h> | # include <X11/Xutil.h> | ||||
| # include "CarlaPluginUI_X11Icon.hpp" | |||||
| #endif | #endif | ||||
| #ifdef CARLA_OS_MAC | #ifdef CARLA_OS_MAC | ||||
| # include "CarlaMacUtils.hpp" | |||||
| # import <Cocoa/Cocoa.h> | # import <Cocoa/Cocoa.h> | ||||
| #endif | #endif | ||||
| @@ -41,8 +43,6 @@ | |||||
| // X11 | // X11 | ||||
| #ifdef HAVE_X11 | #ifdef HAVE_X11 | ||||
| # include "CarlaPluginUI_X11Icon.hpp" | |||||
| typedef void (*EventProcPtr)(XEvent* ev); | typedef void (*EventProcPtr)(XEvent* ev); | ||||
| static const uint X11Key_Escape = 9; | static const uint X11Key_Escape = 9; | ||||
| @@ -375,14 +375,13 @@ private: | |||||
| { | { | ||||
| @public | @public | ||||
| CarlaPluginUI::Callback* callback; | CarlaPluginUI::Callback* callback; | ||||
| NSView* view; | |||||
| } | } | ||||
| - (id) initWithContentRect:(NSRect)contentRect | - (id) initWithContentRect:(NSRect)contentRect | ||||
| styleMask:(unsigned int)aStyle | styleMask:(unsigned int)aStyle | ||||
| backing:(NSBackingStoreType)bufferingType | backing:(NSBackingStoreType)bufferingType | ||||
| defer:(BOOL)flag; | defer:(BOOL)flag; | ||||
| - (void) setup:(CarlaPluginUI::Callback*)cb view:(NSView*)v; | |||||
| - (void) setCallback:(CarlaPluginUI::Callback*)cb; | |||||
| - (BOOL) canBecomeKeyWindow; | - (BOOL) canBecomeKeyWindow; | ||||
| - (BOOL) windowShouldClose:(id)sender; | - (BOOL) windowShouldClose:(id)sender; | ||||
| - (NSSize) windowWillResize:(NSWindow*)sender toSize:(NSSize)frameSize; | - (NSSize) windowWillResize:(NSWindow*)sender toSize:(NSSize)frameSize; | ||||
| @@ -396,17 +395,17 @@ private: | |||||
| defer:(BOOL)flag | defer:(BOOL)flag | ||||
| { | { | ||||
| callback = nil; | callback = nil; | ||||
| view = nil; | |||||
| NSWindow* result = [super initWithContentRect:contentRect | NSWindow* result = [super initWithContentRect:contentRect | ||||
| styleMask:(NSClosableWindowMask | | styleMask:(NSClosableWindowMask | | ||||
| NSTitledWindowMask | | NSTitledWindowMask | | ||||
| NSResizableWindowMask) | NSResizableWindowMask) | ||||
| backing:NSBackingStoreBuffered defer:NO]; | |||||
| backing:NSBackingStoreBuffered | |||||
| defer:YES]; | |||||
| [result setAcceptsMouseMovedEvents:YES]; | |||||
| [result setContentSize:NSMakeSize(1, 1)]; | |||||
| [result setIsVisible:NO]; | [result setIsVisible:NO]; | ||||
| [result setAcceptsMouseMovedEvents:YES]; | |||||
| [result setContentSize:NSMakeSize(18, 100)]; | |||||
| return (CarlaPluginWindow*)result; | return (CarlaPluginWindow*)result; | ||||
| @@ -414,10 +413,9 @@ private: | |||||
| (void)aStyle; (void)bufferingType; (void)flag; | (void)aStyle; (void)bufferingType; (void)flag; | ||||
| } | } | ||||
| - (void)setup:(CarlaPluginUI::Callback*)cb view:(NSView*)v | |||||
| - (void)setCallback:(CarlaPluginUI::Callback*)cb | |||||
| { | { | ||||
| callback = cb; | callback = cb; | ||||
| view = v; | |||||
| } | } | ||||
| - (BOOL)canBecomeKeyWindow | - (BOOL)canBecomeKeyWindow | ||||
| @@ -455,20 +453,22 @@ public: | |||||
| CocoaPluginUI(Callback* 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), | : CarlaPluginUI(cb, isResizable), | ||||
| fView(nullptr), | fView(nullptr), | ||||
| fWindow(0) | |||||
| fWindow(nullptr) | |||||
| { | { | ||||
| [NSAutoreleasePool new]; | |||||
| [NSApplication sharedApplication]; | |||||
| carla_debug("CocoaPluginUI::CocoaPluginUI(%p, " P_UINTPTR, "%s)", cb, parentId, bool2str(isResizable)); | |||||
| const CarlaBackend::AutoNSAutoreleasePool arp; | |||||
| fView = [NSView new]; | |||||
| fView = [[NSView new]retain]; | |||||
| CARLA_SAFE_ASSERT_RETURN(fView != nullptr,) | CARLA_SAFE_ASSERT_RETURN(fView != nullptr,) | ||||
| [fView setHidden:YES]; | |||||
| if (isResizable) | if (isResizable) | ||||
| [fView setAutoresizingMask:NSViewWidthSizable|NSViewHeightSizable]; | [fView setAutoresizingMask:NSViewWidthSizable|NSViewHeightSizable]; | ||||
| fWindow = [[CarlaPluginWindow new]retain]; | fWindow = [[CarlaPluginWindow new]retain]; | ||||
| if (fWindow == 0) | |||||
| if (fWindow == nullptr) | |||||
| { | { | ||||
| [fView release]; | [fView release]; | ||||
| fView = nullptr; | fView = nullptr; | ||||
| @@ -478,12 +478,10 @@ public: | |||||
| if (! isResizable) | if (! isResizable) | ||||
| [[fWindow standardWindowButton:NSWindowZoomButton] setHidden:YES]; | [[fWindow standardWindowButton:NSWindowZoomButton] setHidden:YES]; | ||||
| [fWindow setup:cb view:fView]; | |||||
| [fWindow setCallback:cb]; | |||||
| [fWindow setContentView:fView]; | [fWindow setContentView:fView]; | ||||
| [fWindow makeFirstResponder:fView]; | [fWindow makeFirstResponder:fView]; | ||||
| [fWindow makeKeyAndOrderFront:fWindow]; | [fWindow makeKeyAndOrderFront:fWindow]; | ||||
| [NSApp activateIgnoringOtherApps:YES]; | |||||
| [fWindow center]; | [fWindow center]; | ||||
| if (parentId != 0) | if (parentId != 0) | ||||
| @@ -492,6 +490,7 @@ public: | |||||
| ~CocoaPluginUI() override | ~CocoaPluginUI() override | ||||
| { | { | ||||
| carla_debug("CocoaPluginUI::~CocoaPluginUI()"); | |||||
| if (fView == nullptr) | if (fView == nullptr) | ||||
| return; | return; | ||||
| @@ -502,6 +501,7 @@ public: | |||||
| void show() override | void show() override | ||||
| { | { | ||||
| carla_debug("CocoaPluginUI::show()"); | |||||
| CARLA_SAFE_ASSERT_RETURN(fView != nullptr,); | CARLA_SAFE_ASSERT_RETURN(fView != nullptr,); | ||||
| [fView setHidden:NO]; | [fView setHidden:NO]; | ||||
| @@ -510,6 +510,7 @@ public: | |||||
| void hide() override | void hide() override | ||||
| { | { | ||||
| carla_debug("CocoaPluginUI::hide()"); | |||||
| CARLA_SAFE_ASSERT_RETURN(fView != nullptr,); | CARLA_SAFE_ASSERT_RETURN(fView != nullptr,); | ||||
| [fWindow setIsVisible:NO]; | [fWindow setIsVisible:NO]; | ||||
| @@ -518,18 +519,22 @@ public: | |||||
| void idle() override | void idle() override | ||||
| { | { | ||||
| // carla_debug("CocoaPluginUI::idle()"); | |||||
| } | } | ||||
| void focus() override | void focus() override | ||||
| { | { | ||||
| CARLA_SAFE_ASSERT_RETURN(fWindow != 0,); | |||||
| carla_debug("CocoaPluginUI::focus()"); | |||||
| CARLA_SAFE_ASSERT_RETURN(fWindow != nullptr,); | |||||
| [fWindow makeKeyWindow]; | [fWindow makeKeyWindow]; | ||||
| [NSApp activateIgnoringOtherApps:YES]; | |||||
| } | } | ||||
| void setSize(const uint width, const uint height, const bool forceUpdate) override | void setSize(const uint width, const uint height, const bool forceUpdate) override | ||||
| { | { | ||||
| CARLA_SAFE_ASSERT_RETURN(fWindow != 0,); | |||||
| carla_debug("CocoaPluginUI::setSize(%u, %u, %s)", width, height, bool2str(forceUpdate)); | |||||
| CARLA_SAFE_ASSERT_RETURN(fWindow != nullptr,); | |||||
| CARLA_SAFE_ASSERT_RETURN(fView != nullptr,); | CARLA_SAFE_ASSERT_RETURN(fView != nullptr,); | ||||
| [fView setFrame:NSMakeRect(0, 0, width, height)]; | [fView setFrame:NSMakeRect(0, 0, width, height)]; | ||||
| @@ -552,13 +557,15 @@ public: | |||||
| if (forceUpdate) | if (forceUpdate) | ||||
| { | { | ||||
| // TODO | |||||
| // FIXME, not enough | |||||
| [fView setNeedsDisplay:YES]; | |||||
| } | } | ||||
| } | } | ||||
| void setTitle(const char* const title) override | void setTitle(const char* const title) override | ||||
| { | { | ||||
| CARLA_SAFE_ASSERT_RETURN(fWindow != 0,); | |||||
| carla_debug("CocoaPluginUI::setTitle(\"%s\")", title); | |||||
| CARLA_SAFE_ASSERT_RETURN(fWindow != nullptr,); | |||||
| NSString* titleString = [[NSString alloc] | NSString* titleString = [[NSString alloc] | ||||
| initWithBytes:title | initWithBytes:title | ||||
| @@ -570,7 +577,8 @@ public: | |||||
| void setTransientWinId(const uintptr_t winId) override | void setTransientWinId(const uintptr_t winId) override | ||||
| { | { | ||||
| CARLA_SAFE_ASSERT_RETURN(fWindow != 0,); | |||||
| carla_debug("CocoaPluginUI::setTransientWinId(" P_UINTPTR ")", winId); | |||||
| CARLA_SAFE_ASSERT_RETURN(fWindow != nullptr,); | |||||
| NSWindow* const parentWindow = [NSApp windowWithWindowNumber:winId]; | NSWindow* const parentWindow = [NSApp windowWithWindowNumber:winId]; | ||||
| CARLA_SAFE_ASSERT_RETURN(parentWindow != nullptr,); | CARLA_SAFE_ASSERT_RETURN(parentWindow != nullptr,); | ||||
| @@ -579,24 +587,27 @@ public: | |||||
| ordered:NSWindowAbove]; | ordered:NSWindowAbove]; | ||||
| } | } | ||||
| void setChildWindow(void* const winId) override | |||||
| void setChildWindow(void* const window) override | |||||
| { | { | ||||
| CARLA_SAFE_ASSERT_RETURN(winId != nullptr,); | |||||
| carla_debug("CocoaPluginUI::setChildWindow(%p)", window); | |||||
| CARLA_SAFE_ASSERT_RETURN(window != nullptr,); | |||||
| } | } | ||||
| void* getPtr() const noexcept override | void* getPtr() const noexcept override | ||||
| { | { | ||||
| carla_debug("CocoaPluginUI::getPtr()"); | |||||
| return (void*)fView; | return (void*)fView; | ||||
| } | } | ||||
| void* getDisplay() const noexcept | void* getDisplay() const noexcept | ||||
| { | { | ||||
| carla_debug("CocoaPluginUI::getDisplay()"); | |||||
| return (void*)fWindow; | return (void*)fWindow; | ||||
| } | } | ||||
| private: | private: | ||||
| NSView* fView; | |||||
| id fWindow; | |||||
| NSView* fView; | |||||
| CarlaPluginWindow* fWindow; | |||||
| CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(CocoaPluginUI) | CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(CocoaPluginUI) | ||||
| }; | }; | ||||