| @@ -830,19 +830,19 @@ const char* CarlaEngine::renamePlugin(const uint id, const char* const newName) | |||||
| carla_debug("CarlaEngine::renamePlugin(%i, \"%s\")", id, newName); | carla_debug("CarlaEngine::renamePlugin(%i, \"%s\")", id, newName); | ||||
| CarlaPlugin* const plugin(pData->plugins[id].plugin); | CarlaPlugin* const plugin(pData->plugins[id].plugin); | ||||
| CARLA_SAFE_ASSERT_RETURN_ERRN(plugin != nullptr, "Could not find plugin to rename"); | CARLA_SAFE_ASSERT_RETURN_ERRN(plugin != nullptr, "Could not find plugin to rename"); | ||||
| CARLA_SAFE_ASSERT_RETURN_ERRN(plugin->getId() == id, "Invalid engine internal data"); | CARLA_SAFE_ASSERT_RETURN_ERRN(plugin->getId() == id, "Invalid engine internal data"); | ||||
| if (const char* const name = getUniquePluginName(newName)) | |||||
| { | |||||
| plugin->setName(name); | |||||
| delete[] name; | |||||
| return plugin->getName(); | |||||
| } | |||||
| const char* const uniqueName(getUniquePluginName(newName)); | |||||
| CARLA_SAFE_ASSERT_RETURN_ERRN(uniqueName != nullptr, "Unable to get new unique plugin name"); | |||||
| setLastError("Unable to get new unique plugin name"); | |||||
| return nullptr; | |||||
| plugin->setName(uniqueName); | |||||
| if (pData->options.processMode == ENGINE_PROCESS_MODE_PATCHBAY) | |||||
| pData->graph.renamePlugin(plugin, uniqueName); | |||||
| delete[] uniqueName; | |||||
| return plugin->getName(); | |||||
| } | } | ||||
| bool CarlaEngine::clonePlugin(const uint id) | bool CarlaEngine::clonePlugin(const uint id) | ||||
| @@ -1483,6 +1483,18 @@ void PatchbayGraph::replacePlugin(CarlaPlugin* const oldPlugin, CarlaPlugin* con | |||||
| addNodeToPatchbay(newPlugin->getEngine(), node->nodeId, static_cast<int>(newPlugin->getId()), instance); | addNodeToPatchbay(newPlugin->getEngine(), node->nodeId, static_cast<int>(newPlugin->getId()), instance); | ||||
| } | } | ||||
| void PatchbayGraph::renamePlugin(CarlaPlugin* const plugin, const char* const newName) | |||||
| { | |||||
| CARLA_SAFE_ASSERT_RETURN(plugin != nullptr,); | |||||
| carla_debug("PatchbayGraph::renamePlugin(%p)", plugin, newName); | |||||
| AudioProcessorGraph::Node* const node(graph.getNodeForId(plugin->getPatchbayNodeId())); | |||||
| CARLA_SAFE_ASSERT_RETURN(node != nullptr,); | |||||
| if (! usingExternal) | |||||
| kEngine->callback(ENGINE_CALLBACK_PATCHBAY_CLIENT_RENAMED, node->nodeId, 0, 0, 0.0f, newName); | |||||
| } | |||||
| void PatchbayGraph::removePlugin(CarlaPlugin* const plugin) | void PatchbayGraph::removePlugin(CarlaPlugin* const plugin) | ||||
| { | { | ||||
| CARLA_SAFE_ASSERT_RETURN(plugin != nullptr,); | CARLA_SAFE_ASSERT_RETURN(plugin != nullptr,); | ||||
| @@ -2012,6 +2024,12 @@ void EngineInternalGraph::replacePlugin(CarlaPlugin* const oldPlugin, CarlaPlugi | |||||
| fPatchbay->replacePlugin(oldPlugin, newPlugin); | fPatchbay->replacePlugin(oldPlugin, newPlugin); | ||||
| } | } | ||||
| void EngineInternalGraph::renamePlugin(CarlaPlugin* const plugin, const char* const newName) | |||||
| { | |||||
| CARLA_SAFE_ASSERT_RETURN(fPatchbay != nullptr,); | |||||
| fPatchbay->renamePlugin(plugin, newName); | |||||
| } | |||||
| void EngineInternalGraph::removePlugin(CarlaPlugin* const plugin) | void EngineInternalGraph::removePlugin(CarlaPlugin* const plugin) | ||||
| { | { | ||||
| CARLA_SAFE_ASSERT_RETURN(fPatchbay != nullptr,); | CARLA_SAFE_ASSERT_RETURN(fPatchbay != nullptr,); | ||||
| @@ -165,6 +165,7 @@ struct PatchbayGraph { | |||||
| void addPlugin(CarlaPlugin* const plugin); | void addPlugin(CarlaPlugin* const plugin); | ||||
| void replacePlugin(CarlaPlugin* const oldPlugin, CarlaPlugin* const newPlugin); | void replacePlugin(CarlaPlugin* const oldPlugin, CarlaPlugin* const newPlugin); | ||||
| void renamePlugin(CarlaPlugin* const plugin, const char* const newName); | |||||
| void removePlugin(CarlaPlugin* const plugin); | void removePlugin(CarlaPlugin* const plugin); | ||||
| void removeAllPlugins(); | void removeAllPlugins(); | ||||
| @@ -83,6 +83,7 @@ public: | |||||
| // used for internal patchbay mode | // used for internal patchbay mode | ||||
| void addPlugin(CarlaPlugin* const plugin); | void addPlugin(CarlaPlugin* const plugin); | ||||
| void replacePlugin(CarlaPlugin* const oldPlugin, CarlaPlugin* const newPlugin); | void replacePlugin(CarlaPlugin* const oldPlugin, CarlaPlugin* const newPlugin); | ||||
| void renamePlugin(CarlaPlugin* const plugin, const char* const newName); | |||||
| void removePlugin(CarlaPlugin* const plugin); | void removePlugin(CarlaPlugin* const plugin); | ||||
| void removeAllPlugins(); | void removeAllPlugins(); | ||||
| @@ -774,13 +774,16 @@ private: | |||||
| { | { | ||||
| for (int i=0; connections[i] != nullptr; ++i) | for (int i=0; connections[i] != nullptr; ++i) | ||||
| { | { | ||||
| if (! port->kIsInput) | |||||
| fPreRenameConnections.append(portName); | |||||
| fPreRenameConnections.append(connections[i]); | |||||
| if (port->kIsInput) | if (port->kIsInput) | ||||
| { | |||||
| fPreRenameConnections.append(connections[i]); | |||||
| fPreRenameConnections.append(portName); | fPreRenameConnections.append(portName); | ||||
| } | |||||
| else | |||||
| { | |||||
| fPreRenameConnections.append(portName); | |||||
| fPreRenameConnections.append(connections[i]); | |||||
| } | |||||
| } | } | ||||
| jackbridge_free(connections); | jackbridge_free(connections); | ||||
| @@ -1156,18 +1159,17 @@ public: | |||||
| #ifndef BUILD_BRIDGE | #ifndef BUILD_BRIDGE | ||||
| const char* renamePlugin(const uint id, const char* const newName) override | const char* renamePlugin(const uint id, const char* const newName) override | ||||
| { | { | ||||
| CARLA_SAFE_ASSERT_RETURN(pData->curPluginCount > 0, nullptr); | |||||
| CARLA_SAFE_ASSERT_RETURN(id < pData->curPluginCount, nullptr); | |||||
| if (pData->options.processMode == ENGINE_PROCESS_MODE_CONTINUOUS_RACK || pData->options.processMode == ENGINE_PROCESS_MODE_PATCHBAY) | |||||
| return CarlaEngine::renamePlugin(id, newName); | |||||
| CARLA_SAFE_ASSERT_RETURN(pData->plugins != nullptr, nullptr); | CARLA_SAFE_ASSERT_RETURN(pData->plugins != nullptr, nullptr); | ||||
| CARLA_SAFE_ASSERT_RETURN(pData->curPluginCount != 0, nullptr); | |||||
| CARLA_SAFE_ASSERT_RETURN(id < pData->curPluginCount, nullptr); | |||||
| CARLA_SAFE_ASSERT_RETURN(newName != nullptr && newName[0] != '\0', nullptr); | CARLA_SAFE_ASSERT_RETURN(newName != nullptr && newName[0] != '\0', nullptr); | ||||
| CarlaPlugin* const plugin(pData->plugins[id].plugin); | CarlaPlugin* const plugin(pData->plugins[id].plugin); | ||||
| if (plugin == nullptr) | |||||
| { | |||||
| carla_stderr("CarlaEngine::clonePlugin(%i) - could not find plugin", id); | |||||
| return nullptr; | |||||
| } | |||||
| CARLA_SAFE_ASSERT_RETURN_ERRN(plugin != nullptr, "Could not find plugin to rename"); | |||||
| CARLA_SAFE_ASSERT_RETURN_ERRN(plugin->getId() == id, "Invalid engine internal data"); | |||||
| // before we stop the engine thread we might need to get the plugin data | // before we stop the engine thread we might need to get the plugin data | ||||
| const bool needsReinit = (pData->options.processMode == ENGINE_PROCESS_MODE_MULTIPLE_CLIENTS); | const bool needsReinit = (pData->options.processMode == ENGINE_PROCESS_MODE_MULTIPLE_CLIENTS); | ||||
| @@ -1179,10 +1181,6 @@ public: | |||||
| saveStatePtr = &saveState; | saveStatePtr = &saveState; | ||||
| } | } | ||||
| const ScopedThreadStopper sts(this); | |||||
| CARLA_SAFE_ASSERT(plugin->getId() == id); | |||||
| CarlaString uniqueName; | CarlaString uniqueName; | ||||
| try { | try { | ||||
| @@ -1197,6 +1195,8 @@ public: | |||||
| return nullptr; | return nullptr; | ||||
| } | } | ||||
| const ScopedThreadStopper sts(this); | |||||
| // rename on client client mode, just rename the ports | // rename on client client mode, just rename the ports | ||||
| if (pData->options.processMode == ENGINE_PROCESS_MODE_SINGLE_CLIENT) | if (pData->options.processMode == ENGINE_PROCESS_MODE_SINGLE_CLIENT) | ||||
| { | { | ||||
| @@ -1230,6 +1230,52 @@ public: | |||||
| jackbridge_set_latency_callback(jackClient, carla_jack_latency_callback_plugin, plugin); | jackbridge_set_latency_callback(jackClient, carla_jack_latency_callback_plugin, plugin); | ||||
| jackbridge_set_process_callback(jackClient, carla_jack_process_callback_plugin, plugin); | jackbridge_set_process_callback(jackClient, carla_jack_process_callback_plugin, plugin); | ||||
| jackbridge_on_shutdown(jackClient, carla_jack_shutdown_callback_plugin, plugin); | jackbridge_on_shutdown(jackClient, carla_jack_shutdown_callback_plugin, plugin); | ||||
| /* The following code is because of a tricky situation. | |||||
| We cannot lock or do jack operations during jack callbacks on jack1. jack2 events are asynchronous. | |||||
| When we close the client jack will trigger unregister-port callbacks, which we handle on a separate thread ASAP. | |||||
| But before that happens we already registered a new client with the same ports (the "renamed" one), | |||||
| and at this point the port we receive during that callback is actually the new one from the new client.. | |||||
| JACK2 seems to be reusing ports to save space, which is understandable. | |||||
| Anyway, this means we have to remove all our port-related data before the new client ports are created. | |||||
| (we also stop the separate jack-events thread to avoid any race conditions while modying our port data) */ | |||||
| stopThread(-1); | |||||
| const uint groupId(fUsedGroups.getGroupId(plugin->getName())); | |||||
| if (groupId > 0) | |||||
| { | |||||
| for (LinkedList<PortNameToId>::Itenerator it = fUsedPorts.list.begin2(); it.valid(); it.next()) | |||||
| { | |||||
| for (LinkedList<ConnectionToId>::Itenerator it2 = fUsedConnections.list.begin2(); it2.valid(); it2.next()) | |||||
| { | |||||
| static ConnectionToId connectionFallback = { 0, 0, 0, 0, 0 }; | |||||
| ConnectionToId& connectionToId = it2.getValue(connectionFallback); | |||||
| CARLA_SAFE_ASSERT_CONTINUE(connectionToId.id != 0); | |||||
| if (connectionToId.groupA != groupId && connectionToId.groupB != groupId) | |||||
| continue; | |||||
| callback(ENGINE_CALLBACK_PATCHBAY_CONNECTION_REMOVED, connectionToId.id, 0, 0, 0.0f, nullptr); | |||||
| fUsedConnections.list.remove(it2); | |||||
| } | |||||
| static PortNameToId portNameFallback = { 0, 0, { '\0' }, { '\0' } }; | |||||
| PortNameToId& portNameToId(it.getValue(portNameFallback)); | |||||
| CARLA_SAFE_ASSERT_CONTINUE(portNameToId.group != 0); | |||||
| if (portNameToId.group != groupId) | |||||
| continue; | |||||
| callback(ENGINE_CALLBACK_PATCHBAY_PORT_REMOVED, portNameToId.group, static_cast<int>(portNameToId.port), 0, 0.0f, nullptr); | |||||
| fUsedPorts.list.remove(it); | |||||
| } | |||||
| } | |||||
| startThread(); | |||||
| } | } | ||||
| else | else | ||||
| { | { | ||||
| @@ -1743,7 +1789,10 @@ protected: | |||||
| else | else | ||||
| { | { | ||||
| const PortNameToId& portNameToId(fUsedPorts.getPortNameToId(fullPortName)); | const PortNameToId& portNameToId(fUsedPorts.getPortNameToId(fullPortName)); | ||||
| CARLA_SAFE_ASSERT_RETURN(portNameToId.group > 0 && portNameToId.port > 0,); | |||||
| /* NOTE: Due to JACK2 async behaviour the port we get here might be the same of a previous rename-plugin request. | |||||
| See the comment on CarlaEngineJack::renamePlugin() for more information. */ | |||||
| if (portNameToId.group <= 0 || portNameToId.port <= 0) return; | |||||
| callback(ENGINE_CALLBACK_PATCHBAY_PORT_REMOVED, portNameToId.group, static_cast<int>(portNameToId.port), 0, 0.0f, nullptr); | callback(ENGINE_CALLBACK_PATCHBAY_PORT_REMOVED, portNameToId.group, static_cast<int>(portNameToId.port), 0, 0.0f, nullptr); | ||||
| fUsedPorts.list.removeOne(portNameToId); | fUsedPorts.list.removeOne(portNameToId); | ||||
| @@ -1768,10 +1817,12 @@ protected: | |||||
| CARLA_SAFE_ASSERT_RETURN(fullPortNameB != nullptr && fullPortNameB[0] != '\0',); | CARLA_SAFE_ASSERT_RETURN(fullPortNameB != nullptr && fullPortNameB[0] != '\0',); | ||||
| const PortNameToId& portNameToIdA(fUsedPorts.getPortNameToId(fullPortNameA)); | const PortNameToId& portNameToIdA(fUsedPorts.getPortNameToId(fullPortNameA)); | ||||
| CARLA_SAFE_ASSERT_RETURN(portNameToIdA.group > 0 && portNameToIdA.port > 0,); | |||||
| const PortNameToId& portNameToIdB(fUsedPorts.getPortNameToId(fullPortNameB)); | const PortNameToId& portNameToIdB(fUsedPorts.getPortNameToId(fullPortNameB)); | ||||
| CARLA_SAFE_ASSERT_RETURN(portNameToIdB.group > 0 && portNameToIdB.port > 0,); | |||||
| /* NOTE: Due to JACK2 async behaviour the port we get here might be the same of a previous rename-plugin request. | |||||
| See the comment on CarlaEngineJack::renamePlugin() for more information. */ | |||||
| if (portNameToIdA.group <= 0 || portNameToIdA.port <= 0) return; | |||||
| if (portNameToIdB.group <= 0 || portNameToIdB.port <= 0) return; | |||||
| if (connect) | if (connect) | ||||
| { | { | ||||
| @@ -2301,6 +2352,15 @@ private: | |||||
| // ------------------------------------------------------------------- | // ------------------------------------------------------------------- | ||||
| // disable -Wattributes warnings | |||||
| #if defined(__clang__) | |||||
| # pragma clang diagnostic push | |||||
| # pragma clang diagnostic ignored "-Wattributes" | |||||
| #elif defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) | |||||
| # pragma GCC diagnostic push | |||||
| # pragma GCC diagnostic ignored "-Wattributes" | |||||
| #endif | |||||
| #define handlePtr ((CarlaEngineJack*)arg) | #define handlePtr ((CarlaEngineJack*)arg) | ||||
| static void JACKBRIDGE_API carla_jack_thread_init_callback(void*) | static void JACKBRIDGE_API carla_jack_thread_init_callback(void*) | ||||
| @@ -2429,6 +2489,13 @@ private: | |||||
| } | } | ||||
| #endif | #endif | ||||
| // enable -Wattributes again | |||||
| #if defined(__clang__) | |||||
| # pragma clang diagnostic pop | |||||
| #elif defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) | |||||
| # pragma GCC diagnostic pop | |||||
| #endif | |||||
| CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(CarlaEngineJack) | CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(CarlaEngineJack) | ||||
| }; | }; | ||||
| @@ -974,6 +974,9 @@ class HostWindow(QMainWindow): | |||||
| y = self.ui.graphicsView.verticalScrollBar().value() + self.height()/4 | y = self.ui.graphicsView.verticalScrollBar().value() + self.height()/4 | ||||
| patchcanvas.setInitialPos(x, y) | patchcanvas.setInitialPos(x, y) | ||||
| def updateMiniCanvasLater(self): | |||||
| QTimer.singleShot(self.fMiniCanvasUpdateTimeout, self.ui.miniCanvasPreview.update) | |||||
| # -------------------------------------------------------------------------------------------------------- | # -------------------------------------------------------------------------------------------------------- | ||||
| # Canvas (menu actions) | # Canvas (menu actions) | ||||
| @@ -1013,7 +1016,7 @@ class HostWindow(QMainWindow): | |||||
| if self.host.is_engine_running(): | if self.host.is_engine_running(): | ||||
| self.host.patchbay_refresh(self.fExternalPatchbay) | self.host.patchbay_refresh(self.fExternalPatchbay) | ||||
| QTimer.singleShot(self.fMiniCanvasUpdateTimeout, self.ui.miniCanvasPreview.update) | |||||
| self.updateMiniCanvasLater() | |||||
| @pyqtSlot() | @pyqtSlot() | ||||
| def slot_canvasZoomFit(self): | def slot_canvasZoomFit(self): | ||||
| @@ -1082,7 +1085,7 @@ class HostWindow(QMainWindow): | |||||
| @pyqtSlot(int, int, QPointF) | @pyqtSlot(int, int, QPointF) | ||||
| def slot_canvasItemMoved(self, group_id, split_mode, pos): | def slot_canvasItemMoved(self, group_id, split_mode, pos): | ||||
| self.ui.miniCanvasPreview.update() | |||||
| self.updateMiniCanvasLater() | |||||
| @pyqtSlot(float) | @pyqtSlot(float) | ||||
| def slot_canvasScaleChanged(self, scale): | def slot_canvasScaleChanged(self, scale): | ||||
| @@ -1115,7 +1118,7 @@ class HostWindow(QMainWindow): | |||||
| patchcanvas.addGroup(clientId, clientName, pcSplit, pcIcon) | patchcanvas.addGroup(clientId, clientName, pcSplit, pcIcon) | ||||
| QTimer.singleShot(self.fMiniCanvasUpdateTimeout, self.ui.miniCanvasPreview.update) | |||||
| self.updateMiniCanvasLater() | |||||
| if pluginId < 0: | if pluginId < 0: | ||||
| return | return | ||||
| @@ -1128,12 +1131,12 @@ class HostWindow(QMainWindow): | |||||
| @pyqtSlot(int) | @pyqtSlot(int) | ||||
| def slot_handlePatchbayClientRemovedCallback(self, clientId): | def slot_handlePatchbayClientRemovedCallback(self, clientId): | ||||
| patchcanvas.removeGroup(clientId) | patchcanvas.removeGroup(clientId) | ||||
| QTimer.singleShot(self.fMiniCanvasUpdateTimeout, self.ui.miniCanvasPreview.update) | |||||
| self.updateMiniCanvasLater() | |||||
| @pyqtSlot(int, str) | @pyqtSlot(int, str) | ||||
| def slot_handlePatchbayClientRenamedCallback(self, clientId, newClientName): | def slot_handlePatchbayClientRenamedCallback(self, clientId, newClientName): | ||||
| patchcanvas.renameGroup(clientId, newClientName) | patchcanvas.renameGroup(clientId, newClientName) | ||||
| QTimer.singleShot(self.fMiniCanvasUpdateTimeout, self.ui.miniCanvasPreview.update) | |||||
| self.updateMiniCanvasLater() | |||||
| @pyqtSlot(int, int, int) | @pyqtSlot(int, int, int) | ||||
| def slot_handlePatchbayClientDataChangedCallback(self, clientId, clientIcon, pluginId): | def slot_handlePatchbayClientDataChangedCallback(self, clientId, clientIcon, pluginId): | ||||
| @@ -1151,7 +1154,7 @@ class HostWindow(QMainWindow): | |||||
| pcIcon = patchcanvas.ICON_FILE | pcIcon = patchcanvas.ICON_FILE | ||||
| patchcanvas.setGroupIcon(clientId, pcIcon) | patchcanvas.setGroupIcon(clientId, pcIcon) | ||||
| QTimer.singleShot(self.fMiniCanvasUpdateTimeout, self.ui.miniCanvasPreview.update) | |||||
| self.updateMiniCanvasLater() | |||||
| if pluginId < 0: | if pluginId < 0: | ||||
| return | return | ||||
| @@ -1182,27 +1185,27 @@ class HostWindow(QMainWindow): | |||||
| isAlternate = False | isAlternate = False | ||||
| patchcanvas.addPort(clientId, portId, portName, portMode, portType, isAlternate) | patchcanvas.addPort(clientId, portId, portName, portMode, portType, isAlternate) | ||||
| QTimer.singleShot(self.fMiniCanvasUpdateTimeout, self.ui.miniCanvasPreview.update) | |||||
| self.updateMiniCanvasLater() | |||||
| @pyqtSlot(int, int) | @pyqtSlot(int, int) | ||||
| def slot_handlePatchbayPortRemovedCallback(self, groupId, portId): | def slot_handlePatchbayPortRemovedCallback(self, groupId, portId): | ||||
| patchcanvas.removePort(groupId, portId) | patchcanvas.removePort(groupId, portId) | ||||
| QTimer.singleShot(self.fMiniCanvasUpdateTimeout, self.ui.miniCanvasPreview.update) | |||||
| self.updateMiniCanvasLater() | |||||
| @pyqtSlot(int, int, str) | @pyqtSlot(int, int, str) | ||||
| def slot_handlePatchbayPortRenamedCallback(self, groupId, portId, newPortName): | def slot_handlePatchbayPortRenamedCallback(self, groupId, portId, newPortName): | ||||
| patchcanvas.renamePort(groupId, portId, newPortName) | patchcanvas.renamePort(groupId, portId, newPortName) | ||||
| QTimer.singleShot(self.fMiniCanvasUpdateTimeout, self.ui.miniCanvasPreview.update) | |||||
| self.updateMiniCanvasLater() | |||||
| @pyqtSlot(int, int, int, int, int) | @pyqtSlot(int, int, int, int, int) | ||||
| def slot_handlePatchbayConnectionAddedCallback(self, connectionId, groupOutId, portOutId, groupInId, portInId): | def slot_handlePatchbayConnectionAddedCallback(self, connectionId, groupOutId, portOutId, groupInId, portInId): | ||||
| patchcanvas.connectPorts(connectionId, groupOutId, portOutId, groupInId, portInId) | patchcanvas.connectPorts(connectionId, groupOutId, portOutId, groupInId, portInId) | ||||
| QTimer.singleShot(self.fMiniCanvasUpdateTimeout, self.ui.miniCanvasPreview.update) | |||||
| self.updateMiniCanvasLater() | |||||
| @pyqtSlot(int, int, int) | @pyqtSlot(int, int, int) | ||||
| def slot_handlePatchbayConnectionRemovedCallback(self, connectionId, portOutId, portInId): | def slot_handlePatchbayConnectionRemovedCallback(self, connectionId, portOutId, portInId): | ||||
| patchcanvas.disconnectPorts(connectionId) | patchcanvas.disconnectPorts(connectionId) | ||||
| QTimer.singleShot(self.fMiniCanvasUpdateTimeout, self.ui.miniCanvasPreview.update) | |||||
| self.updateMiniCanvasLater() | |||||
| # -------------------------------------------------------------------------------------------------------- | # -------------------------------------------------------------------------------------------------------- | ||||
| # Settings | # Settings | ||||
| @@ -1889,12 +1892,12 @@ def canvasCallback(action, value1, value2, valueStr): | |||||
| elif action == patchcanvas.ACTION_GROUP_SPLIT: | elif action == patchcanvas.ACTION_GROUP_SPLIT: | ||||
| groupId = value1 | groupId = value1 | ||||
| patchcanvas.splitGroup(groupId) | patchcanvas.splitGroup(groupId) | ||||
| gCarla.gui.ui.miniCanvasPreview.update() | |||||
| gCarla.gui.updateMiniCanvasLater() | |||||
| elif action == patchcanvas.ACTION_GROUP_JOIN: | elif action == patchcanvas.ACTION_GROUP_JOIN: | ||||
| groupId = value1 | groupId = value1 | ||||
| patchcanvas.joinGroup(groupId) | patchcanvas.joinGroup(groupId) | ||||
| gCarla.gui.ui.miniCanvasPreview.update() | |||||
| gCarla.gui.updateMiniCanvasLater() | |||||
| elif action == patchcanvas.ACTION_PORT_INFO: | elif action == patchcanvas.ACTION_PORT_INFO: | ||||
| pass | pass | ||||
| @@ -1923,38 +1926,17 @@ def canvasCallback(action, value1, value2, valueStr): | |||||
| elif action == patchcanvas.ACTION_PLUGIN_EDIT: | elif action == patchcanvas.ACTION_PLUGIN_EDIT: | ||||
| pluginId = value1 | pluginId = value1 | ||||
| pwidget = gCarla.gui.getPluginSlotWidget(pluginId) | |||||
| dialog = gCarla.gui.getPluginEditDialog(pluginId) | |||||
| if dialog is None: | |||||
| return | |||||
| dialog.show() | |||||
| dialog.activateWindow() | |||||
| # FIXME | |||||
| pwidget = gCarla.gui.getPluginSlotWidget(pluginId) | |||||
| if pwidget is not None and pwidget.b_edit is not None: | |||||
| pwidget.b_edit.setChecked(True) | |||||
| if pwidget is not None: | |||||
| pwidget.showEditDialog() | |||||
| elif action == patchcanvas.ACTION_PLUGIN_RENAME: | elif action == patchcanvas.ACTION_PLUGIN_RENAME: | ||||
| pluginId = value1 | pluginId = value1 | ||||
| clientId = value2 | |||||
| newName = valueStr | |||||
| if host.rename_plugin(pluginId, newName): | |||||
| # FIXME | |||||
| pwidget = gCarla.gui.getPluginSlotWidget(pluginId) | |||||
| if pwidget is not None: | |||||
| pwidget.setName(newName) | |||||
| pwidget = gCarla.gui.getPluginSlotWidget(pluginId) | |||||
| patchcanvas.renameGroup(clientId, newName) | |||||
| gCarla.gui.ui.miniCanvasPreview.update() | |||||
| else: | |||||
| CustomMessageBox(gCarla.gui, QMessageBox.Warning, gCarla.gui.tr("Error"), gCarla.gui.tr("Operation failed"), | |||||
| host.get_last_error(), QMessageBox.Ok, QMessageBox.Ok) | |||||
| if pwidget is not None: | |||||
| pwidget.showRenameDialog() | |||||
| elif action == patchcanvas.ACTION_PLUGIN_REMOVE: | elif action == patchcanvas.ACTION_PLUGIN_REMOVE: | ||||
| pluginId = value1 | pluginId = value1 | ||||
| @@ -1965,14 +1947,10 @@ def canvasCallback(action, value1, value2, valueStr): | |||||
| elif action == patchcanvas.ACTION_PLUGIN_SHOW_UI: | elif action == patchcanvas.ACTION_PLUGIN_SHOW_UI: | ||||
| pluginId = value1 | pluginId = value1 | ||||
| pwidget = gCarla.gui.getPluginSlotWidget(pluginId) | |||||
| host.show_custom_ui(pluginId, True) | |||||
| # FIXME | |||||
| pwidget = gCarla.gui.getPluginSlotWidget(pluginId) | |||||
| if pwidget is not None and pwidget.b_gui is not None: | |||||
| pwidget.b_gui.setChecked(True) | |||||
| if pwidget is not None: | |||||
| pwidget.showCustomUI() | |||||
| # ------------------------------------------------------------------------------------------------------------ | # ------------------------------------------------------------------------------------------------------------ | ||||
| # Engine callback | # Engine callback | ||||
| @@ -734,6 +734,37 @@ class AbstractPluginSlot(QFrame, PluginEditParentMeta): | |||||
| #------------------------------------------------------------------ | #------------------------------------------------------------------ | ||||
| def showCustomUI(self): | |||||
| self.host.show_custom_ui(self.fPluginId, True) | |||||
| if self.b_gui is not None: | |||||
| self.b_gui.setChecked(True) | |||||
| def showEditDialog(self): | |||||
| self.fEditDialog.show() | |||||
| self.fEditDialog.activateWindow() | |||||
| if self.b_edit is not None: | |||||
| self.b_edit.setChecked(True) | |||||
| def showRenameDialog(self): | |||||
| oldName = self.fPluginInfo['name'] | |||||
| newNameTry = QInputDialog.getText(self, self.tr("Rename Plugin"), self.tr("New plugin name:"), QLineEdit.Normal, oldName) | |||||
| if not (newNameTry[1] and newNameTry[0] and oldName != newNameTry[0]): | |||||
| return | |||||
| newName = newNameTry[0] | |||||
| if not self.host.rename_plugin(self.fPluginId, newName): | |||||
| CustomMessageBox(self, QMessageBox.Warning, self.tr("Error"), self.tr("Operation failed"), | |||||
| self.host.get_last_error(), QMessageBox.Ok, QMessageBox.Ok) | |||||
| return | |||||
| self.setName(newName) | |||||
| #------------------------------------------------------------------ | |||||
| def activeChanged(self, onOff): | def activeChanged(self, onOff): | ||||
| self.fIsActive = onOff | self.fIsActive = onOff | ||||
| @@ -1046,19 +1077,7 @@ class AbstractPluginSlot(QFrame, PluginEditParentMeta): | |||||
| # Rename | # Rename | ||||
| elif actSel == actRename: | elif actSel == actRename: | ||||
| oldName = self.fPluginInfo['name'] | |||||
| newNameTry = QInputDialog.getText(self, self.tr("Rename Plugin"), self.tr("New plugin name:"), QLineEdit.Normal, oldName) | |||||
| if not (newNameTry[1] and newNameTry[0] and oldName != newNameTry[0]): | |||||
| return | |||||
| newName = newNameTry[0] | |||||
| if self.host.rename_plugin(self.fPluginId, newName): | |||||
| self.setName(newName) | |||||
| else: | |||||
| CustomMessageBox(self, QMessageBox.Warning, self.tr("Error"), self.tr("Operation failed"), | |||||
| self.host.get_last_error(), QMessageBox.Ok, QMessageBox.Ok) | |||||
| self.showRenameDialog() | |||||
| # ------------------------------------------------------------- | # ------------------------------------------------------------- | ||||
| # Replace | # Replace | ||||
| @@ -31,16 +31,14 @@ if config_UseQt5: | |||||
| from PyQt5.QtGui import QCursor, QFont, QFontMetrics | from PyQt5.QtGui import QCursor, QFont, QFontMetrics | ||||
| from PyQt5.QtSvg import QGraphicsSvgItem, QSvgRenderer | from PyQt5.QtSvg import QGraphicsSvgItem, QSvgRenderer | ||||
| from PyQt5.QtWidgets import QGraphicsScene, QGraphicsItem, QGraphicsLineItem, QGraphicsPathItem | from PyQt5.QtWidgets import QGraphicsScene, QGraphicsItem, QGraphicsLineItem, QGraphicsPathItem | ||||
| from PyQt5.QtWidgets import QGraphicsColorizeEffect, QGraphicsDropShadowEffect | |||||
| from PyQt5.QtWidgets import QInputDialog, QLineEdit, QMenu | |||||
| from PyQt5.QtWidgets import QGraphicsColorizeEffect, QGraphicsDropShadowEffect, QMenu | |||||
| else: | else: | ||||
| from PyQt4.QtCore import pyqtSignal, pyqtSlot, qDebug, qCritical, qFatal, qWarning, Qt, QObject | from PyQt4.QtCore import pyqtSignal, pyqtSlot, qDebug, qCritical, qFatal, qWarning, Qt, QObject | ||||
| from PyQt4.QtCore import QAbstractAnimation, QLineF, QPointF, QRectF, QSizeF, QSettings, QTimer | from PyQt4.QtCore import QAbstractAnimation, QLineF, QPointF, QRectF, QSizeF, QSettings, QTimer | ||||
| from PyQt4.QtGui import QColor, QLinearGradient, QPen, QPolygonF, QPainter, QPainterPath | from PyQt4.QtGui import QColor, QLinearGradient, QPen, QPolygonF, QPainter, QPainterPath | ||||
| from PyQt4.QtGui import QCursor, QFont, QFontMetrics | from PyQt4.QtGui import QCursor, QFont, QFontMetrics | ||||
| from PyQt4.QtGui import QGraphicsScene, QGraphicsItem, QGraphicsLineItem, QGraphicsPathItem | from PyQt4.QtGui import QGraphicsScene, QGraphicsItem, QGraphicsLineItem, QGraphicsPathItem | ||||
| from PyQt4.QtGui import QGraphicsColorizeEffect, QGraphicsDropShadowEffect | |||||
| from PyQt4.QtGui import QInputDialog, QLineEdit, QMenu | |||||
| from PyQt4.QtGui import QGraphicsColorizeEffect, QGraphicsDropShadowEffect, QMenu | |||||
| from PyQt4.QtSvg import QGraphicsSvgItem, QSvgRenderer | from PyQt4.QtSvg import QGraphicsSvgItem, QSvgRenderer | ||||
| # ------------------------------------------------------------------------------------------------------------ | # ------------------------------------------------------------------------------------------------------------ | ||||
| @@ -65,18 +63,18 @@ PORT_TYPE_PARAMETER = 4 | |||||
| # Callback Action | # Callback Action | ||||
| ACTION_GROUP_INFO = 0 # group_id, N, N | ACTION_GROUP_INFO = 0 # group_id, N, N | ||||
| ACTION_GROUP_RENAME = 1 # group_id, N, new_name | |||||
| ACTION_GROUP_RENAME = 1 # group_id, N, N | |||||
| ACTION_GROUP_SPLIT = 2 # group_id, N, N | ACTION_GROUP_SPLIT = 2 # group_id, N, N | ||||
| ACTION_GROUP_JOIN = 3 # group_id, N, N | ACTION_GROUP_JOIN = 3 # group_id, N, N | ||||
| ACTION_PORT_INFO = 4 # group_id, port_id, N | ACTION_PORT_INFO = 4 # group_id, port_id, N | ||||
| ACTION_PORT_RENAME = 5 # group_id, port_id, new_name | |||||
| ACTION_PORT_RENAME = 5 # group_id, port_id, N | |||||
| ACTION_PORTS_CONNECT = 6 # N, N, "outG:outP:inG:inP" | ACTION_PORTS_CONNECT = 6 # N, N, "outG:outP:inG:inP" | ||||
| ACTION_PORTS_DISCONNECT = 7 # conn_id, N, N | ACTION_PORTS_DISCONNECT = 7 # conn_id, N, N | ||||
| ACTION_PLUGIN_CLONE = 8 # plugin_id, N, N | ACTION_PLUGIN_CLONE = 8 # plugin_id, N, N | ||||
| ACTION_PLUGIN_EDIT = 9 # plugin_id, N, N | ACTION_PLUGIN_EDIT = 9 # plugin_id, N, N | ||||
| ACTION_PLUGIN_RENAME = 10 # plugin_id, group_id, new_name | |||||
| ACTION_PLUGIN_RENAME = 10 # plugin_id, N, N | |||||
| ACTION_PLUGIN_REMOVE = 11 # plugin_id, N, N | ACTION_PLUGIN_REMOVE = 11 # plugin_id, N, N | ||||
| ACTION_PLUGIN_SHOW_UI = 12 # plugin_id, N, new_name | |||||
| ACTION_PLUGIN_SHOW_UI = 12 # plugin_id, N, N | |||||
| # Icon | # Icon | ||||
| ICON_APPLICATION = 0 | ICON_APPLICATION = 0 | ||||
| @@ -1971,9 +1969,7 @@ class CanvasPort(QGraphicsItem): | |||||
| canvas.callback(ACTION_PORT_INFO, self.m_group_id, self.m_port_id, "") | canvas.callback(ACTION_PORT_INFO, self.m_group_id, self.m_port_id, "") | ||||
| elif act_selected == act_x_rename: | elif act_selected == act_x_rename: | ||||
| new_name_try = QInputDialog.getText(None, "Rename Port", "New name:", QLineEdit.Normal, self.m_port_name) | |||||
| if new_name_try[1] and new_name_try[0]: # 1 - bool ok, 0 - return text | |||||
| canvas.callback(ACTION_PORT_RENAME, self.m_group_id, self.m_port_id, new_name_try[0]) | |||||
| canvas.callback(ACTION_PORT_RENAME, self.m_group_id, self.m_port_id, "") | |||||
| event.accept() | event.accept() | ||||
| @@ -2586,11 +2582,7 @@ class CanvasBox(QGraphicsItem): | |||||
| canvas.callback(ACTION_GROUP_INFO, self.m_group_id, 0, "") | canvas.callback(ACTION_GROUP_INFO, self.m_group_id, 0, "") | ||||
| elif act_selected == act_x_rename: | elif act_selected == act_x_rename: | ||||
| oldName = self.m_group_name | |||||
| newNameTry = QInputDialog.getText(self.parentWidget(), "Rename Group", "New name:", QLineEdit.Normal, oldName) | |||||
| if newNameTry[1] and newNameTry[0] and oldName != newNameTry[0]: | |||||
| canvas.callback(ACTION_GROUP_RENAME, self.m_group_id, 0, newNameTry[0]) | |||||
| canvas.callback(ACTION_GROUP_RENAME, self.m_group_id, 0, "") | |||||
| elif act_selected == act_x_split_join: | elif act_selected == act_x_split_join: | ||||
| if self.m_splitted: | if self.m_splitted: | ||||
| @@ -2608,11 +2600,7 @@ class CanvasBox(QGraphicsItem): | |||||
| canvas.callback(ACTION_PLUGIN_CLONE, self.m_plugin_id, 0, "") | canvas.callback(ACTION_PLUGIN_CLONE, self.m_plugin_id, 0, "") | ||||
| elif act_selected == act_p_rename: | elif act_selected == act_p_rename: | ||||
| oldName = self.m_group_name | |||||
| newNameTry = QInputDialog.getText(self.parentWidget(), "Rename Plugin", "New name:", QLineEdit.Normal, oldName) | |||||
| if newNameTry[1] and newNameTry[0] and oldName != newNameTry[0]: | |||||
| canvas.callback(ACTION_PLUGIN_RENAME, self.m_plugin_id, self.m_group_id, newNameTry[0]) | |||||
| canvas.callback(ACTION_PLUGIN_RENAME, self.m_plugin_id, 0, "") | |||||
| elif act_selected == act_p_remove: | elif act_selected == act_p_remove: | ||||
| canvas.callback(ACTION_PLUGIN_REMOVE, self.m_plugin_id, 0, "") | canvas.callback(ACTION_PLUGIN_REMOVE, self.m_plugin_id, 0, "") | ||||
| @@ -147,7 +147,7 @@ bool carla_sem_timedwait(carla_sem_t& sem, const uint msecs) noexcept | |||||
| CARLA_SAFE_ASSERT_RETURN(msecs > 0, false); | CARLA_SAFE_ASSERT_RETURN(msecs > 0, false); | ||||
| #if defined(CARLA_OS_WIN) | #if defined(CARLA_OS_WIN) | ||||
| return (::WaitForSingleObject(sem.handle, secs*1000) == WAIT_OBJECT_0); | |||||
| return (::WaitForSingleObject(sem.handle, secs*1000 + msecs) == WAIT_OBJECT_0); | |||||
| #elif defined(CARLA_OS_MAC) | #elif defined(CARLA_OS_MAC) | ||||
| return false; // TODO | return false; // TODO | ||||
| #elif defined(CARLA_USE_FUTEXES) | #elif defined(CARLA_USE_FUTEXES) | ||||