1 /*
2  * Copyright © 2005 Richard Hoelscher
3  * Copyright © 2006 Andreas Røsdal
4  * Copyright © 2007 Christian Persch
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19  *
20  * Authors:
21  *      Richard Hoelscher <rah@rahga.com>
22  */
23 
24 #include <config.h>
25 
26 #include <string.h>
27 #include <gtk/gtk.h>
28 #include <glib/gi18n.h>
29 
30 #include "ar-runtime.h"
31 
32 #include "ar-stock.h"
33 
34 static void
menu_item_select_cb(GtkWidget * widget,GtkStatusbar * statusbar)35 menu_item_select_cb (GtkWidget * widget, GtkStatusbar * statusbar)
36 {
37   GtkAction *action;
38   gchar *tooltip;
39   guint context_id;
40 
41   context_id = gtk_statusbar_get_context_id (statusbar, "games-tooltip");
42 
43   action = gtk_activatable_get_related_action (GTK_ACTIVATABLE (widget));
44   g_return_if_fail (action != NULL);
45 
46   g_object_get (action, "tooltip", &tooltip, NULL);
47 
48   if (tooltip) {
49     gtk_statusbar_push (statusbar, context_id, tooltip);
50     g_free (tooltip);
51   }
52 }
53 
54 static void
menu_item_deselect_cb(GtkWidget * widget,GtkStatusbar * statusbar)55 menu_item_deselect_cb (GtkWidget * widget, GtkStatusbar * statusbar)
56 {
57   guint context_id;
58 
59   context_id = gtk_statusbar_get_context_id (statusbar, "games-tooltip");
60   gtk_statusbar_pop (statusbar, context_id);
61 }
62 
63 static void
connect_proxy_cb(GtkUIManager * ui_manager,GtkAction * action,GtkWidget * proxy,GtkWidget * statusbar)64 connect_proxy_cb (GtkUIManager * ui_manager,
65                   GtkAction * action,
66                   GtkWidget * proxy, GtkWidget * statusbar)
67 {
68   if (!GTK_IS_MENU_ITEM (proxy))
69     return;
70 
71   g_signal_connect (proxy, "select",
72                     G_CALLBACK (menu_item_select_cb), statusbar);
73   g_signal_connect (proxy, "deselect",
74                     G_CALLBACK (menu_item_deselect_cb), statusbar);
75 }
76 
77 static void
disconnect_proxy_cb(GtkUIManager * ui_manager,GtkAction * action,GtkWidget * proxy,GtkWidget * statusbar)78 disconnect_proxy_cb (GtkUIManager * ui_manager,
79                      GtkAction * action,
80                      GtkWidget * proxy, GtkWidget * statusbar)
81 {
82   if (!GTK_IS_MENU_ITEM (proxy))
83     return;
84 
85   g_signal_handlers_disconnect_by_func
86     (proxy, G_CALLBACK (menu_item_select_cb), statusbar);
87   g_signal_handlers_disconnect_by_func
88     (proxy, G_CALLBACK (menu_item_deselect_cb), statusbar);
89 }
90 
91 /**
92  *  Call this once, after creating the UI Manager but before
93  *  you start adding actions. Then, whenever an action is added,
94  *  connect_proxy() will set tooltips to be displayed in the statusbar.
95  */
96 void
ar_stock_prepare_for_statusbar_tooltips(GtkUIManager * ui_manager,GtkWidget * statusbar)97 ar_stock_prepare_for_statusbar_tooltips (GtkUIManager * ui_manager,
98                                             GtkWidget * statusbar)
99 {
100   g_signal_connect (ui_manager, "connect-proxy",
101                     G_CALLBACK (connect_proxy_cb), statusbar);
102   g_signal_connect (ui_manager, "disconnect-proxy",
103                     G_CALLBACK (disconnect_proxy_cb), statusbar);
104 }
105 
106 /* This will become GTK_CHECK_VERSION (2, 15, x) once the patch from gtk+ bug 511332 is committed */
107 #undef HAVE_GTK_ICON_FACTORY_ADD_ALIAS
108 
109 #ifndef HAVE_GTK_ICON_FACTORY_ADD_ALIAS
110 
111 static void
register_stock_icon(GtkIconFactory * icon_factory,const char * stock_id,const char * icon_name)112 register_stock_icon (GtkIconFactory * icon_factory,
113                      const char * stock_id,
114                      const char * icon_name)
115 {
116   GtkIconSource *source;
117   GtkIconSet *set;
118 
119   set = gtk_icon_set_new ();
120 
121   source = gtk_icon_source_new ();
122   gtk_icon_source_set_icon_name (source, icon_name);
123   gtk_icon_set_add_source (set, source);
124   gtk_icon_source_free (source);
125 
126   gtk_icon_factory_add (icon_factory, stock_id, set);
127   gtk_icon_set_unref (set);
128 }
129 
130 static void
register_stock_icon_bidi(GtkIconFactory * icon_factory,const char * stock_id,const char * icon_name_ltr,const char * icon_name_rtl)131 register_stock_icon_bidi (GtkIconFactory * icon_factory,
132                           const char * stock_id,
133                           const char * icon_name_ltr,
134                           const char * icon_name_rtl)
135 {
136   GtkIconSource *source;
137   GtkIconSet *set;
138 
139   set = gtk_icon_set_new ();
140 
141   source = gtk_icon_source_new ();
142   gtk_icon_source_set_icon_name (source, icon_name_ltr);
143   gtk_icon_source_set_direction (source, GTK_TEXT_DIR_LTR);
144   gtk_icon_source_set_direction_wildcarded (source, FALSE);
145   gtk_icon_set_add_source (set, source);
146   gtk_icon_source_free (source);
147 
148   source = gtk_icon_source_new ();
149   gtk_icon_source_set_icon_name (source, icon_name_rtl);
150   gtk_icon_source_set_direction (source, GTK_TEXT_DIR_RTL);
151   gtk_icon_source_set_direction_wildcarded (source, FALSE);
152   gtk_icon_set_add_source (set, source);
153   gtk_icon_source_free (source);
154 
155   gtk_icon_factory_add (icon_factory, stock_id, set);
156   gtk_icon_set_unref (set);
157 }
158 
159 #endif /* HAVE_GTK_ICON_FACTORY_ADD_ALIAS */
160 
161 void
ar_stock_init(void)162 ar_stock_init (void)
163 {
164   /* These stocks have a gtk stock icon */
165   const char *stock_icon_aliases[][2] = {
166     { AR_STOCK_CONTENTS,         "help-contents" },
167     { AR_STOCK_HINT,             "dialog-information" },
168     { AR_STOCK_NEW_GAME,         "document-new" },
169     { AR_STOCK_START_NEW_GAME,   "document-new" },
170     { AR_STOCK_RESET,            "edit-clear" },
171     { AR_STOCK_RESTART_GAME,     "view-refresh" },
172     { AR_STOCK_FULLSCREEN,       "view-fullscreen" },
173     { AR_STOCK_LEAVE_FULLSCREEN, "view-restore" },
174     { AR_STOCK_PAUSE_GAME,       "media-playback-pause" },
175   };
176 
177 #ifndef HAVE_GTK_ICON_FACTORY_ADD_ALIAS
178   const char *stock_icon_aliases_bidi[][3] = {
179     { AR_STOCK_REDO_MOVE, "edit-redo", "edit-undo" },
180     { AR_STOCK_UNDO_MOVE, "edit-undo", "edit-redo" },
181   };
182 #endif
183 
184   /* Private icon names */
185   const char *private_icon_names[][2] = {
186     { AR_STOCK_DEAL_CARDS, "cards-deal" }
187   };
188 
189   static const GtkStockItem ar_stock_items[] = {
190     { AR_STOCK_CONTENTS,         N_("_Contents"),          0, GDK_KEY_F1, NULL },
191     { AR_STOCK_FULLSCREEN,       N_("_Fullscreen"),        0, GDK_KEY_F11, NULL },
192     { AR_STOCK_HINT,             N_("_Hint"),              GDK_CONTROL_MASK, 'h', NULL },
193     /* Translators: This "_New" is for the menu item 'Game->New', implies "New Game" */
194     { AR_STOCK_NEW_GAME,         N_("_New"),               GDK_CONTROL_MASK, 'n', NULL },
195     /* Translators: This "_New Game" is for the game-over dialogue */
196     { AR_STOCK_START_NEW_GAME,   N_("_New Game"),          0, 0, NULL },
197     { AR_STOCK_REDO_MOVE,        N_("_Redo Move"),         GDK_CONTROL_MASK | GDK_SHIFT_MASK, 'z', NULL },
198     /* Translators: this is the "Reset" scores button in a scores dialogue */
199     { AR_STOCK_RESET,            N_("_Reset"),             0, 0, NULL },
200     /* Translators: "_Restart" is the menu item 'Game->Restart', implies "Restart Game" */
201     { AR_STOCK_RESTART_GAME,     N_("_Restart"),           0, 0, NULL },
202     { AR_STOCK_UNDO_MOVE,        N_("_Undo Move"),         GDK_CONTROL_MASK, 'z', NULL },
203     { AR_STOCK_DEAL_CARDS,       N_("_Deal"),              GDK_CONTROL_MASK, 'd', NULL },
204     { AR_STOCK_LEAVE_FULLSCREEN, N_("_Leave Fullscreen"),  0, GDK_KEY_F11, NULL },
205     { AR_STOCK_PAUSE_GAME,       N_("_Pause"),             0, GDK_KEY_Pause, NULL },
206   };
207 
208   guint i;
209   GtkIconFactory *icon_factory;
210 
211   icon_factory = gtk_icon_factory_new ();
212 
213 #ifdef HAVE_GTK_ICON_FACTORY_ADD_ALIAS
214   for (i = 0; i < G_N_ELEMENTS (stock_icon_aliases); ++i) {
215     gtk_icon_factory_add_alias (stock_icon_aliases[i][0],
216                                 stock_icon_aliases[i][1]);
217   }
218 
219 #else
220   for (i = 0; i < G_N_ELEMENTS (stock_icon_aliases); ++i) {
221     register_stock_icon (icon_factory,
222                          stock_icon_aliases[i][0],
223                          stock_icon_aliases[i][1]);
224   }
225 
226   for (i = 0; i < G_N_ELEMENTS (stock_icon_aliases_bidi); ++i) {
227     register_stock_icon_bidi (icon_factory,
228                               stock_icon_aliases_bidi[i][0],
229                               stock_icon_aliases_bidi[i][1],
230                               stock_icon_aliases_bidi[i][2]);
231   }
232 #endif /* HAVE_GTK_ICON_FACTORY_ADD_ALIAS */
233 
234   /* Register our private themeable icons */
235   for (i = 0; i < G_N_ELEMENTS (private_icon_names); i++) {
236     register_stock_icon (icon_factory,
237                          private_icon_names[i][0],
238                          private_icon_names[i][1]);
239   }
240 
241   gtk_icon_factory_add_default (icon_factory);
242   g_object_unref (icon_factory);
243 
244   /* GtkIconTheme will then look in our custom hicolor dir
245    * for icons as well as the standard search paths.
246    */
247   /* FIXME: multi-head! */
248   gtk_icon_theme_append_search_path (gtk_icon_theme_get_default (),
249                                      ar_runtime_get_directory (AR_RUNTIME_ICON_THEME_DIRECTORY));
250 
251   gtk_stock_add_static (ar_stock_items, G_N_ELEMENTS (ar_stock_items));
252 }
253 
254 /**
255  * ar_get_licence:
256  *
257  * Returns: (transfer full): a newly allocated string with a GPL licence notice
258  */
259 char *
ar_get_licence(const gchar * game_name)260 ar_get_licence (const gchar *game_name)
261 {
262   const int version = 3;
263   char *license_trans, *license_str;
264 
265   static const char license0[] =
266     /* %s is replaced with the name of the game in gnome-games. */
267     N_("%s is free software; you can redistribute it and/or modify "
268        "it under the terms of the GNU General Public License as published by "
269        "the Free Software Foundation; either version %d of the License, or "
270        "(at your option) any later version.");
271   static const char license1[] =
272     N_("%s is distributed in the hope that it will be useful, "
273        "but WITHOUT ANY WARRANTY; without even the implied warranty of "
274        "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the "
275        "GNU General Public License for more details.");
276   static const char license3[] =
277     N_("You should have received a copy of the GNU General Public License "
278        "along with this program.  If not, see <http://www.gnu.org/licenses/>.");
279 
280   license_trans = g_strjoin ("\n\n", _(license0), _(license1), _(license3), NULL);
281 
282 #pragma GCC diagnostic push
283 #pragma GCC diagnostic ignored "-Wformat-nonliteral"
284   license_str =
285     g_strdup_printf (license_trans, game_name, version, game_name, game_name);
286 #pragma GCC diagnostic pop
287 
288   g_free (license_trans);
289 
290   return license_str;
291 }
292