Merge branch 'stable' into 'main'
[ladish.git] / gui / world_tree.c
blob582559f9c75094918e66041e2108c091cbf7b1c5
1 /* -*- Mode: C ; c-basic-offset: 2 -*- */
2 /*
3 * LADI Session Handler (ladish)
5 * Copyright (C) 2008,2009,2010,2011,2012 Nedko Arnaudov <nedko@arnaudov.name>
7 **************************************************************************
8 * This file contains implementation of the project_list class
9 **************************************************************************
11 * LADI Session Handler is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
16 * LADI Session Handler is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with LADI Session Handler. If not, see <http://www.gnu.org/licenses/>
23 * or write to the Free Software Foundation, Inc.,
24 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
27 #include "common.h"
28 #include "world_tree.h"
29 #include "gtk_builder.h"
30 #include "../common/catdup.h"
31 #include "menu.h"
33 #include <libintl.h>
35 enum entry_type
37 entry_type_view,
38 entry_type_app
41 enum
43 COL_TYPE = 0,
44 COL_NAME,
45 COL_VIEW,
46 COL_ID,
47 COL_RUNNING,
48 COL_TERMINAL,
49 COL_LEVEL,
50 NUM_COLS
53 GtkWidget * g_world_tree_widget;
54 GtkTreeStore * g_treestore;
56 bool get_app_view(GtkTreeIter * app_iter_ptr, graph_view_handle * view_ptr)
58 GtkTreeIter view_iter;
59 gint type;
61 if (!gtk_tree_model_iter_parent(GTK_TREE_MODEL(g_treestore), &view_iter, app_iter_ptr))
63 ASSERT_NO_PASS;
64 return false;
67 gtk_tree_model_get(
68 GTK_TREE_MODEL(g_treestore),
69 &view_iter,
70 COL_TYPE, &type,
71 COL_VIEW, view_ptr,
72 -1);
73 if (type != entry_type_view)
75 ASSERT_NO_PASS;
76 return false;
79 return true;
82 static
83 gboolean
84 on_select(
85 GtkTreeSelection * UNUSED(selection),
86 GtkTreeModel * model,
87 GtkTreePath * path,
88 gboolean path_currently_selected,
89 gpointer UNUSED(data))
91 GtkTreeIter iter;
92 graph_view_handle view;
93 gint type;
94 uint64_t id;
96 if (gtk_tree_model_get_iter(model, &iter, path))
98 gtk_tree_model_get(model, &iter, COL_TYPE, &type, COL_VIEW, &view, COL_ID, &id, -1);
99 switch (type)
101 case entry_type_app:
102 if (!get_app_view(&iter, &view))
104 ASSERT_NO_PASS;
105 break;
107 case entry_type_view:
108 //log_info("%s is going to be %s.", get_view_name(view), path_currently_selected ? "unselected" : "selected");
109 if (!path_currently_selected)
111 activate_view(view);
113 break;
117 return TRUE;
120 bool get_selected_app_id(graph_view_handle * view_ptr, uint64_t * id_ptr)
122 GtkTreeSelection * selection;
123 GtkTreeIter app_iter;
124 gint type;
125 uint64_t id;
126 graph_view_handle view;
128 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(g_world_tree_widget));
129 if (!gtk_tree_selection_get_selected(selection, NULL, &app_iter))
131 return false;
134 gtk_tree_model_get(
135 GTK_TREE_MODEL(g_treestore),
136 &app_iter,
137 COL_TYPE, &type,
138 COL_ID, &id,
139 -1);
140 if (type != entry_type_app)
142 return false;
145 if (!get_app_view(&app_iter, &view))
147 ASSERT_NO_PASS;
148 return false;
151 *view_ptr = view;
152 *id_ptr = id;
154 return true;
157 void on_popup_menu_action_app_start(GtkWidget * UNUSED(menuitem), gpointer UNUSED(userdata))
159 uint64_t id;
160 ladish_app_supervisor_proxy_handle proxy;
161 graph_view_handle view;
163 if (!get_selected_app_id(&view, &id))
165 return;
168 log_info("start app %"PRIu64, id);
170 proxy = graph_view_get_app_supervisor(view);
171 ladish_app_supervisor_proxy_start_app(proxy, id);
174 void on_popup_menu_action_app_stop(GtkWidget * UNUSED(menuitem), gpointer UNUSED(userdata))
176 uint64_t id;
177 ladish_app_supervisor_proxy_handle proxy;
178 graph_view_handle view;
180 if (!get_selected_app_id(&view, &id))
182 return;
185 log_info("stop app %"PRIu64, id);
187 proxy = graph_view_get_app_supervisor(view);
188 ladish_app_supervisor_proxy_stop_app(proxy, id);
191 void on_popup_menu_action_app_kill(GtkWidget * UNUSED(menuitem), gpointer UNUSED(userdata))
193 uint64_t id;
194 ladish_app_supervisor_proxy_handle proxy;
195 graph_view_handle view;
197 if (!get_selected_app_id(&view, &id))
199 return;
202 log_info("kill app %"PRIu64, id);
204 proxy = graph_view_get_app_supervisor(view);
205 ladish_app_supervisor_proxy_kill_app(proxy, id);
208 void on_popup_menu_action_app_remove(GtkWidget * UNUSED(menuitem), gpointer UNUSED(userdata))
210 uint64_t id;
211 ladish_app_supervisor_proxy_handle proxy;
212 graph_view_handle view;
214 if (!get_selected_app_id(&view, &id))
216 return;
219 log_info("remove app %"PRIu64, id);
221 proxy = graph_view_get_app_supervisor(view);
222 ladish_app_supervisor_proxy_remove_app(proxy, id);
225 void on_popup_menu_action_app_properties(GtkWidget * UNUSED(menuitem), gpointer UNUSED(userdata))
227 uint64_t id;
228 ladish_app_supervisor_proxy_handle proxy;
229 graph_view_handle view;
230 char * name;
231 char * command;
232 bool running;
233 bool terminal;
234 const char * level;
235 guint result;
236 GtkEntry * command_entry = GTK_ENTRY(get_gtk_builder_widget("app_command_entry"));
237 GtkEntry * name_entry = GTK_ENTRY(get_gtk_builder_widget("app_name_entry"));
238 GtkToggleButton * terminal_button = GTK_TOGGLE_BUTTON(get_gtk_builder_widget("app_terminal_check_button"));
239 GtkToggleButton * level0_button = GTK_TOGGLE_BUTTON(get_gtk_builder_widget("app_level0"));
240 GtkToggleButton * level1_button = GTK_TOGGLE_BUTTON(get_gtk_builder_widget("app_level1"));
241 GtkToggleButton * level2lash_button = GTK_TOGGLE_BUTTON(get_gtk_builder_widget("app_level2lash"));
242 GtkToggleButton * level2js_button = GTK_TOGGLE_BUTTON(get_gtk_builder_widget("app_level2js"));
244 if (!get_selected_app_id(&view, &id))
246 return;
249 log_info("app %"PRIu64" properties", id);
251 proxy = graph_view_get_app_supervisor(view);
253 if (!ladish_app_supervisor_get_app_properties(proxy, id, &name, &command, &running, &terminal, &level))
255 error_message_box(_("Cannot get app properties"));
256 return;
259 log_info("'%s':'%s' %s level '%s'", name, command, terminal ? "terminal" : "shell", level);
261 gtk_entry_set_text(name_entry, name);
262 gtk_entry_set_text(command_entry, command);
263 gtk_toggle_button_set_active(terminal_button, terminal);
265 gtk_widget_set_sensitive(GTK_WIDGET(command_entry), !running);
266 gtk_widget_set_sensitive(GTK_WIDGET(terminal_button), !running);
267 gtk_widget_set_sensitive(GTK_WIDGET(level0_button), !running);
268 gtk_widget_set_sensitive(GTK_WIDGET(level1_button), !running);
269 gtk_widget_set_sensitive(GTK_WIDGET(level2lash_button), !running);
270 gtk_widget_set_sensitive(GTK_WIDGET(level2js_button), !running && is_room_view(view));
272 /* comparing pointers here is ok, because ladish_map_app_level_constant() was called by ladish_app_supervisor_get_app_properties() */
273 if (level == LADISH_APP_LEVEL_0)
275 gtk_toggle_button_set_active(level0_button, TRUE);
277 else if (level == LADISH_APP_LEVEL_1)
279 gtk_toggle_button_set_active(level1_button, TRUE);
281 else if (level == LADISH_APP_LEVEL_LASH)
283 gtk_toggle_button_set_active(level2lash_button, TRUE);
285 else if (level == LADISH_APP_LEVEL_JACKSESSION)
287 gtk_toggle_button_set_active(level2js_button, TRUE);
289 else
291 log_error("unknown level");
292 ASSERT_NO_PASS;
293 gtk_toggle_button_set_active(level0_button, TRUE);
296 free(name);
297 free(command);
299 gtk_window_set_focus(GTK_WINDOW(g_app_dialog), running ? GTK_WIDGET(name_entry) : GTK_WIDGET(command_entry));
300 gtk_window_set_title(GTK_WINDOW(g_app_dialog), _("App properties"));
302 gtk_widget_show(g_app_dialog);
304 result = gtk_dialog_run(GTK_DIALOG(g_app_dialog));
305 if (result == 2)
307 if (gtk_toggle_button_get_active(level0_button))
309 level = LADISH_APP_LEVEL_0;
311 else if (gtk_toggle_button_get_active(level1_button))
313 level = LADISH_APP_LEVEL_1;
315 else if (gtk_toggle_button_get_active(level2lash_button))
317 level = LADISH_APP_LEVEL_LASH;
319 else if (gtk_toggle_button_get_active(level2js_button))
321 level = LADISH_APP_LEVEL_JACKSESSION;
323 else
325 log_error("unknown level");
326 ASSERT_NO_PASS;
327 level = LADISH_APP_LEVEL_0;
330 log_info("'%s':'%s' %s level '%s'", gtk_entry_get_text(name_entry), gtk_entry_get_text(command_entry), gtk_toggle_button_get_active(terminal_button) ? "terminal" : "shell", level);
331 if (!ladish_app_supervisor_set_app_properties(proxy, id, gtk_entry_get_text(name_entry), gtk_entry_get_text(command_entry), gtk_toggle_button_get_active(terminal_button), level))
333 error_message_box(_("Cannot set app properties."));
337 gtk_widget_hide(g_app_dialog);
340 void popup_menu(GtkWidget * UNUSED(treeview), GdkEventButton * event)
342 GtkTreeSelection * selection;
343 GtkTreeIter iter;
344 GtkWidget * menu;
345 GtkWidget * menuitem;
346 gint type;
347 graph_view_handle view;
348 uint64_t id;
349 gboolean running;
350 gboolean terminal;
351 const char * level;
353 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(g_world_tree_widget));
354 if (!gtk_tree_selection_get_selected(selection, NULL, &iter))
356 return;
359 gtk_tree_model_get(
360 GTK_TREE_MODEL(g_treestore),
361 &iter,
362 COL_TYPE, &type,
363 COL_VIEW, &view,
364 COL_ID, &id,
365 COL_RUNNING, &running,
366 COL_TERMINAL, &terminal,
367 COL_LEVEL, &level,
368 -1);
370 menu = gtk_menu_new();
372 if (type == entry_type_app)
374 if (running)
376 menuitem = gtk_menu_item_new_with_label(_("Stop"));
377 g_signal_connect(menuitem, "activate", (GCallback)on_popup_menu_action_app_stop, NULL);
378 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
380 menuitem = gtk_menu_item_new_with_label(_("Kill"));
381 g_signal_connect(menuitem, "activate", (GCallback)on_popup_menu_action_app_kill, NULL);
382 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
384 else
386 menuitem = gtk_menu_item_new_with_label(_("Start"));
387 g_signal_connect(menuitem, "activate", (GCallback)on_popup_menu_action_app_start, NULL);
388 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
391 menuitem = gtk_menu_item_new_with_label(_("Properties"));
392 g_signal_connect(menuitem, "activate", (GCallback)on_popup_menu_action_app_properties, NULL);
393 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
395 menuitem = gtk_separator_menu_item_new(); /* separator */
396 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
398 menuitem = gtk_menu_item_new_with_label(_("Remove"));
399 g_signal_connect(menuitem, "activate", (GCallback)on_popup_menu_action_app_remove, NULL);
400 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
402 else if (type == entry_type_view)
404 fill_view_popup_menu(GTK_MENU(menu), view);
406 else
408 g_object_ref(menu);
409 g_object_unref(menu);
410 return;
413 gtk_widget_show_all(menu);
415 /* Note: event can be NULL here when called from view_onPopupMenu;
416 * gdk_event_get_time() accepts a NULL argument */
417 gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL, (event != NULL) ? event->button : 0, gdk_event_get_time((GdkEvent *)event));
420 gboolean on_button_pressed(GtkWidget * treeview, GdkEventButton * event, gpointer UNUSED(userdata))
422 /* single click with the right mouse button? */
423 if (event->type == GDK_BUTTON_PRESS && event->button == 3)
425 /* select row if no row is selected or only one other row is selected */
427 GtkTreeSelection *selection;
429 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(treeview));
431 /* Note: gtk_tree_selection_count_selected_rows() does not exist in gtk+-2.0, only in gtk+ >= v2.2 ! */
432 if (gtk_tree_selection_count_selected_rows(selection) <= 1)
434 GtkTreePath *path;
436 /* Get tree path for row that was clicked */
437 if (gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(treeview), (gint)event->x, (gint)event->y, &path, NULL, NULL, NULL))
439 gtk_tree_selection_unselect_all(selection);
440 gtk_tree_selection_select_path(selection, path);
441 gtk_tree_path_free(path);
446 popup_menu(treeview, event);
448 return TRUE; /* we handled this */
451 return FALSE; /* we did not handle this */
454 gboolean on_popup_menu(GtkWidget * treeview, gpointer UNUSED(userdata))
456 popup_menu(treeview, NULL);
457 return TRUE; /* we handled this */
460 static
461 void
462 on_row_activated(
463 GtkTreeView * UNUSED(treeview),
464 GtkTreePath * path,
465 GtkTreeViewColumn * UNUSED(col),
466 gpointer UNUSED(userdata))
468 GtkTreeIter iter;
469 gint type;
470 graph_view_handle view;
471 uint64_t id;
472 gboolean running;
473 ladish_app_supervisor_proxy_handle proxy;
475 if (!gtk_tree_model_get_iter(GTK_TREE_MODEL(g_treestore), &iter, path))
477 return;
480 gtk_tree_model_get(GTK_TREE_MODEL(g_treestore), &iter, COL_TYPE, &type, COL_ID, &id, COL_RUNNING, &running, -1);
481 if (type == entry_type_app)
483 log_info("%s app %"PRIu64, running ? "stop" : "start", id);
485 if (!get_app_view(&iter, &view))
487 ASSERT_NO_PASS;
488 return;
491 proxy = graph_view_get_app_supervisor(view);
492 (running ? ladish_app_supervisor_proxy_stop_app : ladish_app_supervisor_proxy_start_app)(proxy, id);
496 void world_tree_init(void)
498 GtkTreeViewColumn * col;
499 GtkCellRenderer * renderer;
500 GtkTreeSelection * selection;
502 g_world_tree_widget = get_gtk_builder_widget("world_tree");
503 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(g_world_tree_widget), FALSE);
505 col = gtk_tree_view_column_new();
506 gtk_tree_view_column_set_title(col, _("Name"));
507 gtk_tree_view_append_column(GTK_TREE_VIEW(g_world_tree_widget), col);
508 renderer = gtk_cell_renderer_text_new();
509 gtk_tree_view_column_pack_start(col, renderer, TRUE);
510 gtk_tree_view_column_add_attribute(col, renderer, "text", COL_NAME);
512 g_treestore = gtk_tree_store_new(
513 NUM_COLS,
514 G_TYPE_INT,
515 G_TYPE_STRING,
516 G_TYPE_POINTER,
517 G_TYPE_UINT64,
518 G_TYPE_BOOLEAN,
519 G_TYPE_BOOLEAN,
520 G_TYPE_STRING);
521 gtk_tree_view_set_model(GTK_TREE_VIEW(g_world_tree_widget), GTK_TREE_MODEL(g_treestore));
523 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(g_world_tree_widget));
524 gtk_tree_selection_set_select_function(selection, on_select, NULL, NULL);
526 g_signal_connect(g_world_tree_widget, "button-press-event", (GCallback)on_button_pressed, NULL);
527 g_signal_connect(g_world_tree_widget, "popup-menu", (GCallback)on_popup_menu, NULL);
528 g_signal_connect(g_world_tree_widget, "row-activated", (GCallback)on_row_activated, NULL);
531 void world_tree_add(graph_view_handle view, bool force_activate)
533 GtkTreeIter iter;
535 gtk_tree_store_append(g_treestore, &iter, NULL);
536 gtk_tree_store_set(g_treestore, &iter, COL_TYPE, entry_type_view, COL_VIEW, view, COL_NAME, get_view_name(view), -1);
538 /* select the first top level item */
539 if (force_activate || gtk_tree_model_iter_n_children(GTK_TREE_MODEL(g_treestore), NULL) == 1)
541 gtk_tree_selection_select_iter(gtk_tree_view_get_selection(GTK_TREE_VIEW(g_world_tree_widget)), &iter);
545 graph_view_handle world_tree_find_by_opath(const char * opath)
547 gint type;
548 graph_view_handle view;
549 GtkTreeIter iter;
551 if (gtk_tree_model_get_iter_first(GTK_TREE_MODEL(g_treestore), &iter))
555 gtk_tree_model_get(GTK_TREE_MODEL(g_treestore), &iter, COL_TYPE, &type, COL_VIEW, &view, -1);
556 if (type == entry_type_view)
558 if (strcmp(get_view_opath(view), opath) == 0)
560 return view;
564 while (gtk_tree_model_iter_next(GTK_TREE_MODEL(g_treestore), &iter));
567 return NULL;
570 static bool find_view(graph_view_handle view, GtkTreeIter * iter_ptr)
572 gint type;
573 graph_view_handle view2;
575 if (gtk_tree_model_get_iter_first(GTK_TREE_MODEL(g_treestore), iter_ptr))
579 gtk_tree_model_get(GTK_TREE_MODEL(g_treestore), iter_ptr, COL_TYPE, &type, COL_VIEW, &view2, -1);
580 if (type == entry_type_view && view == view2)
582 return true;
585 while (gtk_tree_model_iter_next(GTK_TREE_MODEL(g_treestore), iter_ptr));
588 return false;
591 static bool find_app(graph_view_handle view, uint64_t id, GtkTreeIter * view_iter_ptr, GtkTreeIter * app_iter_ptr)
593 gint type;
594 uint64_t id2;
596 if (!find_view(view, view_iter_ptr))
598 return false;
601 if (!gtk_tree_model_iter_children(GTK_TREE_MODEL(g_treestore), app_iter_ptr, view_iter_ptr))
603 return false;
608 gtk_tree_model_get(GTK_TREE_MODEL(g_treestore), app_iter_ptr, COL_TYPE, &type, COL_ID, &id2, -1);
609 if (type == entry_type_app && id == id2)
611 return true;
614 while (gtk_tree_model_iter_next(GTK_TREE_MODEL(g_treestore), app_iter_ptr));
616 return false;
619 void world_tree_remove(graph_view_handle view)
621 GtkTreeIter iter;
623 if (find_view(view, &iter))
625 gtk_tree_store_remove(g_treestore, &iter);
629 void world_tree_activate(graph_view_handle view)
631 GtkTreeIter iter;
633 if (find_view(view, &iter))
635 gtk_tree_selection_select_iter(gtk_tree_view_get_selection(GTK_TREE_VIEW(g_world_tree_widget)), &iter);
639 void world_tree_name_changed(graph_view_handle view)
641 GtkTreeIter iter;
643 if (find_view(view, &iter))
645 gtk_tree_store_set(g_treestore, &iter, COL_NAME, get_view_name(view), -1);
649 static char * get_app_name_string(const char * app_name, bool running, bool UNUSED(terminal), const char * level)
651 char * app_name_with_status;
652 const char * level_string;
654 level = ladish_map_app_level_constant(level);
655 /* comparing pointers here is ok, because ladish_map_app_level_constant() was called */
656 if (level == LADISH_APP_LEVEL_0)
658 level_string = "[L0]";
660 else if (level == LADISH_APP_LEVEL_1)
662 level_string = "[L1]";
664 else if (level == LADISH_APP_LEVEL_LASH)
666 level_string = "[LASH]";
668 else if (level == LADISH_APP_LEVEL_JACKSESSION)
670 level_string = "[JS]";
672 else
674 level_string = "[L?]";
677 app_name_with_status = catdup3(level_string, running ? " " : _(" (inactive) "), app_name);
678 if (app_name_with_status == NULL)
680 log_error("catdup failed for app name");
681 return NULL;
684 return app_name_with_status;
687 void world_tree_add_app(graph_view_handle view, uint64_t id, const char * app_name, bool running, bool terminal, const char * level)
689 GtkTreeIter iter;
690 const char * view_name;
691 GtkTreeIter child;
692 GtkTreePath * path;
693 char * app_name_with_status;
695 if (!find_view(view, &iter))
697 ASSERT_NO_PASS;
698 return;
701 path = gtk_tree_model_get_path(GTK_TREE_MODEL(g_treestore), &iter);
703 gtk_tree_model_get(GTK_TREE_MODEL(g_treestore), &iter, COL_NAME, &view_name, -1);
705 log_info("adding app '%s' to '%s'", app_name, view_name);
707 app_name_with_status = get_app_name_string(app_name, running, terminal, level);
708 if (app_name_with_status == NULL)
710 goto free_path;
713 gtk_tree_store_append(g_treestore, &child, &iter);
714 gtk_tree_store_set(
715 g_treestore,
716 &child,
717 COL_TYPE, entry_type_app,
718 COL_NAME, app_name_with_status,
719 COL_ID, id,
720 COL_RUNNING, running,
721 COL_TERMINAL, terminal,
722 COL_LEVEL, level,
723 -1);
724 gtk_tree_view_expand_row(GTK_TREE_VIEW(g_world_tree_widget), path, false);
726 free(app_name_with_status);
727 free_path:
728 gtk_tree_path_free(path);
731 void world_tree_app_state_changed(graph_view_handle view, uint64_t id, const char * app_name, bool running, bool terminal, const char * level)
733 GtkTreeIter view_iter;
734 GtkTreeIter app_iter;
735 const char * view_name;
736 GtkTreePath * path;
737 char * app_name_with_status;
739 if (!find_app(view, id, &view_iter, &app_iter))
741 log_error("removed app not found");
742 return;
745 path = gtk_tree_model_get_path(GTK_TREE_MODEL(g_treestore), &view_iter);
747 gtk_tree_model_get(GTK_TREE_MODEL(g_treestore), &view_iter, COL_NAME, &view_name, -1);
749 log_info("changing app state '%s':'%s'", view_name, app_name);
751 app_name_with_status = get_app_name_string(app_name, running, terminal, level);
752 if (app_name_with_status == NULL)
754 goto free_path;
757 gtk_tree_view_expand_row(GTK_TREE_VIEW(g_world_tree_widget), path, false);
758 gtk_tree_store_set(
759 g_treestore,
760 &app_iter,
761 COL_NAME, app_name_with_status,
762 COL_RUNNING, running,
763 COL_TERMINAL, terminal,
764 COL_LEVEL, level,
765 -1);
767 free(app_name_with_status);
768 free_path:
769 gtk_tree_path_free(path);
772 void world_tree_remove_app(graph_view_handle view, uint64_t id)
774 GtkTreeIter view_iter;
775 GtkTreeIter app_iter;
776 const char * view_name;
777 const char * app_name;
778 GtkTreePath * path;
780 if (!find_app(view, id, &view_iter, &app_iter))
782 log_error("removed app not found");
783 return;
786 path = gtk_tree_model_get_path(GTK_TREE_MODEL(g_treestore), &view_iter);
788 gtk_tree_model_get(GTK_TREE_MODEL(g_treestore), &view_iter, COL_NAME, &view_name, -1);
789 gtk_tree_model_get(GTK_TREE_MODEL(g_treestore), &app_iter, COL_NAME, &app_name, -1);
791 log_info("removing app '%s' from '%s'", app_name, view_name);
793 gtk_tree_view_expand_row(GTK_TREE_VIEW(g_world_tree_widget), path, false);
794 gtk_tree_store_remove(g_treestore, &app_iter);
796 gtk_tree_path_free(path);
799 void world_tree_destroy_room_views(void)
801 gint type;
802 graph_view_handle view;
803 GtkTreeIter iter;
804 bool valid;
806 if (!gtk_tree_model_get_iter_first(GTK_TREE_MODEL(g_treestore), &iter))
808 return;
811 loop:
812 gtk_tree_model_get(GTK_TREE_MODEL(g_treestore), &iter, COL_TYPE, &type, COL_VIEW, &view, -1);
813 if (type == entry_type_view && is_room_view(view))
815 //log_info("removing view for room %s", get_view_opath(view));
816 valid = gtk_tree_store_remove(g_treestore, &iter);
818 destroy_view(view);
820 if (!valid)
822 /* no more entries */
823 return;
826 goto loop;
829 if (gtk_tree_model_iter_next(GTK_TREE_MODEL(g_treestore), &iter))
831 goto loop;