Cleanup
[carla.git] / source / frontend / dialogs / jackappdialog.cpp
blob3710428688ed4b3ce44a123a07e77bea25fdaa61
1 /*
2 * Carla plugin host
3 * Copyright (C) 2011-2023 Filipe Coelho <falktx@falktx.com>
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License as
7 * published by the Free Software Foundation; either version 2 of
8 * the License, or any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * For a full copy of the GNU General Public License see the doc/GPL.txt file.
18 #include "jackappdialog.hpp"
20 #ifdef __clang__
21 # pragma clang diagnostic push
22 # pragma clang diagnostic ignored "-Wdeprecated-copy-with-user-provided-copy"
23 # pragma clang diagnostic ignored "-Wdeprecated-register"
24 #elif defined(__GNUC__) && __GNUC__ >= 8
25 # pragma GCC diagnostic push
26 # pragma GCC diagnostic ignored "-Wclass-memaccess"
27 # pragma GCC diagnostic ignored "-Wdeprecated-copy"
28 #endif
30 #include "ui_jackappdialog.h"
31 #include <QtCore/QFileInfo>
32 #include <QtCore/QVector>
33 #include <QtWidgets/QPushButton>
35 #ifdef __clang__
36 # pragma clang diagnostic pop
37 #elif defined(__GNUC__) && __GNUC__ >= 8
38 # pragma GCC diagnostic pop
39 #endif
41 #include "qsafesettings.hpp"
43 #include "CarlaFrontend.h"
44 #include "CarlaLibJackHints.h"
45 #include "CarlaString.hpp"
47 // --------------------------------------------------------------------------------------------------------------------
48 // Jack Application Dialog
50 enum {
51 UI_SESSION_NONE = 0,
52 UI_SESSION_LADISH = 1,
53 UI_SESSION_NSM = 2,
56 struct JackAppDialog::Self {
57 Ui_JackAppDialog ui;
58 const QString fProjectFilename;
60 Self(const char* const projectFilename)
61 : fProjectFilename(projectFilename) {}
63 static Self& create(const char* const projectFilename)
65 Self* const self = new Self(projectFilename);
66 return *self;
70 JackAppDialog::JackAppDialog(QWidget* const parent, const char* const projectFilename)
71 : QDialog(parent),
72 self(Self::create(projectFilename))
74 self.ui.setupUi(this);
76 // -------------------------------------------------------------------------------------------------------------
77 // UI setup
79 self.ui.group_error->setVisible(false);
81 adjustSize();
82 setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
84 #ifdef CARLA_OS_MAC
85 if (parent != nullptr)
86 setWindowModality(Qt::WindowModal);
87 #endif
89 // -------------------------------------------------------------------------------------------------------------
90 // Load settings
92 loadSettings();
94 // -------------------------------------------------------------------------------------------------------------
95 // Set-up connections
97 connect(this, &QDialog::finished,
98 this, &JackAppDialog::slot_saveSettings);
99 connect(self.ui.cb_session_mgr, static_cast<void(QComboBox::*)(int)>(&QComboBox::currentIndexChanged),
100 this, &JackAppDialog::slot_sessionManagerChanged);
101 connect(self.ui.le_command, &QLineEdit::textChanged,
102 this, &JackAppDialog::slot_commandChanged);
105 JackAppDialog::~JackAppDialog()
107 delete &self;
110 // -----------------------------------------------------------------------------------------------------------------
111 // public methods
113 JackAppDialog::CommandAndFlags JackAppDialog::getCommandAndFlags() const
115 const QString command = self.ui.le_command->text();
116 QString name = self.ui.le_name->text();
118 if (name.isEmpty())
120 name = QFileInfo(command.split(' ').first()).baseName();
121 name[0] = name[0].toTitleCase();
124 SessionManager smgr;
125 switch (self.ui.cb_session_mgr->currentIndex())
127 case UI_SESSION_LADISH:
128 smgr = LIBJACK_SESSION_MANAGER_LADISH;
129 break;
130 case UI_SESSION_NSM:
131 smgr = LIBJACK_SESSION_MANAGER_NSM;
132 break;
133 default:
134 smgr = LIBJACK_SESSION_MANAGER_NONE;
135 break;
138 uint flags = 0x0;
139 if (self.ui.cb_manage_window->isChecked())
140 flags |= LIBJACK_FLAG_CONTROL_WINDOW;
141 if (self.ui.cb_capture_first_window->isChecked())
142 flags |= LIBJACK_FLAG_CAPTURE_FIRST_WINDOW;
143 if (self.ui.cb_buffers_addition_mode->isChecked())
144 flags |= LIBJACK_FLAG_AUDIO_BUFFERS_ADDITION;
145 if (self.ui.cb_out_midi_mixdown->isChecked())
146 flags |= LIBJACK_FLAG_MIDI_OUTPUT_CHANNEL_MIXDOWN;
147 if (self.ui.cb_external_start->isChecked())
148 flags |= LIBJACK_FLAG_EXTERNAL_START;
150 const QString labelSetup(QString("%1%2%3%4%5%6").arg(QChar('0' + self.ui.sb_audio_ins->value()))
151 .arg(QChar('0' + self.ui.sb_audio_outs->value()))
152 .arg(QChar('0' + self.ui.sb_midi_ins->value()))
153 .arg(QChar('0' + self.ui.sb_midi_outs->value()))
154 .arg(QChar('0' + smgr))
155 .arg(QChar('0' + flags)));
157 return {command, name, labelSetup};
160 // -----------------------------------------------------------------------------------------------------------------
161 // private methods
163 void JackAppDialog::checkIfButtonBoxShouldBeEnabled(const int index, const QCarlaString& command)
165 bool enabled = command.isNotEmpty();
166 QCarlaString showErr;
168 // NSM applications must not be abstract or absolute paths, and must not contain arguments
169 if (enabled and index == UI_SESSION_NSM)
171 if (QVector<QChar>{'.', '/'}.contains(command[0]))
172 showErr = tr("NSM applications cannot use abstract or absolute paths");
173 else if (command.contains(' ') or command.contains(';') or command.contains('&'))
174 showErr = tr("NSM applications cannot use CLI arguments");
175 else if (self.fProjectFilename.isEmpty())
176 showErr = tr("You need to save the current Carla project before NSM can be used");
179 if (showErr.isNotEmpty())
181 enabled = false;
182 self.ui.l_error->setText(showErr);
183 self.ui.group_error->setVisible(true);
185 else
187 self.ui.group_error->setVisible(false);
190 if (QPushButton* const button = self.ui.buttonBox->button(QDialogButtonBox::Ok))
191 button->setEnabled(enabled);
194 void JackAppDialog::loadSettings()
196 const QSafeSettings settings("falkTX", "CarlaAddJackApp");
198 const QString smName = settings.valueString("SessionManager", "");
200 if (smName == "LADISH (SIGUSR1)")
201 self.ui.cb_session_mgr->setCurrentIndex(UI_SESSION_LADISH);
202 else if (smName == "NSM")
203 self.ui.cb_session_mgr->setCurrentIndex(UI_SESSION_NSM);
204 else
205 self.ui.cb_session_mgr->setCurrentIndex(UI_SESSION_NONE);
207 self.ui.le_command->setText(settings.valueString("Command", ""));
208 self.ui.le_name->setText(settings.valueString("Name", ""));
209 self.ui.sb_audio_ins->setValue(settings.valueIntPositive("NumAudioIns", 2));
210 self.ui.sb_audio_ins->setValue(settings.valueIntPositive("NumAudioIns", 2));
211 self.ui.sb_audio_outs->setValue(settings.valueIntPositive("NumAudioOuts", 2));
212 self.ui.sb_midi_ins->setValue(settings.valueIntPositive("NumMidiIns", 0));
213 self.ui.sb_midi_outs->setValue(settings.valueIntPositive("NumMidiOuts", 0));
214 self.ui.cb_manage_window->setChecked(settings.valueBool("ManageWindow", true));
215 self.ui.cb_capture_first_window->setChecked(settings.valueBool("CaptureFirstWindow", false));
216 self.ui.cb_out_midi_mixdown->setChecked(settings.valueBool("MidiOutMixdown", false));
218 checkIfButtonBoxShouldBeEnabled(self.ui.cb_session_mgr->currentIndex(),
219 self.ui.le_command->text());
222 // -----------------------------------------------------------------------------------------------------------------
223 // private slots
225 void JackAppDialog::slot_commandChanged(const QString& command)
227 checkIfButtonBoxShouldBeEnabled(self.ui.cb_session_mgr->currentIndex(), command);
230 void JackAppDialog::slot_sessionManagerChanged(const int index)
232 checkIfButtonBoxShouldBeEnabled(index, self.ui.le_command->text());
235 void JackAppDialog::slot_saveSettings()
237 QSafeSettings settings("falkTX", "CarlaAddJackApp");
238 settings.setValue("Command", self.ui.le_command->text());
239 settings.setValue("Name", self.ui.le_name->text());
240 settings.setValue("SessionManager", self.ui.cb_session_mgr->currentText());
241 settings.setValue("NumAudioIns", self.ui.sb_audio_ins->value());
242 settings.setValue("NumAudioOuts", self.ui.sb_audio_outs->value());
243 settings.setValue("NumMidiIns", self.ui.sb_midi_ins->value());
244 settings.setValue("NumMidiOuts", self.ui.sb_midi_outs->value());
245 settings.setValue("ManageWindow", self.ui.cb_manage_window->isChecked());
246 settings.setValue("CaptureFirstWindow", self.ui.cb_capture_first_window->isChecked());
247 settings.setValue("MidiOutMixdown", self.ui.cb_out_midi_mixdown->isChecked());
250 // --------------------------------------------------------------------------------------------------------------------
252 const JackAppDialogResults*
253 carla_frontend_createAndExecJackAppDialog(void* const parent, const char* const projectFilename)
255 JackAppDialog gui(reinterpret_cast<QWidget*>(parent), projectFilename);
257 if (gui.exec())
259 static JackAppDialogResults ret = {};
260 static CarlaString retCommand;
261 static CarlaString retName;
262 static CarlaString retLabelSetup;
264 const JackAppDialog::CommandAndFlags cafs = gui.getCommandAndFlags();
265 retCommand = cafs.command.toUtf8().constData();
266 retName = cafs.name.toUtf8().constData();
267 retLabelSetup = cafs.labelSetup.toUtf8().constData();
269 ret.command = retCommand;
270 ret.name = retName;
271 ret.labelSetup = retLabelSetup;
273 return &ret;
276 return nullptr;
279 #if 0
280 // --------------------------------------------------------------------------------------------------------------------
281 // Testing
283 #include "../utils/qsafesettings.cpp"
285 int main(int argc, char* argv[])
287 QApplication app(argc, argv);
289 if (JackAppDialogResults* const res = carla_frontend_createAndExecJackAppDialog(nullptr, ""))
291 printf("Results:\n");
292 printf("\tCommand: %s\n", res->command);
293 printf("\tName: %s\n", res->name);
294 printf("\tLabelSetup: %s\n", res->labelSetup);
297 return 0;
299 #endif
301 // --------------------------------------------------------------------------------------------------------------------