diff --git a/daemon/control.c b/daemon/control.c index 2aaa8ebc..c5e6898d 100644 --- a/daemon/control.c +++ b/daemon/control.c @@ -164,6 +164,25 @@ static void ladish_load_studio(method_call_t * call_ptr) } } +static void ladish_delete_studio(method_call_t * call_ptr) +{ + const char * name; + + dbus_error_init(&g_dbus_error); + + if (!dbus_message_get_args(call_ptr->message, &g_dbus_error, DBUS_TYPE_STRING, &name, DBUS_TYPE_INVALID)) + { + lash_dbus_error(call_ptr, LASH_DBUS_ERROR_INVALID_ARGS, "Invalid arguments to method \"%s\": %s", call_ptr->method_name, g_dbus_error.message); + dbus_error_free(&g_dbus_error); + return; + } + + if (studio_delete(call_ptr, name)) + { + method_return_new_void(call_ptr); + } +} + static void ladish_get_application_list(method_call_t * call_ptr) { DBusMessageIter iter; @@ -267,6 +286,10 @@ METHOD_ARGS_BEGIN(LoadStudio, "Load studio") METHOD_ARG_DESCRIBE_IN("options", "a{sv}", "Load options") METHOD_ARGS_END +METHOD_ARGS_BEGIN(DeleteStudio, "Delete studio") + METHOD_ARG_DESCRIBE_IN("studio_name", "s", "Name of studio to delete") +METHOD_ARGS_END + METHOD_ARGS_BEGIN(GetApplicationList, "Get list of applications that can be launched") METHOD_ARG_DESCRIBE_OUT("applications", "a(sa{sv})", "List of applications, name and properties") METHOD_ARGS_END @@ -278,6 +301,7 @@ METHODS_BEGIN METHOD_DESCRIBE(IsStudioLoaded, ladish_is_studio_loaded) METHOD_DESCRIBE(GetStudioList, ladish_get_studio_list) METHOD_DESCRIBE(LoadStudio, ladish_load_studio) + METHOD_DESCRIBE(DeleteStudio, ladish_delete_studio) METHOD_DESCRIBE(GetApplicationList, ladish_get_application_list) METHOD_DESCRIBE(Exit, ladish_exit) METHODS_END diff --git a/daemon/studio.c b/daemon/studio.c index c6d74a0b..8174c4a9 100644 --- a/daemon/studio.c +++ b/daemon/studio.c @@ -1393,6 +1393,48 @@ fail_free_address: #undef context_ptr +bool studio_delete(void * call_ptr, const char * studio_name) +{ + char * filename; + char * bak_filename; + struct stat st; + bool ret; + + ret = false; + + if (!compose_filename(studio_name, &filename, &bak_filename)) + { + lash_dbus_error(call_ptr, LASH_DBUS_ERROR_GENERIC, "failed to compose studio filename"); + goto exit; + } + + lash_info("Loading studio ('%s')", filename); + + if (unlink(filename) != 0) + { + lash_dbus_error(call_ptr, LASH_DBUS_ERROR_GENERIC, "unlink(%s) failed: %d (%s)", filename, errno, strerror(errno)); + goto free; + } + + /* try to delete the backup file */ + if (stat(bak_filename, &st) == 0) + { + if (unlink(bak_filename) != 0) + { + /* failing to delete backup file will not case delete command failure */ + lash_error("unlink(%s) failed: %d (%s)", bak_filename, errno, strerror(errno)); + } + } + + ret = true; + +free: + free(filename); + free(bak_filename); +exit: + return ret; +} + bool studio_load(void * call_ptr, const char * studio_name) { char * path; diff --git a/daemon/studio.h b/daemon/studio.h index e809754c..8a8fbd5b 100644 --- a/daemon/studio.h +++ b/daemon/studio.h @@ -34,5 +34,6 @@ bool studio_is_loaded(void); bool studios_iterate(void * call_ptr, void * context, bool (* callback)(void * call_ptr, void * context, const char * studio, uint32_t modtime)); bool studio_load(void * call_ptr, const char * studio_name); +bool studio_delete(void * call_ptr, const char * studio_name); #endif /* #ifndef STUDIO_H__0BEDE85E_4FB3_4D74_BC08_C373A22409C0__INCLUDED */ diff --git a/gui/control_proxy.c b/gui/control_proxy.c index 8665943d..666d8119 100644 --- a/gui/control_proxy.c +++ b/gui/control_proxy.c @@ -160,6 +160,17 @@ bool control_proxy_load_studio(const char * studio_name) return true; } +bool control_proxy_delete_studio(const char * studio_name) +{ + if (!dbus_call_simple(SERVICE_NAME, CONTROL_OBJECT_PATH, IFACE_CONTROL, "DeleteStudio", "s", &studio_name, "")) + { + lash_error("DeleteStudio() failed."); + return false; + } + + return true; +} + bool control_proxy_exit(void) { if (!dbus_call_simple(SERVICE_NAME, CONTROL_OBJECT_PATH, IFACE_CONTROL, "Exit", "", "")) diff --git a/gui/control_proxy.h b/gui/control_proxy.h index 353add01..6ea1b450 100644 --- a/gui/control_proxy.h +++ b/gui/control_proxy.h @@ -37,6 +37,7 @@ void control_proxy_on_studio_appeared(void); void control_proxy_on_studio_disappeared(void); bool control_proxy_get_studio_list(void (* callback)(void * context, const char * studio_name), void * context); bool control_proxy_load_studio(const char * studio_name); +bool control_proxy_delete_studio(const char * studio_name); bool control_proxy_exit(void); #endif /* #ifndef CONTROL_PROXY_H__8BC89E98_FE1B_4831_8B89_1A48F676E019__INCLUDED */ diff --git a/gui/gui.glade b/gui/gui.glade index 63c545ad..1320bea5 100644 --- a/gui/gui.glade +++ b/gui/gui.glade @@ -67,6 +67,22 @@ + + + True + _Delete Studio + True + + + + + True + gtk-open + 1 + + + + True @@ -864,7 +880,11 @@ along with LADI Session Handler; if not, write to the Free Software Foundation, - + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + + True GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK diff --git a/gui/main.c b/gui/main.c index 3f41e3d8..15676d0c 100644 --- a/gui/main.c +++ b/gui/main.c @@ -50,11 +50,11 @@ GtkWidget * g_buffer_size_combo; GtkWidget * g_menu_item_load_studio; GtkWidget * g_menu_item_save_studio; GtkWidget * g_menu_item_rename_studio; +GtkWidget * g_menu_item_delete_studio; GtkWidget * g_menu_item_create_room; GtkWidget * g_menu_item_destroy_room; GtkWidget * g_menu_item_load_project; GtkWidget * g_menu_item_start_app; -GtkWidget * g_menu_studio_list; GtkWidget * g_rename_dialog; @@ -63,7 +63,18 @@ graph_view_handle g_studio_view = NULL; static guint g_jack_poll_source_tag; static double g_jack_max_dsp_load = 0.0; -static int g_studio_count = 0; + +struct studio_list +{ + int count; + GtkWidget * menu_item; + GtkWidget * menu; + void (* item_activate_callback)(GtkWidget * item); + bool add_sensitive; +}; + +static struct studio_list g_load_studio_list; +static struct studio_list g_delete_studio_list; #if 0 static void @@ -220,7 +231,24 @@ static void on_load_studio(GtkWidget * item) } } -static void remove_studio_list_menu_entry(GtkWidget * item, GtkContainer * container) +static void on_delete_studio(GtkWidget * item) +{ + const char * studio_name; + + studio_name = gtk_label_get_text(GTK_LABEL(gtk_bin_get_child(GTK_BIN(item)))); + lash_info("Delete studio \"%s\"", studio_name); + + /* TODO: ask user for confirmation */ + + if (!control_proxy_delete_studio(studio_name)) + { + /* TODO: display error message */ + } +} + +#define studio_list_ptr ((struct studio_list *)context) + +static void remove_studio_list_menu_entry(GtkWidget * item, gpointer context) { GtkWidget * label; @@ -232,15 +260,8 @@ static void remove_studio_list_menu_entry(GtkWidget * item, GtkContainer * conta gtk_container_remove(GTK_CONTAINER(item), label); /* destroy the label and drop the item refcount by one */ //lash_info("refcount == %d", (unsigned int)G_OBJECT(item)->ref_count); - gtk_container_remove(container, item); /* drop the refcount of item by one and thus destroy it */ - g_studio_count--; -} - -static void menu_studio_list_clear(void) -{ - gtk_container_foreach(GTK_CONTAINER(g_menu_studio_list), (GtkCallback)remove_studio_list_menu_entry, GTK_CONTAINER(g_menu_studio_list)); - assert(g_studio_count == 0); - g_studio_count = 0; + gtk_container_remove(GTK_CONTAINER(studio_list_ptr->menu), item); /* drop the refcount of item by one and thus destroy it */ + studio_list_ptr->count--; } static void add_studio_list_menu_entry(void * context, const char * studio_name) @@ -249,24 +270,36 @@ static void add_studio_list_menu_entry(void * context, const char * studio_name) item = gtk_menu_item_new_with_label(studio_name); //lash_info("refcount == %d", (unsigned int)G_OBJECT(item)->ref_count); // refcount == 2 because of the label - gtk_widget_set_sensitive(item, (bool)context); + gtk_widget_set_sensitive(item, studio_list_ptr->add_sensitive); gtk_widget_show(item); - gtk_menu_shell_append(GTK_MENU_SHELL(g_menu_studio_list), item); - g_signal_connect(G_OBJECT(item), "activate", G_CALLBACK(on_load_studio), item); - g_studio_count++; + gtk_menu_shell_append(GTK_MENU_SHELL(studio_list_ptr->menu), item); + g_signal_connect(G_OBJECT(item), "activate", G_CALLBACK(studio_list_ptr->item_activate_callback), item); + studio_list_ptr->count++; } -static void activate_load_studio_list(void) +#undef studio_list_ptr + +static void menu_studio_list_clear(struct studio_list * studio_list_ptr) { - menu_studio_list_clear(); - if (!control_proxy_get_studio_list(add_studio_list_menu_entry, (void *)true)) + gtk_container_foreach(GTK_CONTAINER(studio_list_ptr->menu), remove_studio_list_menu_entry, studio_list_ptr); + assert(studio_list_ptr->count == 0); + studio_list_ptr->count = 0; +} + +static void populate_studio_list_menu(GtkMenuItem * menu_item, struct studio_list * studio_list_ptr) +{ + menu_studio_list_clear(studio_list_ptr); + studio_list_ptr->add_sensitive = true; + if (!control_proxy_get_studio_list(add_studio_list_menu_entry, studio_list_ptr)) { - menu_studio_list_clear(); - add_studio_list_menu_entry((void *)false, "Error obtaining studio list"); + menu_studio_list_clear(studio_list_ptr); + studio_list_ptr->add_sensitive = true; + add_studio_list_menu_entry(studio_list_ptr, "Error obtaining studio list"); } - else if (g_studio_count == 0) + else if (studio_list_ptr->count == 0) { - add_studio_list_menu_entry((void *)false, "Empty studio list"); + studio_list_ptr->add_sensitive = true; + add_studio_list_menu_entry(studio_list_ptr, "Empty studio list"); } } @@ -421,6 +454,25 @@ set_main_window_title( free(title); } +static +void +init_studio_list( + struct studio_list * studio_list_ptr, + const char * menu_item, + const char * menu, + void (* item_activate_callback)(GtkWidget * item)) +{ + studio_list_ptr->count = 0; + studio_list_ptr->menu_item = get_glade_widget(menu_item); + studio_list_ptr->menu = get_glade_widget(menu); + studio_list_ptr->item_activate_callback = item_activate_callback; + gtk_menu_item_set_submenu(GTK_MENU_ITEM(studio_list_ptr->menu_item), studio_list_ptr->menu); + g_signal_connect(G_OBJECT(studio_list_ptr->menu_item), "activate", G_CALLBACK(populate_studio_list_menu), studio_list_ptr); + + lash_info("studio_list_ptr = %p", studio_list_ptr); + lash_info("studio_list_ptr->menu = %p", studio_list_ptr->menu); +} + int main(int argc, char** argv) { gtk_init(&argc, &argv); @@ -440,18 +492,17 @@ int main(int argc, char** argv) g_clear_load_button = get_glade_widget("clear_load_button"); g_xrun_progress_bar = get_glade_widget("xrun_progress_bar"); g_buffer_size_combo = get_glade_widget("buffer_size_combo"); - g_menu_item_load_studio = get_glade_widget("menu_item_load_studio"); g_menu_item_save_studio = get_glade_widget("menu_item_save_studio"); g_menu_item_rename_studio = get_glade_widget("menu_item_rename_studio"); g_menu_item_create_room = get_glade_widget("menu_item_create_room"); g_menu_item_destroy_room = get_glade_widget("menu_item_destroy_room"); g_menu_item_load_project = get_glade_widget("menu_item_load_project"); g_menu_item_start_app = get_glade_widget("menu_item_start_app"); - g_menu_studio_list = get_glade_widget("studio_list_menu"); g_rename_dialog = get_glade_widget("rename_dialog"); - gtk_menu_item_set_submenu(GTK_MENU_ITEM(g_menu_item_load_studio), g_menu_studio_list); + init_studio_list(&g_load_studio_list, "menu_item_load_studio", "load_studio_menu", on_load_studio); + init_studio_list(&g_delete_studio_list, "menu_item_delete_studio", "delete_studio_menu", on_delete_studio); world_tree_init(); view_init(); @@ -484,7 +535,6 @@ int main(int argc, char** argv) g_signal_connect(G_OBJECT(get_glade_widget("menu_item_view_arrange")), "activate", G_CALLBACK(arrange), NULL); g_signal_connect(G_OBJECT(g_menu_item_save_studio), "activate", G_CALLBACK(save_studio), NULL); g_signal_connect(G_OBJECT(g_menu_item_rename_studio), "activate", G_CALLBACK(rename_studio), NULL); - g_signal_connect(G_OBJECT(g_menu_item_load_studio), "activate", G_CALLBACK(activate_load_studio_list), NULL); gtk_widget_show(g_main_win);