1 /* Purple is the legal property of its developers, whose names are too numerous
2 * to list here. Please refer to the COPYRIGHT file distributed with this
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
19 #include <gdk-pixbuf/gdk-pixbuf.h>
20 #include <json-glib/json-glib.h>
23 #include "package_revision.h"
24 #include "pidginabout.h"
25 #include "pidginresources.h"
31 #ifdef HAVE_MESON_CONFIG
32 #include "meson-config.h"
35 typedef struct _PidginAboutDialogPrivate PidginAboutDialogPrivate
;
37 struct _PidginAboutDialog
{
41 PidginAboutDialogPrivate
*priv
;
44 struct _PidginAboutDialogClass
{
45 GtkDialogClass parent
;
47 void (*_pidgin_reserved1
)(void);
48 void (*_pidgin_reserved2
)(void);
49 void (*_pidgin_reserved3
)(void);
50 void (*_pidgin_reserved4
)(void);
53 struct _PidginAboutDialogPrivate
{
54 GtkWidget
*close_button
;
55 GtkWidget
*application_name
;
58 GtkWidget
*main_scrolled_window
;
59 GtkTextBuffer
*main_buffer
;
61 GtkWidget
*developers_page
;
62 GtkWidget
*developers_treeview
;
63 GtkTreeStore
*developers_store
;
65 GtkWidget
*translators_page
;
66 GtkWidget
*translators_treeview
;
67 GtkTreeStore
*translators_store
;
69 GtkWidget
*build_info_page
;
70 GtkWidget
*build_info_treeview
;
71 GtkTreeStore
*build_info_store
;
74 G_DEFINE_TYPE_WITH_PRIVATE(PidginAboutDialog
, pidgin_about_dialog
, GTK_TYPE_DIALOG
);
76 /******************************************************************************
78 *****************************************************************************/
80 _pidgin_about_dialog_load_application_name(PidginAboutDialog
*about
) {
81 gchar
*label
= g_strdup_printf(
87 gtk_label_set_text(GTK_LABEL(about
->priv
->application_name
), label
);
93 _pidgin_about_dialog_load_main_page(PidginAboutDialog
*about
) {
94 PidginAboutDialogPrivate
*priv
= pidgin_about_dialog_get_instance_private(about
);
96 GInputStream
*istream
= NULL
;
99 gssize read
= 0, size
= 0;
101 /* now load the html */
102 istream
= g_resource_open_stream(
103 pidgin_get_resource(),
104 "/im/pidgin/Pidgin/About/about.md",
105 G_RESOURCE_LOOKUP_FLAGS_NONE
,
109 str
= g_string_new("");
111 while((read
= g_input_stream_read(istream
, buffer
, sizeof(buffer
), NULL
, NULL
)) > 0) {
112 g_string_append_len(str
, (gchar
*)buffer
, read
);
116 gtk_text_buffer_get_start_iter(priv
->main_buffer
, &start
);
118 talkatu_markdown_buffer_insert_markdown(
119 TALKATU_MARKDOWN_BUFFER(priv
->main_buffer
),
125 g_string_free(str
, TRUE
);
127 g_input_stream_close(istream
, NULL
, NULL
);
131 _pidgin_about_dialog_load_json(GtkTreeStore
*store
, const gchar
*json_section
) {
132 GInputStream
*istream
= NULL
;
133 GList
*l
= NULL
, *sections
= NULL
;
134 GError
*error
= NULL
;
135 JsonParser
*parser
= NULL
;
136 JsonNode
*root_node
= NULL
;
137 JsonObject
*root_object
= NULL
;
138 JsonArray
*sections_array
= NULL
;
140 /* get a stream to the credits resource */
141 istream
= g_resource_open_stream(
142 pidgin_get_resource(),
143 "/im/pidgin/Pidgin/About/credits.json",
144 G_RESOURCE_LOOKUP_FLAGS_NONE
,
148 /* create our parser */
149 parser
= json_parser_new();
151 if(!json_parser_load_from_stream(parser
, istream
, NULL
, &error
)) {
152 g_critical("%s", error
->message
);
155 root_node
= json_parser_get_root(parser
);
156 root_object
= json_node_get_object(root_node
);
158 sections_array
= json_object_get_array_member(root_object
, json_section
);
159 sections
= json_array_get_elements(sections_array
);
161 for(l
= sections
; l
; l
= l
->next
) {
162 GtkTreeIter section_iter
;
163 JsonObject
*section
= json_node_get_object(l
->data
);
164 JsonArray
*people
= NULL
;
165 gchar
*markup
= NULL
;
166 guint idx
= 0, n_people
= 0;
168 markup
= g_strdup_printf(
169 "<span font_weight=\"bold\" font_size=\"large\">%s</span>",
170 json_object_get_string_member(section
, "title")
173 gtk_tree_store_append(store
, §ion_iter
, NULL
);
184 people
= json_object_get_array_member(section
, "people");
185 n_people
= json_array_get_length(people
);
187 for(idx
= 0; idx
< n_people
; idx
++) {
188 GtkTreeIter person_iter
;
190 gtk_tree_store_append(store
, &person_iter
, §ion_iter
);
194 0, json_array_get_string_element(people
, idx
),
201 g_list_free(sections
);
204 g_object_unref(G_OBJECT(parser
));
206 g_input_stream_close(istream
, NULL
, NULL
);
210 _pidgin_about_dialog_load_developers(PidginAboutDialog
*about
) {
211 _pidgin_about_dialog_load_json(about
->priv
->developers_store
, "developers");
215 _pidgin_about_dialog_load_translators(PidginAboutDialog
*about
) {
216 _pidgin_about_dialog_load_json(about
->priv
->translators_store
, "languages");
220 _pidgin_about_dialog_add_build_args(
221 PidginAboutDialog
*about
,
223 const gchar
*build_args
225 GtkTreeIter section
, value
;
226 gchar
**splits
= NULL
;
227 gchar
*markup
= NULL
;
230 markup
= g_strdup_printf("<span font-weight=\"bold\">%s</span>", title
);
231 gtk_tree_store_append(about
->priv
->build_info_store
, §ion
, NULL
);
233 about
->priv
->build_info_store
,
240 /* now walk through the arguments and add them */
241 splits
= g_strsplit(build_args
, " ", -1);
242 for(idx
= 0; splits
[idx
]; idx
++) {
243 gchar
**value_split
= g_strsplit(splits
[idx
], "=", 2);
245 if(value_split
[0] == NULL
|| value_split
[0][0] == '\0') {
249 gtk_tree_store_append(about
->priv
->build_info_store
, &value
, §ion
);
251 about
->priv
->build_info_store
,
253 0, value_split
[0] ? value_split
[0] : "",
254 1, value_split
[1] ? value_split
[1] : "",
258 g_strfreev(value_split
);
265 _pidgin_about_dialog_build_info_add_version(
267 GtkTreeIter
*section
,
274 gchar
*version
= g_strdup_printf("%u.%u.%u", major
, minor
, micro
);
276 gtk_tree_store_append(store
, &item
, section
);
287 _pidgin_about_dialog_load_build_info(PidginAboutDialog
*about
) {
288 GtkTreeIter section
, item
;
289 gchar
*markup
= NULL
;
291 /* create the section */
292 markup
= g_strdup_printf(
293 "<span font-weight=\"bold\">%s</span>",
294 _("Build Information")
296 gtk_tree_store_append(about
->priv
->build_info_store
, §ion
, NULL
);
298 about
->priv
->build_info_store
,
305 /* add the commit hash */
306 gtk_tree_store_append(about
->priv
->build_info_store
, &item
, §ion
);
308 about
->priv
->build_info_store
,
315 /* add the purple version */
316 _pidgin_about_dialog_build_info_add_version(
317 about
->priv
->build_info_store
,
320 PURPLE_MAJOR_VERSION
,
321 PURPLE_MINOR_VERSION
,
325 /* add the glib version */
326 _pidgin_about_dialog_build_info_add_version(
327 about
->priv
->build_info_store
,
335 /* add the gtk version */
336 _pidgin_about_dialog_build_info_add_version(
337 about
->priv
->build_info_store
,
347 _pidgin_about_dialog_load_runtime_info(PidginAboutDialog
*about
) {
349 gchar
*markup
= NULL
;
351 /* create the section */
352 markup
= g_strdup_printf(
353 "<span font-weight=\"bold\">%s</span>",
354 _("Runtime Information")
356 gtk_tree_store_append(about
->priv
->build_info_store
, §ion
, NULL
);
358 about
->priv
->build_info_store
,
365 /* add the purple version */
366 _pidgin_about_dialog_build_info_add_version(
367 about
->priv
->build_info_store
,
370 purple_major_version
,
371 purple_minor_version
,
375 /* add the glib version */
376 _pidgin_about_dialog_build_info_add_version(
377 about
->priv
->build_info_store
,
385 /* add the gtk version */
386 _pidgin_about_dialog_build_info_add_version(
387 about
->priv
->build_info_store
,
397 _pidgin_about_dialog_load_build_configuration(PidginAboutDialog
*about
) {
399 _pidgin_about_dialog_add_build_args(about
, "Meson Arguments", MESON_ARGS
);
400 #endif /* MESON_ARGS */
402 _pidgin_about_dialog_load_build_info(about
);
403 _pidgin_about_dialog_load_runtime_info(about
);
406 /******************************************************************************
408 *****************************************************************************/
410 _pidgin_about_dialog_close(GtkWidget
*b
, gpointer data
) {
411 gtk_widget_destroy(GTK_WIDGET(data
));
414 /******************************************************************************
416 *****************************************************************************/
418 pidgin_about_dialog_class_init(PidginAboutDialogClass
*klass
) {
419 GtkWidgetClass
*widget_class
= GTK_WIDGET_CLASS(klass
);
421 gtk_widget_class_set_template_from_resource(
423 "/im/pidgin/Pidgin/About/about.ui"
426 gtk_widget_class_bind_template_child_private(widget_class
, PidginAboutDialog
, close_button
);
427 gtk_widget_class_bind_template_child_private(widget_class
, PidginAboutDialog
, application_name
);
428 gtk_widget_class_bind_template_child_private(widget_class
, PidginAboutDialog
, stack
);
430 gtk_widget_class_bind_template_child_private(widget_class
, PidginAboutDialog
, main_scrolled_window
);
431 gtk_widget_class_bind_template_child_private(widget_class
, PidginAboutDialog
, main_buffer
);
433 gtk_widget_class_bind_template_child_private(widget_class
, PidginAboutDialog
, developers_page
);
434 gtk_widget_class_bind_template_child_private(widget_class
, PidginAboutDialog
, developers_store
);
435 gtk_widget_class_bind_template_child_private(widget_class
, PidginAboutDialog
, developers_treeview
);
437 gtk_widget_class_bind_template_child_private(widget_class
, PidginAboutDialog
, translators_page
);
438 gtk_widget_class_bind_template_child_private(widget_class
, PidginAboutDialog
, translators_store
);
439 gtk_widget_class_bind_template_child_private(widget_class
, PidginAboutDialog
, translators_treeview
);
441 gtk_widget_class_bind_template_child_private(widget_class
, PidginAboutDialog
, build_info_page
);
442 gtk_widget_class_bind_template_child_private(widget_class
, PidginAboutDialog
, build_info_store
);
443 gtk_widget_class_bind_template_child_private(widget_class
, PidginAboutDialog
, build_info_treeview
);
447 pidgin_about_dialog_init(PidginAboutDialog
*about
) {
448 about
->priv
= pidgin_about_dialog_get_instance_private(about
);
450 gtk_widget_init_template(GTK_WIDGET(about
));
452 /* wire up the close button */
454 about
->priv
->close_button
,
456 G_CALLBACK(_pidgin_about_dialog_close
),
460 /* setup the application name label */
461 _pidgin_about_dialog_load_application_name(about
);
463 /* setup the main page */
464 _pidgin_about_dialog_load_main_page(about
);
466 /* setup the developers stuff */
467 _pidgin_about_dialog_load_developers(about
);
468 gtk_tree_view_expand_all(GTK_TREE_VIEW(about
->priv
->developers_treeview
));
470 /* setup the translators stuff */
471 _pidgin_about_dialog_load_translators(about
);
472 gtk_tree_view_expand_all(GTK_TREE_VIEW(about
->priv
->translators_treeview
));
474 /* setup the build info page */
475 _pidgin_about_dialog_load_build_configuration(about
);
476 gtk_tree_view_expand_all(GTK_TREE_VIEW(about
->priv
->build_info_treeview
));
480 pidgin_about_dialog_new(void) {
481 GtkWidget
*about
= NULL
;
483 about
= g_object_new(
484 PIDGIN_TYPE_ABOUT_DIALOG
,
485 "title", "About Pidgin",