properly handle ladishd crashes
[ladish.git] / gui / world_tree.c
blob53b784c1868e3b7023e3309de25c649b81dcc878
1 /* -*- Mode: C ; c-basic-offset: 2 -*- */
2 /*
3 * LADI Session Handler (ladish)
5 * Copyright (C) 2008, 2009 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 "glade.h"
30 #include "../catdup.h"
32 enum entry_type
34 entry_type_view,
35 entry_type_app
38 enum
40 COL_TYPE = 0,
41 COL_NAME,
42 COL_VIEW,
43 COL_ID,
44 COL_RUNNING,
45 COL_TERMINAL,
46 COL_LEVEL,
47 NUM_COLS
50 GtkWidget * g_world_tree_widget;
51 GtkTreeStore * g_treestore;
53 static
54 gboolean
55 on_select(
56 GtkTreeSelection * selection,
57 GtkTreeModel * model,
58 GtkTreePath * path,
59 gboolean path_currently_selected,
60 gpointer data)
62 GtkTreeIter iter;
63 graph_view_handle view;
64 gint type;
66 if (gtk_tree_model_get_iter(model, &iter, path))
68 gtk_tree_model_get(model, &iter, COL_TYPE, &type, COL_VIEW, &view, -1);
69 if (type == entry_type_view)
71 //log_info("%s is going to be %s.", get_view_name(view), path_currently_selected ? "unselected" : "selected");
72 if (!path_currently_selected)
74 activate_view(view);
79 return TRUE;
82 bool get_selected_app_id(graph_view_handle * view_ptr, uint64_t * id_ptr)
84 GtkTreeSelection * selection;
85 GtkTreeIter app_iter;
86 GtkTreeIter view_iter;
87 gint type;
88 uint64_t id;
89 graph_view_handle view;
91 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(g_world_tree_widget));
92 if (!gtk_tree_selection_get_selected(selection, NULL, &app_iter))
94 return false;
97 gtk_tree_model_get(
98 GTK_TREE_MODEL(g_treestore),
99 &app_iter,
100 COL_TYPE, &type,
101 COL_ID, &id,
102 -1);
103 if (type != entry_type_app)
105 return false;
108 if (!gtk_tree_model_iter_parent(GTK_TREE_MODEL(g_treestore), &view_iter, &app_iter))
110 ASSERT_NO_PASS;
111 return false;
114 gtk_tree_model_get(
115 GTK_TREE_MODEL(g_treestore),
116 &view_iter,
117 COL_TYPE, &type,
118 COL_VIEW, &view,
119 -1);
120 if (type != entry_type_view)
122 ASSERT_NO_PASS;
123 return false;
126 *view_ptr = view;
127 *id_ptr = id;
129 return true;
132 void on_popup_menu_action_app_start(GtkWidget * menuitem, gpointer userdata)
134 uint64_t id;
135 ladish_app_supervisor_proxy_handle proxy;
136 graph_view_handle view;
138 if (!get_selected_app_id(&view, &id))
140 return;
143 log_info("start app %"PRIu64, id);
145 proxy = graph_view_get_app_supervisor(view);
146 ladish_app_supervisor_proxy_start_app(proxy, id);
149 void on_popup_menu_action_app_stop(GtkWidget * menuitem, gpointer userdata)
151 uint64_t id;
152 ladish_app_supervisor_proxy_handle proxy;
153 graph_view_handle view;
155 if (!get_selected_app_id(&view, &id))
157 return;
160 log_info("stop app %"PRIu64, id);
162 proxy = graph_view_get_app_supervisor(view);
163 ladish_app_supervisor_proxy_stop_app(proxy, id);
166 void on_popup_menu_action_app_kill(GtkWidget * menuitem, gpointer userdata)
168 uint64_t id;
169 ladish_app_supervisor_proxy_handle proxy;
170 graph_view_handle view;
172 if (!get_selected_app_id(&view, &id))
174 return;
177 log_info("kill app %"PRIu64, id);
179 proxy = graph_view_get_app_supervisor(view);
180 ladish_app_supervisor_proxy_kill_app(proxy, id);
183 void on_popup_menu_action_app_remove(GtkWidget * menuitem, gpointer userdata)
185 uint64_t id;
186 ladish_app_supervisor_proxy_handle proxy;
187 graph_view_handle view;
189 if (!get_selected_app_id(&view, &id))
191 return;
194 log_info("remove app %"PRIu64, id);
196 proxy = graph_view_get_app_supervisor(view);
197 ladish_app_supervisor_proxy_remove_app(proxy, id);
200 void popup_menu(GtkWidget * treeview, GdkEventButton * event)
202 GtkTreeSelection * selection;
203 GtkTreeIter iter;
204 GtkWidget * menu;
205 GtkWidget * menuitem;
206 gint type;
207 graph_view_handle view;
208 uint64_t id;
209 gboolean running;
210 gboolean terminal;
211 uint8_t level;
213 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(g_world_tree_widget));
214 if (!gtk_tree_selection_get_selected(selection, NULL, &iter))
216 return;
219 gtk_tree_model_get(
220 GTK_TREE_MODEL(g_treestore),
221 &iter,
222 COL_TYPE, &type,
223 COL_VIEW, &view,
224 COL_ID, &id,
225 COL_RUNNING, &running,
226 COL_TERMINAL, &terminal,
227 COL_LEVEL, &level,
228 -1);
229 if (type != entry_type_app)
231 return;
234 menu = gtk_menu_new();
236 if (running)
238 menuitem = gtk_menu_item_new_with_label("Stop");
239 g_signal_connect(menuitem, "activate", (GCallback)on_popup_menu_action_app_stop, NULL);
240 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
242 else
244 menuitem = gtk_menu_item_new_with_label("Start");
245 g_signal_connect(menuitem, "activate", (GCallback)on_popup_menu_action_app_start, NULL);
246 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
249 menuitem = gtk_menu_item_new_with_label("Remove");
250 g_signal_connect(menuitem, "activate", (GCallback)on_popup_menu_action_app_remove, NULL);
251 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
253 if (running)
255 menuitem = gtk_menu_item_new_with_label("Kill");
256 g_signal_connect(menuitem, "activate", (GCallback)on_popup_menu_action_app_kill, NULL);
257 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
260 gtk_widget_show_all(menu);
262 /* Note: event can be NULL here when called from view_onPopupMenu;
263 * gdk_event_get_time() accepts a NULL argument */
264 gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL, (event != NULL) ? event->button : 0, gdk_event_get_time((GdkEvent *)event));
267 gboolean on_button_pressed(GtkWidget * treeview, GdkEventButton * event, gpointer userdata)
269 /* single click with the right mouse button? */
270 if (event->type == GDK_BUTTON_PRESS && event->button == 3)
272 /* select row if no row is selected or only one other row is selected */
274 GtkTreeSelection *selection;
276 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(treeview));
278 /* Note: gtk_tree_selection_count_selected_rows() does not exist in gtk+-2.0, only in gtk+ >= v2.2 ! */
279 if (gtk_tree_selection_count_selected_rows(selection) <= 1)
281 GtkTreePath *path;
283 /* Get tree path for row that was clicked */
284 if (gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(treeview), (gint)event->x, (gint)event->y, &path, NULL, NULL, NULL))
286 gtk_tree_selection_unselect_all(selection);
287 gtk_tree_selection_select_path(selection, path);
288 gtk_tree_path_free(path);
293 popup_menu(treeview, event);
295 return TRUE; /* we handled this */
298 return FALSE; /* we did not handle this */
301 gboolean on_popup_menu(GtkWidget * treeview, gpointer userdata)
303 popup_menu(treeview, NULL);
304 return TRUE; /* we handled this */
307 void world_tree_init(void)
309 GtkTreeViewColumn * col;
310 GtkCellRenderer * renderer;
311 GtkTreeSelection * selection;
313 g_world_tree_widget = get_glade_widget("world_tree");
314 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(g_world_tree_widget), FALSE);
316 col = gtk_tree_view_column_new();
317 gtk_tree_view_column_set_title(col, "Name");
318 gtk_tree_view_append_column(GTK_TREE_VIEW(g_world_tree_widget), col);
319 renderer = gtk_cell_renderer_text_new();
320 gtk_tree_view_column_pack_start(col, renderer, TRUE);
321 gtk_tree_view_column_add_attribute(col, renderer, "text", COL_NAME);
323 g_treestore = gtk_tree_store_new(
324 NUM_COLS,
325 G_TYPE_INT,
326 G_TYPE_STRING,
327 G_TYPE_POINTER,
328 G_TYPE_UINT64,
329 G_TYPE_BOOLEAN,
330 G_TYPE_BOOLEAN,
331 G_TYPE_CHAR);
332 gtk_tree_view_set_model(GTK_TREE_VIEW(g_world_tree_widget), GTK_TREE_MODEL(g_treestore));
334 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(g_world_tree_widget));
335 gtk_tree_selection_set_select_function(selection, on_select, NULL, NULL);
337 g_signal_connect(g_world_tree_widget, "button-press-event", (GCallback)on_button_pressed, NULL);
338 g_signal_connect(g_world_tree_widget, "popup-menu", (GCallback)on_popup_menu, NULL);
341 void world_tree_add(graph_view_handle view, bool force_activate)
343 GtkTreeIter iter;
345 gtk_tree_store_append(g_treestore, &iter, NULL);
346 gtk_tree_store_set(g_treestore, &iter, COL_TYPE, entry_type_view, COL_VIEW, view, COL_NAME, get_view_name(view), -1);
348 /* select the first top level item */
349 if (force_activate || gtk_tree_model_iter_n_children(GTK_TREE_MODEL(g_treestore), NULL) == 1)
351 gtk_tree_selection_select_iter(gtk_tree_view_get_selection(GTK_TREE_VIEW(g_world_tree_widget)), &iter);
355 static bool find_view(graph_view_handle view, GtkTreeIter * iter_ptr)
357 gint type;
358 graph_view_handle view2;
360 if (gtk_tree_model_get_iter_first(GTK_TREE_MODEL(g_treestore), iter_ptr))
364 gtk_tree_model_get(GTK_TREE_MODEL(g_treestore), iter_ptr, COL_TYPE, &type, COL_VIEW, &view2, -1);
365 if (type == entry_type_view && view == view2)
367 return true;
370 while (gtk_tree_model_iter_next(GTK_TREE_MODEL(g_treestore), iter_ptr));
373 return false;
376 static bool find_app(graph_view_handle view, uint64_t id, GtkTreeIter * view_iter_ptr, GtkTreeIter * app_iter_ptr)
378 gint type;
379 uint64_t id2;
381 if (!find_view(view, view_iter_ptr))
383 return false;
386 if (!gtk_tree_model_iter_children(GTK_TREE_MODEL(g_treestore), app_iter_ptr, view_iter_ptr))
388 return false;
393 gtk_tree_model_get(GTK_TREE_MODEL(g_treestore), app_iter_ptr, COL_TYPE, &type, COL_ID, &id2, -1);
394 if (type == entry_type_app && id == id2)
396 return true;
399 while (gtk_tree_model_iter_next(GTK_TREE_MODEL(g_treestore), app_iter_ptr));
401 return false;
404 void world_tree_remove(graph_view_handle view)
406 GtkTreeIter iter;
408 if (find_view(view, &iter))
410 gtk_tree_store_remove(g_treestore, &iter);
414 void world_tree_activate(graph_view_handle view)
416 GtkTreeIter iter;
418 if (find_view(view, &iter))
420 gtk_tree_selection_select_iter(gtk_tree_view_get_selection(GTK_TREE_VIEW(g_world_tree_widget)), &iter);
424 void world_tree_name_changed(graph_view_handle view)
426 GtkTreeIter iter;
428 if (find_view(view, &iter))
430 gtk_tree_store_set(g_treestore, &iter, COL_NAME, get_view_name(view), -1);
434 static char * get_app_name_string(const char * app_name, bool running, bool terminal, uint8_t level)
436 char * app_name_with_status;
438 app_name_with_status = catdup(running ? "" : "(inactive) ", app_name);
439 if (app_name_with_status == NULL)
441 log_error("catdup failed for app name");
442 return NULL;
445 return app_name_with_status;
448 void world_tree_add_app(graph_view_handle view, uint64_t id, const char * app_name, bool running, bool terminal, uint8_t level)
450 GtkTreeIter iter;
451 const char * view_name;
452 GtkTreeIter child;
453 GtkTreePath * path;
454 char * app_name_with_status;
456 if (!find_view(view, &iter))
458 ASSERT_NO_PASS;
459 return;
462 path = gtk_tree_model_get_path(GTK_TREE_MODEL(g_treestore), &iter);
464 gtk_tree_model_get(GTK_TREE_MODEL(g_treestore), &iter, COL_NAME, &view_name, -1);
466 log_info("adding app '%s' to '%s'", app_name, view_name);
468 app_name_with_status = get_app_name_string(app_name, running, terminal, level);
469 if (app_name_with_status == NULL)
471 goto free_path;
474 gtk_tree_store_append(g_treestore, &child, &iter);
475 gtk_tree_store_set(
476 g_treestore,
477 &child,
478 COL_TYPE, entry_type_app,
479 COL_NAME, app_name_with_status,
480 COL_ID, id,
481 COL_RUNNING, running,
482 COL_TERMINAL, terminal,
483 COL_LEVEL, level,
484 -1);
485 gtk_tree_view_expand_row(GTK_TREE_VIEW(g_world_tree_widget), path, false);
487 free(app_name_with_status);
488 free_path:
489 gtk_tree_path_free(path);
492 void world_tree_app_state_changed(graph_view_handle view, uint64_t id, const char * app_name, bool running, bool terminal, uint8_t level)
494 GtkTreeIter view_iter;
495 GtkTreeIter app_iter;
496 const char * view_name;
497 GtkTreePath * path;
498 char * app_name_with_status;
500 if (!find_app(view, id, &view_iter, &app_iter))
502 log_error("removed app not found");
503 return;
506 path = gtk_tree_model_get_path(GTK_TREE_MODEL(g_treestore), &view_iter);
508 gtk_tree_model_get(GTK_TREE_MODEL(g_treestore), &view_iter, COL_NAME, &view_name, -1);
510 log_info("changing app state '%s':'%s'", view_name, app_name);
512 app_name_with_status = get_app_name_string(app_name, running, terminal, level);
513 if (app_name_with_status == NULL)
515 goto free_path;
518 gtk_tree_view_expand_row(GTK_TREE_VIEW(g_world_tree_widget), path, false);
519 gtk_tree_store_set(
520 g_treestore,
521 &app_iter,
522 COL_NAME, app_name_with_status,
523 COL_RUNNING, running,
524 COL_TERMINAL, terminal,
525 COL_LEVEL, level,
526 -1);
528 free(app_name_with_status);
529 free_path:
530 gtk_tree_path_free(path);
533 void world_tree_remove_app(graph_view_handle view, uint64_t id)
535 GtkTreeIter view_iter;
536 GtkTreeIter app_iter;
537 const char * view_name;
538 const char * app_name;
539 GtkTreePath * path;
541 if (!find_app(view, id, &view_iter, &app_iter))
543 log_error("removed app not found");
544 return;
547 path = gtk_tree_model_get_path(GTK_TREE_MODEL(g_treestore), &view_iter);
549 gtk_tree_model_get(GTK_TREE_MODEL(g_treestore), &view_iter, COL_NAME, &view_name, -1);
550 gtk_tree_model_get(GTK_TREE_MODEL(g_treestore), &app_iter, COL_NAME, &app_name, -1);
552 log_info("removing app '%s' from '%s'", app_name, view_name);
554 gtk_tree_view_expand_row(GTK_TREE_VIEW(g_world_tree_widget), path, false);
555 gtk_tree_store_remove(g_treestore, &app_iter);
557 gtk_tree_path_free(path);