already a system macro under MacOS X.
* ./plugins/dummy/dummy.c: fixed vlc:loop, vlc:quit, etc. entries.
* ./plugins/glide/glide.c: activated double buffering.
* ./plugins/mga/xmga.c: started writing an xmga plugin; doesn't work yet.
* ./src/input/input.c: fixed the input memory leak, and the insane thread
spawning we got with vlc:loop.
* ./src/misc/intf_eject.c: disc ejection routine courtesy of Julien Blache,
currently Linux-only.
C: jobi
D: VCD input
+N: Julien Blache
+E: jb@technologeek.org
+D: Disc ejection code
+
N: Emmanuel Blindauer
E: manu@agat.net
D: aRts audio output
List of known vlc bugs
-$Id: BUGS,v 1.3 2002/01/05 16:09:49 sam Exp $
+$Id: BUGS,v 1.4 2002/01/09 02:01:14 sam Exp $
Please try to keep this file up to date. Also, grep for FIXME in the
source files for more and more bugs to fix.
Input:
- * There is a memory leak in the input because the input thread is
- never joined for termination.
-
- * vlc:foo targets don't work anymore.
+ -
Audio output:
* The DirectX video output plugin is broken because of vout4.
- * The GGI video output plugin is broken because of vout4.
-
* The BeOS video output plugin is broken because of vout4.
* The QNX video output plugin is broken because of vout4.
* Saving preferences does not work at all.
+
+Misc:
+
+ * The Jin-Roh DVD seems to segfault.
+
memcpy/memcpymmxext \
memcpy/memcpy3dn \
mga/mga \
+ mga/xmga \
motion/motion \
motion/motionmmx \
motion/motionmmxext \
#
# C Objects
#
-INTERFACE := main interface intf_msg intf_playlist
+INTERFACE := main interface intf_msg intf_playlist intf_eject
INPUT := input input_ext-dec input_ext-intf input_dec input_programs input_clock mpeg_system
VIDEO_OUTPUT := video_output video_text vout_pictures vout_subpictures
AUDIO_OUTPUT := audio_output aout_ext-dec aout_u8 aout_s8 aout_u16 aout_s16 aout_spdif
enableval="$enable_mga"
if test x$enable_mga = xyes
then
- PLUGINS="${PLUGINS} mga"
+ PLUGINS="${PLUGINS} mga xmga"
fi
fi
[ --enable-mga Linux kernel Matrox support (default disabled)],
[ if test x$enable_mga = xyes
then
- PLUGINS="${PLUGINS} mga"
+ PLUGINS="${PLUGINS} mga xmga"
fi ])
dnl
* Collection of useful common types and macros definitions
*****************************************************************************
* Copyright (C) 1998, 1999, 2000 VideoLAN
- * $Id: common.h,v 1.66 2002/01/07 02:12:29 sam Exp $
+ * $Id: common.h,v 1.67 2002/01/09 02:01:14 sam Exp $
*
* Authors: Samuel Hocevar <sam@via.ecp.fr>
* Vincent Seguin <seguin@via.ecp.fr>
void ( * intf_PlaylistDestroy ) ( struct playlist_s * );
void ( * intf_PlaylistJumpto ) ( struct playlist_s *, int );
void ( * intf_UrlDecode ) ( char * );
+ int ( * intf_Eject ) ( const char * );
void ( * msleep ) ( mtime_t );
mtime_t ( * mdate ) ( void );
struct module_s * ( * module_Need ) ( int, char *, struct probedata_s * );
void ( * module_Unneed ) ( struct module_s * );
+
} module_symbols_t;
#ifdef PLUGIN
* control the pace of reading.
*****************************************************************************
* Copyright (C) 1999, 2000 VideoLAN
- * $Id: input_ext-intf.h,v 1.56 2002/01/07 02:12:29 sam Exp $
+ * $Id: input_ext-intf.h,v 1.57 2002/01/09 02:01:14 sam Exp $
*
* Authors: Christophe Massiot <massiot@via.ecp.fr>
*
boolean_t b_error;
boolean_t b_eof;
vlc_thread_t thread_id; /* id for thread functions */
- int * pi_status; /* temporary status flag */
+ int i_status; /* status flag */
/* Input module */
struct module_s * p_input_module;
struct input_thread_s * input_CreateThread ( struct playlist_item_s *,
int *pi_status );
-void input_DestroyThread ( struct input_thread_s *, int *pi_status );
+void input_StopThread ( struct input_thread_s *, int *pi_status );
+void input_DestroyThread ( struct input_thread_s * );
void input_SetStatus ( struct input_thread_s *, int );
void input_Seek ( struct input_thread_s *, off_t );
--- /dev/null
+/*****************************************************************************
+ * intf_eject.h: CD/DVD-ROM ejection handling functions
+ *****************************************************************************
+ * Copyright (C) 2001, 2002 VideoLAN
+ * $Id: intf_eject.h,v 1.1 2002/01/09 02:01:14 sam Exp $
+ *
+ * Author: Julien Blache <jb@technologeek.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
+ *****************************************************************************/
+
+#ifndef PLUGIN
+int intf_Eject( const char * );
+#else
+# define intf_Eject p_symbols->intf_Eject
+#endif
* modules_inner.h : Macros used from within a module.
*****************************************************************************
* Copyright (C) 2001 VideoLAN
- * $Id: modules_inner.h,v 1.10 2001/12/30 07:09:54 sam Exp $
+ * $Id: modules_inner.h,v 1.11 2002/01/09 02:01:14 sam Exp $
*
* Authors: Samuel Hocevar <sam@zoy.org>
*
/* If the module is built-in, then we need to define foo_InitModule instead
* of InitModule. Same for Activate- and DeactivateModule. */
#ifdef BUILTIN
-# define _M( function ) CONCATENATE( function, MODULE_NAME )
-# define _X( function ) CONCATENATE( function, MODULE_NAME )
-# define DECLARE_SYMBOLS ;
-# define STORE_SYMBOLS ;
+# define _M( function ) CONCATENATE( function, MODULE_NAME )
+# define __VLC_SYMBOL( symbol ) CONCATENATE( symbol, MODULE_NAME )
+# define DECLARE_SYMBOLS ;
+# define STORE_SYMBOLS ;
#else
-# define _M( function ) function
-# define _X( function ) CONCATENATE( function, MODULE_SYMBOL )
-# define DECLARE_SYMBOLS module_symbols_t* p_symbols;
-# define STORE_SYMBOLS p_symbols = p_module->p_symbols;
+# define _M( function ) function
+# define __VLC_SYMBOL( symbol ) CONCATENATE( symbol, MODULE_SYMBOL )
+# define DECLARE_SYMBOLS module_symbols_t* p_symbols;
+# define STORE_SYMBOLS p_symbols = p_module->p_symbols;
#endif
#define MODULE_STRING STRINGIFY( MODULE_NAME )
* instance the module name, its shortcuts, its capabilities...
*/
#define MODULE_INIT_START \
- int _X( InitModule ) ( module_t *p_module ) \
+ int __VLC_SYMBOL( InitModule ) ( module_t *p_module ) \
{ \
int i_shortcut = 0; \
p_module->psz_name = MODULE_STRING; \
#define MODULE_ACTIVATE_START \
DECLARE_SYMBOLS; \
\
- int _X( ActivateModule ) ( module_t *p_module ) \
+ int __VLC_SYMBOL( ActivateModule ) ( module_t *p_module ) \
{ \
p_module->p_functions = \
( module_functions_t * )malloc( sizeof( module_functions_t ) ); \
* here.
*/
#define MODULE_DEACTIVATE_START \
- int _X( DeactivateModule )( module_t *p_module ) \
+ int __VLC_SYMBOL( DeactivateModule )( module_t *p_module ) \
{ \
free( p_module->p_functions );
* dummy.c : dummy plugin for vlc
*****************************************************************************
* Copyright (C) 2000, 2001 VideoLAN
- * $Id: dummy.c,v 1.13 2001/12/30 07:09:55 sam Exp $
+ * $Id: dummy.c,v 1.14 2002/01/09 02:01:14 sam Exp $
*
* Authors: Samuel Hocevar <sam@zoy.org>
*
SET_DESCRIPTION( "dummy functions module" )
/* Capability score set to 0 because we don't want to be spawned
* unless explicitly requested to */
- ADD_CAPABILITY( INPUT, 0 )
ADD_CAPABILITY( AOUT, 0 )
ADD_CAPABILITY( VOUT, 0 )
ADD_CAPABILITY( INTF, 0 )
+ /* This one is ok. */
+ ADD_CAPABILITY( INPUT, 100 )
ADD_SHORTCUT( "dummy" )
MODULE_INIT_STOP
* input_dummy.c: dummy input plugin, to manage "vlc:***" special options
*****************************************************************************
* Copyright (C) 2001 VideoLAN
- * $Id: input_dummy.c,v 1.12 2002/01/04 14:01:34 sam Exp $
+ * $Id: input_dummy.c,v 1.13 2002/01/09 02:01:14 sam Exp $
*
* Authors: Samuel Hocevar <sam@zoy.org>
*
if( ( strlen(psz_name) > 4 ) && !strncasecmp( psz_name, "vlc:", 4 ) )
{
/* If the user specified "vlc:" then it's probably a file */
- return( 100 );
+ return( 1 );
}
- return( 1 );
+ return( 0 );
}
/*****************************************************************************
}
intf_ErrMsg( "input error: unknown command `%s'", psz_name );
-
}
/*****************************************************************************
* wall.c : Wall video plugin for vlc
*****************************************************************************
* Copyright (C) 2000, 2001 VideoLAN
- * $Id: wall.c,v 1.9 2002/01/07 17:02:07 sam Exp $
+ * $Id: wall.c,v 1.10 2002/01/09 02:01:14 sam Exp $
*
* Authors: Samuel Hocevar <sam@zoy.org>
*
return( 1 );
}
- p_vout->p_sys->i_col = 3;
- p_vout->p_sys->i_row = 3;
+ p_vout->p_sys->i_col = 6;
+ p_vout->p_sys->i_row = 6;
p_vout->p_sys->pp_vout = malloc( p_vout->p_sys->i_row *
p_vout->p_sys->i_col *
* glide.c : 3dfx Glide plugin for vlc
*****************************************************************************
* Copyright (C) 2000, 2001 VideoLAN
- * $Id: glide.c,v 1.10 2002/01/07 02:12:29 sam Exp $
+ * $Id: glide.c,v 1.11 2002/01/09 02:01:14 sam Exp $
*
* Authors: Samuel Hocevar <sam@zoy.org>
*
static void vout_Render ( vout_thread_t *, picture_t * );
static void vout_Display ( vout_thread_t *, picture_t * );
-static int NewPicture ( vout_thread_t *, picture_t * );
static int OpenDisplay ( vout_thread_t * );
static void CloseDisplay ( vout_thread_t * );
{
GrLfbInfo_t p_buffer_info; /* back buffer info */
- /* Dummy video memory */
- byte_t * p_video; /* base adress */
- size_t i_page_size; /* page size */
+ u8* pp_buffer[2];
+ int i_index;
} vout_sys_t;
I_OUTPUTPICTURES = 0;
- /* Try to initialize up to 1 direct buffers */
- while( I_OUTPUTPICTURES < 1 )
- {
- p_pic = NULL;
-
- /* Find an empty picture slot */
- for( i_index = 0 ; i_index < VOUT_MAX_PICTURES ; i_index++ )
- {
- if( p_vout->p_picture[ i_index ].i_status == FREE_PICTURE )
- {
- p_pic = p_vout->p_picture + i_index;
- break;
- }
- }
+ p_pic = NULL;
- /* Allocate the picture */
- if( p_pic == NULL || NewPicture( p_vout, p_pic ) )
+ /* Find an empty picture slot */
+ for( i_index = 0 ; i_index < VOUT_MAX_PICTURES ; i_index++ )
+ {
+ if( p_vout->p_picture[ i_index ].i_status == FREE_PICTURE )
{
+ p_pic = p_vout->p_picture + i_index;
break;
}
+ }
- p_pic->i_status = DESTROYED_PICTURE;
- p_pic->i_type = DIRECT_PICTURE;
+ if( p_pic == NULL )
+ {
+ return -1;
+ }
- PP_OUTPUTPICTURE[ I_OUTPUTPICTURES ] = p_pic;
+ /* We know the chroma, allocate a buffer which will be used
+ * directly by the decoder */
+ p_pic->i_planes = 1;
- I_OUTPUTPICTURES++;
- }
+ p_pic->p->p_pixels = p_vout->p_sys->pp_buffer[p_vout->p_sys->i_index];
+ p_pic->p->i_pixel_bytes = GLIDE_BYTES_PER_PIXEL;
+ p_pic->p->i_lines = GLIDE_HEIGHT;
- return( 0 );
+ p_pic->p->b_margin = 1;
+ p_pic->p->b_hidden = 1;
+ p_pic->p->i_visible_bytes = GLIDE_WIDTH * GLIDE_BYTES_PER_PIXEL;
+ p_pic->p->i_pitch = p_vout->p_sys->p_buffer_info.strideInBytes;
+ /*1024 * GLIDE_BYTES_PER_PIXEL*/
+
+ p_pic->p->i_red_mask = 0xf800;
+ p_pic->p->i_green_mask = 0x07e0;
+ p_pic->p->i_blue_mask = 0x001f;
+
+ p_pic->i_status = DESTROYED_PICTURE;
+ p_pic->i_type = DIRECT_PICTURE;
+
+ PP_OUTPUTPICTURE[ 0 ] = p_pic;
+
+ I_OUTPUTPICTURES = 1;
+
+ return 0;
}
/*****************************************************************************
GrScreenResolution_t resolution = GR_RESOLUTION_800x600;
GrLfbInfo_t p_front_buffer_info; /* front buffer info */
- p_vout->p_sys->i_page_size = GLIDE_WIDTH * GLIDE_HEIGHT
- * GLIDE_BYTES_PER_PIXEL;
-
- /* Map two framebuffers a the very beginning of the fb */
- p_vout->p_sys->p_video = malloc( p_vout->p_sys->i_page_size * 2 );
- if( (int)p_vout->p_sys->p_video == -1 )
- {
- intf_ErrMsg( "vout error: can't map video memory (%s)",
- strerror(errno) );
- return( 1 );
- }
-
grGlideGetVersion( version );
grGlideInit();
}
grSstSelect( 0 );
- if( !grSstWinOpen(0, resolution, GR_REFRESH_60Hz,
- GR_COLORFORMAT_ABGR, GR_ORIGIN_UPPER_LEFT, 2, 1) )
+ if( !grSstWinOpen( 0, resolution, GR_REFRESH_60Hz,
+ GR_COLORFORMAT_ABGR, GR_ORIGIN_UPPER_LEFT, 2, 1 ) )
{
intf_ErrMsg( "vout error: can't open 3dfx screen" );
return( 1 );
grGlideShutdown();
return( 1 );
}
- grLfbUnlock(GR_LFB_WRITE_ONLY, GR_BUFFER_BACKBUFFER );
+ grLfbUnlock( GR_LFB_WRITE_ONLY, GR_BUFFER_BACKBUFFER );
grBufferClear( 0, 0, 0 );
+ p_vout->p_sys->pp_buffer[0] = p_vout->p_sys->p_buffer_info.lfbPtr;
+ p_vout->p_sys->pp_buffer[1] = p_front_buffer_info.lfbPtr;
+ p_vout->p_sys->i_index = 0;
+
return( 0 );
}
/* shutdown Glide */
grGlideShutdown();
- free( p_vout->p_sys->p_video );
-}
-
-/*****************************************************************************
- * NewPicture: allocate a picture
- *****************************************************************************
- * Returns 0 on success, -1 otherwise
- *****************************************************************************/
-static int NewPicture( vout_thread_t *p_vout, picture_t *p_pic )
-{
- /* We know the chroma, allocate a buffer which will be used
- * directly by the decoder */
- p_pic->p->p_pixels = p_vout->p_sys->p_video;
- p_pic->p->i_pixel_bytes = GLIDE_BYTES_PER_PIXEL;
- p_pic->p->i_lines = GLIDE_HEIGHT;
-
- p_pic->p->b_margin = 1;
- p_pic->p->b_hidden = 1;
- p_pic->p->i_visible_bytes = GLIDE_WIDTH * GLIDE_BYTES_PER_PIXEL;
- p_pic->p->i_pitch = p_vout->p_sys->p_buffer_info.strideInBytes;
- /*1024 * GLIDE_BYTES_PER_PIXEL*/
-
- p_pic->p->i_red_mask = 0xf800;
- p_pic->p->i_green_mask = 0x07e0;
- p_pic->p->i_blue_mask = 0x001f;
-
- p_pic->i_planes = 1;
-
- return 0;
}
* gnome.c : Gnome plugin for vlc
*****************************************************************************
* Copyright (C) 2000 VideoLAN
- * $Id: gnome.c,v 1.6 2002/01/07 02:12:29 sam Exp $
+ * $Id: gnome.c,v 1.7 2002/01/09 02:01:14 sam Exp $
*
* Authors: Samuel Hocevar <sam@zoy.org>
*
{
vlc_mutex_lock( &p_input_bank->pp_input[0]->stream.stream_lock );
- /* New input or stream map change */
- if( p_input_bank->pp_input[0]->stream.b_changed )
+ if( !p_input_bank->pp_input[0]->b_die )
{
- GtkModeManage( p_intf );
- GtkSetupMenus( p_intf );
- p_intf->p_sys->b_playing = 1;
- }
-
- /* Manage the slider */
- if( p_input_bank->pp_input[0]->stream.b_seekable )
- {
- float newvalue;
- newvalue = p_intf->p_sys->p_adj->value;
-
-#define p_area p_input_bank->pp_input[0]->stream.p_selected_area
- /* If the user hasn't touched the slider since the last time,
- * then the input can safely change it */
- if( newvalue == p_intf->p_sys->f_adj_oldvalue )
+ /* New input or stream map change */
+ if( p_input_bank->pp_input[0]->stream.b_changed )
{
- /* Update the value */
- p_intf->p_sys->p_adj->value = p_intf->p_sys->f_adj_oldvalue =
- ( 100. * p_area->i_tell ) / p_area->i_size;
-
- gtk_signal_emit_by_name( GTK_OBJECT( p_intf->p_sys->p_adj ),
- "value_changed" );
+ GtkModeManage( p_intf );
+ GtkSetupMenus( p_intf );
+ p_intf->p_sys->b_playing = 1;
}
- /* Otherwise, send message to the input if the user has
- * finished dragging the slider */
- else if( p_intf->p_sys->b_slider_free )
+
+ /* Manage the slider */
+ if( p_input_bank->pp_input[0]->stream.b_seekable )
{
- off_t i_seek = ( newvalue * p_area->i_size ) / 100;
+ float newvalue;
+ newvalue = p_intf->p_sys->p_adj->value;
- vlc_mutex_unlock( &p_input_bank->pp_input[0]->stream.stream_lock );
- input_Seek( p_input_bank->pp_input[0], i_seek );
- vlc_mutex_lock( &p_input_bank->pp_input[0]->stream.stream_lock );
+#define p_area p_input_bank->pp_input[0]->stream.p_selected_area
+ /* If the user hasn't touched the slider since the last time,
+ * then the input can safely change it */
+ if( newvalue == p_intf->p_sys->f_adj_oldvalue )
+ {
+ /* Update the value */
+ p_intf->p_sys->p_adj->value = p_intf->p_sys->f_adj_oldvalue =
+ ( 100. * p_area->i_tell ) / p_area->i_size;
- /* Update the old value */
- p_intf->p_sys->f_adj_oldvalue = newvalue;
- }
+ gtk_signal_emit_by_name( GTK_OBJECT( p_intf->p_sys->p_adj ),
+ "value_changed" );
+ }
+ /* Otherwise, send message to the input if the user has
+ * finished dragging the slider */
+ else if( p_intf->p_sys->b_slider_free )
+ {
+ off_t i_seek = ( newvalue * p_area->i_size ) / 100;
+
+ vlc_mutex_unlock( &p_input_bank->pp_input[0]->stream.stream_lock );
+ input_Seek( p_input_bank->pp_input[0], i_seek );
+ vlc_mutex_lock( &p_input_bank->pp_input[0]->stream.stream_lock );
+
+ /* Update the old value */
+ p_intf->p_sys->f_adj_oldvalue = newvalue;
+ }
#undef p_area
- }
+ }
- if( p_intf->p_sys->i_part !=
- p_input_bank->pp_input[0]->stream.p_selected_area->i_part )
- {
- p_intf->p_sys->b_chapter_update = 1;
- GtkSetupMenus( p_intf );
+ if( p_intf->p_sys->i_part !=
+ p_input_bank->pp_input[0]->stream.p_selected_area->i_part )
+ {
+ p_intf->p_sys->b_chapter_update = 1;
+ GtkSetupMenus( p_intf );
+ }
}
vlc_mutex_unlock( &p_input_bank->pp_input[0]->stream.stream_lock );
<signal>
<name>activate</name>
<handler>GnomeMenubarFileOpenActivate</handler>
- <data>"intf_window"</data>
<last_modification_time>Sat, 19 May 2001 16:27:02 GMT</last_modification_time>
</signal>
<label>_Open File...</label>
<signal>
<name>activate</name>
<handler>GnomeMenubarDiscOpenActivate</handler>
- <data>"intf_window"</data>
<last_modification_time>Sat, 19 May 2001 16:27:10 GMT</last_modification_time>
</signal>
<label>Open _Disc...</label>
<tooltip>Select a Network Stream</tooltip>
<signal>
<name>activate</name>
- <handler>GnomeMenbarNetworkOpenActivate</handler>
- <data>"intf_window"</data>
- <last_modification_time>Sat, 19 May 2001 16:27:39 GMT</last_modification_time>
+ <handler>GnomeMenubarNetworkOpenActivate</handler>
+ <last_modification_time>Fri, 21 Dec 2001 13:11:28 GMT</last_modification_time>
</signal>
<label>_Network Stream...</label>
<right_justify>False</right_justify>
<right_justify>False</right_justify>
</widget>
+ <widget>
+ <class>GtkPixmapMenuItem</class>
+ <name>menubar_eject</name>
+ <tooltip>Eject disc</tooltip>
+ <signal>
+ <name>activate</name>
+ <handler>GnomeMenubarDiscEjectActivate</handler>
+ <last_modification_time>Fri, 21 Dec 2001 13:11:28 GMT</last_modification_time>
+ </signal>
+ <label>_Eject Disc</label>
+ <right_justify>False</right_justify>
+ <stock_icon>GNOME_STOCK_MENU_TOP</stock_icon>
+ </widget>
+
+ <widget>
+ <class>GtkMenuItem</class>
+ <name>separator15</name>
+ <right_justify>False</right_justify>
+ </widget>
+
<widget>
<class>GtkPixmapMenuItem</class>
<name>menubar_exit</name>
<signal>
<name>activate</name>
<handler>GnomeMenubarExitActivate</handler>
- <data>"intf_window"</data>
<last_modification_time>Sat, 19 May 2001 16:27:52 GMT</last_modification_time>
</signal>
<stock_item>GNOMEUIINFO_MENU_EXIT_ITEM</stock_item>
<signal>
<name>activate</name>
<handler>GnomeMenubarWindowToggleActivate</handler>
- <data>"intf_window"</data>
<last_modification_time>Sat, 19 May 2001 16:28:06 GMT</last_modification_time>
</signal>
<label>_Hide interface</label>
<signal>
<name>activate</name>
<handler>GnomeMenubarFullscreenActivate</handler>
- <data>"intf_window"</data>
<last_modification_time>Sat, 19 May 2001 16:28:15 GMT</last_modification_time>
</signal>
<label>_Fullscreen</label>
<signal>
<name>activate</name>
<handler>GnomeMenubarPlaylistActivate</handler>
- <data>"intf_window"</data>
<last_modification_time>Sat, 19 May 2001 16:28:41 GMT</last_modification_time>
</signal>
<label>_Playlist...</label>
<signal>
<name>activate</name>
<handler>GnomeMenubarModulesActivate</handler>
- <data>"intf_window"</data>
<last_modification_time>Sat, 19 May 2001 16:28:53 GMT</last_modification_time>
</signal>
<label>_Modules...</label>
<signal>
<name>activate</name>
<handler>GnomeMenubarPreferencesActivate</handler>
- <data>"intf_window"</data>
<last_modification_time>Sat, 19 May 2001 16:29:03 GMT</last_modification_time>
</signal>
<stock_item>GNOMEUIINFO_MENU_PREFERENCES_ITEM</stock_item>
<signal>
<name>activate</name>
<handler>GnomeMenubarAboutActivate</handler>
- <data>"intf_window"</data>
<last_modification_time>Sat, 19 May 2001 16:29:19 GMT</last_modification_time>
</signal>
<stock_item>GNOMEUIINFO_MENU_ABOUT_ITEM</stock_item>
<stock_pixmap>GNOME_STOCK_PIXMAP_STOP</stock_pixmap>
</widget>
+ <widget>
+ <class>GtkButton</class>
+ <child_name>Toolbar:button</child_name>
+ <name>toolbar_eject</name>
+ <tooltip>Eject disc</tooltip>
+ <signal>
+ <name>button_press_event</name>
+ <handler>GtkDiscEject</handler>
+ <data>"intf_window"</data>
+ <last_modification_time>Fri, 21 Dec 2001 15:24:18 GMT</last_modification_time>
+ </signal>
+ <label>Eject</label>
+ <stock_pixmap>GNOME_STOCK_PIXMAP_TOP</stock_pixmap>
+ </widget>
+
<widget>
<class>GtkButton</class>
<child_name>Toolbar:button</child_name>
void
-GnomeMenbarNetworkOpenActivate (GtkMenuItem *menuitem,
+GnomeMenubarNetworkOpenActivate (GtkMenuItem *menuitem,
gpointer user_data)
{
GtkNetworkOpenShow( GTK_WIDGET( menuitem ), NULL, "intf_window" );
}
+void
+GnomeMenubarDiscEjectActivate (GtkMenuItem *menuitem,
+ gpointer user_data)
+{
+ GtkDiscEject( GTK_WIDGET( menuitem ), NULL, "intf_window" );
+}
void
GnomeMenubarExitActivate (GtkMenuItem *menuitem,
{
GtkJumpShow( GTK_WIDGET( menuitem ), NULL, "intf_popup" );
}
-
-
-
gpointer user_data);
void
-GnomeMenbarNetworkOpenActivate (GtkMenuItem *menuitem,
+GnomeMenubarNetworkOpenActivate (GtkMenuItem *menuitem,
+ gpointer user_data);
+
+void
+GnomeMenubarDiscEjectActivate (GtkMenuItem *menuitem,
gpointer user_data);
void
void
GtkNetworkOpenChannel (GtkToggleButton *togglebutton,
gpointer user_data);
+
{
GNOME_APP_UI_ITEM, N_("_Network Stream..."),
N_("Select a Network Stream"),
- (gpointer) GnomeMenbarNetworkOpenActivate, NULL, NULL,
+ (gpointer) GnomeMenubarNetworkOpenActivate, NULL, NULL,
GNOME_APP_PIXMAP_STOCK, GNOME_STOCK_MENU_REFRESH,
0, (GdkModifierType) 0, NULL
},
GNOMEUIINFO_SEPARATOR,
+ {
+ GNOME_APP_UI_ITEM, N_("_Eject Disc"),
+ N_("Eject disc"),
+ (gpointer) GnomeMenubarDiscEjectActivate, NULL, NULL,
+ GNOME_APP_PIXMAP_STOCK, GNOME_STOCK_MENU_TOP,
+ 0, (GdkModifierType) 0, NULL
+ },
+ GNOMEUIINFO_SEPARATOR,
GNOMEUIINFO_MENU_EXIT_ITEM (GnomeMenubarExitActivate, NULL),
GNOMEUIINFO_END
};
GtkWidget *toolbar_network;
GtkWidget *toolbar_back;
GtkWidget *toolbar_stop;
+ GtkWidget *toolbar_eject;
GtkWidget *toolbar_play;
GtkWidget *toolbar_pause;
GtkWidget *toolbar_slow;
(GtkDestroyNotify) gtk_widget_unref);
gtk_widget_ref (menubar_file_menu_uiinfo[4].widget);
- gtk_object_set_data_full (GTK_OBJECT (intf_window), "menubar_exit",
+ gtk_object_set_data_full (GTK_OBJECT (intf_window), "menubar_eject",
menubar_file_menu_uiinfo[4].widget,
(GtkDestroyNotify) gtk_widget_unref);
+ gtk_widget_ref (menubar_file_menu_uiinfo[5].widget);
+ gtk_object_set_data_full (GTK_OBJECT (intf_window), "separator15",
+ menubar_file_menu_uiinfo[5].widget,
+ (GtkDestroyNotify) gtk_widget_unref);
+
+ gtk_widget_ref (menubar_file_menu_uiinfo[6].widget);
+ gtk_object_set_data_full (GTK_OBJECT (intf_window), "menubar_exit",
+ menubar_file_menu_uiinfo[6].widget,
+ (GtkDestroyNotify) gtk_widget_unref);
+
gtk_widget_ref (menubar_uiinfo[1].widget);
gtk_object_set_data_full (GTK_OBJECT (intf_window), "menubar_view",
menubar_uiinfo[1].widget,
(GtkDestroyNotify) gtk_widget_unref);
gtk_widget_show (toolbar_stop);
+ tmp_toolbar_icon = gnome_stock_pixmap_widget (intf_window, GNOME_STOCK_PIXMAP_TOP);
+ toolbar_eject = gtk_toolbar_append_element (GTK_TOOLBAR (toolbar),
+ GTK_TOOLBAR_CHILD_BUTTON,
+ NULL,
+ _("Eject"),
+ _("Eject disc"), NULL,
+ tmp_toolbar_icon, NULL, NULL);
+ gtk_widget_ref (toolbar_eject);
+ gtk_object_set_data_full (GTK_OBJECT (intf_window), "toolbar_eject", toolbar_eject,
+ (GtkDestroyNotify) gtk_widget_unref);
+ gtk_widget_show (toolbar_eject);
+
tmp_toolbar_icon = gnome_stock_pixmap_widget (intf_window, GNOME_STOCK_PIXMAP_FORWARD);
toolbar_play = gtk_toolbar_append_element (GTK_TOOLBAR (toolbar),
GTK_TOOLBAR_CHILD_BUTTON,
gtk_signal_connect (GTK_OBJECT (toolbar_stop), "button_press_event",
GTK_SIGNAL_FUNC (GtkControlStop),
"intf_window");
+ gtk_signal_connect (GTK_OBJECT (toolbar_eject), "button_press_event",
+ GTK_SIGNAL_FUNC (GtkDiscEject),
+ "intf_window");
gtk_signal_connect (GTK_OBJECT (toolbar_play), "button_press_event",
GTK_SIGNAL_FUNC (GtkControlPlay),
"intf_window");
* gtk.c : Gtk+ plugin for vlc
*****************************************************************************
* Copyright (C) 2000-2001 VideoLAN
- * $Id: gtk.c,v 1.8 2002/01/07 02:12:29 sam Exp $
+ * $Id: gtk.c,v 1.9 2002/01/09 02:01:14 sam Exp $
*
* Authors: Samuel Hocevar <sam@zoy.org>
*
/* update the playlist */
GtkPlayListManage( p_data );
- if( p_input_bank->pp_input[0] != NULL && !p_intf->b_die )
+ if( p_input_bank->pp_input[0] != NULL )
{
vlc_mutex_lock( &p_input_bank->pp_input[0]->stream.stream_lock );
- /* New input or stream map change */
- if( p_input_bank->pp_input[0]->stream.b_changed )
+ if( !p_input_bank->pp_input[0]->b_die )
{
- GtkModeManage( p_intf );
- GtkSetupMenus( p_intf );
- p_intf->p_sys->b_playing = 1;
- }
+ /* New input or stream map change */
+ if( p_input_bank->pp_input[0]->stream.b_changed )
+ {
+ GtkModeManage( p_intf );
+ GtkSetupMenus( p_intf );
+ p_intf->p_sys->b_playing = 1;
+ }
- /* Manage the slider */
- if( p_input_bank->pp_input[0]->stream.b_seekable )
- {
- float newvalue = p_intf->p_sys->p_adj->value;
+ /* Manage the slider */
+ if( p_input_bank->pp_input[0]->stream.b_seekable )
+ {
+ float newvalue = p_intf->p_sys->p_adj->value;
#define p_area p_input_bank->pp_input[0]->stream.p_selected_area
- /* If the user hasn't touched the slider since the last time,
- * then the input can safely change it */
- if( newvalue == p_intf->p_sys->f_adj_oldvalue )
- {
- /* Update the value */
- p_intf->p_sys->p_adj->value = p_intf->p_sys->f_adj_oldvalue =
- ( 100. * p_area->i_tell ) / p_area->i_size;
+ /* If the user hasn't touched the slider since the last time,
+ * then the input can safely change it */
+ if( newvalue == p_intf->p_sys->f_adj_oldvalue )
+ {
+ /* Update the value */
+ p_intf->p_sys->p_adj->value = p_intf->p_sys->f_adj_oldvalue =
+ ( 100. * p_area->i_tell ) / p_area->i_size;
+
+ gtk_signal_emit_by_name( GTK_OBJECT( p_intf->p_sys->p_adj ),
+ "value_changed" );
+ }
+ /* Otherwise, send message to the input if the user has
+ * finished dragging the slider */
+ else if( p_intf->p_sys->b_slider_free )
+ {
+ off_t i_seek = ( newvalue * p_area->i_size ) / 100;
- gtk_signal_emit_by_name( GTK_OBJECT( p_intf->p_sys->p_adj ),
- "value_changed" );
+ /* release the lock to be able to seek */
+ vlc_mutex_unlock( &p_input_bank->pp_input[0]->stream.stream_lock );
+ input_Seek( p_input_bank->pp_input[0], i_seek );
+ vlc_mutex_lock( &p_input_bank->pp_input[0]->stream.stream_lock );
+
+ /* Update the old value */
+ p_intf->p_sys->f_adj_oldvalue = newvalue;
+ }
+# undef p_area
}
- /* Otherwise, send message to the input if the user has
- * finished dragging the slider */
- else if( p_intf->p_sys->b_slider_free )
- {
- off_t i_seek = ( newvalue * p_area->i_size ) / 100;
-
- /* release the lock to be able to seek */
- vlc_mutex_unlock( &p_input_bank->pp_input[0]->stream.stream_lock );
- input_Seek( p_input_bank->pp_input[0], i_seek );
- vlc_mutex_lock( &p_input_bank->pp_input[0]->stream.stream_lock );
- /* Update the old value */
- p_intf->p_sys->f_adj_oldvalue = newvalue;
+ if( p_intf->p_sys->i_part !=
+ p_input_bank->pp_input[0]->stream.p_selected_area->i_part )
+ {
+ p_intf->p_sys->b_chapter_update = 1;
+ GtkSetupMenus( p_intf );
}
-#undef p_area
- }
-
- if( p_intf->p_sys->i_part !=
- p_input_bank->pp_input[0]->stream.p_selected_area->i_part )
- {
- p_intf->p_sys->b_chapter_update = 1;
- GtkSetupMenus( p_intf );
}
vlc_mutex_unlock( &p_input_bank->pp_input[0]->stream.stream_lock );
-
}
else if( p_intf->p_sys->b_playing && !p_intf->b_die )
{
<right_justify>False</right_justify>
</widget>
+ <widget>
+ <class>GtkMenuItem</class>
+ <name>menubar_eject</name>
+ <tooltip>Eject disc</tooltip>
+ <signal>
+ <name>activate</name>
+ <handler>GtkEjectDiscActivate</handler>
+ <data>"intf_window"</data>
+ <last_modification_time>Fri, 21 Dec 2001 12:51:34 GMT</last_modification_time>
+ </signal>
+ <label>_Eject Disc</label>
+ <right_justify>False</right_justify>
+ </widget>
+
+ <widget>
+ <class>GtkMenuItem</class>
+ <name>separator14</name>
+ <right_justify>False</right_justify>
+ </widget>
+
<widget>
<class>GtkMenuItem</class>
<name>menubar_exit</name>
<label>Stop</label>
</widget>
+ <widget>
+ <class>GtkButton</class>
+ <child_name>Toolbar:button</child_name>
+ <name>toolbar_eject</name>
+ <signal>
+ <name>button_press_event</name>
+ <handler>GtkDiscEject</handler>
+ <data>"intf_window"</data>
+ <last_modification_time>Fri, 21 Dec 2001 15:33:26 GMT</last_modification_time>
+ </signal>
+ <label>Eject</label>
+ </widget>
+
<widget>
<class>GtkButton</class>
<child_name>Toolbar:button</child_name>
* gtk_callbacks.c : Callbacks for the Gtk+ plugin.
*****************************************************************************
* Copyright (C) 2000, 2001 VideoLAN
- * $Id: gtk_callbacks.c,v 1.30 2002/01/07 02:12:29 sam Exp $
+ * $Id: gtk_callbacks.c,v 1.31 2002/01/09 02:01:14 sam Exp $
*
* Authors: Samuel Hocevar <sam@zoy.org>
* Stéphane Borel <stef@via.ecp.fr>
+ * Julien BLACHE <jb@technologeek.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
#include <videolan/vlc.h>
+#include <unistd.h>
+
#include <gtk/gtk.h>
#include <string.h>
#include "interface.h"
#include "intf_playlist.h"
+#include "intf_eject.h"
#include "video.h"
#include "video_output.h"
GtkJumpShow( GTK_WIDGET( menuitem ), NULL, user_data );
}
+
+/****************************************************************************
+ * Callbacks for disc ejection
+ ****************************************************************************/
+gboolean GtkDiscEject ( GtkWidget *widget, GdkEventButton *event,
+ gpointer user_data )
+{
+ char *psz_device = NULL;
+
+ /*
+ * Get the active input
+ * Determine whether we can eject a media, ie it's a VCD or DVD
+ * If it's neither a VCD nor a DVD, then return
+ */
+
+ /*
+ * Don't really know if I must lock the stuff here, we're using it read-only
+ */
+
+ if (p_main->p_playlist->current.psz_name != NULL)
+ {
+ if (strncmp(p_main->p_playlist->current.psz_name, "dvd", 3)
+ || strncmp(p_main->p_playlist->current.psz_name, "vcd", 3))
+ {
+ /* Determine the device name by omitting the first 4 characters */
+ psz_device = strdup((p_main->p_playlist->current.psz_name + 4));
+ }
+ }
+
+ if( psz_device == NULL )
+ {
+ return TRUE;
+ }
+
+ /* If there's a stream playing, we aren't allowed to eject ! */
+ if( p_input_bank->pp_input[0] == NULL )
+ {
+ intf_WarnMsg( 4, "intf: ejecting %s", psz_device );
+
+ intf_Eject( psz_device );
+ }
+
+ free(psz_device);
+ return TRUE;
+}
+
+void GtkEjectDiscActivate ( GtkMenuItem *menuitem, gpointer user_data )
+{
+ fprintf(stderr, "DEBUG: EJECT called from MENU !\n");
+
+ GtkDiscEject( GTK_WIDGET( menuitem ), NULL, user_data );
+}
* gtk_callbacks.h : Callbacks for the gtk plugin.
*****************************************************************************
* Copyright (C) 2000, 2001 VideoLAN
- * $Id: gtk_callbacks.h,v 1.15 2001/05/30 23:02:03 stef Exp $
+ * $Id: gtk_callbacks.h,v 1.16 2002/01/09 02:01:14 sam Exp $
*
* Authors: Samuel Hocevar <sam@zoy.org>
* Stéphane Borel <stef@via.ecp.fr>
void GtkChannelGo ( GtkButton *, gpointer );
void GtkNetworkOpenChannel ( GtkToggleButton *, gpointer );
+
+void
+GtkEjectDiscActivate (GtkMenuItem *menuitem,
+ gpointer user_data);
+
+gboolean
+GtkDiscEject (GtkWidget *widget,
+ GdkEventButton *event,
+ gpointer user_data);
* gtk_display.c: Gtk+ tools for main interface
*****************************************************************************
* Copyright (C) 1999, 2000 VideoLAN
- * $Id: gtk_display.c,v 1.11 2002/01/07 02:12:29 sam Exp $
+ * $Id: gtk_display.c,v 1.12 2002/01/09 02:01:14 sam Exp $
*
* Authors: Samuel Hocevar <sam@zoy.org>
* Stéphane Borel <stef@via.ecp.fr>
/* set control items */
gtk_widget_set_sensitive( GETWIDGET(p_window, "toolbar_back"), FALSE );
+ gtk_widget_set_sensitive( GETWIDGET(p_window, "toolbar_eject"), !b_control);
gtk_widget_set_sensitive( GETWIDGET(p_window, "toolbar_pause"), b_control );
gtk_widget_set_sensitive( GETWIDGET(p_window, "toolbar_slow"), b_control );
gtk_widget_set_sensitive( GETWIDGET(p_window, "toolbar_fast"), b_control );
GtkWidget *menubar_disc;
GtkWidget *menubar_network;
GtkWidget *separator4;
+ GtkWidget *menubar_eject;
+ GtkWidget *separator14;
GtkWidget *menubar_exit;
GtkWidget *menubar_view;
GtkWidget *menubar_view_menu;
GtkWidget *toolbar_network;
GtkWidget *toolbar_back;
GtkWidget *toolbar_stop;
+ GtkWidget *toolbar_eject;
GtkWidget *toolbar_play;
GtkWidget *toolbar_pause;
GtkWidget *toolbar_slow;
gtk_container_add (GTK_CONTAINER (menubar_file_menu), separator4);
gtk_widget_set_sensitive (separator4, FALSE);
+ menubar_eject = gtk_menu_item_new_with_label ("");
+ tmp_key = gtk_label_parse_uline (GTK_LABEL (GTK_BIN (menubar_eject)->child),
+ _("_Eject Disc"));
+ gtk_widget_add_accelerator (menubar_eject, "activate_item", menubar_file_menu_accels,
+ tmp_key, 0, 0);
+ gtk_widget_ref (menubar_eject);
+ gtk_object_set_data_full (GTK_OBJECT (intf_window), "menubar_eject", menubar_eject,
+ (GtkDestroyNotify) gtk_widget_unref);
+ gtk_widget_show (menubar_eject);
+ gtk_container_add (GTK_CONTAINER (menubar_file_menu), menubar_eject);
+ gtk_tooltips_set_tip (tooltips, menubar_eject, _("Eject disc"), NULL);
+
+ separator14 = gtk_menu_item_new ();
+ gtk_widget_ref (separator14);
+ gtk_object_set_data_full (GTK_OBJECT (intf_window), "separator14", separator14,
+ (GtkDestroyNotify) gtk_widget_unref);
+ gtk_widget_show (separator14);
+ gtk_container_add (GTK_CONTAINER (menubar_file_menu), separator14);
+ gtk_widget_set_sensitive (separator14, FALSE);
+
menubar_exit = gtk_menu_item_new_with_label ("");
tmp_key = gtk_label_parse_uline (GTK_LABEL (GTK_BIN (menubar_exit)->child),
_("E_xit"));
(GtkDestroyNotify) gtk_widget_unref);
gtk_widget_show (toolbar_stop);
+ toolbar_eject = gtk_toolbar_append_element (GTK_TOOLBAR (toolbar),
+ GTK_TOOLBAR_CHILD_BUTTON,
+ NULL,
+ _("Eject"),
+ NULL, NULL,
+ NULL, NULL, NULL);
+ gtk_widget_ref (toolbar_eject);
+ gtk_object_set_data_full (GTK_OBJECT (intf_window), "toolbar_eject", toolbar_eject,
+ (GtkDestroyNotify) gtk_widget_unref);
+ gtk_widget_show (toolbar_eject);
+
toolbar_play = gtk_toolbar_append_element (GTK_TOOLBAR (toolbar),
GTK_TOOLBAR_CHILD_BUTTON,
NULL,
gtk_signal_connect (GTK_OBJECT (menubar_network), "activate",
GTK_SIGNAL_FUNC (GtkNetworkOpenActivate),
"intf_window");
+ gtk_signal_connect (GTK_OBJECT (menubar_eject), "activate",
+ GTK_SIGNAL_FUNC (GtkEjectDiscActivate),
+ "intf_window");
gtk_signal_connect (GTK_OBJECT (menubar_exit), "activate",
GTK_SIGNAL_FUNC (GtkExitActivate),
"intf_window");
gtk_signal_connect (GTK_OBJECT (toolbar_stop), "button_press_event",
GTK_SIGNAL_FUNC (GtkControlStop),
"intf_window");
+ gtk_signal_connect (GTK_OBJECT (toolbar_eject), "button_press_event",
+ GTK_SIGNAL_FUNC (GtkDiscEject),
+ "intf_window");
gtk_signal_connect (GTK_OBJECT (toolbar_play), "button_press_event",
GTK_SIGNAL_FUNC (GtkControlPlay),
"intf_window");
mga_SOURCES = mga.c
+xmga_SOURCES = xmga.c
--- /dev/null
+/*****************************************************************************
+ * xmga.c : X11 MGA plugin for vlc
+ *****************************************************************************
+ * Copyright (C) 1998-2001 VideoLAN
+ * $Id: xmga.c,v 1.1 2002/01/09 02:01:14 sam Exp $
+ *
+ * Authors: Vincent Seguin <seguin@via.ecp.fr>
+ * Samuel Hocevar <sam@zoy.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
+ *****************************************************************************/
+
+/*****************************************************************************
+ * Preamble
+ *****************************************************************************/
+#include <errno.h> /* ENOMEM */
+#include <stdlib.h> /* free() */
+#include <string.h> /* strerror() */
+
+#include <videolan/vlc.h>
+
+#ifdef HAVE_MACHINE_PARAM_H
+/* BSD */
+#include <machine/param.h>
+#include <sys/types.h> /* typedef ushort */
+#include <sys/ipc.h>
+#endif
+
+#ifndef WIN32
+#include <netinet/in.h> /* BSD: struct in_addr */
+#endif
+
+#include <sys/shm.h> /* shmget(), shmctl() */
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <X11/keysym.h>
+#include <X11/extensions/XShm.h>
+#include <X11/extensions/dpms.h>
+
+#include "video.h"
+#include "video_output.h"
+
+#include "interface.h"
+#include "netutils.h" /* network_ChannelJoin */
+
+#include "stream_control.h" /* needed by input_ext-intf.h... */
+#include "input_ext-intf.h"
+
+//#include "mga.h"
+
+/*****************************************************************************
+ * Local prototypes
+ *****************************************************************************/
+static void vout_getfunctions( function_list_t * );
+
+static int vout_Probe ( probedata_t * );
+static int vout_Create ( vout_thread_t * );
+static void vout_Destroy ( vout_thread_t * );
+static void vout_Render ( vout_thread_t *, picture_t * );
+static void vout_Display ( vout_thread_t *, picture_t * );
+static int vout_Manage ( vout_thread_t * );
+static int vout_Init ( vout_thread_t * );
+static void vout_End ( vout_thread_t * );
+
+static int CreateWindow ( vout_thread_t * );
+static void DestroyWindow ( vout_thread_t * );
+
+static int NewPicture ( vout_thread_t *, picture_t * );
+static void FreePicture ( vout_thread_t *, picture_t * );
+
+static void ToggleFullScreen ( vout_thread_t * );
+
+static void EnableXScreenSaver ( vout_thread_t * );
+static void DisableXScreenSaver ( vout_thread_t * );
+
+static void CreateCursor ( vout_thread_t * );
+static void DestroyCursor ( vout_thread_t * );
+static void ToggleCursor ( vout_thread_t * );
+
+/*****************************************************************************
+ * Building configuration tree
+ *****************************************************************************/
+MODULE_CONFIG_START
+MODULE_CONFIG_STOP
+
+MODULE_INIT_START
+ SET_DESCRIPTION( "X11 MGA module" )
+ ADD_CAPABILITY( VOUT, 60 )
+ ADD_SHORTCUT( "xmga" )
+MODULE_INIT_STOP
+
+MODULE_ACTIVATE_START
+ vout_getfunctions( &p_module->p_functions->vout );
+MODULE_ACTIVATE_STOP
+
+MODULE_DEACTIVATE_START
+MODULE_DEACTIVATE_STOP
+
+/*****************************************************************************
+ * vout_sys_t: video output method descriptor
+ *****************************************************************************
+ * This structure is part of the video output thread descriptor.
+ * It describes the X11 and XVideo specific properties of an output thread.
+ *****************************************************************************/
+typedef struct vout_sys_s
+{
+ /* Internal settings and properties */
+ Display * p_display; /* display pointer */
+
+ Visual * p_visual; /* visual pointer */
+ int i_screen; /* screen number */
+ Window window; /* root window */
+ GC gc; /* graphic context instance handler */
+
+ boolean_t b_shm; /* shared memory extension flag */
+
+#ifdef MODULE_NAME_IS_xvideo
+ Window yuv_window; /* sub-window for displaying yuv video
+ data */
+ int i_xvport;
+#else
+ Colormap colormap; /* colormap used (8bpp only) */
+
+ int i_screen_depth;
+ int i_bytes_per_pixel;
+ int i_bytes_per_line;
+ int i_red_mask;
+ int i_green_mask;
+ int i_blue_mask;
+#endif
+
+ /* X11 generic properties */
+ Atom wm_protocols;
+ Atom wm_delete_window;
+
+ int i_width; /* width of main window */
+ int i_height; /* height of main window */
+
+ /* Backup of window position and size before fullscreen switch */
+ int i_width_backup;
+ int i_height_backup;
+ int i_xpos_backup;
+ int i_ypos_backup;
+
+ /* Screen saver properties */
+ int i_ss_timeout; /* timeout */
+ int i_ss_interval; /* interval between changes */
+ int i_ss_blanking; /* blanking mode */
+ int i_ss_exposure; /* exposure mode */
+ BOOL b_ss_dpms; /* DPMS mode */
+
+ /* Mouse pointer properties */
+ boolean_t b_mouse_pointer_visible;
+ mtime_t i_time_mouse_last_moved; /* used to auto-hide pointer*/
+ Cursor blank_cursor; /* the hidden cursor */
+ Pixmap cursor_pixmap;
+
+} vout_sys_t;
+
+/*****************************************************************************
+ * picture_sys_t: direct buffer method descriptor
+ *****************************************************************************
+ * This structure is part of the picture descriptor, it describes the
+ * XVideo specific properties of a direct buffer.
+ *****************************************************************************/
+typedef struct picture_sys_s
+{
+} picture_sys_t;
+
+/*****************************************************************************
+ * mwmhints_t: window manager hints
+ *****************************************************************************
+ * Fullscreen needs to be able to hide the wm decorations so we provide
+ * this structure to make it easier.
+ *****************************************************************************/
+#define MWM_HINTS_DECORATIONS (1L << 1)
+#define PROP_MWM_HINTS_ELEMENTS 5
+typedef struct mwmhints_s
+{
+ u32 flags;
+ u32 functions;
+ u32 decorations;
+ s32 input_mode;
+ u32 status;
+} mwmhints_t;
+
+/*****************************************************************************
+ * Chroma defines
+ *****************************************************************************/
+#ifdef MODULE_NAME_IS_xvideo
+# define MAX_DIRECTBUFFERS 5
+#else
+# define MAX_DIRECTBUFFERS 2
+#endif
+
+/*****************************************************************************
+ * Seeking function TODO: put this in a generic location !
+ *****************************************************************************/
+static __inline__ void vout_Seek( off_t i_seek )
+{
+ off_t i_tell;
+
+ vlc_mutex_lock( &p_input_bank->lock );
+ if( p_input_bank->pp_input[0] != NULL )
+ {
+#define S p_input_bank->pp_input[0]->stream
+ i_tell = S.p_selected_area->i_tell + i_seek * (off_t)50 * S.i_mux_rate;
+
+ i_tell = ( i_tell <= 0 /*S.p_selected_area->i_start*/ )
+ ? 0 /*S.p_selected_area->i_start*/
+ : ( i_tell >= S.p_selected_area->i_size )
+ ? S.p_selected_area->i_size
+ : i_tell;
+
+ input_Seek( p_input_bank->pp_input[0], i_tell );
+#undef S
+ }
+ vlc_mutex_unlock( &p_input_bank->lock );
+}
+
+/*****************************************************************************
+ * Functions exported as capabilities. They are declared as static so that
+ * we don't pollute the namespace too much.
+ *****************************************************************************/
+static void vout_getfunctions( function_list_t * p_function_list )
+{
+ p_function_list->pf_probe = vout_Probe;
+ p_function_list->functions.vout.pf_create = vout_Create;
+ p_function_list->functions.vout.pf_init = vout_Init;
+ p_function_list->functions.vout.pf_end = vout_End;
+ p_function_list->functions.vout.pf_destroy = vout_Destroy;
+ p_function_list->functions.vout.pf_manage = vout_Manage;
+ p_function_list->functions.vout.pf_render = vout_Render;
+ p_function_list->functions.vout.pf_display = vout_Display;
+}
+
+/*****************************************************************************
+ * vout_Probe: probe the video driver and return a score
+ *****************************************************************************
+ * This function tries to initialize SDL and returns a score to the
+ * plugin manager so that it can select the best plugin.
+ *****************************************************************************/
+static int vout_Probe( probedata_t *p_data )
+{
+ Display *p_display; /* display pointer */
+ char *psz_display;
+#ifdef MODULE_NAME_IS_xvideo
+ int i_xvport, i_dummy;
+#endif
+
+ /* Open display, unsing 'vlc_display' or DISPLAY environment variable */
+ psz_display = XDisplayName( main_GetPszVariable(VOUT_DISPLAY_VAR, NULL) );
+ p_display = XOpenDisplay( psz_display );
+ if( p_display == NULL ) /* error */
+ {
+ intf_WarnMsg( 3, "vout: cannot open display %s", psz_display );
+ return( 0 );
+ }
+
+#ifdef MODULE_NAME_IS_xvideo
+ /* Check that there is an available XVideo port for this format */
+ i_xvport = XVideoGetPort( p_display, p_data->vout.i_chroma, &i_dummy );
+ if( i_xvport < 0 )
+ {
+ /* It failed, but it's not completely lost ! We try to open an
+ * XVideo port for a YUY2 picture */
+ i_xvport = XVideoGetPort( p_display, FOURCC_YUY2, &i_dummy );
+ if( i_xvport < 0 )
+ {
+ /* It failed, but it's not completely lost ! We try to open an
+ * XVideo port for a simple 16bpp RGB picture */
+ i_xvport = XVideoGetPort( p_display, FOURCC_RV16, &i_dummy );
+ if( i_xvport < 0 )
+ {
+ XCloseDisplay( p_display );
+ return( 0 );
+ }
+ }
+ }
+ XVideoReleasePort( p_display, i_xvport );
+#endif
+
+ /* Clean-up everyting */
+ XCloseDisplay( p_display );
+
+#ifdef MODULE_NAME_IS_xvideo
+ return( 150 );
+#else
+ return( 50 );
+#endif
+}
+
+/*****************************************************************************
+ * vout_Create: allocate X11 video thread output method
+ *****************************************************************************
+ * This function allocate and initialize a X11 vout method. It uses some of the
+ * vout properties to choose the window size, and change them according to the
+ * actual properties of the display.
+ *****************************************************************************/
+static int vout_Create( vout_thread_t *p_vout )
+{
+ char *psz_display;
+
+ /* Allocate structure */
+ p_vout->p_sys = malloc( sizeof( vout_sys_t ) );
+ if( p_vout->p_sys == NULL )
+ {
+ intf_ErrMsg( "vout error: %s", strerror(ENOMEM) );
+ return( 1 );
+ }
+
+ /* Open display, unsing 'vlc_display' or DISPLAY environment variable */
+ psz_display = XDisplayName( main_GetPszVariable( VOUT_DISPLAY_VAR, NULL ) );
+ p_vout->p_sys->p_display = XOpenDisplay( psz_display );
+
+ if( p_vout->p_sys->p_display == NULL ) /* error */
+ {
+ intf_ErrMsg( "vout error: cannot open display %s", psz_display );
+ free( p_vout->p_sys );
+ return( 1 );
+ }
+ p_vout->p_sys->i_screen = DefaultScreen( p_vout->p_sys->p_display );
+
+ /* Create blank cursor (for mouse cursor autohiding) */
+ p_vout->p_sys->b_mouse_pointer_visible = 1;
+ CreateCursor( p_vout );
+
+ /* Spawn base window - this window will include the video output window,
+ * but also command buttons, subtitles and other indicators */
+ if( CreateWindow( p_vout ) )
+ {
+ intf_ErrMsg( "vout error: cannot create X11 window" );
+ DestroyCursor( p_vout );
+ XCloseDisplay( p_vout->p_sys->p_display );
+ free( p_vout->p_sys );
+ return( 1 );
+ }
+
+ /* Disable screen saver and return */
+ DisableXScreenSaver( p_vout );
+
+ return( 0 );
+}
+
+/*****************************************************************************
+ * vout_Destroy: destroy X11 video thread output method
+ *****************************************************************************
+ * Terminate an output method created by vout_CreateOutputMethod
+ *****************************************************************************/
+static void vout_Destroy( vout_thread_t *p_vout )
+{
+ /* Restore cursor if it was blanked */
+ if( !p_vout->p_sys->b_mouse_pointer_visible )
+ {
+ ToggleCursor( p_vout );
+ }
+
+ DestroyCursor( p_vout );
+ EnableXScreenSaver( p_vout );
+ DestroyWindow( p_vout );
+
+ XCloseDisplay( p_vout->p_sys->p_display );
+
+ /* Destroy structure */
+ free( p_vout->p_sys );
+}
+
+/*****************************************************************************
+ * vout_Init: initialize X11 video thread output method
+ *****************************************************************************
+ * This function create the XImages needed by the output thread. It is called
+ * at the beginning of the thread, but also each time the window is resized.
+ *****************************************************************************/
+static int vout_Init( vout_thread_t *p_vout )
+{
+ int i_index;
+ picture_t *p_pic;
+
+ I_OUTPUTPICTURES = 0;
+
+#ifdef MODULE_NAME_IS_xvideo
+ /* Initialize the output structure; we already found an XVideo port,
+ * and the corresponding chroma we will be using. Since we can
+ * arbitrary scale, stick to the coordinates and aspect. */
+ p_vout->output.i_width = p_vout->render.i_width;
+ p_vout->output.i_height = p_vout->render.i_height;
+ p_vout->output.i_aspect = p_vout->render.i_aspect;
+
+#else
+ /* Initialize the output structure: RGB with square pixels, whatever
+ * the input format is, since it's the only format we know */
+ switch( p_vout->p_sys->i_screen_depth )
+ {
+ case 8: /* FIXME: set the palette */
+ p_vout->output.i_chroma = FOURCC_BI_RGB; break;
+ case 15:
+ p_vout->output.i_chroma = FOURCC_RV15; break;
+ case 16:
+ p_vout->output.i_chroma = FOURCC_RV16; break;
+ case 24:
+ p_vout->output.i_chroma = FOURCC_BI_BITFIELDS; break;
+ case 32:
+ p_vout->output.i_chroma = FOURCC_BI_BITFIELDS; break;
+ default:
+ intf_ErrMsg( "vout error: unknown screen depth" );
+ return( 0 );
+ }
+
+ p_vout->output.i_width = p_vout->p_sys->i_width;
+ p_vout->output.i_height = p_vout->p_sys->i_height;
+
+ /* Assume we have square pixels */
+ p_vout->output.i_aspect = p_vout->p_sys->i_width
+ * VOUT_ASPECT_FACTOR / p_vout->p_sys->i_height;
+#endif
+
+ /* Try to initialize up to MAX_DIRECTBUFFERS direct buffers */
+ while( I_OUTPUTPICTURES < MAX_DIRECTBUFFERS )
+ {
+ p_pic = NULL;
+
+ /* Find an empty picture slot */
+ for( i_index = 0 ; i_index < VOUT_MAX_PICTURES ; i_index++ )
+ {
+ if( p_vout->p_picture[ i_index ].i_status == FREE_PICTURE )
+ {
+ p_pic = p_vout->p_picture + i_index;
+ break;
+ }
+ }
+
+ /* Allocate the picture */
+ if( p_pic == NULL || NewPicture( p_vout, p_pic ) )
+ {
+ break;
+ }
+
+ p_pic->i_status = DESTROYED_PICTURE;
+ p_pic->i_type = DIRECT_PICTURE;
+
+ PP_OUTPUTPICTURE[ I_OUTPUTPICTURES ] = p_pic;
+
+ I_OUTPUTPICTURES++;
+ }
+
+ return( 0 );
+}
+
+/*****************************************************************************
+ * vout_Render: render previously calculated output
+ *****************************************************************************/
+static void vout_Render( vout_thread_t *p_vout, picture_t *p_pic )
+{
+ ;
+}
+
+ /*****************************************************************************
+ * vout_Display: displays previously rendered output
+ *****************************************************************************
+ * This function sends the currently rendered image to X11 server.
+ * (The Xv extension takes care of "double-buffering".)
+ *****************************************************************************/
+static void vout_Display( vout_thread_t *p_vout, picture_t *p_pic )
+{
+ int i_width, i_height, i_x, i_y;
+
+ vout_PlacePicture( p_vout, p_vout->p_sys->i_width, p_vout->p_sys->i_height,
+ &i_x, &i_y, &i_width, &i_height );
+}
+
+/*****************************************************************************
+ * vout_Manage: handle X11 events
+ *****************************************************************************
+ * This function should be called regularly by video output thread. It manages
+ * X11 events and allows window resizing. It returns a non null value on
+ * error.
+ *****************************************************************************/
+static int vout_Manage( vout_thread_t *p_vout )
+{
+ XEvent xevent; /* X11 event */
+ boolean_t b_resized; /* window has been resized */
+ char i_key; /* ISO Latin-1 key */
+ KeySym x_key_symbol;
+
+ /* Handle X11 events: ConfigureNotify events are parsed to know if the
+ * output window's size changed, MapNotify and UnmapNotify to know if the
+ * window is mapped (and if the display is useful), and ClientMessages
+ * to intercept window destruction requests */
+
+ b_resized = 0;
+ while( XCheckWindowEvent( p_vout->p_sys->p_display, p_vout->p_sys->window,
+ StructureNotifyMask | KeyPressMask |
+ ButtonPressMask | ButtonReleaseMask |
+ PointerMotionMask | Button1MotionMask , &xevent )
+ == True )
+ {
+ /* ConfigureNotify event: prepare */
+ if( (xevent.type == ConfigureNotify)
+ && ((xevent.xconfigure.width != p_vout->p_sys->i_width)
+ || (xevent.xconfigure.height != p_vout->p_sys->i_height)) )
+ {
+ /* Update dimensions */
+ b_resized = 1;
+ p_vout->i_changes |= VOUT_SIZE_CHANGE;
+ p_vout->p_sys->i_width = xevent.xconfigure.width;
+ p_vout->p_sys->i_height = xevent.xconfigure.height;
+ }
+ /* MapNotify event: change window status and disable screen saver */
+ else if( xevent.type == MapNotify)
+ {
+ if( (p_vout != NULL) && !p_vout->b_active )
+ {
+ DisableXScreenSaver( p_vout );
+ p_vout->b_active = 1;
+ }
+ }
+ /* UnmapNotify event: change window status and enable screen saver */
+ else if( xevent.type == UnmapNotify )
+ {
+ if( (p_vout != NULL) && p_vout->b_active )
+ {
+ EnableXScreenSaver( p_vout );
+ p_vout->b_active = 0;
+ }
+ }
+ /* Keyboard event */
+ else if( xevent.type == KeyPress )
+ {
+ /* We may have keys like F1 trough F12, ESC ... */
+ x_key_symbol = XKeycodeToKeysym( p_vout->p_sys->p_display,
+ xevent.xkey.keycode, 0 );
+ switch( x_key_symbol )
+ {
+ case XK_Escape:
+ p_main->p_intf->b_die = 1;
+ break;
+ case XK_Menu:
+ p_main->p_intf->b_menu_change = 1;
+ break;
+ case XK_Left:
+ vout_Seek( -5 );
+ break;
+ case XK_Right:
+ vout_Seek( 5 );
+ break;
+ case XK_Up:
+ vout_Seek( 60 );
+ break;
+ case XK_Down:
+ vout_Seek( -60 );
+ break;
+ case XK_Home:
+ input_Seek( p_input_bank->pp_input[0],
+ p_input_bank->pp_input[0]->stream.p_selected_area->i_start );
+ break;
+ case XK_End:
+ input_Seek( p_input_bank->pp_input[0],
+ p_input_bank->pp_input[0]->stream.p_selected_area->i_size );
+ break;
+ case XK_Page_Up:
+ vout_Seek( 900 );
+ break;
+ case XK_Page_Down:
+ vout_Seek( -900 );
+ break;
+ case XK_space:
+ input_SetStatus( p_input_bank->pp_input[0],
+ INPUT_STATUS_PAUSE );
+ break;
+
+ default:
+ /* "Normal Keys"
+ * The reason why I use this instead of XK_0 is that
+ * with XLookupString, we don't have to care about
+ * keymaps. */
+
+ if( XLookupString( &xevent.xkey, &i_key, 1, NULL, NULL ) )
+ {
+ /* FIXME: handle stuff here */
+ switch( i_key )
+ {
+ case 'q':
+ case 'Q':
+ p_main->p_intf->b_die = 1;
+ break;
+ case 'f':
+ case 'F':
+ p_vout->i_changes |= VOUT_FULLSCREEN_CHANGE;
+ break;
+
+ case '0': network_ChannelJoin( 0 ); break;
+ case '1': network_ChannelJoin( 1 ); break;
+ case '2': network_ChannelJoin( 2 ); break;
+ case '3': network_ChannelJoin( 3 ); break;
+ case '4': network_ChannelJoin( 4 ); break;
+ case '5': network_ChannelJoin( 5 ); break;
+ case '6': network_ChannelJoin( 6 ); break;
+ case '7': network_ChannelJoin( 7 ); break;
+ case '8': network_ChannelJoin( 8 ); break;
+ case '9': network_ChannelJoin( 9 ); break;
+
+ default:
+ intf_DbgMsg( "vout: unhandled key '%c' (%i)",
+ (char)i_key, i_key );
+ break;
+ }
+ }
+ break;
+ }
+ }
+ /* Mouse click */
+ else if( xevent.type == ButtonPress )
+ {
+ switch( ((XButtonEvent *)&xevent)->button )
+ {
+ case Button1:
+ /* In this part we will eventually manage
+ * clicks for DVD navigation for instance. For the
+ * moment just pause the stream. */
+ input_SetStatus( p_input_bank->pp_input[0],
+ INPUT_STATUS_PAUSE );
+ break;
+
+ case Button4:
+ vout_Seek( 15 );
+ break;
+
+ case Button5:
+ vout_Seek( -15 );
+ break;
+ }
+ }
+ /* Mouse release */
+ else if( xevent.type == ButtonRelease )
+ {
+ switch( ((XButtonEvent *)&xevent)->button )
+ {
+ case Button3:
+ /* FIXME: need locking ! */
+ p_main->p_intf->b_menu_change = 1;
+ break;
+ }
+ }
+ /* Mouse move */
+ else if( xevent.type == MotionNotify )
+ {
+ p_vout->p_sys->i_time_mouse_last_moved = mdate();
+ if( ! p_vout->p_sys->b_mouse_pointer_visible )
+ {
+ ToggleCursor( p_vout );
+ }
+ }
+ /* Other event */
+ else
+ {
+ intf_WarnMsg( 3, "vout: unhandled event %d received", xevent.type );
+ }
+ }
+
+ /* ClientMessage event - only WM_PROTOCOLS with WM_DELETE_WINDOW data
+ * are handled - according to the man pages, the format is always 32
+ * in this case */
+ while( XCheckTypedEvent( p_vout->p_sys->p_display,
+ ClientMessage, &xevent ) )
+ {
+ if( (xevent.xclient.message_type == p_vout->p_sys->wm_protocols)
+ && (xevent.xclient.data.l[0] == p_vout->p_sys->wm_delete_window ) )
+ {
+ p_main->p_intf->b_die = 1;
+ }
+ else
+ {
+ intf_DbgMsg( "vout: unhandled ClientMessage received" );
+ }
+ }
+
+ /*
+ * Fullscreen Change
+ */
+ if ( p_vout->i_changes & VOUT_FULLSCREEN_CHANGE )
+ {
+ ToggleFullScreen( p_vout );
+ p_vout->i_changes &= ~VOUT_FULLSCREEN_CHANGE;
+
+ }
+
+ /*
+ * Size change
+ */
+ if( p_vout->i_changes & VOUT_SIZE_CHANGE )
+ {
+ int i_width, i_height, i_x, i_y;
+
+ p_vout->i_changes &= ~VOUT_SIZE_CHANGE;
+
+ intf_WarnMsg( 3, "vout: video display resized (%dx%d)",
+ p_vout->p_sys->i_width,
+ p_vout->p_sys->i_height );
+
+ vout_PlacePicture( p_vout, p_vout->p_sys->i_width,
+ p_vout->p_sys->i_height,
+ &i_x, &i_y, &i_width, &i_height );
+ }
+
+ /* Autohide Cursour */
+ if( mdate() - p_vout->p_sys->i_time_mouse_last_moved > 2000000 )
+ {
+ /* Hide the mouse automatically */
+ if( p_vout->p_sys->b_mouse_pointer_visible )
+ {
+ ToggleCursor( p_vout );
+ }
+ }
+
+ return 0;
+}
+
+/*****************************************************************************
+ * vout_End: terminate X11 video thread output method
+ *****************************************************************************
+ * Destroy the X11 XImages created by vout_Init. It is called at the end of
+ * the thread, but also each time the window is resized.
+ *****************************************************************************/
+static void vout_End( vout_thread_t *p_vout )
+{
+ int i_index;
+
+ /* Free the direct buffers we allocated */
+ for( i_index = I_OUTPUTPICTURES ; i_index ; )
+ {
+ i_index--;
+ FreePicture( p_vout, PP_OUTPUTPICTURE[ i_index ] );
+ }
+}
+
+/* following functions are local */
+
+/*****************************************************************************
+ * CreateWindow: open and set-up X11 main window
+ *****************************************************************************/
+static int CreateWindow( vout_thread_t *p_vout )
+{
+ XSizeHints xsize_hints;
+ XSetWindowAttributes xwindow_attributes;
+ XGCValues xgcvalues;
+ XEvent xevent;
+
+ boolean_t b_expose;
+ boolean_t b_configure_notify;
+ boolean_t b_map_notify;
+
+ /* Set main window's size */
+ if( p_vout->render.i_height * p_vout->render.i_aspect
+ >= p_vout->render.i_width * VOUT_ASPECT_FACTOR )
+ {
+ p_vout->p_sys->i_width = p_vout->render.i_height
+ * p_vout->render.i_aspect / VOUT_ASPECT_FACTOR;
+ p_vout->p_sys->i_height = p_vout->render.i_height;
+ }
+ else
+ {
+ p_vout->p_sys->i_width = p_vout->render.i_width;
+ p_vout->p_sys->i_height = p_vout->render.i_width
+ * VOUT_ASPECT_FACTOR / p_vout->render.i_aspect;
+ }
+
+#if 0
+ if( p_vout->p_sys->i_width <= 300 && p_vout->p_sys->i_height <= 300 )
+ {
+ p_vout->p_sys->i_width <<= 1;
+ p_vout->p_sys->i_height <<= 1;
+ }
+ else if( p_vout->p_sys->i_width <= 400
+ && p_vout->p_sys->i_height <= 400 )
+ {
+ p_vout->p_sys->i_width += p_vout->p_sys->i_width >> 1;
+ p_vout->p_sys->i_height += p_vout->p_sys->i_height >> 1;
+ }
+#endif
+
+ /* Prepare window manager hints and properties */
+ xsize_hints.base_width = p_vout->p_sys->i_width;
+ xsize_hints.base_height = p_vout->p_sys->i_height;
+ xsize_hints.flags = PSize;
+ p_vout->p_sys->wm_protocols = XInternAtom( p_vout->p_sys->p_display,
+ "WM_PROTOCOLS", True );
+ p_vout->p_sys->wm_delete_window = XInternAtom( p_vout->p_sys->p_display,
+ "WM_DELETE_WINDOW", True );
+
+ /* Prepare window attributes */
+ xwindow_attributes.backing_store = Always; /* save the hidden part */
+ xwindow_attributes.background_pixel = BlackPixel(p_vout->p_sys->p_display,
+ p_vout->p_sys->i_screen);
+ xwindow_attributes.event_mask = ExposureMask | StructureNotifyMask;
+
+
+ /* Create the window and set hints - the window must receive
+ * ConfigureNotify events, and until it is displayed, Expose and
+ * MapNotify events. */
+
+ p_vout->p_sys->window =
+ XCreateWindow( p_vout->p_sys->p_display,
+ DefaultRootWindow( p_vout->p_sys->p_display ),
+ 0, 0,
+ p_vout->p_sys->i_width,
+ p_vout->p_sys->i_height,
+ 0,
+ 0, InputOutput, 0,
+ CWBackingStore | CWBackPixel | CWEventMask,
+ &xwindow_attributes );
+
+ /* Set window manager hints and properties: size hints, command,
+ * window's name, and accepted protocols */
+ XSetWMNormalHints( p_vout->p_sys->p_display, p_vout->p_sys->window,
+ &xsize_hints );
+ XSetCommand( p_vout->p_sys->p_display, p_vout->p_sys->window,
+ p_main->ppsz_argv, p_main->i_argc );
+ XStoreName( p_vout->p_sys->p_display, p_vout->p_sys->window,
+ VOUT_TITLE " (XMGA output)"
+ );
+
+ if( (p_vout->p_sys->wm_protocols == None) /* use WM_DELETE_WINDOW */
+ || (p_vout->p_sys->wm_delete_window == None)
+ || !XSetWMProtocols( p_vout->p_sys->p_display, p_vout->p_sys->window,
+ &p_vout->p_sys->wm_delete_window, 1 ) )
+ {
+ /* WM_DELETE_WINDOW is not supported by window manager */
+ intf_Msg( "vout error: missing or bad window manager" );
+ }
+
+ /* Creation of a graphic context that doesn't generate a GraphicsExpose
+ * event when using functions like XCopyArea */
+ xgcvalues.graphics_exposures = False;
+ p_vout->p_sys->gc = XCreateGC( p_vout->p_sys->p_display,
+ p_vout->p_sys->window,
+ GCGraphicsExposures, &xgcvalues);
+
+ /* Send orders to server, and wait until window is displayed - three
+ * events must be received: a MapNotify event, an Expose event allowing
+ * drawing in the window, and a ConfigureNotify to get the window
+ * dimensions. Once those events have been received, only ConfigureNotify
+ * events need to be received. */
+ b_expose = 0;
+ b_configure_notify = 0;
+ b_map_notify = 0;
+ XMapWindow( p_vout->p_sys->p_display, p_vout->p_sys->window);
+ do
+ {
+ XNextEvent( p_vout->p_sys->p_display, &xevent);
+ if( (xevent.type == Expose)
+ && (xevent.xexpose.window == p_vout->p_sys->window) )
+ {
+ b_expose = 1;
+ }
+ else if( (xevent.type == MapNotify)
+ && (xevent.xmap.window == p_vout->p_sys->window) )
+ {
+ b_map_notify = 1;
+ }
+ else if( (xevent.type == ConfigureNotify)
+ && (xevent.xconfigure.window == p_vout->p_sys->window) )
+ {
+ b_configure_notify = 1;
+ p_vout->p_sys->i_width = xevent.xconfigure.width;
+ p_vout->p_sys->i_height = xevent.xconfigure.height;
+ }
+ } while( !( b_expose && b_configure_notify && b_map_notify ) );
+
+ XSelectInput( p_vout->p_sys->p_display, p_vout->p_sys->window,
+ StructureNotifyMask | KeyPressMask |
+ ButtonPressMask | ButtonReleaseMask |
+ PointerMotionMask );
+
+ /* If the cursor was formerly blank than blank it again */
+ if( !p_vout->p_sys->b_mouse_pointer_visible )
+ {
+ ToggleCursor( p_vout );
+ ToggleCursor( p_vout );
+ }
+
+ XSync( p_vout->p_sys->p_display, False );
+
+ /* At this stage, the window is open, displayed, and ready to
+ * receive data */
+
+ return( 0 );
+}
+
+/*****************************************************************************
+ * DestroyWindow: destroy the window
+ *****************************************************************************
+ *
+ *****************************************************************************/
+static void DestroyWindow( vout_thread_t *p_vout )
+{
+ XSync( p_vout->p_sys->p_display, False );
+
+ XUnmapWindow( p_vout->p_sys->p_display, p_vout->p_sys->window );
+ XFreeGC( p_vout->p_sys->p_display, p_vout->p_sys->gc );
+ XDestroyWindow( p_vout->p_sys->p_display, p_vout->p_sys->window );
+}
+
+/*****************************************************************************
+ * NewPicture: allocate a picture
+ *****************************************************************************
+ * Returns 0 on success, -1 otherwise
+ *****************************************************************************/
+static int NewPicture( vout_thread_t *p_vout, picture_t *p_pic )
+{
+ /* We know the chroma, allocate a buffer which will be used
+ * directly by the decoder */
+ p_pic->p_sys = malloc( sizeof( picture_sys_t ) );
+
+ if( p_pic->p_sys == NULL )
+ {
+ return -1;
+ }
+
+ /* XXX */
+
+ switch( p_vout->output.i_chroma )
+ {
+ /* XXX ?? */
+
+ default:
+ /* Unknown chroma, tell the guy to get lost */
+ free( p_pic->p_sys );
+ intf_ErrMsg( "vout error: never heard of chroma 0x%.8x (%4.4s)",
+ p_vout->output.i_chroma,
+ (char*)&p_vout->output.i_chroma );
+ p_pic->i_planes = 0;
+ return -1;
+ }
+
+ return 0;
+}
+
+/*****************************************************************************
+ * FreePicture: destroy a picture allocated with NewPicture
+ *****************************************************************************
+ * Destroy XImage AND associated data. If using Shm, detach shared memory
+ * segment from server and process, then free it. The XDestroyImage manpage
+ * says that both the image structure _and_ the data pointed to by the
+ * image structure are freed, so no need to free p_image->data.
+ *****************************************************************************/
+static void FreePicture( vout_thread_t *p_vout, picture_t *p_pic )
+{
+
+ XSync( p_vout->p_sys->p_display, False );
+
+ free( p_pic->p_sys );
+}
+
+/*****************************************************************************
+ * ToggleFullScreen: Enable or disable full screen mode
+ *****************************************************************************
+ * This function will switch between fullscreen and window mode.
+ *
+ *****************************************************************************/
+static void ToggleFullScreen ( vout_thread_t *p_vout )
+{
+ Atom prop;
+ mwmhints_t mwmhints;
+ int i_xpos, i_ypos, i_width, i_height;
+
+ p_vout->b_fullscreen = !p_vout->b_fullscreen;
+
+ if( p_vout->b_fullscreen )
+ {
+ Window next_parent, parent, *p_dummy, dummy1;
+ unsigned int dummy2, dummy3;
+
+ intf_WarnMsg( 3, "vout: entering fullscreen mode" );
+
+ /* Save current window coordinates so they can be restored when
+ * we exit from fullscreen mode */
+
+ /* find the real parent, which means the which is a direct child of
+ * the root window */
+ next_parent = parent = p_vout->p_sys->window;
+ while( next_parent != DefaultRootWindow( p_vout->p_sys->p_display ) )
+ {
+ parent = next_parent;
+ XQueryTree( p_vout->p_sys->p_display,
+ parent,
+ &dummy1,
+ &next_parent,
+ &p_dummy,
+ &dummy2 );
+ XFree((void *)p_dummy);
+ }
+
+ XGetGeometry( p_vout->p_sys->p_display,
+ p_vout->p_sys->window,
+ &dummy1,
+ &dummy2,
+ &dummy3,
+ &p_vout->p_sys->i_width_backup,
+ &p_vout->p_sys->i_height_backup,
+ &dummy2, &dummy3 );
+
+ XTranslateCoordinates( p_vout->p_sys->p_display,
+ parent,
+ DefaultRootWindow( p_vout->p_sys->p_display ),
+ 0,
+ 0,
+ &p_vout->p_sys->i_xpos_backup,
+ &p_vout->p_sys->i_ypos_backup,
+ &dummy1 );
+
+ mwmhints.flags = MWM_HINTS_DECORATIONS;
+ mwmhints.decorations = 0;
+
+ i_xpos = 0;
+ i_ypos = 0;
+ i_width = DisplayWidth( p_vout->p_sys->p_display,
+ p_vout->p_sys->i_screen );
+ i_height = DisplayHeight( p_vout->p_sys->p_display,
+ p_vout->p_sys->i_screen );
+
+#if 0
+ /* Being a transient window allows us to really be fullscreen (display
+ * over the taskbar for instance) but then we end-up with the same
+ * result as with the brute force method */
+ XSetTransientForHint( p_vout->p_sys->p_display,
+ p_vout->p_sys->window, None );
+#endif
+ }
+ else
+ {
+ intf_WarnMsg( 3, "vout: leaving fullscreen mode" );
+
+ mwmhints.flags = MWM_HINTS_DECORATIONS;
+ mwmhints.decorations = 1;
+
+ i_xpos = p_vout->p_sys->i_xpos_backup;
+ i_ypos = p_vout->p_sys->i_ypos_backup;
+ i_width = p_vout->p_sys->i_width_backup;
+ i_height = p_vout->p_sys->i_height_backup;
+ }
+
+ /* To my knowledge there are two ways to create a borderless window.
+ * There's the generic way which is to tell x to bypass the window manager,
+ * but this creates problems with the focus of other applications.
+ * The other way is to use the motif property "_MOTIF_WM_HINTS" which
+ * luckily seems to be supported by most window managers.
+ */
+ prop = XInternAtom( p_vout->p_sys->p_display, "_MOTIF_WM_HINTS",
+ False );
+ XChangeProperty( p_vout->p_sys->p_display, p_vout->p_sys->window,
+ prop, prop, 32, PropModeReplace,
+ (unsigned char *)&mwmhints,
+ PROP_MWM_HINTS_ELEMENTS );
+#if 0 /* brute force way to remove decorations */
+ XSetWindowAttributes attributes;
+ attributes.override_redirect = True;
+ XChangeWindowAttributes( p_vout->p_sys->p_display,
+ p_vout->p_sys->window,
+ CWOverrideRedirect,
+ &attributes);
+#endif
+
+ /* We need to unmap and remap the window if we want the window
+ * manager to take our changes into effect */
+ XUnmapWindow( p_vout->p_sys->p_display, p_vout->p_sys->window);
+ XMapRaised( p_vout->p_sys->p_display, p_vout->p_sys->window);
+ XMoveResizeWindow( p_vout->p_sys->p_display,
+ p_vout->p_sys->window,
+ i_xpos,
+ i_ypos,
+ i_width,
+ i_height );
+ XFlush( p_vout->p_sys->p_display );
+}
+
+/*****************************************************************************
+ * EnableXScreenSaver: enable screen saver
+ *****************************************************************************
+ * This function enables the screen saver on a display after it has been
+ * disabled by XDisableScreenSaver.
+ * FIXME: what happens if multiple vlc sessions are running at the same
+ * time ???
+ *****************************************************************************/
+static void EnableXScreenSaver( vout_thread_t *p_vout )
+{
+ int dummy;
+
+ intf_DbgMsg( "vout: enabling screen saver" );
+ XSetScreenSaver( p_vout->p_sys->p_display, p_vout->p_sys->i_ss_timeout,
+ p_vout->p_sys->i_ss_interval,
+ p_vout->p_sys->i_ss_blanking,
+ p_vout->p_sys->i_ss_exposure );
+
+ /* Restore DPMS settings */
+ if( DPMSQueryExtension( p_vout->p_sys->p_display, &dummy, &dummy ) )
+ {
+ if( p_vout->p_sys->b_ss_dpms )
+ {
+ DPMSEnable( p_vout->p_sys->p_display );
+ }
+ }
+}
+
+/*****************************************************************************
+ * DisableXScreenSaver: disable screen saver
+ *****************************************************************************
+ * See XEnableXScreenSaver
+ *****************************************************************************/
+static void DisableXScreenSaver( vout_thread_t *p_vout )
+{
+ int dummy;
+
+ /* Save screen saver informations */
+ XGetScreenSaver( p_vout->p_sys->p_display, &p_vout->p_sys->i_ss_timeout,
+ &p_vout->p_sys->i_ss_interval,
+ &p_vout->p_sys->i_ss_blanking,
+ &p_vout->p_sys->i_ss_exposure );
+
+ /* Disable screen saver */
+ intf_DbgMsg( "vout: disabling screen saver" );
+ XSetScreenSaver( p_vout->p_sys->p_display, 0,
+ p_vout->p_sys->i_ss_interval,
+ p_vout->p_sys->i_ss_blanking,
+ p_vout->p_sys->i_ss_exposure );
+
+ /* Disable DPMS */
+ if( DPMSQueryExtension( p_vout->p_sys->p_display, &dummy, &dummy ) )
+ {
+ CARD16 dummy;
+ /* Save DPMS current state */
+ DPMSInfo( p_vout->p_sys->p_display, &dummy,
+ &p_vout->p_sys->b_ss_dpms );
+ intf_DbgMsg( "vout: disabling DPMS" );
+ DPMSDisable( p_vout->p_sys->p_display );
+ }
+}
+
+/*****************************************************************************
+ * CreateCursor: create a blank mouse pointer
+ *****************************************************************************/
+static void CreateCursor( vout_thread_t *p_vout )
+{
+ XColor cursor_color;
+
+ p_vout->p_sys->cursor_pixmap =
+ XCreatePixmap( p_vout->p_sys->p_display,
+ DefaultRootWindow( p_vout->p_sys->p_display ),
+ 1, 1, 1 );
+
+ XParseColor( p_vout->p_sys->p_display,
+ XCreateColormap( p_vout->p_sys->p_display,
+ DefaultRootWindow(
+ p_vout->p_sys->p_display ),
+ DefaultVisual(
+ p_vout->p_sys->p_display,
+ p_vout->p_sys->i_screen ),
+ AllocNone ),
+ "black", &cursor_color );
+
+ p_vout->p_sys->blank_cursor =
+ XCreatePixmapCursor( p_vout->p_sys->p_display,
+ p_vout->p_sys->cursor_pixmap,
+ p_vout->p_sys->cursor_pixmap,
+ &cursor_color, &cursor_color, 1, 1 );
+}
+
+/*****************************************************************************
+ * DestroyCursor: destroy the blank mouse pointer
+ *****************************************************************************/
+static void DestroyCursor( vout_thread_t *p_vout )
+{
+ XFreePixmap( p_vout->p_sys->p_display, p_vout->p_sys->cursor_pixmap );
+}
+
+/*****************************************************************************
+ * ToggleCursor: hide or show the mouse pointer
+ *****************************************************************************
+ * This function hides the X pointer if it is visible by setting the pointer
+ * sprite to a blank one. To show it again, we disable the sprite.
+ *****************************************************************************/
+static void ToggleCursor( vout_thread_t *p_vout )
+{
+ if( p_vout->p_sys->b_mouse_pointer_visible )
+ {
+ XDefineCursor( p_vout->p_sys->p_display,
+ p_vout->p_sys->window,
+ p_vout->p_sys->blank_cursor );
+ p_vout->p_sys->b_mouse_pointer_visible = 0;
+ }
+ else
+ {
+ XUndefineCursor( p_vout->p_sys->p_display, p_vout->p_sys->window );
+ p_vout->p_sys->b_mouse_pointer_visible = 1;
+ }
+}
+
* decoders.
*****************************************************************************
* Copyright (C) 1998-2001 VideoLAN
- * $Id: input.c,v 1.168 2002/01/07 02:12:29 sam Exp $
+ * $Id: input.c,v 1.169 2002/01/09 02:01:14 sam Exp $
*
* Authors: Christophe Massiot <massiot@via.ecp.fr>
*
*****************************************************************************/
void input_EndBank ( void )
{
+ int i_input;
+
/* Ask all remaining video outputs to die */
- while( p_input_bank->i_count )
+ for( i_input = 0; i_input < p_input_bank->i_count; i_input++ )
{
+ input_StopThread(
+ p_input_bank->pp_input[ i_input ], NULL );
input_DestroyThread(
- p_input_bank->pp_input[ --p_input_bank->i_count ], NULL );
+ p_input_bank->pp_input[ i_input ] );
}
vlc_mutex_destroy( &p_input_bank->lock );
input_thread_t *input_CreateThread ( playlist_item_t *p_item, int *pi_status )
{
input_thread_t * p_input; /* thread descriptor */
- int i_status; /* thread status */
/* Allocate descriptor */
p_input = (input_thread_t *)malloc( sizeof(input_thread_t) );
}
/* Initialize thread properties */
- p_input->b_die = 0;
- p_input->b_error = 0;
- p_input->b_eof = 0;
+ p_input->b_die = 0;
+ p_input->b_error = 0;
+ p_input->b_eof = 0;
/* Set target */
- p_input->p_source = p_item->psz_name;
+ p_input->p_source = p_item->psz_name;
- /* I have never understood that stuff --Meuuh */
- p_input->pi_status = (pi_status != NULL) ? pi_status : &i_status;
- *p_input->pi_status = THREAD_CREATE;
+ /* Set status */
+ p_input->i_status = THREAD_CREATE;
/* Initialize stream description */
p_input->stream.i_es_number = 0;
return( NULL );
}
+#if 0
/* If status is NULL, wait until the thread is created */
if( pi_status == NULL )
{
msleep( THREAD_SLEEP );
} while( (i_status != THREAD_READY) && (i_status != THREAD_ERROR)
&& (i_status != THREAD_FATAL) );
- if( i_status != THREAD_READY )
- {
- return( NULL );
- }
}
+#endif
+
return( p_input );
}
/*****************************************************************************
- * input_DestroyThread: mark an input thread as zombie
+ * input_StopThread: mark an input thread as zombie
*****************************************************************************
* This function should not return until the thread is effectively cancelled.
*****************************************************************************/
-void input_DestroyThread( input_thread_t *p_input, int *pi_status )
+void input_StopThread( input_thread_t *p_input, int *pi_status )
{
- int i_status; /* thread status */
-
- /* Set status */
- p_input->pi_status = (pi_status != NULL) ? pi_status : &i_status;
- *p_input->pi_status = THREAD_DESTROY;
+ /* Make the thread exit from a possible vlc_cond_wait() */
+ vlc_mutex_lock( &p_input->stream.stream_lock );
/* Request thread destruction */
p_input->b_die = 1;
- /* Make the thread exit from a possible vlc_cond_wait() */
- vlc_mutex_lock( &p_input->stream.stream_lock );
vlc_cond_signal( &p_input->stream.stream_wait );
vlc_mutex_unlock( &p_input->stream.stream_lock );
/* If status is NULL, wait until thread has been destroyed */
+#if 0
if( pi_status == NULL )
{
do
} while ( (i_status != THREAD_OVER) && (i_status != THREAD_ERROR)
&& (i_status != THREAD_FATAL) );
}
+#endif
+}
+
+/*****************************************************************************
+ * input_DestroyThread: mark an input thread as zombie
+ *****************************************************************************
+ * This function should not return until the thread is effectively cancelled.
+ *****************************************************************************/
+void input_DestroyThread( input_thread_t *p_input )
+{
+ /* Join the thread */
+ vlc_thread_join( p_input->thread_id );
+
+ /* Destroy Mutex locks */
+ vlc_mutex_destroy( &p_input->stream.control.control_lock );
+ vlc_mutex_destroy( &p_input->stream.stream_lock );
+
+ /* Free input structure */
+ free( p_input );
}
/*****************************************************************************
if( InitThread( p_input ) )
{
/* If we failed, wait before we are killed, and exit */
- *p_input->pi_status = THREAD_ERROR;
+ p_input->i_status = THREAD_ERROR;
p_input->b_error = 1;
ErrorThread( p_input );
DestroyThread( p_input );
return;
}
+ p_input->i_status = THREAD_READY;
+
/* initialization is complete */
vlc_mutex_lock( &p_input->stream.stream_lock );
p_input->stream.b_changed = 1;
return( -1 );
}
- *p_input->pi_status = THREAD_READY;
-
return( 0 );
}
*****************************************************************************/
static void EndThread( input_thread_t * p_input )
{
- int * pi_status; /* thread status */
-
/* Store status */
- pi_status = p_input->pi_status;
- *pi_status = THREAD_END;
+ p_input->i_status = THREAD_END;
if( p_main->b_stats )
{
*****************************************************************************/
static void DestroyThread( input_thread_t * p_input )
{
- int * pi_status; /* thread status */
-
- /* Store status */
- pi_status = p_input->pi_status;
-
- /* Destroy Mutex locks */
- vlc_mutex_destroy( &p_input->stream.control.control_lock );
- vlc_mutex_destroy( &p_input->stream.stream_lock );
-
- /* Free input structure */
- free( p_input );
-
/* Update status */
- *pi_status = THREAD_OVER;
+ p_input->i_status = THREAD_OVER;
}
/*****************************************************************************
* interface, such as command line.
*****************************************************************************
* Copyright (C) 1998-2001 VideoLAN
- * $Id: interface.c,v 1.86 2002/01/07 02:12:30 sam Exp $
+ * $Id: interface.c,v 1.87 2002/01/09 02:01:14 sam Exp $
*
* Authors: Vincent Seguin <seguin@via.ecp.fr>
*
vlc_mutex_lock( &p_input_bank->lock );
- if( p_input_bank->i_count
- && ( p_input_bank->pp_input[0]->b_error
- || p_input_bank->pp_input[0]->b_eof ) )
+ if( p_input_bank->i_count )
{
- intf_WarnMsg( 3, "intf: input thread destroyed" );
- input_DestroyThread( p_input_bank->pp_input[0], NULL );
- p_input_bank->pp_input[0] = NULL;
- p_input_bank->i_count--;
- }
+ int i_input;
+ input_thread_t *p_input;
+
+ for( i_input = 0; i_input < p_input_bank->i_count; i_input++ )
+ {
+ p_input = p_input_bank->pp_input[i_input];
+
+ if( p_input->i_status == THREAD_OVER )
+ {
+ /* XXX: completely stupid ! */
+ input_DestroyThread( p_input );
+ p_input_bank->pp_input[i_input] = NULL;
+ p_input_bank->i_count--;
+ }
+ else if( ( p_input->i_status == THREAD_READY
+ || p_input->i_status == THREAD_ERROR )
+ && ( p_input->b_error || p_input->b_eof ) )
+ {
+ input_StopThread( p_input, NULL );
+ }
+ }
+ }
/* If no stream is being played, try to find one */
- if( !p_input_bank->i_count && !p_intf->b_die )
+ else
{
// vlc_mutex_lock( &p_main->p_playlist->change_lock );
}
else
{
+ input_thread_t *p_input;
+
p_main->p_playlist->b_stopped = 0;
p_main->p_playlist->i_mode = PLAYLIST_FORWARD +
main_GetIntVariable( PLAYLIST_LOOP_VAR,
PLAYLIST_LOOP_DEFAULT );
intf_WarnMsg( 3, "intf: creating new input thread" );
- p_input_bank->pp_input[0] =
- input_CreateThread( &p_main->p_playlist->current, NULL );
- p_input_bank->i_count++;
+ p_input = input_CreateThread( &p_main->p_playlist->current,
+ NULL );
+ if( p_input != NULL )
+ {
+ p_input_bank->pp_input[ p_input_bank->i_count ] = p_input;
+ p_input_bank->i_count++;
+ }
}
}
else
--- /dev/null
+/*****************************************************************************
+ * intf_eject.c: CD/DVD-ROM ejection handling functions
+ *****************************************************************************
+ * Copyright (C) 2001, 2002 VideoLAN
+ * $Id: intf_eject.c,v 1.1 2002/01/09 02:01:14 sam Exp $
+ *
+ * Author: Julien Blache <jb@technologeek.org> for the Linux part
+ * with code taken from the Linux "eject" command
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
+ *****************************************************************************/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+
+#include <videolan/vlc.h>
+
+#ifdef SYS_LINUX
+
+/* This code could be extended to support CD/DVD-ROM chargers */
+# include <linux/version.h>
+ /* handy macro found in 2.1 kernels, but not in older ones */
+# ifndef KERNEL_VERSION
+# define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c))
+# endif
+
+# include <sys/types.h>
+# include <sys/stat.h>
+# include <sys/ioctl.h>
+# include <fcntl.h>
+
+# include <sys/ioctl.h>
+# include <linux/cdrom.h>
+# if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,0)
+# include <linux/ucdrom.h>
+# endif
+
+# include <sys/mount.h>
+# include <scsi/scsi.h>
+# include <scsi/sg.h>
+# include <scsi/scsi_ioctl.h>
+
+#endif
+
+static int EjectCdrom( int i_fd );
+static int EjectScsi ( int i_fd );
+
+/*
+ * Eject using CDROMEJECT ioctl. Return 0 if successful
+ */
+static int EjectCdrom( int i_fd )
+{
+ int i_status;
+
+ i_status = ioctl( i_fd, CDROMEJECT );
+
+ return i_status;
+}
+
+
+/*
+ * Eject using SCSI commands. Return 0 if successful
+ */
+static int EjectScsi( int i_fd )
+{
+ int i_status;
+
+ struct sdata
+ {
+ int inlen;
+ int outlen;
+ char cmd[256];
+ } scsi_cmd;
+
+ scsi_cmd.inlen = 0;
+ scsi_cmd.outlen = 0;
+ scsi_cmd.cmd[0] = ALLOW_MEDIUM_REMOVAL;
+ scsi_cmd.cmd[1] = 0;
+ scsi_cmd.cmd[2] = 0;
+ scsi_cmd.cmd[3] = 0;
+ scsi_cmd.cmd[4] = 0;
+ scsi_cmd.cmd[5] = 0;
+ i_status = ioctl( i_fd, SCSI_IOCTL_SEND_COMMAND, (void *)&scsi_cmd );
+ if( i_status != 0 )
+ {
+ return 1;
+ }
+
+ scsi_cmd.inlen = 0;
+ scsi_cmd.outlen = 0;
+ scsi_cmd.cmd[0] = START_STOP;
+ scsi_cmd.cmd[1] = 0;
+ scsi_cmd.cmd[2] = 0;
+ scsi_cmd.cmd[3] = 0;
+ scsi_cmd.cmd[4] = 1;
+ scsi_cmd.cmd[5] = 0;
+ i_status = ioctl( i_fd, SCSI_IOCTL_SEND_COMMAND, (void *)&scsi_cmd );
+ if( i_status != 0 )
+ {
+ return 1;
+ }
+
+ scsi_cmd.inlen = 0;
+ scsi_cmd.outlen = 0;
+ scsi_cmd.cmd[0] = START_STOP;
+ scsi_cmd.cmd[1] = 0;
+ scsi_cmd.cmd[2] = 0;
+ scsi_cmd.cmd[3] = 0;
+ scsi_cmd.cmd[4] = 2;
+ scsi_cmd.cmd[5] = 0;
+ i_status = ioctl( i_fd, SCSI_IOCTL_SEND_COMMAND, (void *)&scsi_cmd );
+ if( i_status != 0 )
+ {
+ return 1;
+ }
+
+ /* Force kernel to reread partition table when new disc inserted */
+ i_status = ioctl( i_fd, BLKRRPART );
+
+ return i_status;
+}
+
+/*
+ * returns 0 on success
+ * returns 1 on failure
+ * returns -1 if not implemented
+ *
+ * Modify eject_disc() prototype as needed for portability
+ */
+
+int intf_Eject( const char *psz_device )
+{
+ int i_ret;
+
+#ifdef SYS_LINUX
+ int i_fd = 0;
+
+ i_fd = open( psz_device, O_RDONLY | O_NONBLOCK );
+
+ if( i_fd == -1 )
+ {
+ intf_ErrMsg( "intf error: couldn't open device %s", psz_device );
+ return 1;
+ }
+
+ if( EjectCdrom(i_fd) == 0 )
+ {
+ i_ret = 0;
+ }
+ else if( EjectScsi(i_fd) == 0 )
+ {
+ i_ret = 0;
+ }
+ else
+ {
+ intf_ErrMsg( "intf error: couldn't eject %s", psz_device );
+ i_ret = 1;
+ }
+
+ close( i_fd );
+
+#else
+ i_ret = -1;
+
+#endif
+ return i_ret;
+}
+
* modules.c : Built-in and plugin modules management functions
*****************************************************************************
* Copyright (C) 2001 VideoLAN
- * $Id: modules.c,v 1.46 2001/12/30 07:09:56 sam Exp $
+ * $Id: modules.c,v 1.47 2002/01/09 02:01:14 sam Exp $
*
* Authors: Samuel Hocevar <sam@zoy.org>
* Ethan C. Baldridge <BaldridgeE@cadmus.com>
#include "interface.h"
#include "intf_playlist.h"
+#include "intf_eject.h"
#include "stream_control.h"
#include "input_ext-intf.h"
* modules_plugin.h : Plugin management functions used by the core application.
*****************************************************************************
* Copyright (C) 2001 VideoLAN
- * $Id: modules_plugin.h,v 1.3 2002/01/07 02:12:30 sam Exp $
+ * $Id: modules_plugin.h,v 1.4 2002/01/09 02:01:14 sam Exp $
*
* Authors: Samuel Hocevar <sam@zoy.org>
*
(p_symbols)->intf_PlaylistDestroy = intf_PlaylistDestroy; \
(p_symbols)->intf_PlaylistJumpto = intf_PlaylistJumpto; \
(p_symbols)->intf_UrlDecode = intf_UrlDecode; \
+ (p_symbols)->intf_Eject = intf_Eject; \
(p_symbols)->msleep = msleep; \
(p_symbols)->mdate = mdate; \
(p_symbols)->network_ChannelCreate = network_ChannelCreate; \