]> www.fi.muni.cz Git - evince.git/blob - pdf/xpdf/gpdf.cc
aa44c4eb83c86a32794b101fcd38331f256a05e9
[evince.git] / pdf / xpdf / gpdf.cc
1 /*
2  * PDF viewer Bonobo container.
3  *
4  * Author:
5  *   Michael Meeks <michael@imaginator.com>
6  */
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <stddef.h>
10 #include <string.h>
11 extern "C" {
12 #define GString G_String
13 #include <gnome.h>
14
15 #include <liboaf/liboaf.h>
16
17 #include <gdk/gdkprivate.h>
18 #include <gdk/gdkx.h>
19 #include <bonobo.h>
20 #undef  GString 
21 }
22 #include "config.h"
23 #include "bonobo-application-x-pdf.h"
24
25 poptContext ctx;
26 gint  gpdf_debug=0;
27
28 const struct poptOption gpdf_popt_options [] = {
29   { "debug", '\0', POPT_ARG_INT, &gpdf_debug, 0,
30     N_("Enables some debugging functions"), N_("LEVEL") },
31   { NULL, '\0', 0, NULL, 0 }
32 };
33
34 typedef struct _Component Component;
35 typedef struct _Container Container;
36 /* NB. there is a 1 to 1 Container -> Component mapping, this
37    is due to how much MDI sucks; unutterably */
38 struct _Container {
39         BonoboItemContainer *container;
40         BonoboUIComponent   *ui_component;
41   
42         GtkWidget           *app;
43         GtkWidget           *slot;
44         GtkWidget           *view_widget;
45         Component           *component;
46 };
47
48 struct  _Component {
49         Container         *container;
50
51         BonoboClientSite   *client_site;
52         BonoboViewFrame   *view_frame;
53         BonoboObjectClient *server;
54 };
55
56 GList *containers = NULL;
57 /*
58  * Static prototypes.
59  */
60 extern "C" {
61   static Container *container_new       (const char *fname);
62   static void       container_destroy   (Container *cont);
63   static void       container_open_cmd  (GtkWidget *widget, Container *container);
64   static void       container_close_cmd (GtkWidget *widget, Container *container);
65   static void       container_exit_cmd  (void);
66   static void       container_about_cmd (GtkWidget *widget, Container *container);
67   static void       container_dump_cmd  (GtkWidget *widget, Container *container);
68   static Component *container_activate_component (Container *container, char *component_goad_id);
69 }
70
71 /*
72  * The menus.
73  */
74 BonoboUIVerb verbs [] = {
75         BONOBO_UI_UNSAFE_VERB ("FileOpen",  container_open_cmd),
76         BONOBO_UI_UNSAFE_VERB ("FileClose", container_close_cmd),
77         BONOBO_UI_UNSAFE_VERB ("FileExit",  container_exit_cmd),
78
79         BONOBO_UI_UNSAFE_VERB ("HelpAbout", container_about_cmd),
80
81         BONOBO_UI_UNSAFE_VERB ("DebugDumpXml", container_dump_cmd),
82
83         BONOBO_UI_VERB_END
84 };
85
86
87 extern "C" {
88   static gboolean
89   open_pdf (Container *container, const char *name)
90   {
91     BonoboObjectClient *object;
92     BonoboStream *stream;
93     Bonobo_PersistStream persist;
94     Component *comp;
95     CORBA_Environment ev;
96
97     g_return_val_if_fail (container != NULL, FALSE);
98     g_return_val_if_fail (container->view_widget == NULL, FALSE);
99
100     comp = container_activate_component (
101             container, "OAFIID:GNOME_XPDF_Embeddable");
102
103     if (!comp || !(object = comp->server)) {
104       gnome_error_dialog (_("Could not launch bonobo object."));
105       return FALSE;
106     }
107     
108     CORBA_exception_init (&ev);
109     persist = Bonobo_Unknown_queryInterface (
110       bonobo_object_corba_objref (BONOBO_OBJECT (object)),
111       "IDL:Bonobo/PersistStream:1.0", &ev);
112     
113     if (ev._major != CORBA_NO_EXCEPTION ||
114         persist == CORBA_OBJECT_NIL) {
115       gnome_error_dialog ("Panic: component doesn't implement PersistStream.");
116       return FALSE;
117     }
118     
119     stream = bonobo_stream_open (BONOBO_IO_DRIVER_FS, name, Bonobo_Storage_READ, 0);
120     
121     if (stream == NULL) {
122       char *err = g_strconcat (_("Could not open "), name, NULL);
123       gnome_error_dialog_parented (err, GTK_WINDOW(container->app));
124       g_free (err);
125       return FALSE;
126     }
127     
128     Bonobo_PersistStream_load (persist,
129                               (Bonobo_Stream) bonobo_object_corba_objref (BONOBO_OBJECT (stream)),
130                                "application/pdf",
131                                &ev);
132
133     Bonobo_Unknown_unref (persist, &ev);
134     CORBA_Object_release (persist, &ev);
135     CORBA_exception_free (&ev);
136
137 /*    bonobo_view_frame_view_do_verb (comp->view_frame, "ZoomFit"); */
138     return TRUE;
139   }
140   
141   static void
142   set_ok (GtkWidget *widget, gboolean *dialog_result)
143   {
144     *dialog_result = TRUE;
145     gtk_main_quit ();
146   }
147   
148   static guint
149   file_dialog_delete_event (GtkWidget *widget, GdkEventAny *event)
150   {
151     gtk_main_quit ();
152     return TRUE;
153   }
154   
155   static void
156   container_open_cmd (GtkWidget *widget, Container *container)
157   {
158     GtkFileSelection *fsel;
159     gboolean accepted = FALSE;
160     
161     fsel = GTK_FILE_SELECTION (gtk_file_selection_new (_("Load file")));
162     gtk_window_set_modal (GTK_WINDOW (fsel), TRUE);
163     
164     gtk_window_set_transient_for (GTK_WINDOW (fsel),
165                                   GTK_WINDOW (container->app));
166     
167     /* Connect the signals for Ok and Cancel */
168     gtk_signal_connect (GTK_OBJECT (fsel->ok_button), "clicked",
169                         GTK_SIGNAL_FUNC (set_ok), &accepted);
170     gtk_signal_connect (GTK_OBJECT (fsel->cancel_button), "clicked",
171                         GTK_SIGNAL_FUNC (gtk_main_quit), NULL);
172     gtk_window_set_position (GTK_WINDOW (fsel), GTK_WIN_POS_MOUSE);
173     
174     /*
175      * Make sure that we quit the main loop if the window is destroyed 
176      */
177     gtk_signal_connect (GTK_OBJECT (fsel), "delete_event",
178                         GTK_SIGNAL_FUNC (file_dialog_delete_event), NULL);
179     
180     /* Run the dialog */
181     gtk_widget_show (GTK_WIDGET (fsel));
182     gtk_grab_add (GTK_WIDGET (fsel));
183     gtk_main ();
184     
185     if (accepted) {
186       char *name = gtk_file_selection_get_filename (fsel);
187       
188       if (name [strlen (name)-1] != '/') {
189         char *fname = g_strdup (name);
190         if (container->view_widget) /* any sort of MDI sucks :-] */
191           container = container_new (fname);
192         else {
193           if (!open_pdf (container, fname))
194             container_destroy (container);
195         }
196         g_free (fname);
197       } else {
198         GtkWidget *dialog;
199         dialog = gnome_message_box_new ("Can't open a directory",
200                                         GNOME_MESSAGE_BOX_ERROR,
201                                         GNOME_STOCK_BUTTON_OK, NULL);
202         gnome_dialog_set_parent (GNOME_DIALOG (dialog),
203                                  GTK_WINDOW (container->app));
204         gnome_dialog_run (GNOME_DIALOG (dialog));
205       }
206     }
207     
208     gtk_widget_destroy (GTK_WIDGET (fsel));
209   }
210
211   static void 
212   component_destroy (Component *component)
213   {
214     CORBA_Environment ev;
215     Container *container;
216     g_return_if_fail (component != NULL);
217
218     CORBA_exception_init (&ev);
219
220     /* Kill merged menus et al. */
221     bonobo_view_frame_view_deactivate (component->view_frame);
222
223     container = component->container;
224     gtk_widget_destroy (container->view_widget);
225     container->view_widget = NULL;
226
227     if (component->server)
228       Bonobo_Unknown_unref (
229         bonobo_object_corba_objref (BONOBO_OBJECT (component->server)), &ev);
230     component->server = NULL;
231
232     CORBA_exception_free (&ev);
233
234     g_free (component);
235   }
236
237   static void
238   container_destroy (Container *cont)
239   {
240     g_return_if_fail (g_list_find (containers, cont) != NULL);
241
242     containers = g_list_remove (containers, cont);
243     if (cont->app)
244       gtk_widget_destroy (cont->app);
245     cont->app = NULL;
246     
247     if (cont->component)
248       component_destroy (cont->component);
249     cont->component = NULL;
250     
251     g_free (cont);
252
253     if (!containers)
254       gtk_main_quit ();
255   }
256
257   static void
258   container_close (Container *cont)
259   {
260     g_return_if_fail (g_list_find (containers, cont) != NULL);
261     
262     if (cont->component) {
263       component_destroy (cont->component);
264       cont->component = NULL;
265     } else
266       container_destroy (cont);
267   }
268
269   
270   static void
271   container_close_cmd (GtkWidget *widget, Container *cont)
272   {
273     container_close (cont);
274   }
275   
276   static int
277   container_destroy_cb (GtkWidget *widget, GdkEvent *event, Container *cont)
278   {
279     container_destroy (cont);
280     return 1;
281   }
282   
283   static void
284   container_exit_cmd (void)
285   {
286     while (containers)
287       container_destroy ((Container *)containers->data);
288   }
289
290 static void
291 container_dump_cmd (GtkWidget *widget, Container *container)
292 {
293         bonobo_window_dump (BONOBO_WINDOW(container->app), "on demand");
294 }
295
296 static void
297 container_about_cmd (GtkWidget *widget, Container *container)
298 {
299   GtkWidget *about;
300
301   const gchar *authors[] = {
302     N_("Derek B. Noonburg, main author"),
303     N_("Michael Meeks, GNOME port maintainer."),
304     N_("Miguel de Icaza."),
305     N_("Nat Friedman."),
306     NULL
307   };
308   
309 #ifdef ENABLE_NLS
310   int i;
311
312   for (i = 0; authors[i] != NULL; i++)
313     authors [i] = _(authors [i]);
314 #endif
315   
316   about = gnome_about_new (_("GPDF"), xpdfVersion,
317                            _("(C) 1996-1999 Derek B. Noonburg."),
318                            authors, NULL, NULL);
319   
320   gnome_dialog_set_parent (GNOME_DIALOG (about), GTK_WINDOW (container->app));
321   gnome_dialog_set_close (GNOME_DIALOG (about), TRUE);
322   gtk_widget_show (about);
323 }
324 }
325
326 static void
327 container_set_view (Container *container, Component *component)
328 {
329         BonoboViewFrame *view_frame;
330         GtkWidget *view_widget;
331
332         /*
333          * Create the remote view and the local ViewFrame.
334          */
335         view_frame = bonobo_client_site_new_view (
336                 component->client_site,
337                 bonobo_ui_component_get_container (container->ui_component));
338
339         component->view_frame = view_frame;
340
341         /*
342          * Embed the view frame into the application.
343          */
344         view_widget = bonobo_view_frame_get_wrapper (view_frame);
345         bonobo_wrapper_set_visibility (BONOBO_WRAPPER (view_widget), FALSE);
346         container->view_widget = view_widget;
347         container->component   = component;
348
349         gtk_container_add (GTK_CONTAINER (container->slot), view_widget);
350
351         /*
352          * Activate it ( get it to merge menus etc. )
353          */
354         bonobo_view_frame_view_activate (view_frame);
355         bonobo_view_frame_set_covered   (view_frame, FALSE);
356
357         gtk_widget_show_all (GTK_WIDGET (container->slot));
358 }
359
360 static BonoboObjectClient *
361 container_launch_component (BonoboClientSite    *client_site,
362                             BonoboItemContainer *container,
363                             char                *component_goad_id)
364 {
365         BonoboObjectClient *object_server;
366
367         /*
368          * Launch the component.
369          */
370         object_server = bonobo_object_activate (component_goad_id, 0);
371
372         if (object_server == NULL)
373                 return NULL;
374
375         /*
376          * Bind it to the local ClientSite.  Every embedded component
377          * has a local BonoboClientSite object which serves as a
378          * container-side point of contact for the embeddable.  The
379          * container talks to the embeddable through its ClientSite
380          */
381         if (!bonobo_client_site_bind_embeddable (client_site, object_server)) {
382                 bonobo_object_unref (BONOBO_OBJECT (object_server));
383                 return NULL;
384         }
385
386         return object_server;
387 }
388
389 extern "C" {
390   static Component *
391   container_activate_component (Container *container, char *component_goad_id)
392   {
393     Component *component;
394     BonoboClientSite *client_site;
395     BonoboObjectClient *server;
396     
397     /*
398      * The ClientSite is the container-side point of contact for
399      * the Embeddable.  So there is a one-to-one correspondence
400      * between BonoboClientSites and BonoboEmbeddables.  */
401     client_site = bonobo_client_site_new (container->container);
402     
403     /*
404      * A BonoboObjectClient is a simple wrapper for a remote
405      * BonoboObject (a server supporting Bonobo::Unknown).
406      */
407     server = container_launch_component (client_site, container->container,
408                                          component_goad_id);
409     if (server == NULL) {
410       char *error_msg;
411       
412       error_msg = g_strdup_printf (_("Could not launch Embeddable %s!"),
413                                    component_goad_id);
414       gnome_warning_dialog (error_msg);
415       g_free (error_msg);
416       
417       return NULL;
418     }
419     
420     /*
421      * Create the internal data structure which we will use to
422      * keep track of this component.
423      */
424     component = g_new0 (Component, 1);
425     component->container = container;
426     component->client_site = client_site;
427     component->server = server;
428     
429     container_set_view (container, component);
430
431     return component;
432   }
433   
434   static void
435   filenames_dropped (GtkWidget * widget,
436                      GdkDragContext   *context,
437                      gint              x,
438                      gint              y,
439                      GtkSelectionData *selection_data,
440                      guint             info,
441                      guint             time,
442                      Container        *container)
443   {
444     GList *names, *tmp_list;
445     
446     names = gnome_uri_list_extract_filenames ((char *)selection_data->data);
447     tmp_list = names;
448     
449     while (tmp_list) {
450       const char *fname = (const char *)tmp_list->data;
451
452       if (fname) {
453         if (container->view_widget)
454           container = container_new (fname);
455         else
456           open_pdf (container, fname);
457       }
458
459       tmp_list = g_list_next (tmp_list);
460     }
461   }
462 }
463
464 static Container *
465 container_new (const char *fname)
466 {
467         Container *container;
468         static GtkTargetEntry drag_types[] =
469         {
470           { "text/uri-list", 0, 0 },
471         };
472         static gint n_drag_types = sizeof (drag_types) / sizeof (drag_types [0]);
473         BonoboUIContainer *ui_container;
474         
475         container = g_new0 (Container, 1);
476
477         container->app = bonobo_window_new ("pdf-viewer",
478                                          "GNOME PDF viewer");
479
480         gtk_drag_dest_set (container->app,
481                            GTK_DEST_DEFAULT_ALL,
482                            drag_types, n_drag_types,
483                            GDK_ACTION_COPY);
484
485         gtk_signal_connect (GTK_OBJECT(container->app),
486                             "drag_data_received",
487                             GTK_SIGNAL_FUNC(filenames_dropped),
488                             (gpointer)container);
489
490         gtk_window_set_default_size (GTK_WINDOW (container->app), 600, 600);
491         gtk_window_set_policy (GTK_WINDOW (container->app), TRUE, TRUE, FALSE);
492
493         container->container   = bonobo_item_container_new ();
494         container->view_widget = NULL;
495         container->slot = gtk_event_box_new ();
496         gtk_widget_show (container->slot);
497
498         bonobo_window_set_contents (BONOBO_WINDOW(container->app),
499                                  GTK_WIDGET (container->slot));
500         gtk_widget_show_all (container->slot);
501
502         gtk_object_set_data (GTK_OBJECT (container->app), "container_data", container);
503         gtk_signal_connect  (GTK_OBJECT (container->app), "delete_event",
504                              GTK_SIGNAL_FUNC (container_destroy_cb), container);
505
506         ui_container = bonobo_ui_container_new ();
507         bonobo_ui_container_set_win (ui_container, BONOBO_WINDOW(container->app));
508
509         container->ui_component = bonobo_ui_component_new ("gpdf");
510         bonobo_ui_component_set_container (
511                 container->ui_component,
512                 bonobo_object_corba_objref (BONOBO_OBJECT (ui_container)));
513
514         bonobo_ui_component_add_verb_list_with_data (
515                 container->ui_component, verbs, container);
516
517         bonobo_ui_util_set_ui (container->ui_component, DATADIR, "gpdf-ui.xml", "gpdf");
518
519         gtk_widget_show (container->app);
520
521         containers = g_list_append (containers, container);
522
523         if (fname)
524           if (!open_pdf (container, fname)) {
525             container_destroy (container);
526             return NULL;
527           }
528
529         gtk_widget_show (container->app);
530
531         return container;
532 }
533
534 int
535 main (int argc, char **argv)
536 {
537   CORBA_Environment ev;
538   CORBA_ORB         orb;
539   const char      **view_files = NULL;
540   gboolean          loaded;
541   int               i;
542   
543   CORBA_exception_init (&ev);
544   
545
546   gnomelib_register_popt_table (oaf_popt_options, "OAF");
547   gnome_init_with_popt_table("PDFViewer", "0.0.1",
548                              argc, argv,
549                              gpdf_popt_options, 0, &ctx); 
550   orb = oaf_init (argc, argv);
551
552   CORBA_exception_free (&ev);
553
554   if (bonobo_init (orb, NULL, NULL) == FALSE)
555     g_error (_("Could not initialize Bonobo!\n"));
556   bonobo_activate ();
557
558   view_files = poptGetArgs (ctx);
559
560   /* Load files */
561   i = 0;
562   loaded = FALSE;
563   if (view_files) {
564     for (i = 0; view_files[i]; i++)
565       if (container_new (view_files[i])) {
566         loaded = TRUE;
567         while (gtk_events_pending ())
568           gtk_main_iteration ();
569       }
570   }
571   if ((i == 0) || !loaded)
572     container_new (NULL);
573   
574   poptFreeContext (ctx);
575
576   gtk_main ();
577         
578   return 0;
579 }