1 /*****************************************************************************
2 * xmga.c : X11 MGA plugin for vlc
3 *****************************************************************************
4 * Copyright (C) 1998-2001 VideoLAN
5 * $Id: xmga.c,v 1.6 2003/05/15 22:27:38 massiot 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>
57 /*****************************************************************************
59 *****************************************************************************/
60 static int Create ( vlc_object_t * );
61 static void Destroy ( vlc_object_t * );
63 static int Init ( vout_thread_t * );
64 static void End ( vout_thread_t * );
65 static int Manage ( vout_thread_t * );
66 static void MGADisplay( vout_thread_t *, picture_t * );
68 static int CreateWindow ( vout_thread_t * );
69 static void DestroyWindow ( vout_thread_t * );
71 static int NewPicture ( vout_thread_t *, picture_t * );
72 static void FreePicture ( vout_thread_t *, picture_t * );
74 static void ToggleFullScreen ( vout_thread_t * );
76 static void EnableXScreenSaver ( vout_thread_t * );
77 static void DisableXScreenSaver ( vout_thread_t * );
79 static void CreateCursor ( vout_thread_t * );
80 static void DestroyCursor ( vout_thread_t * );
81 static void ToggleCursor ( vout_thread_t * );
83 /*****************************************************************************
85 *****************************************************************************/
87 #define ALT_FS_TEXT N_("Alternate fullscreen method")
88 #define ALT_FS_LONGTEXT N_( \
89 "There are two ways to make a fullscreen window, unfortunately each one " \
90 "has its drawbacks.\n" \
91 "1) Let the window manager handle your fullscreen window (default). But " \
92 "things like taskbars will likely show on top of the video.\n" \
93 "2) Completly bypass the window manager, but then nothing will be able " \
94 "to show on top of the video.")
96 #define DISPLAY_TEXT N_("X11 display name")
97 #define DISPLAY_LONGTEXT N_( \
98 "Specify the X11 hardware display you want to use. By default VLC will " \
99 "use the value of the DISPLAY environment variable.")
102 add_category_hint( N_("Miscellaneous"), NULL, VLC_TRUE );
103 add_string( "xmga-display", NULL, NULL, DISPLAY_TEXT, DISPLAY_LONGTEXT, VLC_TRUE );
104 add_bool( "xmga-altfullscreen", 0, NULL, ALT_FS_TEXT, ALT_FS_LONGTEXT, VLC_TRUE );
105 set_description( _("X11 MGA video output") );
106 set_capability( "video output", 60 );
107 set_callbacks( Create, Destroy );
110 /*****************************************************************************
111 * vout_sys_t: video output method descriptor
112 *****************************************************************************
113 * This structure is part of the video output thread descriptor.
114 * It describes the X11 and XVideo specific properties of an output thread.
115 *****************************************************************************/
118 /* Internal settings and properties */
119 Display * p_display; /* display pointer */
121 Visual * p_visual; /* visual pointer */
122 int i_screen; /* screen number */
123 Window window; /* root window */
124 GC gc; /* graphic context instance handler */
126 vlc_bool_t b_shm; /* shared memory extension flag */
128 #ifdef MODULE_NAME_IS_xvideo
129 Window yuv_window; /* sub-window for displaying yuv video
133 Colormap colormap; /* colormap used (8bpp only) */
136 int i_bytes_per_pixel;
137 int i_bytes_per_line;
143 /* X11 generic properties */
145 Atom wm_delete_window;
147 int i_width; /* width of main window */
148 int i_height; /* height of main window */
149 vlc_bool_t b_altfullscreen; /* which fullscreen method */
151 /* Backup of window position and size before fullscreen switch */
156 int i_width_backup_2;
157 int i_height_backup_2;
161 /* Screen saver properties */
162 int i_ss_timeout; /* timeout */
163 int i_ss_interval; /* interval between changes */
164 int i_ss_blanking; /* blanking mode */
165 int i_ss_exposure; /* exposure mode */
166 BOOL b_ss_dpms; /* DPMS mode */
168 /* Mouse pointer properties */
169 vlc_bool_t b_mouse_pointer_visible;
170 mtime_t i_time_mouse_last_moved; /* used to auto-hide pointer*/
171 Cursor blank_cursor; /* the hidden cursor */
172 mtime_t i_time_button_last_pressed; /* to track dbl-clicks */
173 Pixmap cursor_pixmap;
176 /*****************************************************************************
177 * mwmhints_t: window manager hints
178 *****************************************************************************
179 * Fullscreen needs to be able to hide the wm decorations so we provide
180 * this structure to make it easier.
181 *****************************************************************************/
182 #define MWM_HINTS_DECORATIONS (1L << 1)
183 #define PROP_MWM_HINTS_ELEMENTS 5
184 typedef struct mwmhints_t
193 /*****************************************************************************
195 *****************************************************************************/
196 #ifdef MODULE_NAME_IS_xvideo
197 # define MAX_DIRECTBUFFERS 5
199 # define MAX_DIRECTBUFFERS 2
202 /*****************************************************************************
203 * Create: allocate X11 video thread output method
204 *****************************************************************************
205 * This function allocate and initialize a X11 vout method. It uses some of the
206 * vout properties to choose the window size, and change them according to the
207 * actual properties of the display.
208 *****************************************************************************/
209 static int Create( vlc_object_t *p_this )
211 vout_thread_t *p_vout = (vout_thread_t *)p_this;
214 /* Allocate structure */
215 p_vout->p_sys = malloc( sizeof( vout_sys_t ) );
216 if( p_vout->p_sys == NULL )
218 msg_Err( p_vout, "out of memory" );
222 /* Open display, unsing the "display" config variable or the DISPLAY
223 * environment variable */
224 psz_display = config_GetPsz( p_vout, "xmga-display" );
225 p_vout->p_sys->p_display = XOpenDisplay( psz_display );
227 if( p_vout->p_sys->p_display == NULL ) /* error */
229 msg_Err( p_vout, "cannot open display %s",
230 XDisplayName( psz_display ) );
231 free( p_vout->p_sys );
232 if( psz_display ) free( psz_display );
235 if( psz_display ) free( psz_display );
237 p_vout->p_sys->i_screen = DefaultScreen( p_vout->p_sys->p_display );
239 /* Create blank cursor (for mouse cursor autohiding) */
240 p_vout->p_sys->b_mouse_pointer_visible = 1;
241 CreateCursor( p_vout );
243 /* Spawn base window - this window will include the video output window,
244 * but also command buttons, subtitles and other indicators */
245 if( CreateWindow( p_vout ) )
247 msg_Err( p_vout, "cannot create X11 window" );
248 DestroyCursor( p_vout );
249 XCloseDisplay( p_vout->p_sys->p_display );
250 free( p_vout->p_sys );
254 /* Disable screen saver */
255 DisableXScreenSaver( p_vout );
258 p_vout->p_sys->b_altfullscreen = 0;
260 p_vout->pf_init = Init;
261 p_vout->pf_end = End;
262 p_vout->pf_manage = Manage;
263 p_vout->pf_render = NULL;
264 p_vout->pf_display = MGADisplay;
269 /*****************************************************************************
270 * Destroy: destroy X11 video thread output method
271 *****************************************************************************
272 * Terminate an output method created by Create
273 *****************************************************************************/
274 static void Destroy( vlc_object_t *p_this )
276 vout_thread_t *p_vout = (vout_thread_t *)p_this;
278 /* Restore cursor if it was blanked */
279 if( !p_vout->p_sys->b_mouse_pointer_visible )
281 ToggleCursor( p_vout );
284 DestroyCursor( p_vout );
285 EnableXScreenSaver( p_vout );
286 DestroyWindow( p_vout );
288 XCloseDisplay( p_vout->p_sys->p_display );
290 /* Destroy structure */
291 free( p_vout->p_sys );
294 /*****************************************************************************
295 * Init: initialize X11 video thread output method
296 *****************************************************************************
297 * This function create the XImages needed by the output thread. It is called
298 * at the beginning of the thread, but also each time the window is resized.
299 *****************************************************************************/
300 static int Init( vout_thread_t *p_vout )
305 I_OUTPUTPICTURES = 0;
307 #ifdef MODULE_NAME_IS_xvideo
308 /* Initialize the output structure; we already found an XVideo port,
309 * and the corresponding chroma we will be using. Since we can
310 * arbitrary scale, stick to the coordinates and aspect. */
311 p_vout->output.i_width = p_vout->render.i_width;
312 p_vout->output.i_height = p_vout->render.i_height;
313 p_vout->output.i_aspect = p_vout->render.i_aspect;
316 /* Initialize the output structure: RGB with square pixels, whatever
317 * the input format is, since it's the only format we know */
318 switch( p_vout->p_sys->i_screen_depth )
320 case 8: /* FIXME: set the palette */
321 p_vout->output.i_chroma = VLC_FOURCC('R','G','B','2'); break;
323 p_vout->output.i_chroma = VLC_FOURCC('R','V','1','5'); break;
325 p_vout->output.i_chroma = VLC_FOURCC('R','V','1','6'); break;
327 p_vout->output.i_chroma = VLC_FOURCC('R','V','2','4'); break;
329 p_vout->output.i_chroma = VLC_FOURCC('R','V','3','2'); break;
331 msg_Err( p_vout, "unknown screen depth %i",
332 p_vout->p_sys->i_screen_depth );
336 p_vout->output.i_width = p_vout->p_sys->i_width;
337 p_vout->output.i_height = p_vout->p_sys->i_height;
339 /* Assume we have square pixels */
340 p_vout->output.i_aspect = p_vout->p_sys->i_width
341 * VOUT_ASPECT_FACTOR / p_vout->p_sys->i_height;
344 /* Try to initialize up to MAX_DIRECTBUFFERS direct buffers */
345 while( I_OUTPUTPICTURES < MAX_DIRECTBUFFERS )
349 /* Find an empty picture slot */
350 for( i_index = 0 ; i_index < VOUT_MAX_PICTURES ; i_index++ )
352 if( p_vout->p_picture[ i_index ].i_status == FREE_PICTURE )
354 p_pic = p_vout->p_picture + i_index;
359 /* Allocate the picture */
360 if( p_pic == NULL || NewPicture( p_vout, p_pic ) )
365 p_pic->i_status = DESTROYED_PICTURE;
366 p_pic->i_type = DIRECT_PICTURE;
368 PP_OUTPUTPICTURE[ I_OUTPUTPICTURES ] = p_pic;
376 /*****************************************************************************
377 * MGADisplay: displays previously rendered output
378 *****************************************************************************
379 * This function sends the currently rendered image to X11 server.
380 * (The Xv extension takes care of "double-buffering".)
381 *****************************************************************************/
382 static void MGADisplay( vout_thread_t *p_vout, picture_t *p_pic )
384 int i_width, i_height, i_x, i_y;
386 vout_PlacePicture( p_vout, p_vout->p_sys->i_width, p_vout->p_sys->i_height,
387 &i_x, &i_y, &i_width, &i_height );
390 /*****************************************************************************
391 * Manage: handle X11 events
392 *****************************************************************************
393 * This function should be called regularly by video output thread. It manages
394 * X11 events and allows window resizing. It returns a non null value on
396 *****************************************************************************/
397 static int Manage( vout_thread_t *p_vout )
399 XEvent xevent; /* X11 event */
400 vlc_bool_t b_resized; /* window has been resized */
401 char i_key; /* ISO Latin-1 key */
404 /* Handle X11 events: ConfigureNotify events are parsed to know if the
405 * output window's size changed, MapNotify and UnmapNotify to know if the
406 * window is mapped (and if the display is useful), and ClientMessages
407 * to intercept window destruction requests */
410 while( XCheckWindowEvent( p_vout->p_sys->p_display, p_vout->p_sys->window,
411 StructureNotifyMask | KeyPressMask |
412 ButtonPressMask | ButtonReleaseMask |
413 PointerMotionMask | Button1MotionMask , &xevent )
416 /* ConfigureNotify event: prepare */
417 if( (xevent.type == ConfigureNotify)
418 && ((xevent.xconfigure.width != p_vout->p_sys->i_width)
419 || (xevent.xconfigure.height != p_vout->p_sys->i_height)) )
421 /* Update dimensions */
423 p_vout->i_changes |= VOUT_SIZE_CHANGE;
424 p_vout->p_sys->i_width = xevent.xconfigure.width;
425 p_vout->p_sys->i_height = xevent.xconfigure.height;
428 else if( xevent.type == KeyPress )
430 /* We may have keys like F1 trough F12, ESC ... */
431 x_key_symbol = XKeycodeToKeysym( p_vout->p_sys->p_display,
432 xevent.xkey.keycode, 0 );
433 switch( x_key_symbol )
436 p_vout->p_vlc->b_die = 1;
439 p_vout->p_vlc->p_intf->b_menu_change = 1;
442 input_Seek( p_vout, -5, INPUT_SEEK_SECONDS | INPUT_SEEK_CUR );
445 input_Seek( p_vout, 5, INPUT_SEEK_SECONDS | INPUT_SEEK_CUR );
448 input_Seek( p_vout, 60, INPUT_SEEK_SECONDS | INPUT_SEEK_CUR );
451 input_Seek( p_vout, -60, INPUT_SEEK_SECONDS | INPUT_SEEK_CUR );
454 input_Seek( p_vout, 0, INPUT_SEEK_BYTES | INPUT_SEEK_SET );
457 input_Seek( p_vout, 0, INPUT_SEEK_BYTES | INPUT_SEEK_END );
460 input_Seek( p_vout, 900, INPUT_SEEK_SECONDS | INPUT_SEEK_CUR );
463 input_Seek( p_vout, -900, INPUT_SEEK_SECONDS | INPUT_SEEK_CUR );
466 input_SetStatus( p_input_bank->pp_input[0],
467 INPUT_STATUS_PAUSE );
472 * The reason why I use this instead of XK_0 is that
473 * with XLookupString, we don't have to care about
476 if( XLookupString( &xevent.xkey, &i_key, 1, NULL, NULL ) )
478 /* FIXME: handle stuff here */
483 p_vout->p_vlc->b_die = 1;
487 p_vout->i_changes |= VOUT_FULLSCREEN_CHANGE;
498 else if( xevent.type == ButtonPress )
500 switch( ((XButtonEvent *)&xevent)->button )
503 /* In this part we will eventually manage
504 * clicks for DVD navigation for instance. */
506 /* detect double-clicks */
507 if( ( ((XButtonEvent *)&xevent)->time -
508 p_vout->p_sys->i_time_button_last_pressed ) < 300 )
510 p_vout->i_changes |= VOUT_FULLSCREEN_CHANGE;
513 p_vout->p_sys->i_time_button_last_pressed =
514 ((XButtonEvent *)&xevent)->time;
518 input_Seek( p_vout, 15, INPUT_SEEK_SECONDS | INPUT_SEEK_CUR );
522 input_Seek( p_vout, -15, INPUT_SEEK_SECONDS | INPUT_SEEK_CUR );
527 else if( xevent.type == ButtonRelease )
529 switch( ((XButtonEvent *)&xevent)->button )
532 /* FIXME: need locking ! */
533 p_vout->p_vlc->p_intf->b_menu_change = 1;
538 else if( xevent.type == MotionNotify )
540 p_vout->p_sys->i_time_mouse_last_moved = mdate();
541 if( ! p_vout->p_sys->b_mouse_pointer_visible )
543 ToggleCursor( p_vout );
549 msg_Warn( p_vout, "unhandled event %d received", xevent.type );
553 /* ClientMessage event - only WM_PROTOCOLS with WM_DELETE_WINDOW data
554 * are handled - according to the man pages, the format is always 32
556 while( XCheckTypedEvent( p_vout->p_sys->p_display,
557 ClientMessage, &xevent ) )
559 if( (xevent.xclient.message_type == p_vout->p_sys->wm_protocols)
560 && (xevent.xclient.data.l[0] == p_vout->p_sys->wm_delete_window ) )
562 p_vout->p_vlc->b_die = 1;
569 if ( p_vout->i_changes & VOUT_FULLSCREEN_CHANGE )
571 ToggleFullScreen( p_vout );
572 p_vout->i_changes &= ~VOUT_FULLSCREEN_CHANGE;
579 if( p_vout->i_changes & VOUT_SIZE_CHANGE )
581 int i_width, i_height, i_x, i_y;
583 p_vout->i_changes &= ~VOUT_SIZE_CHANGE;
585 msg_Dbg( p_vout, "video display resized (%dx%d)",
586 p_vout->p_sys->i_width, p_vout->p_sys->i_height );
588 vout_PlacePicture( p_vout, p_vout->p_sys->i_width,
589 p_vout->p_sys->i_height,
590 &i_x, &i_y, &i_width, &i_height );
593 /* Autohide Cursour */
594 if( mdate() - p_vout->p_sys->i_time_mouse_last_moved > 2000000 )
596 /* Hide the mouse automatically */
597 if( p_vout->p_sys->b_mouse_pointer_visible )
599 ToggleCursor( p_vout );
606 /*****************************************************************************
607 * End: terminate X11 video thread output method
608 *****************************************************************************
609 * Destroy the X11 XImages created by Init. It is called at the end of
610 * the thread, but also each time the window is resized.
611 *****************************************************************************/
612 static void End( vout_thread_t *p_vout )
616 /* Free the direct buffers we allocated */
617 for( i_index = I_OUTPUTPICTURES ; i_index ; )
620 FreePicture( p_vout, PP_OUTPUTPICTURE[ i_index ] );
624 /* following functions are local */
626 /*****************************************************************************
627 * CreateWindow: open and set-up X11 main window
628 *****************************************************************************/
629 static int CreateWindow( vout_thread_t *p_vout )
631 XSizeHints xsize_hints;
632 XSetWindowAttributes xwindow_attributes;
637 vlc_bool_t b_configure_notify;
638 vlc_bool_t b_map_notify;
640 /* Set main window's size */
641 p_vout->p_sys->i_width = p_vout->i_window_width;
642 p_vout->p_sys->i_height = p_vout->i_window_height;
644 /* Prepare window manager hints and properties */
645 xsize_hints.base_width = p_vout->p_sys->i_width;
646 xsize_hints.base_height = p_vout->p_sys->i_height;
647 xsize_hints.flags = PSize;
648 p_vout->p_sys->wm_protocols = XInternAtom( p_vout->p_sys->p_display,
649 "WM_PROTOCOLS", True );
650 p_vout->p_sys->wm_delete_window = XInternAtom( p_vout->p_sys->p_display,
651 "WM_DELETE_WINDOW", True );
653 /* Prepare window attributes */
654 xwindow_attributes.backing_store = Always; /* save the hidden part */
655 xwindow_attributes.background_pixel = BlackPixel(p_vout->p_sys->p_display,
656 p_vout->p_sys->i_screen);
657 xwindow_attributes.event_mask = ExposureMask | StructureNotifyMask;
660 /* Create the window and set hints - the window must receive
661 * ConfigureNotify events, and until it is displayed, Expose and
662 * MapNotify events. */
664 p_vout->p_sys->window =
665 XCreateWindow( p_vout->p_sys->p_display,
666 DefaultRootWindow( p_vout->p_sys->p_display ),
668 p_vout->p_sys->i_width,
669 p_vout->p_sys->i_height,
672 CWBackingStore | CWBackPixel | CWEventMask,
673 &xwindow_attributes );
675 /* Set window manager hints and properties: size hints, command,
676 * window's name, and accepted protocols */
677 XSetWMNormalHints( p_vout->p_sys->p_display, p_vout->p_sys->window,
679 XSetCommand( p_vout->p_sys->p_display, p_vout->p_sys->window,
680 p_vout->p_vlc->ppsz_argv, p_vout->p_vlc->i_argc );
681 XStoreName( p_vout->p_sys->p_display, p_vout->p_sys->window,
682 VOUT_TITLE " (XMGA output)"
685 if( (p_vout->p_sys->wm_protocols == None) /* use WM_DELETE_WINDOW */
686 || (p_vout->p_sys->wm_delete_window == None)
687 || !XSetWMProtocols( p_vout->p_sys->p_display, p_vout->p_sys->window,
688 &p_vout->p_sys->wm_delete_window, 1 ) )
690 /* WM_DELETE_WINDOW is not supported by window manager */
691 msg_Err( p_vout, "missing or bad window manager" );
694 /* Creation of a graphic context that doesn't generate a GraphicsExpose
695 * event when using functions like XCopyArea */
696 xgcvalues.graphics_exposures = False;
697 p_vout->p_sys->gc = XCreateGC( p_vout->p_sys->p_display,
698 p_vout->p_sys->window,
699 GCGraphicsExposures, &xgcvalues);
701 /* Send orders to server, and wait until window is displayed - three
702 * events must be received: a MapNotify event, an Expose event allowing
703 * drawing in the window, and a ConfigureNotify to get the window
704 * dimensions. Once those events have been received, only ConfigureNotify
705 * events need to be received. */
707 b_configure_notify = 0;
709 XMapWindow( p_vout->p_sys->p_display, p_vout->p_sys->window);
712 XNextEvent( p_vout->p_sys->p_display, &xevent);
713 if( (xevent.type == Expose)
714 && (xevent.xexpose.window == p_vout->p_sys->window) )
718 else if( (xevent.type == MapNotify)
719 && (xevent.xmap.window == p_vout->p_sys->window) )
723 else if( (xevent.type == ConfigureNotify)
724 && (xevent.xconfigure.window == p_vout->p_sys->window) )
726 b_configure_notify = 1;
727 p_vout->p_sys->i_width = xevent.xconfigure.width;
728 p_vout->p_sys->i_height = xevent.xconfigure.height;
730 } while( !( b_expose && b_configure_notify && b_map_notify ) );
732 XSelectInput( p_vout->p_sys->p_display, p_vout->p_sys->window,
733 StructureNotifyMask | KeyPressMask |
734 ButtonPressMask | ButtonReleaseMask |
737 /* If the cursor was formerly blank than blank it again */
738 if( !p_vout->p_sys->b_mouse_pointer_visible )
740 ToggleCursor( p_vout );
741 ToggleCursor( p_vout );
744 XSync( p_vout->p_sys->p_display, False );
746 /* At this stage, the window is open, displayed, and ready to
752 /*****************************************************************************
753 * DestroyWindow: destroy the window
754 *****************************************************************************
756 *****************************************************************************/
757 static void DestroyWindow( vout_thread_t *p_vout )
759 XSync( p_vout->p_sys->p_display, False );
761 XUnmapWindow( p_vout->p_sys->p_display, p_vout->p_sys->window );
762 XFreeGC( p_vout->p_sys->p_display, p_vout->p_sys->gc );
763 XDestroyWindow( p_vout->p_sys->p_display, p_vout->p_sys->window );
766 /*****************************************************************************
767 * NewPicture: allocate a picture
768 *****************************************************************************
769 * Returns 0 on success, -1 otherwise
770 *****************************************************************************/
771 static int NewPicture( vout_thread_t *p_vout, picture_t *p_pic )
773 /* We know the chroma, allocate a buffer which will be used
774 * directly by the decoder */
775 switch( p_vout->output.i_chroma )
780 /* Unknown chroma, tell the guy to get lost */
781 msg_Err( p_vout, "never heard of chroma 0x%.8x (%4.4s)",
782 p_vout->output.i_chroma, (char*)&p_vout->output.i_chroma );
790 /*****************************************************************************
791 * FreePicture: destroy a picture allocated with NewPicture
792 *****************************************************************************
793 * Destroy XImage AND associated data. If using Shm, detach shared memory
794 * segment from server and process, then free it. The XDestroyImage manpage
795 * says that both the image structure _and_ the data pointed to by the
796 * image structure are freed, so no need to free p_image->data.
797 *****************************************************************************/
798 static void FreePicture( vout_thread_t *p_vout, picture_t *p_pic )
800 XSync( p_vout->p_sys->p_display, False );
803 /*****************************************************************************
804 * ToggleFullScreen: Enable or disable full screen mode
805 *****************************************************************************
806 * This function will switch between fullscreen and window mode.
808 *****************************************************************************/
809 static void ToggleFullScreen ( vout_thread_t *p_vout )
813 int i_xpos, i_ypos, i_width, i_height;
815 XSetWindowAttributes attributes;
817 p_vout->b_fullscreen = !p_vout->b_fullscreen;
819 if( p_vout->b_fullscreen )
821 Window next_parent, parent, *p_dummy, dummy1;
822 unsigned int dummy2, dummy3;
824 msg_Dbg( p_vout, "entering fullscreen mode" );
826 /* Only check the fullscreen method when we actually go fullscreen,
827 * because to go back to window mode we need to know in which
828 * fullscreen mode we where */
829 p_vout->p_sys->b_altfullscreen = config_GetInt( p_vout,
830 "xmga-altfullscreen" );
832 /* Save current window coordinates so they can be restored when
833 * we exit from fullscreen mode. This is the tricky part because
834 * this heavily depends on the behaviour of the window manager.
835 * When you use XMoveWindow some window managers will adjust the top
836 * of the window to the coordinates you gave, but others will instead
837 * adjust the top of the client area to the coordinates
838 * (don't forget windows have decorations). */
840 /* First, get the position and size of the client area */
841 XGetGeometry( p_vout->p_sys->p_display,
842 p_vout->p_sys->window,
846 &p_vout->p_sys->i_width_backup_2,
847 &p_vout->p_sys->i_height_backup_2,
849 XTranslateCoordinates( p_vout->p_sys->p_display,
850 p_vout->p_sys->window,
851 DefaultRootWindow( p_vout->p_sys->p_display ),
854 &p_vout->p_sys->i_xpos_backup_2,
855 &p_vout->p_sys->i_ypos_backup_2,
858 /* Then try to get the position and size of the whole window */
860 /* find the real parent of our window (created by the window manager),
861 * the one which is a direct child of the root window */
862 next_parent = parent = p_vout->p_sys->window;
863 while( next_parent != DefaultRootWindow( p_vout->p_sys->p_display ) )
865 parent = next_parent;
866 XQueryTree( p_vout->p_sys->p_display,
872 XFree((void *)p_dummy);
875 XGetGeometry( p_vout->p_sys->p_display,
876 p_vout->p_sys->window,
880 &p_vout->p_sys->i_width_backup,
881 &p_vout->p_sys->i_height_backup,
884 XTranslateCoordinates( p_vout->p_sys->p_display,
886 DefaultRootWindow( p_vout->p_sys->p_display ),
889 &p_vout->p_sys->i_xpos_backup,
890 &p_vout->p_sys->i_ypos_backup,
893 /* fullscreen window size and position */
896 i_width = DisplayWidth( p_vout->p_sys->p_display,
897 p_vout->p_sys->i_screen );
898 i_height = DisplayHeight( p_vout->p_sys->p_display,
899 p_vout->p_sys->i_screen );
904 msg_Dbg( p_vout, "leaving fullscreen mode" );
906 i_xpos = p_vout->p_sys->i_xpos_backup;
907 i_ypos = p_vout->p_sys->i_ypos_backup;
908 i_width = p_vout->p_sys->i_width_backup;
909 i_height = p_vout->p_sys->i_height_backup;
912 /* To my knowledge there are two ways to create a borderless window.
913 * There's the generic way which is to tell x to bypass the window manager,
914 * but this creates problems with the focus of other applications.
915 * The other way is to use the motif property "_MOTIF_WM_HINTS" which
916 * luckily seems to be supported by most window managers.
918 if( !p_vout->p_sys->b_altfullscreen )
920 mwmhints.flags = MWM_HINTS_DECORATIONS;
921 mwmhints.decorations = !p_vout->b_fullscreen;
923 prop = XInternAtom( p_vout->p_sys->p_display, "_MOTIF_WM_HINTS",
925 XChangeProperty( p_vout->p_sys->p_display, p_vout->p_sys->window,
926 prop, prop, 32, PropModeReplace,
927 (unsigned char *)&mwmhints,
928 PROP_MWM_HINTS_ELEMENTS );
932 /* brute force way to remove decorations */
933 attributes.override_redirect = p_vout->b_fullscreen;
934 XChangeWindowAttributes( p_vout->p_sys->p_display,
935 p_vout->p_sys->window,
940 /* We need to unmap and remap the window if we want the window
941 * manager to take our changes into effect */
942 XUnmapWindow( p_vout->p_sys->p_display, p_vout->p_sys->window);
944 XWindowEvent( p_vout->p_sys->p_display, p_vout->p_sys->window,
945 StructureNotifyMask, &xevent );
946 while( xevent.type != UnmapNotify )
947 XWindowEvent( p_vout->p_sys->p_display, p_vout->p_sys->window,
948 StructureNotifyMask, &xevent );
950 XMapRaised( p_vout->p_sys->p_display, p_vout->p_sys->window);
952 while( xevent.type != MapNotify )
953 XWindowEvent( p_vout->p_sys->p_display, p_vout->p_sys->window,
954 StructureNotifyMask, &xevent );
956 XMoveResizeWindow( p_vout->p_sys->p_display,
957 p_vout->p_sys->window,
963 /* Purge all ConfigureNotify events, this is needed to fix a bug where we
964 * would lose the original size of the window */
965 while( xevent.type != ConfigureNotify )
966 XWindowEvent( p_vout->p_sys->p_display, p_vout->p_sys->window,
967 StructureNotifyMask, &xevent );
968 while( XCheckWindowEvent( p_vout->p_sys->p_display, p_vout->p_sys->window,
969 StructureNotifyMask, &xevent ) );
972 /* We need to check that the window was really restored where we wanted */
973 if( !p_vout->b_fullscreen )
976 unsigned int dummy2, dummy3, dummy4, dummy5;
978 /* Check the position */
979 XTranslateCoordinates( p_vout->p_sys->p_display,
980 p_vout->p_sys->window,
981 DefaultRootWindow( p_vout->p_sys->p_display ),
987 if( dummy2 != p_vout->p_sys->i_xpos_backup_2 ||
988 dummy3 != p_vout->p_sys->i_ypos_backup_2 )
990 /* Ok it didn't work... second try */
992 XMoveWindow( p_vout->p_sys->p_display,
993 p_vout->p_sys->window,
994 p_vout->p_sys->i_xpos_backup_2,
995 p_vout->p_sys->i_ypos_backup_2 );
997 /* Purge all ConfigureNotify events, this is needed to fix a bug
998 * where we would lose the original size of the window */
999 XWindowEvent( p_vout->p_sys->p_display, p_vout->p_sys->window,
1000 StructureNotifyMask, &xevent );
1001 while( xevent.type != ConfigureNotify )
1002 XWindowEvent( p_vout->p_sys->p_display, p_vout->p_sys->window,
1003 StructureNotifyMask, &xevent );
1004 while( XCheckWindowEvent( p_vout->p_sys->p_display,
1005 p_vout->p_sys->window,
1006 StructureNotifyMask, &xevent ) );
1009 /* Check the size */
1010 XGetGeometry( p_vout->p_sys->p_display,
1011 p_vout->p_sys->window,
1019 if( dummy4 != p_vout->p_sys->i_width_backup_2 ||
1020 dummy5 != p_vout->p_sys->i_height_backup_2 )
1022 /* Ok it didn't work... third try */
1024 XResizeWindow( p_vout->p_sys->p_display,
1025 p_vout->p_sys->window,
1026 p_vout->p_sys->i_width_backup_2,
1027 p_vout->p_sys->i_height_backup_2 );
1029 /* Purge all ConfigureNotify events, this is needed to fix a bug
1030 * where we would lose the original size of the window */
1031 XWindowEvent( p_vout->p_sys->p_display, p_vout->p_sys->window,
1032 StructureNotifyMask, &xevent );
1033 while( xevent.type != ConfigureNotify )
1034 XWindowEvent( p_vout->p_sys->p_display, p_vout->p_sys->window,
1035 StructureNotifyMask, &xevent );
1036 while( XCheckWindowEvent( p_vout->p_sys->p_display,
1037 p_vout->p_sys->window,
1038 StructureNotifyMask, &xevent ) );
1042 if( p_vout->p_sys->b_altfullscreen )
1043 XSetInputFocus(p_vout->p_sys->p_display,
1044 p_vout->p_sys->window,
1048 /* signal that the size needs to be updated */
1049 p_vout->p_sys->i_width = i_width;
1050 p_vout->p_sys->i_height = i_height;
1051 p_vout->i_changes |= VOUT_SIZE_CHANGE;
1055 /*****************************************************************************
1056 * EnableXScreenSaver: enable screen saver
1057 *****************************************************************************
1058 * This function enables the screen saver on a display after it has been
1059 * disabled by XDisableScreenSaver.
1060 * FIXME: what happens if multiple vlc sessions are running at the same
1062 *****************************************************************************/
1063 static void EnableXScreenSaver( vout_thread_t *p_vout )
1067 XSetScreenSaver( p_vout->p_sys->p_display, p_vout->p_sys->i_ss_timeout,
1068 p_vout->p_sys->i_ss_interval,
1069 p_vout->p_sys->i_ss_blanking,
1070 p_vout->p_sys->i_ss_exposure );
1072 /* Restore DPMS settings */
1073 if( DPMSQueryExtension( p_vout->p_sys->p_display, &dummy, &dummy ) )
1075 if( p_vout->p_sys->b_ss_dpms )
1077 DPMSEnable( p_vout->p_sys->p_display );
1082 /*****************************************************************************
1083 * DisableXScreenSaver: disable screen saver
1084 *****************************************************************************
1085 * See XEnableXScreenSaver
1086 *****************************************************************************/
1087 static void DisableXScreenSaver( vout_thread_t *p_vout )
1091 /* Save screen saver informations */
1092 XGetScreenSaver( p_vout->p_sys->p_display, &p_vout->p_sys->i_ss_timeout,
1093 &p_vout->p_sys->i_ss_interval,
1094 &p_vout->p_sys->i_ss_blanking,
1095 &p_vout->p_sys->i_ss_exposure );
1097 /* Disable screen saver */
1098 XSetScreenSaver( p_vout->p_sys->p_display, 0,
1099 p_vout->p_sys->i_ss_interval,
1100 p_vout->p_sys->i_ss_blanking,
1101 p_vout->p_sys->i_ss_exposure );
1104 if( DPMSQueryExtension( p_vout->p_sys->p_display, &dummy, &dummy ) )
1107 /* Save DPMS current state */
1108 DPMSInfo( p_vout->p_sys->p_display, &dummy,
1109 &p_vout->p_sys->b_ss_dpms );
1110 DPMSDisable( p_vout->p_sys->p_display );
1114 /*****************************************************************************
1115 * CreateCursor: create a blank mouse pointer
1116 *****************************************************************************/
1117 static void CreateCursor( vout_thread_t *p_vout )
1119 XColor cursor_color;
1121 p_vout->p_sys->cursor_pixmap =
1122 XCreatePixmap( p_vout->p_sys->p_display,
1123 DefaultRootWindow( p_vout->p_sys->p_display ),
1126 XParseColor( p_vout->p_sys->p_display,
1127 XCreateColormap( p_vout->p_sys->p_display,
1129 p_vout->p_sys->p_display ),
1131 p_vout->p_sys->p_display,
1132 p_vout->p_sys->i_screen ),
1134 "black", &cursor_color );
1136 p_vout->p_sys->blank_cursor =
1137 XCreatePixmapCursor( p_vout->p_sys->p_display,
1138 p_vout->p_sys->cursor_pixmap,
1139 p_vout->p_sys->cursor_pixmap,
1140 &cursor_color, &cursor_color, 1, 1 );
1143 /*****************************************************************************
1144 * DestroyCursor: destroy the blank mouse pointer
1145 *****************************************************************************/
1146 static void DestroyCursor( vout_thread_t *p_vout )
1148 XFreePixmap( p_vout->p_sys->p_display, p_vout->p_sys->cursor_pixmap );
1151 /*****************************************************************************
1152 * ToggleCursor: hide or show the mouse pointer
1153 *****************************************************************************
1154 * This function hides the X pointer if it is visible by setting the pointer
1155 * sprite to a blank one. To show it again, we disable the sprite.
1156 *****************************************************************************/
1157 static void ToggleCursor( vout_thread_t *p_vout )
1159 if( p_vout->p_sys->b_mouse_pointer_visible )
1161 XDefineCursor( p_vout->p_sys->p_display,
1162 p_vout->p_sys->window,
1163 p_vout->p_sys->blank_cursor );
1164 p_vout->p_sys->b_mouse_pointer_visible = 0;
1168 XUndefineCursor( p_vout->p_sys->p_display, p_vout->p_sys->window );
1169 p_vout->p_sys->b_mouse_pointer_visible = 1;