1 /** \file   uiabout.c
2  * \brief   GTK3 about dialog
3  *
4  * \todo    Needs a proper logo, not the old, ugly, blue one. The logo from the
5  *          pokefinder website will do nicely, I think.
6  *
7  * \author  Bas Wassink <b.wassink@ziggo.nl>
8  */
9 
10 /*
11  * This file is part of VICE, the Versatile Commodore Emulator.
12  * See README for copyright notice.
13  *
14  *  This program is free software; you can redistribute it and/or modify
15  *  it under the terms of the GNU General Public License as published by
16  *  the Free Software Foundation; either version 2 of the License, or
17  *  (at your option) any later version.
18  *
19  *  This program is distributed in the hope that it will be useful,
20  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
21  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22  *  GNU General Public License for more details.
23  *
24  *  You should have received a copy of the GNU General Public License
25  *  along with this program; if not, write to the Free Software
26  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
27  *  02111-1307  USA.
28  */
29 
30 
31 #include "vice.h"
32 
33 #include <gtk/gtk.h>
34 #include <stdio.h>
35 #include <stdlib.h>
36 
37 #include "debug_gtk3.h"
38 #include "info.h"
39 #include "lib.h"
40 #include "ui.h"
41 #include "version.h"
42 #ifdef USE_SVN_REVISION
43 #include "svnversion.h"
44 #endif
45 #include "uidata.h"
46 
47 #include "uiabout.h"
48 
49 
50 /** \brief  List of current team members
51  *
52  * This list is allocated in create_current_team_list() and deallocated in
53  * the "destroy" callback of the About dialog
54  */
55 static char **authors;
56 
57 
58 /** \brief  Create list of current team members
59  *
60  * \return  heap-allocated list of strings
61  */
create_current_team_list(void)62 static char **create_current_team_list(void)
63 {
64     char **list;
65     size_t i;
66 
67     /* get proper size of list (sizeof doesn't work here) */
68     for (i = 0; core_team[i].name != NULL; i++) {
69         /* NOP */
70     }
71     list = lib_malloc(sizeof *list * (i + 1));
72 
73 #ifdef HAVE_DEBUG_GTK3UI
74     g_print("[debug-gtk3ui] %s(): team members = %d\n", __func__, (int)i);
75 #endif
76 
77     /* create list of current team members */
78     for (i = 0; core_team[i].name != NULL; i++) {
79         list[i] = core_team[i].name;
80     }
81     list[i] = NULL;
82     return list;
83 }
84 
85 
86 #if 0
87 static char **create_translators_list(void)
88 {
89     char **list = lib_malloc(sizeof *list * 256);
90     size_t i;
91 
92     while (trans_team[i].name != NULL) {
93         char *member = lib_malloc(256);
94         snprintf(member, 256, "%s - %s (%s)",
95                 trans_team[i].years,
96                 trans_team[i].name,
97                 trans_team[i].language);
98         list[i++] = member;
99     }
100     list[i] = NULL;
101     return list;
102 }
103 #endif
104 
105 
106 /** \brief  Deallocate current team list
107  *
108  * \param[in,out]   list    list of team member names
109  */
destroy_current_team_list(char ** list)110 static void destroy_current_team_list(char **list)
111 {
112     lib_free(list);
113 }
114 
115 
116 /** \brief  Create VICE logo
117  *
118  * \return  GdkPixbuf instance
119  */
get_vice_logo(void)120 static GdkPixbuf *get_vice_logo(void)
121 {
122     return uidata_get_pixbuf("vice-logo-black.svg");
123 }
124 
125 /** \brief  Handler for the "destroy" event
126  *
127  * \param[in,out]   widget      widget triggering the event (unused)
128  * \param[in]       user_data   data for the event (unused)
129  */
about_destroy_callback(GtkWidget * widget,gpointer user_data)130 static void about_destroy_callback(GtkWidget *widget, gpointer user_data)
131 {
132     destroy_current_team_list(authors);
133     /* GdkPixbuf mentions setting refcount to 1, but it appears the about
134      * dialog parent cleans it up somehow -- compyx */
135 #if 0
136     g_object_unref(user_data);
137 #endif
138 }
139 
140 
141 /** \brief  Handler for the "response" event
142  *
143  * This handles the "response" event, which is triggered for various standard
144  * buttons, although which buttons trigger this is a little unclear at the
145  * moment.
146  *
147  * \param[in,out]   widget      widget triggering the event (the dialog)
148  * \param[in]       response_id response ID
149  * \param[in]       user_data   extra data (unused)
150  */
about_response_callback(GtkWidget * widget,gint response_id,gpointer user_data)151 static void about_response_callback(GtkWidget *widget, gint response_id,
152                                     gpointer user_data)
153 {
154 #ifdef HAVE_DEBUG_GTK3UI
155     g_print("[debug-gtk3ui] %s(): response id: %d\n", __func__, response_id);
156 #endif
157     /* the GTK_RESPONSE_DELETE_EVENT is sent when the user clicks 'Close', but
158      * also when the user clicks the 'X' */
159     if (response_id == GTK_RESPONSE_DELETE_EVENT) {
160 #ifdef HAVE_DEBUG_GTK3UI
161         g_print("[debug-gtk3ui] %s(): CLOSE button clicked\n", __func__);
162 #endif
163         gtk_widget_destroy(widget);
164     }
165 }
166 
167 
168 /** \brief  Callback to show the 'About' dialog
169  *
170  * \param[in,out]   widget      widget triggering the event
171  * \param[in]       user_data   data for the event (unused)
172  */
ui_about_dialog_callback(GtkWidget * widget,gpointer user_data)173 void ui_about_dialog_callback(GtkWidget *widget, gpointer user_data)
174 {
175     GtkWidget *about = gtk_about_dialog_new();
176     GdkPixbuf *logo = get_vice_logo();
177 
178 #ifdef HAVE_DEBUG_GTK3UI
179     g_print("[debug-gtk3ui] %s() called\n", __func__);
180 #endif
181 
182     /* set toplevel window, Gtk doesn't like dialogs without parents */
183     gtk_window_set_transient_for(GTK_WINDOW(about), ui_get_active_window());
184 
185     /* generate team members list */
186     authors = create_current_team_list();
187 
188     /* set window title */
189     gtk_window_set_title(GTK_WINDOW(about), "About VICE");
190 
191     /* set version string */
192     gtk_about_dialog_set_version(GTK_ABOUT_DIALOG(about),
193 #ifdef USE_SVN_REVISION
194             VERSION " r" VICE_SVN_REV_STRING " (Gtk3)"
195 #else
196             VERSION " (Gtk3)"
197 #endif
198             );
199 
200     /* set license */
201     gtk_about_dialog_set_license_type(GTK_ABOUT_DIALOG(about), GTK_LICENSE_GPL_2_0);
202     /* set website link and title */
203     gtk_about_dialog_set_website(GTK_ABOUT_DIALOG(about),
204             "http://vice-emu.sourceforge.net/");
205     gtk_about_dialog_set_website_label(GTK_ABOUT_DIALOG(about),
206             "http://vice-emu.sourceforge.net/");
207     /* set list of current team members */
208     gtk_about_dialog_set_authors(GTK_ABOUT_DIALOG(about), (const gchar **)authors);
209     /* set copyright string */
210     gtk_about_dialog_set_copyright(GTK_ABOUT_DIALOG(about),
211             "Copyright 1996-2018 VICE TEAM");
212 
213     /* set logo */
214     gtk_about_dialog_set_logo(GTK_ABOUT_DIALOG(about), logo);
215 
216     /*
217      * hook up event handlers
218      */
219 
220     /* destroy callback, called when the dialog is closed through the 'X',
221      * but NOT when clicking 'Close' */
222     g_signal_connect(about, "destroy", G_CALLBACK(about_destroy_callback), (gpointer)logo);
223 
224     /* set up a generic handler for various buttons, this makes sure the
225      * 'Close' button is handled properly */
226     g_signal_connect(about, "response", G_CALLBACK(about_response_callback),
227             NULL);
228 
229     /* make the about dialog modal */
230     gtk_window_set_modal(GTK_WINDOW(about), TRUE);
231 
232     /* ... and show the dialog finally */
233     gtk_widget_show(about);
234 }
235