2 * image/x-pdf BonoboObject.
5 * Michael Meeks <michael@imaginator.com>
14 #define GString G_String
16 #include <libgnorba/gnorba.h>
17 #include <bonobo/gnome-bonobo.h>
22 #include "parseargs.h"
34 #include "GOutputDev.h"
35 #include "PSOutputDev.h"
36 #include "TextOutputDev.h"
40 #include "BonoboStream.h"
44 GBool printCommands = gFalse;
47 * Number of servers running on the system
48 * when the count reaches zero, we unregister from the
49 * Name Server and we shut down.
51 static int embeddable_servers = 0;
54 * Our embeddable factory
56 static GnomeEmbeddableFactory *factory;
58 /* This lock protects the global PDF 'xref' variable */
65 GnomeEmbeddable *embeddable;
68 XRef *xref; /* Ugly global XRef hack fix */
70 BonoboStream *pdf_stream;
71 GNOME_Stream bonobo_stream;
84 GtkWidget *drawing_area;
95 xref_do_lock (bed_t *bed)
97 g_return_if_fail (bed != NULL);
99 g_mutex_lock (xref_lock);
100 xref = bed->xref; /* Ugly global XRef hack fix */
104 xref_do_unlock (bed_t *bed)
107 g_mutex_unlock (xref_lock);
112 static void realize_drawing_areas (bed_t *bed);
113 static void setup_pixmap (bed_t *doc, view_data_t *view, GdkWindow *window);
117 redraw_view (view_data_t *view_data, GdkRectangle *rect)
120 bed_t *bed = view_data->bed;
122 g_return_if_fail (view_data->pixmap != NULL);
125 * Do not draw outside the region that we know how to display
127 if (rect->x > view_data->w)
130 if (rect->y > view_data->h)
134 * Clip the draw region
136 if (rect->x + rect->width > view_data->w)
137 rect->width = view_data->w - rect->x;
139 if (rect->y + rect->height > view_data->h)
140 rect->height = view_data->h - rect->y;
143 * Draw the exposed region.
145 gdk_draw_pixmap (view_data->drawing_area->window,
146 view_data->drawing_area->style->white_gc,
155 configure_size (view_data_t *view_data)
157 gtk_widget_set_usize (
158 view_data->drawing_area,
164 render_page (view_data_t *view_data)
166 setup_pixmap (view_data->bed, view_data,
169 xref_do_lock (view_data->bed);
170 view_data->out->startDoc();
171 view_data->bed->pdf->displayPage (view_data->out,
172 view_data->page, view_data->zoom,
174 xref_do_unlock (view_data->bed);
178 redraw_view_all (view_data_t *view_data)
181 g_return_if_fail (view_data != NULL);
184 printf ("Redraw view of page %d\n", view_data->page);
186 render_page (view_data);
189 rect.width = view_data->w;
190 rect.height = view_data->h;
191 redraw_view (view_data, &rect);
192 gtk_widget_queue_draw (GTK_WIDGET (view_data->drawing_area));
196 redraw_all (bed_t *bed)
200 for (l = bed->views; l; l = l->next) {
202 view_data_t *view_data = (view_data_t *)l->data;
203 redraw_view_all (view_data);
208 save_image (GnomePersistStream *ps, GNOME_Stream stream, void *data)
210 g_warning ("Unimplemented");
218 setup_size (bed_t *doc, view_data_t *view_data)
223 if (!doc || !view_data || !doc->pdf) {
228 xref_do_lock (view_data->bed);
229 w = (int)((doc->pdf->getPageWidth (view_data->page)
230 * view_data->zoom) / 72.0);
231 h = (int)((doc->pdf->getPageHeight (view_data->page)
232 * view_data->zoom) / 72.0);
233 xref_do_unlock (view_data->bed);
235 if (view_data->w == w && view_data->h == h)
246 bed_free_data (bed_t *bed)
248 g_return_if_fail (bed != NULL);
254 xref_do_unlock (bed);
257 delete (bed->pdf_stream);
258 bed->pdf_stream = NULL;
260 if (bed->bonobo_stream) {
261 CORBA_Environment ev;
262 CORBA_exception_init (&ev);
263 CORBA_Object_release (bed->bonobo_stream, &ev);
264 bed->bonobo_stream = NULL;
265 CORBA_exception_free (&ev);
270 * Loads a PDF from a GNOME_Stream
273 load_image_from_stream (GnomePersistStream *ps, GNOME_Stream stream, void *data)
275 bed_t *bed = (bed_t *)data;
277 GNOME_Stream_iobuf *buffer;
278 CORBA_Environment ev;
285 if (bed->pdf || bed->pdf_stream ||
286 bed->bonobo_stream) {
287 g_warning ("Won't overwrite pre-existing stream: you wierdo");
290 CORBA_exception_init (&ev);
292 /* We need this for later */
293 CORBA_Object_duplicate (stream, &ev);
294 bed->bonobo_stream = stream;
295 g_return_val_if_fail (ev._major == CORBA_NO_EXCEPTION, 0);
298 printf ("Loading PDF from persiststream\n");
302 bed->pdf_stream = new BonoboStream (stream, 0, -1, &obj);
303 bed->pdf = new PDFDoc (bed->pdf_stream);
304 bed->xref = xref; /* Ugly global XRef hack fix */
308 printf ("Done load\n");
310 if (!(bed->pdf->isOk())) {
311 g_warning ("Duff pdf data\n");
314 if (!bed->pdf->getCatalog()) {
315 g_warning ("Duff pdf catalog\n");
318 xref_do_unlock (bed);
320 realize_drawing_areas (bed);
323 CORBA_exception_free (&ev);
330 destroy_view (GnomeView *view, view_data_t *view_data)
332 view_data->bed->views = g_list_remove (view_data->bed->views, view_data);
333 gtk_object_unref (GTK_OBJECT (view_data->drawing_area));
339 destroy_embed (GnomeView *view, bed_t *bed)
341 CORBA_Environment ev;
343 printf ("Destroying embedded component\n");
346 destroy_view (NULL, (view_data_t *)bed->views->data);
351 embeddable_servers--;
353 if (embeddable_servers == 0){
354 gnome_object_unref (GNOME_OBJECT (factory));
360 setup_pixmap (bed_t *doc, view_data_t *view_data, GdkWindow *window)
362 GdkGCValues gcValues;
366 GdkPixmap *pixmap = NULL;
368 g_return_if_fail (doc != NULL);
369 g_return_if_fail (doc->pdf != NULL);
370 g_return_if_fail (view_data != NULL);
374 if (setup_size (doc, view_data) &&
377 printf ("No need to re-init output device\n");
385 pixmap = gdk_pixmap_new (window, w, h, -1);
387 gdk_color_white (gtk_widget_get_default_colormap(), &view_data->paper);
388 view_data->out = new GOutputDev (pixmap, view_data->paper, window);
390 gdk_color_white (gtk_widget_get_default_colormap (), &gcValues.foreground);
391 gdk_color_black (gtk_widget_get_default_colormap (), &gcValues.background);
392 gcValues.line_width = 1;
393 gcValues.line_style = GDK_LINE_SOLID;
394 strokeGC = gdk_gc_new_with_values (
396 (enum GdkGCValuesMask)(GDK_GC_FOREGROUND | GDK_GC_BACKGROUND | GDK_GC_LINE_WIDTH | GDK_GC_LINE_STYLE));
398 gdk_draw_rectangle (pixmap, strokeGC,
402 view_data->pixmap = pixmap;
403 configure_size (view_data);
407 view_is_good (view_data_t *view_data)
411 !view_data->bed->pdf)
418 first_page (view_data_t *view_data)
420 g_return_val_if_fail (view_is_good (view_data), FALSE);
421 if (view_data->page != 1) {
429 last_page (view_data_t *view_data)
431 g_return_val_if_fail (view_is_good (view_data), FALSE);
432 if (view_data->page < view_data->bed->pdf->getNumPages()) {
433 view_data->page = view_data->bed->pdf->getNumPages();
440 next_page (view_data_t *view_data)
442 g_return_val_if_fail (view_is_good (view_data), FALSE);
443 if (view_data->page < view_data->bed->pdf->getNumPages()) {
451 prev_page (view_data_t *view_data)
453 g_return_val_if_fail (view_is_good (view_data), FALSE);
454 if (view_data->page > 1) {
462 page_first_cb (GnomeUIHandler *uih, void *data, char *path)
464 first_page ((view_data_t *)data);
465 redraw_view_all ((view_data_t *)data);
469 page_next_cb (GnomeUIHandler *uih, void *data, char *path)
471 next_page ((view_data_t *)data);
472 redraw_view_all ((view_data_t *)data);
476 page_prev_cb (GnomeUIHandler *uih, void *data, char *path)
478 prev_page ((view_data_t *)data);
479 redraw_view_all ((view_data_t *)data);
483 page_last_cb (GnomeUIHandler *uih, void *data, char *path)
485 last_page ((view_data_t *)data);
486 redraw_view_all ((view_data_t *)data);
491 view_create_menus (view_data_t *view_data)
493 GNOME_UIHandler remote_uih;
494 GnomeView *view = view_data->view;
497 uih = gnome_view_get_ui_handler (view);
498 remote_uih = gnome_view_get_remote_ui_handler (view);
500 if (remote_uih == CORBA_OBJECT_NIL) {
501 g_warning ("server has no UI hander");
505 gnome_ui_handler_set_container (uih, remote_uih);
507 gnome_ui_handler_menu_new_subtree (uih, "/Page",
509 N_("Set the currently displayed page"),
511 GNOME_UI_HANDLER_PIXMAP_NONE, NULL,
512 0, (GdkModifierType)0);
514 gnome_ui_handler_menu_new_item (uih, "/Page/First",
515 N_("First"), N_("View the first page"), -1,
516 GNOME_UI_HANDLER_PIXMAP_NONE, NULL, 0,
517 (GdkModifierType)0, page_first_cb, (gpointer)view_data);
519 gnome_ui_handler_menu_new_item (uih, "/Page/Prev",
520 N_("Previous"), N_("View the previous page"), -1,
521 GNOME_UI_HANDLER_PIXMAP_NONE, NULL, 0,
522 (GdkModifierType)0, page_prev_cb, (gpointer)view_data);
524 gnome_ui_handler_menu_new_item (uih, "/Page/Next",
525 N_("Next"), N_("View the next page"), -1,
526 GNOME_UI_HANDLER_PIXMAP_NONE, NULL, 0,
527 (GdkModifierType)0, page_next_cb, (gpointer)view_data);
529 gnome_ui_handler_menu_new_item (uih, "/Page/Last",
530 N_("Last"), N_("View the last page"), -1,
531 GNOME_UI_HANDLER_PIXMAP_NONE, NULL, 0,
532 (GdkModifierType)0, page_last_cb, (gpointer)view_data);
534 gnome_ui_handler_toolbar_new_item (uih, "/First",
535 N_("First"), N_("View the first page"), -1,
536 GNOME_UI_HANDLER_PIXMAP_STOCK, GNOME_STOCK_PIXMAP_FIRST,
537 0, (GdkModifierType)0, page_first_cb, (gpointer)view_data);
538 gnome_ui_handler_toolbar_new_item (uih, "/Prev",
539 N_("Previous"), N_("View the previous page"), -1,
540 GNOME_UI_HANDLER_PIXMAP_STOCK, GNOME_STOCK_PIXMAP_BACK,
541 0, (GdkModifierType)0, page_prev_cb, (gpointer)view_data);
542 gnome_ui_handler_toolbar_new_item (uih, "/Next",
543 N_("Next"), N_("View the next page"), -1,
544 GNOME_UI_HANDLER_PIXMAP_STOCK, GNOME_STOCK_PIXMAP_FORWARD,
545 0, (GdkModifierType)0, page_next_cb, (gpointer)view_data);
546 gnome_ui_handler_toolbar_new_item (uih, "/Last",
547 N_("Last"), N_("View the last page"), -1,
548 GNOME_UI_HANDLER_PIXMAP_STOCK, GNOME_STOCK_PIXMAP_LAST,
549 0, (GdkModifierType)0, page_last_cb, (gpointer)view_data);
553 * When this view is deactivated, we must remove our menu items.
556 view_remove_menus (view_data_t *view_data)
558 GnomeView *view = view_data->view;
561 uih = gnome_view_get_ui_handler (view);
563 gnome_ui_handler_unset_container (uih);
569 drawing_area_realize (GtkWidget *drawing_area, view_data_t *view_data)
571 g_return_if_fail (view_data != NULL);
572 g_return_if_fail (drawing_area != NULL);
574 view_data->win = gtk_widget_get_parent_window (drawing_area);
578 drawing_area_exposed (GtkWidget *widget, GdkEventExpose *event, view_data_t *view_data)
581 !view_data->bed->pdf)
584 redraw_view (view_data, &event->area);
590 view_activate (GnomeView *view, gboolean activate, gpointer data)
592 view_data_t *view_data = (view_data_t *) data;
593 g_return_if_fail (view != NULL);
594 g_return_if_fail (view_data != NULL);
596 gnome_view_activate_notify (view, activate);
599 printf ("View change activation to %d\n", activate);
602 * If we were just activated, we merge in our menu entries.
603 * If we were just deactivated, we remove them.
606 view_create_menus (view_data);
608 view_remove_menus (view_data);
612 view_size_query (GnomeView *view, int *desired_width, int *desired_height,
615 view_data_t *view_data = (view_data_t *) data;
617 g_return_if_fail (view_data != NULL);
619 *desired_width = view_data->w;
620 *desired_height = view_data->h;
624 view_zoom_query (GnomeView *view, gdouble new_zoom, gpointer data)
626 view_data_t *view_data = (view_data_t *) data;
628 g_return_if_fail (view_data != NULL);
630 /* The rational behind this is that the _entire_ page is allocated
631 regardless of viewport size, so you _really_ don't want it too big ! */
632 g_return_if_fail (new_zoom > 10.0);
633 g_return_if_fail (new_zoom < 180.0);
635 view_data->zoom = new_zoom;
636 redraw_view_all (view_data);
640 realize_drawing_areas (bed_t *bed)
644 for (l = bed->views; l; l = l->next) {
645 view_data_t *view_data = (view_data_t *)l->data;
646 g_return_if_fail (view_data->win);
647 render_page (view_data);
648 configure_size (view_data);
653 view_switch_page (GnomeView *view, const char *verb_name, void *user_data)
655 view_data_t *view_data = (view_data_t *) user_data;
657 gboolean changed = FALSE;
659 if (!g_strcasecmp (verb_name, "firstpage")) {
660 changed = first_page (view_data);
661 } else if (!g_strcasecmp (verb_name, "prevpage")) {
662 changed = prev_page (view_data);
663 } else if (!g_strcasecmp (verb_name, "nextpage")) {
664 changed = next_page (view_data);
665 } else if (!g_strcasecmp (verb_name, "lastpage")) {
666 changed = last_page (view_data);
668 g_warning ("Unknown verb");
671 render_page (view_data);
672 redraw_view (view_data, &rect);
673 gtk_widget_queue_draw (GTK_WIDGET (view_data->drawing_area));
679 view_factory (GnomeEmbeddable *embeddable,
680 const GNOME_ViewFrame view_frame,
685 bed_t *bed = (bed_t *)data;
686 view_data_t *view_data = g_new (view_data_t, 1);
689 printf ("Created new bonobo object view %p\n", view_data);
692 view_data->scale = 1.0;
693 view_data->bed = bed;
694 view_data->drawing_area = gtk_drawing_area_new ();
695 view_data->pixmap = NULL;
696 view_data->win = NULL;
697 view_data->out = NULL;
700 view_data->zoom = 43.0; /* 86.0; Must be small for demos :-) */
704 GTK_OBJECT (view_data->drawing_area),
706 GTK_SIGNAL_FUNC (drawing_area_realize), view_data);
709 GTK_OBJECT (view_data->drawing_area),
711 GTK_SIGNAL_FUNC (drawing_area_exposed), view_data);
713 gtk_widget_show (view_data->drawing_area);
715 setup_size (bed, view_data);
717 view = gnome_view_new (view_data->drawing_area);
718 view_data->view = view;
721 GTK_OBJECT (view), "destroy",
722 GTK_SIGNAL_FUNC (destroy_view), view_data);
725 uih = gnome_ui_handler_new ();
726 gnome_view_set_ui_handler (view, uih);
728 gtk_signal_connect (GTK_OBJECT (view), "view_activate",
729 GTK_SIGNAL_FUNC (view_activate), view_data);
731 gtk_signal_connect (GTK_OBJECT (view), "size_query",
732 GTK_SIGNAL_FUNC (view_size_query), view_data);
734 gtk_signal_connect (GTK_OBJECT (view), "set_zoom_factor",
735 GTK_SIGNAL_FUNC (view_zoom_query), view_data);
737 bed->views = g_list_prepend (bed->views, view_data);
740 gnome_view_register_verb (view, "FirstPage",
741 view_switch_page, view_data);
742 gnome_view_register_verb (view, "PrevPage",
743 view_switch_page, view_data);
744 gnome_view_register_verb (view, "NextPage",
745 view_switch_page, view_data);
746 gnome_view_register_verb (view, "LastPage",
747 view_switch_page, view_data);
753 embeddable_factory (GnomeEmbeddableFactory *This, void *data)
755 GnomeEmbeddable *embeddable;
756 GnomePersistStream *stream;
757 bed_t *bed = (bed_t *)data;
759 bed = g_new0 (bed_t, 1);
764 printf ("Created new bonobo object %p\n", bed);
767 * Creates the BonoboObject server
769 embeddable = gnome_embeddable_new (view_factory, bed);
770 if (embeddable == NULL){
778 * Interface GNOME::PersistStream
780 stream = gnome_persist_stream_new ("bonobo-object:image-x-pdf",
781 load_image_from_stream,
784 if (stream == NULL) {
785 gtk_object_unref (GTK_OBJECT (embeddable));
790 bed->embeddable = embeddable;
793 * Bind the interfaces
795 gnome_object_add_interface (GNOME_OBJECT (embeddable),
796 GNOME_OBJECT (stream));
798 GTK_OBJECT (embeddable), "destroy",
799 GTK_SIGNAL_FUNC (destroy_embed), bed);
801 embeddable_servers++;
803 /* Setup some verbs */
804 gnome_embeddable_add_verb (embeddable,
807 _("goto the first page"));
808 gnome_embeddable_add_verb (embeddable,
811 _("goto the previous page"));
812 gnome_embeddable_add_verb (embeddable,
815 _("goto the next page"));
816 gnome_embeddable_add_verb (embeddable,
819 _("goto the last page"));
821 return (GnomeObject *) embeddable;
825 init_bonobo_image_x_pdf_factory (void)
827 factory = gnome_embeddable_factory_new (
828 "bonobo-object-factory:image-x-pdf",
829 embeddable_factory, NULL);
838 init_server_factory (int argc, char **argv)
840 CORBA_Environment ev;
842 CORBA_exception_init (&ev);
844 gnome_CORBA_init_with_popt_table (
845 "bonobo-image-x-pdf", "1.0",
846 &argc, argv, NULL, 0, NULL, GNORBA_INIT_SERVER_FUNC, &ev);
848 if (bonobo_init (CORBA_OBJECT_NIL, CORBA_OBJECT_NIL, CORBA_OBJECT_NIL) == FALSE)
849 g_error (_("I could not initialize Bonobo"));
851 CORBA_exception_free (&ev);
855 main (int argc, char *argv [])
857 g_thread_init (NULL);
858 xref_lock = g_mutex_new ();
860 init_server_factory (argc, argv);
861 if (!init_bonobo_image_x_pdf_factory ()) {
862 fprintf (stderr, "Could not initialize the Bonobo PDF factory\n"
863 "probably a server is already running?");
869 initParams (xpdfConfigFile); /* Init font path */
871 gtk_widget_set_default_colormap (gdk_rgb_get_cmap ());
872 gtk_widget_set_default_visual (gdk_rgb_get_visual ());
877 g_mutex_free (xref_lock);