]> git.sesse.net Git - vlc/commitdiff
* ./include/modules_inner.h: replaced _X with __VLC_SYMBOL because _X was
authorSam Hocevar <sam@videolan.org>
Wed, 9 Jan 2002 02:01:14 +0000 (02:01 +0000)
committerSam Hocevar <sam@videolan.org>
Wed, 9 Jan 2002 02:01:14 +0000 (02:01 +0000)
    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.

31 files changed:
AUTHORS
BUGS
Makefile
configure
configure.in
include/common.h
include/input_ext-intf.h
include/intf_eject.h [new file with mode: 0644]
include/modules_inner.h
plugins/dummy/dummy.c
plugins/dummy/input_dummy.c
plugins/filter/wall.c
plugins/glide/glide.c
plugins/gtk/gnome.c
plugins/gtk/gnome.glade
plugins/gtk/gnome_callbacks.c
plugins/gtk/gnome_callbacks.h
plugins/gtk/gnome_interface.c
plugins/gtk/gtk.c
plugins/gtk/gtk.glade
plugins/gtk/gtk_callbacks.c
plugins/gtk/gtk_callbacks.h
plugins/gtk/gtk_display.c
plugins/gtk/gtk_interface.c
plugins/mga/Makefile
plugins/mga/xmga.c [new file with mode: 0644]
src/input/input.c
src/interface/interface.c
src/interface/intf_eject.c [new file with mode: 0644]
src/misc/modules.c
src/misc/modules_plugin.h

diff --git a/AUTHORS b/AUTHORS
index 6110c488869b33448bab1b067ef4fd068613df6a..f78dab6803b3dd3e8a2694f03f8104bab988a695 100644 (file)
--- 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 4ce2e27a7e5734bbb26dea9108b2934ca7690e8c..dd978ef1ffb8c89349c3532d40a1f2f6b8cf03a6 100644 (file)
--- 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.
+
index 95a6b5db48a4d5d2e4c2cbc965e1079b7cc139b9..1ff8bced7c37434527786d6e740281baa2d60c9e 100644 (file)
--- 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
index 0e14ce36631eb24e6cbb0f9ff2410088d04dd466..921317d8ad0d24eb3bb8934023f2bb5c76cfa106 100755 (executable)
--- 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
 
index df82da73d1ab7ee962504000da87453c78b2f723..6d97190aeced8e7c164ee3b55f1294fdec25b589 100644 (file)
@@ -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
index 6658695817c764acfaecc46d13bfee17bb997fe9..2b537b0bbad59a964ef6d205c87a037d2b26bbaa 100644 (file)
@@ -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 <sam@via.ecp.fr>
  *          Vincent Seguin <seguin@via.ecp.fr>
@@ -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
index f30e34697400878fa8ee498a41e8443f2d029528..32da2125fe2c0e79a69214010304b0493b8ac745 100644 (file)
@@ -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 <massiot@via.ecp.fr>
  *
@@ -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 (file)
index 0000000..71e7c1d
--- /dev/null
@@ -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 <jb@technologeek.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
+ *****************************************************************************/
+
+#ifndef PLUGIN
+int intf_Eject( const char * );
+#else
+#   define intf_Eject p_symbols->intf_Eject
+#endif
index e0a25aca34f0280af4bf3c235c2ab2c6a55be107..4a9376f8487e49ba04b9ebad9ad9782bdc4979bf 100644 (file)
@@ -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 <sam@zoy.org>
  *
 /* If the module is built-in, then we need to define foo_InitModule instead
  * of InitModule. Same for Activate- and DeactivateModule. */
 #ifdef BUILTIN
-#   define _M( function )  CONCATENATE( function, MODULE_NAME )
-#   define _X( function )  CONCATENATE( function, MODULE_NAME )
-#   define DECLARE_SYMBOLS ;
-#   define STORE_SYMBOLS   ;
+#   define _M( function )          CONCATENATE( function, MODULE_NAME )
+#   define __VLC_SYMBOL( symbol )  CONCATENATE( symbol, MODULE_NAME )
+#   define DECLARE_SYMBOLS         ;
+#   define STORE_SYMBOLS           ;
 #else
-#   define _M( function )  function
-#   define _X( function )  CONCATENATE( function, MODULE_SYMBOL )
-#   define DECLARE_SYMBOLS module_symbols_t* p_symbols;
-#   define STORE_SYMBOLS   p_symbols = p_module->p_symbols;
+#   define _M( function )          function
+#   define __VLC_SYMBOL( symbol  ) CONCATENATE( symbol, MODULE_SYMBOL )
+#   define DECLARE_SYMBOLS         module_symbols_t* p_symbols;
+#   define STORE_SYMBOLS           p_symbols = p_module->p_symbols;
 #endif
 
 #define MODULE_STRING STRINGIFY( MODULE_NAME )
@@ -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;                                   \
 #define MODULE_ACTIVATE_START                                                 \
     DECLARE_SYMBOLS;                                                          \
                                                                               \
-    int _X( ActivateModule ) ( module_t *p_module )                           \
+    int __VLC_SYMBOL( ActivateModule ) ( module_t *p_module )                 \
     {                                                                         \
         p_module->p_functions =                                               \
           ( module_functions_t * )malloc( sizeof( module_functions_t ) );     \
  * here.
  */
 #define MODULE_DEACTIVATE_START                                               \
-    int _X( DeactivateModule )( module_t *p_module )                          \
+    int __VLC_SYMBOL( DeactivateModule )( module_t *p_module )                \
     {                                                                         \
         free( p_module->p_functions );
 
index 5d23afe9faf74a10b4aff9ca64a11ef7ab6016a2..c68a96de307ea79078f5e8ea40118966fc22f17f 100644 (file)
@@ -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 <sam@zoy.org>
  *
@@ -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
 
index 7b63f261d53c14d257da958fed825abf2eec792e..392e8484696eb9cad5d52a4a5d2d9df342c12e77 100644 (file)
@@ -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 <sam@zoy.org>
  *
@@ -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 );
-
 }
 
 /*****************************************************************************
index acd562973d4f1406fd3e89096c551446a6b34185..a4d078338ce3de50f2d54338e62ae71dd204bbe6 100644 (file)
@@ -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 <sam@zoy.org>
  *
@@ -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 *
index 1d053d54ce39f5a1996fc62e5e921bbdfdb87977..bb7a2a0312c176da7d66424b2456f9d11b0e2bff 100644 (file)
@@ -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 <sam@zoy.org>
  *
@@ -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;
 }
 
index fbaac117c0735a98a01bb39044829dda6e0471e7..b03a3b5a8f66852129728ce987ca6cf72e14b540 100644 (file)
@@ -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 <sam@zoy.org>
  *      
@@ -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 );
index 7f66367f6e320a251bcbbe80055f3d83832bf9bb..c094a3e46ac0142377d11966cba4740206dd40dd 100644 (file)
@@ -93,7 +93,6 @@
              <signal>
                <name>activate</name>
                <handler>GnomeMenubarFileOpenActivate</handler>
-               <data>&quot;intf_window&quot;</data>
                <last_modification_time>Sat, 19 May 2001 16:27:02 GMT</last_modification_time>
              </signal>
              <label>_Open File...</label>
              <signal>
                <name>activate</name>
                <handler>GnomeMenubarDiscOpenActivate</handler>
-               <data>&quot;intf_window&quot;</data>
                <last_modification_time>Sat, 19 May 2001 16:27:10 GMT</last_modification_time>
              </signal>
              <label>Open _Disc...</label>
              <tooltip>Select a Network Stream</tooltip>
              <signal>
                <name>activate</name>
-               <handler>GnomeMenbarNetworkOpenActivate</handler>
-               <data>&quot;intf_window&quot;</data>
-               <last_modification_time>Sat, 19 May 2001 16:27:39 GMT</last_modification_time>
+               <handler>GnomeMenubarNetworkOpenActivate</handler>
+               <last_modification_time>Fri, 21 Dec 2001 13:11:28 GMT</last_modification_time>
              </signal>
              <label>_Network Stream...</label>
              <right_justify>False</right_justify>
              <right_justify>False</right_justify>
            </widget>
 
+           <widget>
+             <class>GtkPixmapMenuItem</class>
+             <name>menubar_eject</name>
+             <tooltip>Eject disc</tooltip>
+             <signal>
+               <name>activate</name>
+               <handler>GnomeMenubarDiscEjectActivate</handler>
+               <last_modification_time>Fri, 21 Dec 2001 13:11:28 GMT</last_modification_time>
+             </signal>
+             <label>_Eject Disc</label>
+             <right_justify>False</right_justify>
+             <stock_icon>GNOME_STOCK_MENU_TOP</stock_icon>
+           </widget>
+
+           <widget>
+             <class>GtkMenuItem</class>
+             <name>separator15</name>
+             <right_justify>False</right_justify>
+           </widget>
+
            <widget>
              <class>GtkPixmapMenuItem</class>
              <name>menubar_exit</name>
              <signal>
                <name>activate</name>
                <handler>GnomeMenubarExitActivate</handler>
-               <data>&quot;intf_window&quot;</data>
                <last_modification_time>Sat, 19 May 2001 16:27:52 GMT</last_modification_time>
              </signal>
              <stock_item>GNOMEUIINFO_MENU_EXIT_ITEM</stock_item>
              <signal>
                <name>activate</name>
                <handler>GnomeMenubarWindowToggleActivate</handler>
-               <data>&quot;intf_window&quot;</data>
                <last_modification_time>Sat, 19 May 2001 16:28:06 GMT</last_modification_time>
              </signal>
              <label>_Hide interface</label>
              <signal>
                <name>activate</name>
                <handler>GnomeMenubarFullscreenActivate</handler>
-               <data>&quot;intf_window&quot;</data>
                <last_modification_time>Sat, 19 May 2001 16:28:15 GMT</last_modification_time>
              </signal>
              <label>_Fullscreen</label>
              <signal>
                <name>activate</name>
                <handler>GnomeMenubarPlaylistActivate</handler>
-               <data>&quot;intf_window&quot;</data>
                <last_modification_time>Sat, 19 May 2001 16:28:41 GMT</last_modification_time>
              </signal>
              <label>_Playlist...</label>
              <signal>
                <name>activate</name>
                <handler>GnomeMenubarModulesActivate</handler>
-               <data>&quot;intf_window&quot;</data>
                <last_modification_time>Sat, 19 May 2001 16:28:53 GMT</last_modification_time>
              </signal>
              <label>_Modules...</label>
              <signal>
                <name>activate</name>
                <handler>GnomeMenubarPreferencesActivate</handler>
-               <data>&quot;intf_window&quot;</data>
                <last_modification_time>Sat, 19 May 2001 16:29:03 GMT</last_modification_time>
              </signal>
              <stock_item>GNOMEUIINFO_MENU_PREFERENCES_ITEM</stock_item>
              <signal>
                <name>activate</name>
                <handler>GnomeMenubarAboutActivate</handler>
-               <data>&quot;intf_window&quot;</data>
                <last_modification_time>Sat, 19 May 2001 16:29:19 GMT</last_modification_time>
              </signal>
              <stock_item>GNOMEUIINFO_MENU_ABOUT_ITEM</stock_item>
          <stock_pixmap>GNOME_STOCK_PIXMAP_STOP</stock_pixmap>
        </widget>
 
+       <widget>
+         <class>GtkButton</class>
+         <child_name>Toolbar:button</child_name>
+         <name>toolbar_eject</name>
+         <tooltip>Eject disc</tooltip>
+         <signal>
+           <name>button_press_event</name>
+           <handler>GtkDiscEject</handler>
+           <data>&quot;intf_window&quot;</data>
+           <last_modification_time>Fri, 21 Dec 2001 15:24:18 GMT</last_modification_time>
+         </signal>
+         <label>Eject</label>
+         <stock_pixmap>GNOME_STOCK_PIXMAP_TOP</stock_pixmap>
+       </widget>
+
        <widget>
          <class>GtkButton</class>
          <child_name>Toolbar:button</child_name>
index f3269278721a2614a05588e692c7b132f0196a65..56473f8dc3dd2f991eea9113777e7d4902a73ea3 100644 (file)
@@ -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" );
 }
-
-
-
index c768fab7b7a7796f758c330896c473f4515b9842..bbf1089f471afd22f4dd26800b70d5a75356c42d 100644 (file)
@@ -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);
+
index c0a4dbb1331b4dd80a2008a1561365eb60139f13..22aec155ff0a54827f4fbf462ea219177d2ac9c4 100644 (file)
@@ -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");
index 335ccc479920776ab6a78508ff41441458730fce..339d62f6f833c7940a6eca572d5646d5f9117873 100644 (file)
@@ -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 <sam@zoy.org>
  *      
@@ -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 )
     {
index 871bb0bc30dae2d8b39caa143765498f4a8506da..78cc3a27b20b7b1c4acf48be1a92abcb50a82b29 100644 (file)
              <right_justify>False</right_justify>
            </widget>
 
+           <widget>
+             <class>GtkMenuItem</class>
+             <name>menubar_eject</name>
+             <tooltip>Eject disc</tooltip>
+             <signal>
+               <name>activate</name>
+               <handler>GtkEjectDiscActivate</handler>
+               <data>&quot;intf_window&quot;</data>
+               <last_modification_time>Fri, 21 Dec 2001 12:51:34 GMT</last_modification_time>
+             </signal>
+             <label>_Eject Disc</label>
+             <right_justify>False</right_justify>
+           </widget>
+
+           <widget>
+             <class>GtkMenuItem</class>
+             <name>separator14</name>
+             <right_justify>False</right_justify>
+           </widget>
+
            <widget>
              <class>GtkMenuItem</class>
              <name>menubar_exit</name>
          <label>Stop</label>
        </widget>
 
+       <widget>
+         <class>GtkButton</class>
+         <child_name>Toolbar:button</child_name>
+         <name>toolbar_eject</name>
+         <signal>
+           <name>button_press_event</name>
+           <handler>GtkDiscEject</handler>
+           <data>&quot;intf_window&quot;</data>
+           <last_modification_time>Fri, 21 Dec 2001 15:33:26 GMT</last_modification_time>
+         </signal>
+         <label>Eject</label>
+       </widget>
+
        <widget>
          <class>GtkButton</class>
          <child_name>Toolbar:button</child_name>
index 1fbeda4f806cae6500123be2fb7592fed9a1b6ce..a420a001f17133a3e9ce83d8f398b05f0a676698 100644 (file)
@@ -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 <sam@zoy.org>
  *          Stéphane Borel <stef@via.ecp.fr>
+ *          Julien BLACHE <jb@technologeek.org>
  *      
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -30,6 +31,8 @@
 
 #include <videolan/vlc.h>
 
+#include <unistd.h>
+
 #include <gtk/gtk.h>
 
 #include <string.h>
@@ -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 );
+}
index 2d8b2da179349232333ec2a25e2dc90b2c374ac8..2dae4d205590c3d8a7d57aeb808877c2040f4213 100644 (file)
@@ -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 <sam@zoy.org>
  *          Stéphane Borel <stef@via.ecp.fr>
@@ -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);
index 26db006290fc8df4c2dfe6a782fd894fa4fcc1eb..cd1c6a4056db2ba698ec06fb34586d688f3faacf 100644 (file)
@@ -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 <sam@zoy.org>
  *          Stéphane Borel <stef@via.ecp.fr>
@@ -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 );
index 3fd7da5b9f61c3d549e8ffbc264796f8ceaa0dc4..5c5683a822ce657e9da0c3288bc7b86fd574ebf1 100644 (file)
@@ -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");
index 630dfcad9f3e8b5f3a2d8e837d073de38ee0c6a7..5f2c872a315cd7a0891f2921c6d9b6749ec1e206 100644 (file)
@@ -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 (file)
index 0000000..5744918
--- /dev/null
@@ -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 <seguin@via.ecp.fr>
+ *          Samuel Hocevar <sam@zoy.org>
+ *      
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
+ *****************************************************************************/
+
+/*****************************************************************************
+ * Preamble
+ *****************************************************************************/
+#include <errno.h>                                                 /* ENOMEM */
+#include <stdlib.h>                                                /* free() */
+#include <string.h>                                            /* strerror() */
+
+#include <videolan/vlc.h>
+
+#ifdef HAVE_MACHINE_PARAM_H
+/* BSD */
+#include <machine/param.h>
+#include <sys/types.h>                                     /* typedef ushort */
+#include <sys/ipc.h>
+#endif
+
+#ifndef WIN32
+#include <netinet/in.h>                               /* BSD: struct in_addr */
+#endif
+
+#include <sys/shm.h>                                   /* shmget(), shmctl() */
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <X11/keysym.h>
+#include <X11/extensions/XShm.h>
+#include <X11/extensions/dpms.h>
+
+#include "video.h"
+#include "video_output.h"
+
+#include "interface.h"
+#include "netutils.h"                                 /* network_ChannelJoin */
+
+#include "stream_control.h"                 /* needed by input_ext-intf.h... */
+#include "input_ext-intf.h"
+
+//#include "mga.h"
+
+/*****************************************************************************
+ * Local prototypes
+ *****************************************************************************/
+static void vout_getfunctions( function_list_t * );
+
+static int  vout_Probe     ( probedata_t * );
+static int  vout_Create    ( vout_thread_t * );
+static void vout_Destroy   ( vout_thread_t * );
+static void vout_Render    ( vout_thread_t *, picture_t * );
+static void vout_Display   ( vout_thread_t *, picture_t * );
+static int  vout_Manage    ( vout_thread_t * );
+static int  vout_Init      ( vout_thread_t * );
+static void vout_End       ( vout_thread_t * );
+
+static int  CreateWindow   ( vout_thread_t * );
+static void DestroyWindow  ( vout_thread_t * );
+
+static int  NewPicture     ( vout_thread_t *, picture_t * );
+static void FreePicture    ( vout_thread_t *, picture_t * );
+
+static void ToggleFullScreen      ( vout_thread_t * );
+
+static void EnableXScreenSaver    ( vout_thread_t * );
+static void DisableXScreenSaver   ( vout_thread_t * );
+
+static void CreateCursor   ( vout_thread_t * );
+static void DestroyCursor  ( vout_thread_t * );
+static void ToggleCursor   ( vout_thread_t * );
+
+/*****************************************************************************
+ * Building configuration tree
+ *****************************************************************************/
+MODULE_CONFIG_START
+MODULE_CONFIG_STOP
+
+MODULE_INIT_START
+    SET_DESCRIPTION( "X11 MGA module" )
+    ADD_CAPABILITY( VOUT, 60 )
+    ADD_SHORTCUT( "xmga" )
+MODULE_INIT_STOP
+
+MODULE_ACTIVATE_START
+    vout_getfunctions( &p_module->p_functions->vout );
+MODULE_ACTIVATE_STOP
+
+MODULE_DEACTIVATE_START
+MODULE_DEACTIVATE_STOP
+
+/*****************************************************************************
+ * vout_sys_t: video output method descriptor
+ *****************************************************************************
+ * This structure is part of the video output thread descriptor.
+ * It describes the X11 and XVideo specific properties of an output thread.
+ *****************************************************************************/
+typedef struct vout_sys_s
+{
+    /* Internal settings and properties */
+    Display *           p_display;                        /* display pointer */
+
+    Visual *            p_visual;                          /* visual pointer */
+    int                 i_screen;                           /* screen number */
+    Window              window;                               /* root window */
+    GC                  gc;              /* graphic context instance handler */
+
+    boolean_t           b_shm;               /* shared memory extension flag */
+
+#ifdef MODULE_NAME_IS_xvideo
+    Window              yuv_window;   /* sub-window for displaying yuv video
+                                                                        data */
+    int                 i_xvport;
+#else
+    Colormap            colormap;               /* colormap used (8bpp only) */
+
+    int                 i_screen_depth;
+    int                 i_bytes_per_pixel;
+    int                 i_bytes_per_line;
+    int                 i_red_mask;
+    int                 i_green_mask;
+    int                 i_blue_mask;
+#endif
+
+    /* X11 generic properties */
+    Atom                wm_protocols;
+    Atom                wm_delete_window;
+
+    int                 i_width;                     /* width of main window */
+    int                 i_height;                   /* height of main window */
+
+    /* Backup of window position and size before fullscreen switch */
+    int                 i_width_backup;
+    int                 i_height_backup;
+    int                 i_xpos_backup;
+    int                 i_ypos_backup;
+
+    /* Screen saver properties */
+    int                 i_ss_timeout;                             /* timeout */
+    int                 i_ss_interval;           /* interval between changes */
+    int                 i_ss_blanking;                      /* blanking mode */
+    int                 i_ss_exposure;                      /* exposure mode */
+    BOOL                b_ss_dpms;                              /* DPMS mode */
+
+    /* Mouse pointer properties */
+    boolean_t           b_mouse_pointer_visible;
+    mtime_t             i_time_mouse_last_moved; /* used to auto-hide pointer*/
+    Cursor              blank_cursor;                   /* the hidden cursor */
+    Pixmap              cursor_pixmap;
+
+} vout_sys_t;
+
+/*****************************************************************************
+ * picture_sys_t: direct buffer method descriptor
+ *****************************************************************************
+ * This structure is part of the picture descriptor, it describes the
+ * XVideo specific properties of a direct buffer.
+ *****************************************************************************/
+typedef struct picture_sys_s
+{
+} picture_sys_t;
+
+/*****************************************************************************
+ * mwmhints_t: window manager hints
+ *****************************************************************************
+ * Fullscreen needs to be able to hide the wm decorations so we provide
+ * this structure to make it easier.
+ *****************************************************************************/
+#define MWM_HINTS_DECORATIONS   (1L << 1)
+#define PROP_MWM_HINTS_ELEMENTS 5
+typedef struct mwmhints_s
+{
+    u32 flags;
+    u32 functions;
+    u32 decorations;
+    s32 input_mode;
+    u32 status;
+} mwmhints_t;
+
+/*****************************************************************************
+ * Chroma defines
+ *****************************************************************************/
+#ifdef MODULE_NAME_IS_xvideo
+#   define MAX_DIRECTBUFFERS 5
+#else
+#   define MAX_DIRECTBUFFERS 2
+#endif
+
+/*****************************************************************************
+ * Seeking function TODO: put this in a generic location !
+ *****************************************************************************/
+static __inline__ void vout_Seek( off_t i_seek )
+{
+    off_t i_tell;
+
+    vlc_mutex_lock( &p_input_bank->lock );
+    if( p_input_bank->pp_input[0] != NULL )
+    {
+#define S p_input_bank->pp_input[0]->stream
+        i_tell = S.p_selected_area->i_tell + i_seek * (off_t)50 * S.i_mux_rate;
+
+        i_tell = ( i_tell <= 0 /*S.p_selected_area->i_start*/ )
+                   ? 0 /*S.p_selected_area->i_start*/
+                   : ( i_tell >= S.p_selected_area->i_size )
+                       ? S.p_selected_area->i_size
+                       : i_tell;
+
+        input_Seek( p_input_bank->pp_input[0], i_tell );
+#undef S
+    }
+    vlc_mutex_unlock( &p_input_bank->lock );
+}
+
+/*****************************************************************************
+ * Functions exported as capabilities. They are declared as static so that
+ * we don't pollute the namespace too much.
+ *****************************************************************************/
+static void vout_getfunctions( function_list_t * p_function_list )
+{
+    p_function_list->pf_probe = vout_Probe;
+    p_function_list->functions.vout.pf_create     = vout_Create;
+    p_function_list->functions.vout.pf_init       = vout_Init;
+    p_function_list->functions.vout.pf_end        = vout_End;
+    p_function_list->functions.vout.pf_destroy    = vout_Destroy;
+    p_function_list->functions.vout.pf_manage     = vout_Manage;
+    p_function_list->functions.vout.pf_render     = vout_Render;
+    p_function_list->functions.vout.pf_display    = vout_Display;
+}
+
+/*****************************************************************************
+ * vout_Probe: probe the video driver and return a score
+ *****************************************************************************
+ * This function tries to initialize SDL and returns a score to the
+ * plugin manager so that it can select the best plugin.
+ *****************************************************************************/
+static int vout_Probe( probedata_t *p_data )
+{
+    Display *p_display;                                   /* display pointer */
+    char    *psz_display;
+#ifdef MODULE_NAME_IS_xvideo
+    int      i_xvport, i_dummy;
+#endif
+
+    /* Open display, unsing 'vlc_display' or DISPLAY environment variable */
+    psz_display = XDisplayName( main_GetPszVariable(VOUT_DISPLAY_VAR, NULL) );
+    p_display = XOpenDisplay( psz_display );
+    if( p_display == NULL )                                         /* error */
+    {
+        intf_WarnMsg( 3, "vout: cannot open display %s", psz_display );
+        return( 0 );
+    }
+
+#ifdef MODULE_NAME_IS_xvideo
+    /* Check that there is an available XVideo port for this format */
+    i_xvport = XVideoGetPort( p_display, p_data->vout.i_chroma, &i_dummy );
+    if( i_xvport < 0 )
+    {
+        /* It failed, but it's not completely lost ! We try to open an
+         * XVideo port for a YUY2 picture */
+        i_xvport = XVideoGetPort( p_display, FOURCC_YUY2, &i_dummy );
+        if( i_xvport < 0 )
+        {
+            /* It failed, but it's not completely lost ! We try to open an
+             * XVideo port for a simple 16bpp RGB picture */
+            i_xvport = XVideoGetPort( p_display, FOURCC_RV16, &i_dummy );
+            if( i_xvport < 0 )
+            {
+                XCloseDisplay( p_display );
+                return( 0 );
+            }
+        }
+    }
+    XVideoReleasePort( p_display, i_xvport );
+#endif
+
+    /* Clean-up everyting */
+    XCloseDisplay( p_display );
+
+#ifdef MODULE_NAME_IS_xvideo 
+    return( 150 );
+#else
+    return( 50 );
+#endif
+}
+
+/*****************************************************************************
+ * vout_Create: allocate X11 video thread output method
+ *****************************************************************************
+ * This function allocate and initialize a X11 vout method. It uses some of the
+ * vout properties to choose the window size, and change them according to the
+ * actual properties of the display.
+ *****************************************************************************/
+static int vout_Create( vout_thread_t *p_vout )
+{
+    char *psz_display;
+
+    /* Allocate structure */
+    p_vout->p_sys = malloc( sizeof( vout_sys_t ) );
+    if( p_vout->p_sys == NULL )
+    {
+        intf_ErrMsg( "vout error: %s", strerror(ENOMEM) );
+        return( 1 );
+    }
+
+    /* Open display, unsing 'vlc_display' or DISPLAY environment variable */
+    psz_display = XDisplayName( main_GetPszVariable( VOUT_DISPLAY_VAR, NULL ) );
+    p_vout->p_sys->p_display = XOpenDisplay( psz_display );
+
+    if( p_vout->p_sys->p_display == NULL )                          /* error */
+    {
+        intf_ErrMsg( "vout error: cannot open display %s", psz_display );
+        free( p_vout->p_sys );
+        return( 1 );
+    }
+    p_vout->p_sys->i_screen = DefaultScreen( p_vout->p_sys->p_display );
+
+    /* Create blank cursor (for mouse cursor autohiding) */
+    p_vout->p_sys->b_mouse_pointer_visible = 1;
+    CreateCursor( p_vout );
+
+    /* Spawn base window - this window will include the video output window,
+     * but also command buttons, subtitles and other indicators */
+    if( CreateWindow( p_vout ) )
+    {
+        intf_ErrMsg( "vout error: cannot create X11 window" );
+        DestroyCursor( p_vout );
+        XCloseDisplay( p_vout->p_sys->p_display );
+        free( p_vout->p_sys );
+        return( 1 );
+    }
+
+    /* Disable screen saver and return */
+    DisableXScreenSaver( p_vout );
+
+    return( 0 );
+}
+
+/*****************************************************************************
+ * vout_Destroy: destroy X11 video thread output method
+ *****************************************************************************
+ * Terminate an output method created by vout_CreateOutputMethod
+ *****************************************************************************/
+static void vout_Destroy( vout_thread_t *p_vout )
+{
+    /* Restore cursor if it was blanked */
+    if( !p_vout->p_sys->b_mouse_pointer_visible )
+    {
+        ToggleCursor( p_vout );
+    }
+
+    DestroyCursor( p_vout );
+    EnableXScreenSaver( p_vout );
+    DestroyWindow( p_vout );
+
+    XCloseDisplay( p_vout->p_sys->p_display );
+
+    /* Destroy structure */
+    free( p_vout->p_sys );
+}
+
+/*****************************************************************************
+ * vout_Init: initialize X11 video thread output method
+ *****************************************************************************
+ * This function create the XImages needed by the output thread. It is called
+ * at the beginning of the thread, but also each time the window is resized.
+ *****************************************************************************/
+static int vout_Init( vout_thread_t *p_vout )
+{
+    int i_index;
+    picture_t *p_pic;
+
+    I_OUTPUTPICTURES = 0;
+
+#ifdef MODULE_NAME_IS_xvideo
+    /* Initialize the output structure; we already found an XVideo port,
+     * and the corresponding chroma we will be using. Since we can
+     * arbitrary scale, stick to the coordinates and aspect. */
+    p_vout->output.i_width  = p_vout->render.i_width;
+    p_vout->output.i_height = p_vout->render.i_height;
+    p_vout->output.i_aspect = p_vout->render.i_aspect;
+
+#else
+    /* Initialize the output structure: RGB with square pixels, whatever
+     * the input format is, since it's the only format we know */
+    switch( p_vout->p_sys->i_screen_depth )
+    {
+        case 8: /* FIXME: set the palette */
+            p_vout->output.i_chroma = FOURCC_BI_RGB; break;
+        case 15:
+            p_vout->output.i_chroma = FOURCC_RV15; break;
+        case 16:
+            p_vout->output.i_chroma = FOURCC_RV16; break;
+        case 24:
+            p_vout->output.i_chroma = FOURCC_BI_BITFIELDS; break;
+        case 32:
+            p_vout->output.i_chroma = FOURCC_BI_BITFIELDS; break;
+        default:
+            intf_ErrMsg( "vout error: unknown screen depth" );
+            return( 0 );
+    }
+
+    p_vout->output.i_width = p_vout->p_sys->i_width;
+    p_vout->output.i_height = p_vout->p_sys->i_height;
+
+    /* Assume we have square pixels */
+    p_vout->output.i_aspect = p_vout->p_sys->i_width
+                               * VOUT_ASPECT_FACTOR / p_vout->p_sys->i_height;
+#endif
+
+    /* Try to initialize up to MAX_DIRECTBUFFERS direct buffers */
+    while( I_OUTPUTPICTURES < MAX_DIRECTBUFFERS )
+    {
+        p_pic = NULL;
+
+        /* Find an empty picture slot */
+        for( i_index = 0 ; i_index < VOUT_MAX_PICTURES ; i_index++ )
+        {
+            if( p_vout->p_picture[ i_index ].i_status == FREE_PICTURE )
+            {
+                p_pic = p_vout->p_picture + i_index;
+                break;
+            }
+        }
+
+        /* Allocate the picture */
+        if( p_pic == NULL || NewPicture( p_vout, p_pic ) )
+        {
+            break;
+        }
+
+        p_pic->i_status = DESTROYED_PICTURE;
+        p_pic->i_type   = DIRECT_PICTURE;
+
+        PP_OUTPUTPICTURE[ I_OUTPUTPICTURES ] = p_pic;
+
+        I_OUTPUTPICTURES++;
+    }
+
+    return( 0 );
+}
+
+/*****************************************************************************
+ * vout_Render: render previously calculated output
+ *****************************************************************************/
+static void vout_Render( vout_thread_t *p_vout, picture_t *p_pic )
+{
+    ;
+}
+
+ /*****************************************************************************
+ * vout_Display: displays previously rendered output
+ *****************************************************************************
+ * This function sends the currently rendered image to X11 server.
+ * (The Xv extension takes care of "double-buffering".)
+ *****************************************************************************/
+static void vout_Display( vout_thread_t *p_vout, picture_t *p_pic )
+{
+    int i_width, i_height, i_x, i_y;
+
+    vout_PlacePicture( p_vout, p_vout->p_sys->i_width, p_vout->p_sys->i_height,
+                       &i_x, &i_y, &i_width, &i_height );
+}
+
+/*****************************************************************************
+ * vout_Manage: handle X11 events
+ *****************************************************************************
+ * This function should be called regularly by video output thread. It manages
+ * X11 events and allows window resizing. It returns a non null value on
+ * error.
+ *****************************************************************************/
+static int vout_Manage( vout_thread_t *p_vout )
+{
+    XEvent      xevent;                                         /* X11 event */
+    boolean_t   b_resized;                        /* window has been resized */
+    char        i_key;                                    /* ISO Latin-1 key */
+    KeySym      x_key_symbol;
+
+    /* Handle X11 events: ConfigureNotify events are parsed to know if the
+     * output window's size changed, MapNotify and UnmapNotify to know if the
+     * window is mapped (and if the display is useful), and ClientMessages
+     * to intercept window destruction requests */
+
+    b_resized = 0;
+    while( XCheckWindowEvent( p_vout->p_sys->p_display, p_vout->p_sys->window,
+                              StructureNotifyMask | KeyPressMask |
+                              ButtonPressMask | ButtonReleaseMask | 
+                              PointerMotionMask | Button1MotionMask , &xevent )
+           == True )
+    {
+        /* ConfigureNotify event: prepare  */
+        if( (xevent.type == ConfigureNotify)
+          && ((xevent.xconfigure.width != p_vout->p_sys->i_width)
+             || (xevent.xconfigure.height != p_vout->p_sys->i_height)) )
+        {
+            /* Update dimensions */
+            b_resized = 1;
+            p_vout->i_changes |= VOUT_SIZE_CHANGE;
+            p_vout->p_sys->i_width = xevent.xconfigure.width;
+            p_vout->p_sys->i_height = xevent.xconfigure.height;
+        }
+        /* MapNotify event: change window status and disable screen saver */
+        else if( xevent.type == MapNotify)
+        {
+            if( (p_vout != NULL) && !p_vout->b_active )
+            {
+                DisableXScreenSaver( p_vout );
+                p_vout->b_active = 1;
+            }
+        }
+        /* UnmapNotify event: change window status and enable screen saver */
+        else if( xevent.type == UnmapNotify )
+        {
+            if( (p_vout != NULL) && p_vout->b_active )
+            {
+                EnableXScreenSaver( p_vout );
+                p_vout->b_active = 0;
+            }
+        }
+        /* Keyboard event */
+        else if( xevent.type == KeyPress )
+        {
+            /* We may have keys like F1 trough F12, ESC ... */
+            x_key_symbol = XKeycodeToKeysym( p_vout->p_sys->p_display,
+                                             xevent.xkey.keycode, 0 );
+            switch( x_key_symbol )
+            {
+                 case XK_Escape:
+                     p_main->p_intf->b_die = 1;
+                     break;
+                 case XK_Menu:
+                     p_main->p_intf->b_menu_change = 1;
+                     break;
+                 case XK_Left:
+                     vout_Seek( -5 );
+                     break;
+                 case XK_Right:
+                     vout_Seek( 5 );
+                     break;
+                 case XK_Up:
+                     vout_Seek( 60 );
+                     break;
+                 case XK_Down:
+                     vout_Seek( -60 );
+                     break;
+                 case XK_Home:
+                     input_Seek( p_input_bank->pp_input[0],
+                     p_input_bank->pp_input[0]->stream.p_selected_area->i_start );
+                     break;
+                 case XK_End:
+                     input_Seek( p_input_bank->pp_input[0],
+                     p_input_bank->pp_input[0]->stream.p_selected_area->i_size );
+                     break;
+                 case XK_Page_Up:
+                     vout_Seek( 900 );
+                     break;
+                 case XK_Page_Down:
+                     vout_Seek( -900 );
+                     break;
+                 case XK_space:
+                     input_SetStatus( p_input_bank->pp_input[0],
+                                      INPUT_STATUS_PAUSE );
+                     break;
+
+                 default:
+                     /* "Normal Keys"
+                      * The reason why I use this instead of XK_0 is that 
+                      * with XLookupString, we don't have to care about
+                      * keymaps. */
+
+                    if( XLookupString( &xevent.xkey, &i_key, 1, NULL, NULL ) )
+                    {
+                        /* FIXME: handle stuff here */
+                        switch( i_key )
+                        {
+                        case 'q':
+                        case 'Q':
+                            p_main->p_intf->b_die = 1;
+                            break;
+                        case 'f':
+                        case 'F':
+                            p_vout->i_changes |= VOUT_FULLSCREEN_CHANGE;
+                            break;
+
+                        case '0': network_ChannelJoin( 0 ); break;
+                        case '1': network_ChannelJoin( 1 ); break;
+                        case '2': network_ChannelJoin( 2 ); break;
+                        case '3': network_ChannelJoin( 3 ); break;
+                        case '4': network_ChannelJoin( 4 ); break;
+                        case '5': network_ChannelJoin( 5 ); break;
+                        case '6': network_ChannelJoin( 6 ); break;
+                        case '7': network_ChannelJoin( 7 ); break;
+                        case '8': network_ChannelJoin( 8 ); break;
+                        case '9': network_ChannelJoin( 9 ); break;
+
+                        default:
+                            intf_DbgMsg( "vout: unhandled key '%c' (%i)", 
+                                         (char)i_key, i_key );
+                            break;
+                        }
+                    }
+                break;
+            }
+        }
+        /* Mouse click */
+        else if( xevent.type == ButtonPress )
+        {
+            switch( ((XButtonEvent *)&xevent)->button )
+            {
+                case Button1:
+                    /* In this part we will eventually manage
+                     * clicks for DVD navigation for instance. For the
+                     * moment just pause the stream. */
+                    input_SetStatus( p_input_bank->pp_input[0],
+                                     INPUT_STATUS_PAUSE );
+                    break;
+
+                case Button4:
+                    vout_Seek( 15 );
+                    break;
+
+                case Button5:
+                    vout_Seek( -15 );
+                    break;
+            }
+        }
+        /* Mouse release */
+        else if( xevent.type == ButtonRelease )
+        {
+            switch( ((XButtonEvent *)&xevent)->button )
+            {
+                case Button3:
+                    /* FIXME: need locking ! */
+                    p_main->p_intf->b_menu_change = 1;
+                    break;
+            }
+        }
+        /* Mouse move */
+        else if( xevent.type == MotionNotify )
+        {
+            p_vout->p_sys->i_time_mouse_last_moved = mdate();
+            if( ! p_vout->p_sys->b_mouse_pointer_visible )
+            {
+                ToggleCursor( p_vout ); 
+            }
+        }
+        /* Other event */
+        else
+        {
+            intf_WarnMsg( 3, "vout: unhandled event %d received", xevent.type );
+        }
+    }
+
+    /* ClientMessage event - only WM_PROTOCOLS with WM_DELETE_WINDOW data
+     * are handled - according to the man pages, the format is always 32
+     * in this case */
+    while( XCheckTypedEvent( p_vout->p_sys->p_display,
+                             ClientMessage, &xevent ) )
+    {
+        if( (xevent.xclient.message_type == p_vout->p_sys->wm_protocols)
+            && (xevent.xclient.data.l[0] == p_vout->p_sys->wm_delete_window ) )
+        {
+            p_main->p_intf->b_die = 1;
+        }
+        else
+        {
+            intf_DbgMsg( "vout: unhandled ClientMessage received" );
+        }
+    }
+
+    /*
+     * Fullscreen Change
+     */
+    if ( p_vout->i_changes & VOUT_FULLSCREEN_CHANGE )
+    {
+        ToggleFullScreen( p_vout );
+        p_vout->i_changes &= ~VOUT_FULLSCREEN_CHANGE;
+
+    }
+
+    /*
+     * Size change
+     */
+    if( p_vout->i_changes & VOUT_SIZE_CHANGE )
+    {
+        int i_width, i_height, i_x, i_y;
+
+        p_vout->i_changes &= ~VOUT_SIZE_CHANGE;
+
+        intf_WarnMsg( 3, "vout: video display resized (%dx%d)",
+                      p_vout->p_sys->i_width,
+                      p_vout->p_sys->i_height );
+        vout_PlacePicture( p_vout, p_vout->p_sys->i_width,
+                           p_vout->p_sys->i_height,
+                           &i_x, &i_y, &i_width, &i_height );
+    }
+
+    /* Autohide Cursour */
+    if( mdate() - p_vout->p_sys->i_time_mouse_last_moved > 2000000 )
+    {
+        /* Hide the mouse automatically */
+        if( p_vout->p_sys->b_mouse_pointer_visible )
+        {
+            ToggleCursor( p_vout ); 
+        }
+    }
+
+    return 0;
+}
+
+/*****************************************************************************
+ * vout_End: terminate X11 video thread output method
+ *****************************************************************************
+ * Destroy the X11 XImages created by vout_Init. It is called at the end of
+ * the thread, but also each time the window is resized.
+ *****************************************************************************/
+static void vout_End( vout_thread_t *p_vout )
+{
+    int i_index;
+
+    /* Free the direct buffers we allocated */
+    for( i_index = I_OUTPUTPICTURES ; i_index ; )
+    {
+        i_index--;
+        FreePicture( p_vout, PP_OUTPUTPICTURE[ i_index ] );
+    }
+}
+
+/* following functions are local */
+
+/*****************************************************************************
+ * CreateWindow: open and set-up X11 main window
+ *****************************************************************************/
+static int CreateWindow( vout_thread_t *p_vout )
+{
+    XSizeHints              xsize_hints;
+    XSetWindowAttributes    xwindow_attributes;
+    XGCValues               xgcvalues;
+    XEvent                  xevent;
+
+    boolean_t               b_expose;
+    boolean_t               b_configure_notify;
+    boolean_t               b_map_notify;
+
+    /* Set main window's size */
+    if( p_vout->render.i_height * p_vout->render.i_aspect
+        >= p_vout->render.i_width * VOUT_ASPECT_FACTOR )
+    {
+        p_vout->p_sys->i_width = p_vout->render.i_height
+          * p_vout->render.i_aspect / VOUT_ASPECT_FACTOR;
+        p_vout->p_sys->i_height = p_vout->render.i_height;
+    }
+    else
+    {
+        p_vout->p_sys->i_width = p_vout->render.i_width;
+        p_vout->p_sys->i_height = p_vout->render.i_width
+          * VOUT_ASPECT_FACTOR / p_vout->render.i_aspect;
+    }
+
+#if 0
+    if( p_vout->p_sys->i_width <= 300 && p_vout->p_sys->i_height <= 300 )
+    {
+        p_vout->p_sys->i_width <<= 1;
+        p_vout->p_sys->i_height <<= 1;
+    }
+    else if( p_vout->p_sys->i_width <= 400
+             && p_vout->p_sys->i_height <= 400 )
+    {
+        p_vout->p_sys->i_width += p_vout->p_sys->i_width >> 1;
+        p_vout->p_sys->i_height += p_vout->p_sys->i_height >> 1;
+    }
+#endif
+
+    /* Prepare window manager hints and properties */
+    xsize_hints.base_width          = p_vout->p_sys->i_width;
+    xsize_hints.base_height         = p_vout->p_sys->i_height;
+    xsize_hints.flags               = PSize;
+    p_vout->p_sys->wm_protocols     = XInternAtom( p_vout->p_sys->p_display,
+                                                   "WM_PROTOCOLS", True );
+    p_vout->p_sys->wm_delete_window = XInternAtom( p_vout->p_sys->p_display,
+                                                   "WM_DELETE_WINDOW", True );
+
+    /* Prepare window attributes */
+    xwindow_attributes.backing_store = Always;       /* save the hidden part */
+    xwindow_attributes.background_pixel = BlackPixel(p_vout->p_sys->p_display,
+                                                     p_vout->p_sys->i_screen);
+    xwindow_attributes.event_mask = ExposureMask | StructureNotifyMask;
+    
+
+    /* Create the window and set hints - the window must receive
+     * ConfigureNotify events, and until it is displayed, Expose and
+     * MapNotify events. */
+
+    p_vout->p_sys->window =
+        XCreateWindow( p_vout->p_sys->p_display,
+                       DefaultRootWindow( p_vout->p_sys->p_display ),
+                       0, 0,
+                       p_vout->p_sys->i_width,
+                       p_vout->p_sys->i_height,
+                       0,
+                       0, InputOutput, 0,
+                       CWBackingStore | CWBackPixel | CWEventMask,
+                       &xwindow_attributes );
+
+    /* Set window manager hints and properties: size hints, command,
+     * window's name, and accepted protocols */
+    XSetWMNormalHints( p_vout->p_sys->p_display, p_vout->p_sys->window,
+                       &xsize_hints );
+    XSetCommand( p_vout->p_sys->p_display, p_vout->p_sys->window,
+                 p_main->ppsz_argv, p_main->i_argc );
+    XStoreName( p_vout->p_sys->p_display, p_vout->p_sys->window,
+                VOUT_TITLE " (XMGA output)"
+              );
+
+    if( (p_vout->p_sys->wm_protocols == None)        /* use WM_DELETE_WINDOW */
+        || (p_vout->p_sys->wm_delete_window == None)
+        || !XSetWMProtocols( p_vout->p_sys->p_display, p_vout->p_sys->window,
+                             &p_vout->p_sys->wm_delete_window, 1 ) )
+    {
+        /* WM_DELETE_WINDOW is not supported by window manager */
+        intf_Msg( "vout error: missing or bad window manager" );
+    } 
+
+    /* Creation of a graphic context that doesn't generate a GraphicsExpose
+     * event when using functions like XCopyArea */
+    xgcvalues.graphics_exposures = False;
+    p_vout->p_sys->gc = XCreateGC( p_vout->p_sys->p_display,
+                                   p_vout->p_sys->window,
+                                   GCGraphicsExposures, &xgcvalues);
+
+    /* Send orders to server, and wait until window is displayed - three
+     * events must be received: a MapNotify event, an Expose event allowing
+     * drawing in the window, and a ConfigureNotify to get the window
+     * dimensions. Once those events have been received, only ConfigureNotify
+     * events need to be received. */
+    b_expose = 0;
+    b_configure_notify = 0;
+    b_map_notify = 0;
+    XMapWindow( p_vout->p_sys->p_display, p_vout->p_sys->window);
+    do
+    {
+        XNextEvent( p_vout->p_sys->p_display, &xevent);
+        if( (xevent.type == Expose)
+            && (xevent.xexpose.window == p_vout->p_sys->window) )
+        {
+            b_expose = 1;
+        }
+        else if( (xevent.type == MapNotify)
+                 && (xevent.xmap.window == p_vout->p_sys->window) )
+        {
+            b_map_notify = 1;
+        }
+        else if( (xevent.type == ConfigureNotify)
+                 && (xevent.xconfigure.window == p_vout->p_sys->window) )
+        {
+            b_configure_notify = 1;
+            p_vout->p_sys->i_width = xevent.xconfigure.width;
+            p_vout->p_sys->i_height = xevent.xconfigure.height;
+        }
+    } while( !( b_expose && b_configure_notify && b_map_notify ) );
+
+    XSelectInput( p_vout->p_sys->p_display, p_vout->p_sys->window,
+                  StructureNotifyMask | KeyPressMask |
+                  ButtonPressMask | ButtonReleaseMask | 
+                  PointerMotionMask );
+
+    /* If the cursor was formerly blank than blank it again */
+    if( !p_vout->p_sys->b_mouse_pointer_visible )
+    {
+        ToggleCursor( p_vout );
+        ToggleCursor( p_vout );
+    }
+
+    XSync( p_vout->p_sys->p_display, False );
+
+    /* At this stage, the window is open, displayed, and ready to
+     * receive data */
+
+    return( 0 );
+}
+
+/*****************************************************************************
+ * DestroyWindow: destroy the window
+ *****************************************************************************
+ *
+ *****************************************************************************/
+static void DestroyWindow( vout_thread_t *p_vout )
+{
+    XSync( p_vout->p_sys->p_display, False );
+
+    XUnmapWindow( p_vout->p_sys->p_display, p_vout->p_sys->window );
+    XFreeGC( p_vout->p_sys->p_display, p_vout->p_sys->gc );
+    XDestroyWindow( p_vout->p_sys->p_display, p_vout->p_sys->window );
+}
+
+/*****************************************************************************
+ * NewPicture: allocate a picture
+ *****************************************************************************
+ * Returns 0 on success, -1 otherwise
+ *****************************************************************************/
+static int NewPicture( vout_thread_t *p_vout, picture_t *p_pic )
+{
+    /* We know the chroma, allocate a buffer which will be used
+     * directly by the decoder */
+    p_pic->p_sys = malloc( sizeof( picture_sys_t ) );
+
+    if( p_pic->p_sys == NULL )
+    {
+        return -1;
+    }
+
+    /* XXX */
+
+    switch( p_vout->output.i_chroma )
+    {
+        /* XXX ?? */
+
+        default:
+            /* Unknown chroma, tell the guy to get lost */
+            free( p_pic->p_sys );
+            intf_ErrMsg( "vout error: never heard of chroma 0x%.8x (%4.4s)",
+                         p_vout->output.i_chroma,
+                         (char*)&p_vout->output.i_chroma );
+            p_pic->i_planes = 0;
+            return -1;
+    }
+
+    return 0;
+}
+
+/*****************************************************************************
+ * FreePicture: destroy a picture allocated with NewPicture
+ *****************************************************************************
+ * Destroy XImage AND associated data. If using Shm, detach shared memory
+ * segment from server and process, then free it. The XDestroyImage manpage
+ * says that both the image structure _and_ the data pointed to by the
+ * image structure are freed, so no need to free p_image->data.
+ *****************************************************************************/
+static void FreePicture( vout_thread_t *p_vout, picture_t *p_pic )
+{
+
+    XSync( p_vout->p_sys->p_display, False );
+
+    free( p_pic->p_sys );
+}
+
+/*****************************************************************************
+ * ToggleFullScreen: Enable or disable full screen mode
+ *****************************************************************************
+ * This function will switch between fullscreen and window mode.
+ *
+ *****************************************************************************/
+static void ToggleFullScreen ( vout_thread_t *p_vout )
+{
+  Atom prop;
+  mwmhints_t mwmhints;
+  int i_xpos, i_ypos, i_width, i_height;
+
+  p_vout->b_fullscreen = !p_vout->b_fullscreen;
+
+  if( p_vout->b_fullscreen )
+  {
+      Window next_parent, parent, *p_dummy, dummy1;
+      unsigned int dummy2, dummy3;
+     
+      intf_WarnMsg( 3, "vout: entering fullscreen mode" );
+
+      /* Save current window coordinates so they can be restored when
+       * we exit from fullscreen mode */
+
+      /* find the real parent, which means the which is a direct child of
+       * the root window */
+      next_parent = parent = p_vout->p_sys->window;
+      while( next_parent != DefaultRootWindow( p_vout->p_sys->p_display ) )
+      {
+          parent = next_parent;
+          XQueryTree( p_vout->p_sys->p_display,
+                      parent,
+                      &dummy1,
+                      &next_parent,
+                      &p_dummy,
+                      &dummy2 );
+          XFree((void *)p_dummy);
+      }
+
+      XGetGeometry( p_vout->p_sys->p_display,
+                    p_vout->p_sys->window,
+                    &dummy1,
+                    &dummy2,
+                    &dummy3,
+                    &p_vout->p_sys->i_width_backup,
+                    &p_vout->p_sys->i_height_backup,
+                    &dummy2, &dummy3 );
+
+      XTranslateCoordinates( p_vout->p_sys->p_display,
+                             parent,
+                             DefaultRootWindow( p_vout->p_sys->p_display ),
+                             0,
+                             0,
+                             &p_vout->p_sys->i_xpos_backup,
+                             &p_vout->p_sys->i_ypos_backup,
+                             &dummy1 );
+
+      mwmhints.flags = MWM_HINTS_DECORATIONS;
+      mwmhints.decorations = 0;
+
+      i_xpos = 0;
+      i_ypos = 0;
+      i_width = DisplayWidth( p_vout->p_sys->p_display,
+                              p_vout->p_sys->i_screen );
+      i_height = DisplayHeight( p_vout->p_sys->p_display,
+                                p_vout->p_sys->i_screen );
+
+#if 0
+      /* Being a transient window allows us to really be fullscreen (display
+       * over the taskbar for instance) but then we end-up with the same
+       * result as with the brute force method */
+      XSetTransientForHint( p_vout->p_sys->p_display,
+                            p_vout->p_sys->window, None );
+#endif
+  }
+  else
+  {
+      intf_WarnMsg( 3, "vout: leaving fullscreen mode" );
+      
+      mwmhints.flags = MWM_HINTS_DECORATIONS;
+      mwmhints.decorations = 1;
+
+      i_xpos = p_vout->p_sys->i_xpos_backup;
+      i_ypos = p_vout->p_sys->i_ypos_backup;
+      i_width = p_vout->p_sys->i_width_backup;
+      i_height = p_vout->p_sys->i_height_backup;
+  }
+
+  /* To my knowledge there are two ways to create a borderless window.
+   * There's the generic way which is to tell x to bypass the window manager,
+   * but this creates problems with the focus of other applications.
+   * The other way is to use the motif property "_MOTIF_WM_HINTS" which
+   * luckily seems to be supported by most window managers.
+   */
+  prop = XInternAtom( p_vout->p_sys->p_display, "_MOTIF_WM_HINTS",
+                      False );
+  XChangeProperty( p_vout->p_sys->p_display, p_vout->p_sys->window,
+                   prop, prop, 32, PropModeReplace,
+                   (unsigned char *)&mwmhints,
+                   PROP_MWM_HINTS_ELEMENTS );
+#if 0 /* brute force way to remove decorations */
+  XSetWindowAttributes attributes;
+  attributes.override_redirect = True;
+  XChangeWindowAttributes( p_vout->p_sys->p_display,
+                           p_vout->p_sys->window,
+                           CWOverrideRedirect,
+                           &attributes);
+#endif
+
+  /* We need to unmap and remap the window if we want the window 
+   * manager to take our changes into effect */
+  XUnmapWindow( p_vout->p_sys->p_display, p_vout->p_sys->window);
+  XMapRaised( p_vout->p_sys->p_display, p_vout->p_sys->window);
+  XMoveResizeWindow( p_vout->p_sys->p_display,
+                     p_vout->p_sys->window,
+                     i_xpos,
+                     i_ypos,
+                     i_width,
+                     i_height );
+  XFlush( p_vout->p_sys->p_display );
+}
+
+/*****************************************************************************
+ * EnableXScreenSaver: enable screen saver
+ *****************************************************************************
+ * This function enables the screen saver on a display after it has been
+ * disabled by XDisableScreenSaver.
+ * FIXME: what happens if multiple vlc sessions are running at the same
+ *        time ???
+ *****************************************************************************/
+static void EnableXScreenSaver( vout_thread_t *p_vout )
+{
+    int dummy;
+
+    intf_DbgMsg( "vout: enabling screen saver" );
+    XSetScreenSaver( p_vout->p_sys->p_display, p_vout->p_sys->i_ss_timeout,
+                     p_vout->p_sys->i_ss_interval,
+                     p_vout->p_sys->i_ss_blanking,
+                     p_vout->p_sys->i_ss_exposure );
+
+    /* Restore DPMS settings */
+    if( DPMSQueryExtension( p_vout->p_sys->p_display, &dummy, &dummy ) )
+    {
+        if( p_vout->p_sys->b_ss_dpms )
+        {
+            DPMSEnable( p_vout->p_sys->p_display );
+        }
+    }
+}
+
+/*****************************************************************************
+ * DisableXScreenSaver: disable screen saver
+ *****************************************************************************
+ * See XEnableXScreenSaver
+ *****************************************************************************/
+static void DisableXScreenSaver( vout_thread_t *p_vout )
+{
+    int dummy;
+
+    /* Save screen saver informations */
+    XGetScreenSaver( p_vout->p_sys->p_display, &p_vout->p_sys->i_ss_timeout,
+                     &p_vout->p_sys->i_ss_interval,
+                     &p_vout->p_sys->i_ss_blanking,
+                     &p_vout->p_sys->i_ss_exposure );
+
+    /* Disable screen saver */
+    intf_DbgMsg( "vout: disabling screen saver" );
+    XSetScreenSaver( p_vout->p_sys->p_display, 0,
+                     p_vout->p_sys->i_ss_interval,
+                     p_vout->p_sys->i_ss_blanking,
+                     p_vout->p_sys->i_ss_exposure );
+
+    /* Disable DPMS */
+    if( DPMSQueryExtension( p_vout->p_sys->p_display, &dummy, &dummy ) )
+    {
+        CARD16 dummy;
+        /* Save DPMS current state */
+        DPMSInfo( p_vout->p_sys->p_display, &dummy,
+                  &p_vout->p_sys->b_ss_dpms );
+        intf_DbgMsg( "vout: disabling DPMS" );
+        DPMSDisable( p_vout->p_sys->p_display );
+   }
+}
+
+/*****************************************************************************
+ * CreateCursor: create a blank mouse pointer
+ *****************************************************************************/
+static void CreateCursor( vout_thread_t *p_vout )
+{
+    XColor cursor_color;
+
+    p_vout->p_sys->cursor_pixmap =
+        XCreatePixmap( p_vout->p_sys->p_display,
+                       DefaultRootWindow( p_vout->p_sys->p_display ),
+                       1, 1, 1 );
+
+    XParseColor( p_vout->p_sys->p_display,
+                 XCreateColormap( p_vout->p_sys->p_display,
+                                  DefaultRootWindow(
+                                                    p_vout->p_sys->p_display ),
+                                  DefaultVisual(
+                                                p_vout->p_sys->p_display,
+                                                p_vout->p_sys->i_screen ),
+                                  AllocNone ),
+                 "black", &cursor_color );
+
+    p_vout->p_sys->blank_cursor =
+        XCreatePixmapCursor( p_vout->p_sys->p_display,
+                             p_vout->p_sys->cursor_pixmap,
+                             p_vout->p_sys->cursor_pixmap,
+                             &cursor_color, &cursor_color, 1, 1 );
+}
+
+/*****************************************************************************
+ * DestroyCursor: destroy the blank mouse pointer
+ *****************************************************************************/
+static void DestroyCursor( vout_thread_t *p_vout )
+{
+    XFreePixmap( p_vout->p_sys->p_display, p_vout->p_sys->cursor_pixmap );
+}
+
+/*****************************************************************************
+ * ToggleCursor: hide or show the mouse pointer
+ *****************************************************************************
+ * This function hides the X pointer if it is visible by setting the pointer
+ * sprite to a blank one. To show it again, we disable the sprite.
+ *****************************************************************************/
+static void ToggleCursor( vout_thread_t *p_vout )
+{
+    if( p_vout->p_sys->b_mouse_pointer_visible )
+    {
+        XDefineCursor( p_vout->p_sys->p_display,
+                       p_vout->p_sys->window,
+                       p_vout->p_sys->blank_cursor );
+        p_vout->p_sys->b_mouse_pointer_visible = 0;
+    }
+    else
+    {
+        XUndefineCursor( p_vout->p_sys->p_display, p_vout->p_sys->window );
+        p_vout->p_sys->b_mouse_pointer_visible = 1;
+    }
+}
+
index d84a262618ca9fedef9209cae9ea40562a3248f1..207c598b04670ff48cfc7bad511229036e145089 100644 (file)
@@ -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 <massiot@via.ecp.fr>
  *
@@ -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;
 }
 
 /*****************************************************************************
index d36ba3b27b44d31371b3e998592c556ed0396688..dc78d91f749e0a23b2c8f9d2324aac018f30a9a3 100644 (file)
@@ -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 <seguin@via.ecp.fr>
  *
@@ -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 (file)
index 0000000..8111436
--- /dev/null
@@ -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 <jb@technologeek.org> for the Linux part
+ *               with code taken from the Linux "eject" command
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
+ *****************************************************************************/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+
+#include <videolan/vlc.h>
+
+#ifdef SYS_LINUX
+
+/* This code could be extended to support CD/DVD-ROM chargers */
+#   include <linux/version.h>
+    /* handy macro found in 2.1 kernels, but not in older ones */
+#   ifndef KERNEL_VERSION
+#       define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c))
+#   endif
+
+#   include <sys/types.h>
+#   include <sys/stat.h>
+#   include <sys/ioctl.h>
+#   include <fcntl.h>
+
+#   include <sys/ioctl.h>
+#   include <linux/cdrom.h>
+#   if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,0)
+#       include <linux/ucdrom.h>
+#   endif
+
+#   include <sys/mount.h>
+#   include <scsi/scsi.h>
+#   include <scsi/sg.h>
+#   include <scsi/scsi_ioctl.h>
+
+#endif
+
+static int EjectCdrom( int i_fd );
+static int EjectScsi ( int i_fd );
+
+/*
+ * Eject using CDROMEJECT ioctl. Return 0 if successful
+ */
+static int EjectCdrom( int i_fd )
+{
+    int i_status;
+  
+    i_status = ioctl( i_fd, CDROMEJECT );
+  
+    return i_status;
+}
+
+
+/*
+ * Eject using SCSI commands. Return 0 if successful
+ */
+static int EjectScsi( int i_fd )
+{
+    int i_status;
+
+    struct sdata
+    {
+        int  inlen;
+        int  outlen;
+        char cmd[256];
+    } scsi_cmd;
+
+    scsi_cmd.inlen  = 0;
+    scsi_cmd.outlen = 0;
+    scsi_cmd.cmd[0] = ALLOW_MEDIUM_REMOVAL;
+    scsi_cmd.cmd[1] = 0;
+    scsi_cmd.cmd[2] = 0;
+    scsi_cmd.cmd[3] = 0;
+    scsi_cmd.cmd[4] = 0;
+    scsi_cmd.cmd[5] = 0;
+    i_status = ioctl( i_fd, SCSI_IOCTL_SEND_COMMAND, (void *)&scsi_cmd );
+    if( i_status != 0 )
+    {
+        return 1;
+    }
+
+    scsi_cmd.inlen  = 0;
+    scsi_cmd.outlen = 0;
+    scsi_cmd.cmd[0] = START_STOP;
+    scsi_cmd.cmd[1] = 0;
+    scsi_cmd.cmd[2] = 0;
+    scsi_cmd.cmd[3] = 0;
+    scsi_cmd.cmd[4] = 1;
+    scsi_cmd.cmd[5] = 0;
+    i_status = ioctl( i_fd, SCSI_IOCTL_SEND_COMMAND, (void *)&scsi_cmd );
+    if( i_status != 0 )
+    {
+        return 1;
+    }
+  
+    scsi_cmd.inlen  = 0;
+    scsi_cmd.outlen = 0;
+    scsi_cmd.cmd[0] = START_STOP;
+    scsi_cmd.cmd[1] = 0;
+    scsi_cmd.cmd[2] = 0;
+    scsi_cmd.cmd[3] = 0;
+    scsi_cmd.cmd[4] = 2;
+    scsi_cmd.cmd[5] = 0;
+    i_status = ioctl( i_fd, SCSI_IOCTL_SEND_COMMAND, (void *)&scsi_cmd );
+    if( i_status != 0 )
+    {
+        return 1;
+    }
+  
+    /* Force kernel to reread partition table when new disc inserted */
+    i_status = ioctl( i_fd, BLKRRPART );
+  
+    return i_status;
+}
+
+/*
+ * returns 0 on success
+ * returns 1 on failure
+ * returns -1 if not implemented
+ *
+ * Modify eject_disc() prototype as needed for portability
+ */
+
+int intf_Eject( const char *psz_device )
+{
+  int i_ret;
+
+#ifdef SYS_LINUX
+  int i_fd = 0;
+
+   i_fd = open( psz_device, O_RDONLY | O_NONBLOCK );
+   
+   if( i_fd == -1 )
+   {
+       intf_ErrMsg( "intf error: couldn't open device %s", psz_device );
+       return 1;
+   }
+
+   if( EjectCdrom(i_fd) == 0 )
+   {
+       i_ret = 0;
+   }
+   else if( EjectScsi(i_fd) == 0 )
+   {
+       i_ret = 0;
+   }
+   else
+   {
+       intf_ErrMsg( "intf error: couldn't eject %s", psz_device );
+       i_ret = 1;
+   }
+
+   close( i_fd );
+
+#else
+   i_ret = -1;
+
+#endif
+   return i_ret;
+}
+
index 4fc8c56f5891673e807afa0d9f3c90d0935ccfe6..d617f2675e89b7b78ff22d861620f1ed9a699cff 100644 (file)
@@ -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 <sam@zoy.org>
  *          Ethan C. Baldridge <BaldridgeE@cadmus.com>
@@ -54,6 +54,7 @@
 
 #include "interface.h"
 #include "intf_playlist.h"
+#include "intf_eject.h"
 
 #include "stream_control.h"
 #include "input_ext-intf.h"
index da0f2211138e874d0de78beef84ea762955d40bb..0535ca08830d4a2c4fb8c8b832bbee5fcfd27008 100644 (file)
@@ -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 <sam@zoy.org>
  *
@@ -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; \