1 /*****************************************************************************
2 * vout_x11.c: X11 video output display method
3 *****************************************************************************
4 * Copyright (C) 1998, 1999, 2000 VideoLAN
5 * $Id: vout_x11.c,v 1.11 2001/02/15 03:01:20 sam Exp $
7 * Authors: Vincent Seguin <seguin@via.ecp.fr>
8 * Samuel Hocevar <sam@zoy.org>
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
23 *****************************************************************************/
25 /*****************************************************************************
27 *****************************************************************************/
30 #include <errno.h> /* ENOMEM */
31 #include <stdlib.h> /* free() */
32 #include <string.h> /* strerror() */
34 #ifdef HAVE_MACHINE_PARAM_H
36 #include <machine/param.h>
37 #include <sys/types.h> /* typedef ushort */
41 #include <sys/shm.h> /* shmget(), shmctl() */
43 #include <X11/Xutil.h>
44 #include <X11/keysym.h>
45 #include <X11/extensions/XShm.h>
55 #include "video_output.h"
57 #include "interface.h"
62 /*****************************************************************************
63 * vout_sys_t: video output X11 method descriptor
64 *****************************************************************************
65 * This structure is part of the video output thread descriptor.
66 * It describes the X11 specific properties of an output thread. X11 video
67 * output is performed through regular resizable windows. Windows can be
68 * dynamically resized to adapt to the size of the streams.
69 *****************************************************************************/
70 typedef struct vout_sys_s
73 boolean_t b_shm
; /* shared memory extension flag */
75 /* Internal settings and properties */
76 Display
* p_display
; /* display pointer */
77 Visual
* p_visual
; /* visual pointer */
78 int i_screen
; /* screen number */
79 Window window
; /* root window */
80 GC gc
; /* graphic context instance handler */
81 Colormap colormap
; /* colormap used (8bpp only) */
83 /* Display buffers and shared memory information */
84 XImage
* p_ximage
[2]; /* XImage pointer */
85 XShmSegmentInfo shm_info
[2]; /* shared memory zone information */
87 /* X11 generic properties */
89 Atom wm_delete_window
;
91 int i_width
; /* width of main window */
92 int i_height
; /* height of main window */
94 /* Screen saver properties */
95 int i_ss_count
; /* enabling/disabling count */
96 int i_ss_timeout
; /* timeout */
97 int i_ss_interval
; /* interval between changes */
98 int i_ss_blanking
; /* blanking mode */
99 int i_ss_exposure
; /* exposure mode */
101 /* Mouse pointer properties */
102 boolean_t b_mouse
; /* is the mouse pointer displayed ? */
106 /*****************************************************************************
108 *****************************************************************************/
109 static int vout_Probe ( probedata_t
*p_data
);
110 static int vout_Create ( struct vout_thread_s
* );
111 static int vout_Init ( struct vout_thread_s
* );
112 static void vout_End ( struct vout_thread_s
* );
113 static void vout_Destroy ( struct vout_thread_s
* );
114 static int vout_Manage ( struct vout_thread_s
* );
115 static void vout_Display ( struct vout_thread_s
* );
116 static void vout_SetPalette( struct vout_thread_s
*, u16
*, u16
*, u16
*, u16
* );
118 static int X11OpenDisplay ( vout_thread_t
*p_vout
, char *psz_display
);
119 static int X11CreateWindowVOUT ( vout_thread_t
*p_vout
);
120 static int X11CreateImage ( vout_thread_t
*p_vout
, XImage
**pp_ximage
);
121 static void X11DestroyImage ( XImage
*p_ximage
);
122 static int X11CreateShmImage ( vout_thread_t
*p_vout
, XImage
**pp_ximage
,
123 XShmSegmentInfo
*p_shm_info
);
124 static void X11DestroyShmImage ( vout_thread_t
*p_vout
, XImage
*p_ximage
,
125 XShmSegmentInfo
*p_shm_info
);
127 static int X11CreateWindow ( vout_thread_t
*p_vout
);
128 static void X11ManageWindow ( vout_thread_t
*p_vout
);
129 static void X11EnableScreenSaver ( vout_thread_t
*p_vout
);
130 static void X11DisableScreenSaver ( vout_thread_t
*p_vout
);
131 static void X11TogglePointer ( vout_thread_t
*p_vout
);
133 /*****************************************************************************
134 * Functions exported as capabilities. They are declared as static so that
135 * we don't pollute the namespace too much.
136 *****************************************************************************/
137 void vout_getfunctions( function_list_t
* p_function_list
)
139 p_function_list
->pf_probe
= vout_Probe
;
140 p_function_list
->functions
.vout
.pf_create
= vout_Create
;
141 p_function_list
->functions
.vout
.pf_init
= vout_Init
;
142 p_function_list
->functions
.vout
.pf_end
= vout_End
;
143 p_function_list
->functions
.vout
.pf_destroy
= vout_Destroy
;
144 p_function_list
->functions
.vout
.pf_manage
= vout_Manage
;
145 p_function_list
->functions
.vout
.pf_display
= vout_Display
;
146 p_function_list
->functions
.vout
.pf_setpalette
= vout_SetPalette
;
149 /*****************************************************************************
150 * vout_Probe: probe the video driver and return a score
151 *****************************************************************************
152 * This function tries to initialize SDL and returns a score to the
153 * plugin manager so that it can select the best plugin.
154 *****************************************************************************/
155 static int vout_Probe( probedata_t
*p_data
)
157 if( TestMethod( VOUT_METHOD_VAR
, "x11" ) )
165 /*****************************************************************************
166 * vout_Create: allocate X11 video thread output method
167 *****************************************************************************
168 * This function allocate and initialize a X11 vout method. It uses some of the
169 * vout properties to choose the window size, and change them according to the
170 * actual properties of the display.
171 *****************************************************************************/
172 static int vout_Create( vout_thread_t
*p_vout
)
176 /* Allocate structure */
177 p_vout
->p_sys
= malloc( sizeof( vout_sys_t
) );
178 if( p_vout
->p_sys
== NULL
)
180 intf_ErrMsg("error: %s", strerror(ENOMEM
) );
184 /* Open display, unsing 'vlc_display' or DISPLAY environment variable */
185 psz_display
= XDisplayName( main_GetPszVariable( VOUT_DISPLAY_VAR
, NULL
) );
186 p_vout
->p_sys
->p_display
= XOpenDisplay( psz_display
);
188 if( !p_vout
->p_sys
->p_display
) /* error */
190 intf_ErrMsg("error: can't open display %s\n", psz_display
);
191 free( p_vout
->p_sys
);
194 p_vout
->p_sys
->i_screen
= DefaultScreen( p_vout
->p_sys
->p_display
);
196 /* Spawn base window - this window will include the video output window,
197 * but also command buttons, subtitles and other indicators */
198 if( X11CreateWindow( p_vout
) )
200 intf_ErrMsg("error: can't create interface window\n" );
201 XCloseDisplay( p_vout
->p_sys
->p_display
);
202 free( p_vout
->p_sys
);
206 /* Open and initialize device. This function issues its own error messages.
207 * Since XLib is usually not thread-safe, we can't use the same display
208 * pointer than the interface or another thread. However, the root window
209 * id is still valid. */
210 if( X11OpenDisplay( p_vout
, psz_display
) )
212 intf_ErrMsg("error: can't initialize X11 display" );
213 XCloseDisplay( p_vout
->p_sys
->p_display
);
214 free( p_vout
->p_sys
);
218 p_vout
->p_sys
->b_mouse
= 1;
220 /* Disable screen saver and return */
221 p_vout
->p_sys
->i_ss_count
= 1;
222 X11DisableScreenSaver( p_vout
);
227 /*****************************************************************************
228 * vout_Init: initialize X11 video thread output method
229 *****************************************************************************
230 * This function create the XImages needed by the output thread. It is called
231 * at the beginning of the thread, but also each time the window is resized.
232 *****************************************************************************/
233 static int vout_Init( vout_thread_t
*p_vout
)
237 /* Create XImages using XShm extension - on failure, fall back to regular
238 * way (and destroy the first image if it was created successfully) */
239 if( p_vout
->p_sys
->b_shm
)
241 /* Create first image */
242 i_err
= X11CreateShmImage( p_vout
, &p_vout
->p_sys
->p_ximage
[0],
243 &p_vout
->p_sys
->shm_info
[0] );
244 if( !i_err
) /* first image has been created */
246 /* Create second image */
247 if( X11CreateShmImage( p_vout
, &p_vout
->p_sys
->p_ximage
[1],
248 &p_vout
->p_sys
->shm_info
[1] ) )
249 { /* error creating the second image */
250 X11DestroyShmImage( p_vout
, p_vout
->p_sys
->p_ximage
[0],
251 &p_vout
->p_sys
->shm_info
[0] );
255 if( i_err
) /* an error occured */
257 intf_Msg("vout: XShm video sextension deactivated" );
258 p_vout
->p_sys
->b_shm
= 0;
262 /* Create XImages without XShm extension */
263 if( !p_vout
->p_sys
->b_shm
)
265 if( X11CreateImage( p_vout
, &p_vout
->p_sys
->p_ximage
[0] ) )
267 intf_ErrMsg("error: can't create images");
268 p_vout
->p_sys
->p_ximage
[0] = NULL
;
269 p_vout
->p_sys
->p_ximage
[1] = NULL
;
272 if( X11CreateImage( p_vout
, &p_vout
->p_sys
->p_ximage
[1] ) )
274 intf_ErrMsg("error: can't create images");
275 X11DestroyImage( p_vout
->p_sys
->p_ximage
[0] );
276 p_vout
->p_sys
->p_ximage
[0] = NULL
;
277 p_vout
->p_sys
->p_ximage
[1] = NULL
;
282 /* Set bytes per line and initialize buffers */
283 p_vout
->i_bytes_per_line
= p_vout
->p_sys
->p_ximage
[0]->bytes_per_line
;
284 vout_SetBuffers( p_vout
, p_vout
->p_sys
->p_ximage
[ 0 ]->data
,
285 p_vout
->p_sys
->p_ximage
[ 1 ]->data
);
289 /*****************************************************************************
290 * vout_End: terminate X11 video thread output method
291 *****************************************************************************
292 * Destroy the X11 XImages created by vout_Init. It is called at the end of
293 * the thread, but also each time the window is resized.
294 *****************************************************************************/
295 static void vout_End( vout_thread_t
*p_vout
)
297 if( p_vout
->p_sys
->b_shm
) /* Shm XImages... */
299 X11DestroyShmImage( p_vout
, p_vout
->p_sys
->p_ximage
[0],
300 &p_vout
->p_sys
->shm_info
[0] );
301 X11DestroyShmImage( p_vout
, p_vout
->p_sys
->p_ximage
[1],
302 &p_vout
->p_sys
->shm_info
[1] );
304 else /* ...or regular XImages */
306 X11DestroyImage( p_vout
->p_sys
->p_ximage
[0] );
307 X11DestroyImage( p_vout
->p_sys
->p_ximage
[1] );
311 /*****************************************************************************
312 * vout_Destroy: destroy X11 video thread output method
313 *****************************************************************************
314 * Terminate an output method created by vout_CreateOutputMethod
315 *****************************************************************************/
316 static void vout_Destroy( vout_thread_t
*p_vout
)
318 /* Enable screen saver */
319 X11EnableScreenSaver( p_vout
);
321 /* Destroy colormap */
322 if( p_vout
->i_screen_depth
== 8 )
324 XFreeColormap( p_vout
->p_sys
->p_display
, p_vout
->p_sys
->colormap
);
328 XUnmapWindow( p_vout
->p_sys
->p_display
, p_vout
->p_sys
->window
);
329 XFreeGC( p_vout
->p_sys
->p_display
, p_vout
->p_sys
->gc
);
330 XDestroyWindow( p_vout
->p_sys
->p_display
, p_vout
->p_sys
->window
);
332 XCloseDisplay( p_vout
->p_sys
->p_display
);
334 /* Destroy structure */
335 free( p_vout
->p_sys
);
338 /*****************************************************************************
339 * vout_Manage: handle X11 events
340 *****************************************************************************
341 * This function should be called regularly by video output thread. It manages
342 * X11 events and allows window resizing. It returns a non null value on
344 *****************************************************************************/
345 static int vout_Manage( vout_thread_t
*p_vout
)
348 * Color/Grayscale or gamma change: in 8bpp, just change the colormap
350 if( (p_vout
->i_changes
& VOUT_GRAYSCALE_CHANGE
)
351 && (p_vout
->i_screen_depth
== 8) )
353 /* FIXME: clear flags ?? */
359 if( p_vout
->i_changes
& VOUT_SIZE_CHANGE
)
361 intf_DbgMsg("resizing window");
362 p_vout
->i_changes
&= ~VOUT_SIZE_CHANGE
;
365 XResizeWindow( p_vout
->p_sys
->p_display
, p_vout
->p_sys
->window
,
366 p_vout
->i_width
, p_vout
->i_height
);
368 /* Destroy XImages to change their size */
371 /* Recreate XImages. If SysInit failed, the thread can't go on. */
372 if( vout_Init( p_vout
) )
374 intf_ErrMsg("error: can't resize display");
378 /* Tell the video output thread that it will need to rebuild YUV
379 * tables. This is needed since conversion buffer size may have
381 p_vout
->i_changes
|= VOUT_YUV_CHANGE
;
382 intf_Msg("vout: video display resized (%dx%d)", p_vout
->i_width
, p_vout
->i_height
);
385 X11ManageWindow( p_vout
);
390 /*****************************************************************************
391 * vout_Display: displays previously rendered output
392 *****************************************************************************
393 * This function send the currently rendered image to X11 server, wait until
394 * it is displayed and switch the two rendering buffer, preparing next frame.
395 *****************************************************************************/
396 static void vout_Display( vout_thread_t
*p_vout
)
398 if( p_vout
->p_sys
->b_shm
) /* XShm is used */
400 /* Display rendered image using shared memory extension */
401 XShmPutImage(p_vout
->p_sys
->p_display
, p_vout
->p_sys
->window
, p_vout
->p_sys
->gc
,
402 p_vout
->p_sys
->p_ximage
[ p_vout
->i_buffer_index
],
404 p_vout
->p_sys
->p_ximage
[ p_vout
->i_buffer_index
]->width
,
405 p_vout
->p_sys
->p_ximage
[ p_vout
->i_buffer_index
]->height
, True
);
407 /* Send the order to the X server */
408 XSync(p_vout
->p_sys
->p_display
, False
);
410 else /* regular X11 capabilities are used */
412 XPutImage(p_vout
->p_sys
->p_display
, p_vout
->p_sys
->window
, p_vout
->p_sys
->gc
,
413 p_vout
->p_sys
->p_ximage
[ p_vout
->i_buffer_index
],
415 p_vout
->p_sys
->p_ximage
[ p_vout
->i_buffer_index
]->width
,
416 p_vout
->p_sys
->p_ximage
[ p_vout
->i_buffer_index
]->height
);
418 /* Send the order to the X server */
419 XSync(p_vout
->p_sys
->p_display
, False
);
423 /*****************************************************************************
424 * vout_SetPalette: sets an 8 bpp palette
425 *****************************************************************************
426 * This function sets the palette given as an argument. It does not return
427 * anything, but could later send information on which colors it was unable
429 *****************************************************************************/
430 static void vout_SetPalette( p_vout_thread_t p_vout
,
431 u16
*red
, u16
*green
, u16
*blue
, u16
*transp
)
436 intf_DbgMsg( "Palette change called" );
438 /* allocate palette */
439 for( i
= 0; i
< 255; i
++ )
441 /* kludge: colors are indexed reversely because color 255 seems
442 * to be reserved for black even if we try to set it to white */
443 color
[i
].pixel
= 255-i
;
445 color
[i
].flags
= DoRed
|DoGreen
|DoBlue
;
446 color
[i
].red
= red
[255-i
];
447 color
[i
].blue
= blue
[255-i
];
448 color
[i
].green
= green
[255-i
];
451 XStoreColors( p_vout
->p_sys
->p_display
, p_vout
->p_sys
->colormap
, color
, 256 );
454 /* following functions are local */
456 /*****************************************************************************
457 * X11OpenDisplay: open and initialize X11 device
458 *****************************************************************************
459 * Create a window according to video output given size, and set other
460 * properties according to the display properties.
461 *****************************************************************************/
462 static int X11OpenDisplay( vout_thread_t
*p_vout
, char *psz_display
)
464 XPixmapFormatValues
* p_xpixmap_format
; /* pixmap formats */
465 XVisualInfo
* p_xvisual
; /* visuals informations */
466 XVisualInfo xvisual_template
; /* visual template */
467 int i_count
; /* array size */
470 p_vout
->p_sys
->p_display
= XOpenDisplay( psz_display
);
471 if( p_vout
->p_sys
->p_display
== NULL
)
473 intf_ErrMsg("error: can't open display %s", psz_display
);
477 /* Initialize structure */
478 p_vout
->p_sys
->b_shm
= (XShmQueryExtension(p_vout
->p_sys
->p_display
) == True
);
479 p_vout
->p_sys
->i_screen
= DefaultScreen( p_vout
->p_sys
->p_display
);
480 if( !p_vout
->p_sys
->b_shm
)
482 intf_Msg("vout: XShm video extension is not available");
485 /* Get screen depth */
486 p_vout
->i_screen_depth
= XDefaultDepth( p_vout
->p_sys
->p_display
, p_vout
->p_sys
->i_screen
);
487 switch( p_vout
->i_screen_depth
)
491 * Screen depth is 8bpp. Use PseudoColor visual with private colormap.
493 xvisual_template
.screen
= p_vout
->p_sys
->i_screen
;
494 xvisual_template
.class = DirectColor
;
495 p_xvisual
= XGetVisualInfo( p_vout
->p_sys
->p_display
, VisualScreenMask
| VisualClassMask
,
496 &xvisual_template
, &i_count
);
497 if( p_xvisual
== NULL
)
499 intf_ErrMsg("error: no PseudoColor visual available");
500 XCloseDisplay( p_vout
->p_sys
->p_display
);
503 p_vout
->i_bytes_per_pixel
= 1;
510 * Screen depth is higher than 8bpp. TrueColor visual is used.
512 xvisual_template
.screen
= p_vout
->p_sys
->i_screen
;
513 xvisual_template
.class = TrueColor
;
514 p_xvisual
= XGetVisualInfo( p_vout
->p_sys
->p_display
, VisualScreenMask
| VisualClassMask
,
515 &xvisual_template
, &i_count
);
516 if( p_xvisual
== NULL
)
518 intf_ErrMsg("error: no TrueColor visual available");
519 XCloseDisplay( p_vout
->p_sys
->p_display
);
522 p_vout
->i_red_mask
= p_xvisual
->red_mask
;
523 p_vout
->i_green_mask
= p_xvisual
->green_mask
;
524 p_vout
->i_blue_mask
= p_xvisual
->blue_mask
;
526 /* There is no difference yet between 3 and 4 Bpp. The only way to find
527 * the actual number of bytes per pixel is to list supported pixmap
529 p_xpixmap_format
= XListPixmapFormats( p_vout
->p_sys
->p_display
, &i_count
);
532 /* Under XFree4.0, the list contains pixmap formats available through
533 * all video depths ; so we have to check against current depth. */
534 p_vout
->i_bytes_per_pixel
= 0;
535 for( ; i_count
-- ; p_xpixmap_format
++ )
537 if( p_xpixmap_format
->depth
== p_vout
->i_screen_depth
)
539 if( p_xpixmap_format
->bits_per_pixel
/ 8 > p_vout
->i_bytes_per_pixel
)
541 p_vout
->i_bytes_per_pixel
= p_xpixmap_format
->bits_per_pixel
/ 8;
547 p_vout
->p_sys
->p_visual
= p_xvisual
->visual
;
550 /* Create a window */
551 if( X11CreateWindowVOUT( p_vout
) )
553 intf_ErrMsg("error: can't open a window");
554 XCloseDisplay( p_vout
->p_sys
->p_display
);
560 /*****************************************************************************
561 * X11CreateWindowVOUT: create X11 vout window
562 *****************************************************************************
563 * The video output window will be created. Normally, this window is wether
564 * full screen or part of a parent window. Therefore, it does not need a
565 * title or other hints. Thery are still supplied in case the window would be
566 * spawned as a standalone one by the interface.
567 *****************************************************************************/
568 static int X11CreateWindowVOUT( vout_thread_t
*p_vout
)
570 XSetWindowAttributes xwindow_attributes
; /* window attributes */
571 XGCValues xgcvalues
; /* graphic context configuration */
572 XEvent xevent
; /* first events */
573 boolean_t b_expose
; /* 'expose' event received */
574 boolean_t b_map_notify
; /* 'map_notify' event received */
576 /* Prepare window attributes */
577 xwindow_attributes
.backing_store
= Always
; /* save the hidden part */
579 /* Create the window and set hints */
580 p_vout
->p_sys
->window
= XCreateSimpleWindow( p_vout
->p_sys
->p_display
,
581 p_vout
->p_sys
->window
,
583 p_vout
->i_width
, p_vout
->i_height
,
585 XSelectInput( p_vout
->p_sys
->p_display
, p_vout
->p_sys
->window
,
586 ExposureMask
| StructureNotifyMask
);
587 XChangeWindowAttributes( p_vout
->p_sys
->p_display
, p_vout
->p_sys
->window
,
588 CWBackingStore
, &xwindow_attributes
);
590 /* Creation of a graphic context that doesn't generate a GraphicsExpose event
591 when using functions like XCopyArea */
592 xgcvalues
.graphics_exposures
= False
;
593 p_vout
->p_sys
->gc
= XCreateGC( p_vout
->p_sys
->p_display
, p_vout
->p_sys
->window
,
594 GCGraphicsExposures
, &xgcvalues
);
596 /* Send orders to server, and wait until window is displayed - two events
597 * must be received: a MapNotify event, an Expose event allowing drawing in the
601 XMapWindow( p_vout
->p_sys
->p_display
, p_vout
->p_sys
->window
);
604 XNextEvent( p_vout
->p_sys
->p_display
, &xevent
);
605 if( (xevent
.type
== Expose
)
606 && (xevent
.xexpose
.window
== p_vout
->p_sys
->window
) )
610 else if( (xevent
.type
== MapNotify
)
611 && (xevent
.xmap
.window
== p_vout
->p_sys
->window
) )
616 while( !( b_expose
&& b_map_notify
) );
617 XSelectInput( p_vout
->p_sys
->p_display
, p_vout
->p_sys
->window
, 0 );
619 /* At this stage, the window is open, displayed, and ready to receive
624 /*****************************************************************************
625 * X11CreateImage: create an XImage
626 *****************************************************************************
627 * Create a simple XImage used as a buffer.
628 *****************************************************************************/
629 static int X11CreateImage( vout_thread_t
*p_vout
, XImage
**pp_ximage
)
631 byte_t
* pb_data
; /* image data storage zone */
632 int i_quantum
; /* XImage quantum (see below) */
634 /* Allocate memory for image */
635 p_vout
->i_bytes_per_line
= p_vout
->i_width
* p_vout
->i_bytes_per_pixel
;
636 pb_data
= (byte_t
*) malloc( p_vout
->i_bytes_per_line
* p_vout
->i_height
);
637 if( !pb_data
) /* error */
639 intf_ErrMsg("error: %s", strerror(ENOMEM
));
643 /* Optimize the quantum of a scanline regarding its size - the quantum is
644 a diviser of the number of bits between the start of two scanlines. */
645 if( !(( p_vout
->i_bytes_per_line
) % 32) )
651 if( !(( p_vout
->i_bytes_per_line
) % 16) )
662 *pp_ximage
= XCreateImage( p_vout
->p_sys
->p_display
, p_vout
->p_sys
->p_visual
,
663 p_vout
->i_screen_depth
, ZPixmap
, 0, pb_data
,
664 p_vout
->i_width
, p_vout
->i_height
, i_quantum
, 0);
665 if(! *pp_ximage
) /* error */
667 intf_ErrMsg( "error: XCreateImage() failed" );
675 /*****************************************************************************
676 * X11CreateShmImage: create an XImage using shared memory extension
677 *****************************************************************************
678 * Prepare an XImage for DisplayX11ShmImage function.
679 * The order of the operations respects the recommandations of the mit-shm
680 * document by J.Corbet and K.Packard. Most of the parameters were copied from
682 *****************************************************************************/
683 static int X11CreateShmImage( vout_thread_t
*p_vout
, XImage
**pp_ximage
,
684 XShmSegmentInfo
*p_shm_info
)
687 *pp_ximage
= XShmCreateImage( p_vout
->p_sys
->p_display
, p_vout
->p_sys
->p_visual
,
688 p_vout
->i_screen_depth
, ZPixmap
, 0,
689 p_shm_info
, p_vout
->i_width
, p_vout
->i_height
);
690 if(! *pp_ximage
) /* error */
692 intf_ErrMsg("error: XShmCreateImage() failed");
696 /* Allocate shared memory segment - 0777 set the access permission
697 * rights (like umask), they are not yet supported by X servers */
698 p_shm_info
->shmid
= shmget( IPC_PRIVATE
,
699 (*pp_ximage
)->bytes_per_line
* (*pp_ximage
)->height
,
701 if( p_shm_info
->shmid
< 0) /* error */
703 intf_ErrMsg("error: can't allocate shared image data (%s)",
705 XDestroyImage( *pp_ximage
);
709 /* Attach shared memory segment to process (read/write) */
710 p_shm_info
->shmaddr
= (*pp_ximage
)->data
= shmat(p_shm_info
->shmid
, 0, 0);
711 if(! p_shm_info
->shmaddr
)
713 intf_ErrMsg("error: can't attach shared memory (%s)",
715 shmctl( p_shm_info
->shmid
, IPC_RMID
, 0 ); /* free shared memory */
716 XDestroyImage( *pp_ximage
);
720 /* Mark the shm segment to be removed when there will be no more
721 * attachements, so it is automatic on process exit or after shmdt */
722 shmctl( p_shm_info
->shmid
, IPC_RMID
, 0 );
724 /* Attach shared memory segment to X server (read only) */
725 p_shm_info
->readOnly
= True
;
726 if( XShmAttach( p_vout
->p_sys
->p_display
, p_shm_info
) == False
) /* error */
728 intf_ErrMsg("error: can't attach shared memory to X11 server");
729 shmdt( p_shm_info
->shmaddr
); /* detach shared memory from process
730 * and automatic free */
731 XDestroyImage( *pp_ximage
);
735 /* Send image to X server. This instruction is required, since having
736 * built a Shm XImage and not using it causes an error on XCloseDisplay */
737 XFlush( p_vout
->p_sys
->p_display
);
741 /*****************************************************************************
742 * X11DestroyImage: destroy an XImage
743 *****************************************************************************
744 * Destroy XImage AND associated data. If pointer is NULL, the image won't be
745 * destroyed (see vout_ManageOutputMethod())
746 *****************************************************************************/
747 static void X11DestroyImage( XImage
*p_ximage
)
749 if( p_ximage
!= NULL
)
751 XDestroyImage( p_ximage
); /* no free() required */
755 /*****************************************************************************
757 *****************************************************************************
758 * Destroy XImage AND associated data. Detach shared memory segment from
759 * server and process, then free it. If pointer is NULL, the image won't be
760 * destroyed (see vout_ManageOutputMethod())
761 *****************************************************************************/
762 static void X11DestroyShmImage( vout_thread_t
*p_vout
, XImage
*p_ximage
,
763 XShmSegmentInfo
*p_shm_info
)
765 /* If pointer is NULL, do nothing */
766 if( p_ximage
== NULL
)
771 XShmDetach( p_vout
->p_sys
->p_display
, p_shm_info
); /* detach from server */
772 XDestroyImage( p_ximage
);
773 if( shmdt( p_shm_info
->shmaddr
) ) /* detach shared memory from process */
774 { /* also automatic freeing... */
775 intf_ErrMsg( "error: can't detach shared memory (%s)",
783 /*****************************************************************************
784 * X11CreateWindow: open and set-up X11 main window
785 *****************************************************************************/
786 static int X11CreateWindow( vout_thread_t
*p_vout
)
788 XSizeHints xsize_hints
;
789 XSetWindowAttributes xwindow_attributes
;
793 boolean_t b_configure_notify
;
794 boolean_t b_map_notify
;
796 /* Set main window's size */
797 p_vout
->p_sys
->i_width
= main_GetIntVariable( VOUT_WIDTH_VAR
,
798 VOUT_WIDTH_DEFAULT
);
799 p_vout
->p_sys
->i_height
= main_GetIntVariable( VOUT_HEIGHT_VAR
,
800 VOUT_HEIGHT_DEFAULT
);
802 /* Prepare window manager hints and properties */
803 xsize_hints
.base_width
= p_vout
->p_sys
->i_width
;
804 xsize_hints
.base_height
= p_vout
->p_sys
->i_height
;
805 xsize_hints
.flags
= PSize
;
806 p_vout
->p_sys
->wm_protocols
= XInternAtom( p_vout
->p_sys
->p_display
,
807 "WM_PROTOCOLS", True
);
808 p_vout
->p_sys
->wm_delete_window
= XInternAtom( p_vout
->p_sys
->p_display
,
809 "WM_DELETE_WINDOW", True
);
811 /* Prepare window attributes */
812 xwindow_attributes
.backing_store
= Always
; /* save the hidden part */
813 xwindow_attributes
.background_pixel
= WhitePixel( p_vout
->p_sys
->p_display
,
814 p_vout
->p_sys
->i_screen
);
816 xwindow_attributes
.event_mask
= ExposureMask
| StructureNotifyMask
;
818 /* Create the window and set hints - the window must receive ConfigureNotify
819 * events, and, until it is displayed, Expose and MapNotify events. */
820 p_vout
->p_sys
->window
=
821 XCreateWindow( p_vout
->p_sys
->p_display
,
822 DefaultRootWindow( p_vout
->p_sys
->p_display
),
824 p_vout
->p_sys
->i_width
, p_vout
->p_sys
->i_height
, 1,
826 CWBackingStore
| CWBackPixel
| CWEventMask
,
827 &xwindow_attributes
);
829 /* Set window manager hints and properties: size hints, command,
830 * window's name, and accepted protocols */
831 XSetWMNormalHints( p_vout
->p_sys
->p_display
, p_vout
->p_sys
->window
,
833 XSetCommand( p_vout
->p_sys
->p_display
, p_vout
->p_sys
->window
,
834 p_main
->ppsz_argv
, p_main
->i_argc
);
835 XStoreName( p_vout
->p_sys
->p_display
, p_vout
->p_sys
->window
, VOUT_TITLE
);
837 if( (p_vout
->p_sys
->wm_protocols
== None
) /* use WM_DELETE_WINDOW */
838 || (p_vout
->p_sys
->wm_delete_window
== None
)
839 || !XSetWMProtocols( p_vout
->p_sys
->p_display
, p_vout
->p_sys
->window
,
840 &p_vout
->p_sys
->wm_delete_window
, 1 ) )
842 /* WM_DELETE_WINDOW is not supported by window manager */
843 intf_Msg("intf error: missing or bad window manager - please exit program kindly.");
846 /* Creation of a graphic context that doesn't generate a GraphicsExpose
847 * event when using functions like XCopyArea */
848 xgcvalues
.graphics_exposures
= False
;
849 p_vout
->p_sys
->gc
= XCreateGC( p_vout
->p_sys
->p_display
, p_vout
->p_sys
->window
,
850 GCGraphicsExposures
, &xgcvalues
);
852 /* Send orders to server, and wait until window is displayed - three
853 * events must be received: a MapNotify event, an Expose event allowing
854 * drawing in the window, and a ConfigureNotify to get the window
855 * dimensions. Once those events have been received, only ConfigureNotify
856 * events need to be received. */
858 b_configure_notify
= 0;
860 XMapWindow( p_vout
->p_sys
->p_display
, p_vout
->p_sys
->window
);
863 XNextEvent( p_vout
->p_sys
->p_display
, &xevent
);
864 if( (xevent
.type
== Expose
)
865 && (xevent
.xexpose
.window
== p_vout
->p_sys
->window
) )
869 else if( (xevent
.type
== MapNotify
)
870 && (xevent
.xmap
.window
== p_vout
->p_sys
->window
) )
874 else if( (xevent
.type
== ConfigureNotify
)
875 && (xevent
.xconfigure
.window
== p_vout
->p_sys
->window
) )
877 b_configure_notify
= 1;
878 p_vout
->p_sys
->i_width
= xevent
.xconfigure
.width
;
879 p_vout
->p_sys
->i_height
= xevent
.xconfigure
.height
;
881 } while( !( b_expose
&& b_configure_notify
&& b_map_notify
) );
883 XSelectInput( p_vout
->p_sys
->p_display
, p_vout
->p_sys
->window
,
884 StructureNotifyMask
| KeyPressMask
| ButtonPressMask
);
886 if( XDefaultDepth(p_vout
->p_sys
->p_display
, p_vout
->p_sys
->i_screen
) == 8 )
888 /* Allocate a new palette */
889 p_vout
->p_sys
->colormap
= XCreateColormap( p_vout
->p_sys
->p_display
,
890 DefaultRootWindow( p_vout
->p_sys
->p_display
),
891 DefaultVisual( p_vout
->p_sys
->p_display
,
892 p_vout
->p_sys
->i_screen
),
895 xwindow_attributes
.colormap
= p_vout
->p_sys
->colormap
;
896 XChangeWindowAttributes( p_vout
->p_sys
->p_display
,
897 p_vout
->p_sys
->window
,
898 CWColormap
, &xwindow_attributes
);
901 /* At this stage, the window is open, displayed, and ready to receive data */
905 /*****************************************************************************
906 * X11ManageWindow: manage X11 main window
907 *****************************************************************************/
908 static void X11ManageWindow( vout_thread_t
*p_vout
)
910 XEvent xevent
; /* X11 event */
911 boolean_t b_resized
; /* window has been resized */
912 char i_key
; /* ISO Latin-1 key */
914 /* Handle X11 events: ConfigureNotify events are parsed to know if the
915 * output window's size changed, MapNotify and UnmapNotify to know if the
916 * window is mapped (and if the display is useful), and ClientMessages
917 * to intercept window destruction requests */
919 while( XCheckWindowEvent( p_vout
->p_sys
->p_display
, p_vout
->p_sys
->window
,
920 StructureNotifyMask
| KeyPressMask
|
921 ButtonPressMask
, &xevent
) == True
)
923 /* ConfigureNotify event: prepare */
924 if( (xevent
.type
== ConfigureNotify
)
925 && ((xevent
.xconfigure
.width
!= p_vout
->p_sys
->i_width
)
926 || (xevent
.xconfigure
.height
!= p_vout
->p_sys
->i_height
)) )
928 /* Update dimensions */
930 p_vout
->p_sys
->i_width
= xevent
.xconfigure
.width
;
931 p_vout
->p_sys
->i_height
= xevent
.xconfigure
.height
;
933 /* MapNotify event: change window status and disable screen saver */
934 else if( xevent
.type
== MapNotify
)
936 if( (p_vout
!= NULL
) && !p_vout
->b_active
)
938 X11DisableScreenSaver( p_vout
);
939 p_vout
->b_active
= 1;
942 /* UnmapNotify event: change window status and enable screen saver */
943 else if( xevent
.type
== UnmapNotify
)
945 if( (p_vout
!= NULL
) && p_vout
->b_active
)
947 X11EnableScreenSaver( p_vout
);
948 p_vout
->b_active
= 0;
952 else if( xevent
.type
== KeyPress
)
954 if( XLookupString( &xevent
.xkey
, &i_key
, 1, NULL
, NULL
) )
956 /* if( intf_ProcessKey( p_vout, i_key ) )
958 intf_DbgMsg("unhandled key '%c' (%i)", (char) i_key, i_key );
963 else if( xevent
.type
== ButtonPress
)
965 switch( ((XButtonEvent
*)&xevent
)->button
)
968 /* in this part we will eventually manage
969 * clicks for DVD navigation for instance */
973 X11TogglePointer( p_vout
);
977 vlc_mutex_lock( &p_vout
->change_lock
);
978 p_vout
->b_interface
= !p_vout
->b_interface
;
979 p_vout
->i_changes
|= VOUT_INTF_CHANGE
;
980 vlc_mutex_unlock( &p_vout
->change_lock
);
988 intf_DbgMsg( "%p -> unhandled event type %d received",
989 p_vout
, xevent
.type
);
994 /* ClientMessage event - only WM_PROTOCOLS with WM_DELETE_WINDOW data
995 * are handled - according to the man pages, the format is always 32
997 while( XCheckTypedEvent( p_vout
->p_sys
->p_display
,
998 ClientMessage
, &xevent
) )
1000 if( (xevent
.xclient
.message_type
== p_vout
->p_sys
->wm_protocols
)
1001 && (xevent
.xclient
.data
.l
[0] == p_vout
->p_sys
->wm_delete_window
) )
1007 intf_DbgMsg( "%p -> unhandled ClientMessage received", p_vout
);
1012 * Handle vout or interface windows resizing
1014 if( p_vout
!= NULL
)
1018 /* If interface window has been resized, change vout size */
1019 intf_DbgMsg( "resizing output window" );
1020 vlc_mutex_lock( &p_vout
->change_lock
);
1021 p_vout
->i_width
= p_vout
->p_sys
->i_width
;
1022 p_vout
->i_height
= p_vout
->p_sys
->i_height
;
1023 p_vout
->i_changes
|= VOUT_SIZE_CHANGE
;
1024 vlc_mutex_unlock( &p_vout
->change_lock
);
1026 else if( (p_vout
->i_width
!= p_vout
->p_sys
->i_width
) ||
1027 (p_vout
->i_height
!= p_vout
->p_sys
->i_height
) )
1029 /* If video output size has changed, change interface window size */
1030 intf_DbgMsg( "resizing output window" );
1031 p_vout
->p_sys
->i_width
= p_vout
->i_width
;
1032 p_vout
->p_sys
->i_height
= p_vout
->i_height
;
1033 XResizeWindow( p_vout
->p_sys
->p_display
, p_vout
->p_sys
->window
,
1034 p_vout
->p_sys
->i_width
, p_vout
->p_sys
->i_height
);
1039 /*****************************************************************************
1040 * X11EnableScreenSaver: enable screen saver
1041 *****************************************************************************
1042 * This function enable the screen saver on a display after it had been
1043 * disabled by XDisableScreenSaver. Both functions use a counter mechanism to
1044 * know wether the screen saver can be activated or not: if n successive calls
1045 * are made to XDisableScreenSaver, n successive calls to XEnableScreenSaver
1046 * will be required before the screen saver could effectively be activated.
1047 *****************************************************************************/
1048 void X11EnableScreenSaver( vout_thread_t
*p_vout
)
1050 if( p_vout
->p_sys
->i_ss_count
++ == 0 )
1052 intf_DbgMsg( "intf: enabling screen saver" );
1053 XSetScreenSaver( p_vout
->p_sys
->p_display
, p_vout
->p_sys
->i_ss_timeout
,
1054 p_vout
->p_sys
->i_ss_interval
, p_vout
->p_sys
->i_ss_blanking
,
1055 p_vout
->p_sys
->i_ss_exposure
);
1059 /*****************************************************************************
1060 * X11DisableScreenSaver: disable screen saver
1061 *****************************************************************************
1062 * See XEnableScreenSaver
1063 *****************************************************************************/
1064 void X11DisableScreenSaver( vout_thread_t
*p_vout
)
1066 if( --p_vout
->p_sys
->i_ss_count
== 0 )
1068 /* Save screen saver informations */
1069 XGetScreenSaver( p_vout
->p_sys
->p_display
, &p_vout
->p_sys
->i_ss_timeout
,
1070 &p_vout
->p_sys
->i_ss_interval
, &p_vout
->p_sys
->i_ss_blanking
,
1071 &p_vout
->p_sys
->i_ss_exposure
);
1073 /* Disable screen saver */
1074 intf_DbgMsg("intf: disabling screen saver");
1075 XSetScreenSaver( p_vout
->p_sys
->p_display
, 0,
1076 p_vout
->p_sys
->i_ss_interval
, p_vout
->p_sys
->i_ss_blanking
,
1077 p_vout
->p_sys
->i_ss_exposure
);
1081 /*****************************************************************************
1082 * X11TogglePointer: hide or show the mouse pointer
1083 *****************************************************************************
1084 * This function hides the X pointer if it is visible by putting it at
1085 * coordinates (32,32) and setting the pointer sprite to a blank one. To
1086 * show it again, we disable the sprite and restore the original coordinates.
1087 *****************************************************************************/
1088 void X11TogglePointer( vout_thread_t
*p_vout
)
1090 static Cursor cursor
;
1091 static boolean_t b_cursor
= 0;
1093 if( p_vout
->p_sys
->b_mouse
)
1095 p_vout
->p_sys
->b_mouse
= 0;
1100 Pixmap blank
= XCreatePixmap( p_vout
->p_sys
->p_display
,
1101 DefaultRootWindow(p_vout
->p_sys
->p_display
),
1104 XParseColor( p_vout
->p_sys
->p_display
,
1105 XCreateColormap( p_vout
->p_sys
->p_display
,
1107 p_vout
->p_sys
->p_display
),
1109 p_vout
->p_sys
->p_display
,
1110 p_vout
->p_sys
->i_screen
),
1114 cursor
= XCreatePixmapCursor( p_vout
->p_sys
->p_display
,
1115 blank
, blank
, &color
, &color
, 1, 1 );
1119 XDefineCursor( p_vout
->p_sys
->p_display
,
1120 p_vout
->p_sys
->window
, cursor
);
1124 p_vout
->p_sys
->b_mouse
= 1;
1126 XUndefineCursor( p_vout
->p_sys
->p_display
, p_vout
->p_sys
->window
);