]> www.fi.muni.cz Git - evince.git/blob - pdf/xpdf/gpdf.cc
update for Dietmer internal changes.
[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:gpdf_component:892f2727-e2ec-423c-91ad-6f7b75fec6c8");
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_query_interface (
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_win_dump (BONOBO_WIN (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         /*
387          * The BonoboContainer object maintains a list of the
388          * ClientSites which it manages.  Here we add the new
389          * ClientSite to that list.
390          */
391         bonobo_item_container_add (container, BONOBO_OBJECT (client_site));
392
393         return object_server;
394 }
395
396 extern "C" {
397   static Component *
398   container_activate_component (Container *container, char *component_goad_id)
399   {
400     Component *component;
401     BonoboClientSite *client_site;
402     BonoboObjectClient *server;
403     
404     /*
405      * The ClientSite is the container-side point of contact for
406      * the Embeddable.  So there is a one-to-one correspondence
407      * between BonoboClientSites and BonoboEmbeddables.  */
408     client_site = bonobo_client_site_new (container->container);
409     
410     /*
411      * A BonoboObjectClient is a simple wrapper for a remote
412      * BonoboObject (a server supporting Bonobo::Unknown).
413      */
414     server = container_launch_component (client_site, container->container,
415                                          component_goad_id);
416     if (server == NULL) {
417       char *error_msg;
418       
419       error_msg = g_strdup_printf (_("Could not launch Embeddable %s!"),
420                                    component_goad_id);
421       gnome_warning_dialog (error_msg);
422       g_free (error_msg);
423       
424       return NULL;
425     }
426     
427     /*
428      * Create the internal data structure which we will use to
429      * keep track of this component.
430      */
431     component = g_new0 (Component, 1);
432     component->container = container;
433     component->client_site = client_site;
434     component->server = server;
435     
436     container_set_view (container, component);
437
438     return component;
439   }
440   
441   static void
442   filenames_dropped (GtkWidget * widget,
443                      GdkDragContext   *context,
444                      gint              x,
445                      gint              y,
446                      GtkSelectionData *selection_data,
447                      guint             info,
448                      guint             time,
449                      Container        *container)
450   {
451     GList *names, *tmp_list;
452     
453     names = gnome_uri_list_extract_filenames ((char *)selection_data->data);
454     tmp_list = names;
455     
456     while (tmp_list) {
457       const char *fname = (const char *)tmp_list->data;
458
459       if (fname) {
460         if (container->view_widget)
461           container = container_new (fname);
462         else
463           open_pdf (container, fname);
464       }
465
466       tmp_list = g_list_next (tmp_list);
467     }
468   }
469 }
470
471 static Container *
472 container_new (const char *fname)
473 {
474         Container *container;
475         static GtkTargetEntry drag_types[] =
476         {
477           { "text/uri-list", 0, 0 },
478         };
479         static gint n_drag_types = sizeof (drag_types) / sizeof (drag_types [0]);
480         BonoboUIContainer *ui_container;
481         
482         container = g_new0 (Container, 1);
483
484         container->app = bonobo_win_new ("pdf-viewer",
485                                          "GNOME PDF viewer");
486
487         gtk_drag_dest_set (container->app,
488                            GTK_DEST_DEFAULT_ALL,
489                            drag_types, n_drag_types,
490                            GDK_ACTION_COPY);
491
492         gtk_signal_connect (GTK_OBJECT(container->app),
493                             "drag_data_received",
494                             GTK_SIGNAL_FUNC(filenames_dropped),
495                             (gpointer)container);
496
497         gtk_window_set_default_size (GTK_WINDOW (container->app), 600, 600);
498         gtk_window_set_policy (GTK_WINDOW (container->app), TRUE, TRUE, FALSE);
499
500         container->container   = bonobo_item_container_new ();
501         container->view_widget = NULL;
502         container->slot = gtk_event_box_new ();
503         gtk_widget_show (container->slot);
504
505         bonobo_win_set_contents (BONOBO_WIN (container->app),
506                                  GTK_WIDGET (container->slot));
507         gtk_widget_show_all (container->slot);
508
509         gtk_object_set_data (GTK_OBJECT (container->app), "container_data", container);
510         gtk_signal_connect  (GTK_OBJECT (container->app), "delete_event",
511                              GTK_SIGNAL_FUNC (container_destroy_cb), container);
512
513         ui_container = bonobo_ui_container_new ();
514         bonobo_ui_container_set_win (ui_container, BONOBO_WIN (container->app));
515
516         container->ui_component = bonobo_ui_component_new ("gpdf");
517         bonobo_ui_component_set_container (
518                 container->ui_component,
519                 bonobo_object_corba_objref (BONOBO_OBJECT (ui_container)));
520
521         bonobo_ui_component_add_verb_list_with_data (
522                 container->ui_component, verbs, container);
523
524         bonobo_ui_util_set_ui (container->ui_component, DATADIR, "gpdf-ui.xml", "gpdf");
525
526         gtk_widget_show (container->app);
527
528         containers = g_list_append (containers, container);
529
530         if (fname)
531           if (!open_pdf (container, fname)) {
532             container_destroy (container);
533             return NULL;
534           }
535
536         gtk_widget_show (container->app);
537
538         return container;
539 }
540
541 int
542 main (int argc, char **argv)
543 {
544   CORBA_Environment ev;
545   CORBA_ORB         orb;
546   const char      **view_files = NULL;
547   gboolean          loaded;
548   int               i;
549   
550   CORBA_exception_init (&ev);
551   
552
553   gnomelib_register_popt_table (oaf_popt_options, "OAF");
554   gnome_init_with_popt_table("PDFViewer", "0.0.1",
555                              argc, argv,
556                              gpdf_popt_options, 0, &ctx); 
557   orb = oaf_init (argc, argv);
558
559   CORBA_exception_free (&ev);
560
561   if (bonobo_init (orb, NULL, NULL) == FALSE)
562     g_error (_("Could not initialize Bonobo!\n"));
563   bonobo_activate ();
564
565   view_files = poptGetArgs (ctx);
566
567   /* Load files */
568   i = 0;
569   loaded = FALSE;
570   if (view_files) {
571     for (i = 0; view_files[i]; i++)
572       if (container_new (view_files[i])) {
573         loaded = TRUE;
574         while (gtk_events_pending ())
575           gtk_main_iteration ();
576       }
577   }
578   if ((i == 0) || !loaded)
579     container_new (NULL);
580   
581   poptFreeContext (ctx);
582
583   gtk_main ();
584         
585   return 0;
586 }