1 /*****************************************************************************
2 * xcommon.c: Functions common to the X11 and XVideo plugins
3 *****************************************************************************
4 * Copyright (C) 1998-2001 VideoLAN
5 * $Id: xcommon.c,v 1.43 2002/07/17 21:34:57 stef Exp $
7 * Authors: Vincent Seguin <seguin@via.ecp.fr>
8 * Samuel Hocevar <sam@zoy.org>
9 * David Kennedy <dkennedy@tinytoad.com>
10 * Gildas Bazin <gbazin@netcourrier.com>
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
25 *****************************************************************************/
27 /*****************************************************************************
29 *****************************************************************************/
30 #include <errno.h> /* ENOMEM */
31 #include <stdlib.h> /* free() */
32 #include <string.h> /* strerror() */
38 #ifdef HAVE_MACHINE_PARAM_H
40 # include <machine/param.h>
41 # include <sys/types.h> /* typedef ushort */
46 # include <netinet/in.h> /* BSD: struct in_addr */
50 # include <sys/shm.h> /* shmget(), shmctl() */
54 #include <X11/Xutil.h>
55 #include <X11/keysym.h>
57 # include <X11/extensions/XShm.h>
59 #ifdef DPMSINFO_IN_DPMS_H
60 # include <X11/extensions/dpms.h>
63 #ifdef MODULE_NAME_IS_xvideo
64 # include <X11/extensions/Xv.h>
65 # include <X11/extensions/Xvlib.h>
70 #include "netutils.h" /* network_ChannelJoin */
72 /*****************************************************************************
74 *****************************************************************************/
75 #ifdef MODULE_NAME_IS_xvideo
76 # define IMAGE_TYPE XvImage
77 # define EXTRA_ARGS int i_xvport, int i_chroma
78 # define EXTRA_ARGS_SHM int i_xvport, int i_chroma, XShmSegmentInfo *p_shm
79 # define DATA_SIZE(p) (p)->data_size
80 # define IMAGE_FREE XFree /* There is nothing like XvDestroyImage */
82 # define IMAGE_TYPE XImage
83 # define EXTRA_ARGS Visual *p_visual, int i_depth, int i_bytes_per_pixel
84 # define EXTRA_ARGS_SHM Visual *p_visual, int i_depth, XShmSegmentInfo *p_shm
85 # define DATA_SIZE(p) ((p)->bytes_per_line * (p)->height)
86 # define IMAGE_FREE XDestroyImage
90 typedef struct x11_window_s x11_window_t;
92 /*****************************************************************************
94 *****************************************************************************/
95 static int vout_Create ( vout_thread_t * );
96 static void vout_Destroy ( vout_thread_t * );
97 static void vout_Render ( vout_thread_t *, picture_t * );
98 static void vout_Display ( vout_thread_t *, picture_t * );
99 static int vout_Manage ( vout_thread_t * );
100 static int vout_Init ( vout_thread_t * );
101 static void vout_End ( vout_thread_t * );
103 static int InitDisplay ( vout_thread_t * );
105 static int CreateWindow ( vout_thread_t *, x11_window_t * );
106 static void DestroyWindow ( vout_thread_t *, x11_window_t * );
108 static int NewPicture ( vout_thread_t *, picture_t * );
109 static void FreePicture ( vout_thread_t *, picture_t * );
111 static IMAGE_TYPE *CreateImage ( vout_thread_t *,
112 Display *, EXTRA_ARGS, int, int );
113 #ifdef HAVE_SYS_SHM_H
114 static IMAGE_TYPE *CreateShmImage ( vout_thread_t *,
115 Display *, EXTRA_ARGS_SHM, int, int );
118 static void ToggleFullScreen ( vout_thread_t * );
120 static void EnableXScreenSaver ( vout_thread_t * );
121 static void DisableXScreenSaver ( vout_thread_t * );
123 static void CreateCursor ( vout_thread_t * );
124 static void DestroyCursor ( vout_thread_t * );
125 static void ToggleCursor ( vout_thread_t * );
127 #ifdef MODULE_NAME_IS_xvideo
128 static int XVideoGetPort ( vout_thread_t *, u32, u32 * );
129 static void XVideoReleasePort ( vout_thread_t *, int );
132 #ifdef MODULE_NAME_IS_x11
133 static void SetPalette ( vout_thread_t *, u16 *, u16 *, u16 * );
136 /*****************************************************************************
137 * x11_window_t: X11 window descriptor
138 *****************************************************************************
139 * This structure contains all the data necessary to describe an X11 window.
140 *****************************************************************************/
143 Window base_window; /* base window */
144 Window video_window; /* sub-window for displaying video */
145 GC gc; /* graphic context instance handler */
146 int i_width; /* width of main window */
147 int i_height; /* height of main window */
149 Atom wm_delete_window;
152 /*****************************************************************************
153 * vout_sys_t: video output method descriptor
154 *****************************************************************************
155 * This structure is part of the video output thread descriptor.
156 * It describes the X11 and XVideo specific properties of an output thread.
157 *****************************************************************************/
160 /* Internal settings and properties */
161 Display * p_display; /* display pointer */
163 Visual * p_visual; /* visual pointer */
164 int i_screen; /* screen number */
166 /* Our current window */
167 x11_window_t * p_win;
169 /* Our two windows */
170 x11_window_t original_window;
171 x11_window_t fullscreen_window;
173 /* X11 generic properties */
174 vlc_bool_t b_altfullscreen; /* which fullscreen method */
175 vlc_bool_t b_createwindow; /* are we the base window's owner ? */
176 #ifdef HAVE_SYS_SHM_H
177 vlc_bool_t b_shm; /* shared memory extension flag */
180 #ifdef MODULE_NAME_IS_xvideo
183 Colormap colormap; /* colormap used (8bpp only) */
186 int i_bytes_per_pixel;
187 int i_bytes_per_line;
190 /* Screen saver properties */
191 int i_ss_timeout; /* timeout */
192 int i_ss_interval; /* interval between changes */
193 int i_ss_blanking; /* blanking mode */
194 int i_ss_exposure; /* exposure mode */
195 #ifdef DPMSINFO_IN_DPMS_H
196 BOOL b_ss_dpms; /* DPMS mode */
199 /* Mouse pointer properties */
200 vlc_bool_t b_mouse_pointer_visible;
201 mtime_t i_time_mouse_last_moved; /* used to auto-hide pointer*/
202 Cursor blank_cursor; /* the hidden cursor */
203 mtime_t i_time_button_last_pressed; /* to track dbl-clicks */
204 Pixmap cursor_pixmap;
207 /*****************************************************************************
208 * picture_sys_t: direct buffer method descriptor
209 *****************************************************************************
210 * This structure is part of the picture descriptor, it describes the
211 * XVideo specific properties of a direct buffer.
212 *****************************************************************************/
215 IMAGE_TYPE * p_image;
217 #ifdef HAVE_SYS_SHM_H
218 XShmSegmentInfo shminfo; /* shared memory zone information */
222 /*****************************************************************************
223 * mwmhints_t: window manager hints
224 *****************************************************************************
225 * Fullscreen needs to be able to hide the wm decorations so we provide
226 * this structure to make it easier.
227 *****************************************************************************/
228 #define MWM_HINTS_DECORATIONS (1L << 1)
229 #define PROP_MWM_HINTS_ELEMENTS 5
230 typedef struct mwmhints_s
239 /*****************************************************************************
241 *****************************************************************************/
242 #ifdef MODULE_NAME_IS_xvideo
243 # define MAX_DIRECTBUFFERS 10
245 # define MAX_DIRECTBUFFERS 2
248 /*****************************************************************************
249 * Functions exported as capabilities. They are declared as static so that
250 * we don't pollute the namespace too much.
251 *****************************************************************************/
252 void _M( vout_getfunctions )( function_list_t * p_function_list )
254 p_function_list->functions.vout.pf_create = vout_Create;
255 p_function_list->functions.vout.pf_init = vout_Init;
256 p_function_list->functions.vout.pf_end = vout_End;
257 p_function_list->functions.vout.pf_destroy = vout_Destroy;
258 p_function_list->functions.vout.pf_manage = vout_Manage;
259 p_function_list->functions.vout.pf_render = vout_Render;
260 p_function_list->functions.vout.pf_display = vout_Display;
263 /*****************************************************************************
264 * vout_Create: allocate X11 video thread output method
265 *****************************************************************************
266 * This function allocate and initialize a X11 vout method. It uses some of the
267 * vout properties to choose the window size, and change them according to the
268 * actual properties of the display.
269 *****************************************************************************/
270 static int vout_Create( vout_thread_t *p_vout )
273 #ifdef MODULE_NAME_IS_xvideo
276 vlc_bool_t b_chroma = 0;
279 /* Allocate structure */
280 p_vout->p_sys = malloc( sizeof( vout_sys_t ) );
281 if( p_vout->p_sys == NULL )
283 msg_Err( p_vout, "out of memory" );
287 /* Open display, unsing the "display" config variable or the DISPLAY
288 * environment variable */
289 psz_display = config_GetPsz( p_vout, MODULE_STRING "-display" );
291 p_vout->p_sys->p_display = XOpenDisplay( psz_display );
293 if( p_vout->p_sys->p_display == NULL ) /* error */
295 msg_Err( p_vout, "cannot open display %s",
296 XDisplayName( psz_display ) );
297 free( p_vout->p_sys );
298 if( psz_display ) free( psz_display );
301 if( psz_display ) free( psz_display );
303 /* Get a screen ID matching the XOpenDisplay return value */
304 p_vout->p_sys->i_screen = DefaultScreen( p_vout->p_sys->p_display );
306 #ifdef MODULE_NAME_IS_xvideo
307 psz_chroma = config_GetPsz( p_vout, "xvideo-chroma" );
310 if( strlen( psz_chroma ) >= 4 )
312 i_chroma = (unsigned char)psz_chroma[0] << 0;
313 i_chroma |= (unsigned char)psz_chroma[1] << 8;
314 i_chroma |= (unsigned char)psz_chroma[2] << 16;
315 i_chroma |= (unsigned char)psz_chroma[3] << 24;
325 msg_Dbg( p_vout, "forcing chroma 0x%.8x (%4.4s)",
326 i_chroma, (char*)&i_chroma );
330 i_chroma = p_vout->render.i_chroma;
333 /* Check that we have access to an XVideo port providing this chroma */
334 p_vout->p_sys->i_xvport = XVideoGetPort( p_vout, i_chroma,
335 &p_vout->output.i_chroma );
336 if( p_vout->p_sys->i_xvport < 0 )
338 /* If a specific chroma format was requested, then we don't try to
339 * be cleverer than the user. He knows pretty well what he wants. */
342 XCloseDisplay( p_vout->p_sys->p_display );
343 free( p_vout->p_sys );
347 /* It failed, but it's not completely lost ! We try to open an
348 * XVideo port for an YUY2 picture. We'll need to do an YUV
349 * conversion, but at least it has got scaling. */
350 p_vout->p_sys->i_xvport = XVideoGetPort( p_vout, FOURCC_YUY2,
351 &p_vout->output.i_chroma );
352 if( p_vout->p_sys->i_xvport < 0 )
354 /* It failed, but it's not completely lost ! We try to open an
355 * XVideo port for a simple 16bpp RGB picture. We'll need to do
356 * an YUV conversion, but at least it has got scaling. */
357 p_vout->p_sys->i_xvport = XVideoGetPort( p_vout, FOURCC_RV16,
358 &p_vout->output.i_chroma );
359 if( p_vout->p_sys->i_xvport < 0 )
361 XCloseDisplay( p_vout->p_sys->p_display );
362 free( p_vout->p_sys );
369 /* Create blank cursor (for mouse cursor autohiding) */
370 p_vout->p_sys->i_time_mouse_last_moved = mdate();
371 p_vout->p_sys->b_mouse_pointer_visible = 1;
372 CreateCursor( p_vout );
374 /* Set main window's size */
375 p_vout->p_sys->original_window.i_width = p_vout->i_window_width;
376 p_vout->p_sys->original_window.i_height = p_vout->i_window_height;
378 /* Spawn base window - this window will include the video output window,
379 * but also command buttons, subtitles and other indicators */
380 if( CreateWindow( p_vout, &p_vout->p_sys->original_window ) )
382 msg_Err( p_vout, "cannot create X11 window" );
383 DestroyCursor( p_vout );
384 XCloseDisplay( p_vout->p_sys->p_display );
385 free( p_vout->p_sys );
389 /* Open and initialize device. */
390 if( InitDisplay( p_vout ) )
392 msg_Err( p_vout, "cannot initialize X11 display" );
393 DestroyCursor( p_vout );
394 DestroyWindow( p_vout, &p_vout->p_sys->original_window );
395 XCloseDisplay( p_vout->p_sys->p_display );
396 free( p_vout->p_sys );
400 /* Disable screen saver */
401 DisableXScreenSaver( p_vout );
404 p_vout->p_sys->b_altfullscreen = 0;
405 p_vout->p_sys->i_time_button_last_pressed = 0;
410 /*****************************************************************************
411 * vout_Destroy: destroy X11 video thread output method
412 *****************************************************************************
413 * Terminate an output method created by vout_CreateOutputMethod
414 *****************************************************************************/
415 static void vout_Destroy( vout_thread_t *p_vout )
417 /* If the fullscreen window is still open, close it */
418 if( p_vout->b_fullscreen )
420 ToggleFullScreen( p_vout );
423 /* Restore cursor if it was blanked */
424 if( !p_vout->p_sys->b_mouse_pointer_visible )
426 ToggleCursor( p_vout );
429 #ifdef MODULE_NAME_IS_x11
430 /* Destroy colormap */
431 if( XDefaultDepth(p_vout->p_sys->p_display, p_vout->p_sys->i_screen) == 8 )
433 XFreeColormap( p_vout->p_sys->p_display, p_vout->p_sys->colormap );
436 XVideoReleasePort( p_vout, p_vout->p_sys->i_xvport );
439 DestroyCursor( p_vout );
440 EnableXScreenSaver( p_vout );
441 DestroyWindow( p_vout, &p_vout->p_sys->original_window );
443 XCloseDisplay( p_vout->p_sys->p_display );
445 /* Destroy structure */
446 free( p_vout->p_sys );
449 /*****************************************************************************
450 * vout_Init: initialize X11 video thread output method
451 *****************************************************************************
452 * This function create the XImages needed by the output thread. It is called
453 * at the beginning of the thread, but also each time the window is resized.
454 *****************************************************************************/
455 static int vout_Init( vout_thread_t *p_vout )
460 I_OUTPUTPICTURES = 0;
462 #ifdef MODULE_NAME_IS_xvideo
463 /* Initialize the output structure; we already found an XVideo port,
464 * and the corresponding chroma we will be using. Since we can
465 * arbitrary scale, stick to the coordinates and aspect. */
466 p_vout->output.i_width = p_vout->render.i_width;
467 p_vout->output.i_height = p_vout->render.i_height;
468 p_vout->output.i_aspect = p_vout->render.i_aspect;
470 switch( p_vout->output.i_chroma )
473 p_vout->output.i_rmask = 0x001f;
474 p_vout->output.i_gmask = 0x07e0;
475 p_vout->output.i_bmask = 0xf800;
478 p_vout->output.i_rmask = 0x001f;
479 p_vout->output.i_gmask = 0x03e0;
480 p_vout->output.i_bmask = 0x7c00;
485 /* Initialize the output structure: RGB with square pixels, whatever
486 * the input format is, since it's the only format we know */
487 switch( p_vout->p_sys->i_screen_depth )
489 case 8: /* FIXME: set the palette */
490 p_vout->output.i_chroma = FOURCC_RGB2; break;
492 p_vout->output.i_chroma = FOURCC_RV15; break;
494 p_vout->output.i_chroma = FOURCC_RV16; break;
496 p_vout->output.i_chroma = FOURCC_RV24; break;
498 p_vout->output.i_chroma = FOURCC_RV24; break;
500 msg_Err( p_vout, "unknown screen depth %i",
501 p_vout->p_sys->i_screen_depth );
505 vout_PlacePicture( p_vout, p_vout->p_sys->p_win->i_width,
506 p_vout->p_sys->p_win->i_height,
508 &p_vout->output.i_width, &p_vout->output.i_height );
510 /* Assume we have square pixels */
511 p_vout->output.i_aspect = p_vout->output.i_width
512 * VOUT_ASPECT_FACTOR / p_vout->output.i_height;
515 /* Try to initialize up to MAX_DIRECTBUFFERS direct buffers */
516 while( I_OUTPUTPICTURES < MAX_DIRECTBUFFERS )
520 /* Find an empty picture slot */
521 for( i_index = 0 ; i_index < VOUT_MAX_PICTURES ; i_index++ )
523 if( p_vout->p_picture[ i_index ].i_status == FREE_PICTURE )
525 p_pic = p_vout->p_picture + i_index;
530 /* Allocate the picture */
531 if( p_pic == NULL || NewPicture( p_vout, p_pic ) )
536 p_pic->i_status = DESTROYED_PICTURE;
537 p_pic->i_type = DIRECT_PICTURE;
539 PP_OUTPUTPICTURE[ I_OUTPUTPICTURES ] = p_pic;
547 /*****************************************************************************
548 * vout_Render: render previously calculated output
549 *****************************************************************************/
550 static void vout_Render( vout_thread_t *p_vout, picture_t *p_pic )
555 /*****************************************************************************
556 * vout_Display: displays previously rendered output
557 *****************************************************************************
558 * This function sends the currently rendered image to X11 server.
559 * (The Xv extension takes care of "double-buffering".)
560 *****************************************************************************/
561 static void vout_Display( vout_thread_t *p_vout, picture_t *p_pic )
563 int i_width, i_height, i_x, i_y;
565 vout_PlacePicture( p_vout, p_vout->p_sys->p_win->i_width,
566 p_vout->p_sys->p_win->i_height,
567 &i_x, &i_y, &i_width, &i_height );
569 #ifdef HAVE_SYS_SHM_H
570 if( p_vout->p_sys->b_shm )
572 /* Display rendered image using shared memory extension */
573 # ifdef MODULE_NAME_IS_xvideo
574 XvShmPutImage( p_vout->p_sys->p_display, p_vout->p_sys->i_xvport,
575 p_vout->p_sys->p_win->video_window,
576 p_vout->p_sys->p_win->gc, p_pic->p_sys->p_image,
577 0 /*src_x*/, 0 /*src_y*/,
578 p_vout->output.i_width, p_vout->output.i_height,
579 0 /*dest_x*/, 0 /*dest_y*/, i_width, i_height,
580 False /* Don't put True here or you'll waste your CPU */ );
582 XShmPutImage( p_vout->p_sys->p_display,
583 p_vout->p_sys->p_win->video_window,
584 p_vout->p_sys->p_win->gc, p_pic->p_sys->p_image,
585 0 /*src_x*/, 0 /*src_y*/, 0 /*dest_x*/, 0 /*dest_y*/,
586 p_vout->output.i_width, p_vout->output.i_height,
587 False /* Don't put True here ! */ );
591 #endif /* HAVE_SYS_SHM_H */
593 /* Use standard XPutImage -- this is gonna be slow ! */
594 #ifdef MODULE_NAME_IS_xvideo
595 XvPutImage( p_vout->p_sys->p_display, p_vout->p_sys->i_xvport,
596 p_vout->p_sys->p_win->video_window,
597 p_vout->p_sys->p_win->gc, p_pic->p_sys->p_image,
598 0 /*src_x*/, 0 /*src_y*/,
599 p_vout->output.i_width, p_vout->output.i_height,
600 0 /*dest_x*/, 0 /*dest_y*/, i_width, i_height );
602 XPutImage( p_vout->p_sys->p_display,
603 p_vout->p_sys->p_win->video_window,
604 p_vout->p_sys->p_win->gc, p_pic->p_sys->p_image,
605 0 /*src_x*/, 0 /*src_y*/, 0 /*dest_x*/, 0 /*dest_y*/,
606 p_vout->output.i_width, p_vout->output.i_height );
610 /* Make sure the command is sent now - do NOT use XFlush !*/
611 XSync( p_vout->p_sys->p_display, False );
614 /*****************************************************************************
615 * vout_Manage: handle X11 events
616 *****************************************************************************
617 * This function should be called regularly by video output thread. It manages
618 * X11 events and allows window resizing. It returns a non null value on
620 *****************************************************************************/
621 static int vout_Manage( vout_thread_t *p_vout )
623 XEvent xevent; /* X11 event */
624 char i_key; /* ISO Latin-1 key */
627 /* Handle X11 events: ConfigureNotify events are parsed to know if the
628 * output window's size changed, MapNotify and UnmapNotify to know if the
629 * window is mapped (and if the display is useful), and ClientMessages
630 * to intercept window destruction requests */
632 while( XCheckWindowEvent( p_vout->p_sys->p_display,
633 p_vout->p_sys->p_win->base_window,
634 StructureNotifyMask | KeyPressMask |
635 ButtonPressMask | ButtonReleaseMask |
636 PointerMotionMask | Button1MotionMask , &xevent )
639 /* ConfigureNotify event: prepare */
640 if( xevent.type == ConfigureNotify )
642 if( (xevent.xconfigure.width != p_vout->p_sys->p_win->i_width)
643 || (xevent.xconfigure.height != p_vout->p_sys->p_win->i_height) )
645 /* Update dimensions */
646 p_vout->i_changes |= VOUT_SIZE_CHANGE;
647 p_vout->p_sys->p_win->i_width = xevent.xconfigure.width;
648 p_vout->p_sys->p_win->i_height = xevent.xconfigure.height;
652 else if( xevent.type == KeyPress )
654 /* We may have keys like F1 trough F12, ESC ... */
655 x_key_symbol = XKeycodeToKeysym( p_vout->p_sys->p_display,
656 xevent.xkey.keycode, 0 );
657 switch( x_key_symbol )
660 if( p_vout->b_fullscreen )
662 p_vout->i_changes |= VOUT_FULLSCREEN_CHANGE;
666 p_vout->p_vlc->b_die = 1;
671 intf_thread_t *p_intf;
672 p_intf = vlc_object_find( p_vout, VLC_OBJECT_INTF,
676 p_intf->b_menu_change = 1;
677 vlc_object_release( p_intf );
682 input_Seek( p_vout, -5, INPUT_SEEK_SECONDS | INPUT_SEEK_CUR );
685 input_Seek( p_vout, 5, INPUT_SEEK_SECONDS | INPUT_SEEK_CUR );
688 input_Seek( p_vout, 60, INPUT_SEEK_SECONDS | INPUT_SEEK_CUR );
691 input_Seek( p_vout, -60, INPUT_SEEK_SECONDS | INPUT_SEEK_CUR );
694 input_Seek( p_vout, 0, INPUT_SEEK_BYTES | INPUT_SEEK_SET );
697 input_Seek( p_vout, 0, INPUT_SEEK_BYTES | INPUT_SEEK_END );
700 input_Seek( p_vout, 900, INPUT_SEEK_SECONDS | INPUT_SEEK_CUR );
703 input_Seek( p_vout, -900, INPUT_SEEK_SECONDS | INPUT_SEEK_CUR );
706 input_SetStatus( p_vout, INPUT_STATUS_PAUSE );
709 case XK_F1: network_ChannelJoin( p_vout, 1 ); break;
710 case XK_F2: network_ChannelJoin( p_vout, 2 ); break;
711 case XK_F3: network_ChannelJoin( p_vout, 3 ); break;
712 case XK_F4: network_ChannelJoin( p_vout, 4 ); break;
713 case XK_F5: network_ChannelJoin( p_vout, 5 ); break;
714 case XK_F6: network_ChannelJoin( p_vout, 6 ); break;
715 case XK_F7: network_ChannelJoin( p_vout, 7 ); break;
716 case XK_F8: network_ChannelJoin( p_vout, 8 ); break;
717 case XK_F9: network_ChannelJoin( p_vout, 9 ); break;
718 case XK_F10: network_ChannelJoin( p_vout, 10 ); break;
719 case XK_F11: network_ChannelJoin( p_vout, 11 ); break;
720 case XK_F12: network_ChannelJoin( p_vout, 12 ); break;
724 * The reason why I use this instead of XK_0 is that
725 * with XLookupString, we don't have to care about
728 if( XLookupString( &xevent.xkey, &i_key, 1, NULL, NULL ) )
730 /* FIXME: handle stuff here */
735 p_vout->p_vlc->b_die = 1;
739 p_vout->i_changes |= VOUT_FULLSCREEN_CHANGE;
750 else if( xevent.type == ButtonPress )
752 int i_width, i_height, i_x, i_y;
754 vout_PlacePicture( p_vout, p_vout->p_sys->p_win->i_width,
755 p_vout->p_sys->p_win->i_height,
756 &i_x, &i_y, &i_width, &i_height );
758 p_vout->i_mouse_x = ( xevent.xmotion.x - i_x )
759 * p_vout->render.i_width / i_width;
760 p_vout->i_mouse_y = ( xevent.xmotion.y - i_y )
761 * p_vout->render.i_height / i_height;
762 p_vout->i_mouse_button = 1;
764 switch( ((XButtonEvent *)&xevent)->button )
767 /* In this part we will eventually manage
768 * clicks for DVD navigation for instance. */
770 /* detect double-clicks */
771 if( ( ((XButtonEvent *)&xevent)->time -
772 p_vout->p_sys->i_time_button_last_pressed ) < 300 )
774 p_vout->i_changes |= VOUT_FULLSCREEN_CHANGE;
777 p_vout->p_sys->i_time_button_last_pressed =
778 ((XButtonEvent *)&xevent)->time;
782 input_Seek( p_vout, 15, INPUT_SEEK_SECONDS | INPUT_SEEK_CUR );
786 input_Seek( p_vout, -15, INPUT_SEEK_SECONDS | INPUT_SEEK_CUR );
791 else if( xevent.type == ButtonRelease )
793 switch( ((XButtonEvent *)&xevent)->button )
797 intf_thread_t *p_intf;
798 p_intf = vlc_object_find( p_vout, VLC_OBJECT_INTF,
802 p_intf->b_menu_change = 1;
803 vlc_object_release( p_intf );
810 else if( xevent.type == MotionNotify )
812 int i_width, i_height, i_x, i_y;
814 /* somewhat different use for vout_PlacePicture:
815 * here the values are needed to give to mouse coordinates
816 * in the original picture space */
817 vout_PlacePicture( p_vout, p_vout->p_sys->p_win->i_width,
818 p_vout->p_sys->p_win->i_height,
819 &i_x, &i_y, &i_width, &i_height );
821 p_vout->i_mouse_x = ( xevent.xmotion.x - i_x )
822 * p_vout->render.i_width / i_width;
823 p_vout->i_mouse_y = ( xevent.xmotion.y - i_y )
824 * p_vout->render.i_height / i_height;
826 p_vout->p_sys->i_time_mouse_last_moved = mdate();
827 if( ! p_vout->p_sys->b_mouse_pointer_visible )
829 ToggleCursor( p_vout );
832 /* Reparent move -- XXX: why are we getting this ? */
833 else if( xevent.type == ReparentNotify )
840 msg_Warn( p_vout, "unhandled event %d received", xevent.type );
844 /* Handle events for video output sub-window */
845 while( XCheckWindowEvent( p_vout->p_sys->p_display,
846 p_vout->p_sys->p_win->video_window,
847 ExposureMask, &xevent ) == True )
849 /* Window exposed (only handled if stream playback is paused) */
850 if( xevent.type == Expose )
852 if( ((XExposeEvent *)&xevent)->count == 0 )
854 /* (if this is the last a collection of expose events...) */
856 if( p_vout->p_vlc->p_input_bank->pp_input[0] != NULL )
858 if( PAUSE_S == p_vout->p_vlc->p_input_bank->pp_input[0]
859 ->stream.control.i_status )
861 /* XVideoDisplay( p_vout )*/;
869 /* ClientMessage event - only WM_PROTOCOLS with WM_DELETE_WINDOW data
870 * are handled - according to the man pages, the format is always 32
872 while( XCheckTypedEvent( p_vout->p_sys->p_display,
873 ClientMessage, &xevent ) )
875 if( (xevent.xclient.message_type == p_vout->p_sys->p_win->wm_protocols)
876 && (xevent.xclient.data.l[0]
877 == p_vout->p_sys->p_win->wm_delete_window ) )
879 p_vout->p_vlc->b_die = 1;
886 if ( p_vout->i_changes & VOUT_FULLSCREEN_CHANGE )
888 ToggleFullScreen( p_vout );
889 p_vout->i_changes &= ~VOUT_FULLSCREEN_CHANGE;
895 * (Needs to be placed after VOUT_FULLSREEN_CHANGE because we can activate
896 * the size flag inside the fullscreen routine)
898 if( p_vout->i_changes & VOUT_SIZE_CHANGE )
900 int i_width, i_height, i_x, i_y;
902 p_vout->i_changes &= ~VOUT_SIZE_CHANGE;
904 msg_Dbg( p_vout, "video display resized (%dx%d)",
905 p_vout->p_sys->p_win->i_width,
906 p_vout->p_sys->p_win->i_height );
908 #ifdef MODULE_NAME_IS_x11
909 /* We need to signal the vout thread about the size change because it
910 * is doing the rescaling */
911 p_vout->i_changes |= VOUT_SIZE_CHANGE;
914 vout_PlacePicture( p_vout, p_vout->p_sys->p_win->i_width,
915 p_vout->p_sys->p_win->i_height,
916 &i_x, &i_y, &i_width, &i_height );
918 XResizeWindow( p_vout->p_sys->p_display,
919 p_vout->p_sys->p_win->video_window, i_width, i_height );
921 XMoveWindow( p_vout->p_sys->p_display,
922 p_vout->p_sys->p_win->video_window, i_x, i_y );
925 /* Autohide Cursour */
926 if( mdate() - p_vout->p_sys->i_time_mouse_last_moved > 2000000 )
928 /* Hide the mouse automatically */
929 if( p_vout->p_sys->b_mouse_pointer_visible )
931 ToggleCursor( p_vout );
938 /*****************************************************************************
939 * vout_End: terminate X11 video thread output method
940 *****************************************************************************
941 * Destroy the X11 XImages created by vout_Init. It is called at the end of
942 * the thread, but also each time the window is resized.
943 *****************************************************************************/
944 static void vout_End( vout_thread_t *p_vout )
948 /* Free the direct buffers we allocated */
949 for( i_index = I_OUTPUTPICTURES ; i_index ; )
952 FreePicture( p_vout, PP_OUTPUTPICTURE[ i_index ] );
956 /* following functions are local */
958 /*****************************************************************************
959 * CreateWindow: open and set-up X11 main window
960 *****************************************************************************/
961 static int CreateWindow( vout_thread_t *p_vout, x11_window_t *p_win )
963 XSizeHints xsize_hints;
964 XSetWindowAttributes xwindow_attributes;
969 vlc_bool_t b_configure_notify;
970 vlc_bool_t b_map_notify;
972 long long int i_drawable;
974 /* Prepare window manager hints and properties */
975 xsize_hints.base_width = p_win->i_width;
976 xsize_hints.base_height = p_win->i_height;
977 xsize_hints.flags = PSize;
978 p_win->wm_protocols =
979 XInternAtom( p_vout->p_sys->p_display, "WM_PROTOCOLS", True );
980 p_win->wm_delete_window =
981 XInternAtom( p_vout->p_sys->p_display, "WM_DELETE_WINDOW", True );
983 /* Prepare window attributes */
984 xwindow_attributes.backing_store = Always; /* save the hidden part */
985 xwindow_attributes.background_pixel = BlackPixel(p_vout->p_sys->p_display,
986 p_vout->p_sys->i_screen);
987 xwindow_attributes.event_mask = ExposureMask | StructureNotifyMask;
989 /* Check whether someone provided us with a window ID */
990 i_drawable = p_vout->b_fullscreen ?
991 -1 : config_GetInt( p_vout, MODULE_STRING "-drawable");
993 if( i_drawable == -1 )
995 p_vout->p_sys->b_createwindow = 1;
997 /* Create the window and set hints - the window must receive
998 * ConfigureNotify events, and until it is displayed, Expose and
999 * MapNotify events. */
1001 p_win->base_window =
1002 XCreateWindow( p_vout->p_sys->p_display,
1003 DefaultRootWindow( p_vout->p_sys->p_display ),
1005 p_win->i_width, p_win->i_height,
1008 CWBackingStore | CWBackPixel | CWEventMask,
1009 &xwindow_attributes );
1011 if( !p_vout->b_fullscreen )
1013 /* Set window manager hints and properties: size hints, command,
1014 * window's name, and accepted protocols */
1015 XSetWMNormalHints( p_vout->p_sys->p_display,
1016 p_win->base_window, &xsize_hints );
1017 XSetCommand( p_vout->p_sys->p_display, p_win->base_window,
1018 p_vout->p_vlc->ppsz_argv, p_vout->p_vlc->i_argc );
1020 XStoreName( p_vout->p_sys->p_display, p_win->base_window,
1021 #ifdef MODULE_NAME_IS_x11
1022 VOUT_TITLE " (X11 output)"
1024 VOUT_TITLE " (XVideo output)"
1031 p_vout->p_sys->b_createwindow = 0;
1032 p_win->base_window = i_drawable;
1034 XChangeWindowAttributes( p_vout->p_sys->p_display,
1036 CWBackingStore | CWBackPixel | CWEventMask,
1037 &xwindow_attributes );
1040 if( (p_win->wm_protocols == None) /* use WM_DELETE_WINDOW */
1041 || (p_win->wm_delete_window == None)
1042 || !XSetWMProtocols( p_vout->p_sys->p_display, p_win->base_window,
1043 &p_win->wm_delete_window, 1 ) )
1045 /* WM_DELETE_WINDOW is not supported by window manager */
1046 msg_Warn( p_vout, "missing or bad window manager" );
1049 /* Creation of a graphic context that doesn't generate a GraphicsExpose
1050 * event when using functions like XCopyArea */
1051 xgcvalues.graphics_exposures = False;
1052 p_win->gc = XCreateGC( p_vout->p_sys->p_display,
1054 GCGraphicsExposures, &xgcvalues );
1056 if( p_vout->p_sys->b_createwindow )
1058 /* Send orders to server, and wait until window is displayed - three
1059 * events must be received: a MapNotify event, an Expose event allowing
1060 * drawing in the window, and a ConfigureNotify to get the window
1061 * dimensions. Once those events have been received, only
1062 * ConfigureNotify events need to be received. */
1064 b_configure_notify = 0;
1066 XMapWindow( p_vout->p_sys->p_display, p_win->base_window );
1069 XNextEvent( p_vout->p_sys->p_display, &xevent);
1070 if( (xevent.type == Expose)
1071 && (xevent.xexpose.window == p_win->base_window) )
1075 else if( (xevent.type == MapNotify)
1076 && (xevent.xmap.window == p_win->base_window) )
1080 else if( (xevent.type == ConfigureNotify)
1081 && (xevent.xconfigure.window == p_win->base_window) )
1083 b_configure_notify = 1;
1084 p_win->i_width = xevent.xconfigure.width;
1085 p_win->i_height = xevent.xconfigure.height;
1087 } while( !( b_expose && b_configure_notify && b_map_notify ) );
1091 /* Get the window's geometry information */
1093 unsigned int dummy2, dummy3;
1094 XGetGeometry( p_vout->p_sys->p_display, p_win->base_window,
1095 &dummy1, &dummy2, &dummy3,
1101 XSelectInput( p_vout->p_sys->p_display, p_win->base_window,
1102 StructureNotifyMask | KeyPressMask |
1103 ButtonPressMask | ButtonReleaseMask |
1104 PointerMotionMask );
1106 #ifdef MODULE_NAME_IS_x11
1107 if( p_vout->p_sys->b_createwindow &&
1108 XDefaultDepth(p_vout->p_sys->p_display, p_vout->p_sys->i_screen) == 8 )
1110 /* Allocate a new palette */
1111 p_vout->p_sys->colormap =
1112 XCreateColormap( p_vout->p_sys->p_display,
1113 DefaultRootWindow( p_vout->p_sys->p_display ),
1114 DefaultVisual( p_vout->p_sys->p_display,
1115 p_vout->p_sys->i_screen ),
1118 xwindow_attributes.colormap = p_vout->p_sys->colormap;
1119 XChangeWindowAttributes( p_vout->p_sys->p_display, p_win->base_window,
1120 CWColormap, &xwindow_attributes );
1124 /* Create video output sub-window. */
1125 p_win->video_window = XCreateSimpleWindow(
1126 p_vout->p_sys->p_display,
1127 p_win->base_window, 0, 0,
1128 p_win->i_width, p_win->i_height,
1130 BlackPixel( p_vout->p_sys->p_display,
1131 p_vout->p_sys->i_screen ),
1132 WhitePixel( p_vout->p_sys->p_display,
1133 p_vout->p_sys->i_screen ) );
1135 XSetWindowBackground( p_vout->p_sys->p_display, p_win->video_window,
1136 BlackPixel( p_vout->p_sys->p_display,
1137 p_vout->p_sys->i_screen ) );
1139 XMapWindow( p_vout->p_sys->p_display, p_win->video_window );
1140 XSelectInput( p_vout->p_sys->p_display, p_win->video_window,
1143 /* make sure the video window will be centered in the next vout_Manage() */
1144 p_vout->i_changes |= VOUT_SIZE_CHANGE;
1146 /* If the cursor was formerly blank than blank it again */
1147 if( !p_vout->p_sys->b_mouse_pointer_visible )
1149 ToggleCursor( p_vout );
1150 ToggleCursor( p_vout );
1153 /* Do NOT use XFlush here ! */
1154 XSync( p_vout->p_sys->p_display, False );
1156 /* At this stage, the window is open, displayed, and ready to
1158 p_vout->p_sys->p_win = p_win;
1163 /*****************************************************************************
1164 * DestroyWindow: destroy the window
1165 *****************************************************************************
1167 *****************************************************************************/
1168 static void DestroyWindow( vout_thread_t *p_vout, x11_window_t *p_win )
1170 /* Do NOT use XFlush here ! */
1171 XSync( p_vout->p_sys->p_display, False );
1173 XDestroyWindow( p_vout->p_sys->p_display, p_win->video_window );
1174 XUnmapWindow( p_vout->p_sys->p_display, p_win->base_window );
1175 XFreeGC( p_vout->p_sys->p_display, p_win->gc );
1176 XDestroyWindow( p_vout->p_sys->p_display, p_win->base_window );
1179 /*****************************************************************************
1180 * NewPicture: allocate a picture
1181 *****************************************************************************
1182 * Returns 0 on success, -1 otherwise
1183 *****************************************************************************/
1184 static int NewPicture( vout_thread_t *p_vout, picture_t *p_pic )
1186 /* We know the chroma, allocate a buffer which will be used
1187 * directly by the decoder */
1188 p_pic->p_sys = malloc( sizeof( picture_sys_t ) );
1190 if( p_pic->p_sys == NULL )
1195 #ifdef HAVE_SYS_SHM_H
1196 if( p_vout->p_sys->b_shm )
1198 /* Create image using XShm extension */
1199 p_pic->p_sys->p_image =
1200 CreateShmImage( p_vout, p_vout->p_sys->p_display,
1201 # ifdef MODULE_NAME_IS_xvideo
1202 p_vout->p_sys->i_xvport, p_vout->output.i_chroma,
1204 p_vout->p_sys->p_visual,
1205 p_vout->p_sys->i_screen_depth,
1207 &p_pic->p_sys->shminfo,
1208 p_vout->output.i_width, p_vout->output.i_height );
1211 #endif /* HAVE_SYS_SHM_H */
1213 /* Create image without XShm extension */
1214 p_pic->p_sys->p_image =
1215 CreateImage( p_vout, p_vout->p_sys->p_display,
1216 #ifdef MODULE_NAME_IS_xvideo
1217 p_vout->p_sys->i_xvport, p_vout->output.i_chroma,
1219 p_vout->p_sys->p_visual,
1220 p_vout->p_sys->i_screen_depth,
1221 p_vout->p_sys->i_bytes_per_pixel,
1223 p_vout->output.i_width, p_vout->output.i_height );
1226 if( p_pic->p_sys->p_image == NULL )
1228 free( p_pic->p_sys );
1232 switch( p_vout->output.i_chroma )
1234 #ifdef MODULE_NAME_IS_xvideo
1237 p_pic->Y_PIXELS = p_pic->p_sys->p_image->data
1238 + p_pic->p_sys->p_image->offsets[0];
1239 p_pic->p[Y_PLANE].i_lines = p_vout->output.i_height;
1240 p_pic->p[Y_PLANE].i_pitch = p_pic->p_sys->p_image->pitches[0];
1241 p_pic->p[Y_PLANE].i_pixel_bytes = 1;
1242 p_pic->p[Y_PLANE].b_margin = 0;
1244 p_pic->U_PIXELS = p_pic->p_sys->p_image->data
1245 + p_pic->p_sys->p_image->offsets[1];
1246 p_pic->p[U_PLANE].i_lines = p_vout->output.i_height / 2;
1247 p_pic->p[U_PLANE].i_pitch = p_pic->p_sys->p_image->pitches[1];
1248 p_pic->p[U_PLANE].i_pixel_bytes = 1;
1249 p_pic->p[U_PLANE].b_margin = 0;
1251 p_pic->V_PIXELS = p_pic->p_sys->p_image->data
1252 + p_pic->p_sys->p_image->offsets[2];
1253 p_pic->p[V_PLANE].i_lines = p_vout->output.i_height / 2;
1254 p_pic->p[V_PLANE].i_pitch = p_pic->p_sys->p_image->pitches[2];
1255 p_pic->p[V_PLANE].i_pixel_bytes = 1;
1256 p_pic->p[V_PLANE].b_margin = 0;
1258 p_pic->i_planes = 3;
1263 p_pic->Y_PIXELS = p_pic->p_sys->p_image->data
1264 + p_pic->p_sys->p_image->offsets[0];
1265 p_pic->p[Y_PLANE].i_lines = p_vout->output.i_height;
1266 p_pic->p[Y_PLANE].i_pitch = p_pic->p_sys->p_image->pitches[0];
1267 p_pic->p[Y_PLANE].i_pixel_bytes = 1;
1268 p_pic->p[Y_PLANE].b_margin = 0;
1270 p_pic->U_PIXELS = p_pic->p_sys->p_image->data
1271 + p_pic->p_sys->p_image->offsets[2];
1272 p_pic->p[U_PLANE].i_lines = p_vout->output.i_height / 2;
1273 p_pic->p[U_PLANE].i_pitch = p_pic->p_sys->p_image->pitches[2];
1274 p_pic->p[U_PLANE].i_pixel_bytes = 1;
1275 p_pic->p[U_PLANE].b_margin = 0;
1277 p_pic->V_PIXELS = p_pic->p_sys->p_image->data
1278 + p_pic->p_sys->p_image->offsets[1];
1279 p_pic->p[V_PLANE].i_lines = p_vout->output.i_height / 2;
1280 p_pic->p[V_PLANE].i_pitch = p_pic->p_sys->p_image->pitches[1];
1281 p_pic->p[V_PLANE].i_pixel_bytes = 1;
1282 p_pic->p[V_PLANE].b_margin = 0;
1284 p_pic->i_planes = 3;
1289 p_pic->p->p_pixels = p_pic->p_sys->p_image->data
1290 + p_pic->p_sys->p_image->offsets[0];
1291 p_pic->p->i_lines = p_vout->output.i_height;
1292 /* XXX: this just looks so plain wrong... check it out ! */
1293 p_pic->p->i_pitch = p_pic->p_sys->p_image->pitches[0] / 4;
1294 p_pic->p->i_pixel_bytes = 4;
1295 p_pic->p->b_margin = 0;
1297 p_pic->i_planes = 1;
1303 p_pic->p->p_pixels = p_pic->p_sys->p_image->data
1304 + p_pic->p_sys->p_image->offsets[0];
1305 p_pic->p->i_lines = p_vout->output.i_height;
1306 p_pic->p->i_pitch = p_pic->p_sys->p_image->pitches[0];
1307 p_pic->p->i_pixel_bytes = 4;
1308 p_pic->p->b_margin = 0;
1310 p_pic->i_planes = 1;
1315 p_pic->p->p_pixels = p_pic->p_sys->p_image->data
1316 + p_pic->p_sys->p_image->offsets[0];
1317 p_pic->p->i_lines = p_vout->output.i_height;
1318 p_pic->p->i_pitch = p_pic->p_sys->p_image->pitches[0];
1319 p_pic->p->i_pixel_bytes = 2;
1320 p_pic->p->b_margin = 0;
1322 p_pic->i_planes = 1;
1327 p_pic->p->p_pixels = p_pic->p_sys->p_image->data
1328 + p_pic->p_sys->p_image->offsets[0];
1329 p_pic->p->i_lines = p_vout->output.i_height;
1330 p_pic->p->i_pitch = p_pic->p_sys->p_image->pitches[0];
1331 p_pic->p->i_pixel_bytes = 2;
1332 p_pic->p->b_margin = 0;
1334 p_pic->i_planes = 1;
1340 p_pic->p->p_pixels = p_pic->p_sys->p_image->data
1341 + p_pic->p_sys->p_image->xoffset;
1342 p_pic->p->i_lines = p_pic->p_sys->p_image->height;
1343 p_pic->p->i_pitch = p_pic->p_sys->p_image->bytes_per_line;
1344 p_pic->p->i_pixel_bytes = p_pic->p_sys->p_image->depth;
1346 if( p_pic->p->i_pitch == p_pic->p_sys->p_image->width )
1348 p_pic->p->b_margin = 0;
1352 p_pic->p->b_margin = 1;
1353 p_pic->p->b_hidden = 1;
1354 p_pic->p->i_visible_bytes = p_pic->p_sys->p_image->width;
1357 p_pic->i_planes = 1;
1364 p_pic->p->p_pixels = p_pic->p_sys->p_image->data
1365 + p_pic->p_sys->p_image->xoffset;
1366 p_pic->p->i_lines = p_pic->p_sys->p_image->height;
1367 p_pic->p->i_pitch = p_pic->p_sys->p_image->bytes_per_line;
1368 p_pic->p->i_pixel_bytes = p_pic->p_sys->p_image->depth;
1370 if( p_pic->p->i_pitch == 2 * p_pic->p_sys->p_image->width )
1372 p_pic->p->b_margin = 0;
1376 p_pic->p->b_margin = 1;
1377 p_pic->p->b_hidden = 1;
1378 p_pic->p->i_visible_bytes = 2 * p_pic->p_sys->p_image->width;
1381 p_pic->i_planes = 1;
1388 p_pic->p->p_pixels = p_pic->p_sys->p_image->data
1389 + p_pic->p_sys->p_image->xoffset;
1390 p_pic->p->i_lines = p_pic->p_sys->p_image->height;
1391 p_pic->p->i_pitch = p_pic->p_sys->p_image->bytes_per_line;
1392 p_pic->p->i_pixel_bytes = p_pic->p_sys->p_image->depth;
1394 if( p_pic->p->i_pitch == 4 * p_pic->p_sys->p_image->width )
1396 p_pic->p->b_margin = 0;
1400 p_pic->p->b_margin = 1;
1401 p_pic->p->b_hidden = 1;
1402 p_pic->p->i_visible_bytes = 4 * p_pic->p_sys->p_image->width;
1405 p_pic->i_planes = 1;
1411 /* Unknown chroma, tell the guy to get lost */
1412 IMAGE_FREE( p_pic->p_sys->p_image );
1413 free( p_pic->p_sys );
1414 msg_Err( p_vout, "never heard of chroma 0x%.8x (%4.4s)",
1415 p_vout->output.i_chroma, (char*)&p_vout->output.i_chroma );
1416 p_pic->i_planes = 0;
1423 /*****************************************************************************
1424 * FreePicture: destroy a picture allocated with NewPicture
1425 *****************************************************************************
1426 * Destroy XImage AND associated data. If using Shm, detach shared memory
1427 * segment from server and process, then free it. The XDestroyImage manpage
1428 * says that both the image structure _and_ the data pointed to by the
1429 * image structure are freed, so no need to free p_image->data.
1430 *****************************************************************************/
1431 static void FreePicture( vout_thread_t *p_vout, picture_t *p_pic )
1433 /* The order of operations is correct */
1434 #ifdef HAVE_SYS_SHM_H
1435 if( p_vout->p_sys->b_shm )
1437 XShmDetach( p_vout->p_sys->p_display, &p_pic->p_sys->shminfo );
1438 IMAGE_FREE( p_pic->p_sys->p_image );
1440 shmctl( p_pic->p_sys->shminfo.shmid, IPC_RMID, 0 );
1441 if( shmdt( p_pic->p_sys->shminfo.shmaddr ) )
1443 msg_Err( p_vout, "cannot detach shared memory (%s)",
1450 IMAGE_FREE( p_pic->p_sys->p_image );
1453 /* Do NOT use XFlush here ! */
1454 XSync( p_vout->p_sys->p_display, False );
1456 free( p_pic->p_sys );
1459 /*****************************************************************************
1460 * ToggleFullScreen: Enable or disable full screen mode
1461 *****************************************************************************
1462 * This function will switch between fullscreen and window mode.
1463 *****************************************************************************/
1464 static void ToggleFullScreen ( vout_thread_t *p_vout )
1467 mwmhints_t mwmhints;
1468 XSetWindowAttributes attributes;
1470 p_vout->b_fullscreen = !p_vout->b_fullscreen;
1472 if( p_vout->b_fullscreen )
1474 msg_Dbg( p_vout, "entering fullscreen mode" );
1475 p_vout->p_sys->p_win = &p_vout->p_sys->fullscreen_window;
1477 /* Only check the fullscreen method when we actually go fullscreen,
1478 * because to go back to window mode we need to know in which
1479 * fullscreen mode we were */
1480 p_vout->p_sys->b_altfullscreen =
1481 config_GetInt( p_vout, MODULE_STRING "-altfullscreen" );
1483 /* fullscreen window size and position */
1484 p_vout->p_sys->p_win->i_width =
1485 DisplayWidth( p_vout->p_sys->p_display, p_vout->p_sys->i_screen );
1486 p_vout->p_sys->p_win->i_height =
1487 DisplayHeight( p_vout->p_sys->p_display, p_vout->p_sys->i_screen );
1489 CreateWindow( p_vout, p_vout->p_sys->p_win );
1491 /* To my knowledge there are two ways to create a borderless window.
1492 * There's the generic way which is to tell x to bypass the window
1493 * manager, but this creates problems with the focus of other
1495 * The other way is to use the motif property "_MOTIF_WM_HINTS" which
1496 * luckily seems to be supported by most window managers. */
1497 if( !p_vout->p_sys->b_altfullscreen )
1499 mwmhints.flags = MWM_HINTS_DECORATIONS;
1500 mwmhints.decorations = !p_vout->b_fullscreen;
1502 prop = XInternAtom( p_vout->p_sys->p_display, "_MOTIF_WM_HINTS",
1504 XChangeProperty( p_vout->p_sys->p_display,
1505 p_vout->p_sys->p_win->base_window,
1506 prop, prop, 32, PropModeReplace,
1507 (unsigned char *)&mwmhints,
1508 PROP_MWM_HINTS_ELEMENTS );
1512 /* brute force way to remove decorations */
1513 attributes.override_redirect = p_vout->b_fullscreen;
1514 XChangeWindowAttributes( p_vout->p_sys->p_display,
1515 p_vout->p_sys->p_win->base_window,
1520 XReparentWindow( p_vout->p_sys->p_display,
1521 p_vout->p_sys->p_win->base_window,
1522 DefaultRootWindow( p_vout->p_sys->p_display ),
1524 XMoveResizeWindow( p_vout->p_sys->p_display,
1525 p_vout->p_sys->p_win->base_window,
1527 p_vout->p_sys->p_win->i_width,
1528 p_vout->p_sys->p_win->i_height );
1532 msg_Dbg( p_vout, "leaving fullscreen mode" );
1533 DestroyWindow( p_vout, &p_vout->p_sys->fullscreen_window );
1534 p_vout->p_sys->p_win = &p_vout->p_sys->original_window;
1537 XSync( p_vout->p_sys->p_display, True );
1539 if( !p_vout->b_fullscreen || p_vout->p_sys->b_altfullscreen )
1541 XSetInputFocus(p_vout->p_sys->p_display,
1542 p_vout->p_sys->p_win->base_window,
1547 /* signal that the size needs to be updated */
1548 p_vout->i_changes |= VOUT_SIZE_CHANGE;
1551 /*****************************************************************************
1552 * EnableXScreenSaver: enable screen saver
1553 *****************************************************************************
1554 * This function enables the screen saver on a display after it has been
1555 * disabled by XDisableScreenSaver.
1556 * FIXME: what happens if multiple vlc sessions are running at the same
1558 *****************************************************************************/
1559 static void EnableXScreenSaver( vout_thread_t *p_vout )
1561 #ifdef DPMSINFO_IN_DPMS_H
1565 XSetScreenSaver( p_vout->p_sys->p_display, p_vout->p_sys->i_ss_timeout,
1566 p_vout->p_sys->i_ss_interval,
1567 p_vout->p_sys->i_ss_blanking,
1568 p_vout->p_sys->i_ss_exposure );
1570 /* Restore DPMS settings */
1571 #ifdef DPMSINFO_IN_DPMS_H
1572 if( DPMSQueryExtension( p_vout->p_sys->p_display, &dummy, &dummy ) )
1574 if( p_vout->p_sys->b_ss_dpms )
1576 DPMSEnable( p_vout->p_sys->p_display );
1582 /*****************************************************************************
1583 * DisableXScreenSaver: disable screen saver
1584 *****************************************************************************
1585 * See XEnableXScreenSaver
1586 *****************************************************************************/
1587 static void DisableXScreenSaver( vout_thread_t *p_vout )
1589 #ifdef DPMSINFO_IN_DPMS_H
1593 /* Save screen saver informations */
1594 XGetScreenSaver( p_vout->p_sys->p_display, &p_vout->p_sys->i_ss_timeout,
1595 &p_vout->p_sys->i_ss_interval,
1596 &p_vout->p_sys->i_ss_blanking,
1597 &p_vout->p_sys->i_ss_exposure );
1599 /* Disable screen saver */
1600 XSetScreenSaver( p_vout->p_sys->p_display, 0,
1601 p_vout->p_sys->i_ss_interval,
1602 p_vout->p_sys->i_ss_blanking,
1603 p_vout->p_sys->i_ss_exposure );
1606 #ifdef DPMSINFO_IN_DPMS_H
1607 if( DPMSQueryExtension( p_vout->p_sys->p_display, &dummy, &dummy ) )
1610 /* Save DPMS current state */
1611 DPMSInfo( p_vout->p_sys->p_display, &unused,
1612 &p_vout->p_sys->b_ss_dpms );
1613 DPMSDisable( p_vout->p_sys->p_display );
1618 /*****************************************************************************
1619 * CreateCursor: create a blank mouse pointer
1620 *****************************************************************************/
1621 static void CreateCursor( vout_thread_t *p_vout )
1623 XColor cursor_color;
1625 p_vout->p_sys->cursor_pixmap =
1626 XCreatePixmap( p_vout->p_sys->p_display,
1627 DefaultRootWindow( p_vout->p_sys->p_display ),
1630 XParseColor( p_vout->p_sys->p_display,
1631 XCreateColormap( p_vout->p_sys->p_display,
1633 p_vout->p_sys->p_display ),
1635 p_vout->p_sys->p_display,
1636 p_vout->p_sys->i_screen ),
1638 "black", &cursor_color );
1640 p_vout->p_sys->blank_cursor =
1641 XCreatePixmapCursor( p_vout->p_sys->p_display,
1642 p_vout->p_sys->cursor_pixmap,
1643 p_vout->p_sys->cursor_pixmap,
1644 &cursor_color, &cursor_color, 1, 1 );
1647 /*****************************************************************************
1648 * DestroyCursor: destroy the blank mouse pointer
1649 *****************************************************************************/
1650 static void DestroyCursor( vout_thread_t *p_vout )
1652 XFreePixmap( p_vout->p_sys->p_display, p_vout->p_sys->cursor_pixmap );
1655 /*****************************************************************************
1656 * ToggleCursor: hide or show the mouse pointer
1657 *****************************************************************************
1658 * This function hides the X pointer if it is visible by setting the pointer
1659 * sprite to a blank one. To show it again, we disable the sprite.
1660 *****************************************************************************/
1661 static void ToggleCursor( vout_thread_t *p_vout )
1663 if( p_vout->p_sys->b_mouse_pointer_visible )
1665 XDefineCursor( p_vout->p_sys->p_display,
1666 p_vout->p_sys->p_win->base_window,
1667 p_vout->p_sys->blank_cursor );
1668 p_vout->p_sys->b_mouse_pointer_visible = 0;
1672 XUndefineCursor( p_vout->p_sys->p_display,
1673 p_vout->p_sys->p_win->base_window );
1674 p_vout->p_sys->b_mouse_pointer_visible = 1;
1678 #ifdef MODULE_NAME_IS_xvideo
1679 /*****************************************************************************
1680 * XVideoGetPort: get YUV12 port
1681 *****************************************************************************/
1682 static int XVideoGetPort( vout_thread_t *p_vout,
1683 u32 i_chroma, u32 *pi_newchroma )
1685 XvAdaptorInfo *p_adaptor;
1687 int i_adaptor, i_num_adaptors, i_requested_adaptor;
1688 int i_selected_port;
1690 switch( XvQueryExtension( p_vout->p_sys->p_display, &i, &i, &i, &i, &i ) )
1695 case XvBadExtension:
1696 msg_Warn( p_vout, "XvBadExtension" );
1700 msg_Warn( p_vout, "XvBadAlloc" );
1704 msg_Warn( p_vout, "XvQueryExtension failed" );
1708 switch( XvQueryAdaptors( p_vout->p_sys->p_display,
1709 DefaultRootWindow( p_vout->p_sys->p_display ),
1710 &i_num_adaptors, &p_adaptor ) )
1715 case XvBadExtension:
1716 msg_Warn( p_vout, "XvBadExtension for XvQueryAdaptors" );
1720 msg_Warn( p_vout, "XvBadAlloc for XvQueryAdaptors" );
1724 msg_Warn( p_vout, "XvQueryAdaptors failed" );
1728 i_selected_port = -1;
1729 i_requested_adaptor = config_GetInt( p_vout, "xvideo-adaptor" );
1731 for( i_adaptor = 0; i_adaptor < i_num_adaptors; ++i_adaptor )
1733 XvImageFormatValues *p_formats;
1734 int i_format, i_num_formats;
1737 /* If we requested an adaptor and it's not this one, we aren't
1739 if( i_requested_adaptor != -1 && i_adaptor != i_requested_adaptor )
1744 /* If the adaptor doesn't have the required properties, skip it */
1745 if( !( p_adaptor[ i_adaptor ].type & XvInputMask ) ||
1746 !( p_adaptor[ i_adaptor ].type & XvImageMask ) )
1751 /* Check that adaptor supports our requested format... */
1752 p_formats = XvListImageFormats( p_vout->p_sys->p_display,
1753 p_adaptor[i_adaptor].base_id,
1757 i_format < i_num_formats && ( i_selected_port == -1 );
1760 /* Code removed, we can get this through xvinfo anyway */
1762 XvEncodingInfo *p_enc;
1763 int i_enc, i_num_encodings;
1764 XvAttribute *p_attr;
1765 int i_attr, i_num_attributes;
1768 /* If this is not the format we want, or at least a
1769 * similar one, forget it */
1770 if( !vout_ChromaCmp( p_formats[ i_format ].id, i_chroma ) )
1775 /* Look for the first available port supporting this format */
1776 for( i_port = p_adaptor[i_adaptor].base_id;
1777 ( i_port < p_adaptor[i_adaptor].base_id
1778 + p_adaptor[i_adaptor].num_ports )
1779 && ( i_selected_port == -1 );
1782 if( XvGrabPort( p_vout->p_sys->p_display, i_port, CurrentTime )
1785 i_selected_port = i_port;
1786 *pi_newchroma = p_formats[ i_format ].id;
1790 /* If no free port was found, forget it */
1791 if( i_selected_port == -1 )
1796 /* If we found a port, print information about it */
1797 msg_Dbg( p_vout, "adaptor %i, port %i, format 0x%x (%4.4s) %s",
1798 i_adaptor, i_selected_port, p_formats[ i_format ].id,
1799 (char *)&p_formats[ i_format ].id,
1800 ( p_formats[ i_format ].format == XvPacked ) ?
1801 "packed" : "planar" );
1804 msg_Dbg( p_vout, " encoding list:" );
1806 if( XvQueryEncodings( p_vout->p_sys->p_display, i_selected_port,
1807 &i_num_encodings, &p_enc )
1810 msg_Dbg( p_vout, " XvQueryEncodings failed" );
1814 for( i_enc = 0; i_enc < i_num_encodings; i_enc++ )
1816 msg_Dbg( p_vout, " id=%ld, name=%s, size=%ldx%ld,"
1817 " numerator=%d, denominator=%d",
1818 p_enc[i_enc].encoding_id, p_enc[i_enc].name,
1819 p_enc[i_enc].width, p_enc[i_enc].height,
1820 p_enc[i_enc].rate.numerator,
1821 p_enc[i_enc].rate.denominator );
1826 XvFreeEncodingInfo( p_enc );
1829 msg_Dbg( p_vout, " attribute list:" );
1830 p_attr = XvQueryPortAttributes( p_vout->p_sys->p_display,
1832 &i_num_attributes );
1833 for( i_attr = 0; i_attr < i_num_attributes; i_attr++ )
1835 msg_Dbg( p_vout, " name=%s, flags=[%s%s ], min=%i, max=%i",
1836 p_attr[i_attr].name,
1837 (p_attr[i_attr].flags & XvGettable) ? " get" : "",
1838 (p_attr[i_attr].flags & XvSettable) ? " set" : "",
1839 p_attr[i_attr].min_value, p_attr[i_attr].max_value );
1842 if( p_attr != NULL )
1849 if( p_formats != NULL )
1856 if( i_num_adaptors > 0 )
1858 XvFreeAdaptorInfo( p_adaptor );
1861 if( i_selected_port == -1 )
1863 if( i_requested_adaptor == -1 )
1865 msg_Warn( p_vout, "no free XVideo port found for format "
1866 "0x%.8x (%4.4s)", i_chroma, (char*)&i_chroma );
1870 msg_Warn( p_vout, "XVideo adaptor %i does not have a free "
1871 "XVideo port for format 0x%.8x (%4.4s)",
1872 i_requested_adaptor, i_chroma, (char*)&i_chroma );
1876 return( i_selected_port );
1879 /*****************************************************************************
1880 * XVideoReleasePort: release YUV12 port
1881 *****************************************************************************/
1882 static void XVideoReleasePort( vout_thread_t *p_vout, int i_port )
1884 XvUngrabPort( p_vout->p_sys->p_display, i_port, CurrentTime );
1888 /*****************************************************************************
1889 * InitDisplay: open and initialize X11 device
1890 *****************************************************************************
1891 * Create a window according to video output given size, and set other
1892 * properties according to the display properties.
1893 *****************************************************************************/
1894 static int InitDisplay( vout_thread_t *p_vout )
1896 #ifdef MODULE_NAME_IS_x11
1897 XPixmapFormatValues * p_formats; /* pixmap formats */
1898 XVisualInfo * p_xvisual; /* visuals informations */
1899 XVisualInfo xvisual_template; /* visual template */
1900 int i_count; /* array size */
1903 #ifdef HAVE_SYS_SHM_H
1904 p_vout->p_sys->b_shm = 0;
1906 if( config_GetInt( p_vout, MODULE_STRING "-shm" ) )
1909 /* FIXME: As of 2001-03-16, XFree4 for MacOS X does not support Xshm */
1911 p_vout->p_sys->b_shm =
1912 ( XShmQueryExtension( p_vout->p_sys->p_display ) == True );
1915 if( !p_vout->p_sys->b_shm )
1917 msg_Warn( p_vout, "XShm video extension is unavailable" );
1922 msg_Dbg( p_vout, "disabling XShm video extension" );
1926 msg_Warn( p_vout, "XShm video extension is unavailable" );
1930 #ifdef MODULE_NAME_IS_xvideo
1931 /* XXX The brightness and contrast values should be read from environment
1932 * XXX variables... */
1934 XVideoSetAttribute( p_vout, "XV_BRIGHTNESS", 0.5 );
1935 XVideoSetAttribute( p_vout, "XV_CONTRAST", 0.5 );
1939 #ifdef MODULE_NAME_IS_x11
1940 /* Initialize structure */
1941 p_vout->p_sys->i_screen = DefaultScreen( p_vout->p_sys->p_display );
1943 /* Get screen depth */
1944 p_vout->p_sys->i_screen_depth = XDefaultDepth( p_vout->p_sys->p_display,
1945 p_vout->p_sys->i_screen );
1946 switch( p_vout->p_sys->i_screen_depth )
1950 * Screen depth is 8bpp. Use PseudoColor visual with private colormap.
1952 xvisual_template.screen = p_vout->p_sys->i_screen;
1953 xvisual_template.class = DirectColor;
1954 p_xvisual = XGetVisualInfo( p_vout->p_sys->p_display,
1955 VisualScreenMask | VisualClassMask,
1956 &xvisual_template, &i_count );
1957 if( p_xvisual == NULL )
1959 msg_Err( p_vout, "no PseudoColor visual available" );
1962 p_vout->p_sys->i_bytes_per_pixel = 1;
1963 p_vout->output.pf_setpalette = SetPalette;
1970 * Screen depth is higher than 8bpp. TrueColor visual is used.
1972 xvisual_template.screen = p_vout->p_sys->i_screen;
1973 xvisual_template.class = TrueColor;
1974 p_xvisual = XGetVisualInfo( p_vout->p_sys->p_display,
1975 VisualScreenMask | VisualClassMask,
1976 &xvisual_template, &i_count );
1977 if( p_xvisual == NULL )
1979 msg_Err( p_vout, "no TrueColor visual available" );
1983 p_vout->output.i_rmask = p_xvisual->red_mask;
1984 p_vout->output.i_gmask = p_xvisual->green_mask;
1985 p_vout->output.i_bmask = p_xvisual->blue_mask;
1987 /* There is no difference yet between 3 and 4 Bpp. The only way
1988 * to find the actual number of bytes per pixel is to list supported
1989 * pixmap formats. */
1990 p_formats = XListPixmapFormats( p_vout->p_sys->p_display, &i_count );
1991 p_vout->p_sys->i_bytes_per_pixel = 0;
1993 for( ; i_count-- ; p_formats++ )
1995 /* Under XFree4.0, the list contains pixmap formats available
1996 * through all video depths ; so we have to check against current
1998 if( p_formats->depth == p_vout->p_sys->i_screen_depth )
2000 if( p_formats->bits_per_pixel / 8
2001 > p_vout->p_sys->i_bytes_per_pixel )
2003 p_vout->p_sys->i_bytes_per_pixel = p_formats->bits_per_pixel / 8;
2009 p_vout->p_sys->p_visual = p_xvisual->visual;
2016 #ifdef HAVE_SYS_SHM_H
2017 /*****************************************************************************
2018 * CreateShmImage: create an XImage or XvImage using shared memory extension
2019 *****************************************************************************
2020 * Prepare an XImage or XvImage for display function.
2021 * The order of the operations respects the recommandations of the mit-shm
2022 * document by J.Corbet and K.Packard. Most of the parameters were copied from
2023 * there. See http://ftp.xfree86.org/pub/XFree86/4.0/doc/mit-shm.TXT
2024 *****************************************************************************/
2025 static IMAGE_TYPE * CreateShmImage( vout_thread_t *p_vout,
2026 Display* p_display, EXTRA_ARGS_SHM,
2027 int i_width, int i_height )
2029 IMAGE_TYPE *p_image;
2031 /* Create XImage / XvImage */
2032 #ifdef MODULE_NAME_IS_xvideo
2033 p_image = XvShmCreateImage( p_display, i_xvport, i_chroma, 0,
2034 i_width, i_height, p_shm );
2036 p_image = XShmCreateImage( p_display, p_visual, i_depth, ZPixmap, 0,
2037 p_shm, i_width, i_height );
2039 if( p_image == NULL )
2041 msg_Err( p_vout, "image creation failed" );
2045 /* Allocate shared memory segment - 0776 set the access permission
2046 * rights (like umask), they are not yet supported by all X servers */
2047 p_shm->shmid = shmget( IPC_PRIVATE, DATA_SIZE(p_image), IPC_CREAT | 0776 );
2048 if( p_shm->shmid < 0 )
2050 msg_Err( p_vout, "cannot allocate shared image data (%s)",
2051 strerror( errno ) );
2052 IMAGE_FREE( p_image );
2056 /* Attach shared memory segment to process (read/write) */
2057 p_shm->shmaddr = p_image->data = shmat( p_shm->shmid, 0, 0 );
2058 if(! p_shm->shmaddr )
2060 msg_Err( p_vout, "cannot attach shared memory (%s)",
2062 IMAGE_FREE( p_image );
2063 shmctl( p_shm->shmid, IPC_RMID, 0 );
2067 /* Read-only data. We won't be using XShmGetImage */
2068 p_shm->readOnly = True;
2070 /* Attach shared memory segment to X server */
2071 if( XShmAttach( p_display, p_shm ) == False )
2073 msg_Err( p_vout, "cannot attach shared memory to X server" );
2074 IMAGE_FREE( p_image );
2075 shmctl( p_shm->shmid, IPC_RMID, 0 );
2076 shmdt( p_shm->shmaddr );
2080 /* Send image to X server. This instruction is required, since having
2081 * built a Shm XImage and not using it causes an error on XCloseDisplay,
2082 * and remember NOT to use XFlush ! */
2083 XSync( p_display, False );
2086 /* Mark the shm segment to be removed when there are no more
2087 * attachements, so it is automatic on process exit or after shmdt */
2088 shmctl( p_shm->shmid, IPC_RMID, 0 );
2095 /*****************************************************************************
2096 * CreateImage: create an XImage or XvImage
2097 *****************************************************************************
2098 * Create a simple image used as a buffer.
2099 *****************************************************************************/
2100 static IMAGE_TYPE * CreateImage( vout_thread_t *p_vout,
2101 Display *p_display, EXTRA_ARGS,
2102 int i_width, int i_height )
2104 byte_t * p_data; /* image data storage zone */
2105 IMAGE_TYPE *p_image;
2106 #ifdef MODULE_NAME_IS_x11
2107 int i_quantum; /* XImage quantum (see below) */
2108 int i_bytes_per_line;
2111 /* Allocate memory for image */
2112 #ifdef MODULE_NAME_IS_xvideo
2113 p_data = (byte_t *) malloc( i_width * i_height * 2 ); /* XXX */
2115 i_bytes_per_line = i_width * i_bytes_per_pixel;
2116 p_data = (byte_t *) malloc( i_bytes_per_line * i_height );
2120 msg_Err( p_vout, "out of memory" );
2124 #ifdef MODULE_NAME_IS_x11
2125 /* Optimize the quantum of a scanline regarding its size - the quantum is
2126 a diviser of the number of bits between the start of two scanlines. */
2127 if( i_bytes_per_line & 0xf )
2131 else if( i_bytes_per_line & 0x10 )
2141 /* Create XImage. p_data will be automatically freed */
2142 #ifdef MODULE_NAME_IS_xvideo
2143 p_image = XvCreateImage( p_display, i_xvport, i_chroma,
2144 p_data, i_width, i_height );
2146 p_image = XCreateImage( p_display, p_visual, i_depth, ZPixmap, 0,
2147 p_data, i_width, i_height, i_quantum, 0 );
2149 if( p_image == NULL )
2151 msg_Err( p_vout, "XCreateImage() failed" );
2159 #ifdef MODULE_NAME_IS_x11
2160 /*****************************************************************************
2161 * SetPalette: sets an 8 bpp palette
2162 *****************************************************************************
2163 * This function sets the palette given as an argument. It does not return
2164 * anything, but could later send information on which colors it was unable
2166 *****************************************************************************/
2167 static void SetPalette( vout_thread_t *p_vout, u16 *red, u16 *green, u16 *blue )
2170 XColor p_colors[255];
2172 /* allocate palette */
2173 for( i = 0; i < 255; i++ )
2175 /* kludge: colors are indexed reversely because color 255 seems
2176 * to be reserved for black even if we try to set it to white */
2177 p_colors[ i ].pixel = 255 - i;
2178 p_colors[ i ].pad = 0;
2179 p_colors[ i ].flags = DoRed | DoGreen | DoBlue;
2180 p_colors[ i ].red = red[ 255 - i ];
2181 p_colors[ i ].blue = blue[ 255 - i ];
2182 p_colors[ i ].green = green[ 255 - i ];
2185 XStoreColors( p_vout->p_sys->p_display,
2186 p_vout->p_sys->colormap, p_colors, 255 );