]> www.fi.muni.cz Git - evince.git/commitdiff
stylisticly nicer bonobo container 'gpdf' pinched from Nat,
authorMichael Meeks <mmeeks@src.gnome.org>
Sat, 21 Aug 1999 17:15:26 +0000 (17:15 +0000)
committerMichael Meeks <mmeeks@src.gnome.org>
Sat, 21 Aug 1999 17:15:26 +0000 (17:15 +0000)
Verb support for next / prev. page.

pdf/xpdf/bonobo-image-x-pdf.cc
pdf/xpdf/gpdf.cc

index 2a3bcfbf58fbec45d080f774308fe1bfdadce13a..c13d9c8794cb42c0e40395d89d9305f656d2b6e5 100644 (file)
@@ -48,7 +48,7 @@ CORBA_ORB orb;
  * BonoboObject data
  */
 typedef struct {
-  GnomeEmbeddable *embed_obj;
+  GnomeEmbeddable *embeddable;
 
   PDFDoc       *pdf;
   GNOME_Stream  stream; /* To free it later */
@@ -66,6 +66,7 @@ typedef struct {
   double                scale;
   GtkWidget            *drawing_area;
   GdkPixmap            *pixmap;
+  GdkWindow            *win;
   GOutputDev           *out;
   GdkColor              paper;
   gint                  w, h;
@@ -73,7 +74,9 @@ typedef struct {
   gint                  page;
 } view_data_t;
 
-static void realize_drawing_areas (bed_t *bed);
+extern "C" {
+  static void realize_drawing_areas (bed_t *bed);
+}
 
 static void
 redraw_view (view_data_t *view_data, GdkRectangle *rect)
@@ -116,13 +119,6 @@ redraw_view (view_data_t *view_data, GdkRectangle *rect)
 static void
 configure_size (view_data_t *view_data, GdkRectangle *rect)
 {
-/*     ArtPixBuf *pixbuf;
-       
-       if (view_data->scaled)
-               pixbuf = view_data->scaled;
-       else
-               pixbuf = view_data->bed->image;
-*/
   gtk_widget_set_usize (
     view_data->drawing_area,
     view_data->w,
@@ -132,6 +128,7 @@ configure_size (view_data_t *view_data, GdkRectangle *rect)
   rect->y = 0;
   rect->width = view_data->w;
   rect->height = view_data->h;
+  printf ("Set size to %d, %d\n", view_data->w, view_data->h);
 }
 
 static void
@@ -192,31 +189,6 @@ load_image_from_stream (GnomePersistStream *ps, GNOME_Stream stream, void *data)
        CORBA_Object_duplicate (stream, &ev);
        g_return_val_if_fail (ev._major == CORBA_NO_EXCEPTION, 0);
 
-/*     buffer = GNOME_Stream_iobuf__alloc ();
-       length = GNOME_Stream_length (stream, &ev);
-
-       name = tempnam (NULL, "xpdf-hack");
-       if (!name)
-         return -1;
-       hack = fopen (name, "wb+");
-       if (!hack)
-         return -1;
-
-       while (length > 0) {
-         guint getlen;
-         if (length > 128)
-           getlen = 128;
-         else
-           getlen = length;
-         GNOME_Stream_read (stream, getlen, &buffer, &ev);
-         fwrite (buffer->_buffer, 1, buffer->_length, hack);
-         length -= buffer->_length;
-       }
-
-       fclose (hack);
-
-       CORBA_free (buffer);*/
-
        printf ("Loading PDF from persiststream\n");
        bed->stream = stream;
        BonoboStream *bs = new BonoboStream (stream);
@@ -306,6 +278,77 @@ setup_pixmap (bed_t *doc, view_data_t *view, GdkWindow *window)
     return pixmap;
 }
 
+extern "C" {
+  static void
+  view_color_select_cb (GnomeUIHandler *uih, void *data, char *path)
+  {
+    view_data_t *view_data = (view_data_t *) data;
+
+    printf ("path '%s'\n", path);
+  }
+}
+
+static void
+view_create_menus (view_data_t *view_data)
+{
+  GNOME_UIHandler remote_uih;
+  GnomeView *view = view_data->view;
+  GnomeUIHandler *uih;
+  
+  uih = gnome_view_get_ui_handler (view);
+  remote_uih = gnome_view_get_remote_ui_handler (view);
+  
+  if (remote_uih == CORBA_OBJECT_NIL) {
+    g_warning ("server has no UI hander");
+    return;
+  }
+  
+  gnome_ui_handler_set_container (uih, remote_uih);
+
+  gnome_ui_handler_menu_new_subtree (uih, "/Colors",
+                                    N_("Select drawing color..."),
+                                    N_("Set the current drawing color"),
+                                    1,
+                                    GNOME_UI_HANDLER_PIXMAP_NONE, NULL,
+                                    0, 0);
+  gnome_ui_handler_menu_new_radiogroup (uih, "/Colors/color radiogroup");
+  
+  gnome_ui_handler_menu_new_radioitem (uih, "/Colors/color radiogroup/White",
+                                      N_("White"),
+                                      N_("Set the current drawing color to white"),
+                                      -1,
+                                      0, (GdkModifierType) 0,
+                                      view_color_select_cb, (gpointer) view_data);
+  
+  gnome_ui_handler_menu_new_radioitem (uih, "/Colors/color radiogroup/Red",
+                                      N_("Red"),
+                                      N_("Set the current drawing color to red"),
+                                      -1, 
+                                      0, (GdkModifierType) 0,
+                                      view_color_select_cb, (gpointer) view_data);
+  
+  gnome_ui_handler_menu_new_radioitem (uih, "/Colors/color radiogroup/Green",
+                                      N_("Green"),
+                                      N_("Set the current drawing color to green"),
+                                      -1,
+                                      0, (GdkModifierType) 0,
+                                      view_color_select_cb, (gpointer) view_data);
+}
+
+/*
+ * When this view is deactivated, we must remove our menu items.
+ */
+static void
+view_remove_menus (view_data_t *view_data)
+{
+       GnomeView *view = view_data->view;
+       GnomeUIHandler *uih;
+
+       uih = gnome_view_get_ui_handler (view);
+
+       gnome_ui_handler_unset_container (uih);
+}
+
 extern "C" {
 
   static void
@@ -313,18 +356,12 @@ extern "C" {
   {
     g_return_if_fail (view_data != NULL);
     g_return_if_fail (view_data->bed != NULL);
-    g_return_if_fail (view_data->bed->pdf != NULL);
-
-    if (!view_data->pixmap) {
-      GdkWindow *win = gtk_widget_get_parent_window (drawing_area);
-      GdkRectangle tmp;
-      
-      g_return_if_fail (win);
-      
-      view_data->pixmap = setup_pixmap (view_data->bed, view_data, win);
-      view_data->bed->pdf->displayPage(view_data->out, view_data->page, view_data->zoom, 0, gTrue);
-
-      configure_size (view_data, &tmp);
+
+    view_data->win = gtk_widget_get_parent_window (drawing_area);
+    if (!view_data->bed->pdf ||
+       !view_data->pixmap) {
+      g_warning ("Failed to setup pixmap");
+      return;
     }
   }
 
@@ -335,32 +372,99 @@ extern "C" {
        !view_data->bed->pdf)
       return TRUE;
     
-/* Hoisted from view_factory: ugly */
     redraw_view (view_data, &event->area);
     
     return TRUE;
   }
-}
 
-static void
-realize_drawing_areas (bed_t *bed)
-{
-  GList *l;
-  
-  for (l = bed->views; l; l = l->next){
-    GdkRectangle rect;
-    view_data_t *view_data = (view_data_t *)l->data;
+  static void
+  view_activate (GnomeView *view, gboolean activate, gpointer data)
+  {
+    view_data_t *view_data = (view_data_t *) data;
+    
+    gnome_view_activate_notify (view, activate);
+    
+    /*
+     * If we were just activated, we merge in our menu entries.
+     * If we were just deactivated, we remove them.
+     */
+    if (activate)
+      view_create_menus (view_data);
+    else
+      view_remove_menus (view_data);
+  }
 
-    drawing_area_realize (view_data->drawing_area, view_data);
-  }  
+  static void
+  view_size_query (GnomeView *view, int *desired_width, int *desired_height,
+                  gpointer data)
+  {
+    view_data_t *view_data = (view_data_t *) data;
+    
+    *desired_width  = view_data->w;
+    *desired_height = view_data->h;
+  }
+
+  static void
+  render_page (view_data_t *view_data)
+  {
+    view_data->pixmap = setup_pixmap (view_data->bed, view_data,
+                                     view_data->win);
+    view_data->bed->pdf->displayPage(view_data->out,
+                                    view_data->page, view_data->zoom,
+                                    0, gTrue);
+  }
+
+  static void
+  realize_drawing_areas (bed_t *bed)
+  {
+    GList *l;
+    
+    for (l = bed->views; l; l = l->next) {
+      GdkRectangle rect;
+      view_data_t *view_data = (view_data_t *)l->data;
+      g_return_if_fail (view_data->win);
+      render_page (view_data);
+      configure_size (view_data, &rect);
+    }  
+  }
+
+  static void
+  view_switch_page (GnomeView *view, const char *verb_name, void *user_data)
+  {
+    view_data_t  *view_data = (view_data_t *) user_data;
+    GdkRectangle  rect;
+    gboolean      changed = FALSE;
+
+    if (!g_strcasecmp (verb_name, "nextpage")) {
+      printf ("next page\n");
+      if (view_data->page < view_data->bed->pdf->getNumPages()) {
+       view_data->page++;
+       changed = TRUE;
+      }
+    } else if (!g_strcasecmp (verb_name, "prevpage")) {
+      printf ("previous page\n");
+      if (view_data->page > 1) {
+       view_data->page--;
+       changed = TRUE;
+      }
+    } else
+      g_warning ("Unknown verb");
+
+    if (changed) {
+      render_page (view_data);
+      redraw_view (view_data, &rect);
+      gtk_widget_queue_draw (GTK_WIDGET (view_data->drawing_area));
+    }
+  }
 }
 
 static GnomeView *
-view_factory (GnomeEmbeddable *embed_obj,
+view_factory (GnomeEmbeddable *embeddable,
              const GNOME_ViewFrame view_frame,
              void *data)
 {
         GnomeView *view;
+       GnomeUIHandler *uih;
        bed_t *bed = (bed_t *)data;
        view_data_t *view_data = g_new (view_data_t, 1);
 
@@ -370,6 +474,7 @@ view_factory (GnomeEmbeddable *embed_obj,
        view_data->bed    = bed;
        view_data->drawing_area = gtk_drawing_area_new ();
        view_data->pixmap = NULL;
+       view_data->win    = NULL;
        view_data->out    = NULL;
        view_data->w      = 320;
        view_data->h      = 320;
@@ -396,15 +501,31 @@ view_factory (GnomeEmbeddable *embed_obj,
                GTK_OBJECT (view), "destroy",
                GTK_SIGNAL_FUNC (destroy_view), view_data);
 
+       /* UI handling */
+       uih = gnome_ui_handler_new ();
+       gnome_view_set_ui_handler (view, uih);
+
+       gtk_signal_connect (GTK_OBJECT (view), "view_activate",
+                           GTK_SIGNAL_FUNC (view_activate), view_data);
+
+       gtk_signal_connect (GTK_OBJECT (view), "size_query",
+                           GTK_SIGNAL_FUNC (view_size_query), view_data);
+
        bed->views = g_list_prepend (bed->views, view_data);
 
+       /* Verb handling */
+       gnome_view_register_verb (view, "NextPage",
+                                 view_switch_page, view_data);
+       gnome_view_register_verb (view, "PrevPage",
+                                 view_switch_page, view_data);
+
         return view;
 }
 
 static GnomeObject *
-embed_obj_factory (GnomeEmbeddableFactory *This, void *data)
+embeddable_factory (GnomeEmbeddableFactory *This, void *data)
 {
-       GnomeEmbeddable *embed_obj;
+       GnomeEmbeddable *embeddable;
        GnomePersistStream *stream;
        bed_t *bed = (bed_t *)data;
 
@@ -416,8 +537,8 @@ embed_obj_factory (GnomeEmbeddableFactory *This, void *data)
        /*
         * Creates the BonoboObject server
         */
-       embed_obj = gnome_embeddable_new (view_factory, bed);
-       if (embed_obj == NULL){
+       embeddable = gnome_embeddable_new (view_factory, bed);
+       if (embeddable == NULL){
                g_free (bed);
                return NULL;
        }
@@ -431,23 +552,35 @@ embed_obj_factory (GnomeEmbeddableFactory *This, void *data)
                                           load_image_from_stream,
                                           save_image,
                                           bed);
-       if (stream == NULL){
-               gtk_object_unref (GTK_OBJECT (embed_obj));
+       if (stream == NULL) {
+               gtk_object_unref (GTK_OBJECT (embeddable));
                g_free (bed);
                return NULL;
        }
 
-       bed->embed_obj = embed_obj;
+       bed->embeddable = embeddable;
 
        /*
         * Bind the interfaces
         */
-       gnome_object_add_interface (GNOME_OBJECT (embed_obj),
+       gnome_object_add_interface (GNOME_OBJECT (embeddable),
                                    GNOME_OBJECT (stream));
        gtk_signal_connect (
-         GTK_OBJECT (embed_obj), "destroy",
+         GTK_OBJECT (embeddable), "destroy",
          GTK_SIGNAL_FUNC (destroy_embed), bed);
-       return (GnomeObject *) embed_obj;
+
+
+       /* Setup some verbs */
+       gnome_embeddable_add_verb (embeddable,
+                                  "NextPage",
+                                  _("_Next page"),
+                                  _("goto the next page"));
+       gnome_embeddable_add_verb (embeddable,
+                                  "PrevPage",
+                                  _("_Previous page"),
+                                  _("goto the previous page"));
+       
+       return (GnomeObject *) embeddable;
 }
 
 static void
@@ -457,7 +590,7 @@ init_bonobo_image_x_png_factory (void)
        
        factory = gnome_embeddable_factory_new (
                "bonobo-object-factory:image-x-pdf",
-               embed_obj_factory, NULL);
+               embeddable_factory, NULL);
 }
 
 static void
@@ -474,21 +607,20 @@ init_server_factory (int argc, char **argv)
 int
 main (int argc, char *argv [])
 {
-       CORBA_exception_init (&ev);
-
-       init_server_factory (argc, argv);
-       init_bonobo_image_x_png_factory ();
-
-       errorInit();
-
-       initParams (xpdfConfigFile); /* Init font path */
-
-       gtk_widget_set_default_colormap (gdk_rgb_get_cmap ());
-       gtk_widget_set_default_visual (gdk_rgb_get_visual ());
-       gtk_main ();
-       
-       CORBA_exception_free (&ev);
-
-       return 0;
+  CORBA_exception_init (&ev);
+  
+  init_server_factory (argc, argv);
+  init_bonobo_image_x_png_factory ();
+  
+  errorInit();
+  
+  initParams (xpdfConfigFile); /* Init font path */
+  
+  gtk_widget_set_default_colormap (gdk_rgb_get_cmap ());
+  gtk_widget_set_default_visual (gdk_rgb_get_visual ());
+  gtk_main ();
+  
+  CORBA_exception_free (&ev);
+  
+  return 0;
 }
-      
index f0237c76646302dfb62b5eb74595884147053c28..7a4963479d4eb094706d86f2d1c5fa166a67a35d 100644 (file)
@@ -1,15 +1,10 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
 /*
- * test-container.c
+ * PDF viewer Bonobo container.
  *
- * A simple program to act as a test container for embeddable
- * components.
+ * Author:
+ *   Michael Meeks <michael@imaginator.com>
  *
- * Authors:
- *    Nat Friedman (nat@gnome-support.com)
- *    Miguel de Icaza (miguel@gnu.org)
  */
-
 #include <stdio.h>
 #include <stdlib.h>
 #include <stddef.h>
@@ -46,8 +41,6 @@ extern "C" {
 #include "Error.h"
 #include "config.h"
 
-CORBA_Environment ev;
-CORBA_ORB orb;
 poptContext ctx;
 gint  gpdf_debug=1;
 
@@ -57,449 +50,599 @@ const struct poptOption gpdf_popt_options [] = {
   { NULL, '\0', 0, NULL, 0 }
 };
 
-/*
- * A handle to some Embeddables and their ClientSites so we can add
- * views to existing components.
- */
-GnomeObjectClient *text_obj;
-GnomeClientSite *text_client_site;
+typedef struct {
+       GnomeContainer  *container;
+       GnomeUIHandler  *uih;
 
-GnomeObjectClient *image_png_obj;
-GnomeClientSite   *image_client_site;
+       GnomeViewFrame  *active_view_frame;
 
-/*
- * The currently active view.  We keep track of this
- * so we can deactivate it when a new view is activated.
- */
-GnomeViewFrame *active_view_frame;
-
-char *server_goadid = "gnome_xpdf_viewer";
+       GtkWidget       *app;
+       GtkWidget       *vbox;
+} Container;
 
 typedef struct {
-       GtkWidget *app;
-       GnomeContainer *container;
-       GtkWidget *box;
-       GnomeUIHandler *uih;
-       gboolean contains_pdf;
-} Application;
-
-/* List of applications */
-GList *apps = NULL;
+       Container         *container;
 
-static Application * application_new (void);
+       GnomeClientSite   *client_site;
+       GnomeViewFrame    *view_frame;
+       GnomeObjectClient *server;
 
-static void
-application_destroy (Application *app)
-{
-       apps = g_list_remove (apps, app);
-       gtk_widget_destroy (app->app);
-       g_free (app);
-       if (!apps)
-               gtk_main_quit ();
-}
+       GtkWidget         *views_hbox;
+} Component;
 
-static void
-applications_destroy ()
-{
-       while (apps)
-               application_destroy ((Application *)apps->data);
+GList *containers = NULL;
+/*
+ * Static prototypes.
+ */
+extern "C" {
+  static Container *container_new       (void);
+  static void       container_destroy   (Container *cont);
+  static void       container_open_cmd  (GtkWidget *widget, Container *container);
+  static void       container_close_cmd (GtkWidget *widget, Container *container);
+  static void       container_exit_cmd  (void);
+  static Component *container_activate_component (Container *container, char *component_goad_id);
 }
 
-static GnomeObjectClient *
-launch_server (GnomeClientSite *client_site, GnomeContainer *container, char *goadid)
-{
-       GnomeObjectClient *object_server;
-       
-       gnome_container_add (container, GNOME_OBJECT (client_site));
-
-       printf ("Launching...\n");
-       object_server = gnome_object_activate_with_goad_id (NULL, goadid, GOAD_ACTIVATE_SHLIB, NULL);
-       printf ("Return: %p\n", object_server);
-       if (!object_server){
-               g_warning (_("Can not activate object_server\n"));
-               return NULL;
-       }
+/*
+ * The menus.
+ */
+static GnomeUIInfo container_file_menu [] = {
+       GNOMEUIINFO_MENU_OPEN_ITEM (container_open_cmd, NULL),
+       GNOMEUIINFO_SEPARATOR,
+       GNOMEUIINFO_MENU_CLOSE_ITEM(container_close_cmd, NULL),
+       GNOMEUIINFO_SEPARATOR,
+       GNOMEUIINFO_MENU_EXIT_ITEM (container_exit_cmd, NULL),
+       GNOMEUIINFO_END
+};
 
-       if (!gnome_client_site_bind_embeddable (client_site, object_server)){
-               g_warning (_("Can not bind object server to client_site\n"));
-               return NULL;
-       }
+static GnomeUIInfo container_main_menu [] = {
+       GNOMEUIINFO_MENU_FILE_TREE (container_file_menu),
+       GNOMEUIINFO_END
+};
 
-       return object_server;
+extern "C" {
+  static void
+  open_pdf (Container *container, const char *name)
+  {
+    GnomeObjectClient *object;
+    GnomeStream *stream;
+    GNOME_PersistStream persist;
+    Component *comp;
+    CORBA_Environment ev;
+
+    comp = container_activate_component (container, "bonobo-object:image-x-pdf");
+    if (!comp || !(object = comp->server)) {
+      gnome_error_dialog (_("Could not launch bonobo object."));
+      return;
+    }
+    
+    CORBA_exception_init (&ev);
+    persist = GNOME_Unknown_query_interface (
+      gnome_object_corba_objref (GNOME_OBJECT (object)),
+      "IDL:GNOME/PersistStream:1.0", &ev);
+    
+    if (ev._major != CORBA_NO_EXCEPTION ||
+       persist == CORBA_OBJECT_NIL) {
+      gnome_error_dialog ("Panic: component is well broken.");
+      return;
+    }
+    
+    stream = gnome_stream_fs_open (name, GNOME_Storage_READ);
+    
+    if (stream == NULL) {
+      char *err = g_strconcat (_("Could not open "), name, NULL);
+      gnome_error_dialog_parented (err, GTK_WINDOW(container->app));
+      g_free (err);
+      return;
+    }
+    
+    GNOME_PersistStream_load (persist,
+                             (GNOME_Stream) gnome_object_corba_objref (GNOME_OBJECT (stream)), &ev);
+    
+    GNOME_Unknown_unref (persist, &ev);
+    CORBA_Object_release (persist, &ev);
+    CORBA_exception_free (&ev);
+/*     app->contains_pdf = TRUE; */
+  }
+  
+  static void
+  set_ok (GtkWidget *widget, gboolean *dialog_result)
+  {
+    *dialog_result = TRUE;
+    gtk_main_quit ();
+  }
+  
+  static guint
+  file_dialog_delete_event (GtkWidget *widget, GdkEventAny *event)
+  {
+    gtk_main_quit ();
+    return TRUE;
+  }
+  
+  static void
+  container_open_cmd (GtkWidget *widget, Container *app)
+  {
+    GtkFileSelection *fsel;
+    gboolean accepted = FALSE;
+    
+    fsel = GTK_FILE_SELECTION (gtk_file_selection_new (_("Load file")));
+    gtk_window_set_modal (GTK_WINDOW (fsel), TRUE);
+    
+    gtk_window_set_transient_for (GTK_WINDOW (fsel),
+                                 GTK_WINDOW (app->app));
+    
+    /* Connect the signals for Ok and Cancel */
+    gtk_signal_connect (GTK_OBJECT (fsel->ok_button), "clicked",
+                       GTK_SIGNAL_FUNC (set_ok), &accepted);
+    gtk_signal_connect (GTK_OBJECT (fsel->cancel_button), "clicked",
+                       GTK_SIGNAL_FUNC (gtk_main_quit), NULL);
+    gtk_window_set_position (GTK_WINDOW (fsel), GTK_WIN_POS_MOUSE);
+    
+    /*
+     * Make sure that we quit the main loop if the window is destroyed 
+     */
+    gtk_signal_connect (GTK_OBJECT (fsel), "delete_event",
+                       GTK_SIGNAL_FUNC (file_dialog_delete_event), NULL);
+    
+    /* Run the dialog */
+    gtk_widget_show (GTK_WIDGET (fsel));
+    gtk_grab_add (GTK_WIDGET (fsel));
+    gtk_main ();
+    
+    if (accepted) {
+      char *name = gtk_file_selection_get_filename (fsel);
+      
+      if (name [strlen (name)-1] != '/') {
+/*                     if (app->contains_pdf)
+                       app = application_new ();*/
+       char *fname = g_strdup (name);
+       open_pdf (app, fname);
+       g_free (fname);
+      } else {
+       GtkWidget *dialog;
+       dialog = gnome_message_box_new ("Can't open a directory",
+                                       GNOME_MESSAGE_BOX_ERROR,
+                                       GNOME_STOCK_BUTTON_OK, NULL);
+       gnome_dialog_set_parent (GNOME_DIALOG (dialog),
+                                GTK_WINDOW (app->app));
+       gnome_dialog_run (GNOME_DIALOG (dialog));
+      }
+    }
+    
+    gtk_widget_destroy (GTK_WIDGET (fsel));
+  }
+
+  static void
+  container_destroy (Container *cont)
+  {
+    containers = g_list_remove (containers, cont);
+    gtk_widget_destroy (cont->app);
+    g_free (cont);
+    if (!containers)
+      gtk_main_quit ();
+  }
+  
+  static void
+  container_close_cmd (GtkWidget *widget, Container *cont)
+  {
+    container_destroy (cont);
+  }
+  
+  static void
+  container_exit_cmd (void)
+  {
+    while (containers)
+      container_destroy ((Container *)containers->data);
+  }
+
+  static void
+  component_user_activate_request_cb (GnomeViewFrame *view_frame, gpointer data)
+  {
+    Component *component = (Component *) data;
+    Container *container = component->container;
+    
+    /*
+     * If there is a
+     * If there is already an active View, deactivate it.
+     */
+    if (container->active_view_frame != NULL) {
+      /*
+       * This just sends a notice to the embedded View that
+       * it is being deactivated.  We will also forcibly
+       * cover it so that it does not receive any Gtk
+       * events.
+       */
+      gnome_view_frame_view_deactivate (container->active_view_frame);
+      
+      /*
+       * Here we manually cover it if it hasn't acquiesced.
+       * If it has consented to be deactivated, then it will
+       * already have notified us that it is inactive, and
+       * we will have covered it and set active_view_frame
+       * to NULL.  Which is why this check is here.
+       */
+      if (container->active_view_frame != NULL)
+       gnome_view_frame_set_covered (container->active_view_frame, TRUE);
+      
+      container->active_view_frame = NULL;
+    }
+    
+    /*
+     * Activate the View which the user clicked on.  This just
+     * sends a request to the embedded View to activate itself.
+     * When it agrees to be activated, it will notify its
+     * ViewFrame, and our view_activated_cb callback will be
+     * called.
+     *
+     * We do not uncover the View here, because it may not wish to
+     * be activated, and so we wait until it notifies us that it
+     * has been activated to uncover it.
+     */
+    gnome_view_frame_view_activate (view_frame);
+  }
+  
+  static void
+  component_view_activated_cb (GnomeViewFrame *view_frame, gboolean activated, gpointer data)
+  {
+    Component *component = (Component *) data;
+    Container *container = component->container;
+    
+    if (activated) {
+      /*
+       * If the View is requesting to be activated, then we
+       * check whether or not there is already an active
+       * View.
+       */
+      if (container->active_view_frame != NULL) {
+       g_warning ("View requested to be activated but there is already "
+                  "an active View!\n");
+       return;
+      }
+      
+      /*
+       * Otherwise, uncover it so that it can receive
+       * events, and set it as the active View.
+       */
+      gnome_view_frame_set_covered (view_frame, FALSE);
+      container->active_view_frame = view_frame;
+    } else {
+      /*
+       * If the View is asking to be deactivated, always
+       * oblige.  We may have already deactivated it (see
+       * user_activation_request_cb), but there's no harm in
+       * doing it again.  There is always the possibility
+       * that a View will ask to be deactivated when we have
+       * not told it to deactivate itself, and that is
+       * why we cover the view here.
+       */
+      gnome_view_frame_set_covered (view_frame, TRUE);
+      
+      if (view_frame == container->active_view_frame)
+       container->active_view_frame = NULL;
+    }                                                                       
+  }
+  
+  static void
+  component_user_context_cb (GnomeViewFrame *view_frame, gpointer data)
+  {
+    Component *component = (Component *) data;
+    char *executed_verb;
+    GList *l;
+    
+    /*
+     * See if the remote GnomeEmbeddable supports any verbs at
+     * all.
+     */
+    l = gnome_client_site_get_verbs (component->client_site);
+    if (l == NULL)
+      return;
+    gnome_client_site_free_verbs (l);
+    
+    /*
+     * Popup the verb popup and execute the chosen verb.  This
+     * function saves us the work of creating the menu, connecting
+     * the callback, and executing the verb on the remove
+     * GnomeView.  We could implement all this functionality
+     * ourselves if we wanted.
+     */
+    executed_verb = gnome_view_frame_popup_verbs (view_frame);
+    
+    g_free (executed_verb);
+  }
 }
 
-static GnomeObjectClient *
-launch_server_moniker (GnomeClientSite *client_site, GnomeContainer *container, char *moniker)
+static void
+component_add_view (Component *component)
 {
-       GnomeObjectClient *object_server;
-       
-       gnome_container_add (container, GNOME_OBJECT (client_site));
+       GnomeViewFrame *view_frame;
+       GtkWidget *view_widget;
 
-       printf ("Launching moniker %s...\n", moniker);
-       object_server = gnome_object_activate (moniker, GOAD_ACTIVATE_SHLIB);
-       printf ("Return: %p\n", object_server);
-       if (!object_server){
-               g_warning (_("Can not activate object_server\n"));
-               return NULL;
-       }
+       /*
+        * Create the remote view and the local ViewFrame.
+        */
+       view_frame = gnome_client_site_embeddable_new_view (component->client_site);
+       component->view_frame = view_frame;
 
-       if (!gnome_client_site_bind_embeddable (client_site, object_server)){
-               g_warning (_("Can not bind object server to client_site\n"));
-               return NULL;
-       }
+       /*
+        * Set the GnomeUIHandler for this ViewFrame.  That way, the
+        * embedded component can get access to our UIHandler server
+        * so that it can merge menu and toolbar items when it gets
+        * activated.
+        */
+       gnome_view_frame_set_ui_handler (view_frame, component->container->uih);
 
-       return object_server;
-}
+       /*
+        * Embed the view frame into the application.
+        */
+       view_widget = gnome_view_frame_get_wrapper (view_frame);
+       gtk_box_pack_start (GTK_BOX (component->views_hbox), view_widget,
+                           FALSE, FALSE, 5);
 
-/*
- * This function is called when the user double clicks on a View in
- * order to activate it.
- */
-static gint
-user_activation_request_cb (GnomeViewFrame *view_frame)
-{
        /*
-        * If there is already an active View, deactivate it.
+        * The "user_activate" signal will be emitted when the user
+        * double clicks on the "cover".  The cover is a transparent
+        * window which sits on top of the component and keeps any
+        * events (mouse, keyboard) from reaching it.  When the user
+        * double clicks on the cover, the container (that's us)
+        * can choose to activate the component.
         */
-        if (active_view_frame != NULL) {
-               /*
-                * This just sends a notice to the embedded View that
-                * it is being deactivated.  We will also forcibly
-                * cover it so that it does not receive any Gtk
-                * events.
-                */
-                gnome_view_frame_view_deactivate (active_view_frame);
-
-               /*
-                * Here we manually cover it if it hasn't acquiesced.
-                * If it has consented to be deactivated, then it will
-                * already have notified us that it is inactive, and
-                * we will have covered it and set active_view_frame
-                * to NULL.  Which is why this check is here.
-                */
-               if (active_view_frame != NULL)
-                       gnome_view_frame_set_covered (active_view_frame, TRUE);
-                                                                            
-               active_view_frame = NULL;
-       }
+       gtk_signal_connect (GTK_OBJECT (view_frame), "user_activate",
+                           GTK_SIGNAL_FUNC (component_user_activate_request_cb), component);
 
-        /*
-        * Activate the View which the user clicked on.  This just
-        * sends a request to the embedded View to activate itself.
-        * When it agrees to be activated, it will notify its
-        * ViewFrame, and our view_activated_cb callback will be
-        * called.
-        *
-        * We do not uncover the View here, because it may not wish to
-        * be activated, and so we wait until it notifies us that it
-        * has been activated to uncover it.
+       /*
+        * In-place activation of a component is a two-step process.
+        * After the user double clicks on the component, our signal
+        * callback (compoennt_user_activate_request_cb()) asks the
+        * component to activate itself (see
+        * gnome_view_frame_view_activate()).  The component can then
+        * choose to either accept or refuse activation.  When an
+        * embedded component notifies us of its decision to change
+        * its activation state, the "view_activated" signal is
+        * emitted from the view frame.  It is at that point that we
+        * actually remove the cover so that events can get through.
         */
-        gnome_view_frame_view_activate (view_frame);
+       gtk_signal_connect (GTK_OBJECT (view_frame), "view_activated",
+                           GTK_SIGNAL_FUNC (component_view_activated_cb), component);
 
-        return FALSE;
-}                                                                               
+       /*
+        * The "user_context" signal is emitted when the user right
+        * clicks on the wrapper.  We use it to pop up a verb menu.
+        */
+       gtk_signal_connect (GTK_OBJECT (view_frame), "user_context",
+                           GTK_SIGNAL_FUNC (component_user_context_cb), component);
 
-/*
- * Gets called when the View notifies the ViewFrame that it would like
- * to be activated or deactivated.
- */
-static gint
-view_activated_cb (GnomeViewFrame *view_frame, gboolean activated)
-{
+       /*
+        * Show the component.
+        */
+       gtk_widget_show_all (view_widget);
+}
 
-        if (activated) {
-               /*
-                * If the View is requesting to be activated, then we
-                * check whether or not there is already an active
-                * View.
-                */
-               if (active_view_frame != NULL) {
-                       g_warning ("View requested to be activated but there is already "
-                                  "an active View!\n");
-                       return FALSE;
-               }
-
-               /*
-                * Otherwise, uncover it so that it can receive
-                * events, and set it as the active View.
-                */
-               gnome_view_frame_set_covered (view_frame, FALSE);
-                active_view_frame = view_frame;
-        } else {
-               /*
-                * If the View is asking to be deactivated, always
-                * oblige.  We may have already deactivated it (see
-                * user_activation_request_cb), but there's no harm in
-                * doing it again.  There is always the possibility
-                * that a View will ask to be deactivated when we have
-                * not told it to deactivate itself, and that is
-                * why we cover the view here.
-                */
-               gnome_view_frame_set_covered (view_frame, TRUE);
-
-               if (view_frame == active_view_frame)
-                       active_view_frame = NULL;
-        }                                                                       
-
-        return FALSE;
-}                                                                               
-
-static GnomeViewFrame *
-add_view (Application *app,
-         GnomeClientSite *client_site, GnomeObjectClient *server) 
+static void
+component_new_view_cb (GtkWidget *button, gpointer data)
 {
-       GnomeViewFrame *view_frame;
-       GtkWidget *view_widget;
-       
-       view_frame = gnome_client_site_embeddable_new_view (client_site);
-
-       gtk_signal_connect (GTK_OBJECT (view_frame), "user_activate",
-                           GTK_SIGNAL_FUNC (user_activation_request_cb), NULL);
-       gtk_signal_connect (GTK_OBJECT (view_frame), "view_activated",
-                           GTK_SIGNAL_FUNC (view_activated_cb), NULL);
+       Component *component = (Component *) data;
 
-       gnome_view_frame_set_ui_handler (view_frame, app->uih);
+       component_add_view (component);
+}
 
-       view_widget = gnome_view_frame_get_wrapper (view_frame);
+static void
+component_load_pf_cb (GtkWidget *button, gpointer data)
+{
+}
 
-       gtk_box_pack_start (GTK_BOX (app->box), view_widget, TRUE, TRUE, 0);
-       gtk_widget_show_all (app->box);
+static void
+component_load_ps_cb (GtkWidget *button, gpointer data)
+{
+}
 
-       return view_frame;
-} /* add_view */
+static void
+component_destroy_cb (GtkWidget *button, gpointer data)
+{
+}
 
 static GnomeObjectClient *
-add_cmd (Application *app, char *server_goadid,
-        GnomeClientSite **client_site)
+container_launch_component (GnomeClientSite *client_site,
+                           GnomeContainer *container,
+                           char *component_goad_id)
 {
-       GnomeObjectClient *server;
-       
-       *client_site = gnome_client_site_new (app->container);
+       GnomeObjectClient *object_server;
+
+       /*
+        * Launch the component.
+        */
+       object_server = gnome_object_activate_with_goad_id (
+               NULL, component_goad_id, 0, NULL);
+
+       if (object_server == NULL)
+               return NULL;
 
-       server = launch_server (*client_site, app->container, server_goadid);
-       if (server == NULL)
+       /*
+        * Bind it to the local ClientSite.  Every embedded component
+        * has a local GnomeClientSite object which serves as a
+        * container-side point of contact for the embeddable.  The
+        * container talks to the embeddable through its ClientSite
+        */
+       if (!gnome_client_site_bind_embeddable (client_site, object_server)) {
+               gnome_object_unref (GNOME_OBJECT (object_server));
                return NULL;
+       }
+
+       /*
+        * The GnomeContainer object maintains a list of the
+        * ClientSites which it manages.  Here we add the new
+        * ClientSite to that list.
+        */
+       gnome_container_add (container, GNOME_OBJECT (client_site));
 
-       add_view (app, *client_site, server);
-       return server;
+       return object_server;
 }
 
-static void
-open_pdf (Application *app, const char *name)
+/*
+ * Use query_interface to see if `obj' has `interface'.
+ */
+static gboolean
+gnome_object_has_interface (GnomeObject *obj, char *interface)
 {
-       GnomeObjectClient *object;
-       GnomeStream *stream;
-       GNOME_PersistStream persist;
-
-       object = add_cmd (app, "bonobo-object:image-x-pdf", &image_client_site);
-       if (object == NULL) {
-               gnome_error_dialog (_("Could not launch bonobo object."));
-               return;
-       }
+       CORBA_Environment ev;
+       CORBA_Object requested_interface;
 
-       image_png_obj = object;
+       CORBA_exception_init (&ev);
 
-       persist = GNOME_Unknown_query_interface (
-               gnome_object_corba_objref (GNOME_OBJECT (object)),
-               "IDL:GNOME/PersistStream:1.0", &ev);
+       requested_interface = GNOME_Unknown_query_interface (
+               gnome_object_corba_objref (obj), interface, &ev);
 
-        if (ev._major != CORBA_NO_EXCEPTION ||
-           persist == CORBA_OBJECT_NIL) {
-               gnome_error_dialog ("Panic: component is well broken.");
-                return;
-       }
-       
-       stream = gnome_stream_fs_open (name, GNOME_Storage_READ);
+       CORBA_exception_free (&ev);
 
-       if (stream == NULL) {
-               char *err = g_strconcat (_("Could not open "), name, NULL);
-               gnome_error_dialog_parented (err, GTK_WINDOW(app->app));
-               g_free (err);
-               return;
+       if (!CORBA_Object_is_nil(requested_interface, &ev) &&
+           ev._major == CORBA_NO_EXCEPTION)
+       {
+               /* Get rid of the interface we've been passed */
+               CORBA_Object_release (requested_interface, &ev);
+               return TRUE;
        }
-       
-       GNOME_PersistStream_load (persist,
-            (GNOME_Stream) gnome_object_corba_objref (GNOME_OBJECT (stream)), &ev);
 
-       GNOME_Unknown_unref (persist, &ev);
-       CORBA_Object_release (persist, &ev);
-       app->contains_pdf = TRUE;
+       return FALSE;
 }
 
 static void
-set_ok (GtkWidget *widget, gboolean *dialog_result)
+container_create_component_frame (Container *container, Component *component, char *name)
 {
-       *dialog_result = TRUE;
-       gtk_main_quit ();
+       /*
+        * This hbox will store all the views of the component.
+        */
+       component->views_hbox = gtk_hbox_new (FALSE, 2);
+
+       gtk_box_pack_start (GTK_BOX (container->vbox), component->views_hbox,
+                           TRUE, FALSE, 5);
+       gtk_widget_show_all (component->views_hbox);
 }
 
-static guint
-file_dialog_delete_event (GtkWidget *widget, GdkEventAny *event)
-{
-       gtk_main_quit ();
-       return TRUE;
+extern "C" {
+  static Component *
+  container_activate_component (Container *container, char *component_goad_id)
+  {
+    Component *component;
+    GnomeClientSite *client_site;
+    GnomeObjectClient *server;
+    
+    /*
+     * The ClientSite is the container-side point of contact for
+     * the Embeddable.  So there is a one-to-one correspondence
+     * between GnomeClientSites and GnomeEmbeddables.  */
+    client_site = gnome_client_site_new (container->container);
+    
+    /*
+     * A GnomeObjectClient is a simple wrapper for a remote
+     * GnomeObject (a server supporting GNOME::Unknown).
+     */
+    server = container_launch_component (client_site, container->container,
+                                        component_goad_id);
+    if (server == NULL) {
+      char *error_msg;
+      
+      error_msg = g_strdup_printf (_("Could not launch Embeddable %s!"),
+                                  component_goad_id);
+      gnome_warning_dialog (error_msg);
+      g_free (error_msg);
+      
+      return NULL;
+    }
+    
+    /*
+     * Create the internal data structure which we will use to
+     * keep track of this component.
+     */
+    component = g_new0 (Component, 1);
+    component->container = container;
+    component->client_site = client_site;
+    component->server = server;
+    
+    /*
+     * Now we have a GnomeEmbeddable bound to our local
+     * ClientSite.  Here we create a little on-screen box to store
+     * the embeddable in, when the user adds views for it.
+     */
+    container_create_component_frame (container, component, component_goad_id);
+    
+    component_add_view (component);
+
+    return component;
+  }
 }
 
 static void
-file_open_cmd (GtkWidget *widget, Application *app)
+container_create_menus (Container *container)
 {
-       GtkFileSelection *fsel;
-       gboolean accepted = FALSE;
-
-       fsel = GTK_FILE_SELECTION (gtk_file_selection_new (_("Load file")));
-       gtk_window_set_modal (GTK_WINDOW (fsel), TRUE);
-
-       gtk_window_set_transient_for (GTK_WINDOW (fsel),
-                                     GTK_WINDOW (app->app));
+       GnomeUIHandlerMenuItem *menu_list;
 
-       /* Connect the signals for Ok and Cancel */
-       gtk_signal_connect (GTK_OBJECT (fsel->ok_button), "clicked",
-                           GTK_SIGNAL_FUNC (set_ok), &accepted);
-       gtk_signal_connect (GTK_OBJECT (fsel->cancel_button), "clicked",
-                           GTK_SIGNAL_FUNC (gtk_main_quit), NULL);
-       gtk_window_set_position (GTK_WINDOW (fsel), GTK_WIN_POS_MOUSE);
+       gnome_ui_handler_create_menubar (container->uih);
 
        /*
-        * Make sure that we quit the main loop if the window is destroyed 
+        * Create the basic menus out of UIInfo structures.
         */
-       gtk_signal_connect (GTK_OBJECT (fsel), "delete_event",
-                           GTK_SIGNAL_FUNC (file_dialog_delete_event), NULL);
-
-       /* Run the dialog */
-       gtk_widget_show (GTK_WIDGET (fsel));
-       gtk_grab_add (GTK_WIDGET (fsel));
-       gtk_main ();
-
-       if (accepted) {
-               char *name = gtk_file_selection_get_filename (fsel);
-
-               if (name [strlen (name)-1] != '/') {
-                       if (app->contains_pdf)
-                               app = application_new ();
-                       char *fname = g_strdup (name);
-                       open_pdf (app, fname);
-                       g_free (fname);
-               } else {
-                       GtkWidget *dialog;
-                       dialog = gnome_message_box_new ("Can't open a directory",
-                                                       GNOME_MESSAGE_BOX_ERROR,
-                                                       GNOME_STOCK_BUTTON_OK, NULL);
-                       gnome_dialog_set_parent (GNOME_DIALOG (dialog),
-                                                GTK_WINDOW (app->app));
-                       gnome_dialog_run (GNOME_DIALOG (dialog));
-               }
-       }
-
-       gtk_widget_destroy (GTK_WIDGET (fsel));
+       menu_list = gnome_ui_handler_menu_parse_uiinfo_list_with_data (container_main_menu, container);
+       gnome_ui_handler_menu_add_list (container->uih, "/", menu_list);
+       gnome_ui_handler_menu_free_list (menu_list);
 }
 
 static void
-close_cmd (GtkWidget *widget, Application *app)
+container_create (void)
 {
-       application_destroy (app);
-}
+       Container *container;
 
-static void
-exit_cmd (void)
-{
-       applications_destroy ();
-}
+       container = g_new0 (Container, 1);
 
-static GnomeUIInfo container_file_menu [] = {
-       GNOMEUIINFO_MENU_OPEN_ITEM (file_open_cmd, NULL),
-       GNOMEUIINFO_SEPARATOR,
-       GNOMEUIINFO_MENU_CLOSE_ITEM(close_cmd, NULL),
-       GNOMEUIINFO_SEPARATOR,
-       GNOMEUIINFO_MENU_EXIT_ITEM (exit_cmd, NULL),
-       GNOMEUIINFO_END
-};
+       container->app = gnome_app_new ("sample-container",
+                                       "Sample Bonobo Container");
 
-static GnomeUIInfo container_main_menu [] = {
-       GNOMEUIINFO_MENU_FILE_TREE (container_file_menu),
-       GNOMEUIINFO_END
-};
+       gtk_window_set_default_size (GTK_WINDOW (container->app), 400, 400);
+       gtk_window_set_policy (GTK_WINDOW (container->app), TRUE, TRUE, FALSE);
 
-static Application *
-application_new (void)
-{
-       Application *app;
-       GnomeUIHandlerMenuItem *menu_list;
+       container->container = gnome_container_new ();
 
-       app = g_new0 (Application, 1);
-       app->app = gnome_app_new ("gpdf",
-                                 "GNOME PDF viewer");
-       app->container = GNOME_CONTAINER (gnome_container_new ());
-       app->contains_pdf = FALSE;
+       /*
+        * This is the VBox we will stuff embedded components into.
+        */
+       container->vbox = gtk_vbox_new (FALSE, 0);
+       gnome_app_set_contents (GNOME_APP (container->app), container->vbox);
 
-       app->box = gtk_vbox_new (FALSE, 0);
-       gtk_widget_show (app->box);
-       gnome_app_set_contents (GNOME_APP (app->app), app->box);
+       /*
+        * Create the GnomeUIHandler object which will be used to
+        * create the container's menus and toolbars.  The UIHandler
+        * also creates a CORBA server which embedded components use
+        * to do menu/toolbar merging.
+        */
+       container->uih = gnome_ui_handler_new ();
+       gnome_ui_handler_set_app (container->uih, GNOME_APP (container->app));
 
        /*
         * Create the menus.
         */
-       app->uih = gnome_ui_handler_new ();
-
-       gnome_ui_handler_set_app (app->uih, GNOME_APP (app->app));
-       gnome_ui_handler_create_menubar (app->uih);
-
-       menu_list = gnome_ui_handler_menu_parse_uiinfo_list_with_data (container_main_menu, app);
-       gnome_ui_handler_menu_add_list (app->uih, "/", menu_list);
-       gnome_ui_handler_menu_free_list (menu_list);
-
-/*     gnome_ui_handler_create_toolbar (app->uih, "Common");
-       gnome_ui_handler_toolbar_new_item (app->uih,
-                                          "/Common/item 1",
-                                          "Container-added Item 1", "I am the container.  Hear me roar.",
-                                          0, GNOME_UI_HANDLER_PIXMAP_NONE, NULL, 0, 0,
-                                          NULL, NULL);*/
-
-       gtk_widget_show (app->app);
-
-       apps = g_list_append (apps, app);
-       return app;
+       container_create_menus (container);
+       
+       gtk_widget_show_all (container->app);
 }
 
 int
-main (int argc, char *argv [])
+main (int argc, char **argv)
 {
-       Application *app;
-       char **view_files = NULL;
+       CORBA_Environment ev;
+       CORBA_ORB orb;
 
-       if (argc != 1){
-               server_goadid = argv [1];
-       }
-       
        CORBA_exception_init (&ev);
-       
-       gnome_CORBA_init_with_popt_table ("PDFViewer", "0.0.1",
-                                         &argc, argv,
-                                         gpdf_popt_options, 0, &ctx,
-                                         GNORBA_INIT_SERVER_FUNC, &ev);
-       orb = gnome_CORBA_ORB ();
-       
-       if (bonobo_init (orb, NULL, NULL) == FALSE)
-               g_error (_("Can not bonobo_init\n"));
 
-       app = application_new ();
+       gnome_CORBA_init ("gnome_xpdf_viewer", "0.1", &argc, argv, 0, &ev);
 
-       view_files = poptGetArgs (ctx);
+       CORBA_exception_free (&ev);
 
-       /* Load files */
-       if (view_files) {
-               int i;
-               for (i = 0; view_files[i]; i++) {
-                       if (app->contains_pdf)
-                               app = application_new ();
-                       open_pdf (app, view_files[i]);
-               }
-       }
+       orb = gnome_CORBA_ORB ();
+
+       if (bonobo_init (orb, NULL, NULL) == FALSE)
+               g_error (_("Could not initialize Bonobo!\n"));
 
-       poptFreeContext (ctx);
+       container_create ();
 
        gtk_main ();
 
-       CORBA_exception_free (&ev);
-       
        return 0;
 }