]> git.sesse.net Git - vlc/blob - modules/misc/notify/xosd.c
51f10c877a9266e29e84e98205e5866ef8ac410f
[vlc] / modules / misc / notify / xosd.c
1 /*****************************************************************************
2  * xosd.c : X On Screen Display interface
3  *****************************************************************************
4  * Copyright (C) 2001 the VideoLAN team
5  * $Id$
6  *
7  * Authors: Loïc Minier <lool@videolan.org>
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22  *****************************************************************************/
23
24 /*****************************************************************************
25  * Preamble
26  *****************************************************************************/
27
28 #include <xosd.h>
29 #ifdef HAVE_CONFIG_H
30 # include "config.h"
31 #endif
32
33 #include <vlc_common.h>
34 #include <vlc_plugin.h>
35 #include <vlc_playlist.h>
36 #include <vlc_input.h>
37 #include <vlc_interface.h>
38
39 #ifdef HAVE_UNISTD_H
40 #    include <unistd.h>
41 #endif
42
43 /*****************************************************************************
44  * intf_sys_t: description and status of rc interface
45  *****************************************************************************/
46 struct intf_sys_t
47 {
48     xosd *      p_osd;          /* libxosd handle */
49     bool        b_need_update;  /* Update display ? */
50     vlc_mutex_t lock;           /* lock for the condition variable */
51     vlc_cond_t  cond;           /* condition variable to know when to update */
52 };
53
54 #define MAX_LINE_LENGTH 256
55
56 /*****************************************************************************
57  * Local prototypes.
58  *****************************************************************************/
59 static int  Open        ( vlc_object_t * );
60 static void Close       ( vlc_object_t * );
61
62 static void Run         ( intf_thread_t * );
63
64 static int PlaylistNext ( vlc_object_t *p_this, const char *psz_variable,
65                           vlc_value_t oval, vlc_value_t nval, void *param );
66
67 /*****************************************************************************
68  * Module descriptor
69  *****************************************************************************/
70 #define POSITION_TEXT N_("Flip vertical position")
71 #define POSITION_LONGTEXT N_("Display XOSD output at the bottom of the " \
72                              "screen instead of the top.")
73
74 #define TXT_OFS_TEXT N_("Vertical offset")
75 #define TXT_OFS_LONGTEXT N_("Vertical offset between the border of the screen "\
76                             "and the displayed text (in pixels, defaults to "\
77                             "30 pixels)." )
78
79 #define SHD_OFS_TEXT N_("Shadow offset")
80 #define SHD_OFS_LONGTEXT N_("Offset between the text and the shadow (in " \
81                             "pixels, defaults to 2 pixels)." )
82
83 #define FONT_TEXT N_("Font")
84 #define FONT_LONGTEXT N_("Font used to display text in the XOSD output.")
85 #define COLOUR_TEXT N_("Color")
86 #define COLOUR_LONGTEXT N_("Color used to display text in the XOSD output.")
87
88 vlc_module_begin ()
89     set_category( CAT_INTERFACE )
90     set_subcategory( SUBCAT_INTERFACE_CONTROL )
91     set_description( N_("XOSD interface") )
92     set_shortname( "XOSD" )
93     add_bool( "xosd-position", 1, NULL, POSITION_TEXT, POSITION_LONGTEXT, true )
94     add_integer( "xosd-text-offset", 30, NULL, TXT_OFS_TEXT, TXT_OFS_LONGTEXT, true )
95     add_integer( "xosd-shadow-offset", 2, NULL,
96                  SHD_OFS_TEXT, SHD_OFS_LONGTEXT, true )
97     add_string( "xosd-font",
98                 "-adobe-helvetica-bold-r-normal-*-*-160-*-*-p-*-iso8859-1",
99                 NULL, FONT_TEXT, FONT_LONGTEXT, true )
100     add_string( "xosd-colour", "LawnGreen",
101                     NULL, COLOUR_TEXT, COLOUR_LONGTEXT, true )
102     set_capability( "interface", 10 )
103     set_callbacks( Open, Close )
104 vlc_module_end ()
105
106 /*****************************************************************************
107  * Open: initialize and create stuff
108  *****************************************************************************/
109 static int Open( vlc_object_t *p_this )
110 {
111     intf_thread_t *p_intf = (intf_thread_t *)p_this;
112     xosd *p_osd;
113     char *psz_font, *psz_colour;
114
115     /* Allocate instance and initialize some members */
116     p_intf->p_sys = malloc( sizeof( intf_sys_t ) );
117     if( p_intf->p_sys == NULL )
118         return VLC_ENOMEM;
119
120     if( getenv( "DISPLAY" ) == NULL )
121     {
122         msg_Err( p_intf, "no display, please set the DISPLAY variable" );
123         free( p_intf->p_sys );
124         return VLC_EGENERIC;
125     }
126
127     /* Initialize library */
128 #if defined(HAVE_XOSD_VERSION_0) || defined(HAVE_XOSD_VERSION_1)
129     psz_font = config_GetPsz( p_intf, "xosd-font" );
130     psz_colour = config_GetPsz( p_intf,"xosd-colour" );
131     p_osd  = p_intf->p_sys->p_osd = xosd_init( psz_font, psz_colour, 3,
132                                                XOSD_top, 0, 1 );
133     free( psz_font );
134     free( psz_colour );
135
136     if( p_intf->p_sys->p_osd == NULL )
137     {
138         msg_Err( p_intf, "couldn't initialize libxosd" );
139         free( p_intf->p_sys );
140         return VLC_EGENERIC;
141     }
142 #else
143     p_osd = p_intf->p_sys->p_osd = xosd_create( 1 );
144     if( p_osd == NULL )
145     {
146         msg_Err( p_intf, "couldn't initialize libxosd" );
147         free( p_intf->p_sys );
148         return VLC_EGENERIC;
149     }
150
151     psz_colour = config_GetPsz( p_intf, "xosd-colour" );
152     xosd_set_colour( p_osd, psz_colour );
153     xosd_set_timeout( p_osd, 3 );
154     free( psz_colour );
155 #endif
156
157     // Initialize mutex and condition variable before adding the callbacks
158     vlc_mutex_init( &p_intf->p_sys->lock );
159     vlc_cond_init( &p_intf->p_sys->cond );
160     // Add the callbacks
161     playlist_t *p_playlist = pl_Hold( p_intf );
162     var_AddCallback( p_playlist, "item-current", PlaylistNext, p_this );
163     var_AddCallback( p_playlist, "item-change", PlaylistNext, p_this );
164     pl_Release( p_intf );
165
166     /* Set user preferences */
167     psz_font = config_GetPsz( p_intf, "xosd-font" );
168     xosd_set_font( p_intf->p_sys->p_osd, psz_font );
169     free( psz_font );
170     xosd_set_outline_colour( p_intf->p_sys->p_osd,"black" );
171 #ifdef HAVE_XOSD_VERSION_2
172     xosd_set_horizontal_offset( p_intf->p_sys->p_osd,
173                     config_GetInt( p_intf, "xosd-text-offset" ) );
174     xosd_set_vertical_offset( p_intf->p_sys->p_osd,
175                     config_GetInt( p_intf, "xosd-text-offset" ) );
176 #else
177     xosd_set_offset( p_intf->p_sys->p_osd,
178                     config_GetInt( p_intf, "xosd-text-offset" ) );
179 #endif
180     xosd_set_shadow_offset( p_intf->p_sys->p_osd,
181                     config_GetInt( p_intf, "xosd-shadow-offset" ));
182     xosd_set_pos( p_intf->p_sys->p_osd,
183                     config_GetInt( p_intf, "xosd-position" ) ?
184                                          XOSD_bottom: XOSD_top );
185
186     /* Initialize to NULL */
187     xosd_display( p_osd, 0, XOSD_string, "XOSD interface initialized" );
188
189     p_intf->pf_run = Run;
190
191     p_intf->p_sys->b_need_update = true;
192
193     return VLC_SUCCESS;
194 }
195
196 /*****************************************************************************
197  * Close: destroy interface stuff
198  *****************************************************************************/
199 static void Close( vlc_object_t *p_this )
200 {
201     intf_thread_t *p_intf = (intf_thread_t *)p_this;
202
203     playlist_t *p_playlist = pl_Hold( p_intf );
204     var_DelCallback( p_playlist, "item-current", PlaylistNext, p_this );
205     var_DelCallback( p_playlist, "item-change", PlaylistNext, p_this );
206     pl_Release( p_intf );
207
208     /* Uninitialize library */
209     xosd_destroy( p_intf->p_sys->p_osd );
210
211     /* Destroy structure */
212     vlc_cond_destroy( &p_intf->p_sys->cond );
213     vlc_mutex_destroy( &p_intf->p_sys->lock );
214     free( p_intf->p_sys );
215 }
216
217 /*****************************************************************************
218  * Run: xosd thread
219  *****************************************************************************
220  * This part of the interface runs in a separate thread
221  *****************************************************************************/
222 static void Run( intf_thread_t *p_intf )
223 {
224     playlist_t *p_playlist;
225     playlist_item_t *p_item = NULL;
226     char *psz_display = NULL;
227     int cancel = vlc_savecancel();
228
229     while( true )
230     {
231         // Wait for a signal
232         vlc_restorecancel( cancel );
233         vlc_mutex_lock( &p_intf->p_sys->lock );
234         mutex_cleanup_push( &p_intf->p_sys->lock );
235         while( !p_intf->p_sys->b_need_update )
236             vlc_cond_wait( &p_intf->p_sys->cond, &p_intf->p_sys->lock );
237         p_intf->p_sys->b_need_update = false;
238         vlc_cleanup_run();
239
240         // Compute the signal
241         cancel = vlc_savecancel();
242         p_playlist = pl_Hold( p_intf );
243         PL_LOCK;
244
245         // If the playlist is empty don't do anything
246         if( playlist_IsEmpty( p_playlist ) )
247         {
248             PL_UNLOCK;
249             pl_Release( p_intf );
250             continue;
251         }
252
253         free( psz_display );
254         int i_status = playlist_Status( p_playlist );
255         if( i_status == PLAYLIST_STOPPED )
256         {
257             psz_display = strdup(_("Stop"));
258             PL_UNLOCK;
259             pl_Release( p_intf );
260         }
261         else if( i_status == PLAYLIST_PAUSED )
262         {
263             psz_display = strdup(_("Pause"));
264             PL_UNLOCK;
265             pl_Release( p_intf );
266         }
267         else
268         {
269             p_item = playlist_CurrentPlayingItem( p_playlist );
270             if( !p_item )
271             {
272                 PL_UNLOCK;
273                 pl_Release( p_intf );
274                 continue;
275             }
276             input_item_t *p_input = p_item->p_input;
277             vlc_gc_incref( p_input );
278
279             PL_UNLOCK;
280             pl_Release( p_intf );
281
282             mtime_t i_duration = input_item_GetDuration( p_input );
283             if( i_duration != -1 )
284             {
285                 char psz_durationstr[MSTRTIME_MAX_SIZE];
286                 secstotimestr( psz_durationstr, i_duration / 1000000 );
287                 if( asprintf( &psz_display, "%s (%s)", p_input->psz_name, psz_durationstr ) == -1 )
288                     psz_display = NULL;
289             }
290             else
291                 psz_display = strdup( p_input->psz_name );
292
293             vlc_gc_decref( p_input );
294         }
295
296         /* Display */
297         xosd_display( p_intf->p_sys->p_osd, 0, /* first line */
298                       XOSD_string, psz_display );
299     }
300 }
301
302 static int PlaylistNext( vlc_object_t *p_this, const char *psz_variable,
303                 vlc_value_t oval, vlc_value_t nval, void *param )
304 {
305     (void)p_this;    (void)psz_variable;    (void)oval;    (void)nval;
306     intf_thread_t *p_intf = (intf_thread_t *)param;
307
308     // Send the signal using the condition variable
309     vlc_mutex_lock( &p_intf->p_sys->lock );
310     p_intf->p_sys->b_need_update = true;
311     vlc_cond_signal( &p_intf->p_sys->cond );
312     vlc_mutex_unlock( &p_intf->p_sys->lock );
313
314     return VLC_SUCCESS;
315 }
316