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"
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"
30 #include "ui_jackappdialog.h"
31 #include <QtCore/QFileInfo>
32 #include <QtCore/QVector>
33 #include <QtWidgets/QPushButton>
36 # pragma clang diagnostic pop
37 #elif defined(__GNUC__) && __GNUC__ >= 8
38 # pragma GCC diagnostic pop
41 #include "qsafesettings.hpp"
43 #include "CarlaFrontend.h"
44 #include "CarlaLibJackHints.h"
45 #include "CarlaString.hpp"
47 // --------------------------------------------------------------------------------------------------------------------
48 // Jack Application Dialog
52 UI_SESSION_LADISH
= 1,
56 struct JackAppDialog::Self
{
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
);
70 JackAppDialog::JackAppDialog(QWidget
* const parent
, const char* const projectFilename
)
72 self(Self::create(projectFilename
))
74 self
.ui
.setupUi(this);
76 // -------------------------------------------------------------------------------------------------------------
79 self
.ui
.group_error
->setVisible(false);
82 setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint
);
85 if (parent
!= nullptr)
86 setWindowModality(Qt::WindowModal
);
89 // -------------------------------------------------------------------------------------------------------------
94 // -------------------------------------------------------------------------------------------------------------
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()
110 // -----------------------------------------------------------------------------------------------------------------
113 JackAppDialog::CommandAndFlags
JackAppDialog::getCommandAndFlags() const
115 const QString command
= self
.ui
.le_command
->text();
116 QString name
= self
.ui
.le_name
->text();
120 name
= QFileInfo(command
.split(' ').first()).baseName();
121 name
[0] = name
[0].toTitleCase();
125 switch (self
.ui
.cb_session_mgr
->currentIndex())
127 case UI_SESSION_LADISH
:
128 smgr
= LIBJACK_SESSION_MANAGER_LADISH
;
131 smgr
= LIBJACK_SESSION_MANAGER_NSM
;
134 smgr
= LIBJACK_SESSION_MANAGER_NONE
;
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 // -----------------------------------------------------------------------------------------------------------------
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())
182 self
.ui
.l_error
->setText(showErr
);
183 self
.ui
.group_error
->setVisible(true);
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
);
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 // -----------------------------------------------------------------------------------------------------------------
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
);
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
;
271 ret
.labelSetup
= retLabelSetup
;
280 // --------------------------------------------------------------------------------------------------------------------
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
);
301 // --------------------------------------------------------------------------------------------------------------------