ladishd: app list serialization; autolaunch on load
This commit is contained in:
parent
89461c363c
commit
0b6ad2626f
|
@ -43,6 +43,8 @@ struct ladish_app
|
|||
uint8_t level;
|
||||
pid_t pid;
|
||||
bool zombie;
|
||||
bool hidden;
|
||||
bool autorun;
|
||||
};
|
||||
|
||||
struct ladish_app_supervisor
|
||||
|
@ -126,18 +128,85 @@ struct ladish_app * ladish_app_supervisor_find_app_by_id(struct ladish_app_super
|
|||
return NULL;
|
||||
}
|
||||
|
||||
void remove_app_internal(struct ladish_app_supervisor * supervisor_ptr, struct ladish_app * app_ptr)
|
||||
static
|
||||
struct ladish_app *
|
||||
add_app_internal(
|
||||
struct ladish_app_supervisor * supervisor_ptr,
|
||||
const char * name,
|
||||
const char * commandline,
|
||||
dbus_bool_t terminal,
|
||||
dbus_bool_t autorun,
|
||||
uint8_t level)
|
||||
{
|
||||
list_del(&app_ptr->siblings);
|
||||
struct ladish_app * app_ptr;
|
||||
dbus_bool_t running;
|
||||
|
||||
app_ptr = malloc(sizeof(struct ladish_app));
|
||||
if (app_ptr == NULL)
|
||||
{
|
||||
log_error("malloc of struct ladish_app failed");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
app_ptr->name = strdup(name);
|
||||
if (app_ptr->name == NULL)
|
||||
{
|
||||
log_error("strdup() failed for app name");
|
||||
free(app_ptr);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
app_ptr->commandline = strdup(commandline);
|
||||
if (app_ptr->commandline == NULL)
|
||||
{
|
||||
log_error("strdup() failed for app commandline");
|
||||
free(app_ptr->name);
|
||||
free(app_ptr);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
app_ptr->terminal = terminal;
|
||||
app_ptr->level = level;
|
||||
app_ptr->pid = 0;
|
||||
|
||||
app_ptr->id = supervisor_ptr->next_id++;
|
||||
app_ptr->zombie = false;
|
||||
app_ptr->hidden = false;
|
||||
app_ptr->autorun = autorun;
|
||||
list_add_tail(&app_ptr->siblings, &supervisor_ptr->applist);
|
||||
|
||||
running = false;
|
||||
dbus_signal_emit(
|
||||
g_dbus_connection,
|
||||
supervisor_ptr->opath,
|
||||
IFACE_APP_SUPERVISOR,
|
||||
"AppRemoved",
|
||||
"tt",
|
||||
"AppAdded",
|
||||
"ttsbby",
|
||||
&supervisor_ptr->version,
|
||||
&app_ptr->id);
|
||||
&app_ptr->id,
|
||||
&app_ptr->name,
|
||||
&running,
|
||||
&terminal,
|
||||
&app_ptr->level);
|
||||
|
||||
return app_ptr;
|
||||
}
|
||||
|
||||
void remove_app_internal(struct ladish_app_supervisor * supervisor_ptr, struct ladish_app * app_ptr)
|
||||
{
|
||||
list_del(&app_ptr->siblings);
|
||||
|
||||
if (!app_ptr->hidden)
|
||||
{
|
||||
dbus_signal_emit(
|
||||
g_dbus_connection,
|
||||
supervisor_ptr->opath,
|
||||
IFACE_APP_SUPERVISOR,
|
||||
"AppRemoved",
|
||||
"tt",
|
||||
&supervisor_ptr->version,
|
||||
&app_ptr->id);
|
||||
}
|
||||
|
||||
free(app_ptr->name);
|
||||
free(app_ptr->commandline);
|
||||
|
@ -149,6 +218,11 @@ void emit_app_state_changed(struct ladish_app_supervisor * supervisor_ptr, struc
|
|||
dbus_bool_t running;
|
||||
dbus_bool_t terminal;
|
||||
|
||||
if (app_ptr->hidden)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
running = app_ptr->pid != 0;
|
||||
terminal = app_ptr->terminal;
|
||||
|
||||
|
@ -167,16 +241,32 @@ void emit_app_state_changed(struct ladish_app_supervisor * supervisor_ptr, struc
|
|||
|
||||
#define supervisor_ptr ((struct ladish_app_supervisor *)supervisor_handle)
|
||||
|
||||
void ladish_app_supervisor_destroy(ladish_app_supervisor_handle supervisor_handle)
|
||||
void ladish_app_supervisor_clear(ladish_app_supervisor_handle supervisor_handle)
|
||||
{
|
||||
struct list_head * node_ptr;
|
||||
struct list_head * safe_node_ptr;
|
||||
struct ladish_app * app_ptr;
|
||||
|
||||
while (!list_empty(&supervisor_ptr->applist))
|
||||
list_for_each_safe(node_ptr, safe_node_ptr, &supervisor_ptr->applist)
|
||||
{
|
||||
app_ptr = list_entry(supervisor_ptr->applist.next, struct ladish_app, siblings);
|
||||
remove_app_internal(supervisor_ptr, app_ptr);
|
||||
app_ptr = list_entry(node_ptr, struct ladish_app, siblings);
|
||||
if (app_ptr->pid != 0)
|
||||
{
|
||||
log_info("terminating '%s'...", app_ptr->name);
|
||||
app_ptr->zombie = true;
|
||||
kill(app_ptr->pid, SIGTERM);
|
||||
}
|
||||
else
|
||||
{
|
||||
log_info("removing '%s'", app_ptr->name);
|
||||
remove_app_internal(supervisor_ptr, app_ptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ladish_app_supervisor_destroy(ladish_app_supervisor_handle supervisor_handle)
|
||||
{
|
||||
ladish_app_supervisor_clear(supervisor_handle);
|
||||
free(supervisor_ptr->name);
|
||||
free(supervisor_ptr->opath);
|
||||
free(supervisor_ptr);
|
||||
|
@ -211,6 +301,82 @@ bool ladish_app_supervisor_child_exit(ladish_app_supervisor_handle supervisor_ha
|
|||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
ladish_app_supervisor_enum(
|
||||
ladish_app_supervisor_handle supervisor_handle,
|
||||
void * context,
|
||||
bool (* callback)(void * context, const char * name, bool running, const char * command, bool terminal, uint8_t level))
|
||||
{
|
||||
struct list_head * node_ptr;
|
||||
struct ladish_app * app_ptr;
|
||||
|
||||
list_for_each(node_ptr, &supervisor_ptr->applist)
|
||||
{
|
||||
app_ptr = list_entry(node_ptr, struct ladish_app, siblings);
|
||||
|
||||
if (app_ptr->hidden)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!callback(context, app_ptr->name, app_ptr->pid != 0, app_ptr->commandline, app_ptr->terminal, app_ptr->level))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
ladish_app_supervisor_add(
|
||||
ladish_app_supervisor_handle supervisor_handle,
|
||||
const char * name,
|
||||
bool autorun,
|
||||
const char * command,
|
||||
bool terminal,
|
||||
uint8_t level)
|
||||
{
|
||||
struct ladish_app * app_ptr;
|
||||
|
||||
app_ptr = add_app_internal(supervisor_ptr, name, command, terminal, autorun, level);
|
||||
if (app_ptr == NULL)
|
||||
{
|
||||
log_error("add_app_internal() failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ladish_app_supervisor_autorun(ladish_app_supervisor_handle supervisor_handle)
|
||||
{
|
||||
struct list_head * node_ptr;
|
||||
struct ladish_app * app_ptr;
|
||||
|
||||
list_for_each(node_ptr, &supervisor_ptr->applist)
|
||||
{
|
||||
app_ptr = list_entry(node_ptr, struct ladish_app, siblings);
|
||||
|
||||
if (!app_ptr->autorun)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
app_ptr->autorun = false;
|
||||
|
||||
log_info("autorun('%s', %s, '%s') called", app_ptr->name, app_ptr->terminal ? "terminal" : "shell", app_ptr->commandline);
|
||||
|
||||
if (!loader_execute(supervisor_ptr->name, app_ptr->name, "/", app_ptr->terminal, app_ptr->commandline, &app_ptr->pid))
|
||||
{
|
||||
log_error("Execution of '%s' failed", app_ptr->commandline);
|
||||
return;
|
||||
}
|
||||
|
||||
emit_app_state_changed(supervisor_ptr, app_ptr);
|
||||
}
|
||||
}
|
||||
|
||||
#undef supervisor_ptr
|
||||
#define supervisor_ptr ((struct ladish_app_supervisor *)call_ptr->iface_context)
|
||||
|
||||
|
@ -246,6 +412,11 @@ static void get_all(struct dbus_method_call * call_ptr)
|
|||
{
|
||||
app_ptr = list_entry(node_ptr, struct ladish_app, siblings);
|
||||
|
||||
if (app_ptr->hidden)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
log_info("app '%s' (%llu)", app_ptr->name, (unsigned long long)app_ptr->id);
|
||||
|
||||
if (!dbus_message_iter_open_container (&array_iter, DBUS_TYPE_STRUCT, NULL, &struct_iter))
|
||||
|
@ -311,7 +482,6 @@ static void run_custom(struct dbus_method_call * call_ptr)
|
|||
char * end;
|
||||
unsigned int index;
|
||||
struct ladish_app * app_ptr;
|
||||
dbus_bool_t running;
|
||||
|
||||
if (!dbus_message_get_args(
|
||||
call_ptr->message,
|
||||
|
@ -378,57 +548,25 @@ static void run_custom(struct dbus_method_call * call_ptr)
|
|||
index++;
|
||||
}
|
||||
|
||||
app_ptr = malloc(sizeof(struct ladish_app));
|
||||
app_ptr = add_app_internal(supervisor_ptr, name, commandline, terminal, false, 0);
|
||||
if (app_ptr == NULL)
|
||||
{
|
||||
lash_dbus_error(call_ptr, LASH_DBUS_ERROR_GENERIC, "malloc of struct ladish_app failed");
|
||||
lash_dbus_error(call_ptr, LASH_DBUS_ERROR_GENERIC, "add_app_internal() failed");
|
||||
free(name);
|
||||
return;
|
||||
}
|
||||
|
||||
app_ptr->id = supervisor_ptr->next_id++;
|
||||
app_ptr->name = name;
|
||||
app_ptr->commandline = strdup(commandline);
|
||||
app_ptr->terminal = terminal;
|
||||
app_ptr->pid = 0;
|
||||
if (app_ptr->commandline == NULL)
|
||||
{
|
||||
lash_dbus_error(call_ptr, LASH_DBUS_ERROR_GENERIC, "strdup() failed for commandline");
|
||||
free(app_ptr);
|
||||
free(name);
|
||||
return;
|
||||
}
|
||||
|
||||
app_ptr->zombie = false;
|
||||
list_add_tail(&app_ptr->siblings, &supervisor_ptr->applist);
|
||||
|
||||
if (!loader_execute(supervisor_ptr->name, name, "/", terminal, commandline, &app_ptr->pid))
|
||||
{
|
||||
lash_dbus_error(call_ptr, LASH_DBUS_ERROR_GENERIC, "Execution of '%s' failed", commandline);
|
||||
list_del(&app_ptr->siblings);
|
||||
free(app_ptr->commandline);
|
||||
free(app_ptr);
|
||||
remove_app_internal(supervisor_ptr, app_ptr);
|
||||
free(name);
|
||||
return;
|
||||
}
|
||||
|
||||
log_info("%s pid is %lu", app_ptr->name, (unsigned long)app_ptr->pid);
|
||||
|
||||
running = true;
|
||||
terminal = app_ptr->terminal;
|
||||
|
||||
dbus_signal_emit(
|
||||
g_dbus_connection,
|
||||
supervisor_ptr->opath,
|
||||
IFACE_APP_SUPERVISOR,
|
||||
"AppAdded",
|
||||
"ttsbby",
|
||||
&supervisor_ptr->version,
|
||||
&app_ptr->id,
|
||||
&app_ptr->name,
|
||||
&running,
|
||||
&terminal,
|
||||
&app_ptr->level);
|
||||
emit_app_state_changed(supervisor_ptr, app_ptr);
|
||||
|
||||
method_return_new_void(call_ptr);
|
||||
}
|
||||
|
|
|
@ -36,6 +36,25 @@ void ladish_app_supervisor_destroy(ladish_app_supervisor_handle supervisor_handl
|
|||
|
||||
bool ladish_app_supervisor_child_exit(ladish_app_supervisor_handle supervisor_handle, pid_t pid);
|
||||
|
||||
bool
|
||||
ladish_app_supervisor_enum(
|
||||
ladish_app_supervisor_handle supervisor_handle,
|
||||
void * context,
|
||||
bool (* callback)(void * context, const char * name, bool running, const char * command, bool terminal, uint8_t level));
|
||||
|
||||
void ladish_app_supervisor_clear(ladish_app_supervisor_handle supervisor_handle);
|
||||
|
||||
bool
|
||||
ladish_app_supervisor_add(
|
||||
ladish_app_supervisor_handle supervisor_handle,
|
||||
const char * name,
|
||||
bool autorun,
|
||||
const char * command,
|
||||
bool terminal,
|
||||
uint8_t level);
|
||||
|
||||
void ladish_app_supervisor_autorun(ladish_app_supervisor_handle supervisor_handle);
|
||||
|
||||
extern const struct dbus_interface_descriptor g_iface_app_supervisor;
|
||||
|
||||
#endif /* #ifndef APP_SUPERVISOR_H__712E6589_DCB1_4CE9_9812_4F250D55E8A2__INCLUDED */
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <expat.h>
|
||||
#include <limits.h>
|
||||
|
||||
#include "escape.h"
|
||||
#include "cmd.h"
|
||||
|
@ -49,9 +50,11 @@
|
|||
#define PARSE_CONTEXT_KEY 10
|
||||
#define PARSE_CONTEXT_CONNECTIONS 11
|
||||
#define PARSE_CONTEXT_CONNECTION 12
|
||||
#define PARSE_CONTEXT_APPLICATIONS 13
|
||||
#define PARSE_CONTEXT_APPLICATION 14
|
||||
|
||||
#define MAX_STACK_DEPTH 10
|
||||
#define MAX_DATA_SIZE 1024
|
||||
#define MAX_DATA_SIZE 10240
|
||||
|
||||
struct parse_context
|
||||
{
|
||||
|
@ -65,6 +68,9 @@ struct parse_context
|
|||
ladish_port_handle port;
|
||||
ladish_dict_handle dict;
|
||||
uint64_t connection_id;
|
||||
bool terminal;
|
||||
bool autorun;
|
||||
uint8_t level;
|
||||
};
|
||||
|
||||
#define context_ptr ((struct parse_context *)data)
|
||||
|
@ -77,7 +83,8 @@ static void callback_chrdata(void * data, const XML_Char * s, int len)
|
|||
}
|
||||
|
||||
if (context_ptr->element[context_ptr->depth] == PARSE_CONTEXT_PARAMETER ||
|
||||
context_ptr->element[context_ptr->depth] == PARSE_CONTEXT_KEY)
|
||||
context_ptr->element[context_ptr->depth] == PARSE_CONTEXT_KEY ||
|
||||
context_ptr->element[context_ptr->depth] == PARSE_CONTEXT_APPLICATION)
|
||||
{
|
||||
if (context_ptr->data_used + len >= sizeof(context_ptr->data))
|
||||
{
|
||||
|
@ -97,6 +104,8 @@ static void callback_elstart(void * data, const char * el, const char ** attr)
|
|||
uuid_t uuid2;
|
||||
ladish_port_handle port1;
|
||||
ladish_port_handle port2;
|
||||
long int li_value;
|
||||
char * end_ptr;
|
||||
|
||||
if (context_ptr->error)
|
||||
{
|
||||
|
@ -448,6 +457,83 @@ static void callback_elstart(void * data, const char * el, const char ** attr)
|
|||
return;
|
||||
}
|
||||
|
||||
if (strcmp(el, "applications") == 0)
|
||||
{
|
||||
//log_info("<applications>");
|
||||
context_ptr->element[++context_ptr->depth] = PARSE_CONTEXT_APPLICATIONS;
|
||||
return;
|
||||
}
|
||||
|
||||
if (strcmp(el, "application") == 0)
|
||||
{
|
||||
//log_info("<application>");
|
||||
context_ptr->element[++context_ptr->depth] = PARSE_CONTEXT_APPLICATION;
|
||||
|
||||
if (attr[0] == NULL ||
|
||||
attr[1] == NULL ||
|
||||
attr[2] == NULL ||
|
||||
attr[3] == NULL ||
|
||||
attr[4] == NULL ||
|
||||
attr[5] == NULL ||
|
||||
attr[6] == NULL ||
|
||||
attr[7] == NULL ||
|
||||
attr[8] != NULL ||
|
||||
strcmp(attr[0], "name") != 0 ||
|
||||
strcmp(attr[2], "terminal") != 0 ||
|
||||
strcmp(attr[4], "level") != 0 ||
|
||||
strcmp(attr[6], "autorun") != 0)
|
||||
{
|
||||
log_error("'application' XML element must contain exactly four attributes, named \"name\", \"terminal\", \"level\" and \"autorun\", in this order");
|
||||
context_ptr->error = XML_TRUE;
|
||||
return;
|
||||
}
|
||||
|
||||
if (strcmp(attr[3], "true") != 0 && strcmp(attr[3], "false") != 0)
|
||||
{
|
||||
log_error("'application@terminal' XML attribute is boolean and the only valid values are \"true\" and \"false\"");
|
||||
context_ptr->error = XML_TRUE;
|
||||
return;
|
||||
}
|
||||
|
||||
if (strcmp(attr[7], "true") != 0 && strcmp(attr[7], "false") != 0)
|
||||
{
|
||||
log_error("'application@autorun' XML attribute is boolean and the only valid values are \"true\" and \"false\"");
|
||||
context_ptr->error = XML_TRUE;
|
||||
return;
|
||||
}
|
||||
|
||||
errno = 0; /* To distinguish success/failure after call */
|
||||
li_value = strtol(attr[5], &end_ptr, 10);
|
||||
if ((errno == ERANGE && (li_value == LONG_MAX || li_value == LONG_MIN)) || (errno != 0 && li_value == 0) || end_ptr == attr[5])
|
||||
{
|
||||
log_error("'application@level' XML attribute '%s' is not valid integer.", attr[5]);
|
||||
context_ptr->error = XML_TRUE;
|
||||
return;
|
||||
}
|
||||
|
||||
if (li_value < 0 || li_value > 255)
|
||||
{
|
||||
log_error("'application@level' XML attribute '%s' is not valid uint8.", attr[5]);
|
||||
context_ptr->error = XML_TRUE;
|
||||
return;
|
||||
}
|
||||
|
||||
context_ptr->str = strdup(attr[1]);
|
||||
if (context_ptr->str == NULL)
|
||||
{
|
||||
log_error("strdup() failed");
|
||||
context_ptr->error = XML_TRUE;
|
||||
return;
|
||||
}
|
||||
|
||||
context_ptr->terminal = strcmp(attr[3], "true") == 0;
|
||||
context_ptr->autorun = strcmp(attr[7], "true") == 0;
|
||||
context_ptr->level = (uint8_t)li_value;
|
||||
|
||||
context_ptr->data_used = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
if (strcmp(el, "dict") == 0)
|
||||
{
|
||||
//log_info("<dict>");
|
||||
|
@ -700,6 +786,17 @@ static void callback_elend(void * data, const char * el)
|
|||
ASSERT(context_ptr->port != NULL);
|
||||
context_ptr->port = NULL;
|
||||
}
|
||||
else if (context_ptr->element[context_ptr->depth] == PARSE_CONTEXT_APPLICATION)
|
||||
{
|
||||
context_ptr->data[context_ptr->data_used] = 0;
|
||||
log_info("application '%s' (%s, %s, level %u) with commandline '%s'", context_ptr->str, context_ptr->terminal ? "terminal" : "shell", context_ptr->autorun ? "autorun" : "stopped", (unsigned int)context_ptr->level, context_ptr->data);
|
||||
|
||||
if (!ladish_app_supervisor_add(g_studio.app_supervisor, context_ptr->str, context_ptr->autorun, context_ptr->data, context_ptr->terminal, context_ptr->level))
|
||||
{
|
||||
log_error("ladish_app_supervisor_add() failed.");
|
||||
context_ptr->error = XML_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
context_ptr->depth--;
|
||||
|
||||
|
|
|
@ -557,6 +557,71 @@ bool save_studio_connection(void * context, ladish_port_handle port1_handle, lad
|
|||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool save_studio_app(void * context, const char * name, bool running, const char * command, bool terminal, uint8_t level)
|
||||
{
|
||||
char buf[100];
|
||||
|
||||
log_info("saving app: name='%s', %srunning, %s, level %u, commandline='%s'", name, running ? "" : "not ", terminal ? "terminal" : "shell", (unsigned int)level, command);
|
||||
|
||||
if (!write_string(fd, " <application name=\""))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!write_string(fd, name))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!write_string(fd, "\" terminal=\""))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!write_string(fd, terminal ? "true" : "false"))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!write_string(fd, "\" level=\""))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
sprintf(buf, "%u", (unsigned int)level);
|
||||
|
||||
if (!write_string(fd, buf))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!write_string(fd, "\" autorun=\""))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!write_string(fd, running ? "true" : "false"))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!write_string(fd, "\">"))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!write_string(fd, command))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!write_string(fd, "</application>\n"))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -767,9 +832,24 @@ static bool run(void * command_context)
|
|||
goto close;
|
||||
}
|
||||
|
||||
if (!write_string(fd, " <applications>\n"))
|
||||
{
|
||||
goto close;
|
||||
}
|
||||
|
||||
if (!ladish_app_supervisor_enum(g_studio.app_supervisor, &save_context, save_studio_app))
|
||||
{
|
||||
goto close;
|
||||
}
|
||||
|
||||
if (!write_string(fd, " </applications>\n"))
|
||||
{
|
||||
goto close;
|
||||
}
|
||||
|
||||
if (!write_dict(fd, " ", ladish_graph_get_dict(g_studio.studio_graph)))
|
||||
{
|
||||
return false;
|
||||
goto close;
|
||||
}
|
||||
|
||||
if (!write_string(fd, "</studio>\n"))
|
||||
|
|
|
@ -63,6 +63,8 @@ static bool run(void * context)
|
|||
g_studio.filename = NULL;
|
||||
}
|
||||
|
||||
ladish_app_supervisor_clear(g_studio.app_supervisor);
|
||||
|
||||
cmd_ptr->state = LADISH_COMMAND_STATE_DONE;
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -156,6 +156,8 @@ void on_event_jack_started(void)
|
|||
}
|
||||
}
|
||||
|
||||
ladish_app_supervisor_autorun(g_studio.app_supervisor);
|
||||
|
||||
emit_studio_started();
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue