X-Git-Url: http://git.annexia.org/?a=blobdiff_plain;f=main.c;h=954ac3e9fd03c5287147bd34a6ac3e5e7914c791;hb=53c851e51c855a0493481881807d6fd8777cda93;hp=039cf3903c215acabf63ecabd690d5d0d42ef47b;hpb=06576813e9eee9338ade91bb2486a52af9507471;p=ovirt-viewer.git diff --git a/main.c b/main.c index 039cf39..954ac3e 100644 --- a/main.c +++ b/main.c @@ -22,7 +22,6 @@ #include #include #include -#include #include #include @@ -40,10 +39,6 @@ #include #endif -#ifndef G_THREADS_ENABLED -#error "This program requires GLib threads, and cannot be compiled without." -#endif - #include "internal.h" /*#define HTTPS "https"*/ @@ -61,21 +56,31 @@ gboolean check_cert = TRUE; static void start_ui (void); static GtkWidget *menu_item_new (int which_menu); static void connect_to_wui (GtkWidget *, gpointer); +static void login_to_wui (GtkWidget *, gpointer); static gboolean delete_event (GtkWidget *widget, GdkEvent *event, gpointer data); static void destroy (GtkWidget *widget, gpointer data); +static void clear_connectmenu (void); /* For any widgets accessed from multiple functions. */ +static GtkWidget *window; +static GtkWidget *connectitem; +static GtkWidget *connectmenu; +static GtkWidget *no_connections; +static GtkWidget *refresh_vmlist; +static GtkWidget *refresh_vmlist_separator; static GtkWidget *connection_area; static GtkWidget *ca_hostname; static GtkWidget *ca_button; +static GtkWidget *ca_error; static GtkWidget *login_area; static GtkWidget *la_username; static GtkWidget *la_password; static GtkWidget *la_button; +static GdkCursor *busy_cursor; /* Menus. */ enum menuNums { - FILE_MENU, + CONNECT_MENU, VIEW_MENU, SEND_KEY_MENU, WINDOW_MENU, @@ -90,7 +95,7 @@ struct menuItem { }; static struct menuItem menuItems[] = { - { FILE_MENU, NULL, "_File", "File" }, + { CONNECT_MENU, NULL, "_Connect", "Connect" }, { VIEW_MENU, NULL, "_View", "View" }, { SEND_KEY_MENU, NULL, "_Send Key", "Send Key" }, { WINDOW_MENU, NULL, "_Window", "Window" }, @@ -102,16 +107,15 @@ static const char *title = "oVirt Viewer"; /* Gtk widget styles. Avoid installation hassles by keeping this * inside the binary. It can still be overridden by the user (who - * will do that?). + * will do that?) */ static const char *styles = - "\ -style \"ovirt-viewer-yellow-box\"\n\ -{\n\ - bg[NORMAL] = shade (1.5, \"yellow\")\n\ -}\n\ -widget \"*.ovirt-viewer-connection-area\" style \"ovirt-viewer-yellow-box\"\n\ -"; + "style \"ovirt-viewer-yellow-box\"\n" + "{\n" + " bg[NORMAL] = shade (1.5, \"yellow\")\n" + "}\n" + "widget \"*.ovirt-viewer-connection-area\" style \"ovirt-viewer-yellow-box\"\n" + ; /* Command-line arguments. */ static int print_version = 0; @@ -152,13 +156,19 @@ main (int argc, char *argv[]) * The WUI thread keeps the UI updated by adding idle events which are * processed in the main thread - see: * http://mail.gnome.org/archives/gtk-app-devel-list/2007-March/msg00232.html + * + * Note that under Win32 you must confine all Gtk/Gdk interactions + * to a single thread - see: + * http://developer.gimp.org/api/2.0/gdk/gdk-Threads.html */ if (!g_thread_supported ()) { - g_thread_init (NULL); - gdk_threads_init (); + g_thread_init (NULL); +#ifndef WIN32 + gdk_threads_init (); +#endif } else { - fprintf (stderr, "GLib threads not supported or not working."); - exit (1); + fprintf (stderr, "GLib threads not supported or not working."); + exit (1); } gtk_init (&argc, &argv); @@ -184,6 +194,8 @@ main (int argc, char *argv[]) start_wui_thread (); start_ui (); + DEBUG ("entering the Gtk main loop"); + gtk_main (); stop_wui_thread (); @@ -195,11 +207,8 @@ main (int argc, char *argv[]) static void start_ui (void) { - GtkWidget *window; GtkWidget *vbox; GtkWidget *menubar; - GtkWidget *file; - GtkWidget *filemenu; GtkWidget *view; GtkWidget *viewmenu; GtkWidget *sendkey; @@ -214,9 +223,16 @@ start_ui (void) GtkWidget *la_hbox; GtkWidget *notebook; + DEBUG ("creating viewer windows and menus"); + /* Parse styles. */ gtk_rc_parse_string (styles); + /* Busy cursor, used by main_busy() function. + * XXX This cursor is crap - how can we use the Bluecurve/theme cursor? + */ + busy_cursor = gdk_cursor_new (GDK_WATCH); + /* Window. */ window = gtk_window_new (GTK_WINDOW_TOPLEVEL); gtk_window_set_default_size (GTK_WINDOW (window), 800, 600); @@ -233,9 +249,22 @@ start_ui (void) /* Menubar. */ menubar = gtk_menu_bar_new (); - file = menu_item_new (FILE_MENU); - filemenu = gtk_menu_new (); - gtk_menu_item_set_submenu (GTK_MENU_ITEM (file), filemenu); + connectitem = menu_item_new (CONNECT_MENU); + connectmenu = gtk_menu_new (); + gtk_menu_item_set_submenu (GTK_MENU_ITEM (connectitem), connectmenu); + + no_connections = gtk_menu_item_new_with_label ("Not connected"); + gtk_menu_append (GTK_MENU (connectmenu), no_connections); + gtk_widget_set_sensitive (no_connections, FALSE); + + /* This is not added to the menu yet, but will be when we are + * connected. + */ + refresh_vmlist = + gtk_menu_item_new_with_label ("Refresh list of virtual machines"); + g_object_ref (refresh_vmlist); + refresh_vmlist_separator = gtk_separator_menu_item_new (); + g_object_ref (refresh_vmlist_separator); #if 0 screenshot = gtk_menu_item_new_with_mnemonic ("_Screenshot"); @@ -260,7 +289,7 @@ start_ui (void) helpmenu = gtk_menu_new (); gtk_menu_item_set_submenu (GTK_MENU_ITEM (help), helpmenu); - gtk_menu_bar_append (GTK_MENU_BAR (menubar), file); + gtk_menu_bar_append (GTK_MENU_BAR (menubar), connectitem); gtk_menu_bar_append (GTK_MENU_BAR (menubar), view); gtk_menu_bar_append (GTK_MENU_BAR (menubar), sendkey); gtk_menu_bar_append (GTK_MENU_BAR (menubar), wind); @@ -274,10 +303,12 @@ start_ui (void) ca_hostname = gtk_entry_new (); gtk_entry_set_width_chars (GTK_ENTRY (ca_hostname), 24); ca_button = gtk_button_new_with_label ("Connect"); + ca_error = gtk_label_new (NULL); gtk_box_pack_start (GTK_BOX (ca_hbox), ca_hostname, FALSE, FALSE, 0); gtk_box_pack_start (GTK_BOX (ca_hbox), ca_button, FALSE, FALSE, 0); gtk_box_pack_start (GTK_BOX (ca_vbox), ca_label, FALSE, FALSE, 4); gtk_box_pack_start (GTK_BOX (ca_vbox), ca_hbox, TRUE, FALSE, 4); + gtk_box_pack_start (GTK_BOX (ca_vbox), ca_error, TRUE, FALSE, 4); gtk_container_add (GTK_CONTAINER (connection_area), ca_vbox); gtk_widget_set_name (connection_area, "ovirt-viewer-connection-area"); @@ -300,6 +331,9 @@ start_ui (void) gtk_widget_set_name (login_area, "ovirt-viewer-login-area"); + g_signal_connect (G_OBJECT (la_button), "clicked", + G_CALLBACK (login_to_wui), NULL); + /* Tabbed notebook. */ notebook = gtk_notebook_new (); gtk_notebook_set_tab_pos (GTK_NOTEBOOK (notebook), GTK_POS_LEFT); @@ -327,7 +361,7 @@ start_ui (void) } static GtkWidget * -menu_item_new(int which_menu) +menu_item_new (int which_menu) { GtkWidget *widget; GtkWidget *label; @@ -335,14 +369,14 @@ menu_item_new(int which_menu) text = menuItems[which_menu].ungrabbed_text; - widget = gtk_menu_item_new(); - label = g_object_new(GTK_TYPE_ACCEL_LABEL, NULL); - gtk_label_set_text_with_mnemonic(GTK_LABEL(label), text); - gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5); + widget = gtk_menu_item_new (); + label = g_object_new (GTK_TYPE_ACCEL_LABEL, NULL); + gtk_label_set_text_with_mnemonic (GTK_LABEL (label), text); + gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); - gtk_container_add(GTK_CONTAINER(widget), label); - gtk_accel_label_set_accel_widget(GTK_ACCEL_LABEL(label), widget); - gtk_widget_show(label); + gtk_container_add (GTK_CONTAINER (widget), label); + gtk_accel_label_set_accel_widget (GTK_ACCEL_LABEL (label), widget); + gtk_widget_show (label); menuItems[which_menu].label = label; @@ -375,8 +409,220 @@ connect_to_wui (GtkWidget *widget, gpointer data) /* https:// + hostname + /ovirt + \0 */ len = 8 + strlen (hostname) + 6 + 1; - uri = alloca (len); + uri = g_alloca (len); snprintf (uri, len, HTTPS "://%s/ovirt", hostname); wui_thread_send_connect (uri); } + +static void +login_to_wui (GtkWidget *widget, gpointer data) +{ + const char *username, *password; + + username = gtk_entry_get_text (GTK_ENTRY (la_username)); + if (STREQ (username, "")) return; + password = gtk_entry_get_text (GTK_ENTRY (la_password)); + + wui_thread_send_login (username, password); +} + +/* Remove all menu items from the Connect menu. */ +static void +remove_menu_item (GtkWidget *menu_item, gpointer data) +{ + gtk_container_remove (GTK_CONTAINER (connectmenu), menu_item); +} + +static void +clear_connectmenu (void) +{ + DEBUG ("clear Connect menu"); + gtk_container_foreach (GTK_CONTAINER (connectmenu), remove_menu_item, NULL); +} + +/* The WUI thread has changed its state to connected. */ +gboolean +main_connected (gpointer data) +{ + DEBUG ("connected"); + ASSERT_IS_MAIN_THREAD (); + + gtk_label_set_text (GTK_LABEL (ca_error), NULL); + + gtk_widget_hide (connection_area); + if (!wui_thread_is_logged_in ()) + gtk_widget_show (login_area); + return FALSE; +} + +/* The WUI thread has changed its state to disconnected. */ +gboolean +main_disconnected (gpointer data) +{ + DEBUG ("disconnected"); + ASSERT_IS_MAIN_THREAD (); + + gtk_widget_show (connection_area); + gtk_widget_hide (login_area); + + clear_connectmenu (); + gtk_menu_append (GTK_MENU (connectmenu), no_connections); + gtk_widget_show_all (connectmenu); + + return FALSE; +} + +/* The WUI thread has changed its state to logged in. */ +gboolean +main_logged_in (gpointer data) +{ + DEBUG ("logged in"); + ASSERT_IS_MAIN_THREAD (); + + gtk_widget_hide (login_area); + return FALSE; +} + +/* The WUI thread has changed its state to logged out. */ +gboolean +main_logged_out (gpointer data) +{ + DEBUG ("logged out"); + ASSERT_IS_MAIN_THREAD (); + + if (wui_thread_is_connected ()) + gtk_widget_show (login_area); + return FALSE; +} + +/* The WUI thread has changed its state to busy. */ +gboolean +main_busy (gpointer data) +{ + GdkWindow *gdk_window; + + DEBUG ("busy"); + ASSERT_IS_MAIN_THREAD (); + + gdk_window = gtk_widget_get_window (window); + if (gdk_window) { + gdk_window_set_cursor (gdk_window, busy_cursor); + gdk_flush (); + } + + return FALSE; +} + +/* The WUI thread has changed its state to idle. */ +gboolean +main_idle (gpointer data) +{ + GdkWindow *gdk_window; + + DEBUG ("idle"); + ASSERT_IS_MAIN_THREAD (); + + gdk_window = gtk_widget_get_window (window); + if (gdk_window) { + gdk_window_set_cursor (gdk_window, NULL); + gdk_flush (); + } + + return FALSE; +} + +/* The WUI thread had a connection error. This function must + * free the string. + */ +gboolean +main_connection_error (gpointer _str) +{ + char *str = (char *) _str; + + DEBUG ("connection error: %s", str); + ASSERT_IS_MAIN_THREAD (); + + gtk_label_set_text (GTK_LABEL (ca_error), str); + g_free (str); + + return FALSE; +} + +/* The WUI thread had a login error. This function must + * free the string. + */ +gboolean +main_login_error (gpointer _str) +{ + char *str = (char *) _str; + + DEBUG ("login error: %s", str); + ASSERT_IS_MAIN_THREAD (); + + /* + gtk_label_set_text (GTK_LABEL (la_error), str); + */ + g_free (str); + + return FALSE; +} + +/* The WUI thread reports a general status error. This function + * must free the string. + */ +gboolean +main_status_error (gpointer _str) +{ + char *str = (char *) _str; + + DEBUG ("status error: %s", str); + ASSERT_IS_MAIN_THREAD (); + + /* + gtk_label_set_text (GTK_LABEL (...), str); + */ + g_free (str); + + return FALSE; +} + +/* The WUI thread has updated the vm list. */ +static void +add_vm_to_connectmenu (gpointer _vm, gpointer data) +{ + struct vm *vm = (struct vm *) _vm; + GtkWidget *item; + + DEBUG ("adding %s to Connect menu", vm->description); + + item = gtk_menu_item_new_with_label (vm->description); + gtk_menu_append (GTK_MENU (connectmenu), item); +} + +gboolean +main_vmlist_updated (gpointer data) +{ + GSList *vmlist; + + DEBUG ("vmlist updated"); + ASSERT_IS_MAIN_THREAD (); + + /* Get the new vmlist. */ + if (wui_thread_get_vmlist (&vmlist)) { + clear_connectmenu (); + + gtk_menu_append (GTK_MENU (connectmenu), refresh_vmlist); + + if (vmlist != NULL) { + gtk_menu_append (GTK_MENU (connectmenu), refresh_vmlist_separator); + g_slist_foreach (vmlist, add_vm_to_connectmenu, NULL); + } + free_vmlist (vmlist); + + /* Grrrr Gtk is stupid. */ + gtk_widget_show_all (connectmenu); + } + + return FALSE; +}