# include <X11/extensions/Xvlib.h>
#endif
+#ifdef MODULE_NAME_IS_glx
+# include <GL/glx.h>
+#endif
+
#ifdef HAVE_XINERAMA
# include <X11/extensions/Xinerama.h>
#endif
static void TestNetWMSupport( vout_thread_t * );
static int ConvertKey( int );
-/* Object variables callbacks */
-static int OnTopCallback( vlc_object_t *, char const *,
- vlc_value_t, vlc_value_t, void * );
+static int WindowOnTop( vout_thread_t *, vlc_bool_t );
/*****************************************************************************
* Activate: allocate X11 video thread output method
{
vout_thread_t *p_vout = (vout_thread_t *)p_this;
char * psz_display;
- vlc_value_t val, text;
+ vlc_value_t val;
#ifdef MODULE_NAME_IS_xvideo
char * psz_chroma;
return VLC_ENOMEM;
}
+ vlc_mutex_init( p_vout, &p_vout->p_sys->lock );
+
/* Open display, using the "display" config variable or the DISPLAY
* environment variable */
psz_display = config_GetPsz( p_vout, MODULE_STRING "-display" );
TestNetWMSupport( p_vout );
- /* Add a variable to indicate if the window should be on top of others */
- var_Create( p_vout, "video-on-top", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
- text.psz_string = _("Always on top");
- var_Change( p_vout, "video-on-top", VLC_VAR_SETTEXT, &text, NULL );
- var_AddCallback( p_vout, "video-on-top", OnTopCallback, NULL );
+ /* Variable to indicate if the window should be on top of others */
/* Trigger a callback right now */
var_Get( p_vout, "video-on-top", &val );
var_Set( p_vout, "video-on-top", val );
{
XFreeColormap( p_vout->p_sys->p_display, p_vout->p_sys->colormap );
}
-#else
+#elif defined(MODULE_NAME_IS_xvideo)
XVideoReleasePort( p_vout, p_vout->p_sys->i_xvport );
#endif
XCloseDisplay( p_vout->p_sys->p_display );
/* Destroy structure */
+ vlc_mutex_destroy( &p_vout->p_sys->lock );
free( p_vout->p_sys );
}
break;
}
-#else
+#elif defined(MODULE_NAME_IS_x11)
/* 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 )
return VLC_SUCCESS;
}
- /*****************************************************************************
+/*****************************************************************************
* DisplayVideo: displays previously rendered output
*****************************************************************************
* This function sends the currently rendered image to X11 server.
p_vout->p_sys->p_win->i_height,
&i_x, &i_y, &i_width, &i_height );
+ vlc_mutex_lock( &p_vout->p_sys->lock );
+
#ifdef HAVE_SYS_SHM_H
if( p_vout->p_sys->b_shm )
{
/* Make sure the command is sent now - do NOT use XFlush !*/
XSync( p_vout->p_sys->p_display, False );
+
+ vlc_mutex_unlock( &p_vout->p_sys->lock );
}
/*****************************************************************************
XEvent xevent; /* X11 event */
vlc_value_t val;
+ vlc_mutex_lock( &p_vout->p_sys->lock );
+
/* Handle events from the owner window */
if( p_vout->p_sys->p_win->owner_window )
{
/* ConfigureNotify event: prepare */
if( xevent.type == ConfigureNotify )
{
- if( (unsigned int)xevent.xconfigure.width
- != p_vout->p_sys->p_win->i_width ||
- (unsigned int)xevent.xconfigure.height
- != p_vout->p_sys->p_win->i_height )
- {
- /* Update dimensions */
- XResizeWindow( p_vout->p_sys->p_display,
- p_vout->p_sys->p_win->base_window,
- xevent.xconfigure.width,
- xevent.xconfigure.height );
- }
+ /* Update dimensions */
+ XResizeWindow( p_vout->p_sys->p_display,
+ p_vout->p_sys->p_win->base_window,
+ xevent.xconfigure.width,
+ xevent.xconfigure.height );
}
}
}
var_Get( p_vout, "mouse-button-down", &val );
val.i_int |= 8;
var_Set( p_vout, "mouse-button-down", val );
- input_Seek( p_vout, 15, INPUT_SEEK_SECONDS | INPUT_SEEK_CUR );
break;
case Button5:
var_Get( p_vout, "mouse-button-down", &val );
val.i_int |= 16;
var_Set( p_vout, "mouse-button-down", val );
- input_Seek( p_vout, -15, INPUT_SEEK_SECONDS | INPUT_SEEK_CUR );
break;
}
}
FIND_ANYWHERE );
if( p_playlist != NULL )
{
- vlc_value_t val;
+ vlc_value_t val; val.b_bool = VLC_TRUE;
var_Set( p_playlist, "intf-popupmenu", val );
vlc_object_release( p_playlist );
}
}
}
+ vlc_mutex_unlock( &p_vout->p_sys->lock );
+
return 0;
}
p_win->wm_delete_window =
XInternAtom( p_vout->p_sys->p_display, "WM_DELETE_WINDOW", True );
+ /* Never have a 0-pixel-wide window */
+ xsize_hints.min_width = 2;
+ xsize_hints.min_height = 1;
+
/* Prepare window attributes */
xwindow_attributes.backing_store = Always; /* save the hidden part */
xwindow_attributes.background_pixel = BlackPixel(p_vout->p_sys->p_display,
xsize_hints.base_width = xsize_hints.width = p_win->i_width;
xsize_hints.base_height = xsize_hints.height = p_win->i_height;
- xsize_hints.flags = PSize;
+ xsize_hints.flags = PSize | PMinSize;
if( p_win->i_x >=0 || p_win->i_y >= 0 )
{
XStoreName( p_vout->p_sys->p_display, p_win->base_window,
#ifdef MODULE_NAME_IS_x11
VOUT_TITLE " (X11 output)"
+#elif defined(MODULE_NAME_IS_glx)
+ VOUT_TITLE " (GLX output)"
#else
VOUT_TITLE " (XVideo output)"
#endif
&& (xevent.xexpose.window == p_win->base_window) )
{
b_expose = VLC_TRUE;
+ /* ConfigureNotify isn't sent if there isn't a window manager.
+ * Expose should be the last event to be received so it should
+ * be fine to assume we won't receive it anymore. */
+ b_configure_notify = VLC_TRUE;
}
else if( (xevent.type == MapNotify)
&& (xevent.xmap.window == p_win->base_window) )
/* Do NOT use XFlush here ! */
XSync( p_vout->p_sys->p_display, False );
- XDestroyWindow( p_vout->p_sys->p_display, p_win->video_window );
+ if( p_win->video_window != None )
+ XDestroyWindow( p_vout->p_sys->p_display, p_win->video_window );
+
XFreeGC( p_vout->p_sys->p_display, p_win->gc );
XUnmapWindow( p_vout->p_sys->p_display, p_win->base_window );
*****************************************************************************/
static int NewPicture( vout_thread_t *p_vout, picture_t *p_pic )
{
+#ifndef MODULE_NAME_IS_glx
+
#ifdef MODULE_NAME_IS_xvideo
int i_plane;
#endif
p_pic->p_sys->p_image =
CreateShmImage( p_vout, p_vout->p_sys->p_display,
# ifdef MODULE_NAME_IS_xvideo
- p_vout->p_sys->i_xvport, p_vout->output.i_chroma,
+ p_vout->p_sys->i_xvport,
+ VLC2X11_FOURCC(p_vout->output.i_chroma),
# else
p_vout->p_sys->p_visual,
p_vout->p_sys->i_screen_depth,
p_pic->p_sys->p_image =
CreateImage( p_vout, p_vout->p_sys->p_display,
#ifdef MODULE_NAME_IS_xvideo
- p_vout->p_sys->i_xvport, p_vout->output.i_chroma,
+ p_vout->p_sys->i_xvport,
+ VLC2X11_FOURCC(p_vout->output.i_chroma),
p_pic->format.i_bits_per_pixel,
#else
p_vout->p_sys->p_visual,
case VLC_FOURCC('R','V','3','2'):
p_pic->p->i_lines = p_pic->p_sys->p_image->height;
+ p_pic->p->i_visible_lines = p_pic->p_sys->p_image->height;
p_pic->p->p_pixels = p_pic->p_sys->p_image->data
+ p_pic->p_sys->p_image->xoffset;
p_pic->p->i_pitch = p_pic->p_sys->p_image->bytes_per_line;
return -1;
}
+#endif /* !MODULE_NAME_IS_glx */
+
return 0;
}
config_GetInt( p_vout, MODULE_STRING "-altfullscreen" );
XUnmapWindow( p_vout->p_sys->p_display,
- p_vout->p_sys->p_win->base_window);
+ p_vout->p_sys->p_win->base_window );
p_vout->p_sys->p_win = &p_vout->p_sys->fullscreen_window;
CreateWindow( p_vout, p_vout->p_sys->p_win );
+ XDestroyWindow( p_vout->p_sys->p_display,
+ p_vout->p_sys->fullscreen_window.video_window );
+ XReparentWindow( p_vout->p_sys->p_display,
+ p_vout->p_sys->original_window.video_window,
+ p_vout->p_sys->fullscreen_window.base_window, 0, 0 );
+ p_vout->p_sys->fullscreen_window.video_window =
+ p_vout->p_sys->original_window.video_window;
/* 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
#define SCREEN p_vout->p_sys->p_win->i_screen
- /* Get Informations about Xinerama (num of screens) */
+ /* Get Information about Xinerama (num of screens) */
screens = XineramaQueryScreens( p_vout->p_sys->p_display,
&i_num_screens );
#undef SCREEN
}
+ else
#endif
+ {
+ /* The window wasn't necessarily created at the requested size */
+ p_vout->p_sys->p_win->i_x = p_vout->p_sys->p_win->i_y = 0;
+ p_vout->p_sys->p_win->i_width =
+ DisplayWidth( p_vout->p_sys->p_display,
+ p_vout->p_sys->i_screen );
+ p_vout->p_sys->p_win->i_height =
+ DisplayHeight( p_vout->p_sys->p_display,
+ p_vout->p_sys->i_screen );
+ }
XMoveResizeWindow( p_vout->p_sys->p_display,
p_vout->p_sys->p_win->base_window,
else
{
msg_Dbg( p_vout, "leaving fullscreen mode" );
+
+ XReparentWindow( p_vout->p_sys->p_display,
+ p_vout->p_sys->original_window.video_window,
+ p_vout->p_sys->original_window.base_window, 0, 0 );
+
+ p_vout->p_sys->fullscreen_window.video_window = None;
DestroyWindow( p_vout, &p_vout->p_sys->fullscreen_window );
p_vout->p_sys->p_win = &p_vout->p_sys->original_window;
XMapWindow( p_vout->p_sys->p_display,
- p_vout->p_sys->p_win->base_window);
+ p_vout->p_sys->p_win->base_window );
}
/* Unfortunately, using XSync() here is not enough to ensure the
int dummy;
#endif
- /* Save screen saver informations */
+ /* Save screen saver information */
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,
i_format < i_num_formats && ( i_selected_port == -1 );
i_format++ )
{
- /* Code removed, we can get this through xvinfo anyway */
-#if 0
- XvEncodingInfo *p_enc;
- int i_enc, i_num_encodings;
XvAttribute *p_attr;
int i_attr, i_num_attributes;
-#endif
/* If this is not the format we want, or at least a
* similar one, forget it */
( p_formats[ i_format ].format == XvPacked ) ?
"packed" : "planar" );
-#if 0
- msg_Dbg( p_vout, " encoding list:" );
-
- if( XvQueryEncodings( p_vout->p_sys->p_display, i_selected_port,
- &i_num_encodings, &p_enc )
- != Success )
- {
- msg_Dbg( p_vout, " XvQueryEncodings failed" );
- continue;
- }
-
- for( i_enc = 0; i_enc < i_num_encodings; i_enc++ )
- {
- msg_Dbg( p_vout, " id=%ld, name=%s, size=%ldx%ld,"
- " numerator=%d, denominator=%d",
- p_enc[i_enc].encoding_id, p_enc[i_enc].name,
- p_enc[i_enc].width, p_enc[i_enc].height,
- p_enc[i_enc].rate.numerator,
- p_enc[i_enc].rate.denominator );
- }
-
- if( p_enc != NULL )
- {
- XvFreeEncodingInfo( p_enc );
- }
-
- msg_Dbg( p_vout, " attribute list:" );
+ /* Make sure XV_AUTOPAINT_COLORKEY is set */
p_attr = XvQueryPortAttributes( p_vout->p_sys->p_display,
i_selected_port,
&i_num_attributes );
+
for( i_attr = 0; i_attr < i_num_attributes; i_attr++ )
{
- msg_Dbg( p_vout, " name=%s, flags=[%s%s ], min=%i, max=%i",
- p_attr[i_attr].name,
- (p_attr[i_attr].flags & XvGettable) ? " get" : "",
- (p_attr[i_attr].flags & XvSettable) ? " set" : "",
- p_attr[i_attr].min_value, p_attr[i_attr].max_value );
+ if( !strcmp( p_attr[i_attr].name, "XV_AUTOPAINT_COLORKEY" ) )
+ {
+ const Atom autopaint =
+ XInternAtom( p_vout->p_sys->p_display,
+ "XV_AUTOPAINT_COLORKEY", False );
+ XvSetPortAttribute( p_vout->p_sys->p_display,
+ i_selected_port, autopaint, 1 );
+ break;
+ }
}
if( p_attr != NULL )
{
XFree( p_attr );
}
-#endif
}
if( p_formats != NULL )
{
#ifdef MODULE_NAME_IS_x11
XPixmapFormatValues * p_formats; /* pixmap formats */
- XVisualInfo * p_xvisual; /* visuals informations */
+ XVisualInfo * p_xvisual; /* visuals information */
XVisualInfo xvisual_template; /* visual template */
int i_count; /* array size */
#endif
/* Allocate memory for image */
#ifdef MODULE_NAME_IS_xvideo
p_data = (byte_t *) malloc( i_width * i_height * i_bits_per_pixel / 8 );
-#else
+#elif defined(MODULE_NAME_IS_x11)
i_bytes_per_line = i_width * i_bytes_per_pixel;
p_data = (byte_t *) malloc( i_bytes_per_line * i_height );
#endif
#ifdef MODULE_NAME_IS_xvideo
p_image = XvCreateImage( p_display, i_xvport, i_chroma,
p_data, i_width, i_height );
-#else
+#elif defined(MODULE_NAME_IS_x11)
p_image = XCreateImage( p_display, p_visual, i_depth, ZPixmap, 0,
p_data, i_width, i_height, i_quantum, 0 );
#endif
static int Control( vout_thread_t *p_vout, int i_query, va_list args )
{
double f_arg;
+ vlc_bool_t b_arg;
switch( i_query )
{
f_arg = va_arg( args, double );
+ vlc_mutex_lock( &p_vout->p_sys->lock );
+
/* Update dimensions */
+ /* FIXME: export InitWindowSize() from vout core */
XResizeWindow( p_vout->p_sys->p_display,
p_vout->p_sys->p_win->base_window,
- p_vout->render.i_width * f_arg,
- p_vout->render.i_height * f_arg );
+ p_vout->i_window_width * f_arg,
+ p_vout->i_window_height * f_arg );
+ vlc_mutex_unlock( &p_vout->p_sys->lock );
return VLC_SUCCESS;
+ case VOUT_CLOSE:
+ vlc_mutex_lock( &p_vout->p_sys->lock );
+ XUnmapWindow( p_vout->p_sys->p_display,
+ p_vout->p_sys->original_window.base_window );
+ vlc_mutex_unlock( &p_vout->p_sys->lock );
+ /* Fall through */
+
case VOUT_REPARENT:
+ vlc_mutex_lock( &p_vout->p_sys->lock );
XReparentWindow( p_vout->p_sys->p_display,
- p_vout->p_sys->p_win->base_window,
+ p_vout->p_sys->original_window.base_window,
DefaultRootWindow( p_vout->p_sys->p_display ),
0, 0 );
XSync( p_vout->p_sys->p_display, False );
- p_vout->p_sys->p_win->owner_window = 0;
+ p_vout->p_sys->original_window.owner_window = 0;
+ vlc_mutex_unlock( &p_vout->p_sys->lock );
+ return vout_vaControlDefault( p_vout, i_query, args );
+
+ case VOUT_SET_STAY_ON_TOP:
+ if( p_vout->p_sys->p_win->owner_window )
+ return vout_ControlWindow( p_vout,
+ (void *)p_vout->p_sys->p_win->owner_window, i_query, args);
+
+ b_arg = va_arg( args, vlc_bool_t );
+ vlc_mutex_lock( &p_vout->p_sys->lock );
+ WindowOnTop( p_vout, b_arg );
+ vlc_mutex_unlock( &p_vout->p_sys->lock );
return VLC_SUCCESS;
default:
- msg_Dbg( p_vout, "control query not supported" );
- return VLC_EGENERIC;
+ return vout_vaControlDefault( p_vout, i_query, args );
}
}
{
int i_ret, i_format;
unsigned long i, i_items, i_bytesafter;
- Atom net_wm_supported, *p_args = NULL;
+ Atom net_wm_supported;
+ union { Atom *p_atom; unsigned char *p_char; } p_args;
+
+ p_args.p_atom = NULL;
p_vout->p_sys->b_net_wm_state_fullscreen = VLC_FALSE;
p_vout->p_sys->b_net_wm_state_above = VLC_FALSE;
0, 16384, False, AnyPropertyType,
&net_wm_supported,
&i_format, &i_items, &i_bytesafter,
- (unsigned char **)(intptr_t)&p_args );
+ (unsigned char **)&p_args );
if( i_ret != Success || i_items == 0 ) return;
for( i = 0; i < i_items; i++ )
{
- if( p_args[i] == p_vout->p_sys->net_wm_state_fullscreen )
+ if( p_args.p_atom[i] == p_vout->p_sys->net_wm_state_fullscreen )
{
msg_Dbg( p_vout,
"Window manager supports _NET_WM_STATE_FULLSCREEN" );
p_vout->p_sys->b_net_wm_state_fullscreen = VLC_TRUE;
}
- else if( p_args[i] == p_vout->p_sys->net_wm_state_above )
+ else if( p_args.p_atom[i] == p_vout->p_sys->net_wm_state_above )
{
msg_Dbg( p_vout, "Window manager supports _NET_WM_STATE_ABOVE" );
p_vout->p_sys->b_net_wm_state_above = VLC_TRUE;
}
- else if( p_args[i] == p_vout->p_sys->net_wm_state_below )
+ else if( p_args.p_atom[i] == p_vout->p_sys->net_wm_state_below )
{
msg_Dbg( p_vout, "Window manager supports _NET_WM_STATE_BELOW" );
p_vout->p_sys->b_net_wm_state_below = VLC_TRUE;
}
- else if( p_args[i] == p_vout->p_sys->net_wm_state_stays_on_top )
+ else if( p_args.p_atom[i] == p_vout->p_sys->net_wm_state_stays_on_top )
{
msg_Dbg( p_vout,
"Window manager supports _NET_WM_STATE_STAYS_ON_TOP" );
}
}
- XFree( p_args );
+ XFree( p_args.p_atom );
}
/*****************************************************************************
}
/*****************************************************************************
- * object variables callbacks: a bunch of object variables are used by the
- * interfaces to interact with the vout.
+ * WindowOnTop: Switches the "always on top" state of the video window.
*****************************************************************************/
-static int OnTopCallback( vlc_object_t *p_this, char const *psz_cmd,
- vlc_value_t oldval, vlc_value_t newval, void *p_data )
+static int WindowOnTop( vout_thread_t *p_vout, vlc_bool_t b_on_top )
{
- vout_thread_t *p_vout = (vout_thread_t *)p_this;
-
if( p_vout->p_sys->b_net_wm_state_stays_on_top )
{
XClientMessageEvent event;
event.display = p_vout->p_sys->p_display;
event.window = p_vout->p_sys->p_win->base_window;
event.format = 32;
- event.data.l[ 0 ] = newval.b_bool; /* set property */
+ event.data.l[ 0 ] = b_on_top; /* set property */
event.data.l[ 1 ] = p_vout->p_sys->net_wm_state_stays_on_top;
XSendEvent( p_vout->p_sys->p_display,