630 lines
16 KiB
C
630 lines
16 KiB
C
/*
|
|
* Copyright (C) 2008 Martin Willi
|
|
* Hochschule fuer Technik Rapperswil
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify it
|
|
* under the terms of the GNU General Public License as published by the
|
|
* Free Software Foundation; either version 2 of the License, or (at your
|
|
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
|
|
*
|
|
* This program is distributed in the hope that it will be useful, but
|
|
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
* for more details.
|
|
*/
|
|
|
|
#include "dumm.h"
|
|
|
|
#include <collections/linked_list.h>
|
|
|
|
#include <sys/types.h>
|
|
#include <unistd.h>
|
|
#include <sched.h>
|
|
|
|
#include <glib.h>
|
|
#include <gtk/gtk.h>
|
|
#include <vte/vte.h>
|
|
#include <vte/reaper.h>
|
|
|
|
/**
|
|
* notebook page with vte and guest
|
|
*/
|
|
typedef struct {
|
|
gint num;
|
|
GtkWidget *vte;
|
|
guest_t *guest;
|
|
} page_t;
|
|
|
|
/**
|
|
* Main window
|
|
*/
|
|
GtkWidget *window;
|
|
|
|
/**
|
|
* notebook with guests, vtes
|
|
*/
|
|
GtkWidget *notebook;
|
|
|
|
/**
|
|
* dumm context
|
|
*/
|
|
dumm_t *dumm;
|
|
|
|
/**
|
|
* pages in notebook, page_t
|
|
*/
|
|
linked_list_t *pages;
|
|
|
|
/**
|
|
* handle guest termination, SIGCHILD
|
|
*/
|
|
static void child_exited(VteReaper *vtereaper, gint pid, gint status)
|
|
{
|
|
enumerator_t *enumerator;
|
|
page_t *page;
|
|
|
|
enumerator = pages->create_enumerator(pages);
|
|
while (enumerator->enumerate(enumerator, (void**)&page))
|
|
{
|
|
if (page->guest->get_pid(page->guest) == pid)
|
|
{
|
|
page->guest->sigchild(page->guest);
|
|
vte_terminal_feed(VTE_TERMINAL(page->vte),
|
|
"\n\r--- guest terminated ---\n\r", -1);
|
|
break;
|
|
}
|
|
}
|
|
enumerator->destroy(enumerator);
|
|
}
|
|
|
|
static page_t* get_page(int num)
|
|
{
|
|
enumerator_t *enumerator;
|
|
page_t *page, *found = NULL;
|
|
|
|
enumerator = pages->create_enumerator(pages);
|
|
while (enumerator->enumerate(enumerator, (void**)&page))
|
|
{
|
|
if (page->num == num)
|
|
{
|
|
found = page;
|
|
break;
|
|
}
|
|
}
|
|
enumerator->destroy(enumerator);
|
|
return found;
|
|
}
|
|
|
|
/**
|
|
* Guest invocation callback
|
|
*/
|
|
static pid_t invoke(void *vte, guest_t *guest,
|
|
char *args[], int argc)
|
|
{
|
|
GPid pid;
|
|
|
|
if (vte_terminal_fork_command_full(VTE_TERMINAL(vte),
|
|
VTE_PTY_NO_LASTLOG | VTE_PTY_NO_UTMP | VTE_PTY_NO_WTMP,
|
|
NULL, args, NULL,
|
|
G_SPAWN_CHILD_INHERITS_STDIN | G_SPAWN_SEARCH_PATH,
|
|
NULL, NULL, &pid, NULL))
|
|
{
|
|
return pid;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
void idle(void)
|
|
{
|
|
gtk_main_iteration_do(FALSE);
|
|
sched_yield();
|
|
}
|
|
|
|
static void start_guest()
|
|
{
|
|
page_t *page;
|
|
|
|
page = get_page(gtk_notebook_get_current_page(GTK_NOTEBOOK(notebook)));
|
|
if (page && page->guest->get_state(page->guest) == GUEST_STOPPED)
|
|
{
|
|
vte_terminal_feed(VTE_TERMINAL(page->vte),
|
|
"--- starting guest ---\n\r", -1);
|
|
page->guest->start(page->guest, invoke, VTE_TERMINAL(page->vte), idle);
|
|
}
|
|
}
|
|
|
|
static void start_all_guests()
|
|
{
|
|
enumerator_t *enumerator;
|
|
page_t *page;
|
|
|
|
enumerator = pages->create_enumerator(pages);
|
|
while (enumerator->enumerate(enumerator, (void**)&page))
|
|
{
|
|
if (page->guest->get_state(page->guest) == GUEST_STOPPED)
|
|
{
|
|
vte_terminal_feed(VTE_TERMINAL(page->vte),
|
|
"--- starting all guests ---\n\r", -1);
|
|
page->guest->start(page->guest, invoke,
|
|
VTE_TERMINAL(page->vte), idle);
|
|
}
|
|
}
|
|
enumerator->destroy(enumerator);
|
|
}
|
|
|
|
static void stop_guest()
|
|
{
|
|
page_t *page;
|
|
|
|
page = get_page(gtk_notebook_get_current_page(GTK_NOTEBOOK(notebook)));
|
|
if (page && page->guest->get_state(page->guest) == GUEST_RUNNING)
|
|
{
|
|
page->guest->stop(page->guest, idle);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* quit signal handler
|
|
*/
|
|
static void quit()
|
|
{
|
|
enumerator_t *enumerator;
|
|
page_t *page;
|
|
|
|
dumm->load_template(dumm, NULL);
|
|
|
|
enumerator = pages->create_enumerator(pages);
|
|
while (enumerator->enumerate(enumerator, &page))
|
|
{
|
|
if (page->guest->get_state(page->guest) != GUEST_STOPPED)
|
|
{
|
|
page->guest->stop(page->guest, idle);
|
|
}
|
|
}
|
|
enumerator->destroy(enumerator);
|
|
gtk_main_quit();
|
|
}
|
|
|
|
static void error_dialog(char *msg)
|
|
{
|
|
GtkWidget *error;
|
|
|
|
error = gtk_message_dialog_new(GTK_WINDOW(window),
|
|
GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_ERROR,
|
|
GTK_BUTTONS_CLOSE, msg);
|
|
gtk_dialog_run(GTK_DIALOG(error));
|
|
gtk_widget_destroy(error);
|
|
}
|
|
|
|
static void create_switch()
|
|
{
|
|
GtkWidget *dialog, *table, *label, *name;
|
|
bridge_t *bridge;
|
|
|
|
dialog = gtk_dialog_new_with_buttons("Create new switch", GTK_WINDOW(window),
|
|
GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
|
|
GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,
|
|
GTK_STOCK_NEW, GTK_RESPONSE_ACCEPT, NULL);
|
|
|
|
table = gtk_table_new(1, 2, TRUE);
|
|
gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), table);
|
|
|
|
label = gtk_label_new("Switch name");
|
|
gtk_table_attach(GTK_TABLE(table), label, 0, 1, 0, 1, 0, 0, 0, 0);
|
|
gtk_widget_show(label);
|
|
|
|
name = gtk_entry_new();
|
|
gtk_table_attach(GTK_TABLE(table), name, 1, 2, 0, 1,
|
|
GTK_FILL | GTK_EXPAND | GTK_SHRINK, 0, 0, 0);
|
|
gtk_widget_show(name);
|
|
|
|
gtk_widget_show(table);
|
|
|
|
while (TRUE)
|
|
{
|
|
switch (gtk_dialog_run(GTK_DIALOG(dialog)))
|
|
{
|
|
case GTK_RESPONSE_ACCEPT:
|
|
{
|
|
if (streq(gtk_entry_get_text(GTK_ENTRY(name)), ""))
|
|
{
|
|
continue;
|
|
}
|
|
bridge = dumm->create_bridge(dumm,
|
|
(char*)gtk_entry_get_text(GTK_ENTRY(name)));
|
|
if (!bridge)
|
|
{
|
|
error_dialog("creating bridge failed!");
|
|
continue;
|
|
}
|
|
break;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
gtk_widget_destroy(dialog);
|
|
}
|
|
|
|
static void delete_switch()
|
|
{
|
|
|
|
}
|
|
|
|
static void connect_guest()
|
|
{
|
|
page_t *page;
|
|
GtkWidget *dialog, *table, *label, *name, *box;
|
|
bridge_t *bridge;
|
|
iface_t *iface;
|
|
enumerator_t *enumerator;
|
|
|
|
page = get_page(gtk_notebook_get_current_page(GTK_NOTEBOOK(notebook)));
|
|
if (!page || page->guest->get_state(page->guest) != GUEST_RUNNING)
|
|
{
|
|
return;
|
|
}
|
|
|
|
dialog = gtk_dialog_new_with_buttons("Connect guest", GTK_WINDOW(window),
|
|
GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
|
|
GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,
|
|
GTK_STOCK_NEW, GTK_RESPONSE_ACCEPT, NULL);
|
|
|
|
table = gtk_table_new(2, 2, TRUE);
|
|
gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), table);
|
|
|
|
label = gtk_label_new("Interface name");
|
|
gtk_table_attach(GTK_TABLE(table), label, 0, 1, 0, 1, 0, 0, 0, 0);
|
|
gtk_widget_show(label);
|
|
|
|
name = gtk_entry_new();
|
|
gtk_table_attach(GTK_TABLE(table), name, 1, 2, 0, 1,
|
|
GTK_FILL | GTK_EXPAND | GTK_SHRINK, 0, 0, 0);
|
|
gtk_widget_show(name);
|
|
|
|
label = gtk_label_new("Connected switch");
|
|
gtk_table_attach(GTK_TABLE(table), label, 0, 1, 1, 2, 0, 0, 0, 0);
|
|
gtk_widget_show(label);
|
|
|
|
box = gtk_combo_box_new_text();
|
|
gtk_table_attach(GTK_TABLE(table), box, 1, 2, 1, 2,
|
|
GTK_FILL | GTK_EXPAND | GTK_SHRINK, 0, 0, 0);
|
|
enumerator = dumm->create_bridge_enumerator(dumm);
|
|
while (enumerator->enumerate(enumerator, &bridge))
|
|
{
|
|
gtk_combo_box_append_text(GTK_COMBO_BOX(box), bridge->get_name(bridge));
|
|
}
|
|
enumerator->destroy(enumerator);
|
|
gtk_widget_show(box);
|
|
|
|
gtk_widget_show(table);
|
|
|
|
while (TRUE)
|
|
{
|
|
switch (gtk_dialog_run(GTK_DIALOG(dialog)))
|
|
{
|
|
case GTK_RESPONSE_ACCEPT:
|
|
{
|
|
if (streq(gtk_entry_get_text(GTK_ENTRY(name)), ""))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
iface = page->guest->create_iface(page->guest,
|
|
(char*)gtk_entry_get_text(GTK_ENTRY(name)));
|
|
if (!iface)
|
|
{
|
|
error_dialog("creating interface failed!");
|
|
continue;
|
|
}
|
|
enumerator = dumm->create_bridge_enumerator(dumm);
|
|
while (enumerator->enumerate(enumerator, &bridge))
|
|
{
|
|
if (!bridge->connect_iface(bridge, iface))
|
|
{
|
|
error_dialog("connecting interface failed!");
|
|
}
|
|
break;
|
|
}
|
|
enumerator->destroy(enumerator);
|
|
break;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
gtk_widget_destroy(dialog);
|
|
}
|
|
|
|
static void disconnect_guest()
|
|
{
|
|
|
|
}
|
|
|
|
static void delete_guest()
|
|
{
|
|
page_t *page;
|
|
|
|
page = get_page(gtk_notebook_get_current_page(GTK_NOTEBOOK(notebook)));
|
|
if (page)
|
|
{
|
|
page->guest->stop(page->guest, idle);
|
|
dumm->delete_guest(dumm, page->guest);
|
|
gtk_notebook_remove_page(GTK_NOTEBOOK(notebook), page->num);
|
|
pages->remove(pages, page, NULL);
|
|
g_free(page);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* create a new page for a guest
|
|
*/
|
|
static page_t* create_page(guest_t *guest)
|
|
{
|
|
GtkWidget *label;
|
|
page_t *page;
|
|
|
|
page = g_new(page_t, 1);
|
|
page->guest = guest;
|
|
page->vte = vte_terminal_new();
|
|
label = gtk_label_new(guest->get_name(guest));
|
|
page->num = gtk_notebook_append_page(GTK_NOTEBOOK(notebook),
|
|
page->vte, label);
|
|
gtk_widget_show(page->vte);
|
|
pages->insert_last(pages, page);
|
|
return page;
|
|
}
|
|
|
|
/**
|
|
* create a new guest
|
|
*/
|
|
static void create_guest()
|
|
{
|
|
guest_t *guest;
|
|
GtkWidget *dialog, *table, *label, *name, *kernel, *master, *args;
|
|
|
|
dialog = gtk_dialog_new_with_buttons("Create new guest", GTK_WINDOW(window),
|
|
GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
|
|
GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,
|
|
GTK_STOCK_NEW, GTK_RESPONSE_ACCEPT, NULL);
|
|
|
|
table = gtk_table_new(4, 2, TRUE);
|
|
gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), table);
|
|
|
|
label = gtk_label_new("Guest name");
|
|
gtk_table_attach(GTK_TABLE(table), label, 0, 1, 0, 1, 0, 0, 0, 0);
|
|
gtk_widget_show(label);
|
|
|
|
label = gtk_label_new("UML kernel");
|
|
gtk_table_attach(GTK_TABLE(table), label, 0, 1, 1, 2, 0, 0, 0, 0);
|
|
gtk_widget_show(label);
|
|
|
|
label = gtk_label_new("Master filesystem");
|
|
gtk_table_attach(GTK_TABLE(table), label, 0, 1, 2, 3, 0, 0, 0, 0);
|
|
gtk_widget_show(label);
|
|
|
|
label = gtk_label_new("Kernel arguments");
|
|
gtk_table_attach(GTK_TABLE(table), label, 0, 1, 3, 4, 0, 0, 0, 0);
|
|
gtk_widget_show(label);
|
|
|
|
name = gtk_entry_new();
|
|
gtk_table_attach(GTK_TABLE(table), name, 1, 2, 0, 1,
|
|
GTK_FILL | GTK_EXPAND | GTK_SHRINK, 0, 0, 0);
|
|
gtk_widget_show(name);
|
|
|
|
kernel = gtk_file_chooser_button_new("Select UML kernel image",
|
|
GTK_FILE_CHOOSER_ACTION_OPEN);
|
|
gtk_table_attach(GTK_TABLE(table), kernel, 1, 2, 1, 2,
|
|
GTK_FILL | GTK_EXPAND | GTK_SHRINK, 0, 0, 0);
|
|
gtk_widget_show(kernel);
|
|
|
|
master = gtk_file_chooser_button_new("Select master filesystem",
|
|
GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER);
|
|
gtk_table_attach(GTK_TABLE(table), master, 1, 2, 2, 3,
|
|
GTK_FILL | GTK_EXPAND | GTK_SHRINK, 0, 0, 0);
|
|
gtk_widget_show(master);
|
|
|
|
args = gtk_entry_new();
|
|
gtk_table_attach(GTK_TABLE(table), args, 1, 2, 3, 4,
|
|
GTK_FILL | GTK_EXPAND | GTK_SHRINK, 0, 0, 0);
|
|
gtk_widget_show(args);
|
|
|
|
gtk_widget_show(table);
|
|
|
|
while (TRUE)
|
|
{
|
|
switch (gtk_dialog_run(GTK_DIALOG(dialog)))
|
|
{
|
|
case GTK_RESPONSE_ACCEPT:
|
|
{
|
|
char *sname, *skernel, *smaster, *sargs;
|
|
page_t *page;
|
|
|
|
sname = (char*)gtk_entry_get_text(GTK_ENTRY(name));
|
|
skernel = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(kernel));
|
|
smaster = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(master));
|
|
sargs = (char*)gtk_entry_get_text(GTK_ENTRY(args));
|
|
|
|
if (!sname[0] || !skernel || !smaster)
|
|
{
|
|
continue;
|
|
}
|
|
guest = dumm->create_guest(dumm, sname, skernel, smaster, sargs);
|
|
if (!guest)
|
|
{
|
|
error_dialog("creating guest failed!");
|
|
continue;
|
|
}
|
|
page = create_page(guest);
|
|
gtk_notebook_set_current_page(GTK_NOTEBOOK(notebook), page->num);
|
|
break;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
gtk_widget_destroy(dialog);
|
|
}
|
|
|
|
/**
|
|
* main routine, parses args and reads from console
|
|
*/
|
|
int main(int argc, char *argv[])
|
|
{
|
|
GtkWidget *menubar, *menu, *menuitem, *vbox;
|
|
GtkWidget *dummMenu, *guestMenu, *switchMenu;
|
|
enumerator_t *enumerator;
|
|
guest_t *guest;
|
|
|
|
library_init(NULL, "dumm");
|
|
gtk_init(&argc, &argv);
|
|
|
|
pages = linked_list_create();
|
|
dumm = dumm_create(NULL);
|
|
|
|
/* setup window */
|
|
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
|
|
g_signal_connect(G_OBJECT(window), "destroy", G_CALLBACK(quit), NULL);
|
|
gtk_window_set_title(GTK_WINDOW (window), "Dumm");
|
|
gtk_window_set_default_size(GTK_WINDOW (window), 1000, 500);
|
|
g_signal_connect(G_OBJECT(vte_reaper_get()), "child-exited",
|
|
G_CALLBACK(child_exited), NULL);
|
|
|
|
/* add vbox with menubar, notebook */
|
|
vbox = gtk_vbox_new(FALSE, 0);
|
|
gtk_container_add(GTK_CONTAINER(window), vbox);
|
|
menubar = gtk_menu_bar_new();
|
|
gtk_box_pack_start(GTK_BOX(vbox), menubar, FALSE, TRUE, 0);
|
|
notebook = gtk_notebook_new();
|
|
g_object_set(G_OBJECT(notebook), "homogeneous", TRUE, NULL);
|
|
gtk_notebook_set_tab_pos(GTK_NOTEBOOK(notebook), GTK_POS_BOTTOM);
|
|
gtk_container_add(GTK_CONTAINER(vbox), notebook);
|
|
|
|
/* Dumm menu */
|
|
menu = gtk_menu_new();
|
|
dummMenu = gtk_menu_item_new_with_mnemonic("_Dumm");
|
|
gtk_menu_bar_append(GTK_MENU_BAR(menubar), dummMenu);
|
|
gtk_widget_show(dummMenu);
|
|
gtk_menu_item_set_submenu(GTK_MENU_ITEM(dummMenu), menu);
|
|
|
|
/* Dumm -> exit */
|
|
menuitem = gtk_image_menu_item_new_from_stock(GTK_STOCK_QUIT, NULL);
|
|
g_signal_connect(G_OBJECT(menuitem), "activate",
|
|
G_CALLBACK(quit), NULL);
|
|
gtk_menu_append(GTK_MENU(menu), menuitem);
|
|
gtk_widget_show(menuitem);
|
|
|
|
/* Guest menu */
|
|
menu = gtk_menu_new();
|
|
guestMenu = gtk_menu_item_new_with_mnemonic("_Guest");
|
|
gtk_menu_bar_append(GTK_MENU_BAR(menubar), guestMenu);
|
|
gtk_widget_show(guestMenu);
|
|
gtk_menu_item_set_submenu(GTK_MENU_ITEM(guestMenu), menu);
|
|
|
|
/* Guest -> new */
|
|
menuitem = gtk_image_menu_item_new_from_stock(GTK_STOCK_NEW, NULL);
|
|
g_signal_connect(G_OBJECT(menuitem), "activate",
|
|
G_CALLBACK(create_guest), NULL);
|
|
gtk_menu_append(GTK_MENU(menu), menuitem);
|
|
gtk_widget_show(menuitem);
|
|
|
|
/* Guest -> delete */
|
|
menuitem = gtk_image_menu_item_new_from_stock(GTK_STOCK_DELETE, NULL);
|
|
g_signal_connect(G_OBJECT(menuitem), "activate",
|
|
G_CALLBACK(delete_guest), NULL);
|
|
gtk_menu_append(GTK_MENU(menu), menuitem);
|
|
gtk_widget_show(menuitem);
|
|
|
|
menuitem = gtk_separator_menu_item_new();
|
|
gtk_menu_append(GTK_MENU(menu), menuitem);
|
|
gtk_widget_show(menuitem);
|
|
|
|
/* Guest -> start */
|
|
menuitem = gtk_menu_item_new_with_mnemonic("_Start");
|
|
g_signal_connect(G_OBJECT(menuitem), "activate",
|
|
G_CALLBACK(start_guest), NULL);
|
|
gtk_menu_append(GTK_MENU(menu), menuitem);
|
|
gtk_widget_show(menuitem);
|
|
|
|
/* Guest -> startall */
|
|
menuitem = gtk_menu_item_new_with_mnemonic("Start _all");
|
|
g_signal_connect(G_OBJECT(menuitem), "activate",
|
|
G_CALLBACK(start_all_guests), NULL);
|
|
gtk_menu_append(GTK_MENU(menu), menuitem);
|
|
gtk_widget_show(menuitem);
|
|
|
|
/* Guest -> stop */
|
|
menuitem = gtk_image_menu_item_new_from_stock(GTK_STOCK_STOP, NULL);
|
|
g_signal_connect(G_OBJECT(menuitem), "activate",
|
|
G_CALLBACK(stop_guest), NULL);
|
|
gtk_menu_append(GTK_MENU(menu), menuitem);
|
|
gtk_widget_show(menuitem);
|
|
|
|
menuitem = gtk_separator_menu_item_new();
|
|
gtk_menu_append(GTK_MENU(menu), menuitem);
|
|
gtk_widget_show(menuitem);
|
|
|
|
/* Guest -> connect */
|
|
menuitem = gtk_image_menu_item_new_from_stock(GTK_STOCK_CONNECT, NULL);
|
|
g_signal_connect(G_OBJECT(menuitem), "activate",
|
|
G_CALLBACK(connect_guest), NULL);
|
|
gtk_menu_append(GTK_MENU(menu), menuitem);
|
|
gtk_widget_show(menuitem);
|
|
|
|
/* Guest -> disconnect */
|
|
menuitem = gtk_image_menu_item_new_from_stock(GTK_STOCK_DISCONNECT, NULL);
|
|
g_signal_connect(G_OBJECT(menuitem), "activate",
|
|
G_CALLBACK(disconnect_guest), NULL);
|
|
gtk_menu_append(GTK_MENU(menu), menuitem);
|
|
gtk_widget_set_sensitive(menuitem, FALSE);
|
|
gtk_widget_show(menuitem);
|
|
|
|
/* Switch menu */
|
|
menu = gtk_menu_new();
|
|
switchMenu = gtk_menu_item_new_with_mnemonic("_Switch");
|
|
gtk_menu_bar_append(GTK_MENU_BAR(menubar), switchMenu);
|
|
gtk_widget_show(switchMenu);
|
|
gtk_menu_item_set_submenu(GTK_MENU_ITEM(switchMenu), menu);
|
|
|
|
/* Switch -> new */
|
|
menuitem = gtk_image_menu_item_new_from_stock(GTK_STOCK_NEW, NULL);
|
|
g_signal_connect(G_OBJECT(menuitem), "activate",
|
|
G_CALLBACK(create_switch), NULL);
|
|
gtk_menu_append(GTK_MENU(menu), menuitem);
|
|
gtk_widget_show(menuitem);
|
|
|
|
/* Switch -> delete */
|
|
menuitem = gtk_image_menu_item_new_from_stock(GTK_STOCK_DELETE, NULL);
|
|
g_signal_connect(G_OBJECT(menuitem), "activate",
|
|
G_CALLBACK(delete_switch), NULL);
|
|
gtk_menu_append(GTK_MENU(menu), menuitem);
|
|
gtk_widget_set_sensitive(menuitem, FALSE);
|
|
gtk_widget_show(menuitem);
|
|
|
|
/* show widgets */
|
|
gtk_widget_show(menubar);
|
|
gtk_widget_show(notebook);
|
|
gtk_widget_show(vbox);
|
|
gtk_widget_show(window);
|
|
|
|
/* fill notebook with guests */
|
|
enumerator = dumm->create_guest_enumerator(dumm);
|
|
while (enumerator->enumerate(enumerator, (void**)&guest))
|
|
{
|
|
create_page(guest);
|
|
}
|
|
enumerator->destroy(enumerator);
|
|
|
|
gtk_main();
|
|
|
|
dumm->destroy(dumm);
|
|
pages->destroy_function(pages, g_free);
|
|
|
|
library_deinit();
|
|
return 0;
|
|
}
|
|
|