1 /*****************************************************************************
2 * xcommon.c: Functions common to the X11 and XVideo plugins
3 *****************************************************************************
4 * Copyright (C) 1998-2006 the VideoLAN team
7 * Authors: Vincent Seguin <seguin@via.ecp.fr>
8 * Sam Hocevar <sam@zoy.org>
9 * David Kennedy <dkennedy@tinytoad.com>
10 * Gildas Bazin <gbazin@videolan.org>
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., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
25 *****************************************************************************/
27 /*****************************************************************************
29 *****************************************************************************/
34 #include <vlc_common.h>
35 #include <vlc_playlist.h>
37 #include <vlc_vout_window.h>
40 #ifdef HAVE_MACHINE_PARAM_H
42 # include <machine/param.h>
43 # include <sys/types.h> /* typedef ushort */
48 #include <X11/Xproto.h>
50 #include <X11/Xutil.h>
51 #ifdef DPMSINFO_IN_DPMS_H
52 # include <X11/extensions/dpms.h>
55 #ifdef MODULE_NAME_IS_glx
61 /*****************************************************************************
63 *****************************************************************************/
64 int Activate ( vlc_object_t * );
65 void Deactivate ( vlc_object_t * );
67 static int ManageVideo ( vout_thread_t * );
68 static int Control ( vout_thread_t *, int, va_list );
70 static int CreateWindow ( vout_thread_t *, x11_window_t * );
71 static void DestroyWindow ( vout_thread_t *, x11_window_t * );
73 static void ToggleFullScreen ( vout_thread_t * );
75 static void EnableXScreenSaver ( vout_thread_t * );
76 static void DisableXScreenSaver ( vout_thread_t * );
78 static void CreateCursor ( vout_thread_t * );
79 static void DestroyCursor ( vout_thread_t * );
80 static void ToggleCursor ( vout_thread_t * );
82 static int X11ErrorHandler( Display *, XErrorEvent * );
84 /*****************************************************************************
85 * Activate: allocate X11 video thread output method
86 *****************************************************************************
87 * This function allocate and initialize a X11 vout method. It uses some of the
88 * vout properties to choose the window size, and change them according to the
89 * actual properties of the display.
90 *****************************************************************************/
91 int Activate ( vlc_object_t *p_this )
93 vout_thread_t *p_vout = (vout_thread_t *)p_this;
96 p_vout->pf_render = NULL;
97 p_vout->pf_manage = ManageVideo;
98 p_vout->pf_control = Control;
100 /* Allocate structure */
101 p_vout->p_sys = malloc( sizeof( vout_sys_t ) );
102 if( p_vout->p_sys == NULL )
105 /* Open display, using the "display" config variable or the DISPLAY
106 * environment variable */
107 psz_display = config_GetPsz( p_vout, MODULE_STRING "-display" );
109 p_vout->p_sys->p_display = XOpenDisplay( psz_display );
111 if( p_vout->p_sys->p_display == NULL ) /* error */
113 msg_Err( p_vout, "cannot open display %s",
114 XDisplayName( psz_display ) );
115 free( p_vout->p_sys );
121 /* Replace error handler so we can intercept some non-fatal errors */
122 XSetErrorHandler( X11ErrorHandler );
124 /* Get a screen ID matching the XOpenDisplay return value */
125 p_vout->p_sys->i_screen = DefaultScreen( p_vout->p_sys->p_display );
127 #if defined(MODULE_NAME_IS_glx)
129 int i_opcode, i_evt, i_err = 0;
130 int i_maj, i_min = 0;
132 /* Check for GLX extension */
133 if( !XQueryExtension( p_vout->p_sys->p_display, "GLX",
134 &i_opcode, &i_evt, &i_err ) )
136 msg_Err( p_this, "GLX extension not supported" );
137 XCloseDisplay( p_vout->p_sys->p_display );
138 free( p_vout->p_sys );
141 if( !glXQueryExtension( p_vout->p_sys->p_display, &i_err, &i_evt ) )
143 msg_Err( p_this, "glXQueryExtension failed" );
144 XCloseDisplay( p_vout->p_sys->p_display );
145 free( p_vout->p_sys );
149 /* Check GLX version */
150 if (!glXQueryVersion( p_vout->p_sys->p_display, &i_maj, &i_min ) )
152 msg_Err( p_this, "glXQueryVersion failed" );
153 XCloseDisplay( p_vout->p_sys->p_display );
154 free( p_vout->p_sys );
157 if( i_maj <= 0 || ((i_maj == 1) && (i_min < 3)) )
159 p_vout->p_sys->b_glx13 = false;
160 msg_Dbg( p_this, "using GLX 1.2 API" );
164 p_vout->p_sys->b_glx13 = true;
165 msg_Dbg( p_this, "using GLX 1.3 API" );
170 /* Create blank cursor (for mouse cursor autohiding) */
171 p_vout->p_sys->i_time_mouse_last_moved = mdate();
172 p_vout->p_sys->i_mouse_hide_timeout =
173 var_GetInteger(p_vout, "mouse-hide-timeout") * 1000;
174 p_vout->p_sys->b_mouse_pointer_visible = 1;
175 CreateCursor( p_vout );
177 /* Set main window's size */
178 p_vout->p_sys->window.i_x = 0;
179 p_vout->p_sys->window.i_y = 0;
180 p_vout->p_sys->window.i_width = p_vout->i_window_width;
181 p_vout->p_sys->window.i_height = p_vout->i_window_height;
182 var_Create( p_vout, "video-title", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
183 /* Spawn base window - this window will include the video output window,
184 * but also command buttons, subtitles and other indicators */
185 if( CreateWindow( p_vout, &p_vout->p_sys->window ) )
187 msg_Err( p_vout, "cannot create X11 window" );
188 DestroyCursor( p_vout );
189 XCloseDisplay( p_vout->p_sys->p_display );
190 free( p_vout->p_sys );
194 /* Disable screen saver */
195 DisableXScreenSaver( p_vout );
198 p_vout->p_sys->i_time_button_last_pressed = 0;
200 /* Variable to indicate if the window should be on top of others */
201 /* Trigger a callback right now */
202 var_TriggerCallback( p_vout, "video-on-top" );
207 /*****************************************************************************
208 * Deactivate: destroy X11 video thread output method
209 *****************************************************************************
210 * Terminate an output method created by Open
211 *****************************************************************************/
212 void Deactivate ( vlc_object_t *p_this )
214 vout_thread_t *p_vout = (vout_thread_t *)p_this;
216 /* Restore cursor if it was blanked */
217 if( !p_vout->p_sys->b_mouse_pointer_visible )
219 ToggleCursor( p_vout );
222 DestroyCursor( p_vout );
223 EnableXScreenSaver( p_vout );
224 DestroyWindow( p_vout, &p_vout->p_sys->window );
225 XCloseDisplay( p_vout->p_sys->p_display );
227 /* Destroy structure */
228 free( p_vout->p_sys );
231 /*****************************************************************************
232 * ManageVideo: handle X11 events
233 *****************************************************************************
234 * This function should be called regularly by video output thread. It manages
235 * X11 events and allows window resizing. It returns a non null value on
237 *****************************************************************************/
238 static int ManageVideo( vout_thread_t *p_vout )
240 XEvent xevent; /* X11 event */
243 /* Handle events from the owner window */
244 while( XCheckWindowEvent( p_vout->p_sys->p_display,
245 p_vout->p_sys->window.owner_window->xid,
246 StructureNotifyMask, &xevent ) == True )
248 /* ConfigureNotify event: prepare */
249 if( xevent.type == ConfigureNotify )
250 /* Update dimensions */
251 XResizeWindow( p_vout->p_sys->p_display,
252 p_vout->p_sys->window.base_window,
253 xevent.xconfigure.width,
254 xevent.xconfigure.height );
257 /* Handle X11 events: ConfigureNotify events are parsed to know if the
258 * output window's size changed, MapNotify and UnmapNotify to know if the
259 * window is mapped (and if the display is useful), and ClientMessages
260 * to intercept window destruction requests */
262 while( XCheckWindowEvent( p_vout->p_sys->p_display,
263 p_vout->p_sys->window.base_window,
264 StructureNotifyMask |
265 ButtonPressMask | ButtonReleaseMask |
266 PointerMotionMask | Button1MotionMask , &xevent )
269 /* ConfigureNotify event: prepare */
270 if( xevent.type == ConfigureNotify )
272 if( (unsigned int)xevent.xconfigure.width
273 != p_vout->p_sys->window.i_width
274 || (unsigned int)xevent.xconfigure.height
275 != p_vout->p_sys->window.i_height )
277 /* Update dimensions */
278 p_vout->i_changes |= VOUT_SIZE_CHANGE;
279 p_vout->p_sys->window.i_width = xevent.xconfigure.width;
280 p_vout->p_sys->window.i_height = xevent.xconfigure.height;
284 else if( xevent.type == ButtonPress )
286 switch( ((XButtonEvent *)&xevent)->button )
289 var_Get( p_vout, "mouse-button-down", &val );
291 var_Set( p_vout, "mouse-button-down", val );
293 var_SetBool( p_vout->p_libvlc, "intf-popupmenu", false );
295 /* detect double-clicks */
296 if( ( ((XButtonEvent *)&xevent)->time -
297 p_vout->p_sys->i_time_button_last_pressed ) < 300 )
299 p_vout->i_changes |= VOUT_FULLSCREEN_CHANGE;
302 p_vout->p_sys->i_time_button_last_pressed =
303 ((XButtonEvent *)&xevent)->time;
306 var_Get( p_vout, "mouse-button-down", &val );
308 var_Set( p_vout, "mouse-button-down", val );
312 var_Get( p_vout, "mouse-button-down", &val );
314 var_Set( p_vout, "mouse-button-down", val );
315 var_SetBool( p_vout->p_libvlc, "intf-popupmenu", true );
319 var_Get( p_vout, "mouse-button-down", &val );
321 var_Set( p_vout, "mouse-button-down", val );
325 var_Get( p_vout, "mouse-button-down", &val );
327 var_Set( p_vout, "mouse-button-down", val );
332 else if( xevent.type == ButtonRelease )
334 switch( ((XButtonEvent *)&xevent)->button )
338 var_Get( p_vout, "mouse-button-down", &val );
340 var_Set( p_vout, "mouse-button-down", val );
342 var_SetBool( p_vout, "mouse-clicked", true );
348 var_Get( p_vout, "mouse-button-down", &val );
350 var_Set( p_vout, "mouse-button-down", val );
352 var_ToggleBool( p_vout->p_libvlc, "intf-show" );
358 var_Get( p_vout, "mouse-button-down", &val );
360 var_Set( p_vout, "mouse-button-down", val );
366 var_Get( p_vout, "mouse-button-down", &val );
368 var_Set( p_vout, "mouse-button-down", val );
372 var_Get( p_vout, "mouse-button-down", &val );
374 var_Set( p_vout, "mouse-button-down", val );
380 else if( xevent.type == MotionNotify )
382 unsigned int i_width, i_height, i_x, i_y;
384 /* somewhat different use for vout_PlacePicture:
385 * here the values are needed to give to mouse coordinates
386 * in the original picture space */
387 vout_PlacePicture( p_vout, p_vout->p_sys->window.i_width,
388 p_vout->p_sys->window.i_height,
389 &i_x, &i_y, &i_width, &i_height );
391 /* Compute the x coordinate and check if the value is
392 in [0,p_vout->fmt_in.i_visible_width] */
393 val.i_int = ( xevent.xmotion.x - i_x ) *
394 p_vout->fmt_in.i_visible_width / i_width +
395 p_vout->fmt_in.i_x_offset;
397 if( (int)(xevent.xmotion.x - i_x) < 0 )
399 else if( (unsigned int)val.i_int > p_vout->fmt_in.i_visible_width )
400 val.i_int = p_vout->fmt_in.i_visible_width;
402 var_Set( p_vout, "mouse-x", val );
404 /* compute the y coordinate and check if the value is
405 in [0,p_vout->fmt_in.i_visible_height] */
406 val.i_int = ( xevent.xmotion.y - i_y ) *
407 p_vout->fmt_in.i_visible_height / i_height +
408 p_vout->fmt_in.i_y_offset;
410 if( (int)(xevent.xmotion.y - i_y) < 0 )
412 else if( (unsigned int)val.i_int > p_vout->fmt_in.i_visible_height )
413 val.i_int = p_vout->fmt_in.i_visible_height;
415 var_Set( p_vout, "mouse-y", val );
417 var_SetBool( p_vout, "mouse-moved", true );
419 p_vout->p_sys->i_time_mouse_last_moved = mdate();
420 if( ! p_vout->p_sys->b_mouse_pointer_visible )
422 ToggleCursor( p_vout );
425 else if( xevent.type == ReparentNotify /* XXX: why do we get this? */
426 || xevent.type == MapNotify
427 || xevent.type == UnmapNotify )
429 /* Ignore these events */
431 else /* Other events */
433 msg_Warn( p_vout, "unhandled event %d received", xevent.type );
437 /* Handle events for video output sub-window */
438 while( XCheckWindowEvent( p_vout->p_sys->p_display,
439 p_vout->p_sys->window.video_window,
440 ExposureMask, &xevent ) == True );
442 /* ClientMessage event - only WM_PROTOCOLS with WM_DELETE_WINDOW data
443 * are handled - according to the man pages, the format is always 32
445 while( XCheckTypedEvent( p_vout->p_sys->p_display,
446 ClientMessage, &xevent ) )
448 if( (xevent.xclient.message_type == p_vout->p_sys->window.wm_protocols)
449 && ((Atom)xevent.xclient.data.l[0]
450 == p_vout->p_sys->window.wm_delete_window ) )
452 /* the user wants to close the window */
453 playlist_t * p_playlist = pl_Hold( p_vout );
454 if( p_playlist != NULL )
456 playlist_Stop( p_playlist );
457 pl_Release( p_vout );
465 if ( p_vout->i_changes & VOUT_FULLSCREEN_CHANGE )
467 /* Update the object variable and trigger callback */
468 var_SetBool( p_vout, "fullscreen", !p_vout->b_fullscreen );
470 ToggleFullScreen( p_vout );
471 p_vout->i_changes &= ~VOUT_FULLSCREEN_CHANGE;
474 /* autoscale toggle */
475 if( p_vout->i_changes & VOUT_SCALE_CHANGE )
477 p_vout->i_changes &= ~VOUT_SCALE_CHANGE;
479 p_vout->b_autoscale = var_GetBool( p_vout, "autoscale" );
480 p_vout->i_zoom = ZOOM_FP_FACTOR;
482 p_vout->i_changes |= VOUT_SIZE_CHANGE;
486 if( p_vout->i_changes & VOUT_ZOOM_CHANGE )
488 p_vout->i_changes &= ~VOUT_ZOOM_CHANGE;
490 p_vout->b_autoscale = false;
492 (int)( ZOOM_FP_FACTOR * var_GetFloat( p_vout, "scale" ) );
494 p_vout->i_changes |= VOUT_SIZE_CHANGE;
497 if( p_vout->i_changes & VOUT_CROP_CHANGE ||
498 p_vout->i_changes & VOUT_ASPECT_CHANGE )
500 p_vout->i_changes &= ~VOUT_CROP_CHANGE;
501 p_vout->i_changes &= ~VOUT_ASPECT_CHANGE;
503 p_vout->fmt_out.i_x_offset = p_vout->fmt_in.i_x_offset;
504 p_vout->fmt_out.i_y_offset = p_vout->fmt_in.i_y_offset;
505 p_vout->fmt_out.i_visible_width = p_vout->fmt_in.i_visible_width;
506 p_vout->fmt_out.i_visible_height = p_vout->fmt_in.i_visible_height;
507 p_vout->fmt_out.i_aspect = p_vout->fmt_in.i_aspect;
508 p_vout->fmt_out.i_sar_num = p_vout->fmt_in.i_sar_num;
509 p_vout->fmt_out.i_sar_den = p_vout->fmt_in.i_sar_den;
510 p_vout->output.i_aspect = p_vout->fmt_in.i_aspect;
512 p_vout->i_changes |= VOUT_SIZE_CHANGE;
518 * (Needs to be placed after VOUT_FULLSREEN_CHANGE because we can activate
519 * the size flag inside the fullscreen routine)
521 if( p_vout->i_changes & VOUT_SIZE_CHANGE )
523 unsigned int i_width, i_height, i_x, i_y;
525 p_vout->i_changes &= ~VOUT_SIZE_CHANGE;
527 vout_PlacePicture( p_vout, p_vout->p_sys->window.i_width,
528 p_vout->p_sys->window.i_height,
529 &i_x, &i_y, &i_width, &i_height );
531 XMoveResizeWindow( p_vout->p_sys->p_display,
532 p_vout->p_sys->window.video_window,
533 i_x, i_y, i_width, i_height );
536 /* Autohide Cursour */
537 if( mdate() - p_vout->p_sys->i_time_mouse_last_moved >
538 p_vout->p_sys->i_mouse_hide_timeout )
540 /* Hide the mouse automatically */
541 if( p_vout->p_sys->b_mouse_pointer_visible )
543 ToggleCursor( p_vout );
550 /* following functions are local */
552 /*****************************************************************************
553 * CreateWindow: open and set-up X11 main window
554 *****************************************************************************/
555 static int CreateWindow( vout_thread_t *p_vout, x11_window_t *p_win )
557 XSizeHints xsize_hints;
558 XSetWindowAttributes xwindow_attributes;
562 bool b_map_notify = false;
564 /* Prepare window manager hints and properties */
565 p_win->wm_protocols =
566 XInternAtom( p_vout->p_sys->p_display, "WM_PROTOCOLS", True );
567 p_win->wm_delete_window =
568 XInternAtom( p_vout->p_sys->p_display, "WM_DELETE_WINDOW", True );
570 /* Never have a 0-pixel-wide window */
571 xsize_hints.min_width = 2;
572 xsize_hints.min_height = 1;
574 /* Prepare window attributes */
575 xwindow_attributes.backing_store = Always; /* save the hidden part */
576 xwindow_attributes.background_pixel = BlackPixel(p_vout->p_sys->p_display,
577 p_vout->p_sys->i_screen);
578 xwindow_attributes.event_mask = ExposureMask | StructureNotifyMask;
581 vout_window_cfg_t wnd_cfg;
582 memset( &wnd_cfg, 0, sizeof(wnd_cfg) );
583 wnd_cfg.type = VOUT_WINDOW_TYPE_XID;
584 wnd_cfg.x = p_win->i_x;
585 wnd_cfg.y = p_win->i_y;
586 wnd_cfg.width = p_win->i_width;
587 wnd_cfg.height = p_win->i_height;
589 p_win->owner_window = vout_window_New( VLC_OBJECT(p_vout), NULL, &wnd_cfg );
590 if( !p_win->owner_window )
592 xsize_hints.base_width = xsize_hints.width = p_win->i_width;
593 xsize_hints.base_height = xsize_hints.height = p_win->i_height;
594 xsize_hints.flags = PSize | PMinSize;
596 if( p_win->i_x >=0 || p_win->i_y >= 0 )
598 xsize_hints.x = p_win->i_x;
599 xsize_hints.y = p_win->i_y;
600 xsize_hints.flags |= PPosition;
603 /* Select events we are interested in. */
604 XSelectInput( p_vout->p_sys->p_display,
605 p_win->owner_window->xid, StructureNotifyMask );
607 /* Get the parent window's geometry information */
608 XGetGeometry( p_vout->p_sys->p_display,
609 p_win->owner_window->xid,
610 &(Window){ 0 }, &(int){ 0 }, &(int){ 0 },
613 &(unsigned){ 0 }, &(unsigned){ 0 } );
615 /* From man XSelectInput: only one client at a time can select a
616 * ButtonPress event, so we need to open a new window anyway. */
618 XCreateWindow( p_vout->p_sys->p_display,
619 p_win->owner_window->xid,
621 p_win->i_width, p_win->i_height,
623 0, CopyFromParent, 0,
624 CWBackingStore | CWBackPixel | CWEventMask,
625 &xwindow_attributes );
628 if( (p_win->wm_protocols == None) /* use WM_DELETE_WINDOW */
629 || (p_win->wm_delete_window == None)
630 || !XSetWMProtocols( p_vout->p_sys->p_display, p_win->base_window,
631 &p_win->wm_delete_window, 1 ) )
633 /* WM_DELETE_WINDOW is not supported by window manager */
634 msg_Warn( p_vout, "missing or bad window manager" );
637 /* Creation of a graphic context that doesn't generate a GraphicsExpose
638 * event when using functions like XCopyArea */
639 xgcvalues.graphics_exposures = False;
640 p_win->gc = XCreateGC( p_vout->p_sys->p_display,
642 GCGraphicsExposures, &xgcvalues );
644 /* Wait till the window is mapped */
645 XMapWindow( p_vout->p_sys->p_display, p_win->base_window );
648 XWindowEvent( p_vout->p_sys->p_display, p_win->base_window,
649 SubstructureNotifyMask | StructureNotifyMask, &xevent);
650 if( (xevent.type == MapNotify)
651 && (xevent.xmap.window == p_win->base_window) )
655 else if( (xevent.type == ConfigureNotify)
656 && (xevent.xconfigure.window == p_win->base_window) )
658 p_win->i_width = xevent.xconfigure.width;
659 p_win->i_height = xevent.xconfigure.height;
661 } while( !b_map_notify );
663 long mask = StructureNotifyMask | PointerMotionMask;
664 if( var_CreateGetBool( p_vout, "mouse-events" ) )
665 mask |= ButtonPressMask | ButtonReleaseMask;
666 XSelectInput( p_vout->p_sys->p_display, p_win->base_window, mask );
668 /* Create video output sub-window. */
669 p_win->video_window = XCreateSimpleWindow(
670 p_vout->p_sys->p_display,
671 p_win->base_window, 0, 0,
672 p_win->i_width, p_win->i_height,
674 BlackPixel( p_vout->p_sys->p_display,
675 p_vout->p_sys->i_screen ),
676 WhitePixel( p_vout->p_sys->p_display,
677 p_vout->p_sys->i_screen ) );
679 XSetWindowBackground( p_vout->p_sys->p_display, p_win->video_window,
680 BlackPixel( p_vout->p_sys->p_display,
681 p_vout->p_sys->i_screen ) );
683 XMapWindow( p_vout->p_sys->p_display, p_win->video_window );
684 XSelectInput( p_vout->p_sys->p_display, p_win->video_window,
687 /* make sure the video window will be centered in the next ManageVideo() */
688 p_vout->i_changes |= VOUT_SIZE_CHANGE;
690 /* If the cursor was formerly blank than blank it again */
691 if( !p_vout->p_sys->b_mouse_pointer_visible )
693 ToggleCursor( p_vout );
694 ToggleCursor( p_vout );
697 /* Do NOT use XFlush here ! */
698 XSync( p_vout->p_sys->p_display, False );
703 /*****************************************************************************
704 * DestroyWindow: destroy the window
705 *****************************************************************************
707 *****************************************************************************/
708 static void DestroyWindow( vout_thread_t *p_vout, x11_window_t *p_win )
710 /* Do NOT use XFlush here ! */
711 XSync( p_vout->p_sys->p_display, False );
713 if( p_win->video_window != None )
714 XDestroyWindow( p_vout->p_sys->p_display, p_win->video_window );
716 XFreeGC( p_vout->p_sys->p_display, p_win->gc );
718 XUnmapWindow( p_vout->p_sys->p_display, p_win->base_window );
719 XDestroyWindow( p_vout->p_sys->p_display, p_win->base_window );
721 /* make sure base window is destroyed before proceeding further */
722 bool b_destroy_notify = false;
726 XWindowEvent( p_vout->p_sys->p_display, p_win->base_window,
727 SubstructureNotifyMask | StructureNotifyMask, &xevent);
728 if( (xevent.type == DestroyNotify)
729 && (xevent.xmap.window == p_win->base_window) )
731 b_destroy_notify = true;
733 } while( !b_destroy_notify );
735 vout_window_Delete( p_win->owner_window );
738 /*****************************************************************************
739 * ToggleFullScreen: Enable or disable full screen mode
740 *****************************************************************************
741 * This function will switch between fullscreen and window mode.
742 *****************************************************************************/
743 static void ToggleFullScreen ( vout_thread_t *p_vout )
745 p_vout->b_fullscreen = !p_vout->b_fullscreen;
746 vout_window_SetFullScreen( p_vout->p_sys->window.owner_window,
747 p_vout->b_fullscreen );
750 /*****************************************************************************
751 * EnableXScreenSaver: enable screen saver
752 *****************************************************************************
753 * This function enables the screen saver on a display after it has been
754 * disabled by XDisableScreenSaver.
755 * FIXME: what happens if multiple vlc sessions are running at the same
757 *****************************************************************************/
758 static void EnableXScreenSaver( vout_thread_t *p_vout )
760 #ifdef DPMSINFO_IN_DPMS_H
764 if( p_vout->p_sys->i_ss_timeout )
766 XSetScreenSaver( p_vout->p_sys->p_display, p_vout->p_sys->i_ss_timeout,
767 p_vout->p_sys->i_ss_interval,
768 p_vout->p_sys->i_ss_blanking,
769 p_vout->p_sys->i_ss_exposure );
772 /* Restore DPMS settings */
773 #ifdef DPMSINFO_IN_DPMS_H
774 if( DPMSQueryExtension( p_vout->p_sys->p_display, &dummy, &dummy ) )
776 if( p_vout->p_sys->b_ss_dpms )
778 DPMSEnable( p_vout->p_sys->p_display );
784 /*****************************************************************************
785 * DisableXScreenSaver: disable screen saver
786 *****************************************************************************
787 * See XEnableXScreenSaver
788 *****************************************************************************/
789 static void DisableXScreenSaver( vout_thread_t *p_vout )
791 #ifdef DPMSINFO_IN_DPMS_H
795 /* Save screen saver information */
796 XGetScreenSaver( p_vout->p_sys->p_display, &p_vout->p_sys->i_ss_timeout,
797 &p_vout->p_sys->i_ss_interval,
798 &p_vout->p_sys->i_ss_blanking,
799 &p_vout->p_sys->i_ss_exposure );
801 /* Disable screen saver */
802 if( p_vout->p_sys->i_ss_timeout )
804 XSetScreenSaver( p_vout->p_sys->p_display, 0,
805 p_vout->p_sys->i_ss_interval,
806 p_vout->p_sys->i_ss_blanking,
807 p_vout->p_sys->i_ss_exposure );
811 #ifdef DPMSINFO_IN_DPMS_H
812 if( DPMSQueryExtension( p_vout->p_sys->p_display, &dummy, &dummy ) )
815 /* Save DPMS current state */
816 DPMSInfo( p_vout->p_sys->p_display, &unused,
817 &p_vout->p_sys->b_ss_dpms );
818 DPMSDisable( p_vout->p_sys->p_display );
823 /*****************************************************************************
824 * CreateCursor: create a blank mouse pointer
825 *****************************************************************************/
826 static void CreateCursor( vout_thread_t *p_vout )
830 p_vout->p_sys->cursor_pixmap =
831 XCreatePixmap( p_vout->p_sys->p_display,
832 DefaultRootWindow( p_vout->p_sys->p_display ),
835 XParseColor( p_vout->p_sys->p_display,
836 XCreateColormap( p_vout->p_sys->p_display,
838 p_vout->p_sys->p_display ),
840 p_vout->p_sys->p_display,
841 p_vout->p_sys->i_screen ),
843 "black", &cursor_color );
845 p_vout->p_sys->blank_cursor =
846 XCreatePixmapCursor( p_vout->p_sys->p_display,
847 p_vout->p_sys->cursor_pixmap,
848 p_vout->p_sys->cursor_pixmap,
849 &cursor_color, &cursor_color, 1, 1 );
852 /*****************************************************************************
853 * DestroyCursor: destroy the blank mouse pointer
854 *****************************************************************************/
855 static void DestroyCursor( vout_thread_t *p_vout )
857 XFreePixmap( p_vout->p_sys->p_display, p_vout->p_sys->cursor_pixmap );
860 /*****************************************************************************
861 * ToggleCursor: hide or show the mouse pointer
862 *****************************************************************************
863 * This function hides the X pointer if it is visible by setting the pointer
864 * sprite to a blank one. To show it again, we disable the sprite.
865 *****************************************************************************/
866 static void ToggleCursor( vout_thread_t *p_vout )
868 if( p_vout->p_sys->b_mouse_pointer_visible )
870 XDefineCursor( p_vout->p_sys->p_display,
871 p_vout->p_sys->window.base_window,
872 p_vout->p_sys->blank_cursor );
873 p_vout->p_sys->b_mouse_pointer_visible = 0;
877 XUndefineCursor( p_vout->p_sys->p_display,
878 p_vout->p_sys->window.base_window );
879 p_vout->p_sys->b_mouse_pointer_visible = 1;
883 /*****************************************************************************
884 * X11ErrorHandler: replace error handler so we can intercept some of them
885 *****************************************************************************/
886 static int X11ErrorHandler( Display * display, XErrorEvent * event )
890 XGetErrorText( display, event->error_code, txt, sizeof( txt ) );
892 "[????????] x11 video output error: X11 request %u.%u failed "
893 "with error code %u:\n %s\n",
894 event->request_code, event->minor_code, event->error_code, txt );
896 switch( event->request_code )
898 case X_SetInputFocus:
899 /* Ignore errors on XSetInputFocus()
900 * (they happen when a window is not yet mapped) */
904 XSetErrorHandler(NULL);
905 return (XSetErrorHandler(X11ErrorHandler))( display, event );
908 /*****************************************************************************
909 * Control: control facility for the vout
910 *****************************************************************************/
911 static int Control( vout_thread_t *p_vout, int i_query, va_list args )
913 unsigned int i_width, i_height;
918 i_width = va_arg( args, unsigned int );
919 i_height = va_arg( args, unsigned int );
920 if( !i_width ) i_width = p_vout->i_window_width;
921 if( !i_height ) i_height = p_vout->i_window_height;
923 return vout_window_SetSize( p_vout->p_sys->window.owner_window,
926 case VOUT_SET_STAY_ON_TOP:
927 return vout_window_SetOnTop( p_vout->p_sys->window.owner_window,
928 va_arg( args, int ) );