Release versions 1.2.11 and 1.2.11-1
[videolink.git] / browser_widget.cpp
1 // Copyright 2005-8 Ben Hutchings <ben@decadent.org.uk>.
2 // See the file "COPYING" for licence details.
3
4 #include "browser_widget.hpp"
5
6 #include <cassert>
7 #include <cstring>
8
9 #include <limits.h>
10
11 #include "videolink.hpp"
12 #include "wchar_t_short.h"
13 #include <gtkmozembed_internal.h>
14 #if MOZ_VERSION_GE(1,9,0)
15 #include <gtkmozembed_glue.cpp>
16 #endif
17 #include "wchar_t_default.h"
18
19 #include "xpcom_support.hpp"
20
21 using xpcom_support::check;
22
23 browser_widget::browser_widget()
24         : Gtk::Bin(GTK_BIN(gtk_moz_embed_new()))
25 {
26 }
27 browser_widget::~browser_widget()
28 {
29 }
30
31 GtkMozEmbed * browser_widget::gobj()
32 {
33     return GTK_MOZ_EMBED(gobject_);
34 }
35 const GtkMozEmbed * browser_widget::gobj() const
36 {
37     return GTK_MOZ_EMBED(gobject_);
38 }
39
40 void browser_widget::load_uri(const char * uri)
41 {
42     gtk_moz_embed_load_url(gobj(), uri);
43 }
44 void browser_widget::load_uri(const std::string & uri)
45 {
46     return load_uri(uri.c_str());
47 }
48 void browser_widget::stop_load()
49 {
50     gtk_moz_embed_stop_load(gobj());
51 }
52 void browser_widget::go_back()
53 {
54     gtk_moz_embed_go_back(gobj());
55 }
56 void browser_widget::go_forward()
57 {
58     gtk_moz_embed_go_forward(gobj());
59 }
60 void browser_widget::reload(gint32 flags)
61 {
62     gtk_moz_embed_reload(gobj(), flags);
63 }
64
65 bool browser_widget::can_go_back() const
66 {
67     return gtk_moz_embed_can_go_back(const_cast<GtkMozEmbed *>(gobj()));
68 }
69 bool browser_widget::can_go_forward() const
70 {
71     return gtk_moz_embed_can_go_forward(const_cast<GtkMozEmbed *>(gobj()));
72 }
73
74 namespace
75 {
76     template<typename T>
77     class c_scoped_ptr
78     {
79     public:
80         explicit c_scoped_ptr(T * p = 0) : p_(p) {}
81         ~c_scoped_ptr() { free(p_); }
82         T * get() const { return p_; }
83         T * release()
84         {
85             T * p = p_;
86             p_ = NULL;
87             return p;
88         }
89         void reset(T * p = 0)
90         {
91             free(p_);
92             p_ = p;
93         }
94     private:
95         T * p_;
96     };
97 }
98
99 std::string browser_widget::get_link_message() const
100 {
101     c_scoped_ptr<char> str(
102         gtk_moz_embed_get_link_message(const_cast<GtkMozEmbed *>(gobj())));
103     return std::string(str.get());
104 }
105 std::string browser_widget::get_js_status() const
106 {
107     c_scoped_ptr<char> str(
108         gtk_moz_embed_get_js_status(const_cast<GtkMozEmbed *>(gobj())));
109     return std::string(str.get());
110 }
111 std::string browser_widget::get_title() const
112 {
113     c_scoped_ptr<char> str(
114         gtk_moz_embed_get_title(const_cast<GtkMozEmbed *>(gobj())));
115     return std::string(str.get());
116 }
117 std::string browser_widget::get_location() const
118 {
119     c_scoped_ptr<char> str(
120         gtk_moz_embed_get_location(const_cast<GtkMozEmbed *>(gobj())));
121     return std::string(str.get());
122 }
123 already_AddRefed<nsIWebBrowser> browser_widget::get_browser()
124 {
125     nsIWebBrowser * result = 0;
126     gtk_moz_embed_get_nsIWebBrowser(gobj(), &result);
127     assert(result);
128     return dont_AddRef(result);
129 }
130
131 namespace
132 {
133     void browser_widget_signal_link_message_callback(GtkMozEmbed * self, void * data)
134     {
135         typedef sigc::slot<void> SlotType;
136
137         if (Glib::ObjectBase::_get_current_wrapper((GObject *)self))
138         {
139             try
140             {
141                 if (sigc::slot_base * const slot =
142                     Glib::SignalProxyNormal::data_to_slot(data))
143                     (*static_cast<SlotType*>(slot))();
144             }
145             catch(...)
146             {
147                 Glib::exception_handlers_invoke();
148             }
149         }
150     }
151
152     const Glib::SignalProxyInfo browser_widget_signal_link_message_info =
153     {
154         "link_message",
155         (GCallback) &browser_widget_signal_link_message_callback,
156         (GCallback) &browser_widget_signal_link_message_callback
157     };
158
159     void browser_widget_signal_js_status_callback(GtkMozEmbed * self, void * data)
160     {
161         typedef sigc::slot<void> SlotType;
162
163         if (Glib::ObjectBase::_get_current_wrapper((GObject *)self))
164         {
165             try
166             {
167                 if (sigc::slot_base * const slot =
168                     Glib::SignalProxyNormal::data_to_slot(data))
169                     (*static_cast<SlotType*>(slot))();
170             }
171             catch(...)
172             {
173                 Glib::exception_handlers_invoke();
174             }
175         }
176     }
177
178     const Glib::SignalProxyInfo browser_widget_signal_js_status_info =
179     {
180         "js_status",
181         (GCallback) &browser_widget_signal_js_status_callback,
182         (GCallback) &browser_widget_signal_js_status_callback
183     };
184
185     void browser_widget_signal_location_callback(GtkMozEmbed * self, void * data)
186     {
187         typedef sigc::slot<void> SlotType;
188
189         if (Glib::ObjectBase::_get_current_wrapper((GObject *)self))
190         {
191             try
192             {
193                 if (sigc::slot_base * const slot =
194                     Glib::SignalProxyNormal::data_to_slot(data))
195                     (*static_cast<SlotType*>(slot))();
196             }
197             catch(...)
198             {
199                 Glib::exception_handlers_invoke();
200             }
201         }
202     }
203
204     const Glib::SignalProxyInfo browser_widget_signal_location_info =
205     {
206         "location",
207         (GCallback) &browser_widget_signal_location_callback,
208         (GCallback) &browser_widget_signal_location_callback
209     };
210
211     void browser_widget_signal_title_callback(GtkMozEmbed * self, void * data)
212     {
213         typedef sigc::slot<void> SlotType;
214
215         if (Glib::ObjectBase::_get_current_wrapper((GObject *)self))
216         {
217             try
218             {
219                 if (sigc::slot_base * const slot =
220                     Glib::SignalProxyNormal::data_to_slot(data))
221                     (*static_cast<SlotType*>(slot))();
222             }
223             catch(...)
224             {
225                 Glib::exception_handlers_invoke();
226             }
227         }
228     }
229
230     const Glib::SignalProxyInfo browser_widget_signal_title_info =
231     {
232         "title",
233         (GCallback) &browser_widget_signal_title_callback,
234         (GCallback) &browser_widget_signal_title_callback
235     };
236
237     void browser_widget_signal_progress_callback(
238         GtkMozEmbed * self, gint p0, gint p1, void * data)
239     {
240         typedef sigc::slot<void, gint, gint> SlotType;
241
242         if (Glib::ObjectBase::_get_current_wrapper((GObject *)self))
243         {
244             try
245             {
246                 if (sigc::slot_base * const slot =
247                     Glib::SignalProxyNormal::data_to_slot(data))
248                     (*static_cast<SlotType*>(slot))(p0, p1);
249             }
250             catch(...)
251             {
252                 Glib::exception_handlers_invoke();
253             }
254         }
255     }
256
257     const Glib::SignalProxyInfo browser_widget_signal_progress_info =
258     {
259         "progress",
260         (GCallback) &browser_widget_signal_progress_callback,
261         (GCallback) &browser_widget_signal_progress_callback
262     };
263
264     void browser_widget_signal_net_state_callback(
265         GtkMozEmbed * self, const char * p0, gint p1, guint p2, void * data)
266     {
267         typedef sigc::slot<void, const char *, gint, guint> SlotType;
268
269         if (Glib::ObjectBase::_get_current_wrapper((GObject *)self))
270         {
271             try
272             {
273                 if (sigc::slot_base * const slot =
274                     Glib::SignalProxyNormal::data_to_slot(data))
275                     (*static_cast<SlotType*>(slot))(p0, p1, p2);
276             }
277             catch(...)
278             {
279                 Glib::exception_handlers_invoke();
280             }
281         }
282     }
283
284     const Glib::SignalProxyInfo browser_widget_signal_net_state_info =
285     {
286         "net_state_all",
287         (GCallback) &browser_widget_signal_net_state_callback,
288         (GCallback) &browser_widget_signal_net_state_callback
289     };
290
291     void browser_widget_signal_net_start_callback(GtkMozEmbed * self, void * data)
292     {
293         typedef sigc::slot<void> SlotType;
294
295         if (Glib::ObjectBase::_get_current_wrapper((GObject *)self))
296         {
297             try
298             {
299                 if (sigc::slot_base * const slot =
300                     Glib::SignalProxyNormal::data_to_slot(data))
301                     (*static_cast<SlotType*>(slot))();
302             }
303             catch(...)
304             {
305                 Glib::exception_handlers_invoke();
306             }
307         }
308     }
309
310     const Glib::SignalProxyInfo browser_widget_signal_net_start_info =
311     {
312         "net_start",
313         (GCallback) &browser_widget_signal_net_start_callback,
314         (GCallback) &browser_widget_signal_net_start_callback
315     };
316
317     void browser_widget_signal_net_stop_callback(GtkMozEmbed * self, void * data)
318     {
319         typedef sigc::slot<void> SlotType;
320
321         if (Glib::ObjectBase::_get_current_wrapper((GObject *)self))
322         {
323             try
324             {
325                 if (sigc::slot_base * const slot =
326                     Glib::SignalProxyNormal::data_to_slot(data))
327                     (*static_cast<SlotType*>(slot))();
328             }
329             catch(...)
330             {
331                 Glib::exception_handlers_invoke();
332             }
333         }
334     }
335
336     const Glib::SignalProxyInfo browser_widget_signal_net_stop_info =
337     {
338         "net_stop",
339         (GCallback) &browser_widget_signal_net_stop_callback,
340         (GCallback) &browser_widget_signal_net_stop_callback
341     };
342
343     void browser_widget_signal_new_window_callback(
344         GtkMozEmbed * self, GtkMozEmbed ** p0, guint p1, void * data)
345     {
346         typedef sigc::slot<browser_widget *, guint> SlotType;
347
348         if (Glib::ObjectBase::_get_current_wrapper((GObject *)self))
349         {
350             try
351             {
352                 if (sigc::slot_base * const slot =
353                     Glib::SignalProxyNormal::data_to_slot(data))
354                 {
355                     if (browser_widget * result =
356                         (*static_cast<SlotType*>(slot))(p1))
357                     {
358                         *p0 = result->gobj();
359                         return;
360                     }
361                 }
362             }
363             catch(...)
364             {
365                 Glib::exception_handlers_invoke();
366             }
367         }
368
369         *p0 = NULL;
370         return;
371     }
372
373     const Glib::SignalProxyInfo browser_widget_signal_new_window_info =
374     {
375         "new_window",
376         (GCallback) &browser_widget_signal_new_window_callback,
377         (GCallback) &browser_widget_signal_new_window_callback
378     };
379
380     void browser_widget_signal_visibility_callback(
381         GtkMozEmbed * self, gboolean p0, void * data)
382     {
383         typedef sigc::slot<void, bool> SlotType;
384
385         if (Glib::ObjectBase::_get_current_wrapper((GObject *)self))
386         {
387             try
388             {
389                 if (sigc::slot_base * const slot =
390                     Glib::SignalProxyNormal::data_to_slot(data))
391                     (*static_cast<SlotType*>(slot))(p0);
392             }
393             catch(...)
394             {
395                 Glib::exception_handlers_invoke();
396             }
397         }
398     }
399
400     const Glib::SignalProxyInfo browser_widget_signal_visibility_info =
401     {
402         "visibility",
403         (GCallback) &browser_widget_signal_visibility_callback,
404         (GCallback) &browser_widget_signal_visibility_callback
405     };
406
407     void browser_widget_signal_destroy_browser_callback(
408         GtkMozEmbed * self, void * data)
409     {
410         typedef sigc::slot<void> SlotType;
411
412         if (Glib::ObjectBase::_get_current_wrapper((GObject *)self))
413         {
414             try
415             {
416                 if (sigc::slot_base * const slot =
417                     Glib::SignalProxyNormal::data_to_slot(data))
418                     (*static_cast<SlotType*>(slot))();
419             }
420             catch(...)
421             {
422                 Glib::exception_handlers_invoke();
423             }
424         }
425     }
426
427     const Glib::SignalProxyInfo browser_widget_signal_destroy_info =
428     {
429         "destroy_browser",
430         (GCallback) &browser_widget_signal_destroy_browser_callback,
431         (GCallback) &browser_widget_signal_destroy_browser_callback
432     };
433
434     gint browser_widget_signal_open_uri_callback(
435         GtkMozEmbed * self, const char * p0, void * data)
436     {
437         typedef sigc::slot<bool, const char *> SlotType;
438
439         if (Glib::ObjectBase::_get_current_wrapper((GObject *)self))
440         {
441             try
442             {
443                 if (sigc::slot_base * const slot =
444                     Glib::SignalProxyNormal::data_to_slot(data))
445                     return (*static_cast<SlotType*>(slot))(p0);
446             }
447             catch(...)
448             {
449                 Glib::exception_handlers_invoke();
450             }
451         }
452
453         return 0;
454     }
455
456     const Glib::SignalProxyInfo browser_widget_signal_open_uri_info =
457     {
458         "open_uri",
459         (GCallback) &browser_widget_signal_open_uri_callback,
460         (GCallback) &browser_widget_signal_open_uri_callback
461     };
462
463 } // namespace
464
465 Glib::SignalProxy0<void> browser_widget::signal_link_message()
466 {
467     return Glib::SignalProxy0<void>(this, &browser_widget_signal_link_message_info);
468 }
469 Glib::SignalProxy0<void> browser_widget::signal_js_status()
470 {
471     return Glib::SignalProxy0<void>(this, &browser_widget_signal_js_status_info);
472 }
473 Glib::SignalProxy0<void> browser_widget::signal_location()
474 {
475     return Glib::SignalProxy0<void>(this, &browser_widget_signal_location_info);
476 }
477 Glib::SignalProxy0<void> browser_widget::signal_title()
478 {
479     return Glib::SignalProxy0<void>(this, &browser_widget_signal_title_info);
480 }
481 Glib::SignalProxy2<void, gint /*cur*/, gint /*max*/> browser_widget::signal_progress()
482 {
483     return Glib::SignalProxy2<void, gint, gint>(
484         this, &browser_widget_signal_progress_info);
485 }
486 Glib::SignalProxy3<void, const char *, gint /*flags*/, guint /*status*/>
487 browser_widget::signal_net_state()
488 {
489     return Glib::SignalProxy3<void, const char *, gint, guint>(
490         this, &browser_widget_signal_net_state_info);
491 }
492 Glib::SignalProxy0<void> browser_widget::signal_net_start()
493 {
494     return Glib::SignalProxy0<void>(this, &browser_widget_signal_net_start_info);
495 }
496 Glib::SignalProxy0<void> browser_widget::signal_net_stop()
497 {
498     return Glib::SignalProxy0<void>(this, &browser_widget_signal_net_stop_info);
499 }
500 Glib::SignalProxy1<browser_widget *, guint /*chromemask*/> browser_widget::signal_new_window()
501 {
502     return Glib::SignalProxy1<browser_widget *, guint>(
503         this, &browser_widget_signal_new_window_info);
504 }
505 Glib::SignalProxy1<void, bool /*visibility*/> browser_widget::signal_visibility()
506 {
507     return Glib::SignalProxy1<void, bool>(
508         this, &browser_widget_signal_visibility_info);
509 }
510 Glib::SignalProxy0<void> browser_widget::signal_destroy()
511 {
512     return Glib::SignalProxy0<void>(this, &browser_widget_signal_destroy_info);
513 }
514 Glib::SignalProxy1<bool, const char * /*uri*/> browser_widget::signal_open_uri()
515 {
516     return Glib::SignalProxy1<bool, const char *>(
517         this, &browser_widget_signal_open_uri_info);
518 }
519
520 browser_widget::browser_widget(GObject * gobject, bool take_copy)
521 {
522     assert(GTK_MOZ_EMBED(gobject));
523     gobject_ = gobject;
524     if (take_copy)
525         reference();
526 }
527 Glib::ObjectBase * browser_widget::wrap_new(GObject * gobject)
528 {
529     return new browser_widget(gobject, false);
530 }
531
532 browser_widget::initialiser::initialiser()
533 {
534 #if MOZ_VERSION_GE(1,9,0)
535     static const GREVersionRange gre_versions = {
536 #if MOZ_VERSION_EQ(1,9,0)
537         "1.9a", PR_TRUE,
538         "1.9.1", PR_FALSE
539 #elif MOZ_VERSION_EQ(1,9,1)
540         "1.9.1", PR_TRUE,
541         "1.9.2", PR_FALSE
542 #elif MOZ_VERSION_EQ(2,0,-1) || MOZ_VERSION_EQ(2,0,0)
543         "2.0b", PR_TRUE,
544         "2.0.1", PR_FALSE
545 #elif MOZ_VERSION_EQ(2,0,1)
546         "2.0.1", PR_TRUE,
547         "2.0.2", PR_FALSE
548 #else
549 #error "version is unsupported, but you could try continuing the pattern above"
550 #endif
551     };
552     char path[PATH_MAX];
553     check(GRE_GetGREPathWithProperties(&gre_versions, 1, 0, 0,
554                                        path, sizeof(path)));
555
556     check(XPCOMGlueStartup(path));
557     check(GTKEmbedGlueStartup());
558     check(GTKEmbedGlueStartupInternal());
559
560     char * last_slash = std::strrchr(path, '/');
561     if (last_slash != path)
562         *last_slash = '\0';
563     gtk_moz_embed_set_path(path);
564 #else
565     gtk_moz_embed_set_comp_path(MOZ_LIB_DIR);
566 #endif
567
568     gtk_moz_embed_push_startup();
569
570     wrap_register(gtk_moz_embed_get_type(), wrap_new);
571 }
572
573 browser_widget::initialiser::~initialiser()
574 {
575     gtk_moz_embed_pop_startup();
576
577 #if MOZ_VERSION_GE(1,9,0)
578     XPCOMGlueShutdown();
579 #endif
580 }
581
582 namespace Glib
583 {
584     browser_widget * wrap(GtkMozEmbed * object, bool take_copy)
585     {
586         return dynamic_cast<browser_widget *>(
587             Glib::wrap_auto((GObject*)(object), take_copy));
588     }
589 }