1 /*****************************************************************************
2 * xmga.c : X11 MGA plugin for vlc
3 *****************************************************************************
4 * Copyright (C) 1998-2001 VideoLAN
5 * $Id: xmga.c,v 1.16 2002/06/01 12:32:00 sam Exp $
7 * Authors: Vincent Seguin <seguin@via.ecp.fr>
8 * Samuel Hocevar <sam@zoy.org>
9 * Gildas Bazin <gbazin@netcourrier.com>
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
24 *****************************************************************************/
26 /*****************************************************************************
28 *****************************************************************************/
29 #include <errno.h> /* ENOMEM */
30 #include <stdlib.h> /* free() */
31 #include <string.h> /* strerror() */
37 #ifdef HAVE_MACHINE_PARAM_H
39 #include <machine/param.h>
40 #include <sys/types.h> /* typedef ushort */
45 #include <netinet/in.h> /* BSD: struct in_addr */
48 #include <sys/shm.h> /* shmget(), shmctl() */
50 #include <X11/Xutil.h>
51 #include <X11/keysym.h>
52 #include <X11/extensions/XShm.h>
53 #include <X11/extensions/dpms.h>
55 #include "netutils.h" /* network_ChannelJoin */
59 /*****************************************************************************
61 *****************************************************************************/
62 static void vout_getfunctions( function_list_t * );
64 static int vout_Create ( vout_thread_t * );
65 static void vout_Destroy ( vout_thread_t * );
66 static void vout_Render ( vout_thread_t *, picture_t * );
67 static void vout_Display ( vout_thread_t *, picture_t * );
68 static int vout_Manage ( vout_thread_t * );
69 static int vout_Init ( vout_thread_t * );
70 static void vout_End ( vout_thread_t * );
72 static int CreateWindow ( vout_thread_t * );
73 static void DestroyWindow ( vout_thread_t * );
75 static int NewPicture ( vout_thread_t *, picture_t * );
76 static void FreePicture ( vout_thread_t *, picture_t * );
78 static void ToggleFullScreen ( vout_thread_t * );
80 static void EnableXScreenSaver ( vout_thread_t * );
81 static void DisableXScreenSaver ( vout_thread_t * );
83 static void CreateCursor ( vout_thread_t * );
84 static void DestroyCursor ( vout_thread_t * );
85 static void ToggleCursor ( vout_thread_t * );
87 /*****************************************************************************
88 * Building configuration tree
89 *****************************************************************************/
91 #define ALT_FS_TEXT N_("alternate fullscreen method")
92 #define ALT_FS_LONGTEXT N_( \
93 "There are two ways to make a fullscreen window, unfortunately each one " \
94 "has its drawbacks.\n" \
95 "1) Let the window manager handle your fullscreen window (default). But " \
96 "things like taskbars will likely show on top of the video.\n" \
97 "2) Completly bypass the window manager, but then nothing will be able " \
98 "to show on top of the video.")
100 #define DISPLAY_TEXT N_("X11 display name")
101 #define DISPLAY_LONGTEXT N_( \
102 "Specify the X11 hardware display you want to use. By default vlc will " \
103 "use the value of the DISPLAY environment variable.")
106 ADD_CATEGORY_HINT( N_("Miscellaneous"), NULL )
107 ADD_STRING ( "xmga-display", NULL, NULL, DISPLAY_TEXT, DISPLAY_LONGTEXT )
108 ADD_BOOL ( "xmga-altfullscreen", 0, NULL, ALT_FS_TEXT, ALT_FS_LONGTEXT )
112 SET_DESCRIPTION( _("X11 MGA module") )
113 ADD_CAPABILITY( VOUT, 60 )
116 MODULE_ACTIVATE_START
117 vout_getfunctions( &p_module->p_functions->vout );
120 MODULE_DEACTIVATE_START
121 MODULE_DEACTIVATE_STOP
123 /*****************************************************************************
124 * vout_sys_t: video output method descriptor
125 *****************************************************************************
126 * This structure is part of the video output thread descriptor.
127 * It describes the X11 and XVideo specific properties of an output thread.
128 *****************************************************************************/
131 /* Internal settings and properties */
132 Display * p_display; /* display pointer */
134 Visual * p_visual; /* visual pointer */
135 int i_screen; /* screen number */
136 Window window; /* root window */
137 GC gc; /* graphic context instance handler */
139 vlc_bool_t b_shm; /* shared memory extension flag */
141 #ifdef MODULE_NAME_IS_xvideo
142 Window yuv_window; /* sub-window for displaying yuv video
146 Colormap colormap; /* colormap used (8bpp only) */
149 int i_bytes_per_pixel;
150 int i_bytes_per_line;
156 /* X11 generic properties */
158 Atom wm_delete_window;
160 int i_width; /* width of main window */
161 int i_height; /* height of main window */
162 vlc_bool_t b_altfullscreen; /* which fullscreen method */
164 /* Backup of window position and size before fullscreen switch */
169 int i_width_backup_2;
170 int i_height_backup_2;
174 /* Screen saver properties */
175 int i_ss_timeout; /* timeout */
176 int i_ss_interval; /* interval between changes */
177 int i_ss_blanking; /* blanking mode */
178 int i_ss_exposure; /* exposure mode */
179 BOOL b_ss_dpms; /* DPMS mode */
181 /* Mouse pointer properties */
182 vlc_bool_t b_mouse_pointer_visible;
183 mtime_t i_time_mouse_last_moved; /* used to auto-hide pointer*/
184 Cursor blank_cursor; /* the hidden cursor */
185 mtime_t i_time_button_last_pressed; /* to track dbl-clicks */
186 Pixmap cursor_pixmap;
189 /*****************************************************************************
190 * mwmhints_t: window manager hints
191 *****************************************************************************
192 * Fullscreen needs to be able to hide the wm decorations so we provide
193 * this structure to make it easier.
194 *****************************************************************************/
195 #define MWM_HINTS_DECORATIONS (1L << 1)
196 #define PROP_MWM_HINTS_ELEMENTS 5
197 typedef struct mwmhints_s
206 /*****************************************************************************
208 *****************************************************************************/
209 #ifdef MODULE_NAME_IS_xvideo
210 # define MAX_DIRECTBUFFERS 5
212 # define MAX_DIRECTBUFFERS 2
215 /*****************************************************************************
216 * Functions exported as capabilities. They are declared as static so that
217 * we don't pollute the namespace too much.
218 *****************************************************************************/
219 static void vout_getfunctions( function_list_t * p_function_list )
221 p_function_list->functions.vout.pf_create = vout_Create;
222 p_function_list->functions.vout.pf_init = vout_Init;
223 p_function_list->functions.vout.pf_end = vout_End;
224 p_function_list->functions.vout.pf_destroy = vout_Destroy;
225 p_function_list->functions.vout.pf_manage = vout_Manage;
226 p_function_list->functions.vout.pf_render = vout_Render;
227 p_function_list->functions.vout.pf_display = vout_Display;
230 /*****************************************************************************
231 * vout_Create: allocate X11 video thread output method
232 *****************************************************************************
233 * This function allocate and initialize a X11 vout method. It uses some of the
234 * vout properties to choose the window size, and change them according to the
235 * actual properties of the display.
236 *****************************************************************************/
237 static int vout_Create( vout_thread_t *p_vout )
241 /* Allocate structure */
242 p_vout->p_sys = malloc( sizeof( vout_sys_t ) );
243 if( p_vout->p_sys == NULL )
245 msg_Err( p_vout, "out of memory" );
249 /* Open display, unsing the "display" config variable or the DISPLAY
250 * environment variable */
251 psz_display = config_GetPsz( p_vout, "xmga-display" );
252 p_vout->p_sys->p_display = XOpenDisplay( psz_display );
254 if( p_vout->p_sys->p_display == NULL ) /* error */
256 msg_Err( p_vout, "cannot open display %s",
257 XDisplayName( psz_display ) );
258 free( p_vout->p_sys );
259 if( psz_display ) free( psz_display );
262 if( psz_display ) free( psz_display );
264 p_vout->p_sys->i_screen = DefaultScreen( p_vout->p_sys->p_display );
266 /* Create blank cursor (for mouse cursor autohiding) */
267 p_vout->p_sys->b_mouse_pointer_visible = 1;
268 CreateCursor( p_vout );
270 /* Spawn base window - this window will include the video output window,
271 * but also command buttons, subtitles and other indicators */
272 if( CreateWindow( p_vout ) )
274 msg_Err( p_vout, "cannot create X11 window" );
275 DestroyCursor( p_vout );
276 XCloseDisplay( p_vout->p_sys->p_display );
277 free( p_vout->p_sys );
281 /* Disable screen saver */
282 DisableXScreenSaver( p_vout );
285 p_vout->p_sys->b_altfullscreen = 0;
290 /*****************************************************************************
291 * vout_Destroy: destroy X11 video thread output method
292 *****************************************************************************
293 * Terminate an output method created by vout_CreateOutputMethod
294 *****************************************************************************/
295 static void vout_Destroy( vout_thread_t *p_vout )
297 /* Restore cursor if it was blanked */
298 if( !p_vout->p_sys->b_mouse_pointer_visible )
300 ToggleCursor( p_vout );
303 DestroyCursor( p_vout );
304 EnableXScreenSaver( p_vout );
305 DestroyWindow( p_vout );
307 XCloseDisplay( p_vout->p_sys->p_display );
309 /* Destroy structure */
310 free( p_vout->p_sys );
313 /*****************************************************************************
314 * vout_Init: initialize X11 video thread output method
315 *****************************************************************************
316 * This function create the XImages needed by the output thread. It is called
317 * at the beginning of the thread, but also each time the window is resized.
318 *****************************************************************************/
319 static int vout_Init( vout_thread_t *p_vout )
324 I_OUTPUTPICTURES = 0;
326 #ifdef MODULE_NAME_IS_xvideo
327 /* Initialize the output structure; we already found an XVideo port,
328 * and the corresponding chroma we will be using. Since we can
329 * arbitrary scale, stick to the coordinates and aspect. */
330 p_vout->output.i_width = p_vout->render.i_width;
331 p_vout->output.i_height = p_vout->render.i_height;
332 p_vout->output.i_aspect = p_vout->render.i_aspect;
335 /* Initialize the output structure: RGB with square pixels, whatever
336 * the input format is, since it's the only format we know */
337 switch( p_vout->p_sys->i_screen_depth )
339 case 8: /* FIXME: set the palette */
340 p_vout->output.i_chroma = FOURCC_RGB2; break;
342 p_vout->output.i_chroma = FOURCC_RV15; break;
344 p_vout->output.i_chroma = FOURCC_RV16; break;
346 p_vout->output.i_chroma = FOURCC_RV24; break;
348 p_vout->output.i_chroma = FOURCC_RV32; break;
350 msg_Err( p_vout, "unknown screen depth %i",
351 p_vout->p_sys->i_screen_depth );
355 p_vout->output.i_width = p_vout->p_sys->i_width;
356 p_vout->output.i_height = p_vout->p_sys->i_height;
358 /* Assume we have square pixels */
359 p_vout->output.i_aspect = p_vout->p_sys->i_width
360 * VOUT_ASPECT_FACTOR / p_vout->p_sys->i_height;
363 /* Try to initialize up to MAX_DIRECTBUFFERS direct buffers */
364 while( I_OUTPUTPICTURES < MAX_DIRECTBUFFERS )
368 /* Find an empty picture slot */
369 for( i_index = 0 ; i_index < VOUT_MAX_PICTURES ; i_index++ )
371 if( p_vout->p_picture[ i_index ].i_status == FREE_PICTURE )
373 p_pic = p_vout->p_picture + i_index;
378 /* Allocate the picture */
379 if( p_pic == NULL || NewPicture( p_vout, p_pic ) )
384 p_pic->i_status = DESTROYED_PICTURE;
385 p_pic->i_type = DIRECT_PICTURE;
387 PP_OUTPUTPICTURE[ I_OUTPUTPICTURES ] = p_pic;
395 /*****************************************************************************
396 * vout_Render: render previously calculated output
397 *****************************************************************************/
398 static void vout_Render( vout_thread_t *p_vout, picture_t *p_pic )
403 /*****************************************************************************
404 * vout_Display: displays previously rendered output
405 *****************************************************************************
406 * This function sends the currently rendered image to X11 server.
407 * (The Xv extension takes care of "double-buffering".)
408 *****************************************************************************/
409 static void vout_Display( vout_thread_t *p_vout, picture_t *p_pic )
411 int i_width, i_height, i_x, i_y;
413 vout_PlacePicture( p_vout, p_vout->p_sys->i_width, p_vout->p_sys->i_height,
414 &i_x, &i_y, &i_width, &i_height );
417 /*****************************************************************************
418 * vout_Manage: handle X11 events
419 *****************************************************************************
420 * This function should be called regularly by video output thread. It manages
421 * X11 events and allows window resizing. It returns a non null value on
423 *****************************************************************************/
424 static int vout_Manage( vout_thread_t *p_vout )
426 XEvent xevent; /* X11 event */
427 vlc_bool_t b_resized; /* window has been resized */
428 char i_key; /* ISO Latin-1 key */
431 /* Handle X11 events: ConfigureNotify events are parsed to know if the
432 * output window's size changed, MapNotify and UnmapNotify to know if the
433 * window is mapped (and if the display is useful), and ClientMessages
434 * to intercept window destruction requests */
437 while( XCheckWindowEvent( p_vout->p_sys->p_display, p_vout->p_sys->window,
438 StructureNotifyMask | KeyPressMask |
439 ButtonPressMask | ButtonReleaseMask |
440 PointerMotionMask | Button1MotionMask , &xevent )
443 /* ConfigureNotify event: prepare */
444 if( (xevent.type == ConfigureNotify)
445 && ((xevent.xconfigure.width != p_vout->p_sys->i_width)
446 || (xevent.xconfigure.height != p_vout->p_sys->i_height)) )
448 /* Update dimensions */
450 p_vout->i_changes |= VOUT_SIZE_CHANGE;
451 p_vout->p_sys->i_width = xevent.xconfigure.width;
452 p_vout->p_sys->i_height = xevent.xconfigure.height;
455 else if( xevent.type == KeyPress )
457 /* We may have keys like F1 trough F12, ESC ... */
458 x_key_symbol = XKeycodeToKeysym( p_vout->p_sys->p_display,
459 xevent.xkey.keycode, 0 );
460 switch( x_key_symbol )
463 p_vout->p_vlc->b_die = 1;
466 p_vout->p_vlc->p_intf->b_menu_change = 1;
469 input_Seek( p_vout, -5, INPUT_SEEK_SECONDS | INPUT_SEEK_CUR );
472 input_Seek( p_vout, 5, INPUT_SEEK_SECONDS | INPUT_SEEK_CUR );
475 input_Seek( p_vout, 60, INPUT_SEEK_SECONDS | INPUT_SEEK_CUR );
478 input_Seek( p_vout, -60, INPUT_SEEK_SECONDS | INPUT_SEEK_CUR );
481 input_Seek( p_vout, 0, INPUT_SEEK_BYTES | INPUT_SEEK_SET );
484 input_Seek( p_vout, 0, INPUT_SEEK_BYTES | INPUT_SEEK_END );
487 input_Seek( p_vout, 900, INPUT_SEEK_SECONDS | INPUT_SEEK_CUR );
490 input_Seek( p_vout, -900, INPUT_SEEK_SECONDS | INPUT_SEEK_CUR );
493 input_SetStatus( p_input_bank->pp_input[0],
494 INPUT_STATUS_PAUSE );
499 * The reason why I use this instead of XK_0 is that
500 * with XLookupString, we don't have to care about
503 if( XLookupString( &xevent.xkey, &i_key, 1, NULL, NULL ) )
505 /* FIXME: handle stuff here */
510 p_vout->p_vlc->b_die = 1;
514 p_vout->i_changes |= VOUT_FULLSCREEN_CHANGE;
517 case '0': network_ChannelJoin( 0 ); break;
518 case '1': network_ChannelJoin( 1 ); break;
519 case '2': network_ChannelJoin( 2 ); break;
520 case '3': network_ChannelJoin( 3 ); break;
521 case '4': network_ChannelJoin( 4 ); break;
522 case '5': network_ChannelJoin( 5 ); break;
523 case '6': network_ChannelJoin( 6 ); break;
524 case '7': network_ChannelJoin( 7 ); break;
525 case '8': network_ChannelJoin( 8 ); break;
526 case '9': network_ChannelJoin( 9 ); break;
536 else if( xevent.type == ButtonPress )
538 switch( ((XButtonEvent *)&xevent)->button )
541 /* In this part we will eventually manage
542 * clicks for DVD navigation for instance. */
544 /* detect double-clicks */
545 if( ( ((XButtonEvent *)&xevent)->time -
546 p_vout->p_sys->i_time_button_last_pressed ) < 300 )
548 p_vout->i_changes |= VOUT_FULLSCREEN_CHANGE;
551 p_vout->p_sys->i_time_button_last_pressed =
552 ((XButtonEvent *)&xevent)->time;
556 input_Seek( p_vout, 15, INPUT_SEEK_SECONDS | INPUT_SEEK_CUR );
560 input_Seek( p_vout, -15, INPUT_SEEK_SECONDS | INPUT_SEEK_CUR );
565 else if( xevent.type == ButtonRelease )
567 switch( ((XButtonEvent *)&xevent)->button )
570 /* FIXME: need locking ! */
571 p_vout->p_vlc->p_intf->b_menu_change = 1;
576 else if( xevent.type == MotionNotify )
578 p_vout->p_sys->i_time_mouse_last_moved = mdate();
579 if( ! p_vout->p_sys->b_mouse_pointer_visible )
581 ToggleCursor( p_vout );
587 msg_Warn( p_vout, "unhandled event %d received", xevent.type );
591 /* ClientMessage event - only WM_PROTOCOLS with WM_DELETE_WINDOW data
592 * are handled - according to the man pages, the format is always 32
594 while( XCheckTypedEvent( p_vout->p_sys->p_display,
595 ClientMessage, &xevent ) )
597 if( (xevent.xclient.message_type == p_vout->p_sys->wm_protocols)
598 && (xevent.xclient.data.l[0] == p_vout->p_sys->wm_delete_window ) )
600 p_vout->p_vlc->b_die = 1;
607 if ( p_vout->i_changes & VOUT_FULLSCREEN_CHANGE )
609 ToggleFullScreen( p_vout );
610 p_vout->i_changes &= ~VOUT_FULLSCREEN_CHANGE;
617 if( p_vout->i_changes & VOUT_SIZE_CHANGE )
619 int i_width, i_height, i_x, i_y;
621 p_vout->i_changes &= ~VOUT_SIZE_CHANGE;
623 msg_Dbg( p_vout, "video display resized (%dx%d)",
624 p_vout->p_sys->i_width, p_vout->p_sys->i_height );
626 vout_PlacePicture( p_vout, p_vout->p_sys->i_width,
627 p_vout->p_sys->i_height,
628 &i_x, &i_y, &i_width, &i_height );
631 /* Autohide Cursour */
632 if( mdate() - p_vout->p_sys->i_time_mouse_last_moved > 2000000 )
634 /* Hide the mouse automatically */
635 if( p_vout->p_sys->b_mouse_pointer_visible )
637 ToggleCursor( p_vout );
644 /*****************************************************************************
645 * vout_End: terminate X11 video thread output method
646 *****************************************************************************
647 * Destroy the X11 XImages created by vout_Init. It is called at the end of
648 * the thread, but also each time the window is resized.
649 *****************************************************************************/
650 static void vout_End( vout_thread_t *p_vout )
654 /* Free the direct buffers we allocated */
655 for( i_index = I_OUTPUTPICTURES ; i_index ; )
658 FreePicture( p_vout, PP_OUTPUTPICTURE[ i_index ] );
662 /* following functions are local */
664 /*****************************************************************************
665 * CreateWindow: open and set-up X11 main window
666 *****************************************************************************/
667 static int CreateWindow( vout_thread_t *p_vout )
669 XSizeHints xsize_hints;
670 XSetWindowAttributes xwindow_attributes;
675 vlc_bool_t b_configure_notify;
676 vlc_bool_t b_map_notify;
678 /* Set main window's size */
679 p_vout->p_sys->i_width = p_vout->i_window_width;
680 p_vout->p_sys->i_height = p_vout->i_window_height;
682 /* Prepare window manager hints and properties */
683 xsize_hints.base_width = p_vout->p_sys->i_width;
684 xsize_hints.base_height = p_vout->p_sys->i_height;
685 xsize_hints.flags = PSize;
686 p_vout->p_sys->wm_protocols = XInternAtom( p_vout->p_sys->p_display,
687 "WM_PROTOCOLS", True );
688 p_vout->p_sys->wm_delete_window = XInternAtom( p_vout->p_sys->p_display,
689 "WM_DELETE_WINDOW", True );
691 /* Prepare window attributes */
692 xwindow_attributes.backing_store = Always; /* save the hidden part */
693 xwindow_attributes.background_pixel = BlackPixel(p_vout->p_sys->p_display,
694 p_vout->p_sys->i_screen);
695 xwindow_attributes.event_mask = ExposureMask | StructureNotifyMask;
698 /* Create the window and set hints - the window must receive
699 * ConfigureNotify events, and until it is displayed, Expose and
700 * MapNotify events. */
702 p_vout->p_sys->window =
703 XCreateWindow( p_vout->p_sys->p_display,
704 DefaultRootWindow( p_vout->p_sys->p_display ),
706 p_vout->p_sys->i_width,
707 p_vout->p_sys->i_height,
710 CWBackingStore | CWBackPixel | CWEventMask,
711 &xwindow_attributes );
713 /* Set window manager hints and properties: size hints, command,
714 * window's name, and accepted protocols */
715 XSetWMNormalHints( p_vout->p_sys->p_display, p_vout->p_sys->window,
717 XSetCommand( p_vout->p_sys->p_display, p_vout->p_sys->window,
718 p_vout->p_vlc->ppsz_argv, p_vout->p_vlc->i_argc );
719 XStoreName( p_vout->p_sys->p_display, p_vout->p_sys->window,
720 VOUT_TITLE " (XMGA output)"
723 if( (p_vout->p_sys->wm_protocols == None) /* use WM_DELETE_WINDOW */
724 || (p_vout->p_sys->wm_delete_window == None)
725 || !XSetWMProtocols( p_vout->p_sys->p_display, p_vout->p_sys->window,
726 &p_vout->p_sys->wm_delete_window, 1 ) )
728 /* WM_DELETE_WINDOW is not supported by window manager */
729 msg_Err( p_vout, "missing or bad window manager" );
732 /* Creation of a graphic context that doesn't generate a GraphicsExpose
733 * event when using functions like XCopyArea */
734 xgcvalues.graphics_exposures = False;
735 p_vout->p_sys->gc = XCreateGC( p_vout->p_sys->p_display,
736 p_vout->p_sys->window,
737 GCGraphicsExposures, &xgcvalues);
739 /* Send orders to server, and wait until window is displayed - three
740 * events must be received: a MapNotify event, an Expose event allowing
741 * drawing in the window, and a ConfigureNotify to get the window
742 * dimensions. Once those events have been received, only ConfigureNotify
743 * events need to be received. */
745 b_configure_notify = 0;
747 XMapWindow( p_vout->p_sys->p_display, p_vout->p_sys->window);
750 XNextEvent( p_vout->p_sys->p_display, &xevent);
751 if( (xevent.type == Expose)
752 && (xevent.xexpose.window == p_vout->p_sys->window) )
756 else if( (xevent.type == MapNotify)
757 && (xevent.xmap.window == p_vout->p_sys->window) )
761 else if( (xevent.type == ConfigureNotify)
762 && (xevent.xconfigure.window == p_vout->p_sys->window) )
764 b_configure_notify = 1;
765 p_vout->p_sys->i_width = xevent.xconfigure.width;
766 p_vout->p_sys->i_height = xevent.xconfigure.height;
768 } while( !( b_expose && b_configure_notify && b_map_notify ) );
770 XSelectInput( p_vout->p_sys->p_display, p_vout->p_sys->window,
771 StructureNotifyMask | KeyPressMask |
772 ButtonPressMask | ButtonReleaseMask |
775 /* If the cursor was formerly blank than blank it again */
776 if( !p_vout->p_sys->b_mouse_pointer_visible )
778 ToggleCursor( p_vout );
779 ToggleCursor( p_vout );
782 XSync( p_vout->p_sys->p_display, False );
784 /* At this stage, the window is open, displayed, and ready to
790 /*****************************************************************************
791 * DestroyWindow: destroy the window
792 *****************************************************************************
794 *****************************************************************************/
795 static void DestroyWindow( vout_thread_t *p_vout )
797 XSync( p_vout->p_sys->p_display, False );
799 XUnmapWindow( p_vout->p_sys->p_display, p_vout->p_sys->window );
800 XFreeGC( p_vout->p_sys->p_display, p_vout->p_sys->gc );
801 XDestroyWindow( p_vout->p_sys->p_display, p_vout->p_sys->window );
804 /*****************************************************************************
805 * NewPicture: allocate a picture
806 *****************************************************************************
807 * Returns 0 on success, -1 otherwise
808 *****************************************************************************/
809 static int NewPicture( vout_thread_t *p_vout, picture_t *p_pic )
811 /* We know the chroma, allocate a buffer which will be used
812 * directly by the decoder */
813 switch( p_vout->output.i_chroma )
818 /* Unknown chroma, tell the guy to get lost */
819 msg_Err( p_vout, "never heard of chroma 0x%.8x (%4.4s)",
820 p_vout->output.i_chroma, (char*)&p_vout->output.i_chroma );
828 /*****************************************************************************
829 * FreePicture: destroy a picture allocated with NewPicture
830 *****************************************************************************
831 * Destroy XImage AND associated data. If using Shm, detach shared memory
832 * segment from server and process, then free it. The XDestroyImage manpage
833 * says that both the image structure _and_ the data pointed to by the
834 * image structure are freed, so no need to free p_image->data.
835 *****************************************************************************/
836 static void FreePicture( vout_thread_t *p_vout, picture_t *p_pic )
838 XSync( p_vout->p_sys->p_display, False );
841 /*****************************************************************************
842 * ToggleFullScreen: Enable or disable full screen mode
843 *****************************************************************************
844 * This function will switch between fullscreen and window mode.
846 *****************************************************************************/
847 static void ToggleFullScreen ( vout_thread_t *p_vout )
851 int i_xpos, i_ypos, i_width, i_height;
853 XSetWindowAttributes attributes;
855 p_vout->b_fullscreen = !p_vout->b_fullscreen;
857 if( p_vout->b_fullscreen )
859 Window next_parent, parent, *p_dummy, dummy1;
860 unsigned int dummy2, dummy3;
862 msg_Dbg( p_vout, "entering fullscreen mode" );
864 /* Only check the fullscreen method when we actually go fullscreen,
865 * because to go back to window mode we need to know in which
866 * fullscreen mode we where */
867 p_vout->p_sys->b_altfullscreen = config_GetInt( p_vout,
868 "xmga-altfullscreen" );
870 /* Save current window coordinates so they can be restored when
871 * we exit from fullscreen mode. This is the tricky part because
872 * this heavily depends on the behaviour of the window manager.
873 * When you use XMoveWindow some window managers will adjust the top
874 * of the window to the coordinates you gave, but others will instead
875 * adjust the top of the client area to the coordinates
876 * (don't forget windows have decorations). */
878 /* First, get the position and size of the client area */
879 XGetGeometry( p_vout->p_sys->p_display,
880 p_vout->p_sys->window,
884 &p_vout->p_sys->i_width_backup_2,
885 &p_vout->p_sys->i_height_backup_2,
887 XTranslateCoordinates( p_vout->p_sys->p_display,
888 p_vout->p_sys->window,
889 DefaultRootWindow( p_vout->p_sys->p_display ),
892 &p_vout->p_sys->i_xpos_backup_2,
893 &p_vout->p_sys->i_ypos_backup_2,
896 /* Then try to get the position and size of the whole window */
898 /* find the real parent of our window (created by the window manager),
899 * the one which is a direct child of the root window */
900 next_parent = parent = p_vout->p_sys->window;
901 while( next_parent != DefaultRootWindow( p_vout->p_sys->p_display ) )
903 parent = next_parent;
904 XQueryTree( p_vout->p_sys->p_display,
910 XFree((void *)p_dummy);
913 XGetGeometry( p_vout->p_sys->p_display,
914 p_vout->p_sys->window,
918 &p_vout->p_sys->i_width_backup,
919 &p_vout->p_sys->i_height_backup,
922 XTranslateCoordinates( p_vout->p_sys->p_display,
924 DefaultRootWindow( p_vout->p_sys->p_display ),
927 &p_vout->p_sys->i_xpos_backup,
928 &p_vout->p_sys->i_ypos_backup,
931 /* fullscreen window size and position */
934 i_width = DisplayWidth( p_vout->p_sys->p_display,
935 p_vout->p_sys->i_screen );
936 i_height = DisplayHeight( p_vout->p_sys->p_display,
937 p_vout->p_sys->i_screen );
942 msg_Dbg( p_vout, "leaving fullscreen mode" );
944 i_xpos = p_vout->p_sys->i_xpos_backup;
945 i_ypos = p_vout->p_sys->i_ypos_backup;
946 i_width = p_vout->p_sys->i_width_backup;
947 i_height = p_vout->p_sys->i_height_backup;
950 /* To my knowledge there are two ways to create a borderless window.
951 * There's the generic way which is to tell x to bypass the window manager,
952 * but this creates problems with the focus of other applications.
953 * The other way is to use the motif property "_MOTIF_WM_HINTS" which
954 * luckily seems to be supported by most window managers.
956 if( !p_vout->p_sys->b_altfullscreen )
958 mwmhints.flags = MWM_HINTS_DECORATIONS;
959 mwmhints.decorations = !p_vout->b_fullscreen;
961 prop = XInternAtom( p_vout->p_sys->p_display, "_MOTIF_WM_HINTS",
963 XChangeProperty( p_vout->p_sys->p_display, p_vout->p_sys->window,
964 prop, prop, 32, PropModeReplace,
965 (unsigned char *)&mwmhints,
966 PROP_MWM_HINTS_ELEMENTS );
970 /* brute force way to remove decorations */
971 attributes.override_redirect = p_vout->b_fullscreen;
972 XChangeWindowAttributes( p_vout->p_sys->p_display,
973 p_vout->p_sys->window,
978 /* We need to unmap and remap the window if we want the window
979 * manager to take our changes into effect */
980 XUnmapWindow( p_vout->p_sys->p_display, p_vout->p_sys->window);
982 XWindowEvent( p_vout->p_sys->p_display, p_vout->p_sys->window,
983 StructureNotifyMask, &xevent );
984 while( xevent.type != UnmapNotify )
985 XWindowEvent( p_vout->p_sys->p_display, p_vout->p_sys->window,
986 StructureNotifyMask, &xevent );
988 XMapRaised( p_vout->p_sys->p_display, p_vout->p_sys->window);
990 while( xevent.type != MapNotify )
991 XWindowEvent( p_vout->p_sys->p_display, p_vout->p_sys->window,
992 StructureNotifyMask, &xevent );
994 XMoveResizeWindow( p_vout->p_sys->p_display,
995 p_vout->p_sys->window,
1001 /* Purge all ConfigureNotify events, this is needed to fix a bug where we
1002 * would lose the original size of the window */
1003 while( xevent.type != ConfigureNotify )
1004 XWindowEvent( p_vout->p_sys->p_display, p_vout->p_sys->window,
1005 StructureNotifyMask, &xevent );
1006 while( XCheckWindowEvent( p_vout->p_sys->p_display, p_vout->p_sys->window,
1007 StructureNotifyMask, &xevent ) );
1010 /* We need to check that the window was really restored where we wanted */
1011 if( !p_vout->b_fullscreen )
1014 unsigned int dummy2, dummy3, dummy4, dummy5;
1016 /* Check the position */
1017 XTranslateCoordinates( p_vout->p_sys->p_display,
1018 p_vout->p_sys->window,
1019 DefaultRootWindow( p_vout->p_sys->p_display ),
1025 if( dummy2 != p_vout->p_sys->i_xpos_backup_2 ||
1026 dummy3 != p_vout->p_sys->i_ypos_backup_2 )
1028 /* Ok it didn't work... second try */
1030 XMoveWindow( p_vout->p_sys->p_display,
1031 p_vout->p_sys->window,
1032 p_vout->p_sys->i_xpos_backup_2,
1033 p_vout->p_sys->i_ypos_backup_2 );
1035 /* Purge all ConfigureNotify events, this is needed to fix a bug
1036 * where we would lose the original size of the window */
1037 XWindowEvent( p_vout->p_sys->p_display, p_vout->p_sys->window,
1038 StructureNotifyMask, &xevent );
1039 while( xevent.type != ConfigureNotify )
1040 XWindowEvent( p_vout->p_sys->p_display, p_vout->p_sys->window,
1041 StructureNotifyMask, &xevent );
1042 while( XCheckWindowEvent( p_vout->p_sys->p_display,
1043 p_vout->p_sys->window,
1044 StructureNotifyMask, &xevent ) );
1047 /* Check the size */
1048 XGetGeometry( p_vout->p_sys->p_display,
1049 p_vout->p_sys->window,
1057 if( dummy4 != p_vout->p_sys->i_width_backup_2 ||
1058 dummy5 != p_vout->p_sys->i_height_backup_2 )
1060 /* Ok it didn't work... third try */
1062 XResizeWindow( p_vout->p_sys->p_display,
1063 p_vout->p_sys->window,
1064 p_vout->p_sys->i_width_backup_2,
1065 p_vout->p_sys->i_height_backup_2 );
1067 /* Purge all ConfigureNotify events, this is needed to fix a bug
1068 * where we would lose the original size of the window */
1069 XWindowEvent( p_vout->p_sys->p_display, p_vout->p_sys->window,
1070 StructureNotifyMask, &xevent );
1071 while( xevent.type != ConfigureNotify )
1072 XWindowEvent( p_vout->p_sys->p_display, p_vout->p_sys->window,
1073 StructureNotifyMask, &xevent );
1074 while( XCheckWindowEvent( p_vout->p_sys->p_display,
1075 p_vout->p_sys->window,
1076 StructureNotifyMask, &xevent ) );
1080 if( p_vout->p_sys->b_altfullscreen )
1081 XSetInputFocus(p_vout->p_sys->p_display,
1082 p_vout->p_sys->window,
1086 /* signal that the size needs to be updated */
1087 p_vout->p_sys->i_width = i_width;
1088 p_vout->p_sys->i_height = i_height;
1089 p_vout->i_changes |= VOUT_SIZE_CHANGE;
1093 /*****************************************************************************
1094 * EnableXScreenSaver: enable screen saver
1095 *****************************************************************************
1096 * This function enables the screen saver on a display after it has been
1097 * disabled by XDisableScreenSaver.
1098 * FIXME: what happens if multiple vlc sessions are running at the same
1100 *****************************************************************************/
1101 static void EnableXScreenSaver( vout_thread_t *p_vout )
1105 XSetScreenSaver( p_vout->p_sys->p_display, p_vout->p_sys->i_ss_timeout,
1106 p_vout->p_sys->i_ss_interval,
1107 p_vout->p_sys->i_ss_blanking,
1108 p_vout->p_sys->i_ss_exposure );
1110 /* Restore DPMS settings */
1111 if( DPMSQueryExtension( p_vout->p_sys->p_display, &dummy, &dummy ) )
1113 if( p_vout->p_sys->b_ss_dpms )
1115 DPMSEnable( p_vout->p_sys->p_display );
1120 /*****************************************************************************
1121 * DisableXScreenSaver: disable screen saver
1122 *****************************************************************************
1123 * See XEnableXScreenSaver
1124 *****************************************************************************/
1125 static void DisableXScreenSaver( vout_thread_t *p_vout )
1129 /* Save screen saver informations */
1130 XGetScreenSaver( p_vout->p_sys->p_display, &p_vout->p_sys->i_ss_timeout,
1131 &p_vout->p_sys->i_ss_interval,
1132 &p_vout->p_sys->i_ss_blanking,
1133 &p_vout->p_sys->i_ss_exposure );
1135 /* Disable screen saver */
1136 XSetScreenSaver( p_vout->p_sys->p_display, 0,
1137 p_vout->p_sys->i_ss_interval,
1138 p_vout->p_sys->i_ss_blanking,
1139 p_vout->p_sys->i_ss_exposure );
1142 if( DPMSQueryExtension( p_vout->p_sys->p_display, &dummy, &dummy ) )
1145 /* Save DPMS current state */
1146 DPMSInfo( p_vout->p_sys->p_display, &dummy,
1147 &p_vout->p_sys->b_ss_dpms );
1148 DPMSDisable( p_vout->p_sys->p_display );
1152 /*****************************************************************************
1153 * CreateCursor: create a blank mouse pointer
1154 *****************************************************************************/
1155 static void CreateCursor( vout_thread_t *p_vout )
1157 XColor cursor_color;
1159 p_vout->p_sys->cursor_pixmap =
1160 XCreatePixmap( p_vout->p_sys->p_display,
1161 DefaultRootWindow( p_vout->p_sys->p_display ),
1164 XParseColor( p_vout->p_sys->p_display,
1165 XCreateColormap( p_vout->p_sys->p_display,
1167 p_vout->p_sys->p_display ),
1169 p_vout->p_sys->p_display,
1170 p_vout->p_sys->i_screen ),
1172 "black", &cursor_color );
1174 p_vout->p_sys->blank_cursor =
1175 XCreatePixmapCursor( p_vout->p_sys->p_display,
1176 p_vout->p_sys->cursor_pixmap,
1177 p_vout->p_sys->cursor_pixmap,
1178 &cursor_color, &cursor_color, 1, 1 );
1181 /*****************************************************************************
1182 * DestroyCursor: destroy the blank mouse pointer
1183 *****************************************************************************/
1184 static void DestroyCursor( vout_thread_t *p_vout )
1186 XFreePixmap( p_vout->p_sys->p_display, p_vout->p_sys->cursor_pixmap );
1189 /*****************************************************************************
1190 * ToggleCursor: hide or show the mouse pointer
1191 *****************************************************************************
1192 * This function hides the X pointer if it is visible by setting the pointer
1193 * sprite to a blank one. To show it again, we disable the sprite.
1194 *****************************************************************************/
1195 static void ToggleCursor( vout_thread_t *p_vout )
1197 if( p_vout->p_sys->b_mouse_pointer_visible )
1199 XDefineCursor( p_vout->p_sys->p_display,
1200 p_vout->p_sys->window,
1201 p_vout->p_sys->blank_cursor );
1202 p_vout->p_sys->b_mouse_pointer_visible = 0;
1206 XUndefineCursor( p_vout->p_sys->p_display, p_vout->p_sys->window );
1207 p_vout->p_sys->b_mouse_pointer_visible = 1;