]> git.sesse.net Git - vlc/blob - plugins/x11/vout_common.c
* MPEG-1 aspect ratio patch, courtesy of Vladimir Chernyshov
[vlc] / plugins / x11 / vout_common.c
1 /*****************************************************************************
2  * vout_common.c: Functions common to the X11 and XVideo plugins
3  *****************************************************************************
4  * Copyright (C) 1998-2001 VideoLAN
5  * $Id: vout_common.c,v 1.2 2001/12/10 10:58:54 massiot Exp $
6  *
7  * Authors: Vincent Seguin <seguin@via.ecp.fr>
8  *          Samuel Hocevar <sam@zoy.org>
9  *          David Kennedy <dkennedy@tinytoad.com>
10  *
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.
15  *
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.
20  *
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  *****************************************************************************/
25
26 #include "modules_inner.h"
27
28 /*****************************************************************************
29  * Preamble
30  *****************************************************************************/
31 #include "defs.h"
32
33 #include <errno.h>                                                 /* ENOMEM */
34 #include <stdlib.h>                                                /* free() */
35 #include <string.h>                                            /* strerror() */
36
37 #ifdef HAVE_MACHINE_PARAM_H
38 /* BSD */
39 #include <machine/param.h>
40 #include <sys/types.h>                                     /* typedef ushort */
41 #include <sys/ipc.h>
42 #endif
43
44 #ifndef WIN32
45 #include <netinet/in.h>                               /* BSD: struct in_addr */
46 #endif
47
48 #include <sys/shm.h>                                   /* shmget(), shmctl() */
49 #include <X11/Xlib.h>
50 #include <X11/Xutil.h>
51 #include <X11/keysym.h>
52 #include <X11/extensions/XShm.h>
53
54 #define x11 12
55 #define xvideo 42
56 #if ( MODULE_NAME == x11 )
57 #   define MODULE_NAME_IS_x11 1
58 #elif ( MODULE_NAME == xvideo )
59 #   define MODULE_NAME_IS_xvideo 1
60 #   include <X11/extensions/Xv.h>
61 #   include <X11/extensions/Xvlib.h>
62 #   include <X11/extensions/dpms.h>
63 #endif
64 #undef x11
65 #undef xvideo
66
67 #include "common.h"
68 #include "intf_msg.h"
69 #include "threads.h"
70 #include "mtime.h"
71 #include "tests.h"
72
73 #include "video.h"
74 #include "video_output.h"
75 #include "vout_common.h"
76
77 #include "interface.h"
78 #include "netutils.h"                                 /* network_ChannelJoin */
79
80 #include "stream_control.h"                 /* needed by input_ext-intf.h... */
81 #include "input_ext-intf.h"
82
83 #include "modules.h"
84 #include "modules_export.h"
85
86 /*****************************************************************************
87  * vout_Manage: handle X11 events
88  *****************************************************************************
89  * This function should be called regularly by video output thread. It manages
90  * X11 events and allows window resizing. It returns a non null value on
91  * error.
92  *****************************************************************************/
93 static __inline__ void vout_Seek( int i_seek )
94 {
95     int i_tell = p_main->p_intf->p_input->stream.p_selected_area->i_tell;
96
97     i_tell += i_seek * 50 * p_main->p_intf->p_input->stream.i_mux_rate;
98
99     if( i_tell < p_main->p_intf->p_input->stream.p_selected_area->i_start )
100     {
101         i_tell = p_main->p_intf->p_input->stream.p_selected_area->i_start;
102     }
103     else if( i_tell > p_main->p_intf->p_input->stream.p_selected_area->i_size )
104     {
105         i_tell = p_main->p_intf->p_input->stream.p_selected_area->i_size;
106     }
107
108     input_Seek( p_main->p_intf->p_input, i_tell );
109 }
110
111 int _M( vout_Manage ) ( vout_thread_t *p_vout )
112 {
113     XEvent      xevent;                                         /* X11 event */
114     boolean_t   b_resized;                        /* window has been resized */
115     char        i_key;                                    /* ISO Latin-1 key */
116     KeySym      x_key_symbol;
117
118     /* Handle X11 events: ConfigureNotify events are parsed to know if the
119      * output window's size changed, MapNotify and UnmapNotify to know if the
120      * window is mapped (and if the display is useful), and ClientMessages
121      * to intercept window destruction requests */
122
123     b_resized = 0;
124     while( XCheckWindowEvent( p_vout->p_sys->p_display, p_vout->p_sys->window,
125                               StructureNotifyMask | KeyPressMask |
126                               ButtonPressMask | ButtonReleaseMask | 
127                               PointerMotionMask | Button1MotionMask , &xevent )
128            == True )
129     {
130         /* ConfigureNotify event: prepare  */
131         if( (xevent.type == ConfigureNotify)
132           && ((xevent.xconfigure.width != p_vout->p_sys->i_window_width)
133              || (xevent.xconfigure.height != p_vout->p_sys->i_window_height)) )
134         {
135             /* Update dimensions */
136             b_resized = 1;
137             p_vout->p_sys->i_window_width = xevent.xconfigure.width;
138             p_vout->p_sys->i_window_height = xevent.xconfigure.height;
139         }
140         /* MapNotify event: change window status and disable screen saver */
141         else if( xevent.type == MapNotify)
142         {
143             if( (p_vout != NULL) && !p_vout->b_active )
144             {
145                 _M( XCommonDisableScreenSaver ) ( p_vout );
146                 p_vout->b_active = 1;
147             }
148         }
149         /* UnmapNotify event: change window status and enable screen saver */
150         else if( xevent.type == UnmapNotify )
151         {
152             if( (p_vout != NULL) && p_vout->b_active )
153             {
154                 _M( XCommonEnableScreenSaver ) ( p_vout );
155                 p_vout->b_active = 0;
156             }
157         }
158         /* Keyboard event */
159         else if( xevent.type == KeyPress )
160         {
161             /* We may have keys like F1 trough F12, ESC ... */
162             x_key_symbol = XKeycodeToKeysym( p_vout->p_sys->p_display,
163                                              xevent.xkey.keycode, 0 );
164             switch( x_key_symbol )
165             {
166                  case XK_Escape:
167                      p_main->p_intf->b_die = 1;
168                      break;
169                  case XK_Menu:
170                      p_main->p_intf->b_menu_change = 1;
171                      break;
172                  case XK_Left:
173                      vout_Seek( -5 );
174                      break;
175                  case XK_Right:
176                      vout_Seek( 5 );
177                      break;
178                  case XK_Up:
179                      vout_Seek( 60 );
180                      break;
181                  case XK_Down:
182                      vout_Seek( -60 );
183                      break;
184                  case XK_Home:
185                      input_Seek( p_main->p_intf->p_input,
186                      p_main->p_intf->p_input->stream.p_selected_area->i_start );
187                      break;
188                  case XK_End:
189                      input_Seek( p_main->p_intf->p_input,
190                      p_main->p_intf->p_input->stream.p_selected_area->i_size );
191                      break;
192                  case XK_Page_Up:
193                      vout_Seek( 900 );
194                      break;
195                  case XK_Page_Down:
196                      vout_Seek( -900 );
197                      break;
198                  case XK_space:
199                      input_SetStatus( p_main->p_intf->p_input,
200                                       INPUT_STATUS_PAUSE );
201                      break;
202
203                  default:
204                      /* "Normal Keys"
205                       * The reason why I use this instead of XK_0 is that 
206                       * with XLookupString, we don't have to care about
207                       * keymaps. */
208
209                     if( XLookupString( &xevent.xkey, &i_key, 1, NULL, NULL ) )
210                     {
211                         /* FIXME: handle stuff here */
212                         switch( i_key )
213                         {
214                         case 'q':
215                         case 'Q':
216                             p_main->p_intf->b_die = 1;
217                             break;
218                         case 'f':
219                         case 'F':
220                             p_vout->i_changes |= VOUT_FULLSCREEN_CHANGE;
221                             break;
222
223                         case '0': network_ChannelJoin( 0 ); break;
224                         case '1': network_ChannelJoin( 1 ); break;
225                         case '2': network_ChannelJoin( 2 ); break;
226                         case '3': network_ChannelJoin( 3 ); break;
227                         case '4': network_ChannelJoin( 4 ); break;
228                         case '5': network_ChannelJoin( 5 ); break;
229                         case '6': network_ChannelJoin( 6 ); break;
230                         case '7': network_ChannelJoin( 7 ); break;
231                         case '8': network_ChannelJoin( 8 ); break;
232                         case '9': network_ChannelJoin( 9 ); break;
233
234                         default:
235                             intf_DbgMsg( "vout: unhandled key '%c' (%i)", 
236                                          (char)i_key, i_key );
237                             break;
238                         }
239                     }
240                 break;
241             }
242         }
243         /* Mouse click */
244         else if( xevent.type == ButtonPress )
245         {
246             switch( ((XButtonEvent *)&xevent)->button )
247             {
248                 case Button1:
249                     /* In this part we will eventually manage
250                      * clicks for DVD navigation for instance. For the
251                      * moment just pause the stream. */
252                     input_SetStatus( p_main->p_intf->p_input,
253                                      INPUT_STATUS_PAUSE );
254                     break;
255             }
256         }
257         /* Mouse release */
258         else if( xevent.type == ButtonRelease )
259         {
260             switch( ((XButtonEvent *)&xevent)->button )
261             {
262                 case Button3:
263                     /* FIXME: need locking ! */
264                     p_main->p_intf->b_menu_change = 1;
265                     break;
266             }
267         }
268         /* Mouse move */
269         else if( xevent.type == MotionNotify )
270         {
271             p_vout->p_sys->i_time_mouse_last_moved = mdate();
272             if( ! p_vout->p_sys->b_mouse_pointer_visible )
273             {
274                 _M( XCommonToggleMousePointer ) ( p_vout ); 
275             }
276         }
277         /* Other event */
278         else
279         {
280             intf_WarnMsg( 3, "vout: unhandled event %d received", xevent.type );
281         }
282     }
283
284     /* Handle events for YUV video output sub-window */
285     while( XCheckWindowEvent( p_vout->p_sys->p_display,
286                               p_vout->p_sys->yuv_window,
287                               ExposureMask, &xevent ) == True )
288     {
289         /* Window exposed (only handled if stream playback is paused) */
290         if( xevent.type == Expose )
291         {
292             if( ((XExposeEvent *)&xevent)->count == 0 )
293             {
294                 /* (if this is the last a collection of expose events...) */
295                 if( p_main->p_intf->p_input != NULL )
296                 {
297                     if( PAUSE_S ==
298                             p_main->p_intf->p_input->stream.control.i_status )
299                     {
300 /*                        XVideoDisplay( p_vout )*/;
301                     }
302                 }
303             }
304         }
305     }
306
307     /* ClientMessage event - only WM_PROTOCOLS with WM_DELETE_WINDOW data
308      * are handled - according to the man pages, the format is always 32
309      * in this case */
310     while( XCheckTypedEvent( p_vout->p_sys->p_display,
311                              ClientMessage, &xevent ) )
312     {
313         if( (xevent.xclient.message_type == p_vout->p_sys->wm_protocols)
314             && (xevent.xclient.data.l[0] == p_vout->p_sys->wm_delete_window ) )
315         {
316             p_main->p_intf->b_die = 1;
317         }
318         else
319         {
320             intf_DbgMsg( "vout: unhandled ClientMessage received" );
321         }
322     }
323
324     if ( p_vout->i_changes & VOUT_FULLSCREEN_CHANGE )
325     {
326         p_vout->i_changes &= ~VOUT_FULLSCREEN_CHANGE;
327
328         p_vout->b_fullscreen = !p_vout->b_fullscreen;
329
330         /* Get rid of the old window */
331         _M( XCommonDestroyWindow ) ( p_vout );
332
333         /* And create a new one */
334         if( _M( XCommonCreateWindow ) ( p_vout ) )
335         {
336             intf_ErrMsg( "vout error: cannot create X11 window" );
337             XCloseDisplay( p_vout->p_sys->p_display );
338
339             free( p_vout->p_sys );
340             return( 1 );
341         }
342
343     }
344
345 #ifdef MODULE_NAME_IS_x11
346     /*
347      * Handle vout window resizing
348      */
349     if( b_resized )
350     {
351         /* If interface window has been resized, change vout size */
352         intf_DbgMsg( "vout: resizing output window" );
353         p_vout->i_width =  p_vout->p_sys->i_width;
354         p_vout->i_height = p_vout->p_sys->i_height;
355         p_vout->i_changes |= VOUT_SIZE_CHANGE;
356     }
357     else if( (p_vout->i_width  != p_vout->p_sys->i_width) ||
358              (p_vout->i_height != p_vout->p_sys->i_height) )
359     {
360         /* If video output size has changed, change interface window size */
361         intf_DbgMsg( "vout: resizing output window" );
362         p_vout->p_sys->i_width =    p_vout->i_width;
363         p_vout->p_sys->i_height =   p_vout->i_height;
364         XResizeWindow( p_vout->p_sys->p_display, p_vout->p_sys->window,
365                        p_vout->p_sys->i_width, p_vout->p_sys->i_height );
366     }
367     /*
368      * Color/Grayscale or gamma change: in 8bpp, just change the colormap
369      */
370     if( (p_vout->i_changes & VOUT_GRAYSCALE_CHANGE)
371         && (p_vout->i_screen_depth == 8) )
372     {
373         /* FIXME: clear flags ?? */
374     }
375
376     /*
377      * Size change
378      */
379     if( p_vout->i_changes & VOUT_SIZE_CHANGE )
380     {
381         intf_DbgMsg( "vout info: resizing window" );
382         p_vout->i_changes &= ~VOUT_SIZE_CHANGE;
383
384         /* Resize window */
385         XResizeWindow( p_vout->p_sys->p_display, p_vout->p_sys->window,
386                        p_vout->i_width, p_vout->i_height );
387
388         /* Destroy XImages to change their size */
389         vout_End( p_vout );
390
391         /* Recreate XImages. If SysInit failed, the thread can't go on. */
392         if( vout_Init( p_vout ) )
393         {
394             intf_ErrMsg( "vout error: cannot resize display" );
395             return( 1 );
396        }
397
398         /* Tell the video output thread that it will need to rebuild YUV
399          * tables. This is needed since conversion buffer size may have
400          * changed */
401         p_vout->i_changes |= VOUT_YUV_CHANGE;
402         intf_Msg( "vout: video display resized (%dx%d)",
403                   p_vout->i_width, p_vout->i_height);
404     }
405 #else
406     /*
407      * Size change
408      */
409     if( p_vout->i_changes & VOUT_SIZE_CHANGE )
410     {
411         p_vout->i_changes &= ~VOUT_SIZE_CHANGE;
412
413         p_vout->i_width = p_vout->p_sys->i_window_width;
414         p_vout->i_height = p_vout->p_sys->i_window_height;
415
416         intf_WarnMsg( 3, "vout: video display resized (%dx%d)",
417                       p_vout->i_width, p_vout->i_height );
418     }
419 #endif
420
421     /* Autohide Cursour */
422     if( mdate() - p_vout->p_sys->i_time_mouse_last_moved > 2000000 )
423     {
424         /* Hide the mouse automatically */
425         if( p_vout->p_sys->b_mouse_pointer_visible )
426         {
427             _M( XCommonToggleMousePointer ) ( p_vout ); 
428         }
429     }
430
431     return 0;
432 }
433
434 /*****************************************************************************
435  * XCommonCreateWindow: open and set-up X11 main window
436  *****************************************************************************/
437 int _M( XCommonCreateWindow ) ( vout_thread_t *p_vout )
438 {
439     XSizeHints              xsize_hints;
440     XSetWindowAttributes    xwindow_attributes;
441     XGCValues               xgcvalues;
442     XEvent                  xevent;
443     Atom                    prop;
444     mwmhints_t              mwmhints;
445
446     boolean_t               b_expose;
447     boolean_t               b_configure_notify;
448     boolean_t               b_map_notify;
449
450     /* If we're full screen, we're full screen! */
451     if( p_vout->b_fullscreen ) 
452     {
453         p_vout->p_sys->i_window_width =
454            DisplayWidth( p_vout->p_sys->p_display, p_vout->p_sys->i_screen );
455         p_vout->p_sys->i_window_height =
456            DisplayHeight( p_vout->p_sys->p_display, p_vout->p_sys->i_screen ); 
457     }
458     else
459     {
460         /* Set main window's size */
461         p_vout->p_sys->i_window_width = p_vout->i_width;
462         p_vout->p_sys->i_window_height = p_vout->i_height;
463     }
464
465     /* Prepare window manager hints and properties */
466     xsize_hints.base_width          = p_vout->p_sys->i_window_width;
467     xsize_hints.base_height         = p_vout->p_sys->i_window_height;
468     xsize_hints.flags               = PSize;
469     p_vout->p_sys->wm_protocols     = XInternAtom( p_vout->p_sys->p_display,
470                                                    "WM_PROTOCOLS", True );
471     p_vout->p_sys->wm_delete_window = XInternAtom( p_vout->p_sys->p_display,
472                                                    "WM_DELETE_WINDOW", True );
473
474     /* Prepare window attributes */
475     xwindow_attributes.backing_store = Always;       /* save the hidden part */
476     xwindow_attributes.background_pixel = BlackPixel( p_vout->p_sys->p_display,
477                                                       p_vout->p_sys->i_screen );
478     xwindow_attributes.event_mask = ExposureMask | StructureNotifyMask;
479     
480
481     /* Create the window and set hints - the window must receive ConfigureNotify
482      * events, and, until it is displayed, Expose and MapNotify events. */
483
484     p_vout->p_sys->window =
485         XCreateWindow( p_vout->p_sys->p_display,
486                        DefaultRootWindow( p_vout->p_sys->p_display ),
487                        0, 0,
488                        p_vout->p_sys->i_window_width,
489                        p_vout->p_sys->i_window_height,
490 #ifdef MODULE_NAME_IS_x11
491                        /* XXX - what's this ? */
492                        0,
493 #else
494                        1,
495 #endif
496                        0, InputOutput, 0,
497                        CWBackingStore | CWBackPixel | CWEventMask,
498                        &xwindow_attributes );
499
500     if ( p_vout->b_fullscreen )
501     {
502         prop = XInternAtom(p_vout->p_sys->p_display, "_MOTIF_WM_HINTS", False);
503         mwmhints.flags = MWM_HINTS_DECORATIONS;
504         mwmhints.decorations = 0;
505         XChangeProperty( p_vout->p_sys->p_display, p_vout->p_sys->window,
506                          prop, prop, 32, PropModeReplace,
507                          (unsigned char *)&mwmhints, PROP_MWM_HINTS_ELEMENTS );
508
509         XSetTransientForHint( p_vout->p_sys->p_display,
510                               p_vout->p_sys->window, None );
511         XRaiseWindow( p_vout->p_sys->p_display, p_vout->p_sys->window );
512     }
513
514     /* Set window manager hints and properties: size hints, command,
515      * window's name, and accepted protocols */
516     XSetWMNormalHints( p_vout->p_sys->p_display, p_vout->p_sys->window,
517                        &xsize_hints );
518     XSetCommand( p_vout->p_sys->p_display, p_vout->p_sys->window,
519                  p_main->ppsz_argv, p_main->i_argc );
520     XStoreName( p_vout->p_sys->p_display, p_vout->p_sys->window,
521 #ifdef MODULE_NAME_IS_x11
522                 VOUT_TITLE " (X11 output)"
523 #else
524                 VOUT_TITLE " (XVideo output)"
525 #endif
526               );
527
528     if( (p_vout->p_sys->wm_protocols == None)        /* use WM_DELETE_WINDOW */
529         || (p_vout->p_sys->wm_delete_window == None)
530         || !XSetWMProtocols( p_vout->p_sys->p_display, p_vout->p_sys->window,
531                              &p_vout->p_sys->wm_delete_window, 1 ) )
532     {
533         /* WM_DELETE_WINDOW is not supported by window manager */
534         intf_Msg( "vout error: missing or bad window manager" );
535     }
536
537     /* Creation of a graphic context that doesn't generate a GraphicsExpose
538      * event when using functions like XCopyArea */
539     xgcvalues.graphics_exposures = False;
540     p_vout->p_sys->gc = XCreateGC( p_vout->p_sys->p_display,
541                                    p_vout->p_sys->window,
542                                    GCGraphicsExposures, &xgcvalues);
543
544     /* Send orders to server, and wait until window is displayed - three
545      * events must be received: a MapNotify event, an Expose event allowing
546      * drawing in the window, and a ConfigureNotify to get the window
547      * dimensions. Once those events have been received, only ConfigureNotify
548      * events need to be received. */
549     b_expose = 0;
550     b_configure_notify = 0;
551     b_map_notify = 0;
552     XMapWindow( p_vout->p_sys->p_display, p_vout->p_sys->window);
553     do
554     {
555         XNextEvent( p_vout->p_sys->p_display, &xevent);
556         if( (xevent.type == Expose)
557             && (xevent.xexpose.window == p_vout->p_sys->window) )
558         {
559             b_expose = 1;
560         }
561         else if( (xevent.type == MapNotify)
562                  && (xevent.xmap.window == p_vout->p_sys->window) )
563         {
564             b_map_notify = 1;
565         }
566         else if( (xevent.type == ConfigureNotify)
567                  && (xevent.xconfigure.window == p_vout->p_sys->window) )
568         {
569             b_configure_notify = 1;
570             p_vout->p_sys->i_window_width = xevent.xconfigure.width;
571             p_vout->p_sys->i_window_height = xevent.xconfigure.height;
572         }
573     } while( !( b_expose && b_configure_notify && b_map_notify ) );
574
575     XSelectInput( p_vout->p_sys->p_display, p_vout->p_sys->window,
576                   StructureNotifyMask | KeyPressMask |
577                   ButtonPressMask | ButtonReleaseMask | 
578                   PointerMotionMask );
579
580     if( p_vout->b_fullscreen )
581     {
582         XSetInputFocus( p_vout->p_sys->p_display, p_vout->p_sys->window,
583                         RevertToNone, CurrentTime );
584         XMoveWindow( p_vout->p_sys->p_display, p_vout->p_sys->window, 0, 0 );
585     }
586
587 #ifdef MODULE_NAME_IS_x11
588     if( XDefaultDepth(p_vout->p_sys->p_display, p_vout->p_sys->i_screen) == 8 )
589     {
590         /* Allocate a new palette */
591         p_vout->p_sys->colormap =
592             XCreateColormap( p_vout->p_sys->p_display,
593                              DefaultRootWindow( p_vout->p_sys->p_display ),
594                              DefaultVisual( p_vout->p_sys->p_display,
595                                             p_vout->p_sys->i_screen ),
596                              AllocAll );
597
598         xwindow_attributes.colormap = p_vout->p_sys->colormap;
599         XChangeWindowAttributes( p_vout->p_sys->p_display,
600                                  p_vout->p_sys->window,
601                                  CWColormap, &xwindow_attributes );
602     }
603
604 #else
605     /* Create YUV output sub-window. */
606     p_vout->p_sys->yuv_window=XCreateSimpleWindow( p_vout->p_sys->p_display,
607                          p_vout->p_sys->window, 0, 0, 1, 1, 0,
608                          BlackPixel( p_vout->p_sys->p_display,
609                                          p_vout->p_sys->i_screen ),
610                          WhitePixel( p_vout->p_sys->p_display,
611                                          p_vout->p_sys->i_screen ) );
612
613     p_vout->p_sys->yuv_gc = XCreateGC( p_vout->p_sys->p_display,
614                                        p_vout->p_sys->yuv_window,
615                                        GCGraphicsExposures, &xgcvalues );
616     
617     XSetWindowBackground( p_vout->p_sys->p_display, p_vout->p_sys->yuv_window,
618              BlackPixel(p_vout->p_sys->p_display, p_vout->p_sys->i_screen ) );
619     
620     XMapWindow( p_vout->p_sys->p_display, p_vout->p_sys->yuv_window );
621     XSelectInput( p_vout->p_sys->p_display, p_vout->p_sys->yuv_window,
622                   ExposureMask );
623 #endif
624
625     /* If the cursor was formerly blank than blank it again */
626     if( !p_vout->p_sys->b_mouse_pointer_visible )
627     {
628         _M( XCommonToggleMousePointer ) ( p_vout );
629         _M( XCommonToggleMousePointer ) ( p_vout );
630     }
631
632     XSync( p_vout->p_sys->p_display, False );
633
634     /* At this stage, the window is open, displayed, and ready to
635      * receive data */
636
637     return( 0 );
638 }
639
640 void _M( XCommonDestroyWindow ) ( vout_thread_t *p_vout )
641 {
642     XSync( p_vout->p_sys->p_display, False );
643
644 #ifdef MODULE_NAME_IS_xvideo
645     XFreeGC( p_vout->p_sys->p_display, p_vout->p_sys->yuv_gc );
646     XDestroyWindow( p_vout->p_sys->p_display, p_vout->p_sys->yuv_window );
647 #endif
648
649     XUnmapWindow( p_vout->p_sys->p_display, p_vout->p_sys->window );
650     XFreeGC( p_vout->p_sys->p_display, p_vout->p_sys->gc );
651     XDestroyWindow( p_vout->p_sys->p_display, p_vout->p_sys->window );
652 }
653
654 /*****************************************************************************
655  * XCommonEnableScreenSaver: enable screen saver
656  *****************************************************************************
657  * This function enable the screen saver on a display after it had been
658  * disabled by XDisableScreenSaver. Both functions use a counter mechanism to
659  * know wether the screen saver can be activated or not: if n successive calls
660  * are made to XDisableScreenSaver, n successive calls to XEnableScreenSaver
661  * will be required before the screen saver could effectively be activated.
662  *****************************************************************************/
663 void _M( XCommonEnableScreenSaver ) ( vout_thread_t *p_vout )
664 {
665     intf_DbgMsg( "vout: enabling screen saver" );
666     XSetScreenSaver( p_vout->p_sys->p_display, p_vout->p_sys->i_ss_timeout,
667                      p_vout->p_sys->i_ss_interval,
668                      p_vout->p_sys->i_ss_blanking,
669                      p_vout->p_sys->i_ss_exposure );
670 }
671
672 /*****************************************************************************
673  * XCommonDisableScreenSaver: disable screen saver
674  *****************************************************************************
675  * See XEnableScreenSaver
676  *****************************************************************************/
677 void _M( XCommonDisableScreenSaver ) ( vout_thread_t *p_vout )
678 {
679     /* Save screen saver informations */
680     XGetScreenSaver( p_vout->p_sys->p_display, &p_vout->p_sys->i_ss_timeout,
681                      &p_vout->p_sys->i_ss_interval,
682                      &p_vout->p_sys->i_ss_blanking,
683                      &p_vout->p_sys->i_ss_exposure );
684
685     /* Disable screen saver */
686     intf_DbgMsg( "vout: disabling screen saver" );
687     XSetScreenSaver( p_vout->p_sys->p_display, 0,
688                      p_vout->p_sys->i_ss_interval,
689                      p_vout->p_sys->i_ss_blanking,
690                      p_vout->p_sys->i_ss_exposure );
691
692 #ifdef MODULE_NAME_IS_xvideo
693     DPMSDisable( p_vout->p_sys->p_display );
694 #endif
695 }
696
697 /*****************************************************************************
698  * XCommonToggleMousePointer: hide or show the mouse pointer
699  *****************************************************************************
700  * This function hides the X pointer if it is visible by putting it at
701  * coordinates (32,32) and setting the pointer sprite to a blank one. To
702  * show it again, we disable the sprite and restore the original coordinates.
703  *****************************************************************************/
704 void _M( XCommonToggleMousePointer ) ( vout_thread_t *p_vout )
705 {
706     if( p_vout->p_sys->b_mouse_pointer_visible )
707     {
708         XDefineCursor( p_vout->p_sys->p_display,
709                        p_vout->p_sys->window,
710                        p_vout->p_sys->blank_cursor );
711         p_vout->p_sys->b_mouse_pointer_visible = 0;
712     }
713     else
714     {
715         XUndefineCursor( p_vout->p_sys->p_display, p_vout->p_sys->window );
716         p_vout->p_sys->b_mouse_pointer_visible = 1;
717     }
718 }
719