From c7b1c474c6a8687a0645553beb0e5c6f868d8c5c Mon Sep 17 00:00:00 2001 From: Sam Hocevar Date: Wed, 9 Jan 2002 02:01:14 +0000 Subject: [PATCH] * ./include/modules_inner.h: replaced _X with __VLC_SYMBOL because _X was 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. --- AUTHORS | 4 + BUGS | 14 +- Makefile | 3 +- configure | 2 +- configure.in | 2 +- include/common.h | 4 +- include/input_ext-intf.h | 7 +- include/intf_eject.h | 28 + include/modules_inner.h | 24 +- plugins/dummy/dummy.c | 5 +- plugins/dummy/input_dummy.c | 7 +- plugins/filter/wall.c | 6 +- plugins/glide/glide.c | 116 ++-- plugins/gtk/gnome.c | 83 +-- plugins/gtk/gnome.glade | 49 +- plugins/gtk/gnome_callbacks.c | 11 +- plugins/gtk/gnome_callbacks.h | 7 +- plugins/gtk/gnome_interface.c | 38 +- plugins/gtk/gtk.c | 86 +-- plugins/gtk/gtk.glade | 33 + plugins/gtk/gtk_callbacks.c | 58 +- plugins/gtk/gtk_callbacks.h | 11 +- plugins/gtk/gtk_display.c | 3 +- plugins/gtk/gtk_interface.c | 40 ++ plugins/mga/Makefile | 1 + plugins/mga/xmga.c | 1208 +++++++++++++++++++++++++++++++++ src/input/input.c | 89 +-- src/interface/interface.c | 47 +- src/interface/intf_eject.c | 182 +++++ src/misc/modules.c | 3 +- src/misc/modules_plugin.h | 3 +- 31 files changed, 1905 insertions(+), 269 deletions(-) create mode 100644 include/intf_eject.h create mode 100644 plugins/mga/xmga.c create mode 100644 src/interface/intf_eject.c diff --git a/AUTHORS b/AUTHORS index 6110c48886..f78dab6803 100644 --- a/AUTHORS +++ b/AUTHORS @@ -38,6 +38,10 @@ E: jobi@via.ecp.fr 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 diff --git a/BUGS b/BUGS index 4ce2e27a7e..dd978ef1ff 100644 --- a/BUGS +++ b/BUGS @@ -1,5 +1,5 @@ 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. @@ -17,10 +17,7 @@ Core: 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: @@ -37,8 +34,6 @@ Video 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. @@ -69,3 +64,8 @@ Gtk interface: * Saving preferences does not work at all. + +Misc: + + * The Jin-Roh DVD seems to segfault. + diff --git a/Makefile b/Makefile index 95a6b5db48..1ff8bced7c 100644 --- a/Makefile +++ b/Makefile @@ -100,6 +100,7 @@ PLUGINS_TARGETS := ac3_adec/ac3_adec \ memcpy/memcpymmxext \ memcpy/memcpy3dn \ mga/mga \ + mga/xmga \ motion/motion \ motion/motionmmx \ motion/motionmmxext \ @@ -122,7 +123,7 @@ PLUGINS_TARGETS := ac3_adec/ac3_adec \ # # 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 diff --git a/configure b/configure index 0e14ce3663..921317d8ad 100755 --- a/configure +++ b/configure @@ -6439,7 +6439,7 @@ if test "${enable_mga+set}" = set; then enableval="$enable_mga" if test x$enable_mga = xyes then - PLUGINS="${PLUGINS} mga" + PLUGINS="${PLUGINS} mga xmga" fi fi diff --git a/configure.in b/configure.in index df82da73d1..6d97190aec 100644 --- a/configure.in +++ b/configure.in @@ -948,7 +948,7 @@ AC_ARG_ENABLE(mga, [ --enable-mga Linux kernel Matrox support (default disabled)], [ if test x$enable_mga = xyes then - PLUGINS="${PLUGINS} mga" + PLUGINS="${PLUGINS} mga xmga" fi ]) dnl diff --git a/include/common.h b/include/common.h index 6658695817..2b537b0bba 100644 --- a/include/common.h +++ b/include/common.h @@ -3,7 +3,7 @@ * 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 * Vincent Seguin @@ -468,6 +468,7 @@ typedef struct module_symbols_s 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 ); @@ -576,6 +577,7 @@ typedef struct module_symbols_s struct module_s * ( * module_Need ) ( int, char *, struct probedata_s * ); void ( * module_Unneed ) ( struct module_s * ); + } module_symbols_t; #ifdef PLUGIN diff --git a/include/input_ext-intf.h b/include/input_ext-intf.h index f30e346974..32da2125fe 100644 --- a/include/input_ext-intf.h +++ b/include/input_ext-intf.h @@ -4,7 +4,7 @@ * 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 * @@ -259,7 +259,7 @@ typedef struct input_thread_s 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; @@ -343,7 +343,8 @@ void input_EndBank ( void ); 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 ); diff --git a/include/intf_eject.h b/include/intf_eject.h new file mode 100644 index 0000000000..71e7c1de82 --- /dev/null +++ b/include/intf_eject.h @@ -0,0 +1,28 @@ +/***************************************************************************** + * 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 + * + * 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 diff --git a/include/modules_inner.h b/include/modules_inner.h index e0a25aca34..4a9376f848 100644 --- a/include/modules_inner.h +++ b/include/modules_inner.h @@ -2,7 +2,7 @@ * 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 * @@ -56,15 +56,15 @@ /* 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 ) @@ -75,7 +75,7 @@ * 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; \ @@ -115,7 +115,7 @@ #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 ) ); \ @@ -136,7 +136,7 @@ * 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 ); diff --git a/plugins/dummy/dummy.c b/plugins/dummy/dummy.c index 5d23afe9fa..c68a96de30 100644 --- a/plugins/dummy/dummy.c +++ b/plugins/dummy/dummy.c @@ -2,7 +2,7 @@ * 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 * @@ -50,10 +50,11 @@ MODULE_INIT_START 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 diff --git a/plugins/dummy/input_dummy.c b/plugins/dummy/input_dummy.c index 7b63f261d5..392e848469 100644 --- a/plugins/dummy/input_dummy.c +++ b/plugins/dummy/input_dummy.c @@ -2,7 +2,7 @@ * 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 * @@ -89,10 +89,10 @@ static int DummyProbe( probedata_t *p_data ) 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 ); } /***************************************************************************** @@ -153,7 +153,6 @@ static void DummyOpen( input_thread_t * p_input ) } intf_ErrMsg( "input error: unknown command `%s'", psz_name ); - } /***************************************************************************** diff --git a/plugins/filter/wall.c b/plugins/filter/wall.c index acd562973d..a4d078338c 100644 --- a/plugins/filter/wall.c +++ b/plugins/filter/wall.c @@ -2,7 +2,7 @@ * 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 * @@ -134,8 +134,8 @@ static int vout_Create( vout_thread_t *p_vout ) 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 * diff --git a/plugins/glide/glide.c b/plugins/glide/glide.c index 1d053d54ce..bb7a2a0312 100644 --- a/plugins/glide/glide.c +++ b/plugins/glide/glide.c @@ -2,7 +2,7 @@ * 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 * @@ -60,7 +60,6 @@ static int vout_Manage ( vout_thread_t * ); 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 * ); @@ -94,9 +93,8 @@ typedef struct vout_sys_s { 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; @@ -167,36 +165,49 @@ int vout_Init( vout_thread_t *p_vout ) 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; } /***************************************************************************** @@ -286,18 +297,6 @@ static int OpenDisplay( vout_thread_t *p_vout ) 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(); @@ -308,8 +307,8 @@ static int OpenDisplay( vout_thread_t *p_vout ) } 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 ); @@ -347,10 +346,14 @@ static int OpenDisplay( vout_thread_t *p_vout ) 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 ); } @@ -367,34 +370,5 @@ static void CloseDisplay( vout_thread_t *p_vout ) /* 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; } diff --git a/plugins/gtk/gnome.c b/plugins/gtk/gnome.c index fbaac117c0..b03a3b5a8f 100644 --- a/plugins/gtk/gnome.c +++ b/plugins/gtk/gnome.c @@ -2,7 +2,7 @@ * 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 * @@ -329,53 +329,56 @@ static gint GnomeManage( gpointer p_data ) { 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 ); diff --git a/plugins/gtk/gnome.glade b/plugins/gtk/gnome.glade index 7f66367f6e..c094a3e46a 100644 --- a/plugins/gtk/gnome.glade +++ b/plugins/gtk/gnome.glade @@ -93,7 +93,6 @@ activate GnomeMenubarFileOpenActivate - "intf_window" Sat, 19 May 2001 16:27:02 GMT @@ -108,7 +107,6 @@ activate GnomeMenubarDiscOpenActivate - "intf_window" Sat, 19 May 2001 16:27:10 GMT @@ -122,9 +120,8 @@ Select a Network Stream activate - GnomeMenbarNetworkOpenActivate - "intf_window" - Sat, 19 May 2001 16:27:39 GMT + GnomeMenubarNetworkOpenActivate + Fri, 21 Dec 2001 13:11:28 GMT False @@ -137,13 +134,32 @@ False + + GtkPixmapMenuItem + menubar_eject + Eject disc + + activate + GnomeMenubarDiscEjectActivate + Fri, 21 Dec 2001 13:11:28 GMT + + + False + GNOME_STOCK_MENU_TOP + + + + GtkMenuItem + separator15 + False + + GtkPixmapMenuItem menubar_exit activate GnomeMenubarExitActivate - "intf_window" Sat, 19 May 2001 16:27:52 GMT GNOMEUIINFO_MENU_EXIT_ITEM @@ -166,7 +182,6 @@ activate GnomeMenubarWindowToggleActivate - "intf_window" Sat, 19 May 2001 16:28:06 GMT @@ -179,7 +194,6 @@ activate GnomeMenubarFullscreenActivate - "intf_window" Sat, 19 May 2001 16:28:15 GMT @@ -232,7 +246,6 @@ activate GnomeMenubarPlaylistActivate - "intf_window" Sat, 19 May 2001 16:28:41 GMT @@ -248,7 +261,6 @@ activate GnomeMenubarModulesActivate - "intf_window" Sat, 19 May 2001 16:28:53 GMT @@ -297,7 +309,6 @@ activate GnomeMenubarPreferencesActivate - "intf_window" Sat, 19 May 2001 16:29:03 GMT GNOMEUIINFO_MENU_PREFERENCES_ITEM @@ -320,7 +331,6 @@ activate GnomeMenubarAboutActivate - "intf_window" Sat, 19 May 2001 16:29:19 GMT GNOMEUIINFO_MENU_ABOUT_ITEM @@ -434,6 +444,21 @@ GNOME_STOCK_PIXMAP_STOP + + GtkButton + Toolbar:button + toolbar_eject + Eject disc + + button_press_event + GtkDiscEject + "intf_window" + Fri, 21 Dec 2001 15:24:18 GMT + + + GNOME_STOCK_PIXMAP_TOP + + GtkButton Toolbar:button diff --git a/plugins/gtk/gnome_callbacks.c b/plugins/gtk/gnome_callbacks.c index f326927872..56473f8dc3 100644 --- a/plugins/gtk/gnome_callbacks.c +++ b/plugins/gtk/gnome_callbacks.c @@ -30,12 +30,18 @@ GnomeMenubarDiscOpenActivate (GtkMenuItem *menuitem, 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, @@ -259,6 +265,3 @@ GnomePopupJumpActivate (GtkMenuItem *menuitem, { GtkJumpShow( GTK_WIDGET( menuitem ), NULL, "intf_popup" ); } - - - diff --git a/plugins/gtk/gnome_callbacks.h b/plugins/gtk/gnome_callbacks.h index c768fab7b7..bbf1089f47 100644 --- a/plugins/gtk/gnome_callbacks.h +++ b/plugins/gtk/gnome_callbacks.h @@ -11,7 +11,11 @@ GnomeMenubarDiscOpenActivate (GtkMenuItem *menuitem, gpointer user_data); void -GnomeMenbarNetworkOpenActivate (GtkMenuItem *menuitem, +GnomeMenubarNetworkOpenActivate (GtkMenuItem *menuitem, + gpointer user_data); + +void +GnomeMenubarDiscEjectActivate (GtkMenuItem *menuitem, gpointer user_data); void @@ -141,3 +145,4 @@ GtkNetworkOpenBroadcast (GtkToggleButton *togglebutton, void GtkNetworkOpenChannel (GtkToggleButton *togglebutton, gpointer user_data); + diff --git a/plugins/gtk/gnome_interface.c b/plugins/gtk/gnome_interface.c index c0a4dbb133..22aec155ff 100644 --- a/plugins/gtk/gnome_interface.c +++ b/plugins/gtk/gnome_interface.c @@ -32,11 +32,19 @@ static GnomeUIInfo menubar_file_menu_uiinfo[] = { 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 }; @@ -145,6 +153,7 @@ create_intf_window (void) GtkWidget *toolbar_network; GtkWidget *toolbar_back; GtkWidget *toolbar_stop; + GtkWidget *toolbar_eject; GtkWidget *toolbar_play; GtkWidget *toolbar_pause; GtkWidget *toolbar_slow; @@ -220,10 +229,20 @@ create_intf_window (void) (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, @@ -390,6 +409,18 @@ create_intf_window (void) (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, @@ -682,6 +713,9 @@ create_intf_window (void) 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"); diff --git a/plugins/gtk/gtk.c b/plugins/gtk/gtk.c index 335ccc4799..339d62f6f8 100644 --- a/plugins/gtk/gtk.c +++ b/plugins/gtk/gtk.c @@ -2,7 +2,7 @@ * 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 * @@ -328,61 +328,63 @@ static gint GtkManage( gpointer p_data ) /* 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 ) { diff --git a/plugins/gtk/gtk.glade b/plugins/gtk/gtk.glade index 871bb0bc30..78cc3a27b2 100644 --- a/plugins/gtk/gtk.glade +++ b/plugins/gtk/gtk.glade @@ -140,6 +140,26 @@ False + + GtkMenuItem + menubar_eject + Eject disc + + activate + GtkEjectDiscActivate + "intf_window" + Fri, 21 Dec 2001 12:51:34 GMT + + + False + + + + GtkMenuItem + separator14 + False + + GtkMenuItem menubar_exit @@ -441,6 +461,19 @@ + + GtkButton + Toolbar:button + toolbar_eject + + button_press_event + GtkDiscEject + "intf_window" + Fri, 21 Dec 2001 15:33:26 GMT + + + + GtkButton Toolbar:button diff --git a/plugins/gtk/gtk_callbacks.c b/plugins/gtk/gtk_callbacks.c index 1fbeda4f80..a420a001f1 100644 --- a/plugins/gtk/gtk_callbacks.c +++ b/plugins/gtk/gtk_callbacks.c @@ -2,10 +2,11 @@ * 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 * Stéphane Borel + * Julien BLACHE * * 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 @@ -30,6 +31,8 @@ #include +#include + #include #include @@ -39,6 +42,7 @@ #include "interface.h" #include "intf_playlist.h" +#include "intf_eject.h" #include "video.h" #include "video_output.h" @@ -463,3 +467,55 @@ void GtkJumpActivate( GtkMenuItem * menuitem, gpointer user_data ) 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 ); +} diff --git a/plugins/gtk/gtk_callbacks.h b/plugins/gtk/gtk_callbacks.h index 2d8b2da179..2dae4d2055 100644 --- a/plugins/gtk/gtk_callbacks.h +++ b/plugins/gtk/gtk_callbacks.h @@ -2,7 +2,7 @@ * 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 * Stéphane Borel @@ -70,3 +70,12 @@ void GtkNetworkJoin ( GtkEditable *, gpointer ); void GtkChannelGo ( GtkButton *, gpointer ); void GtkNetworkOpenChannel ( GtkToggleButton *, gpointer ); + +void +GtkEjectDiscActivate (GtkMenuItem *menuitem, + gpointer user_data); + +gboolean +GtkDiscEject (GtkWidget *widget, + GdkEventButton *event, + gpointer user_data); diff --git a/plugins/gtk/gtk_display.c b/plugins/gtk/gtk_display.c index 26db006290..cd1c6a4056 100644 --- a/plugins/gtk/gtk_display.c +++ b/plugins/gtk/gtk_display.c @@ -2,7 +2,7 @@ * 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 * Stéphane Borel @@ -225,6 +225,7 @@ gint GtkModeManage( intf_thread_t * p_intf ) /* 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 ); diff --git a/plugins/gtk/gtk_interface.c b/plugins/gtk/gtk_interface.c index 3fd7da5b9f..5c5683a822 100644 --- a/plugins/gtk/gtk_interface.c +++ b/plugins/gtk/gtk_interface.c @@ -29,6 +29,8 @@ create_intf_window (void) GtkWidget *menubar_disc; GtkWidget *menubar_network; GtkWidget *separator4; + GtkWidget *menubar_eject; + GtkWidget *separator14; GtkWidget *menubar_exit; GtkWidget *menubar_view; GtkWidget *menubar_view_menu; @@ -60,6 +62,7 @@ create_intf_window (void) GtkWidget *toolbar_network; GtkWidget *toolbar_back; GtkWidget *toolbar_stop; + GtkWidget *toolbar_eject; GtkWidget *toolbar_play; GtkWidget *toolbar_pause; GtkWidget *toolbar_slow; @@ -196,6 +199,26 @@ create_intf_window (void) 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")); @@ -500,6 +523,17 @@ create_intf_window (void) (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, @@ -776,6 +810,9 @@ create_intf_window (void) 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"); @@ -812,6 +849,9 @@ create_intf_window (void) 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"); diff --git a/plugins/mga/Makefile b/plugins/mga/Makefile index 630dfcad9f..5f2c872a31 100644 --- a/plugins/mga/Makefile +++ b/plugins/mga/Makefile @@ -1 +1,2 @@ mga_SOURCES = mga.c +xmga_SOURCES = xmga.c diff --git a/plugins/mga/xmga.c b/plugins/mga/xmga.c new file mode 100644 index 0000000000..57449188d0 --- /dev/null +++ b/plugins/mga/xmga.c @@ -0,0 +1,1208 @@ +/***************************************************************************** + * 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 + * Samuel Hocevar + * + * 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 /* ENOMEM */ +#include /* free() */ +#include /* strerror() */ + +#include + +#ifdef HAVE_MACHINE_PARAM_H +/* BSD */ +#include +#include /* typedef ushort */ +#include +#endif + +#ifndef WIN32 +#include /* BSD: struct in_addr */ +#endif + +#include /* shmget(), shmctl() */ +#include +#include +#include +#include +#include + +#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; + } +} + diff --git a/src/input/input.c b/src/input/input.c index d84a262618..207c598b04 100644 --- a/src/input/input.c +++ b/src/input/input.c @@ -4,7 +4,7 @@ * 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 * @@ -113,11 +113,15 @@ void input_InitBank ( void ) *****************************************************************************/ 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 ); @@ -134,7 +138,6 @@ void input_EndBank ( void ) 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) ); @@ -146,16 +149,15 @@ input_thread_t *input_CreateThread ( playlist_item_t *p_item, int *pi_status ) } /* 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; @@ -196,6 +198,7 @@ input_thread_t *input_CreateThread ( playlist_item_t *p_item, int *pi_status ) return( NULL ); } +#if 0 /* If status is NULL, wait until the thread is created */ if( pi_status == NULL ) { @@ -204,36 +207,30 @@ input_thread_t *input_CreateThread ( playlist_item_t *p_item, int *pi_status ) 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 @@ -242,6 +239,25 @@ void input_DestroyThread( input_thread_t *p_input, int *pi_status ) } 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 ); } /***************************************************************************** @@ -254,13 +270,15 @@ static void RunThread( input_thread_t *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; @@ -507,8 +525,6 @@ static int InitThread( input_thread_t * p_input ) return( -1 ); } - *p_input->pi_status = THREAD_READY; - return( 0 ); } @@ -531,11 +547,8 @@ static void ErrorThread( input_thread_t *p_input ) *****************************************************************************/ 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 ) { @@ -605,20 +618,8 @@ static void CloseThread( input_thread_t * p_input ) *****************************************************************************/ 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; } /***************************************************************************** diff --git a/src/interface/interface.c b/src/interface/interface.c index d36ba3b27b..dc78d91f74 100644 --- a/src/interface/interface.c +++ b/src/interface/interface.c @@ -4,7 +4,7 @@ * 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 * @@ -128,18 +128,33 @@ static void intf_Manage( intf_thread_t *p_intf ) 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 ); @@ -155,14 +170,20 @@ static void intf_Manage( intf_thread_t *p_intf ) } 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 diff --git a/src/interface/intf_eject.c b/src/interface/intf_eject.c new file mode 100644 index 0000000000..8111436b4a --- /dev/null +++ b/src/interface/intf_eject.c @@ -0,0 +1,182 @@ +/***************************************************************************** + * 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 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 +#include +#include +#include + +#include + +#ifdef SYS_LINUX + +/* This code could be extended to support CD/DVD-ROM chargers */ +# include + /* 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 +# include +# include +# include + +# include +# include +# if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,0) +# include +# endif + +# include +# include +# include +# include + +#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; +} + diff --git a/src/misc/modules.c b/src/misc/modules.c index 4fc8c56f58..d617f2675e 100644 --- a/src/misc/modules.c +++ b/src/misc/modules.c @@ -2,7 +2,7 @@ * 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 * Ethan C. Baldridge @@ -54,6 +54,7 @@ #include "interface.h" #include "intf_playlist.h" +#include "intf_eject.h" #include "stream_control.h" #include "input_ext-intf.h" diff --git a/src/misc/modules_plugin.h b/src/misc/modules_plugin.h index da0f221113..0535ca0883 100644 --- a/src/misc/modules_plugin.h +++ b/src/misc/modules_plugin.h @@ -2,7 +2,7 @@ * 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 * @@ -174,6 +174,7 @@ module_error( void ) (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; \ -- 2.39.2