1 /*************************************************************************/
2 /* Copyright (C) 2007-2009 sujith <m.sujith@gmail.com>                   */
3 /* Copyright (C) 2009-2014 matias <mati86dl@gmail.com>                   */
4 /*                                                                       */
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 3 of the License, or     */
8 /* (at your option) any later version.                                   */
9 /*                                                                       */
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.                          */
14 /*                                                                       */
15 /* You should have received a copy of the GNU General Public License     */
16 /* along with this program.  If not, see <http://www.gnu.org/licenses/>. */
17 /*************************************************************************/
getFrameIndexReference(const MachineFunction & MF,int FI,Register & FrameReg) const18 
19 #ifdef HAVE_CONFIG_H
20 #include <config.h>
21 #endif
22 
23 #if defined(GETTEXT_PACKAGE)
24 #include <glib/gi18n-lib.h>
25 #else
26 #include <glib/gi18n.h>
27 #endif
28 
29 #include <glib.h>
30 #include <glib-object.h>
31 #include <gmodule.h>
32 #include <gtk/gtk.h>
33 
34 #include <libpeas/peas.h>
35 #include <libpeas-gtk/peas-gtk.h>
36 
37 #include <libnotify/notify.h>
38 
39 #include "plugins/pragha-plugin-macros.h"
40 
41 #include "src/pragha.h"
42 #include "src/pragha-hig.h"
43 #include "src/pragha-playback.h"
44 #include "src/pragha-utils.h"
45 #include "src/pragha-preferences-dialog.h"
46 
47 #define PRAGHA_TYPE_NOTIFY_PLUGIN         (pragha_notify_plugin_get_type ())
48 #define PRAGHA_NOTIFY_PLUGIN(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), PRAGHA_TYPE_NOTIFY_PLUGIN, PraghaNotifyPlugin))
49 #define PRAGHA_NOTIFY_PLUGIN_CLASS(k)     (G_TYPE_CHECK_CLASS_CAST((k), PRAGHA_TYPE_NOTIFY_PLUGIN, PraghaNotifyPlugin))
50 #define PRAGHA_IS_NOTIFY_PLUGIN(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), PRAGHA_TYPE_NOTIFY_PLUGIN))
51 #define PRAGHA_IS_NOTIFY_PLUGIN_CLASS(k)  (G_TYPE_CHECK_CLASS_TYPE ((k), PRAGHA_TYPE_NOTIFY_PLUGIN))
52 #define PRAGHA_NOTIFY_PLUGIN_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), PRAGHA_TYPE_NOTIFY_PLUGIN, PraghaNotifyPluginClass))
53 
54 typedef struct {
55 	PraghaApplication  *pragha;
56 	GtkWidget          *setting_widget;
57 
58 	NotifyNotification *notify;
59 
60 	GtkWidget          *album_art_in_osd_w;
61 	GtkWidget          *actions_in_osd_w;
62 	gboolean            album_art_in_osd;
63 	gboolean            actions_in_osd;
64 } PraghaNotifyPluginPrivate;
65 
66 PRAGHA_PLUGIN_REGISTER (PRAGHA_TYPE_NOTIFY_PLUGIN,
67                         PraghaNotifyPlugin,
68                         pragha_notify_plugin)
69 
70 static gboolean
71 can_support_actions (void)
72 {
73 	static gboolean supported;
74 	static gboolean have_checked = FALSE;
75 
76 	if( !have_checked ){
77 		GList * c;
78 		GList * caps = notify_get_server_caps( );
79 
80 		have_checked = TRUE;
81 
82 		for( c=caps; c && !supported; c=c->next )
83 			supported = !strcmp( "actions", (char*)c->data );
84 
85 		g_list_free_full( caps, g_free );
86 	}
87 
88 	return supported;
89 }
90 
91 static void
92 notify_closed_cb (NotifyNotification *osd,
93                   PraghaNotifyPlugin *plugin)
94 {
95 	g_object_unref (G_OBJECT(osd));
96 
97 	if (plugin->priv->notify == osd) {
98 		plugin->priv->notify = NULL;
99 	}
100 }
101 
102 static void
103 notify_Prev_Callback (NotifyNotification *osd,
104                       const char *action,
105                       PraghaNotifyPlugin *plugin)
106 {
107 	PraghaBackend *backend;
108 
109 	g_assert (action != NULL);
110 
111 	PraghaApplication *pragha = plugin->priv->pragha;
112 
113 	backend = pragha_application_get_backend (pragha);
114 	if (pragha_backend_emitted_error (backend) == FALSE)
115 		pragha_playback_prev_track(pragha);
116 }
117 
118 static void
119 notify_Next_Callback (NotifyNotification *osd,
120                       const char         *action,
121                       PraghaNotifyPlugin *plugin)
122 {
123 	PraghaBackend *backend;
124 
125 	g_assert (action != NULL);
126 
127 	PraghaApplication *pragha = plugin->priv->pragha;
128 
129 	backend = pragha_application_get_backend (pragha);
130 	if (pragha_backend_emitted_error (backend) == FALSE)
131 		pragha_playback_next_track(pragha);
132 }
133 
134 void
135 pragha_notify_plugin_show_new_track (PraghaPlaylist     *playlist,
136                                      PraghaMusicobject  *mobj,
137                                      PraghaNotifyPlugin *plugin)
138 {
139 	PraghaNotifyPluginPrivate *priv = NULL;
140 	PraghaToolbar *toolbar;
141 	gchar *summary, *body, *slength;
142 	GError *error = NULL;
143 
144 	priv = plugin->priv;
145 
146 	if (NULL == mobj)
147 		return;
148 
149 	if (gtk_window_is_active(GTK_WINDOW (pragha_application_get_window(priv->pragha))))
150 		return;
151 
152 	const gchar *file = pragha_musicobject_get_file (mobj);
153 	const gchar *title = pragha_musicobject_get_title (mobj);
154 	const gchar *artist = pragha_musicobject_get_artist (mobj);
155 	const gchar *album = pragha_musicobject_get_album (mobj);
156 	gint length = pragha_musicobject_get_length (mobj);
157 
158 	if(string_is_not_empty(title))
159 		summary = g_strdup(title);
160 	else
161 		summary = g_path_get_basename(file);
162 
163 	slength = convert_length_str(length);
164 
165 	body = g_markup_printf_escaped(_("by <b>%s</b> in <b>%s</b> <b>(%s)</b>"),
166 	                               string_is_not_empty(artist) ? artist : _("Unknown Artist"),
167 	                               string_is_not_empty(album) ? album : _("Unknown Album"),
168 	                               slength);
169 
170 	/* Create notification instance */
171 
172 	if (priv->notify == NULL) {
173 		priv->notify = notify_notification_new(summary, body, NULL);
174 
175 		if (can_support_actions() && priv->actions_in_osd) {
176 			notify_notification_add_action(
177 				priv->notify, "media-skip-backward", _("Previous track"),
178 				NOTIFY_ACTION_CALLBACK(notify_Prev_Callback), plugin,
179 				NULL);
180 			notify_notification_add_action(
181 				priv->notify, "media-skip-forward", _("Next track"),
182 				NOTIFY_ACTION_CALLBACK(notify_Next_Callback), plugin,
183 				NULL);
184 		}
185 		notify_notification_set_hint (priv->notify, "transient", g_variant_new_boolean (TRUE));
186 		g_signal_connect (priv->notify, "closed", G_CALLBACK (notify_closed_cb), plugin);
187 	}
188 	else {
189 		notify_notification_update (priv->notify, summary, body, NULL);
190 
191 		if (!priv->actions_in_osd)
192 			notify_notification_clear_actions (priv->notify);
193 	}
194 
195 	/* Add album art if set */
196 	if (priv->album_art_in_osd) {
197 		toolbar = pragha_application_get_toolbar (priv->pragha);
198 		notify_notification_set_image_from_pixbuf (priv->notify,
199 			pragha_album_art_get_pixbuf (pragha_toolbar_get_album_art(toolbar)));
200 	}
201 
202 	/* Show OSD */
203 	if (!notify_notification_show (priv->notify, &error)) {
204 		g_warning("Unable to show OSD notification: %s", error->message);
205 		g_error_free (error);
206 	}
207 
208 	/* Cleanup */
209 
210 	g_free(summary);
211 	g_free(body);
212 	g_free(slength);
213 }
214 
215 static void
216 pragha_notify_preferences_dialog_response (GtkDialog          *dialog,
217                                            gint                response_id,
218                                            PraghaNotifyPlugin *plugin)
219 {
220 	PraghaPreferences *preferences;
221 	gchar *plugin_group = NULL;
222 
223 	PraghaNotifyPluginPrivate *priv = plugin->priv;
224 
225 	switch(response_id) {
226 		case GTK_RESPONSE_CANCEL:
227 			gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(priv->album_art_in_osd_w),
228 			                              priv->album_art_in_osd);
229 			gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(priv->actions_in_osd_w),
230 			                              priv->actions_in_osd);
231 			break;
232 		case GTK_RESPONSE_OK:
233 			priv->album_art_in_osd =
234 				gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(priv->album_art_in_osd_w));
235 			priv->actions_in_osd =
236 				gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(priv->actions_in_osd_w));
237 
238 			preferences = pragha_preferences_get ();
239 			plugin_group = pragha_preferences_get_plugin_group_name(preferences, "notify");
240 
241 			pragha_preferences_set_boolean (preferences,
242 			                                plugin_group, "album_art_in_osd",
243 			                                priv->album_art_in_osd);
244 			pragha_preferences_set_boolean (preferences,
245 			                                plugin_group, "actions_in_osd",
246 			                                priv->actions_in_osd);
247 
248 			g_object_unref (preferences);
249 			g_free (plugin_group);
250 			break;
251 		default:
252 			break;
253 	}
254 }
255 
256 static void
257 pragha_notify_plugin_append_setting (PraghaNotifyPlugin *plugin)
258 {
259 	PreferencesDialog *dialog;
260 	GtkWidget *table, *albumart_in_osd, *actions_in_osd;
261 	guint row = 0;
262 
263 	PraghaNotifyPluginPrivate *priv = plugin->priv;
264 
265 	table = pragha_hig_workarea_table_new ();
266 
267 	pragha_hig_workarea_table_add_section_title(table, &row, _("Notifications"));
268 
269 	albumart_in_osd = gtk_check_button_new_with_label(_("Show Album art in notifications"));
270 	pragha_hig_workarea_table_add_wide_control(table, &row, albumart_in_osd);
271 
272 	gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(albumart_in_osd), priv->album_art_in_osd);
273 
274 	actions_in_osd = gtk_check_button_new_with_label(_("Add actions to change track in notifications"));
275 	pragha_hig_workarea_table_add_wide_control(table, &row, actions_in_osd);
276 
277 	gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(actions_in_osd), priv->actions_in_osd);
278 
279 	if (!can_support_actions())
280 		gtk_widget_set_sensitive (actions_in_osd, FALSE);
281 
282 	priv->setting_widget = table;
283 	priv->album_art_in_osd_w = albumart_in_osd;
284 	priv->actions_in_osd_w = actions_in_osd;
285 
286 	dialog = pragha_application_get_preferences_dialog (priv->pragha);
287 	pragha_preferences_append_desktop_setting (dialog, table, FALSE);
288 
289 	/* Configure handler and settings */
290 	pragha_preferences_dialog_connect_handler (dialog,
291 	                                           G_CALLBACK(pragha_notify_preferences_dialog_response),
292 	                                           plugin);
293 }
294 
295 static void
296 pragha_notify_plugin_remove_setting (PraghaNotifyPlugin *plugin)
297 {
298 	PreferencesDialog *dialog;
299 	PraghaNotifyPluginPrivate *priv = plugin->priv;
300 
301 	dialog = pragha_application_get_preferences_dialog (priv->pragha);
302 
303 	pragha_preferences_dialog_disconnect_handler (dialog,
304 	                                              G_CALLBACK(pragha_notify_preferences_dialog_response),
305 	                                              plugin);
306 	pragha_preferences_remove_desktop_setting (dialog, priv->setting_widget);
307 }
308 
309 static void
310 pragha_plugin_activate (PeasActivatable *activatable)
311 {
312 	PraghaPreferences *preferences;
313 	PraghaPlaylist *playlist;
314 	gchar *plugin_group = NULL;
315 
316 	PraghaNotifyPlugin *plugin = PRAGHA_NOTIFY_PLUGIN (activatable);
317 	PraghaNotifyPluginPrivate *priv = plugin->priv;
318 
319 	CDEBUG(DBG_PLUGIN, "Notify plugin %s", G_STRFUNC);
320 
321 	priv->pragha = g_object_get_data (G_OBJECT (plugin), "object");
322 
323 	notify_init (PACKAGE_NAME);
324 
325 	preferences = pragha_application_get_preferences (priv->pragha);
326 	plugin_group = pragha_preferences_get_plugin_group_name (preferences, "notify");
327 	if (pragha_preferences_has_group (preferences, plugin_group)) {
328 		priv->actions_in_osd =
329 			pragha_preferences_get_boolean (preferences,
330 			                                plugin_group,
331 			                                "actions_in_osd");
332 		priv->album_art_in_osd =
333 			pragha_preferences_get_boolean (preferences,
334 			                                plugin_group,
335 			                                "album_art_in_osd");
336 	}
337 	else {
338 		priv->actions_in_osd = TRUE;
339 		priv->album_art_in_osd = TRUE;
340 	}
341 
342 	/* Fix for nofify-osd users */
343 	if (!can_support_actions())
344 		priv->actions_in_osd = FALSE;
345 
346 	playlist = pragha_application_get_playlist (priv->pragha);
347 	g_signal_connect (playlist, "playlist-set-track",
348 	                  G_CALLBACK(pragha_notify_plugin_show_new_track), plugin);
349 
350 	pragha_notify_plugin_append_setting (plugin);
351 
352 	g_free (plugin_group);
353 }
354 
355 static void
356 pragha_plugin_deactivate (PeasActivatable *activatable)
357 {
358 	PraghaPlaylist *playlist;
359 
360 	PraghaNotifyPlugin *plugin = PRAGHA_NOTIFY_PLUGIN (activatable);
361 	PraghaNotifyPluginPrivate *priv = plugin->priv;
362 
363 	CDEBUG(DBG_PLUGIN, "Notify plugin %s", G_STRFUNC);
364 
365 	notify_uninit ();
366 
367 	playlist = pragha_application_get_playlist (priv->pragha);
368 	g_signal_handlers_disconnect_by_func (playlist,
369 	                                      pragha_notify_plugin_show_new_track,
370 	                                      plugin);
371 
372 	pragha_notify_plugin_remove_setting (plugin);
373 
374 	priv->pragha= NULL;
375 }
376