Tabbed notebook functionality.
[ovirt-viewer.git] / main.c
diff --git a/main.c b/main.c
index 954ac3e..cf37b31 100644 (file)
--- a/main.c
+++ b/main.c
@@ -76,6 +76,9 @@ static GtkWidget *login_area;
 static GtkWidget *la_username;
 static GtkWidget *la_password;
 static GtkWidget *la_button;
+static GtkWidget *notebook;
+static GtkWidget *statusbar;
+static guint statusbar_ctx;
 static GdkCursor *busy_cursor;
 
 /* Menus. */
@@ -221,7 +224,6 @@ start_ui (void)
   GtkWidget *ca_hbox;
   GtkWidget *ca_label;
   GtkWidget *la_hbox;
-  GtkWidget *notebook;
 
   DEBUG ("creating viewer windows and menus");
 
@@ -336,10 +338,16 @@ start_ui (void)
 
   /* Tabbed notebook. */
   notebook = gtk_notebook_new ();
-  gtk_notebook_set_tab_pos (GTK_NOTEBOOK (notebook), GTK_POS_LEFT);
+  /*gtk_notebook_set_tab_pos (GTK_NOTEBOOK (notebook), GTK_POS_LEFT);*/
   gtk_notebook_set_show_tabs (GTK_NOTEBOOK (notebook), TRUE);
   gtk_notebook_set_scrollable (GTK_NOTEBOOK (notebook), TRUE);
 
+  /* Status bar. */
+  statusbar = gtk_statusbar_new ();
+  statusbar_ctx = gtk_statusbar_get_context_id (GTK_STATUSBAR (statusbar),
+                                               "context");
+  gtk_statusbar_push (GTK_STATUSBAR (statusbar), statusbar_ctx, "");
+
   /* Packing. */
   gtk_container_add (GTK_CONTAINER (window), vbox);
   gtk_container_add_with_properties (GTK_CONTAINER (vbox), menubar,
@@ -350,6 +358,8 @@ start_ui (void)
                                     "expand", FALSE, "fill", TRUE, NULL);
   gtk_container_add_with_properties (GTK_CONTAINER (vbox), notebook,
                                     "expand", TRUE, NULL);
+  gtk_container_add_with_properties (GTK_CONTAINER (vbox), statusbar,
+                                    "expand", FALSE, NULL);
 
   /* Show widgets. */
   gtk_widget_show_all (window);
@@ -427,6 +437,57 @@ login_to_wui (GtkWidget *widget, gpointer data)
   wui_thread_send_login (username, password);
 }
 
+/* Connect to a virtual machine.  This callback is called from the
+ * connect menu.  It searches the notebook of gtk-vnc widgets to see
+ * if we have already connected to this machine, and if not it
+ * makes a new connection.
+ */
+static void
+connect_to_vm (GtkWidget *widget, gpointer _vm)
+{
+  struct vm *vm = (struct vm *) _vm;
+  int n = gtk_notebook_get_n_pages (GTK_NOTEBOOK (notebook));
+  int i, uuidlen, len;
+  GtkWidget *child;
+  const char *label;
+  char *label2;
+
+  DEBUG ("searching tabs for uuid %s", vm->uuid);
+
+  uuidlen = strlen (vm->uuid);
+
+  /* Search the tabs for this UUID, and if found, switch to it and return. */
+  for (i = 0; i < n; ++i) {
+    child = gtk_notebook_get_nth_page (GTK_NOTEBOOK (notebook), i);
+    label = gtk_notebook_get_tab_label_text (GTK_NOTEBOOK (notebook), child);
+    len = strlen (label);
+    if (len >= uuidlen &&
+       STREQ (label + len - uuidlen, vm->uuid)) {
+      DEBUG ("found on tab %d", i);
+      gtk_notebook_set_current_page (GTK_NOTEBOOK (notebook), i);
+      return;
+    }
+  }
+
+  DEBUG ("not found, creating new tab");
+
+  /* This VM isn't in the notebook already, so create a new console. */
+  len = strlen (vm->description) + 1 + strlen (vm->uuid) + 1;
+  label2 = g_alloca (len);
+  snprintf (label2, len, "%s %s", vm->description, vm->uuid);
+
+  child = gtk_label_new (label2); /* XXX */
+
+  /* NB. We have to do this before adding it to the notebook. */
+  gtk_widget_show (child);
+
+  i = gtk_notebook_append_page (GTK_NOTEBOOK (notebook), child, NULL);
+  gtk_notebook_set_tab_label_text (GTK_NOTEBOOK (notebook), child, label2);
+  gtk_notebook_set_current_page (GTK_NOTEBOOK (notebook), i);
+
+  DEBUG ("finished creating new tab");
+}
+
 /* Remove all menu items from the Connect menu. */
 static void
 remove_menu_item (GtkWidget *menu_item, gpointer data)
@@ -579,37 +640,38 @@ main_status_error (gpointer _str)
   DEBUG ("status error: %s", str);
   ASSERT_IS_MAIN_THREAD ();
 
-  /*
-  gtk_label_set_text (GTK_LABEL (...), str);
-  */
+  gtk_statusbar_pop (GTK_STATUSBAR (statusbar), statusbar_ctx);
+  gtk_statusbar_push (GTK_STATUSBAR (statusbar), statusbar_ctx, 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);
+/* The WUI thread has updated the vm list.  Here in the main thread
+ * we keep our own copy of the vmlist.
+ */
+static GSList *vmlist = NULL;
 
-  item = gtk_menu_item_new_with_label (vm->description);
-  gtk_menu_append (GTK_MENU (connectmenu), item);
-}
+static void add_vm_to_connectmenu (gpointer _vm, gpointer data);
 
 gboolean
 main_vmlist_updated (gpointer data)
 {
-  GSList *vmlist;
+  GSList *new_vmlist;
 
   DEBUG ("vmlist updated");
   ASSERT_IS_MAIN_THREAD ();
 
   /* Get the new vmlist. */
-  if (wui_thread_get_vmlist (&vmlist)) {
+  if (wui_thread_get_vmlist (&new_vmlist)) {
+    /* Free the previous vmlist.  This invalidates all the vm pointers
+     * contained in the Connect menu callbacks, but we're going to
+     * delete those callbacks and create news ones in a moment anyway ...
+     */
+    free_vmlist (vmlist);
+
+    vmlist = new_vmlist;
+
     clear_connectmenu ();
 
     gtk_menu_append (GTK_MENU (connectmenu), refresh_vmlist);
@@ -618,7 +680,6 @@ main_vmlist_updated (gpointer data)
       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);
@@ -626,3 +687,18 @@ main_vmlist_updated (gpointer data)
 
   return FALSE;
 }
+
+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);
+
+  g_signal_connect (G_OBJECT (item), "activate",
+                   G_CALLBACK (connect_to_vm), vm);
+}