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.13 2001/02/16 06:37:09 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_timeout; /* timeout */
96 int i_ss_interval; /* interval between changes */
97 int i_ss_blanking; /* blanking mode */
98 int i_ss_exposure; /* exposure mode */
100 /* Mouse pointer properties */
101 boolean_t b_mouse; /* is the mouse pointer displayed ? */
105 /*****************************************************************************
107 *****************************************************************************/
108 static int vout_Probe ( probedata_t *p_data );
109 static int vout_Create ( struct vout_thread_s * );
110 static int vout_Init ( struct vout_thread_s * );
111 static void vout_End ( struct vout_thread_s * );
112 static void vout_Destroy ( struct vout_thread_s * );
113 static int vout_Manage ( struct vout_thread_s * );
114 static void vout_Display ( struct vout_thread_s * );
115 static void vout_SetPalette( struct vout_thread_s *, u16*, u16*, u16*, u16* );
117 static int X11CreateWindow ( vout_thread_t *p_vout );
119 static int X11InitDisplay ( vout_thread_t *p_vout, char *psz_display );
121 static int X11CreateImage ( vout_thread_t *p_vout, XImage **pp_ximage );
122 static void X11DestroyImage ( XImage *p_ximage );
123 static int X11CreateShmImage ( vout_thread_t *p_vout, XImage **pp_ximage,
124 XShmSegmentInfo *p_shm_info );
125 static void X11DestroyShmImage ( vout_thread_t *p_vout, XImage *p_ximage,
126 XShmSegmentInfo *p_shm_info );
128 /* local prototypes */
129 static void X11TogglePointer ( vout_thread_t *p_vout );
130 static void X11EnableScreenSaver ( vout_thread_t *p_vout );
131 static void X11DisableScreenSaver ( 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 == NULL ) /* 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( X11InitDisplay( 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 X11DisableScreenSaver( p_vout );
226 /*****************************************************************************
227 * vout_Init: initialize X11 video thread output method
228 *****************************************************************************
229 * This function create the XImages needed by the output thread. It is called
230 * at the beginning of the thread, but also each time the window is resized.
231 *****************************************************************************/
232 static int vout_Init( vout_thread_t *p_vout )
236 /* Create XImages using XShm extension - on failure, fall back to regular
237 * way (and destroy the first image if it was created successfully) */
238 if( p_vout->p_sys->b_shm )
240 /* Create first image */
241 i_err = X11CreateShmImage( p_vout, &p_vout->p_sys->p_ximage[0],
242 &p_vout->p_sys->shm_info[0] );
243 if( !i_err ) /* first image has been created */
245 /* Create second image */
246 if( X11CreateShmImage( p_vout, &p_vout->p_sys->p_ximage[1],
247 &p_vout->p_sys->shm_info[1] ) )
248 { /* error creating the second image */
249 X11DestroyShmImage( p_vout, p_vout->p_sys->p_ximage[0],
250 &p_vout->p_sys->shm_info[0] );
254 if( i_err ) /* an error occured */
256 intf_Msg("vout: XShm video extension unavailable" );
257 p_vout->p_sys->b_shm = 0;
261 /* Create XImages without XShm extension */
262 if( !p_vout->p_sys->b_shm )
264 if( X11CreateImage( p_vout, &p_vout->p_sys->p_ximage[0] ) )
266 intf_ErrMsg("error: can't create images");
267 p_vout->p_sys->p_ximage[0] = NULL;
268 p_vout->p_sys->p_ximage[1] = NULL;
271 if( X11CreateImage( p_vout, &p_vout->p_sys->p_ximage[1] ) )
273 intf_ErrMsg("error: can't create images");
274 X11DestroyImage( p_vout->p_sys->p_ximage[0] );
275 p_vout->p_sys->p_ximage[0] = NULL;
276 p_vout->p_sys->p_ximage[1] = NULL;
281 /* Set bytes per line and initialize buffers */
282 p_vout->i_bytes_per_line = p_vout->p_sys->p_ximage[0]->bytes_per_line;
283 vout_SetBuffers( p_vout, p_vout->p_sys->p_ximage[ 0 ]->data,
284 p_vout->p_sys->p_ximage[ 1 ]->data );
288 /*****************************************************************************
289 * vout_End: terminate X11 video thread output method
290 *****************************************************************************
291 * Destroy the X11 XImages created by vout_Init. It is called at the end of
292 * the thread, but also each time the window is resized.
293 *****************************************************************************/
294 static void vout_End( vout_thread_t *p_vout )
296 if( p_vout->p_sys->b_shm ) /* Shm XImages... */
298 X11DestroyShmImage( p_vout, p_vout->p_sys->p_ximage[0],
299 &p_vout->p_sys->shm_info[0] );
300 X11DestroyShmImage( p_vout, p_vout->p_sys->p_ximage[1],
301 &p_vout->p_sys->shm_info[1] );
303 else /* ...or regular XImages */
305 X11DestroyImage( p_vout->p_sys->p_ximage[0] );
306 X11DestroyImage( p_vout->p_sys->p_ximage[1] );
310 /*****************************************************************************
311 * vout_Destroy: destroy X11 video thread output method
312 *****************************************************************************
313 * Terminate an output method created by vout_CreateOutputMethod
314 *****************************************************************************/
315 static void vout_Destroy( vout_thread_t *p_vout )
317 /* Enable screen saver */
318 X11EnableScreenSaver( p_vout );
320 /* Destroy colormap */
321 if( p_vout->i_screen_depth == 8 )
323 XFreeColormap( p_vout->p_sys->p_display, p_vout->p_sys->colormap );
327 XUnmapWindow( p_vout->p_sys->p_display, p_vout->p_sys->window );
328 XFreeGC( p_vout->p_sys->p_display, p_vout->p_sys->gc );
329 XDestroyWindow( p_vout->p_sys->p_display, p_vout->p_sys->window );
331 XCloseDisplay( p_vout->p_sys->p_display );
333 /* Destroy structure */
334 free( p_vout->p_sys );
337 /*****************************************************************************
338 * vout_Manage: handle X11 events
339 *****************************************************************************
340 * This function should be called regularly by video output thread. It manages
341 * X11 events and allows window resizing. It returns a non null value on
343 *****************************************************************************/
344 static int vout_Manage( vout_thread_t *p_vout )
346 XEvent xevent; /* X11 event */
347 boolean_t b_resized; /* window has been resized */
348 char i_key; /* ISO Latin-1 key */
350 /* Handle X11 events: ConfigureNotify events are parsed to know if the
351 * output window's size changed, MapNotify and UnmapNotify to know if the
352 * window is mapped (and if the display is useful), and ClientMessages
353 * to intercept window destruction requests */
355 while( XCheckWindowEvent( p_vout->p_sys->p_display, p_vout->p_sys->window,
356 StructureNotifyMask | KeyPressMask |
357 ButtonPressMask, &xevent ) == True )
359 /* ConfigureNotify event: prepare */
360 if( (xevent.type == ConfigureNotify)
361 && ((xevent.xconfigure.width != p_vout->p_sys->i_width)
362 || (xevent.xconfigure.height != p_vout->p_sys->i_height)) )
364 /* Update dimensions */
366 p_vout->p_sys->i_width = xevent.xconfigure.width;
367 p_vout->p_sys->i_height = xevent.xconfigure.height;
369 /* MapNotify event: change window status and disable screen saver */
370 else if( xevent.type == MapNotify)
372 if( (p_vout != NULL) && !p_vout->b_active )
374 X11DisableScreenSaver( p_vout );
375 p_vout->b_active = 1;
378 /* UnmapNotify event: change window status and enable screen saver */
379 else if( xevent.type == UnmapNotify )
381 if( (p_vout != NULL) && p_vout->b_active )
383 X11EnableScreenSaver( p_vout );
384 p_vout->b_active = 0;
388 else if( xevent.type == KeyPress )
390 if( XLookupString( &xevent.xkey, &i_key, 1, NULL, NULL ) )
392 /* FIXME: handle stuff here */
396 /* FIXME: need locking ! */
397 p_main->p_intf->b_die = 1;
403 else if( xevent.type == ButtonPress )
405 switch( ((XButtonEvent *)&xevent)->button )
408 /* in this part we will eventually manage
409 * clicks for DVD navigation for instance */
413 X11TogglePointer( p_vout );
417 /* FIXME: need locking ! */
418 p_main->p_intf->b_menu_change = 1;
426 intf_DbgMsg( "%p -> unhandled event type %d received",
427 p_vout, xevent.type );
432 /* ClientMessage event - only WM_PROTOCOLS with WM_DELETE_WINDOW data
433 * are handled - according to the man pages, the format is always 32
435 while( XCheckTypedEvent( p_vout->p_sys->p_display,
436 ClientMessage, &xevent ) )
438 if( (xevent.xclient.message_type == p_vout->p_sys->wm_protocols)
439 && (xevent.xclient.data.l[0] == p_vout->p_sys->wm_delete_window ) )
441 p_main->p_intf->b_die = 1;
445 intf_DbgMsg( "%p -> unhandled ClientMessage received", p_vout );
450 * Handle vout window resizing
454 /* If interface window has been resized, change vout size */
455 intf_DbgMsg( "resizing output window" );
456 p_vout->i_width = p_vout->p_sys->i_width;
457 p_vout->i_height = p_vout->p_sys->i_height;
458 p_vout->i_changes |= VOUT_SIZE_CHANGE;
460 else if( (p_vout->i_width != p_vout->p_sys->i_width) ||
461 (p_vout->i_height != p_vout->p_sys->i_height) )
463 /* If video output size has changed, change interface window size */
464 intf_DbgMsg( "resizing output window" );
465 p_vout->p_sys->i_width = p_vout->i_width;
466 p_vout->p_sys->i_height = p_vout->i_height;
467 XResizeWindow( p_vout->p_sys->p_display, p_vout->p_sys->window,
468 p_vout->p_sys->i_width, p_vout->p_sys->i_height );
471 * Color/Grayscale or gamma change: in 8bpp, just change the colormap
473 if( (p_vout->i_changes & VOUT_GRAYSCALE_CHANGE)
474 && (p_vout->i_screen_depth == 8) )
476 /* FIXME: clear flags ?? */
482 if( p_vout->i_changes & VOUT_SIZE_CHANGE )
484 intf_DbgMsg("resizing window");
485 p_vout->i_changes &= ~VOUT_SIZE_CHANGE;
488 XResizeWindow( p_vout->p_sys->p_display, p_vout->p_sys->window,
489 p_vout->i_width, p_vout->i_height );
491 /* Destroy XImages to change their size */
494 /* Recreate XImages. If SysInit failed, the thread can't go on. */
495 if( vout_Init( p_vout ) )
497 intf_ErrMsg("error: can't resize display");
501 /* Tell the video output thread that it will need to rebuild YUV
502 * tables. This is needed since conversion buffer size may have
504 p_vout->i_changes |= VOUT_YUV_CHANGE;
505 intf_Msg("vout: video display resized (%dx%d)", p_vout->i_width, p_vout->i_height);
511 /*****************************************************************************
512 * vout_Display: displays previously rendered output
513 *****************************************************************************
514 * This function send the currently rendered image to X11 server, wait until
515 * it is displayed and switch the two rendering buffer, preparing next frame.
516 *****************************************************************************/
517 static void vout_Display( vout_thread_t *p_vout )
519 if( p_vout->p_sys->b_shm) /* XShm is used */
521 /* Display rendered image using shared memory extension */
522 XShmPutImage(p_vout->p_sys->p_display, p_vout->p_sys->window, p_vout->p_sys->gc,
523 p_vout->p_sys->p_ximage[ p_vout->i_buffer_index ],
525 p_vout->p_sys->p_ximage[ p_vout->i_buffer_index ]->width,
526 p_vout->p_sys->p_ximage[ p_vout->i_buffer_index ]->height, True);
528 /* Send the order to the X server */
529 XSync(p_vout->p_sys->p_display, False);
531 else /* regular X11 capabilities are used */
533 XPutImage(p_vout->p_sys->p_display, p_vout->p_sys->window, p_vout->p_sys->gc,
534 p_vout->p_sys->p_ximage[ p_vout->i_buffer_index ],
536 p_vout->p_sys->p_ximage[ p_vout->i_buffer_index ]->width,
537 p_vout->p_sys->p_ximage[ p_vout->i_buffer_index ]->height);
539 /* Send the order to the X server */
540 XSync(p_vout->p_sys->p_display, False);
544 /*****************************************************************************
545 * vout_SetPalette: sets an 8 bpp palette
546 *****************************************************************************
547 * This function sets the palette given as an argument. It does not return
548 * anything, but could later send information on which colors it was unable
550 *****************************************************************************/
551 static void vout_SetPalette( p_vout_thread_t p_vout,
552 u16 *red, u16 *green, u16 *blue, u16 *transp )
555 XColor p_colors[255];
557 intf_DbgMsg( "Palette change called" );
559 /* allocate palette */
560 for( i = 0, j = 255; i < 255; i++, j-- )
562 /* kludge: colors are indexed reversely because color 255 seems
563 * to be reserved for black even if we try to set it to white */
564 p_colors[ i ].pixel = j;
565 p_colors[ i ].pad = 0;
566 p_colors[ i ].flags = DoRed | DoGreen | DoBlue;
567 p_colors[ i ].red = red[ j ];
568 p_colors[ i ].blue = blue[ j ];
569 p_colors[ i ].green = green[ j ];
572 XStoreColors( p_vout->p_sys->p_display,
573 p_vout->p_sys->colormap, p_colors, 256 );
576 /* following functions are local */
578 /*****************************************************************************
579 * X11CreateWindow: open and set-up X11 main window
580 *****************************************************************************/
581 static int X11CreateWindow( vout_thread_t *p_vout )
583 XSizeHints xsize_hints;
584 XSetWindowAttributes xwindow_attributes;
588 boolean_t b_configure_notify;
589 boolean_t b_map_notify;
591 /* Set main window's size */
592 p_vout->p_sys->i_width = main_GetIntVariable( VOUT_WIDTH_VAR,
593 VOUT_WIDTH_DEFAULT );
594 p_vout->p_sys->i_height = main_GetIntVariable( VOUT_HEIGHT_VAR,
595 VOUT_HEIGHT_DEFAULT );
597 /* Prepare window manager hints and properties */
598 xsize_hints.base_width = p_vout->p_sys->i_width;
599 xsize_hints.base_height = p_vout->p_sys->i_height;
600 xsize_hints.flags = PSize;
601 p_vout->p_sys->wm_protocols = XInternAtom( p_vout->p_sys->p_display,
602 "WM_PROTOCOLS", True );
603 p_vout->p_sys->wm_delete_window = XInternAtom( p_vout->p_sys->p_display,
604 "WM_DELETE_WINDOW", True );
606 /* Prepare window attributes */
607 xwindow_attributes.backing_store = Always; /* save the hidden part */
608 xwindow_attributes.background_pixel = WhitePixel( p_vout->p_sys->p_display,
609 p_vout->p_sys->i_screen );
611 xwindow_attributes.event_mask = ExposureMask | StructureNotifyMask;
613 /* Create the window and set hints - the window must receive ConfigureNotify
614 * events, and, until it is displayed, Expose and MapNotify events. */
615 p_vout->p_sys->window =
616 XCreateWindow( p_vout->p_sys->p_display,
617 DefaultRootWindow( p_vout->p_sys->p_display ),
619 p_vout->p_sys->i_width, p_vout->p_sys->i_height, 1,
621 CWBackingStore | CWBackPixel | CWEventMask,
622 &xwindow_attributes );
624 /* Set window manager hints and properties: size hints, command,
625 * window's name, and accepted protocols */
626 XSetWMNormalHints( p_vout->p_sys->p_display, p_vout->p_sys->window,
628 XSetCommand( p_vout->p_sys->p_display, p_vout->p_sys->window,
629 p_main->ppsz_argv, p_main->i_argc );
630 XStoreName( p_vout->p_sys->p_display, p_vout->p_sys->window,
631 VOUT_TITLE " (X11 output)" );
633 if( (p_vout->p_sys->wm_protocols == None) /* use WM_DELETE_WINDOW */
634 || (p_vout->p_sys->wm_delete_window == None)
635 || !XSetWMProtocols( p_vout->p_sys->p_display, p_vout->p_sys->window,
636 &p_vout->p_sys->wm_delete_window, 1 ) )
638 /* WM_DELETE_WINDOW is not supported by window manager */
639 intf_Msg( "intf error: missing or bad window manager" );
642 /* Creation of a graphic context that doesn't generate a GraphicsExpose
643 * event when using functions like XCopyArea */
644 xgcvalues.graphics_exposures = False;
645 p_vout->p_sys->gc = XCreateGC( p_vout->p_sys->p_display,
646 p_vout->p_sys->window,
647 GCGraphicsExposures, &xgcvalues);
649 /* Send orders to server, and wait until window is displayed - three
650 * events must be received: a MapNotify event, an Expose event allowing
651 * drawing in the window, and a ConfigureNotify to get the window
652 * dimensions. Once those events have been received, only ConfigureNotify
653 * events need to be received. */
655 b_configure_notify = 0;
657 XMapWindow( p_vout->p_sys->p_display, p_vout->p_sys->window);
660 XNextEvent( p_vout->p_sys->p_display, &xevent);
661 if( (xevent.type == Expose)
662 && (xevent.xexpose.window == p_vout->p_sys->window) )
666 else if( (xevent.type == MapNotify)
667 && (xevent.xmap.window == p_vout->p_sys->window) )
671 else if( (xevent.type == ConfigureNotify)
672 && (xevent.xconfigure.window == p_vout->p_sys->window) )
674 b_configure_notify = 1;
675 p_vout->p_sys->i_width = xevent.xconfigure.width;
676 p_vout->p_sys->i_height = xevent.xconfigure.height;
678 } while( !( b_expose && b_configure_notify && b_map_notify ) );
680 XSelectInput( p_vout->p_sys->p_display, p_vout->p_sys->window,
681 StructureNotifyMask | KeyPressMask | ButtonPressMask );
683 if( XDefaultDepth(p_vout->p_sys->p_display, p_vout->p_sys->i_screen) == 8 )
685 /* Allocate a new palette */
686 p_vout->p_sys->colormap =
687 XCreateColormap( p_vout->p_sys->p_display,
688 DefaultRootWindow( p_vout->p_sys->p_display ),
689 DefaultVisual( p_vout->p_sys->p_display,
690 p_vout->p_sys->i_screen ),
693 xwindow_attributes.colormap = p_vout->p_sys->colormap;
694 XChangeWindowAttributes( p_vout->p_sys->p_display,
695 p_vout->p_sys->window,
696 CWColormap, &xwindow_attributes );
699 /* At this stage, the window is open, displayed, and ready to
704 /*****************************************************************************
705 * X11InitDisplay: open and initialize X11 device
706 *****************************************************************************
707 * Create a window according to video output given size, and set other
708 * properties according to the display properties.
709 *****************************************************************************/
710 static int X11InitDisplay( vout_thread_t *p_vout, char *psz_display )
712 XPixmapFormatValues * p_formats; /* pixmap formats */
713 XVisualInfo * p_xvisual; /* visuals informations */
714 XVisualInfo xvisual_template; /* visual template */
715 int i_count; /* array size */
717 /* Initialize structure */
718 p_vout->p_sys->i_screen = DefaultScreen( p_vout->p_sys->p_display );
719 p_vout->p_sys->b_shm = ( XShmQueryExtension( p_vout->p_sys->p_display )
721 if( !p_vout->p_sys->b_shm )
723 intf_Msg("vout: XShm video extension is not available");
726 /* Get screen depth */
727 p_vout->i_screen_depth = XDefaultDepth( p_vout->p_sys->p_display,
728 p_vout->p_sys->i_screen );
729 switch( p_vout->i_screen_depth )
733 * Screen depth is 8bpp. Use PseudoColor visual with private colormap.
735 xvisual_template.screen = p_vout->p_sys->i_screen;
736 xvisual_template.class = DirectColor;
737 p_xvisual = XGetVisualInfo( p_vout->p_sys->p_display,
738 VisualScreenMask | VisualClassMask,
739 &xvisual_template, &i_count );
740 if( p_xvisual == NULL )
742 intf_ErrMsg("vout error: no PseudoColor visual available");
745 p_vout->i_bytes_per_pixel = 1;
752 * Screen depth is higher than 8bpp. TrueColor visual is used.
754 xvisual_template.screen = p_vout->p_sys->i_screen;
755 xvisual_template.class = TrueColor;
756 p_xvisual = XGetVisualInfo( p_vout->p_sys->p_display,
757 VisualScreenMask | VisualClassMask,
758 &xvisual_template, &i_count );
759 if( p_xvisual == NULL )
761 intf_ErrMsg("vout error: no TrueColor visual available");
764 p_vout->i_red_mask = p_xvisual->red_mask;
765 p_vout->i_green_mask = p_xvisual->green_mask;
766 p_vout->i_blue_mask = p_xvisual->blue_mask;
768 /* There is no difference yet between 3 and 4 Bpp. The only way
769 * to find the actual number of bytes per pixel is to list supported
771 p_formats = XListPixmapFormats( p_vout->p_sys->p_display, &i_count );
772 p_vout->i_bytes_per_pixel = 0;
774 for( ; i_count-- ; p_formats++ )
776 /* Under XFree4.0, the list contains pixmap formats available
777 * through all video depths ; so we have to check against current
779 if( p_formats->depth == p_vout->i_screen_depth )
781 if( p_formats->bits_per_pixel / 8
782 > p_vout->i_bytes_per_pixel )
784 p_vout->i_bytes_per_pixel = p_formats->bits_per_pixel / 8;
790 p_vout->p_sys->p_visual = p_xvisual->visual;
796 /*****************************************************************************
797 * X11CreateImage: create an XImage
798 *****************************************************************************
799 * Create a simple XImage used as a buffer.
800 *****************************************************************************/
801 static int X11CreateImage( vout_thread_t *p_vout, XImage **pp_ximage )
803 byte_t * pb_data; /* image data storage zone */
804 int i_quantum; /* XImage quantum (see below) */
806 /* Allocate memory for image */
807 p_vout->i_bytes_per_line = p_vout->i_width * p_vout->i_bytes_per_pixel;
808 pb_data = (byte_t *) malloc( p_vout->i_bytes_per_line * p_vout->i_height );
809 if( !pb_data ) /* error */
811 intf_ErrMsg("error: %s", strerror(ENOMEM));
815 /* Optimize the quantum of a scanline regarding its size - the quantum is
816 a diviser of the number of bits between the start of two scanlines. */
817 if( !(( p_vout->i_bytes_per_line ) % 32) )
823 if( !(( p_vout->i_bytes_per_line ) % 16) )
834 *pp_ximage = XCreateImage( p_vout->p_sys->p_display,
835 p_vout->p_sys->p_visual, p_vout->i_screen_depth,
837 p_vout->i_width, p_vout->i_height, i_quantum, 0);
838 if(! *pp_ximage ) /* error */
840 intf_ErrMsg( "error: XCreateImage() failed" );
848 /*****************************************************************************
849 * X11CreateShmImage: create an XImage using shared memory extension
850 *****************************************************************************
851 * Prepare an XImage for DisplayX11ShmImage function.
852 * The order of the operations respects the recommandations of the mit-shm
853 * document by J.Corbet and K.Packard. Most of the parameters were copied from
855 *****************************************************************************/
856 static int X11CreateShmImage( vout_thread_t *p_vout, XImage **pp_ximage,
857 XShmSegmentInfo *p_shm_info)
861 XShmCreateImage( p_vout->p_sys->p_display, p_vout->p_sys->p_visual,
862 p_vout->i_screen_depth, ZPixmap, 0,
863 p_shm_info, p_vout->i_width, p_vout->i_height );
864 if(! *pp_ximage ) /* error */
866 intf_ErrMsg("error: XShmCreateImage() failed");
870 /* Allocate shared memory segment - 0777 set the access permission
871 * rights (like umask), they are not yet supported by X servers */
873 shmget( IPC_PRIVATE, (*pp_ximage)->bytes_per_line
874 * (*pp_ximage)->height, IPC_CREAT | 0777);
875 if( p_shm_info->shmid < 0) /* error */
877 intf_ErrMsg("error: can't allocate shared image data (%s)",
879 XDestroyImage( *pp_ximage );
883 /* Attach shared memory segment to process (read/write) */
884 p_shm_info->shmaddr = (*pp_ximage)->data = shmat(p_shm_info->shmid, 0, 0);
885 if(! p_shm_info->shmaddr )
887 intf_ErrMsg("error: can't attach shared memory (%s)",
889 shmctl( p_shm_info->shmid, IPC_RMID, 0 ); /* free shared memory */
890 XDestroyImage( *pp_ximage );
894 /* Mark the shm segment to be removed when there will be no more
895 * attachements, so it is automatic on process exit or after shmdt */
896 shmctl( p_shm_info->shmid, IPC_RMID, 0 );
898 /* Attach shared memory segment to X server (read only) */
899 p_shm_info->readOnly = True;
900 if( XShmAttach( p_vout->p_sys->p_display, p_shm_info )
901 == False ) /* error */
903 intf_ErrMsg("error: can't attach shared memory to X11 server");
904 shmdt( p_shm_info->shmaddr ); /* detach shared memory from process
905 * and automatic free */
906 XDestroyImage( *pp_ximage );
910 /* Send image to X server. This instruction is required, since having
911 * built a Shm XImage and not using it causes an error on XCloseDisplay */
912 XFlush( p_vout->p_sys->p_display );
916 /*****************************************************************************
917 * X11DestroyImage: destroy an XImage
918 *****************************************************************************
919 * Destroy XImage AND associated data. If pointer is NULL, the image won't be
920 * destroyed (see vout_ManageOutputMethod())
921 *****************************************************************************/
922 static void X11DestroyImage( XImage *p_ximage )
924 if( p_ximage != NULL )
926 XDestroyImage( p_ximage ); /* no free() required */
930 /*****************************************************************************
932 *****************************************************************************
933 * Destroy XImage AND associated data. Detach shared memory segment from
934 * server and process, then free it. If pointer is NULL, the image won't be
935 * destroyed (see vout_ManageOutputMethod())
936 *****************************************************************************/
937 static void X11DestroyShmImage( vout_thread_t *p_vout, XImage *p_ximage,
938 XShmSegmentInfo *p_shm_info )
940 /* If pointer is NULL, do nothing */
941 if( p_ximage == NULL )
946 XShmDetach( p_vout->p_sys->p_display, p_shm_info );/* detach from server */
947 XDestroyImage( p_ximage );
949 if( shmdt( p_shm_info->shmaddr ) ) /* detach shared memory from process */
950 { /* also automatic freeing... */
951 intf_ErrMsg( "error: can't detach shared memory (%s)",
959 /*****************************************************************************
960 * X11EnableScreenSaver: enable screen saver
961 *****************************************************************************
962 * This function enable the screen saver on a display after it had been
963 * disabled by XDisableScreenSaver. Both functions use a counter mechanism to
964 * know wether the screen saver can be activated or not: if n successive calls
965 * are made to XDisableScreenSaver, n successive calls to XEnableScreenSaver
966 * will be required before the screen saver could effectively be activated.
967 *****************************************************************************/
968 void X11EnableScreenSaver( vout_thread_t *p_vout )
970 intf_DbgMsg( "intf: enabling screen saver" );
971 XSetScreenSaver( p_vout->p_sys->p_display, p_vout->p_sys->i_ss_timeout,
972 p_vout->p_sys->i_ss_interval,
973 p_vout->p_sys->i_ss_blanking,
974 p_vout->p_sys->i_ss_exposure );
977 /*****************************************************************************
978 * X11DisableScreenSaver: disable screen saver
979 *****************************************************************************
980 * See XEnableScreenSaver
981 *****************************************************************************/
982 void X11DisableScreenSaver( vout_thread_t *p_vout )
984 /* Save screen saver informations */
985 XGetScreenSaver( p_vout->p_sys->p_display, &p_vout->p_sys->i_ss_timeout,
986 &p_vout->p_sys->i_ss_interval,
987 &p_vout->p_sys->i_ss_blanking,
988 &p_vout->p_sys->i_ss_exposure );
990 /* Disable screen saver */
991 intf_DbgMsg("intf: disabling screen saver");
992 XSetScreenSaver( p_vout->p_sys->p_display, 0,
993 p_vout->p_sys->i_ss_interval,
994 p_vout->p_sys->i_ss_blanking,
995 p_vout->p_sys->i_ss_exposure );
998 /*****************************************************************************
999 * X11TogglePointer: hide or show the mouse pointer
1000 *****************************************************************************
1001 * This function hides the X pointer if it is visible by putting it at
1002 * coordinates (32,32) and setting the pointer sprite to a blank one. To
1003 * show it again, we disable the sprite and restore the original coordinates.
1004 *****************************************************************************/
1005 void X11TogglePointer( vout_thread_t *p_vout )
1007 static Cursor cursor;
1008 static boolean_t b_cursor = 0;
1010 if( p_vout->p_sys->b_mouse )
1012 p_vout->p_sys->b_mouse = 0;
1017 Pixmap blank = XCreatePixmap( p_vout->p_sys->p_display,
1018 DefaultRootWindow(p_vout->p_sys->p_display),
1021 XParseColor( p_vout->p_sys->p_display,
1022 XCreateColormap( p_vout->p_sys->p_display,
1024 p_vout->p_sys->p_display ),
1026 p_vout->p_sys->p_display,
1027 p_vout->p_sys->i_screen ),
1031 cursor = XCreatePixmapCursor( p_vout->p_sys->p_display,
1032 blank, blank, &color, &color, 1, 1 );
1036 XDefineCursor( p_vout->p_sys->p_display,
1037 p_vout->p_sys->window, cursor );
1041 p_vout->p_sys->b_mouse = 1;
1043 XUndefineCursor( p_vout->p_sys->p_display, p_vout->p_sys->window );