1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: src/gtk/aboutdlg.cpp
3 // Purpose: native GTK+ wxAboutBox() implementation
4 // Author: Vadim Zeitlin
5 // Created: 2006-10-08
6 // Copyright: (c) 2006 Vadim Zeitlin <vadim@wxwidgets.org>
7 // Licence: wxWindows licence
8 ///////////////////////////////////////////////////////////////////////////////
9
10 // ============================================================================
11 // declarations
12 // ============================================================================
13
14 // ----------------------------------------------------------------------------
15 // headers
16 // ----------------------------------------------------------------------------
17
18 // for compilers that support precompilation, includes "wx.h".
19 #include "wx/wxprec.h"
20
21 #if wxUSE_ABOUTDLG
22
23 #include "wx/aboutdlg.h"
24
25 #ifndef WX_PRECOMP
26 #include "wx/window.h"
27 #endif //WX_PRECOMP
28
29 #include "wx/gtk/private.h"
30
31 // ----------------------------------------------------------------------------
32 // GtkArray: temporary array of GTK strings
33 // ----------------------------------------------------------------------------
34
35 namespace
36 {
37
38 class GtkArray
39 {
40 public:
41 // Create empty GtkArray
GtkArray()42 GtkArray() : m_strings(0), m_count(0)
43 {
44 }
45
46 // Create GtkArray from wxArrayString. Note that the created object is
47 // only valid as long as 'a' is!
GtkArray(const wxArrayString & a)48 GtkArray(const wxArrayString& a)
49 {
50 m_count = a.size();
51 m_strings = new const gchar *[m_count + 1];
52
53 for ( size_t n = 0; n < m_count; n++ )
54 {
55 #if wxUSE_UNICODE
56 // notice that there is no need to copy the string pointer here
57 // because this class is used only as a temporary and during its
58 // existence the pointer persists in wxString which uses it either
59 // for internal representation (in wxUSE_UNICODE_UTF8 case) or as
60 // cached m_convertedToChar (in wxUSE_UNICODE_WCHAR case)
61 m_strings[n] = wxGTK_CONV_SYS(a[n]);
62 #else // !wxUSE_UNICODE
63 // and in ANSI build we can simply borrow the pointer from
64 // wxCharBuffer (which owns it in this case) instead of copying it
65 // but we then become responsible for freeing it
66 m_strings[n] = wxGTK_CONV_SYS(a[n]).release();
67 #endif // wxUSE_UNICODE/!wxUSE_UNICODE
68 }
69
70 // array must be NULL-terminated
71 m_strings[m_count] = NULL;
72 }
73
operator const gchar**() const74 operator const gchar **() const { return m_strings; }
75
~GtkArray()76 ~GtkArray()
77 {
78 #if !wxUSE_UNICODE
79 for ( size_t n = 0; n < m_count; n++ )
80 free(const_cast<gchar *>(m_strings[n]));
81 #endif
82
83 delete [] m_strings;
84 }
85
86 private:
87 const gchar **m_strings;
88 size_t m_count;
89
90 wxDECLARE_NO_COPY_CLASS(GtkArray);
91 };
92
93 } // anonymous namespace
94
95 // ============================================================================
96 // implementation
97 // ============================================================================
98
99 // GTK+ about dialog is modeless, keep track of it in this variable
100 static GtkAboutDialog *gs_aboutDialog = NULL;
101
102 extern "C" {
wxGtkAboutDialogOnClose(GtkAboutDialog * about)103 static void wxGtkAboutDialogOnClose(GtkAboutDialog *about)
104 {
105 gtk_widget_destroy(GTK_WIDGET(about));
106 if ( about == gs_aboutDialog )
107 gs_aboutDialog = NULL;
108 }
109 }
110
111 #ifdef __WXGTK3__
112 extern "C" {
activate_link(GtkAboutDialog *,const char * link,void * dontIgnore)113 static gboolean activate_link(GtkAboutDialog*, const char* link, void* dontIgnore)
114 {
115 if (dontIgnore)
116 {
117 wxLaunchDefaultBrowser(wxGTK_CONV_BACK_SYS(link));
118 return true;
119 }
120 return false;
121 }
122 }
123 #else
124 extern "C" {
wxGtkAboutDialogOnLink(GtkAboutDialog *,const char * link,void *)125 static void wxGtkAboutDialogOnLink(GtkAboutDialog*, const char* link, void*)
126 {
127 wxLaunchDefaultBrowser(wxGTK_CONV_BACK_SYS(link));
128 }
129 }
130 #endif
131
wxAboutBox(const wxAboutDialogInfo & info,wxWindow * parent)132 void wxAboutBox(const wxAboutDialogInfo& info, wxWindow* parent)
133 {
134 // don't create another dialog if one is already present
135 if ( !gs_aboutDialog )
136 gs_aboutDialog = GTK_ABOUT_DIALOG(gtk_about_dialog_new());
137
138 GtkAboutDialog * const dlg = gs_aboutDialog;
139 gtk_about_dialog_set_program_name(dlg, wxGTK_CONV_SYS(info.GetName()));
140 if ( info.HasVersion() )
141 gtk_about_dialog_set_version(dlg, wxGTK_CONV_SYS(info.GetVersion()));
142 else
143 gtk_about_dialog_set_version(dlg, NULL);
144 if ( info.HasCopyright() )
145 gtk_about_dialog_set_copyright(dlg, wxGTK_CONV_SYS(info.GetCopyrightToDisplay()));
146 else
147 gtk_about_dialog_set_copyright(dlg, NULL);
148 if ( info.HasDescription() )
149 gtk_about_dialog_set_comments(dlg, wxGTK_CONV_SYS(info.GetDescription()));
150 else
151 gtk_about_dialog_set_comments(dlg, NULL);
152 if ( info.HasLicence() )
153 gtk_about_dialog_set_license(dlg, wxGTK_CONV_SYS(info.GetLicence()));
154 else
155 gtk_about_dialog_set_license(dlg, NULL);
156
157 wxIcon icon = info.GetIcon();
158 if ( icon.IsOk() )
159 gtk_about_dialog_set_logo(dlg, info.GetIcon().GetPixbuf());
160
161 if ( info.HasWebSite() )
162 {
163 #ifdef __WXGTK3__
164 g_signal_connect(dlg, "activate-link", G_CALLBACK(activate_link), dlg);
165 #else
166 // NB: must be called before gtk_about_dialog_set_website() as
167 // otherwise it has no effect (although GTK+ docs don't mention
168 // this...)
169 gtk_about_dialog_set_url_hook(wxGtkAboutDialogOnLink, NULL, NULL);
170 #endif
171
172 gtk_about_dialog_set_website(dlg, wxGTK_CONV_SYS(info.GetWebSiteURL()));
173 gtk_about_dialog_set_website_label
174 (
175 dlg,
176 wxGTK_CONV_SYS(info.GetWebSiteDescription())
177 );
178 }
179 else
180 {
181 gtk_about_dialog_set_website(dlg, NULL);
182 gtk_about_dialog_set_website_label(dlg, NULL);
183 #ifdef __WXGTK3__
184 g_signal_connect(dlg, "activate-link", G_CALLBACK(activate_link), NULL);
185 #else
186 gtk_about_dialog_set_url_hook(NULL, NULL, NULL);
187 #endif
188 }
189
190 if ( info.HasDevelopers() )
191 gtk_about_dialog_set_authors(dlg, GtkArray(info.GetDevelopers()));
192 else
193 gtk_about_dialog_set_authors(dlg, GtkArray());
194 if ( info.HasDocWriters() )
195 gtk_about_dialog_set_documenters(dlg, GtkArray(info.GetDocWriters()));
196 else
197 gtk_about_dialog_set_documenters(dlg, GtkArray());
198 if ( info.HasArtists() )
199 gtk_about_dialog_set_artists(dlg, GtkArray(info.GetArtists()));
200 else
201 gtk_about_dialog_set_artists(dlg, GtkArray());
202
203 wxString transCredits;
204 if ( info.HasTranslators() )
205 {
206 const wxArrayString& translators = info.GetTranslators();
207 const size_t count = translators.size();
208 for ( size_t n = 0; n < count; n++ )
209 {
210 transCredits << translators[n] << wxT('\n');
211 }
212 }
213 else // no translators explicitly specified
214 {
215 // maybe we have translator credits in the message catalog?
216 wxString translator = _("translator-credits");
217
218 // gtk_about_dialog_set_translator_credits() is smart enough to
219 // detect if "translator-credits" is untranslated and hide the
220 // translators tab in that case, however it will still show the
221 // "credits" button, (at least GTK 2.10.6) even if there are no
222 // credits informations at all, so we still need to do the check
223 // ourselves
224 if ( translator != wxT("translator-credits") ) // untranslated!
225 transCredits = translator;
226 }
227
228 if ( !transCredits.empty() )
229 gtk_about_dialog_set_translator_credits(dlg, wxGTK_CONV_SYS(transCredits));
230 else
231 gtk_about_dialog_set_translator_credits(dlg, NULL);
232
233 g_signal_connect(dlg, "response",
234 G_CALLBACK(wxGtkAboutDialogOnClose), NULL);
235
236 GtkWindow* gtkParent = NULL;
237 if (parent && parent->m_widget)
238 gtkParent = (GtkWindow*)gtk_widget_get_ancestor(parent->m_widget, GTK_TYPE_WINDOW);
239 gtk_window_set_transient_for(GTK_WINDOW(dlg), gtkParent);
240
241 gtk_window_present(GTK_WINDOW(dlg));
242 }
243
244 #endif // wxUSE_ABOUTDLG
245