1 /* totem-interface.c
2  *
3  *  Copyright (C) 2005 Bastien Nocera
4  *
5  *  The Gnome Library is free software; you can redistribute it and/or
6  *  modify it under the terms of the GNU Library General Public License as
7  *  published by the Free Software Foundation; either version 2 of the
8  *  License, or (at your option) any later version.
9  *
10  *  The Gnome Library 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 GNU
13  *  Library General Public License for more details.
14  *
15  *  You should have received a copy of the GNU Library General Public
16  *  License along with the Gnome Library; see the file COPYING.LIB.  If not,
17  *  see <http://www.gnu.org/licenses/>.
18  *
19  *  Author: Bastien Nocera <hadess@hadess.net>
20  *
21  * The Totem project hereby grant permission for non-gpl compatible GStreamer
22  * plugins to be used and distributed together with GStreamer and Totem. This
23  * permission are above and beyond the permissions granted by the GPL license
24  * Totem is covered by.
25  *
26  * Monday 7th February 2005: Christian Schaller: Add exception clause.
27  * See license_change file for details.
28  *
29  */
30 
31 /**
32  * SECTION:totem-interface
33  * @short_description: interface utility/loading/error functions
34  * @stability: Unstable
35  * @include: totem-interface.h
36  *
37  * A collection of interface utility functions, for loading interfaces and displaying errors.
38  **/
39 
40 #include "config.h"
41 
42 #include <glib.h>
43 #include <glib/gi18n.h>
44 #include <gtk/gtk.h>
45 #include <gtk/gtkx.h>
46 
47 #include "totem-interface.h"
48 
49 static GtkWidget *
totem_interface_error_dialog(const char * title,const char * reason,GtkWindow * parent)50 totem_interface_error_dialog (const char *title, const char *reason,
51 		GtkWindow *parent)
52 {
53 	GtkWidget *error_dialog;
54 
55 	if (reason == NULL)
56 		g_warning ("%s called with reason == NULL", G_STRFUNC);
57 
58 	error_dialog =
59 		gtk_message_dialog_new (NULL,
60 				GTK_DIALOG_MODAL,
61 				GTK_MESSAGE_ERROR,
62 				GTK_BUTTONS_OK,
63 				"%s", title);
64 	gtk_message_dialog_format_secondary_text
65 		(GTK_MESSAGE_DIALOG (error_dialog), "%s", reason);
66 
67 	gtk_window_set_transient_for (GTK_WINDOW (error_dialog),
68 				      GTK_WINDOW (parent));
69 	gtk_window_set_title (GTK_WINDOW (error_dialog), ""); /* as per HIG */
70 	gtk_dialog_set_default_response (GTK_DIALOG (error_dialog),
71 			GTK_RESPONSE_OK);
72 	gtk_window_set_modal (GTK_WINDOW (error_dialog), TRUE);
73 
74 	return error_dialog;
75 }
76 
77 /**
78  * totem_interface_error:
79  * @title: the error title
80  * @reason: the error reason (secondary text)
81  * @parent: the error dialogue's parent #GtkWindow
82  *
83  * Display a modal error dialogue with @title as its primary error text, and @reason
84  * as its secondary text.
85  **/
86 void
totem_interface_error(const char * title,const char * reason,GtkWindow * parent)87 totem_interface_error (const char *title, const char *reason,
88 		GtkWindow *parent)
89 {
90 	GtkWidget *error_dialog;
91 
92 	error_dialog = totem_interface_error_dialog (title, reason, parent);
93 
94 	g_signal_connect (G_OBJECT (error_dialog), "response", G_CALLBACK
95 			(gtk_widget_destroy), error_dialog);
96 
97 	gtk_window_present (GTK_WINDOW (error_dialog));
98 }
99 
100 /**
101  * totem_interface_error_blocking:
102  * @title: the error title
103  * @reason: the error reason (secondary text)
104  * @parent: the error dialogue's parent #GtkWindow
105  *
106  * Display a modal error dialogue like totem_interface_error() which blocks until the user has
107  * dismissed it.
108  **/
109 void
totem_interface_error_blocking(const char * title,const char * reason,GtkWindow * parent)110 totem_interface_error_blocking (const char *title, const char *reason,
111 		GtkWindow *parent)
112 {
113 	GtkWidget *error_dialog;
114 
115 	error_dialog = totem_interface_error_dialog (title, reason, parent);
116 
117 	gtk_dialog_run (GTK_DIALOG (error_dialog));
118 	gtk_widget_destroy (error_dialog);
119 }
120 
121 /**
122  * totem_interface_error_with_link:
123  * @title: the error title
124  * @reason: the error reason (secondary text)
125  * @uri: the URI to open
126  * @label: a label for the URI's button, or %NULL to use @uri as the label
127  * @parent: the error dialogue's parent #GtkWindow
128  *
129  * Display a modal error dialogue like totem_interface_error(),
130  * but add a button which will open @uri in a browser window.
131  **/
132 void
totem_interface_error_with_link(const char * title,const char * reason,const char * uri,const char * label,GtkWindow * parent)133 totem_interface_error_with_link (const char *title, const char *reason,
134 				 const char *uri, const char *label, GtkWindow *parent)
135 {
136 	GtkWidget *error_dialog, *link_button, *hbox;
137 
138 	if (label == NULL)
139 		label = uri;
140 
141 	error_dialog = totem_interface_error_dialog (title, reason, parent);
142 	link_button = gtk_link_button_new_with_label (uri, label);
143 
144 	hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
145 	gtk_box_set_homogeneous (GTK_BOX (hbox), TRUE);
146 	gtk_box_pack_start (GTK_BOX (hbox), link_button, FALSE, FALSE, 0);
147 	gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (error_dialog))), hbox, TRUE, FALSE, 0);
148 	gtk_widget_show_all (hbox);
149 
150 	gtk_dialog_set_default_response (GTK_DIALOG (error_dialog), GTK_RESPONSE_OK);
151 
152 	g_signal_connect (G_OBJECT (error_dialog), "response", G_CALLBACK
153 			(gtk_widget_destroy), error_dialog);
154 
155 	gtk_window_present (GTK_WINDOW (error_dialog));
156 }
157 
158 /**
159  * totem_interface_load:
160  * @name: the #GtkBuilder UI file to load
161  * @fatal: %TRUE if errors loading the file should be fatal, %FALSE otherwise
162  * @parent: (allow-none): the parent window to use when displaying error dialogues, or %NULL
163  * @user_data: (allow-none): the user data to pass to gtk_builder_connect_signals(), or %NULL
164  *
165  * Load a #GtkBuilder UI file with the given name and return the #GtkBuilder instance for it. If loading the file fails, an error dialogue is shown.
166  *
167  * Return value: (transfer full): the loaded #GtkBuilder object, or %NULL
168  */
169 GtkBuilder *
totem_interface_load(const char * name,gboolean fatal,GtkWindow * parent,gpointer user_data)170 totem_interface_load (const char *name, gboolean fatal, GtkWindow *parent, gpointer user_data)
171 {
172 	GtkBuilder *builder = NULL;
173 	char *filename;
174 
175 	filename = totem_interface_get_full_path (name);
176 	if (filename == NULL) {
177 		char *msg;
178 
179 		msg = g_strdup_printf (_("Couldn’t load the “%s” interface. %s"), name, _("The file does not exist."));
180 		if (fatal == FALSE)
181 			totem_interface_error (msg, _("Make sure that Totem is properly installed."), parent);
182 		else
183 			totem_interface_error_blocking (msg, _("Make sure that Totem is properly installed."), parent);
184 
185 		g_free (msg);
186 		return NULL;
187 	}
188 
189 	builder = totem_interface_load_with_full_path (filename, fatal, parent,
190 						       user_data);
191 	g_free (filename);
192 
193 	return builder;
194 }
195 
196 /**
197  * totem_interface_load_with_full_path:
198  * @filename: the #GtkBuilder UI file path to load
199  * @fatal: %TRUE if errors loading the file should be fatal, %FALSE otherwise
200  * @parent: (allow-none): the parent window to use when displaying error dialogues, or %NULL
201  * @user_data: (allow-none): the user data to pass to gtk_builder_connect_signals(), or %NULL
202  *
203  * Load a #GtkBuilder UI file from the given path and return the #GtkBuilder instance for it. If loading the file fails, an error dialogue is shown.
204  *
205  * Return value: (transfer full): the loaded #GtkBuilder object, or %NULL
206  */
207 GtkBuilder *
totem_interface_load_with_full_path(const char * filename,gboolean fatal,GtkWindow * parent,gpointer user_data)208 totem_interface_load_with_full_path (const char *filename, gboolean fatal,
209 				     GtkWindow *parent, gpointer user_data)
210 {
211 	GtkBuilder *builder = NULL;
212 	GError *error = NULL;
213 
214 	if (filename != NULL) {
215 		builder = gtk_builder_new ();
216 		gtk_builder_set_translation_domain (builder, GETTEXT_PACKAGE);
217 	}
218 
219 	if (builder == NULL || gtk_builder_add_from_file (builder, filename, &error) == FALSE) {
220 		char *msg;
221 
222 		msg = g_strdup_printf (_("Couldn’t load the “%s” interface. %s"), filename, error->message);
223 		if (fatal == FALSE)
224 			totem_interface_error (msg, _("Make sure that Totem is properly installed."), parent);
225 		else
226 			totem_interface_error_blocking (msg, _("Make sure that Totem is properly installed."), parent);
227 
228 		g_free (msg);
229 		g_error_free (error);
230 
231 		return NULL;
232 	}
233 
234 	gtk_builder_connect_signals (builder, user_data);
235 
236 	return builder;
237 }
238 
239 char *
totem_interface_get_full_path(const char * name)240 totem_interface_get_full_path (const char *name)
241 {
242 	char *filename;
243 
244 #ifdef TOTEM_RUN_IN_SOURCE_TREE
245 	/* Try the GtkBuilder file in the source tree first */
246 	filename = g_build_filename ("..", "data", name, NULL);
247 	if (g_file_test (filename, G_FILE_TEST_EXISTS) == FALSE)
248 	{
249 		g_free (filename);
250 		/* Try the local file */
251 		filename = g_build_filename (DATADIR,
252 				"totem", name, NULL);
253 
254 		if (g_file_test (filename, G_FILE_TEST_EXISTS) == FALSE)
255 		{
256 			g_free (filename);
257 			return NULL;
258 		}
259 	}
260 #else
261 	filename = g_build_filename (DATADIR,
262 	                                "totem", name, NULL);
263 #endif
264 
265 	return filename;
266 }
267 
268 /**
269  * totem_interface_create_header_button:
270  * @header: The header widget to put the button in
271  * @button: The button to use in the header
272  * @icon_name: The icon name for the button image
273  * @pack_type: A #GtkPackType to tell us where to include the button
274  *
275  * Put the given @icon_name into @button, and pack @button into @header
276  * according to @pack_type.
277  *
278  * Return value: (transfer none): the button passed as input
279  */
280 GtkWidget *
totem_interface_create_header_button(GtkWidget * header,GtkWidget * button,const char * icon_name,GtkPackType pack_type)281 totem_interface_create_header_button (GtkWidget  *header,
282 				      GtkWidget  *button,
283 				      const char *icon_name,
284 				      GtkPackType pack_type)
285 {
286 	GtkWidget *image;
287 	GtkStyleContext *context;
288 
289 	image = gtk_image_new_from_icon_name (icon_name, GTK_ICON_SIZE_MENU);
290 	gtk_button_set_image (GTK_BUTTON (button), image);
291 	context = gtk_widget_get_style_context (button);
292 	gtk_style_context_add_class (context, "image-button");
293 	g_object_set (G_OBJECT (button), "valign", GTK_ALIGN_CENTER, NULL);
294 	if (GTK_IS_MENU_BUTTON (button))
295 		      g_object_set (G_OBJECT (button), "use-popover", TRUE, NULL);
296 
297 	if (pack_type == GTK_PACK_END)
298 		gtk_header_bar_pack_end (GTK_HEADER_BAR (header), button);
299 	else
300 		gtk_header_bar_pack_start (GTK_HEADER_BAR (header), button);
301 
302 	return button;
303 }
304