1 /*
2 *
3 * Author: Giacomo Lozito <james@develia.org>, (C) 2005-2007
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18 *
19 */
20
21 #include <glib.h>
22 #include <string.h>
23
24 #include <libaudcore/drct.h>
25 #include <libaudcore/i18n.h>
26 #include <libaudcore/audstrings.h>
27 #include <libaudcore/hook.h>
28
29 #include "aosd_trigger.h"
30 #include "aosd_trigger_private.h"
31 #include "aosd_cfg.h"
32 #include "aosd_osd.h"
33
34 /* prototypes of trigger functions */
35 static void aosd_trigger_func_pb_start_onoff ( bool );
36 static void aosd_trigger_func_pb_start_cb ( void * , void * );
37 static void aosd_trigger_func_pb_titlechange_onoff ( bool );
38 static void aosd_trigger_func_pb_titlechange_cb ( void * , void * );
39 static void aosd_trigger_func_pb_pauseon_onoff ( bool );
40 static void aosd_trigger_func_pb_pauseon_cb ( void * , void * );
41 static void aosd_trigger_func_pb_pauseoff_onoff ( bool );
42 static void aosd_trigger_func_pb_pauseoff_cb ( void * , void * );
43 static void aosd_trigger_func_hook_cb ( void * markup_text , void * unused );
44
45 /* map trigger codes to trigger objects */
46 aosd_trigger_t aosd_triggers[] =
47 {
48 // AOSD_TRIGGER_PB_START
49 { N_("Playback Start") ,
50 N_("Triggers OSD when a playlist entry is played.") ,
51 aosd_trigger_func_pb_start_onoff ,
52 aosd_trigger_func_pb_start_cb },
53
54 // AOSD_TRIGGER_PB_TITLECHANGE
55 { N_("Title Change") ,
56 N_("Triggers OSD when the song title changes (for internet streams).") ,
57 aosd_trigger_func_pb_titlechange_onoff ,
58 aosd_trigger_func_pb_titlechange_cb },
59
60 // AOSD_TRIGGER_PB_PAUSEON
61 { N_("Pause On") ,
62 N_("Triggers OSD when playback is paused.") ,
63 aosd_trigger_func_pb_pauseon_onoff ,
64 aosd_trigger_func_pb_pauseon_cb },
65
66 // AOSD_TRIGGER_PB_PAUSEOFF
67 { N_("Pause Off") ,
68 N_("Triggers OSD when playback is unpaused.") ,
69 aosd_trigger_func_pb_pauseoff_onoff ,
70 aosd_trigger_func_pb_pauseoff_cb }
71 };
72
73 static_assert (aud::n_elems (aosd_triggers) == AOSD_NUM_TRIGGERS, "update aosd_triggers");
74
75 /* TRIGGER API */
76
77 const char *
aosd_trigger_get_name(int trig_code)78 aosd_trigger_get_name ( int trig_code )
79 {
80 if (trig_code >= 0 && trig_code < aud::n_elems (aosd_triggers))
81 return aosd_triggers[trig_code].name;
82 return nullptr;
83 }
84
85
86 const char *
aosd_trigger_get_desc(int trig_code)87 aosd_trigger_get_desc ( int trig_code )
88 {
89 if (trig_code >= 0 && trig_code < aud::n_elems (aosd_triggers))
90 return aosd_triggers[trig_code].desc;
91 return nullptr;
92 }
93
94
aosd_trigger_start(const aosd_cfg_osd_trigger_t & cfg_trigger)95 void aosd_trigger_start (const aosd_cfg_osd_trigger_t & cfg_trigger)
96 {
97 for (int i = 0; i < AOSD_NUM_TRIGGERS; i ++)
98 {
99 if (cfg_trigger.enabled[i])
100 aosd_triggers[i].onoff_func (true);
101 }
102
103 /* When called, this hook will display the text of the user pointer
104 or the current playing song, if nullptr */
105 hook_associate( "aosd toggle" , aosd_trigger_func_hook_cb , nullptr );
106 }
107
108
aosd_trigger_stop(const aosd_cfg_osd_trigger_t & cfg_trigger)109 void aosd_trigger_stop (const aosd_cfg_osd_trigger_t & cfg_trigger)
110 {
111 hook_dissociate( "aosd toggle" , aosd_trigger_func_hook_cb );
112
113 for (int i = 0; i < AOSD_NUM_TRIGGERS; i ++)
114 {
115 if (cfg_trigger.enabled[i])
116 aosd_triggers[i].onoff_func (false);
117 }
118 }
119
120
121 /* TRIGGER FUNCTIONS */
122
123 static void
aosd_trigger_func_pb_start_onoff(bool turn_on)124 aosd_trigger_func_pb_start_onoff ( bool turn_on )
125 {
126 if (turn_on == true)
127 hook_associate("playback ready", aosd_trigger_func_pb_start_cb, nullptr);
128 else
129 hook_dissociate("playback ready", aosd_trigger_func_pb_start_cb);
130 }
131
132 static void
aosd_trigger_func_pb_start_cb(void * hook_data,void * user_data)133 aosd_trigger_func_pb_start_cb(void * hook_data, void * user_data)
134 {
135 String title = aud_drct_get_title ();
136 char * markup = g_markup_printf_escaped ("<span font_desc='%s'>%s</span>",
137 (const char *) global_config.text.fonts_name[0], (const char *) title);
138
139 aosd_osd_display (markup, & global_config, false);
140 g_free (markup);
141 }
142
143 typedef struct
144 {
145 String title;
146 String filename;
147 }
148 aosd_pb_titlechange_prevs_t;
149
150 static void
aosd_trigger_func_pb_titlechange_onoff(bool turn_on)151 aosd_trigger_func_pb_titlechange_onoff ( bool turn_on )
152 {
153 static aosd_pb_titlechange_prevs_t *prevs = nullptr;
154
155 if ( turn_on == true )
156 {
157 prevs = new aosd_pb_titlechange_prevs_t;
158 hook_associate( "title change" , aosd_trigger_func_pb_titlechange_cb , prevs );
159 }
160 else
161 {
162 hook_dissociate( "title change" , aosd_trigger_func_pb_titlechange_cb );
163 if ( prevs != nullptr )
164 {
165 delete prevs;
166 prevs = nullptr;
167 }
168 }
169 }
170
171 static void
aosd_trigger_func_pb_titlechange_cb(void * plentry_gp,void * prevs_gp)172 aosd_trigger_func_pb_titlechange_cb ( void * plentry_gp , void * prevs_gp )
173 {
174 if (aud_drct_get_playing ())
175 {
176 aosd_pb_titlechange_prevs_t *prevs = (aosd_pb_titlechange_prevs_t *) prevs_gp;
177 String pl_entry_filename = aud_drct_get_filename ();
178 Tuple pl_entry_tuple = aud_drct_get_tuple ();
179 String pl_entry_title = pl_entry_tuple.get_str (Tuple::FormattedTitle);
180
181 /* same filename but title changed, useful to detect http stream song changes */
182
183 if ( ( prevs->title != nullptr ) && ( prevs->filename != nullptr ) )
184 {
185 if ( ( pl_entry_filename != nullptr ) && ( !strcmp(pl_entry_filename,prevs->filename) ) )
186 {
187 if ( ( pl_entry_title != nullptr ) && ( strcmp(pl_entry_title,prevs->title) ) )
188 {
189 /* string formatting is done here a.t.m. - TODO - improve this area */
190 char * markup = g_markup_printf_escaped
191 ("<span font_desc='%s'>%s</span>",
192 (const char *) global_config.text.fonts_name[0],
193 (const char *) pl_entry_title);
194
195 aosd_osd_display (markup, & global_config, false);
196 g_free (markup);
197
198 prevs->title = pl_entry_title;
199 }
200 }
201 else
202 {
203 prevs->filename = pl_entry_filename;
204 /* if filename changes, reset title as well */
205 prevs->title = pl_entry_title;
206 }
207 }
208 else
209 {
210 prevs->title = pl_entry_title;
211 prevs->filename = pl_entry_filename;
212 }
213 }
214 }
215
216 static void
aosd_trigger_func_pb_pauseon_onoff(bool turn_on)217 aosd_trigger_func_pb_pauseon_onoff ( bool turn_on )
218 {
219 if ( turn_on == true )
220 hook_associate( "playback pause" , aosd_trigger_func_pb_pauseon_cb , nullptr );
221 else
222 hook_dissociate( "playback pause" , aosd_trigger_func_pb_pauseon_cb );
223 }
224
225 static void
aosd_trigger_func_pb_pauseon_cb(void * unused1,void * unused2)226 aosd_trigger_func_pb_pauseon_cb ( void * unused1 , void * unused2 )
227 {
228 char * markup = g_markup_printf_escaped ("<span font_desc='%s'>Paused</span>",
229 (const char *) global_config.text.fonts_name[0]);
230 aosd_osd_display (markup, & global_config, false);
231 g_free (markup);
232 }
233
234
235 static void
aosd_trigger_func_pb_pauseoff_onoff(bool turn_on)236 aosd_trigger_func_pb_pauseoff_onoff ( bool turn_on )
237 {
238 if ( turn_on == true )
239 hook_associate( "playback unpause" , aosd_trigger_func_pb_pauseoff_cb , nullptr );
240 else
241 hook_dissociate( "playback unpause" , aosd_trigger_func_pb_pauseoff_cb );
242 }
243
244 static void
aosd_trigger_func_pb_pauseoff_cb(void * unused1,void * unused2)245 aosd_trigger_func_pb_pauseoff_cb ( void * unused1 , void * unused2 )
246 {
247 Tuple tuple = aud_drct_get_tuple ();
248 int time_cur, time_tot;
249 int time_cur_m, time_cur_s, time_tot_m, time_tot_s;
250
251 time_tot = tuple.get_int (Tuple::Length) / 1000;
252 time_cur = aud_drct_get_time() / 1000;
253 time_cur_s = time_cur % 60;
254 time_cur_m = (time_cur - time_cur_s) / 60;
255 time_tot_s = time_tot % 60;
256 time_tot_m = (time_tot - time_tot_s) / 60;
257
258 String title = tuple.get_str (Tuple::FormattedTitle);
259 char * markup = g_markup_printf_escaped
260 ("<span font_desc='%s'>%s (%i:%02i/%i:%02i)</span>",
261 (const char *) global_config.text.fonts_name[0], (const char *) title,
262 time_cur_m, time_cur_s, time_tot_m, time_tot_s);
263
264 aosd_osd_display (markup, & global_config, false);
265 g_free (markup);
266 }
267
268
269 /* Call with hook_call("aosd toggle", param);
270 If param != nullptr, display the supplied text in the OSD
271 If param == nullptr, display the current playing song */
272 static void
aosd_trigger_func_hook_cb(void * markup_text,void * unused)273 aosd_trigger_func_hook_cb ( void * markup_text , void * unused )
274 {
275 if ( markup_text != nullptr )
276 {
277 /* Display text from caller */
278 aosd_osd_display ((char *) markup_text, & global_config, false);
279 } else {
280 /* Display currently playing song */
281 aosd_trigger_func_pb_start_cb (nullptr, nullptr);
282 }
283 }
284