1 /* -*- Mode: C ; c-basic-offset: 2 -*- */
3 * LADI Session Handler (ladish)
5 * Copyright (C) 2008, 2009, 2010 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.
28 #include "world_tree.h"
29 #include "gtk_builder.h"
30 #include "../common/catdup.h"
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
;
61 if (!gtk_tree_model_iter_parent(GTK_TREE_MODEL(g_treestore
), &view_iter
, app_iter_ptr
))
68 GTK_TREE_MODEL(g_treestore
),
73 if (type
!= entry_type_view
)
85 GtkTreeSelection
* selection
,
88 gboolean path_currently_selected
,
92 graph_view_handle view
;
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);
102 if (!get_app_view(&iter
, &view
))
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
)
120 bool get_selected_app_id(graph_view_handle
* view_ptr
, uint64_t * id_ptr
)
122 GtkTreeSelection
* selection
;
123 GtkTreeIter app_iter
;
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
))
135 GTK_TREE_MODEL(g_treestore
),
140 if (type
!= entry_type_app
)
145 if (!get_app_view(&app_iter
, &view
))
157 void on_popup_menu_action_app_start(GtkWidget
* menuitem
, gpointer userdata
)
160 ladish_app_supervisor_proxy_handle proxy
;
161 graph_view_handle view
;
163 if (!get_selected_app_id(&view
, &id
))
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
* menuitem
, gpointer userdata
)
177 ladish_app_supervisor_proxy_handle proxy
;
178 graph_view_handle view
;
180 if (!get_selected_app_id(&view
, &id
))
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
* menuitem
, gpointer userdata
)
194 ladish_app_supervisor_proxy_handle proxy
;
195 graph_view_handle view
;
197 if (!get_selected_app_id(&view
, &id
))
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
* menuitem
, gpointer userdata
)
211 ladish_app_supervisor_proxy_handle proxy
;
212 graph_view_handle view
;
214 if (!get_selected_app_id(&view
, &id
))
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
* menuitem
, gpointer userdata
)
228 ladish_app_supervisor_proxy_handle proxy
;
229 graph_view_handle view
;
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
* level2_button
= GTK_TOGGLE_BUTTON(get_gtk_builder_widget("app_level2"));
242 GtkToggleButton
* level3_button
= GTK_TOGGLE_BUTTON(get_gtk_builder_widget("app_level3"));
244 if (!get_selected_app_id(&view
, &id
))
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"));
259 log_info("'%s':'%s' %s level %"PRIu8
, 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
);
273 gtk_toggle_button_set_active(level0_button
, TRUE
);
276 gtk_toggle_button_set_active(level1_button
, TRUE
);
279 gtk_toggle_button_set_active(level2_button
, TRUE
);
282 gtk_toggle_button_set_active(level3_button
, TRUE
);
285 log_error("unknown level");
287 gtk_toggle_button_set_active(level0_button
, TRUE
);
293 gtk_window_set_focus(GTK_WINDOW(g_app_dialog
), running
? GTK_WIDGET(name_entry
) : GTK_WIDGET(command_entry
));
294 gtk_window_set_title(GTK_WINDOW(g_app_dialog
), _("App properties"));
296 gtk_widget_show(g_app_dialog
);
298 result
= gtk_dialog_run(GTK_DIALOG(g_app_dialog
));
301 if (gtk_toggle_button_get_active(level0_button
))
305 else if (gtk_toggle_button_get_active(level1_button
))
309 else if (gtk_toggle_button_get_active(level2_button
))
313 else if (gtk_toggle_button_get_active(level3_button
))
319 log_error("unknown level");
324 log_info("'%s':'%s' %s level %"PRIu8
, gtk_entry_get_text(name_entry
), gtk_entry_get_text(command_entry
), gtk_toggle_button_get_active(terminal_button
) ? "terminal" : "shell", level
);
325 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
))
327 error_message_box(_("Cannot set app properties."));
331 gtk_widget_hide(g_app_dialog
);
334 void popup_menu(GtkWidget
* treeview
, GdkEventButton
* event
)
336 GtkTreeSelection
* selection
;
339 GtkWidget
* menuitem
;
341 graph_view_handle view
;
347 selection
= gtk_tree_view_get_selection(GTK_TREE_VIEW(g_world_tree_widget
));
348 if (!gtk_tree_selection_get_selected(selection
, NULL
, &iter
))
354 GTK_TREE_MODEL(g_treestore
),
359 COL_RUNNING
, &running
,
360 COL_TERMINAL
, &terminal
,
364 menu
= gtk_menu_new();
366 if (type
== entry_type_app
)
370 menuitem
= gtk_menu_item_new_with_label(_("Stop"));
371 g_signal_connect(menuitem
, "activate", (GCallback
)on_popup_menu_action_app_stop
, NULL
);
372 gtk_menu_shell_append(GTK_MENU_SHELL(menu
), menuitem
);
374 menuitem
= gtk_menu_item_new_with_label(_("Kill"));
375 g_signal_connect(menuitem
, "activate", (GCallback
)on_popup_menu_action_app_kill
, NULL
);
376 gtk_menu_shell_append(GTK_MENU_SHELL(menu
), menuitem
);
380 menuitem
= gtk_menu_item_new_with_label(_("Start"));
381 g_signal_connect(menuitem
, "activate", (GCallback
)on_popup_menu_action_app_start
, NULL
);
382 gtk_menu_shell_append(GTK_MENU_SHELL(menu
), menuitem
);
385 menuitem
= gtk_menu_item_new_with_label(_("Properties"));
386 g_signal_connect(menuitem
, "activate", (GCallback
)on_popup_menu_action_app_properties
, NULL
);
387 gtk_menu_shell_append(GTK_MENU_SHELL(menu
), menuitem
);
389 menuitem
= gtk_separator_menu_item_new(); /* separator */
390 gtk_menu_shell_append(GTK_MENU_SHELL(menu
), menuitem
);
392 menuitem
= gtk_menu_item_new_with_label(_("Remove"));
393 g_signal_connect(menuitem
, "activate", (GCallback
)on_popup_menu_action_app_remove
, NULL
);
394 gtk_menu_shell_append(GTK_MENU_SHELL(menu
), menuitem
);
396 else if (type
== entry_type_view
)
398 fill_view_popup_menu(GTK_MENU(menu
), view
);
403 g_object_unref(menu
);
407 gtk_widget_show_all(menu
);
409 /* Note: event can be NULL here when called from view_onPopupMenu;
410 * gdk_event_get_time() accepts a NULL argument */
411 gtk_menu_popup(GTK_MENU(menu
), NULL
, NULL
, NULL
, NULL
, (event
!= NULL
) ? event
->button
: 0, gdk_event_get_time((GdkEvent
*)event
));
414 gboolean
on_button_pressed(GtkWidget
* treeview
, GdkEventButton
* event
, gpointer userdata
)
416 /* single click with the right mouse button? */
417 if (event
->type
== GDK_BUTTON_PRESS
&& event
->button
== 3)
419 /* select row if no row is selected or only one other row is selected */
421 GtkTreeSelection
*selection
;
423 selection
= gtk_tree_view_get_selection(GTK_TREE_VIEW(treeview
));
425 /* Note: gtk_tree_selection_count_selected_rows() does not exist in gtk+-2.0, only in gtk+ >= v2.2 ! */
426 if (gtk_tree_selection_count_selected_rows(selection
) <= 1)
430 /* Get tree path for row that was clicked */
431 if (gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(treeview
), (gint
)event
->x
, (gint
)event
->y
, &path
, NULL
, NULL
, NULL
))
433 gtk_tree_selection_unselect_all(selection
);
434 gtk_tree_selection_select_path(selection
, path
);
435 gtk_tree_path_free(path
);
440 popup_menu(treeview
, event
);
442 return TRUE
; /* we handled this */
445 return FALSE
; /* we did not handle this */
448 gboolean
on_popup_menu(GtkWidget
* treeview
, gpointer userdata
)
450 popup_menu(treeview
, NULL
);
451 return TRUE
; /* we handled this */
454 static void on_row_activated(GtkTreeView
* treeview
, GtkTreePath
* path
, GtkTreeViewColumn
* col
, gpointer userdata
)
458 graph_view_handle view
;
461 ladish_app_supervisor_proxy_handle proxy
;
463 if (!gtk_tree_model_get_iter(GTK_TREE_MODEL(g_treestore
), &iter
, path
))
468 gtk_tree_model_get(GTK_TREE_MODEL(g_treestore
), &iter
, COL_TYPE
, &type
, COL_ID
, &id
, COL_RUNNING
, &running
, -1);
469 if (type
== entry_type_app
)
471 log_info("%s app %"PRIu64
, running
? "stop" : "start", id
);
473 if (!get_app_view(&iter
, &view
))
479 proxy
= graph_view_get_app_supervisor(view
);
480 (running
? ladish_app_supervisor_proxy_stop_app
: ladish_app_supervisor_proxy_start_app
)(proxy
, id
);
484 void world_tree_init(void)
486 GtkTreeViewColumn
* col
;
487 GtkCellRenderer
* renderer
;
488 GtkTreeSelection
* selection
;
490 g_world_tree_widget
= get_gtk_builder_widget("world_tree");
491 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(g_world_tree_widget
), FALSE
);
493 col
= gtk_tree_view_column_new();
494 gtk_tree_view_column_set_title(col
, _("Name"));
495 gtk_tree_view_append_column(GTK_TREE_VIEW(g_world_tree_widget
), col
);
496 renderer
= gtk_cell_renderer_text_new();
497 gtk_tree_view_column_pack_start(col
, renderer
, TRUE
);
498 gtk_tree_view_column_add_attribute(col
, renderer
, "text", COL_NAME
);
500 g_treestore
= gtk_tree_store_new(
509 gtk_tree_view_set_model(GTK_TREE_VIEW(g_world_tree_widget
), GTK_TREE_MODEL(g_treestore
));
511 selection
= gtk_tree_view_get_selection(GTK_TREE_VIEW(g_world_tree_widget
));
512 gtk_tree_selection_set_select_function(selection
, on_select
, NULL
, NULL
);
514 g_signal_connect(g_world_tree_widget
, "button-press-event", (GCallback
)on_button_pressed
, NULL
);
515 g_signal_connect(g_world_tree_widget
, "popup-menu", (GCallback
)on_popup_menu
, NULL
);
516 g_signal_connect(g_world_tree_widget
, "row-activated", (GCallback
)on_row_activated
, NULL
);
519 void world_tree_add(graph_view_handle view
, bool force_activate
)
523 gtk_tree_store_append(g_treestore
, &iter
, NULL
);
524 gtk_tree_store_set(g_treestore
, &iter
, COL_TYPE
, entry_type_view
, COL_VIEW
, view
, COL_NAME
, get_view_name(view
), -1);
526 /* select the first top level item */
527 if (force_activate
|| gtk_tree_model_iter_n_children(GTK_TREE_MODEL(g_treestore
), NULL
) == 1)
529 gtk_tree_selection_select_iter(gtk_tree_view_get_selection(GTK_TREE_VIEW(g_world_tree_widget
)), &iter
);
533 graph_view_handle
world_tree_find_by_opath(const char * opath
)
536 graph_view_handle view
;
539 if (gtk_tree_model_get_iter_first(GTK_TREE_MODEL(g_treestore
), &iter
))
543 gtk_tree_model_get(GTK_TREE_MODEL(g_treestore
), &iter
, COL_TYPE
, &type
, COL_VIEW
, &view
, -1);
544 if (type
== entry_type_view
)
546 if (strcmp(get_view_opath(view
), opath
) == 0)
552 while (gtk_tree_model_iter_next(GTK_TREE_MODEL(g_treestore
), &iter
));
558 static bool find_view(graph_view_handle view
, GtkTreeIter
* iter_ptr
)
561 graph_view_handle view2
;
563 if (gtk_tree_model_get_iter_first(GTK_TREE_MODEL(g_treestore
), iter_ptr
))
567 gtk_tree_model_get(GTK_TREE_MODEL(g_treestore
), iter_ptr
, COL_TYPE
, &type
, COL_VIEW
, &view2
, -1);
568 if (type
== entry_type_view
&& view
== view2
)
573 while (gtk_tree_model_iter_next(GTK_TREE_MODEL(g_treestore
), iter_ptr
));
579 static bool find_app(graph_view_handle view
, uint64_t id
, GtkTreeIter
* view_iter_ptr
, GtkTreeIter
* app_iter_ptr
)
584 if (!find_view(view
, view_iter_ptr
))
589 if (!gtk_tree_model_iter_children(GTK_TREE_MODEL(g_treestore
), app_iter_ptr
, view_iter_ptr
))
596 gtk_tree_model_get(GTK_TREE_MODEL(g_treestore
), app_iter_ptr
, COL_TYPE
, &type
, COL_ID
, &id2
, -1);
597 if (type
== entry_type_app
&& id
== id2
)
602 while (gtk_tree_model_iter_next(GTK_TREE_MODEL(g_treestore
), app_iter_ptr
));
607 void world_tree_remove(graph_view_handle view
)
611 if (find_view(view
, &iter
))
613 gtk_tree_store_remove(g_treestore
, &iter
);
617 void world_tree_activate(graph_view_handle view
)
621 if (find_view(view
, &iter
))
623 gtk_tree_selection_select_iter(gtk_tree_view_get_selection(GTK_TREE_VIEW(g_world_tree_widget
)), &iter
);
627 void world_tree_name_changed(graph_view_handle view
)
631 if (find_view(view
, &iter
))
633 gtk_tree_store_set(g_treestore
, &iter
, COL_NAME
, get_view_name(view
), -1);
637 static char * get_app_name_string(const char * app_name
, bool running
, bool terminal
, uint8_t level
)
639 char * app_name_with_status
;
640 const char * level_string
;
645 level_string
= "[L0]";
648 level_string
= "[L1]";
651 level_string
= "[L?]";
654 app_name_with_status
= catdup3(level_string
, running
? " " : _(" (inactive) "), app_name
);
655 if (app_name_with_status
== NULL
)
657 log_error("catdup failed for app name");
661 return app_name_with_status
;
664 void world_tree_add_app(graph_view_handle view
, uint64_t id
, const char * app_name
, bool running
, bool terminal
, uint8_t level
)
667 const char * view_name
;
670 char * app_name_with_status
;
672 if (!find_view(view
, &iter
))
678 path
= gtk_tree_model_get_path(GTK_TREE_MODEL(g_treestore
), &iter
);
680 gtk_tree_model_get(GTK_TREE_MODEL(g_treestore
), &iter
, COL_NAME
, &view_name
, -1);
682 log_info("adding app '%s' to '%s'", app_name
, view_name
);
684 app_name_with_status
= get_app_name_string(app_name
, running
, terminal
, level
);
685 if (app_name_with_status
== NULL
)
690 gtk_tree_store_append(g_treestore
, &child
, &iter
);
694 COL_TYPE
, entry_type_app
,
695 COL_NAME
, app_name_with_status
,
697 COL_RUNNING
, running
,
698 COL_TERMINAL
, terminal
,
701 gtk_tree_view_expand_row(GTK_TREE_VIEW(g_world_tree_widget
), path
, false);
703 free(app_name_with_status
);
705 gtk_tree_path_free(path
);
708 void world_tree_app_state_changed(graph_view_handle view
, uint64_t id
, const char * app_name
, bool running
, bool terminal
, uint8_t level
)
710 GtkTreeIter view_iter
;
711 GtkTreeIter app_iter
;
712 const char * view_name
;
714 char * app_name_with_status
;
716 if (!find_app(view
, id
, &view_iter
, &app_iter
))
718 log_error("removed app not found");
722 path
= gtk_tree_model_get_path(GTK_TREE_MODEL(g_treestore
), &view_iter
);
724 gtk_tree_model_get(GTK_TREE_MODEL(g_treestore
), &view_iter
, COL_NAME
, &view_name
, -1);
726 log_info("changing app state '%s':'%s'", view_name
, app_name
);
728 app_name_with_status
= get_app_name_string(app_name
, running
, terminal
, level
);
729 if (app_name_with_status
== NULL
)
734 gtk_tree_view_expand_row(GTK_TREE_VIEW(g_world_tree_widget
), path
, false);
738 COL_NAME
, app_name_with_status
,
739 COL_RUNNING
, running
,
740 COL_TERMINAL
, terminal
,
744 free(app_name_with_status
);
746 gtk_tree_path_free(path
);
749 void world_tree_remove_app(graph_view_handle view
, uint64_t id
)
751 GtkTreeIter view_iter
;
752 GtkTreeIter app_iter
;
753 const char * view_name
;
754 const char * app_name
;
757 if (!find_app(view
, id
, &view_iter
, &app_iter
))
759 log_error("removed app not found");
763 path
= gtk_tree_model_get_path(GTK_TREE_MODEL(g_treestore
), &view_iter
);
765 gtk_tree_model_get(GTK_TREE_MODEL(g_treestore
), &view_iter
, COL_NAME
, &view_name
, -1);
766 gtk_tree_model_get(GTK_TREE_MODEL(g_treestore
), &app_iter
, COL_NAME
, &app_name
, -1);
768 log_info("removing app '%s' from '%s'", app_name
, view_name
);
770 gtk_tree_view_expand_row(GTK_TREE_VIEW(g_world_tree_widget
), path
, false);
771 gtk_tree_store_remove(g_treestore
, &app_iter
);
773 gtk_tree_path_free(path
);
776 void world_tree_destroy_room_views(void)
779 graph_view_handle view
;
783 if (!gtk_tree_model_get_iter_first(GTK_TREE_MODEL(g_treestore
), &iter
))
789 gtk_tree_model_get(GTK_TREE_MODEL(g_treestore
), &iter
, COL_TYPE
, &type
, COL_VIEW
, &view
, -1);
790 if (type
== entry_type_view
&& is_room_view(view
))
792 //log_info("removing view for room %s", get_view_opath(view));
793 valid
= gtk_tree_store_remove(g_treestore
, &iter
);
799 /* no more entries */
806 if (gtk_tree_model_iter_next(GTK_TREE_MODEL(g_treestore
), &iter
))