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