00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030 #include <errno.h>
00031 #include <stdlib.h>
00032 #include <string.h>
00033
00034 #include <vlc/vlc.h>
00035 #include <vlc/intf.h>
00036 #include <vlc/vout.h>
00037 #include <vlc_keys.h>
00038
00039 #ifdef HAVE_MACHINE_PARAM_H
00040
00041 # include <machine/param.h>
00042 # include <sys/types.h>
00043 # include <sys/ipc.h>
00044 #endif
00045
00046 #ifndef WIN32
00047 # include <netinet/in.h>
00048 #endif
00049
00050 #ifdef HAVE_SYS_SHM_H
00051 # include <sys/shm.h>
00052 #endif
00053
00054 #include <X11/Xlib.h>
00055 #include <X11/Xproto.h>
00056 #include <X11/Xmd.h>
00057 #include <X11/Xutil.h>
00058 #include <X11/keysym.h>
00059 #ifdef HAVE_SYS_SHM_H
00060 # include <X11/extensions/XShm.h>
00061 #endif
00062 #ifdef DPMSINFO_IN_DPMS_H
00063 # include <X11/extensions/dpms.h>
00064 #endif
00065
00066 #ifdef MODULE_NAME_IS_xvideo
00067 # include <X11/extensions/Xv.h>
00068 # include <X11/extensions/Xvlib.h>
00069 #endif
00070
00071 #ifdef MODULE_NAME_IS_glx
00072 # include <GL/glx.h>
00073 #endif
00074
00075 #ifdef HAVE_XINERAMA
00076 # include <X11/extensions/Xinerama.h>
00077 #endif
00078
00079 #include "xcommon.h"
00080
00081
00082
00083
00084 int E_(Activate) ( vlc_object_t * );
00085 void E_(Deactivate) ( vlc_object_t * );
00086
00087 static int InitVideo ( vout_thread_t * );
00088 static void EndVideo ( vout_thread_t * );
00089 static void DisplayVideo ( vout_thread_t *, picture_t * );
00090 static int ManageVideo ( vout_thread_t * );
00091 static int Control ( vout_thread_t *, int, va_list );
00092
00093 static int InitDisplay ( vout_thread_t * );
00094
00095 static int CreateWindow ( vout_thread_t *, x11_window_t * );
00096 static void DestroyWindow ( vout_thread_t *, x11_window_t * );
00097
00098 static int NewPicture ( vout_thread_t *, picture_t * );
00099 static void FreePicture ( vout_thread_t *, picture_t * );
00100
00101 static IMAGE_TYPE *CreateImage ( vout_thread_t *,
00102 Display *, EXTRA_ARGS, int, int );
00103 #ifdef HAVE_SYS_SHM_H
00104 static IMAGE_TYPE *CreateShmImage ( vout_thread_t *,
00105 Display *, EXTRA_ARGS_SHM, int, int );
00106 static vlc_bool_t b_shm = VLC_TRUE;
00107 #endif
00108
00109 static void ToggleFullScreen ( vout_thread_t * );
00110
00111 static void EnableXScreenSaver ( vout_thread_t * );
00112 static void DisableXScreenSaver ( vout_thread_t * );
00113
00114 static void CreateCursor ( vout_thread_t * );
00115 static void DestroyCursor ( vout_thread_t * );
00116 static void ToggleCursor ( vout_thread_t * );
00117
00118 #ifdef MODULE_NAME_IS_xvideo
00119 static int XVideoGetPort ( vout_thread_t *, vlc_fourcc_t, vlc_fourcc_t * );
00120 static void XVideoReleasePort( vout_thread_t *, int );
00121 #endif
00122
00123 #ifdef MODULE_NAME_IS_x11
00124 static void SetPalette ( vout_thread_t *,
00125 uint16_t *, uint16_t *, uint16_t * );
00126 #endif
00127
00128 static void TestNetWMSupport( vout_thread_t * );
00129 static int ConvertKey( int );
00130
00131 static int WindowOnTop( vout_thread_t *, vlc_bool_t );
00132
00133 static int X11ErrorHandler( Display *, XErrorEvent * );
00134
00135
00136
00137
00138
00139
00140
00141
00142 int E_(Activate) ( vlc_object_t *p_this )
00143 {
00144 vout_thread_t *p_vout = (vout_thread_t *)p_this;
00145 char * psz_display;
00146 vlc_value_t val;
00147
00148 #ifdef MODULE_NAME_IS_xvideo
00149 char * psz_chroma;
00150 vlc_fourcc_t i_chroma = 0;
00151 vlc_bool_t b_chroma = 0;
00152 #endif
00153
00154 p_vout->pf_init = InitVideo;
00155 p_vout->pf_end = EndVideo;
00156 p_vout->pf_manage = ManageVideo;
00157 p_vout->pf_render = NULL;
00158 p_vout->pf_display = DisplayVideo;
00159 p_vout->pf_control = Control;
00160
00161
00162 p_vout->p_sys = malloc( sizeof( vout_sys_t ) );
00163 if( p_vout->p_sys == NULL )
00164 {
00165 msg_Err( p_vout, "out of memory" );
00166 return VLC_ENOMEM;
00167 }
00168
00169 vlc_mutex_init( p_vout, &p_vout->p_sys->lock );
00170
00171
00172
00173 psz_display = config_GetPsz( p_vout, MODULE_STRING "-display" );
00174
00175 p_vout->p_sys->p_display = XOpenDisplay( psz_display );
00176
00177 if( p_vout->p_sys->p_display == NULL )
00178 {
00179 msg_Err( p_vout, "cannot open display %s",
00180 XDisplayName( psz_display ) );
00181 free( p_vout->p_sys );
00182 if( psz_display ) free( psz_display );
00183 return VLC_EGENERIC;
00184 }
00185 if( psz_display ) free( psz_display );
00186
00187
00188 XSetErrorHandler( X11ErrorHandler );
00189
00190
00191 p_vout->p_sys->i_screen = DefaultScreen( p_vout->p_sys->p_display );
00192
00193 #ifdef MODULE_NAME_IS_xvideo
00194 psz_chroma = config_GetPsz( p_vout, "xvideo-chroma" );
00195 if( psz_chroma )
00196 {
00197 if( strlen( psz_chroma ) >= 4 )
00198 {
00199
00200
00201 memcpy(&i_chroma, psz_chroma, 4);
00202 b_chroma = 1;
00203 }
00204
00205 free( psz_chroma );
00206 }
00207
00208 if( b_chroma )
00209 {
00210 msg_Dbg( p_vout, "forcing chroma 0x%.8x (%4.4s)",
00211 i_chroma, (char*)&i_chroma );
00212 }
00213 else
00214 {
00215 i_chroma = p_vout->render.i_chroma;
00216 }
00217
00218
00219 p_vout->p_sys->i_xvport = XVideoGetPort( p_vout, VLC2X11_FOURCC(i_chroma),
00220 &p_vout->output.i_chroma );
00221 if( p_vout->p_sys->i_xvport < 0 )
00222 {
00223
00224
00225 if( b_chroma )
00226 {
00227 XCloseDisplay( p_vout->p_sys->p_display );
00228 free( p_vout->p_sys );
00229 return VLC_EGENERIC;
00230 }
00231
00232
00233
00234
00235 p_vout->p_sys->i_xvport =
00236 XVideoGetPort( p_vout, X11_FOURCC('Y','U','Y','2'),
00237 &p_vout->output.i_chroma );
00238 if( p_vout->p_sys->i_xvport < 0 )
00239 {
00240
00241
00242
00243 p_vout->p_sys->i_xvport =
00244 XVideoGetPort( p_vout, X11_FOURCC('R','V','1','6'),
00245 &p_vout->output.i_chroma );
00246 if( p_vout->p_sys->i_xvport < 0 )
00247 {
00248 XCloseDisplay( p_vout->p_sys->p_display );
00249 free( p_vout->p_sys );
00250 return VLC_EGENERIC;
00251 }
00252 }
00253 }
00254 p_vout->output.i_chroma = X112VLC_FOURCC(p_vout->output.i_chroma);
00255 #endif
00256
00257
00258 p_vout->p_sys->i_time_mouse_last_moved = mdate();
00259 p_vout->p_sys->b_mouse_pointer_visible = 1;
00260 CreateCursor( p_vout );
00261
00262
00263 p_vout->p_sys->original_window.i_width = p_vout->i_window_width;
00264 p_vout->p_sys->original_window.i_height = p_vout->i_window_height;
00265 var_Create( p_vout, "video-title", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
00266
00267
00268 if( CreateWindow( p_vout, &p_vout->p_sys->original_window ) )
00269 {
00270 msg_Err( p_vout, "cannot create X11 window" );
00271 DestroyCursor( p_vout );
00272 XCloseDisplay( p_vout->p_sys->p_display );
00273 free( p_vout->p_sys );
00274 return VLC_EGENERIC;
00275 }
00276
00277
00278 if( InitDisplay( p_vout ) )
00279 {
00280 msg_Err( p_vout, "cannot initialize X11 display" );
00281 DestroyCursor( p_vout );
00282 DestroyWindow( p_vout, &p_vout->p_sys->original_window );
00283 XCloseDisplay( p_vout->p_sys->p_display );
00284 free( p_vout->p_sys );
00285 return VLC_EGENERIC;
00286 }
00287
00288
00289 DisableXScreenSaver( p_vout );
00290
00291
00292 p_vout->p_sys->b_altfullscreen = 0;
00293 p_vout->p_sys->i_time_button_last_pressed = 0;
00294
00295 TestNetWMSupport( p_vout );
00296
00297
00298
00299 var_Get( p_vout, "video-on-top", &val );
00300 var_Set( p_vout, "video-on-top", val );
00301
00302 return VLC_SUCCESS;
00303 }
00304
00305
00306
00307
00308
00309
00310 void E_(Deactivate) ( vlc_object_t *p_this )
00311 {
00312 vout_thread_t *p_vout = (vout_thread_t *)p_this;
00313
00314
00315 if( p_vout->b_fullscreen )
00316 {
00317 ToggleFullScreen( p_vout );
00318 }
00319
00320
00321 if( !p_vout->p_sys->b_mouse_pointer_visible )
00322 {
00323 ToggleCursor( p_vout );
00324 }
00325
00326 #ifdef MODULE_NAME_IS_x11
00327
00328 if( XDefaultDepth(p_vout->p_sys->p_display, p_vout->p_sys->i_screen) == 8 )
00329 {
00330 XFreeColormap( p_vout->p_sys->p_display, p_vout->p_sys->colormap );
00331 }
00332 #elif defined(MODULE_NAME_IS_xvideo)
00333 XVideoReleasePort( p_vout, p_vout->p_sys->i_xvport );
00334 #endif
00335
00336 DestroyCursor( p_vout );
00337 EnableXScreenSaver( p_vout );
00338 DestroyWindow( p_vout, &p_vout->p_sys->original_window );
00339
00340 XCloseDisplay( p_vout->p_sys->p_display );
00341
00342
00343 vlc_mutex_destroy( &p_vout->p_sys->lock );
00344 free( p_vout->p_sys );
00345 }
00346
00347
00348
00349
00350
00351
00352
00353 static int InitVideo( vout_thread_t *p_vout )
00354 {
00355 int i_index;
00356 picture_t *p_pic;
00357
00358 I_OUTPUTPICTURES = 0;
00359
00360 #ifdef MODULE_NAME_IS_xvideo
00361
00362
00363
00364 p_vout->output.i_width = p_vout->render.i_width;
00365 p_vout->output.i_height = p_vout->render.i_height;
00366 p_vout->output.i_aspect = p_vout->render.i_aspect;
00367
00368 p_vout->fmt_out = p_vout->fmt_in;
00369 p_vout->fmt_out.i_chroma = p_vout->output.i_chroma;
00370
00371 switch( p_vout->output.i_chroma )
00372 {
00373 case VLC_FOURCC('R','V','1','5'):
00374 p_vout->output.i_rmask = 0x001f;
00375 p_vout->output.i_gmask = 0x07e0;
00376 p_vout->output.i_bmask = 0xf800;
00377 break;
00378 case VLC_FOURCC('R','V','1','6'):
00379 p_vout->output.i_rmask = 0x001f;
00380 p_vout->output.i_gmask = 0x03e0;
00381 p_vout->output.i_bmask = 0x7c00;
00382 break;
00383 }
00384
00385 #elif defined(MODULE_NAME_IS_x11)
00386
00387
00388 switch( p_vout->p_sys->i_screen_depth )
00389 {
00390 case 8:
00391 p_vout->output.i_chroma = VLC_FOURCC('R','G','B','2'); break;
00392 case 15:
00393 p_vout->output.i_chroma = VLC_FOURCC('R','V','1','5'); break;
00394 case 16:
00395 p_vout->output.i_chroma = VLC_FOURCC('R','V','1','6'); break;
00396 case 24:
00397 case 32:
00398 p_vout->output.i_chroma = VLC_FOURCC('R','V','3','2'); break;
00399 default:
00400 msg_Err( p_vout, "unknown screen depth %i",
00401 p_vout->p_sys->i_screen_depth );
00402 return VLC_SUCCESS;
00403 }
00404
00405 vout_PlacePicture( p_vout, p_vout->p_sys->p_win->i_width,
00406 p_vout->p_sys->p_win->i_height,
00407 &i_index, &i_index,
00408 &p_vout->fmt_out.i_visible_width,
00409 &p_vout->fmt_out.i_visible_height );
00410
00411 p_vout->fmt_out.i_chroma = p_vout->output.i_chroma;
00412
00413 p_vout->output.i_width = p_vout->fmt_out.i_width =
00414 p_vout->fmt_out.i_visible_width * p_vout->fmt_in.i_width /
00415 p_vout->fmt_in.i_visible_width;
00416 p_vout->output.i_height = p_vout->fmt_out.i_height =
00417 p_vout->fmt_out.i_visible_height * p_vout->fmt_in.i_height /
00418 p_vout->fmt_in.i_visible_height;
00419 p_vout->fmt_out.i_x_offset =
00420 p_vout->fmt_out.i_visible_width * p_vout->fmt_in.i_x_offset /
00421 p_vout->fmt_in.i_visible_width;
00422 p_vout->fmt_out.i_y_offset =
00423 p_vout->fmt_out.i_visible_height * p_vout->fmt_in.i_y_offset /
00424 p_vout->fmt_in.i_visible_height;
00425
00426 p_vout->fmt_out.i_sar_num = p_vout->fmt_out.i_sar_den = 1;
00427 p_vout->output.i_aspect = p_vout->fmt_out.i_aspect =
00428 p_vout->fmt_out.i_width * VOUT_ASPECT_FACTOR /p_vout->fmt_out.i_height;
00429
00430 msg_Dbg( p_vout, "x11 image size %ix%i (%i,%i,%ix%i)",
00431 p_vout->fmt_out.i_width, p_vout->fmt_out.i_height,
00432 p_vout->fmt_out.i_x_offset, p_vout->fmt_out.i_y_offset,
00433 p_vout->fmt_out.i_visible_width,
00434 p_vout->fmt_out.i_visible_height );
00435 #endif
00436
00437
00438 while( I_OUTPUTPICTURES < MAX_DIRECTBUFFERS )
00439 {
00440 p_pic = NULL;
00441
00442
00443 for( i_index = 0 ; i_index < VOUT_MAX_PICTURES ; i_index++ )
00444 {
00445 if( p_vout->p_picture[ i_index ].i_status == FREE_PICTURE )
00446 {
00447 p_pic = p_vout->p_picture + i_index;
00448 break;
00449 }
00450 }
00451
00452
00453 if( p_pic == NULL || NewPicture( p_vout, p_pic ) )
00454 {
00455 break;
00456 }
00457
00458 p_pic->i_status = DESTROYED_PICTURE;
00459 p_pic->i_type = DIRECT_PICTURE;
00460
00461 PP_OUTPUTPICTURE[ I_OUTPUTPICTURES ] = p_pic;
00462
00463 I_OUTPUTPICTURES++;
00464 }
00465
00466 if( p_vout->output.i_chroma == VLC_FOURCC('Y','V','1','2') )
00467 {
00468
00469
00470 p_vout->output.i_chroma = VLC_FOURCC('I','4','2','0');
00471 p_vout->fmt_out.i_chroma = VLC_FOURCC('I','4','2','0');
00472 }
00473
00474 return VLC_SUCCESS;
00475 }
00476
00477
00478
00479
00480
00481
00482
00483 static void DisplayVideo( vout_thread_t *p_vout, picture_t *p_pic )
00484 {
00485 int i_width, i_height, i_x, i_y;
00486
00487 vout_PlacePicture( p_vout, p_vout->p_sys->p_win->i_width,
00488 p_vout->p_sys->p_win->i_height,
00489 &i_x, &i_y, &i_width, &i_height );
00490
00491 vlc_mutex_lock( &p_vout->p_sys->lock );
00492
00493 #ifdef HAVE_SYS_SHM_H
00494 if( p_vout->p_sys->b_shm )
00495 {
00496
00497 # ifdef MODULE_NAME_IS_xvideo
00498 XvShmPutImage( p_vout->p_sys->p_display, p_vout->p_sys->i_xvport,
00499 p_vout->p_sys->p_win->video_window,
00500 p_vout->p_sys->p_win->gc, p_pic->p_sys->p_image,
00501 p_vout->fmt_out.i_x_offset,
00502 p_vout->fmt_out.i_y_offset,
00503 p_vout->fmt_out.i_visible_width,
00504 p_vout->fmt_out.i_visible_height,
00505 0 , 0 , i_width, i_height,
00506 False );
00507 # else
00508 XShmPutImage( p_vout->p_sys->p_display,
00509 p_vout->p_sys->p_win->video_window,
00510 p_vout->p_sys->p_win->gc, p_pic->p_sys->p_image,
00511 p_vout->fmt_out.i_x_offset,
00512 p_vout->fmt_out.i_y_offset,
00513 0 , 0 ,
00514 p_vout->fmt_out.i_visible_width,
00515 p_vout->fmt_out.i_visible_height,
00516 False );
00517 # endif
00518 }
00519 else
00520 #endif
00521 {
00522
00523 #ifdef MODULE_NAME_IS_xvideo
00524 XvPutImage( p_vout->p_sys->p_display, p_vout->p_sys->i_xvport,
00525 p_vout->p_sys->p_win->video_window,
00526 p_vout->p_sys->p_win->gc, p_pic->p_sys->p_image,
00527 p_vout->fmt_out.i_x_offset,
00528 p_vout->fmt_out.i_y_offset,
00529 p_vout->fmt_out.i_visible_width,
00530 p_vout->fmt_out.i_visible_height,
00531 0 , 0 , i_width, i_height );
00532 #else
00533 XPutImage( p_vout->p_sys->p_display,
00534 p_vout->p_sys->p_win->video_window,
00535 p_vout->p_sys->p_win->gc, p_pic->p_sys->p_image,
00536 p_vout->fmt_out.i_x_offset,
00537 p_vout->fmt_out.i_y_offset,
00538 0 , 0 ,
00539 p_vout->fmt_out.i_visible_width,
00540 p_vout->fmt_out.i_visible_height );
00541 #endif
00542 }
00543
00544
00545 XSync( p_vout->p_sys->p_display, False );
00546
00547 vlc_mutex_unlock( &p_vout->p_sys->lock );
00548 }
00549
00550
00551
00552
00553
00554
00555
00556
00557 static int ManageVideo( vout_thread_t *p_vout )
00558 {
00559 XEvent xevent;
00560 vlc_value_t val;
00561
00562 vlc_mutex_lock( &p_vout->p_sys->lock );
00563
00564
00565 if( p_vout->p_sys->p_win->owner_window )
00566 {
00567 while( XCheckWindowEvent( p_vout->p_sys->p_display,
00568 p_vout->p_sys->p_win->owner_window,
00569 StructureNotifyMask, &xevent ) == True )
00570 {
00571
00572 if( xevent.type == ConfigureNotify )
00573 {
00574
00575 XResizeWindow( p_vout->p_sys->p_display,
00576 p_vout->p_sys->p_win->base_window,
00577 xevent.xconfigure.width,
00578 xevent.xconfigure.height );
00579 }
00580 }
00581 }
00582
00583
00584
00585
00586
00587
00588 while( XCheckWindowEvent( p_vout->p_sys->p_display,
00589 p_vout->p_sys->p_win->base_window,
00590 StructureNotifyMask | KeyPressMask |
00591 ButtonPressMask | ButtonReleaseMask |
00592 PointerMotionMask | Button1MotionMask , &xevent )
00593 == True )
00594 {
00595
00596 if( xevent.type == ConfigureNotify )
00597 {
00598 if( (unsigned int)xevent.xconfigure.width
00599 != p_vout->p_sys->p_win->i_width
00600 || (unsigned int)xevent.xconfigure.height
00601 != p_vout->p_sys->p_win->i_height )
00602 {
00603
00604 p_vout->i_changes |= VOUT_SIZE_CHANGE;
00605 p_vout->p_sys->p_win->i_width = xevent.xconfigure.width;
00606 p_vout->p_sys->p_win->i_height = xevent.xconfigure.height;
00607 }
00608 }
00609
00610 else if( xevent.type == KeyPress )
00611 {
00612 unsigned int state = xevent.xkey.state;
00613 KeySym x_key_symbol;
00614 char i_key;
00615
00616
00617 x_key_symbol = XKeycodeToKeysym( p_vout->p_sys->p_display,
00618 xevent.xkey.keycode, 0 );
00619 val.i_int = ConvertKey( (int)x_key_symbol );
00620
00621 xevent.xkey.state &= ~ShiftMask;
00622 xevent.xkey.state &= ~ControlMask;
00623 xevent.xkey.state &= ~Mod1Mask;
00624
00625 if( !val.i_int &&
00626 XLookupString( &xevent.xkey, &i_key, 1, NULL, NULL ) )
00627 {
00628
00629
00630
00631
00632 val.i_int = i_key;
00633 }
00634
00635 if( val.i_int )
00636 {
00637 if( state & ShiftMask )
00638 {
00639 val.i_int |= KEY_MODIFIER_SHIFT;
00640 }
00641 if( state & ControlMask )
00642 {
00643 val.i_int |= KEY_MODIFIER_CTRL;
00644 }
00645 if( state & Mod1Mask )
00646 {
00647 val.i_int |= KEY_MODIFIER_ALT;
00648 }
00649 var_Set( p_vout->p_vlc, "key-pressed", val );
00650 }
00651 }
00652
00653 else if( xevent.type == ButtonPress )
00654 {
00655 switch( ((XButtonEvent *)&xevent)->button )
00656 {
00657 case Button1:
00658 var_Get( p_vout, "mouse-button-down", &val );
00659 val.i_int |= 1;
00660 var_Set( p_vout, "mouse-button-down", val );
00661
00662
00663 if( ( ((XButtonEvent *)&xevent)->time -
00664 p_vout->p_sys->i_time_button_last_pressed ) < 300 )
00665 {
00666 p_vout->i_changes |= VOUT_FULLSCREEN_CHANGE;
00667 }
00668
00669 p_vout->p_sys->i_time_button_last_pressed =
00670 ((XButtonEvent *)&xevent)->time;
00671 break;
00672 case Button2:
00673 var_Get( p_vout, "mouse-button-down", &val );
00674 val.i_int |= 2;
00675 var_Set( p_vout, "mouse-button-down", val );
00676 break;
00677
00678 case Button3:
00679 var_Get( p_vout, "mouse-button-down", &val );
00680 val.i_int |= 4;
00681 var_Set( p_vout, "mouse-button-down", val );
00682 break;
00683
00684 case Button4:
00685 var_Get( p_vout, "mouse-button-down", &val );
00686 val.i_int |= 8;
00687 var_Set( p_vout, "mouse-button-down", val );
00688 break;
00689
00690 case Button5:
00691 var_Get( p_vout, "mouse-button-down", &val );
00692 val.i_int |= 16;
00693 var_Set( p_vout, "mouse-button-down", val );
00694 break;
00695 }
00696 }
00697
00698 else if( xevent.type == ButtonRelease )
00699 {
00700 switch( ((XButtonEvent *)&xevent)->button )
00701 {
00702 case Button1:
00703 var_Get( p_vout, "mouse-button-down", &val );
00704 val.i_int &= ~1;
00705 var_Set( p_vout, "mouse-button-down", val );
00706
00707 val.b_bool = VLC_TRUE;
00708 var_Set( p_vout, "mouse-clicked", val );
00709 break;
00710
00711 case Button2:
00712 {
00713 playlist_t *p_playlist;
00714
00715 var_Get( p_vout, "mouse-button-down", &val );
00716 val.i_int &= ~2;
00717 var_Set( p_vout, "mouse-button-down", val );
00718
00719 p_playlist = vlc_object_find( p_vout,
00720 VLC_OBJECT_PLAYLIST,
00721 FIND_ANYWHERE );
00722 if( p_playlist != NULL )
00723 {
00724 vlc_value_t val;
00725 var_Get( p_playlist, "intf-show", &val );
00726 val.b_bool = !val.b_bool;
00727 var_Set( p_playlist, "intf-show", val );
00728 vlc_object_release( p_playlist );
00729 }
00730 }
00731 break;
00732
00733 case Button3:
00734 {
00735 intf_thread_t *p_intf;
00736 playlist_t *p_playlist;
00737
00738 var_Get( p_vout, "mouse-button-down", &val );
00739 val.i_int &= ~4;
00740 var_Set( p_vout, "mouse-button-down", val );
00741 p_intf = vlc_object_find( p_vout, VLC_OBJECT_INTF,
00742 FIND_ANYWHERE );
00743 if( p_intf )
00744 {
00745 p_intf->b_menu_change = 1;
00746 vlc_object_release( p_intf );
00747 }
00748
00749 p_playlist = vlc_object_find( p_vout,
00750 VLC_OBJECT_PLAYLIST,
00751 FIND_ANYWHERE );
00752 if( p_playlist != NULL )
00753 {
00754 vlc_value_t val; val.b_bool = VLC_TRUE;
00755 var_Set( p_playlist, "intf-popupmenu", val );
00756 vlc_object_release( p_playlist );
00757 }
00758 }
00759 break;
00760
00761 case Button4:
00762 var_Get( p_vout, "mouse-button-down", &val );
00763 val.i_int &= ~8;
00764 var_Set( p_vout, "mouse-button-down", val );
00765 break;
00766
00767 case Button5:
00768 var_Get( p_vout, "mouse-button-down", &val );
00769 val.i_int &= ~16;
00770 var_Set( p_vout, "mouse-button-down", val );
00771 break;
00772
00773 }
00774 }
00775
00776 else if( xevent.type == MotionNotify )
00777 {
00778 int i_width, i_height, i_x, i_y;
00779 vlc_value_t val;
00780
00781
00782
00783
00784 vout_PlacePicture( p_vout, p_vout->p_sys->p_win->i_width,
00785 p_vout->p_sys->p_win->i_height,
00786 &i_x, &i_y, &i_width, &i_height );
00787
00788 val.i_int = ( xevent.xmotion.x - i_x ) *
00789 p_vout->fmt_in.i_visible_width / i_width +
00790 p_vout->fmt_in.i_x_offset;
00791 var_Set( p_vout, "mouse-x", val );
00792 val.i_int = ( xevent.xmotion.y - i_y ) *
00793 p_vout->fmt_in.i_visible_height / i_height +
00794 p_vout->fmt_in.i_y_offset;
00795 var_Set( p_vout, "mouse-y", val );
00796
00797 val.b_bool = VLC_TRUE;
00798 var_Set( p_vout, "mouse-moved", val );
00799
00800 p_vout->p_sys->i_time_mouse_last_moved = mdate();
00801 if( ! p_vout->p_sys->b_mouse_pointer_visible )
00802 {
00803 ToggleCursor( p_vout );
00804 }
00805 }
00806 else if( xevent.type == ReparentNotify
00807 || xevent.type == MapNotify
00808 || xevent.type == UnmapNotify )
00809 {
00810
00811 }
00812 else
00813 {
00814 msg_Warn( p_vout, "unhandled event %d received", xevent.type );
00815 }
00816 }
00817
00818
00819 while( XCheckWindowEvent( p_vout->p_sys->p_display,
00820 p_vout->p_sys->p_win->video_window,
00821 ExposureMask, &xevent ) == True )
00822 {
00823
00824 if( xevent.type == Expose )
00825 {
00826 if( ((XExposeEvent *)&xevent)->count == 0 )
00827 {
00828
00829 #if 0
00830 if( p_vout->p_vlc->p_input_bank->pp_input[0] != NULL )
00831 {
00832 if( PAUSE_S == p_vout->p_vlc->p_input_bank->pp_input[0]
00833 ->stream.control.i_status )
00834 {
00835 ;
00836 }
00837 }
00838 #endif
00839 }
00840 }
00841 }
00842
00843
00844
00845
00846 while( XCheckTypedEvent( p_vout->p_sys->p_display,
00847 ClientMessage, &xevent ) )
00848 {
00849 if( (xevent.xclient.message_type == p_vout->p_sys->p_win->wm_protocols)
00850 && ((Atom)xevent.xclient.data.l[0]
00851 == p_vout->p_sys->p_win->wm_delete_window ) )
00852 {
00853
00854 playlist_t * p_playlist =
00855 (playlist_t *)vlc_object_find( p_vout, VLC_OBJECT_PLAYLIST,
00856 FIND_ANYWHERE );
00857 if( p_playlist != NULL )
00858 {
00859 playlist_Stop( p_playlist );
00860 vlc_object_release( p_playlist );
00861 }
00862 }
00863 }
00864
00865
00866
00867
00868 if ( p_vout->i_changes & VOUT_FULLSCREEN_CHANGE )
00869 {
00870 vlc_value_t val;
00871
00872
00873 val.b_bool = !p_vout->b_fullscreen;
00874 var_Set( p_vout, "fullscreen", val );
00875
00876 ToggleFullScreen( p_vout );
00877 p_vout->i_changes &= ~VOUT_FULLSCREEN_CHANGE;
00878 }
00879
00880 if( p_vout->i_changes & VOUT_CROP_CHANGE ||
00881 p_vout->i_changes & VOUT_ASPECT_CHANGE )
00882 {
00883 p_vout->i_changes &= ~VOUT_CROP_CHANGE;
00884 p_vout->i_changes &= ~VOUT_ASPECT_CHANGE;
00885
00886 p_vout->fmt_out.i_x_offset = p_vout->fmt_in.i_x_offset;
00887 p_vout->fmt_out.i_y_offset = p_vout->fmt_in.i_y_offset;
00888 p_vout->fmt_out.i_visible_width = p_vout->fmt_in.i_visible_width;
00889 p_vout->fmt_out.i_visible_height = p_vout->fmt_in.i_visible_height;
00890 p_vout->fmt_out.i_aspect = p_vout->fmt_in.i_aspect;
00891 p_vout->fmt_out.i_sar_num = p_vout->fmt_in.i_sar_num;
00892 p_vout->fmt_out.i_sar_den = p_vout->fmt_in.i_sar_den;
00893 p_vout->output.i_aspect = p_vout->fmt_in.i_aspect;
00894
00895 p_vout->i_changes |= VOUT_SIZE_CHANGE;
00896 }
00897
00898
00899
00900
00901
00902
00903
00904 if( p_vout->i_changes & VOUT_SIZE_CHANGE )
00905 {
00906 int i_width, i_height, i_x, i_y;
00907
00908 p_vout->i_changes &= ~VOUT_SIZE_CHANGE;
00909
00910 #ifdef MODULE_NAME_IS_x11
00911
00912
00913 p_vout->i_changes |= VOUT_SIZE_CHANGE;
00914 #endif
00915
00916 vout_PlacePicture( p_vout, p_vout->p_sys->p_win->i_width,
00917 p_vout->p_sys->p_win->i_height,
00918 &i_x, &i_y, &i_width, &i_height );
00919
00920 XMoveResizeWindow( p_vout->p_sys->p_display,
00921 p_vout->p_sys->p_win->video_window,
00922 i_x, i_y, i_width, i_height );
00923 }
00924
00925
00926 if( mdate() - p_vout->p_sys->i_time_mouse_last_moved > 2000000 )
00927 {
00928
00929 if( p_vout->p_sys->b_mouse_pointer_visible )
00930 {
00931 ToggleCursor( p_vout );
00932 }
00933 }
00934
00935 vlc_mutex_unlock( &p_vout->p_sys->lock );
00936
00937 return 0;
00938 }
00939
00940
00941
00942
00943
00944
00945
00946 static void EndVideo( vout_thread_t *p_vout )
00947 {
00948 int i_index;
00949
00950
00951 for( i_index = I_OUTPUTPICTURES ; i_index ; )
00952 {
00953 i_index--;
00954 FreePicture( p_vout, PP_OUTPUTPICTURE[ i_index ] );
00955 }
00956 }
00957
00958
00959
00960
00961
00962
00963 static int CreateWindow( vout_thread_t *p_vout, x11_window_t *p_win )
00964 {
00965 XSizeHints xsize_hints;
00966 XSetWindowAttributes xwindow_attributes;
00967 XGCValues xgcvalues;
00968 XEvent xevent;
00969
00970 vlc_bool_t b_expose = VLC_FALSE;
00971 vlc_bool_t b_configure_notify = VLC_FALSE;
00972 vlc_bool_t b_map_notify = VLC_FALSE;
00973 vlc_value_t val;
00974
00975
00976 p_win->wm_protocols =
00977 XInternAtom( p_vout->p_sys->p_display, "WM_PROTOCOLS", True );
00978 p_win->wm_delete_window =
00979 XInternAtom( p_vout->p_sys->p_display, "WM_DELETE_WINDOW", True );
00980
00981
00982 xsize_hints.min_width = 2;
00983 xsize_hints.min_height = 1;
00984
00985
00986 xwindow_attributes.backing_store = Always;
00987 xwindow_attributes.background_pixel = BlackPixel(p_vout->p_sys->p_display,
00988 p_vout->p_sys->i_screen);
00989 xwindow_attributes.event_mask = ExposureMask | StructureNotifyMask;
00990
00991 if( !p_vout->b_fullscreen )
00992 {
00993 p_win->owner_window =
00994 (Window)vout_RequestWindow( p_vout, &p_win->i_x, &p_win->i_y,
00995 &p_win->i_width, &p_win->i_height );
00996
00997 xsize_hints.base_width = xsize_hints.width = p_win->i_width;
00998 xsize_hints.base_height = xsize_hints.height = p_win->i_height;
00999 xsize_hints.flags = PSize | PMinSize;
01000
01001 if( p_win->i_x >=0 || p_win->i_y >= 0 )
01002 {
01003 xsize_hints.x = p_win->i_x;
01004 xsize_hints.y = p_win->i_y;
01005 xsize_hints.flags |= PPosition;
01006 }
01007 }
01008 else
01009 {
01010
01011 p_win->owner_window = 0;
01012 p_win->i_x = p_win->i_y = 0;
01013 p_win->i_width =
01014 DisplayWidth( p_vout->p_sys->p_display, p_vout->p_sys->i_screen );
01015 p_win->i_height =
01016 DisplayHeight( p_vout->p_sys->p_display, p_vout->p_sys->i_screen );
01017 }
01018
01019 if( !p_win->owner_window )
01020 {
01021
01022
01023
01024
01025 p_win->base_window =
01026 XCreateWindow( p_vout->p_sys->p_display,
01027 DefaultRootWindow( p_vout->p_sys->p_display ),
01028 p_win->i_x, p_win->i_y,
01029 p_win->i_width, p_win->i_height,
01030 0,
01031 0, InputOutput, 0,
01032 CWBackingStore | CWBackPixel | CWEventMask,
01033 &xwindow_attributes );
01034
01035 if( !p_vout->b_fullscreen )
01036 {
01037
01038
01039 XSetWMNormalHints( p_vout->p_sys->p_display,
01040 p_win->base_window, &xsize_hints );
01041 XSetCommand( p_vout->p_sys->p_display, p_win->base_window,
01042 p_vout->p_vlc->ppsz_argv, p_vout->p_vlc->i_argc );
01043
01044 if( !var_GetBool( p_vout, "video-deco") )
01045 {
01046 Atom prop;
01047 mwmhints_t mwmhints;
01048
01049 mwmhints.flags = MWM_HINTS_DECORATIONS;
01050 mwmhints.decorations = False;
01051
01052 prop = XInternAtom( p_vout->p_sys->p_display, "_MOTIF_WM_HINTS",
01053 False );
01054
01055 XChangeProperty( p_vout->p_sys->p_display,
01056 p_win->base_window,
01057 prop, prop, 32, PropModeReplace,
01058 (unsigned char *)&mwmhints,
01059 PROP_MWM_HINTS_ELEMENTS );
01060 }
01061 else
01062 {
01063 var_Get( p_vout, "video-title", &val );
01064 if( !val.psz_string || !*val.psz_string )
01065 {
01066 XStoreName( p_vout->p_sys->p_display, p_win->base_window,
01067 #ifdef MODULE_NAME_IS_x11
01068 VOUT_TITLE " (X11 output)"
01069 #elif defined(MODULE_NAME_IS_glx)
01070 VOUT_TITLE " (GLX output)"
01071 #else
01072 VOUT_TITLE " (XVideo output)"
01073 #endif
01074 );
01075 }
01076 else
01077 {
01078 XStoreName( p_vout->p_sys->p_display,
01079 p_win->base_window, val.psz_string );
01080 }
01081 }
01082 }
01083 }
01084 else
01085 {
01086 Window dummy1;
01087 unsigned int dummy2, dummy3;
01088
01089
01090 XSelectInput( p_vout->p_sys->p_display, p_win->owner_window,
01091 StructureNotifyMask );
01092
01093
01094 XGetGeometry( p_vout->p_sys->p_display, p_win->owner_window,
01095 &dummy1, &dummy2, &dummy3,
01096 &p_win->i_width,
01097 &p_win->i_height,
01098 &dummy2, &dummy3 );
01099
01100
01101 b_configure_notify = VLC_TRUE;
01102
01103
01104
01105 p_win->base_window =
01106 XCreateWindow( p_vout->p_sys->p_display,
01107 p_win->owner_window,
01108 0, 0,
01109 p_win->i_width, p_win->i_height,
01110 0,
01111 0, CopyFromParent, 0,
01112 CWBackingStore | CWBackPixel | CWEventMask,
01113 &xwindow_attributes );
01114 }
01115
01116 if( (p_win->wm_protocols == None)
01117 || (p_win->wm_delete_window == None)
01118 || !XSetWMProtocols( p_vout->p_sys->p_display, p_win->base_window,
01119 &p_win->wm_delete_window, 1 ) )
01120 {
01121
01122 msg_Warn( p_vout, "missing or bad window manager" );
01123 }
01124
01125
01126
01127 xgcvalues.graphics_exposures = False;
01128 p_win->gc = XCreateGC( p_vout->p_sys->p_display,
01129 p_win->base_window,
01130 GCGraphicsExposures, &xgcvalues );
01131
01132
01133
01134
01135
01136
01137 XMapWindow( p_vout->p_sys->p_display, p_win->base_window );
01138 do
01139 {
01140 XWindowEvent( p_vout->p_sys->p_display, p_win->base_window,
01141 SubstructureNotifyMask | StructureNotifyMask |
01142 ExposureMask, &xevent);
01143 if( (xevent.type == Expose)
01144 && (xevent.xexpose.window == p_win->base_window) )
01145 {
01146 b_expose = VLC_TRUE;
01147
01148
01149
01150 b_configure_notify = VLC_TRUE;
01151 }
01152 else if( (xevent.type == MapNotify)
01153 && (xevent.xmap.window == p_win->base_window) )
01154 {
01155 b_map_notify = VLC_TRUE;
01156 }
01157 else if( (xevent.type == ConfigureNotify)
01158 && (xevent.xconfigure.window == p_win->base_window) )
01159 {
01160 b_configure_notify = VLC_TRUE;
01161 p_win->i_width = xevent.xconfigure.width;
01162 p_win->i_height = xevent.xconfigure.height;
01163 }
01164 } while( !( b_expose && b_configure_notify && b_map_notify ) );
01165
01166 XSelectInput( p_vout->p_sys->p_display, p_win->base_window,
01167 StructureNotifyMask | KeyPressMask |
01168 ButtonPressMask | ButtonReleaseMask |
01169 PointerMotionMask );
01170
01171 #ifdef MODULE_NAME_IS_x11
01172 if( XDefaultDepth(p_vout->p_sys->p_display, p_vout->p_sys->i_screen) == 8 )
01173 {
01174
01175 p_vout->p_sys->colormap =
01176 XCreateColormap( p_vout->p_sys->p_display,
01177 DefaultRootWindow( p_vout->p_sys->p_display ),
01178 DefaultVisual( p_vout->p_sys->p_display,
01179 p_vout->p_sys->i_screen ),
01180 AllocAll );
01181
01182 xwindow_attributes.colormap = p_vout->p_sys->colormap;
01183 XChangeWindowAttributes( p_vout->p_sys->p_display, p_win->base_window,
01184 CWColormap, &xwindow_attributes );
01185 }
01186 #endif
01187
01188
01189 p_win->video_window = XCreateSimpleWindow(
01190 p_vout->p_sys->p_display,
01191 p_win->base_window, 0, 0,
01192 p_win->i_width, p_win->i_height,
01193 0,
01194 BlackPixel( p_vout->p_sys->p_display,
01195 p_vout->p_sys->i_screen ),
01196 WhitePixel( p_vout->p_sys->p_display,
01197 p_vout->p_sys->i_screen ) );
01198
01199 XSetWindowBackground( p_vout->p_sys->p_display, p_win->video_window,
01200 BlackPixel( p_vout->p_sys->p_display,
01201 p_vout->p_sys->i_screen ) );
01202
01203 XMapWindow( p_vout->p_sys->p_display, p_win->video_window );
01204 XSelectInput( p_vout->p_sys->p_display, p_win->video_window,
01205 ExposureMask );
01206
01207
01208 p_vout->i_changes |= VOUT_SIZE_CHANGE;
01209
01210
01211 if( !p_vout->p_sys->b_mouse_pointer_visible )
01212 {
01213 ToggleCursor( p_vout );
01214 ToggleCursor( p_vout );
01215 }
01216
01217
01218 XSync( p_vout->p_sys->p_display, False );
01219
01220
01221
01222 p_vout->p_sys->p_win = p_win;
01223
01224 return VLC_SUCCESS;
01225 }
01226
01227
01228
01229
01230
01231
01232 static void DestroyWindow( vout_thread_t *p_vout, x11_window_t *p_win )
01233 {
01234
01235 XSync( p_vout->p_sys->p_display, False );
01236
01237 if( p_win->video_window != None )
01238 XDestroyWindow( p_vout->p_sys->p_display, p_win->video_window );
01239
01240 XFreeGC( p_vout->p_sys->p_display, p_win->gc );
01241
01242 XUnmapWindow( p_vout->p_sys->p_display, p_win->base_window );
01243 XDestroyWindow( p_vout->p_sys->p_display, p_win->base_window );
01244
01245 if( p_win->owner_window )
01246 vout_ReleaseWindow( p_vout, (void *)p_win->owner_window );
01247 }
01248
01249
01250
01251
01252
01253
01254 static int NewPicture( vout_thread_t *p_vout, picture_t *p_pic )
01255 {
01256 #ifndef MODULE_NAME_IS_glx
01257
01258 #ifdef MODULE_NAME_IS_xvideo
01259 int i_plane;
01260 #endif
01261
01262
01263
01264 p_pic->p_sys = malloc( sizeof( picture_sys_t ) );
01265
01266 if( p_pic->p_sys == NULL )
01267 {
01268 return -1;
01269 }
01270
01271
01272 vout_InitPicture( VLC_OBJECT(p_vout), p_pic, p_vout->output.i_chroma,
01273 p_vout->output.i_width, p_vout->output.i_height,
01274 p_vout->output.i_aspect );
01275
01276 #ifdef HAVE_SYS_SHM_H
01277 if( p_vout->p_sys->b_shm )
01278 {
01279
01280 p_pic->p_sys->p_image =
01281 CreateShmImage( p_vout, p_vout->p_sys->p_display,
01282 # ifdef MODULE_NAME_IS_xvideo
01283 p_vout->p_sys->i_xvport,
01284 VLC2X11_FOURCC(p_vout->output.i_chroma),
01285 # else
01286 p_vout->p_sys->p_visual,
01287 p_vout->p_sys->i_screen_depth,
01288 # endif
01289 &p_pic->p_sys->shminfo,
01290 p_vout->output.i_width, p_vout->output.i_height );
01291 }
01292
01293 if( !p_vout->p_sys->b_shm || !p_pic->p_sys->p_image )
01294 #endif
01295 {
01296
01297 p_pic->p_sys->p_image =
01298 CreateImage( p_vout, p_vout->p_sys->p_display,
01299 #ifdef MODULE_NAME_IS_xvideo
01300 p_vout->p_sys->i_xvport,
01301 VLC2X11_FOURCC(p_vout->output.i_chroma),
01302 p_pic->format.i_bits_per_pixel,
01303 #else
01304 p_vout->p_sys->p_visual,
01305 p_vout->p_sys->i_screen_depth,
01306 p_vout->p_sys->i_bytes_per_pixel,
01307 #endif
01308 p_vout->output.i_width, p_vout->output.i_height );
01309
01310 #ifdef HAVE_SYS_SHM_H
01311 if( p_pic->p_sys->p_image && p_vout->p_sys->b_shm )
01312 {
01313 msg_Warn( p_vout, "couldn't create SHM image, disabling SHM." );
01314 p_vout->p_sys->b_shm = VLC_FALSE;
01315 }
01316 #endif
01317 }
01318
01319 if( p_pic->p_sys->p_image == NULL )
01320 {
01321 free( p_pic->p_sys );
01322 return -1;
01323 }
01324
01325 switch( p_vout->output.i_chroma )
01326 {
01327 #ifdef MODULE_NAME_IS_xvideo
01328 case VLC_FOURCC('I','4','2','0'):
01329 case VLC_FOURCC('Y','V','1','2'):
01330 case VLC_FOURCC('Y','2','1','1'):
01331 case VLC_FOURCC('Y','U','Y','2'):
01332 case VLC_FOURCC('U','Y','V','Y'):
01333 case VLC_FOURCC('R','V','1','5'):
01334 case VLC_FOURCC('R','V','1','6'):
01335 case VLC_FOURCC('R','V','2','4'):
01336 case VLC_FOURCC('R','V','3','2'):
01337
01338 for( i_plane = 0; i_plane < p_pic->p_sys->p_image->num_planes;
01339 i_plane++ )
01340 {
01341 p_pic->p[i_plane].p_pixels = p_pic->p_sys->p_image->data
01342 + p_pic->p_sys->p_image->offsets[i_plane];
01343 p_pic->p[i_plane].i_pitch =
01344 p_pic->p_sys->p_image->pitches[i_plane];
01345 }
01346 if( p_vout->output.i_chroma == VLC_FOURCC('Y','V','1','2') )
01347 {
01348
01349
01350 p_pic->U_PIXELS = p_pic->p_sys->p_image->data
01351 + p_pic->p_sys->p_image->offsets[2];
01352 p_pic->V_PIXELS = p_pic->p_sys->p_image->data
01353 + p_pic->p_sys->p_image->offsets[1];
01354 }
01355 break;
01356
01357 #else
01358 case VLC_FOURCC('R','G','B','2'):
01359 case VLC_FOURCC('R','V','1','6'):
01360 case VLC_FOURCC('R','V','1','5'):
01361 case VLC_FOURCC('R','V','2','4'):
01362 case VLC_FOURCC('R','V','3','2'):
01363
01364 p_pic->p->i_lines = p_pic->p_sys->p_image->height;
01365 p_pic->p->i_visible_lines = p_pic->p_sys->p_image->height;
01366 p_pic->p->p_pixels = p_pic->p_sys->p_image->data
01367 + p_pic->p_sys->p_image->xoffset;
01368 p_pic->p->i_pitch = p_pic->p_sys->p_image->bytes_per_line;
01369
01370
01371
01372 p_pic->p->i_visible_pitch = p_pic->p->i_pixel_pitch
01373 * p_pic->p_sys->p_image->width;
01374 break;
01375 #endif
01376
01377 default:
01378
01379 IMAGE_FREE( p_pic->p_sys->p_image );
01380 free( p_pic->p_sys );
01381 msg_Err( p_vout, "never heard of chroma 0x%.8x (%4.4s)",
01382 p_vout->output.i_chroma, (char*)&p_vout->output.i_chroma );
01383 p_pic->i_planes = 0;
01384 return -1;
01385 }
01386
01387 #endif
01388
01389 return 0;
01390 }
01391
01392
01393
01394
01395
01396
01397
01398
01399
01400 static void FreePicture( vout_thread_t *p_vout, picture_t *p_pic )
01401 {
01402
01403 #ifdef HAVE_SYS_SHM_H
01404 if( p_vout->p_sys->b_shm )
01405 {
01406 XShmDetach( p_vout->p_sys->p_display, &p_pic->p_sys->shminfo );
01407 IMAGE_FREE( p_pic->p_sys->p_image );
01408
01409 shmctl( p_pic->p_sys->shminfo.shmid, IPC_RMID, 0 );
01410 if( shmdt( p_pic->p_sys->shminfo.shmaddr ) )
01411 {
01412 msg_Err( p_vout, "cannot detach shared memory (%s)",
01413 strerror(errno) );
01414 }
01415 }
01416 else
01417 #endif
01418 {
01419 IMAGE_FREE( p_pic->p_sys->p_image );
01420 }
01421
01422
01423 XSync( p_vout->p_sys->p_display, False );
01424
01425 free( p_pic->p_sys );
01426 }
01427
01428
01429
01430
01431
01432
01433 static void ToggleFullScreen ( vout_thread_t *p_vout )
01434 {
01435 Atom prop;
01436 XEvent xevent;
01437 mwmhints_t mwmhints;
01438 XSetWindowAttributes attributes;
01439
01440 #ifdef HAVE_XINERAMA
01441 int i_d1, i_d2;
01442 #endif
01443
01444 p_vout->b_fullscreen = !p_vout->b_fullscreen;
01445
01446 if( p_vout->b_fullscreen )
01447 {
01448 msg_Dbg( p_vout, "entering fullscreen mode" );
01449
01450 p_vout->p_sys->b_altfullscreen =
01451 config_GetInt( p_vout, MODULE_STRING "-altfullscreen" );
01452
01453 XUnmapWindow( p_vout->p_sys->p_display,
01454 p_vout->p_sys->p_win->base_window );
01455
01456 p_vout->p_sys->p_win = &p_vout->p_sys->fullscreen_window;
01457
01458 CreateWindow( p_vout, p_vout->p_sys->p_win );
01459 XDestroyWindow( p_vout->p_sys->p_display,
01460 p_vout->p_sys->fullscreen_window.video_window );
01461 XReparentWindow( p_vout->p_sys->p_display,
01462 p_vout->p_sys->original_window.video_window,
01463 p_vout->p_sys->fullscreen_window.base_window, 0, 0 );
01464 p_vout->p_sys->fullscreen_window.video_window =
01465 p_vout->p_sys->original_window.video_window;
01466
01467
01468
01469
01470
01471
01472
01473 if( !p_vout->p_sys->b_altfullscreen )
01474 {
01475 mwmhints.flags = MWM_HINTS_DECORATIONS;
01476 mwmhints.decorations = False;
01477
01478 prop = XInternAtom( p_vout->p_sys->p_display, "_MOTIF_WM_HINTS",
01479 False );
01480 XChangeProperty( p_vout->p_sys->p_display,
01481 p_vout->p_sys->p_win->base_window,
01482 prop, prop, 32, PropModeReplace,
01483 (unsigned char *)&mwmhints,
01484 PROP_MWM_HINTS_ELEMENTS );
01485 }
01486 else
01487 {
01488
01489 attributes.override_redirect = True;
01490 XChangeWindowAttributes( p_vout->p_sys->p_display,
01491 p_vout->p_sys->p_win->base_window,
01492 CWOverrideRedirect,
01493 &attributes);
01494
01495
01496 XReparentWindow( p_vout->p_sys->p_display,
01497 p_vout->p_sys->p_win->base_window,
01498 DefaultRootWindow( p_vout->p_sys->p_display ),
01499 0, 0 );
01500 }
01501
01502 if( p_vout->p_sys->b_net_wm_state_fullscreen )
01503 {
01504 XClientMessageEvent event;
01505
01506 memset( &event, 0, sizeof( XClientMessageEvent ) );
01507
01508 event.type = ClientMessage;
01509 event.message_type = p_vout->p_sys->net_wm_state;
01510 event.display = p_vout->p_sys->p_display;
01511 event.window = p_vout->p_sys->p_win->base_window;
01512 event.format = 32;
01513 event.data.l[ 0 ] = 1;
01514 event.data.l[ 1 ] = p_vout->p_sys->net_wm_state_fullscreen;
01515
01516 XSendEvent( p_vout->p_sys->p_display,
01517 DefaultRootWindow( p_vout->p_sys->p_display ),
01518 False, SubstructureRedirectMask,
01519 (XEvent*)&event );
01520 }
01521
01522
01523 XReparentWindow( p_vout->p_sys->p_display,
01524 p_vout->p_sys->p_win->base_window,
01525 DefaultRootWindow( p_vout->p_sys->p_display ),
01526 0, 0 );
01527
01528 #ifdef HAVE_XINERAMA
01529 if( XineramaQueryExtension( p_vout->p_sys->p_display, &i_d1, &i_d2 ) &&
01530 XineramaIsActive( p_vout->p_sys->p_display ) )
01531 {
01532 XineramaScreenInfo *screens;
01533 int i_num_screens;
01534
01535 msg_Dbg( p_vout, "using XFree Xinerama extension");
01536
01537 #define SCREEN p_vout->p_sys->p_win->i_screen
01538
01539
01540 screens = XineramaQueryScreens( p_vout->p_sys->p_display,
01541 &i_num_screens );
01542
01543 SCREEN = config_GetInt( p_vout,
01544 MODULE_STRING "-xineramascreen" );
01545
01546
01547 if( SCREEN >= i_num_screens || SCREEN < 0 )
01548 {
01549 msg_Dbg( p_vout, "requested screen number invalid (%d/%d)", SCREEN, i_num_screens );
01550 SCREEN = 0;
01551 }
01552
01553
01554 p_vout->p_sys->p_win->i_x = screens[SCREEN].x_org;
01555 p_vout->p_sys->p_win->i_y = screens[SCREEN].y_org;
01556
01557
01558 p_vout->p_sys->p_win->i_width = screens[SCREEN].width;
01559 p_vout->p_sys->p_win->i_height = screens[SCREEN].height;
01560
01561 XFree(screens);
01562
01563 #undef SCREEN
01564
01565 }
01566 else
01567 #endif
01568 {
01569
01570 p_vout->p_sys->p_win->i_x = p_vout->p_sys->p_win->i_y = 0;
01571 p_vout->p_sys->p_win->i_width =
01572 DisplayWidth( p_vout->p_sys->p_display,
01573 p_vout->p_sys->i_screen );
01574 p_vout->p_sys->p_win->i_height =
01575 DisplayHeight( p_vout->p_sys->p_display,
01576 p_vout->p_sys->i_screen );
01577 }
01578
01579 XMoveResizeWindow( p_vout->p_sys->p_display,
01580 p_vout->p_sys->p_win->base_window,
01581 p_vout->p_sys->p_win->i_x,
01582 p_vout->p_sys->p_win->i_y,
01583 p_vout->p_sys->p_win->i_width,
01584 p_vout->p_sys->p_win->i_height );
01585 }
01586 else
01587 {
01588 msg_Dbg( p_vout, "leaving fullscreen mode" );
01589
01590 XReparentWindow( p_vout->p_sys->p_display,
01591 p_vout->p_sys->original_window.video_window,
01592 p_vout->p_sys->original_window.base_window, 0, 0 );
01593
01594 p_vout->p_sys->fullscreen_window.video_window = None;
01595 DestroyWindow( p_vout, &p_vout->p_sys->fullscreen_window );
01596 p_vout->p_sys->p_win = &p_vout->p_sys->original_window;
01597
01598 XMapWindow( p_vout->p_sys->p_display,
01599 p_vout->p_sys->p_win->base_window );
01600 }
01601
01602
01603
01604
01605
01606 do
01607 {
01608 XWindowEvent( p_vout->p_sys->p_display,
01609 p_vout->p_sys->p_win->base_window,
01610 StructureNotifyMask, &xevent );
01611 } while( xevent.type != MapNotify );
01612
01613
01614
01615 XSetInputFocus(p_vout->p_sys->p_display,
01616 p_vout->p_sys->p_win->base_window,
01617 RevertToParent,
01618 CurrentTime);
01619
01620
01621 p_vout->i_changes |= VOUT_SIZE_CHANGE;
01622 }
01623
01624
01625
01626
01627
01628
01629
01630
01631
01632 static void EnableXScreenSaver( vout_thread_t *p_vout )
01633 {
01634 #ifdef DPMSINFO_IN_DPMS_H
01635 int dummy;
01636 #endif
01637
01638 if( p_vout->p_sys->i_ss_timeout )
01639 {
01640 XSetScreenSaver( p_vout->p_sys->p_display, p_vout->p_sys->i_ss_timeout,
01641 p_vout->p_sys->i_ss_interval,
01642 p_vout->p_sys->i_ss_blanking,
01643 p_vout->p_sys->i_ss_exposure );
01644 }
01645
01646
01647 #ifdef DPMSINFO_IN_DPMS_H
01648 if( DPMSQueryExtension( p_vout->p_sys->p_display, &dummy, &dummy ) )
01649 {
01650 if( p_vout->p_sys->b_ss_dpms )
01651 {
01652 DPMSEnable( p_vout->p_sys->p_display );
01653 }
01654 }
01655 #endif
01656 }
01657
01658
01659
01660
01661
01662
01663 static void DisableXScreenSaver( vout_thread_t *p_vout )
01664 {
01665 #ifdef DPMSINFO_IN_DPMS_H
01666 int dummy;
01667 #endif
01668
01669
01670 XGetScreenSaver( p_vout->p_sys->p_display, &p_vout->p_sys->i_ss_timeout,
01671 &p_vout->p_sys->i_ss_interval,
01672 &p_vout->p_sys->i_ss_blanking,
01673 &p_vout->p_sys->i_ss_exposure );
01674
01675
01676 if( p_vout->p_sys->i_ss_timeout )
01677 {
01678 XSetScreenSaver( p_vout->p_sys->p_display, 0,
01679 p_vout->p_sys->i_ss_interval,
01680 p_vout->p_sys->i_ss_blanking,
01681 p_vout->p_sys->i_ss_exposure );
01682 }
01683
01684
01685 #ifdef DPMSINFO_IN_DPMS_H
01686 if( DPMSQueryExtension( p_vout->p_sys->p_display, &dummy, &dummy ) )
01687 {
01688 CARD16 unused;
01689
01690 DPMSInfo( p_vout->p_sys->p_display, &unused,
01691 &p_vout->p_sys->b_ss_dpms );
01692 DPMSDisable( p_vout->p_sys->p_display );
01693 }
01694 #endif
01695 }
01696
01697
01698
01699
01700 static void CreateCursor( vout_thread_t *p_vout )
01701 {
01702 XColor cursor_color;
01703
01704 p_vout->p_sys->cursor_pixmap =
01705 XCreatePixmap( p_vout->p_sys->p_display,
01706 DefaultRootWindow( p_vout->p_sys->p_display ),
01707 1, 1, 1 );
01708
01709 XParseColor( p_vout->p_sys->p_display,
01710 XCreateColormap( p_vout->p_sys->p_display,
01711 DefaultRootWindow(
01712 p_vout->p_sys->p_display ),
01713 DefaultVisual(
01714 p_vout->p_sys->p_display,
01715 p_vout->p_sys->i_screen ),
01716 AllocNone ),
01717 "black", &cursor_color );
01718
01719 p_vout->p_sys->blank_cursor =
01720 XCreatePixmapCursor( p_vout->p_sys->p_display,
01721 p_vout->p_sys->cursor_pixmap,
01722 p_vout->p_sys->cursor_pixmap,
01723 &cursor_color, &cursor_color, 1, 1 );
01724 }
01725
01726
01727
01728
01729 static void DestroyCursor( vout_thread_t *p_vout )
01730 {
01731 XFreePixmap( p_vout->p_sys->p_display, p_vout->p_sys->cursor_pixmap );
01732 }
01733
01734
01735
01736
01737
01738
01739
01740 static void ToggleCursor( vout_thread_t *p_vout )
01741 {
01742 if( p_vout->p_sys->b_mouse_pointer_visible )
01743 {
01744 XDefineCursor( p_vout->p_sys->p_display,
01745 p_vout->p_sys->p_win->base_window,
01746 p_vout->p_sys->blank_cursor );
01747 p_vout->p_sys->b_mouse_pointer_visible = 0;
01748 }
01749 else
01750 {
01751 XUndefineCursor( p_vout->p_sys->p_display,
01752 p_vout->p_sys->p_win->base_window );
01753 p_vout->p_sys->b_mouse_pointer_visible = 1;
01754 }
01755 }
01756
01757 #ifdef MODULE_NAME_IS_xvideo
01758
01759
01760
01761 static int XVideoGetPort( vout_thread_t *p_vout,
01762 vlc_fourcc_t i_chroma, vlc_fourcc_t *pi_newchroma )
01763 {
01764 XvAdaptorInfo *p_adaptor;
01765 unsigned int i;
01766 int i_adaptor, i_num_adaptors, i_requested_adaptor;
01767 int i_selected_port;
01768
01769 switch( XvQueryExtension( p_vout->p_sys->p_display, &i, &i, &i, &i, &i ) )
01770 {
01771 case Success:
01772 break;
01773
01774 case XvBadExtension:
01775 msg_Warn( p_vout, "XvBadExtension" );
01776 return -1;
01777
01778 case XvBadAlloc:
01779 msg_Warn( p_vout, "XvBadAlloc" );
01780 return -1;
01781
01782 default:
01783 msg_Warn( p_vout, "XvQueryExtension failed" );
01784 return -1;
01785 }
01786
01787 switch( XvQueryAdaptors( p_vout->p_sys->p_display,
01788 DefaultRootWindow( p_vout->p_sys->p_display ),
01789 &i_num_adaptors, &p_adaptor ) )
01790 {
01791 case Success:
01792 break;
01793
01794 case XvBadExtension:
01795 msg_Warn( p_vout, "XvBadExtension for XvQueryAdaptors" );
01796 return -1;
01797
01798 case XvBadAlloc:
01799 msg_Warn( p_vout, "XvBadAlloc for XvQueryAdaptors" );
01800 return -1;
01801
01802 default:
01803 msg_Warn( p_vout, "XvQueryAdaptors failed" );
01804 return -1;
01805 }
01806
01807 i_selected_port = -1;
01808 i_requested_adaptor = config_GetInt( p_vout, "xvideo-adaptor" );
01809
01810 for( i_adaptor = 0; i_adaptor < i_num_adaptors; ++i_adaptor )
01811 {
01812 XvImageFormatValues *p_formats;
01813 int i_format, i_num_formats;
01814 int i_port;
01815
01816
01817
01818 if( i_requested_adaptor != -1 && i_adaptor != i_requested_adaptor )
01819 {
01820 continue;
01821 }
01822
01823
01824 if( !( p_adaptor[ i_adaptor ].type & XvInputMask ) ||
01825 !( p_adaptor[ i_adaptor ].type & XvImageMask ) )
01826 {
01827 continue;
01828 }
01829
01830
01831 p_formats = XvListImageFormats( p_vout->p_sys->p_display,
01832 p_adaptor[i_adaptor].base_id,
01833 &i_num_formats );
01834
01835 for( i_format = 0;
01836 i_format < i_num_formats && ( i_selected_port == -1 );
01837 i_format++ )
01838 {
01839 XvAttribute *p_attr;
01840 int i_attr, i_num_attributes;
01841
01842
01843
01844 if( !vout_ChromaCmp( p_formats[ i_format ].id, i_chroma ) )
01845 {
01846 continue;
01847 }
01848
01849
01850 for( i_port = p_adaptor[i_adaptor].base_id;
01851 ( i_port < (int)(p_adaptor[i_adaptor].base_id
01852 + p_adaptor[i_adaptor].num_ports) )
01853 && ( i_selected_port == -1 );
01854 i_port++ )
01855 {
01856 if( XvGrabPort( p_vout->p_sys->p_display, i_port, CurrentTime )
01857 == Success )
01858 {
01859 i_selected_port = i_port;
01860 *pi_newchroma = p_formats[ i_format ].id;
01861 }
01862 }
01863
01864
01865 if( i_selected_port == -1 )
01866 {
01867 continue;
01868 }
01869
01870
01871 msg_Dbg( p_vout, "adaptor %i, port %i, format 0x%x (%4.4s) %s",
01872 i_adaptor, i_selected_port, p_formats[ i_format ].id,
01873 (char *)&p_formats[ i_format ].id,
01874 ( p_formats[ i_format ].format == XvPacked ) ?
01875 "packed" : "planar" );
01876
01877
01878 p_attr = XvQueryPortAttributes( p_vout->p_sys->p_display,
01879 i_selected_port,
01880 &i_num_attributes );
01881
01882 for( i_attr = 0; i_attr < i_num_attributes; i_attr++ )
01883 {
01884 if( !strcmp( p_attr[i_attr].name, "XV_AUTOPAINT_COLORKEY" ) )
01885 {
01886 const Atom autopaint =
01887 XInternAtom( p_vout->p_sys->p_display,
01888 "XV_AUTOPAINT_COLORKEY", False );
01889 XvSetPortAttribute( p_vout->p_sys->p_display,
01890 i_selected_port, autopaint, 1 );
01891 break;
01892 }
01893 }
01894
01895 if( p_attr != NULL )
01896 {
01897 XFree( p_attr );
01898 }
01899 }
01900
01901 if( p_formats != NULL )
01902 {
01903 XFree( p_formats );
01904 }
01905
01906 }
01907
01908 if( i_num_adaptors > 0 )
01909 {
01910 XvFreeAdaptorInfo( p_adaptor );
01911 }
01912
01913 if( i_selected_port == -1 )
01914 {
01915 int i_chroma_tmp = X112VLC_FOURCC( i_chroma );
01916 if( i_requested_adaptor == -1 )
01917 {
01918 msg_Warn( p_vout, "no free XVideo port found for format "
01919 "0x%.8x (%4.4s)", i_chroma_tmp, (char*)&i_chroma_tmp );
01920 }
01921 else
01922 {
01923 msg_Warn( p_vout, "XVideo adaptor %i does not have a free "
01924 "XVideo port for format 0x%.8x (%4.4s)",
01925 i_requested_adaptor, i_chroma_tmp, (char*)&i_chroma_tmp );
01926 }
01927 }
01928
01929 return i_selected_port;
01930 }
01931
01932
01933
01934
01935 static void XVideoReleasePort( vout_thread_t *p_vout, int i_port )
01936 {
01937 XvUngrabPort( p_vout->p_sys->p_display, i_port, CurrentTime );
01938 }
01939 #endif
01940
01941
01942
01943
01944
01945
01946
01947 static int InitDisplay( vout_thread_t *p_vout )
01948 {
01949 #ifdef MODULE_NAME_IS_x11
01950 XPixmapFormatValues * p_formats;
01951 XVisualInfo * p_xvisual;
01952 XVisualInfo xvisual_template;
01953 int i_count;
01954 #endif
01955
01956 #ifdef HAVE_SYS_SHM_H
01957 p_vout->p_sys->b_shm = 0;
01958
01959 if( config_GetInt( p_vout, MODULE_STRING "-shm" ) )
01960 {
01961 # ifdef SYS_DARWIN
01962
01963 # else
01964 p_vout->p_sys->b_shm =
01965 ( XShmQueryExtension( p_vout->p_sys->p_display ) == True );
01966 # endif
01967
01968 if( !p_vout->p_sys->b_shm )
01969 {
01970 msg_Warn( p_vout, "XShm video extension is unavailable" );
01971 }
01972 }
01973 else
01974 {
01975 msg_Dbg( p_vout, "disabling XShm video extension" );
01976 }
01977
01978 #else
01979 msg_Warn( p_vout, "XShm video extension is unavailable" );
01980
01981 #endif
01982
01983 #ifdef MODULE_NAME_IS_xvideo
01984
01985
01986 #if 0
01987 XVideoSetAttribute( p_vout, "XV_BRIGHTNESS", 0.5 );
01988 XVideoSetAttribute( p_vout, "XV_CONTRAST", 0.5 );
01989 #endif
01990 #endif
01991
01992 #ifdef MODULE_NAME_IS_x11
01993
01994 p_vout->p_sys->i_screen = DefaultScreen( p_vout->p_sys->p_display );
01995
01996
01997 p_vout->p_sys->i_screen_depth = XDefaultDepth( p_vout->p_sys->p_display,
01998 p_vout->p_sys->i_screen );
01999 switch( p_vout->p_sys->i_screen_depth )
02000 {
02001 case 8:
02002
02003
02004
02005 xvisual_template.screen = p_vout->p_sys->i_screen;
02006 xvisual_template.class = DirectColor;
02007 p_xvisual = XGetVisualInfo( p_vout->p_sys->p_display,
02008 VisualScreenMask | VisualClassMask,
02009 &xvisual_template, &i_count );
02010 if( p_xvisual == NULL )
02011 {
02012 msg_Err( p_vout, "no PseudoColor visual available" );
02013 return VLC_EGENERIC;
02014 }
02015 p_vout->p_sys->i_bytes_per_pixel = 1;
02016 p_vout->output.pf_setpalette = SetPalette;
02017 break;
02018 case 15:
02019 case 16:
02020 case 24:
02021 default:
02022
02023
02024
02025 xvisual_template.screen = p_vout->p_sys->i_screen;
02026 xvisual_template.class = TrueColor;
02027 p_xvisual = XGetVisualInfo( p_vout->p_sys->p_display,
02028 VisualScreenMask | VisualClassMask,
02029 &xvisual_template, &i_count );
02030 if( p_xvisual == NULL )
02031 {
02032 msg_Err( p_vout, "no TrueColor visual available" );
02033 return VLC_EGENERIC;
02034 }
02035
02036 p_vout->output.i_rmask = p_xvisual->red_mask;
02037 p_vout->output.i_gmask = p_xvisual->green_mask;
02038 p_vout->output.i_bmask = p_xvisual->blue_mask;
02039
02040
02041
02042
02043 p_formats = XListPixmapFormats( p_vout->p_sys->p_display, &i_count );
02044 p_vout->p_sys->i_bytes_per_pixel = 0;
02045
02046 for( ; i_count-- ; p_formats++ )
02047 {
02048
02049
02050
02051 if( p_formats->depth == (int)p_vout->p_sys->i_screen_depth )
02052 {
02053 if( p_formats->bits_per_pixel / 8
02054 > (int)p_vout->p_sys->i_bytes_per_pixel )
02055 {
02056 p_vout->p_sys->i_bytes_per_pixel =
02057 p_formats->bits_per_pixel / 8;
02058 }
02059 }
02060 }
02061 break;
02062 }
02063 p_vout->p_sys->p_visual = p_xvisual->visual;
02064 XFree( p_xvisual );
02065 #endif
02066
02067 return VLC_SUCCESS;
02068 }
02069
02070 #ifdef HAVE_SYS_SHM_H
02071
02072
02073
02074
02075
02076
02077
02078
02079 static IMAGE_TYPE * CreateShmImage( vout_thread_t *p_vout,
02080 Display* p_display, EXTRA_ARGS_SHM,
02081 int i_width, int i_height )
02082 {
02083 IMAGE_TYPE *p_image;
02084 Status result;
02085
02086
02087 #ifdef MODULE_NAME_IS_xvideo
02088
02089
02090 i_height = ( i_height + 15 ) >> 4 << 4;
02091 i_width = ( i_width + 15 ) >> 4 << 4;
02092
02093 p_image = XvShmCreateImage( p_display, i_xvport, i_chroma, 0,
02094 i_width, i_height, p_shm );
02095 #else
02096 p_image = XShmCreateImage( p_display, p_visual, i_depth, ZPixmap, 0,
02097 p_shm, i_width, i_height );
02098 #endif
02099 if( p_image == NULL )
02100 {
02101 msg_Err( p_vout, "image creation failed" );
02102 return NULL;
02103 }
02104
02105
02106
02107 p_shm->shmid = shmget( IPC_PRIVATE, DATA_SIZE(p_image), IPC_CREAT | 0776 );
02108 if( p_shm->shmid < 0 )
02109 {
02110 msg_Err( p_vout, "cannot allocate shared image data (%s)",
02111 strerror( errno ) );
02112 IMAGE_FREE( p_image );
02113 return NULL;
02114 }
02115
02116
02117 p_shm->shmaddr = p_image->data = shmat( p_shm->shmid, 0, 0 );
02118 if(! p_shm->shmaddr )
02119 {
02120 msg_Err( p_vout, "cannot attach shared memory (%s)",
02121 strerror(errno));
02122 IMAGE_FREE( p_image );
02123 shmctl( p_shm->shmid, IPC_RMID, 0 );
02124 return NULL;
02125 }
02126
02127
02128 p_shm->readOnly = True;
02129
02130
02131 XSynchronize( p_display, True );
02132 b_shm = VLC_TRUE;
02133 result = XShmAttach( p_display, p_shm );
02134 if( result == False || !b_shm )
02135 {
02136 msg_Err( p_vout, "cannot attach shared memory to X server" );
02137 IMAGE_FREE( p_image );
02138 shmctl( p_shm->shmid, IPC_RMID, 0 );
02139 shmdt( p_shm->shmaddr );
02140 return NULL;
02141 }
02142 XSynchronize( p_display, False );
02143
02144
02145
02146
02147 XSync( p_display, False );
02148
02149 #if 0
02150
02151
02152 shmctl( p_shm->shmid, IPC_RMID, 0 );
02153 #endif
02154
02155 return p_image;
02156 }
02157 #endif
02158
02159
02160
02161
02162
02163
02164 static IMAGE_TYPE * CreateImage( vout_thread_t *p_vout,
02165 Display *p_display, EXTRA_ARGS,
02166 int i_width, int i_height )
02167 {
02168 byte_t * p_data;
02169 IMAGE_TYPE *p_image;
02170 #ifdef MODULE_NAME_IS_x11
02171 int i_quantum;
02172 int i_bytes_per_line;
02173 #endif
02174
02175
02176 #ifdef MODULE_NAME_IS_xvideo
02177
02178
02179 i_height = ( i_height + 15 ) >> 4 << 4;
02180 i_width = ( i_width + 15 ) >> 4 << 4;
02181
02182 p_data = (byte_t *) malloc( i_width * i_height * i_bits_per_pixel / 8 );
02183 #elif defined(MODULE_NAME_IS_x11)
02184 i_bytes_per_line = i_width * i_bytes_per_pixel;
02185 p_data = (byte_t *) malloc( i_bytes_per_line * i_height );
02186 #endif
02187 if( !p_data )
02188 {
02189 msg_Err( p_vout, "out of memory" );
02190 return NULL;
02191 }
02192
02193 #ifdef MODULE_NAME_IS_x11
02194
02195
02196 if( i_bytes_per_line & 0xf )
02197 {
02198 i_quantum = 0x8;
02199 }
02200 else if( i_bytes_per_line & 0x10 )
02201 {
02202 i_quantum = 0x10;
02203 }
02204 else
02205 {
02206 i_quantum = 0x20;
02207 }
02208 #endif
02209
02210
02211 #ifdef MODULE_NAME_IS_xvideo
02212 p_image = XvCreateImage( p_display, i_xvport, i_chroma,
02213 p_data, i_width, i_height );
02214 #elif defined(MODULE_NAME_IS_x11)
02215 p_image = XCreateImage( p_display, p_visual, i_depth, ZPixmap, 0,
02216 p_data, i_width, i_height, i_quantum, 0 );
02217 #endif
02218 if( p_image == NULL )
02219 {
02220 msg_Err( p_vout, "XCreateImage() failed" );
02221 free( p_data );
02222 return NULL;
02223 }
02224
02225 return p_image;
02226 }
02227
02228
02229
02230
02231 static int X11ErrorHandler( Display * display, XErrorEvent * event )
02232 {
02233
02234
02235 if( event->request_code == X_SetInputFocus )
02236 {
02237 fprintf(stderr, "XSetInputFocus failed\n");
02238 return 0;
02239 }
02240
02241 if( event->request_code == 150 &&
02242 event->minor_code == X_ShmAttach )
02243 {
02244 fprintf(stderr, "XShmAttach failed\n");
02245 b_shm = VLC_FALSE;
02246 return 0;
02247 }
02248
02249 XSetErrorHandler(NULL);
02250 return (XSetErrorHandler(X11ErrorHandler))( display, event );
02251 }
02252
02253 #ifdef MODULE_NAME_IS_x11
02254
02255
02256
02257
02258
02259
02260
02261 static void SetPalette( vout_thread_t *p_vout,
02262 uint16_t *red, uint16_t *green, uint16_t *blue )
02263 {
02264 int i;
02265 XColor p_colors[255];
02266
02267
02268 for( i = 0; i < 255; i++ )
02269 {
02270
02271
02272 p_colors[ i ].pixel = 255 - i;
02273 p_colors[ i ].pad = 0;
02274 p_colors[ i ].flags = DoRed | DoGreen | DoBlue;
02275 p_colors[ i ].red = red[ 255 - i ];
02276 p_colors[ i ].blue = blue[ 255 - i ];
02277 p_colors[ i ].green = green[ 255 - i ];
02278 }
02279
02280 XStoreColors( p_vout->p_sys->p_display,
02281 p_vout->p_sys->colormap, p_colors, 255 );
02282 }
02283 #endif
02284
02285
02286
02287
02288 static int Control( vout_thread_t *p_vout, int i_query, va_list args )
02289 {
02290 vlc_bool_t b_arg;
02291
02292 switch( i_query )
02293 {
02294 case VOUT_SET_ZOOM:
02295 if( p_vout->p_sys->p_win->owner_window )
02296 return vout_ControlWindow( p_vout,
02297 (void *)p_vout->p_sys->p_win->owner_window, i_query, args);
02298
02299 vlc_mutex_lock( &p_vout->p_sys->lock );
02300
02301
02302 XResizeWindow( p_vout->p_sys->p_display,
02303 p_vout->p_sys->p_win->base_window,
02304 p_vout->i_window_width,
02305 p_vout->i_window_height );
02306
02307 vlc_mutex_unlock( &p_vout->p_sys->lock );
02308 return VLC_SUCCESS;
02309
02310 case VOUT_CLOSE:
02311 vlc_mutex_lock( &p_vout->p_sys->lock );
02312 XUnmapWindow( p_vout->p_sys->p_display,
02313 p_vout->p_sys->original_window.base_window );
02314 vlc_mutex_unlock( &p_vout->p_sys->lock );
02315
02316
02317 case VOUT_REPARENT:
02318 vlc_mutex_lock( &p_vout->p_sys->lock );
02319 XReparentWindow( p_vout->p_sys->p_display,
02320 p_vout->p_sys->original_window.base_window,
02321 DefaultRootWindow( p_vout->p_sys->p_display ),
02322 0, 0 );
02323 XSync( p_vout->p_sys->p_display, False );
02324 p_vout->p_sys->original_window.owner_window = 0;
02325 vlc_mutex_unlock( &p_vout->p_sys->lock );
02326 return vout_vaControlDefault( p_vout, i_query, args );
02327
02328 case VOUT_SET_STAY_ON_TOP:
02329 if( p_vout->p_sys->p_win->owner_window )
02330 return vout_ControlWindow( p_vout,
02331 (void *)p_vout->p_sys->p_win->owner_window, i_query, args);
02332
02333 b_arg = va_arg( args, vlc_bool_t );
02334 vlc_mutex_lock( &p_vout->p_sys->lock );
02335 WindowOnTop( p_vout, b_arg );
02336 vlc_mutex_unlock( &p_vout->p_sys->lock );
02337 return VLC_SUCCESS;
02338
02339 default:
02340 return vout_vaControlDefault( p_vout, i_query, args );
02341 }
02342 }
02343
02344
02345
02346
02347 static void TestNetWMSupport( vout_thread_t *p_vout )
02348 {
02349 int i_ret, i_format;
02350 unsigned long i, i_items, i_bytesafter;
02351 Atom net_wm_supported;
02352 union { Atom *p_atom; unsigned char *p_char; } p_args;
02353
02354 p_args.p_atom = NULL;
02355
02356 p_vout->p_sys->b_net_wm_state_fullscreen = VLC_FALSE;
02357 p_vout->p_sys->b_net_wm_state_above = VLC_FALSE;
02358 p_vout->p_sys->b_net_wm_state_below = VLC_FALSE;
02359 p_vout->p_sys->b_net_wm_state_stays_on_top = VLC_FALSE;
02360
02361 net_wm_supported =
02362 XInternAtom( p_vout->p_sys->p_display, "_NET_SUPPORTED", False );
02363
02364 i_ret = XGetWindowProperty( p_vout->p_sys->p_display,
02365 DefaultRootWindow( p_vout->p_sys->p_display ),
02366 net_wm_supported,
02367 0, 16384, False, AnyPropertyType,
02368 &net_wm_supported,
02369 &i_format, &i_items, &i_bytesafter,
02370 (unsigned char **)&p_args );
02371
02372 if( i_ret != Success || i_items == 0 ) return;
02373
02374 msg_Dbg( p_vout, "Window manager supports NetWM" );
02375
02376 p_vout->p_sys->net_wm_state =
02377 XInternAtom( p_vout->p_sys->p_display, "_NET_WM_STATE", False );
02378 p_vout->p_sys->net_wm_state_fullscreen =
02379 XInternAtom( p_vout->p_sys->p_display, "_NET_WM_STATE_FULLSCREEN",
02380 False );
02381 p_vout->p_sys->net_wm_state_above =
02382 XInternAtom( p_vout->p_sys->p_display, "_NET_WM_STATE_ABOVE", False );
02383 p_vout->p_sys->net_wm_state_below =
02384 XInternAtom( p_vout->p_sys->p_display, "_NET_WM_STATE_BELOW", False );
02385 p_vout->p_sys->net_wm_state_stays_on_top =
02386 XInternAtom( p_vout->p_sys->p_display, "_NET_WM_STATE_STAYS_ON_TOP",
02387 False );
02388
02389 for( i = 0; i < i_items; i++ )
02390 {
02391 if( p_args.p_atom[i] == p_vout->p_sys->net_wm_state_fullscreen )
02392 {
02393 msg_Dbg( p_vout,
02394 "Window manager supports _NET_WM_STATE_FULLSCREEN" );
02395 p_vout->p_sys->b_net_wm_state_fullscreen = VLC_TRUE;
02396 }
02397 else if( p_args.p_atom[i] == p_vout->p_sys->net_wm_state_above )
02398 {
02399 msg_Dbg( p_vout, "Window manager supports _NET_WM_STATE_ABOVE" );
02400 p_vout->p_sys->b_net_wm_state_above = VLC_TRUE;
02401 }
02402 else if( p_args.p_atom[i] == p_vout->p_sys->net_wm_state_below )
02403 {
02404 msg_Dbg( p_vout, "Window manager supports _NET_WM_STATE_BELOW" );
02405 p_vout->p_sys->b_net_wm_state_below = VLC_TRUE;
02406 }
02407 else if( p_args.p_atom[i] == p_vout->p_sys->net_wm_state_stays_on_top )
02408 {
02409 msg_Dbg( p_vout,
02410 "Window manager supports _NET_WM_STATE_STAYS_ON_TOP" );
02411 p_vout->p_sys->b_net_wm_state_stays_on_top = VLC_TRUE;
02412 }
02413 }
02414
02415 XFree( p_args.p_atom );
02416 }
02417
02418
02419
02420
02421 static struct
02422 {
02423 int i_x11key;
02424 int i_vlckey;
02425
02426 } x11keys_to_vlckeys[] =
02427 {
02428 { XK_F1, KEY_F1 }, { XK_F2, KEY_F2 }, { XK_F3, KEY_F3 }, { XK_F4, KEY_F4 },
02429 { XK_F5, KEY_F5 }, { XK_F6, KEY_F6 }, { XK_F7, KEY_F7 }, { XK_F8, KEY_F8 },
02430 { XK_F9, KEY_F9 }, { XK_F10, KEY_F10 }, { XK_F11, KEY_F11 },
02431 { XK_F12, KEY_F12 },
02432
02433 { XK_Return, KEY_ENTER },
02434 { XK_KP_Enter, KEY_ENTER },
02435 { XK_space, KEY_SPACE },
02436 { XK_Escape, KEY_ESC },
02437
02438 { XK_Menu, KEY_MENU },
02439 { XK_Left, KEY_LEFT },
02440 { XK_Right, KEY_RIGHT },
02441 { XK_Up, KEY_UP },
02442 { XK_Down, KEY_DOWN },
02443
02444 { XK_Home, KEY_HOME },
02445 { XK_End, KEY_END },
02446 { XK_Page_Up, KEY_PAGEUP },
02447 { XK_Page_Down, KEY_PAGEDOWN },
02448
02449 { XK_Insert, KEY_INSERT },
02450 { XK_Delete, KEY_DELETE },
02451
02452 { 0, 0 }
02453 };
02454
02455 static int ConvertKey( int i_key )
02456 {
02457 int i;
02458
02459 for( i = 0; x11keys_to_vlckeys[i].i_x11key != 0; i++ )
02460 {
02461 if( x11keys_to_vlckeys[i].i_x11key == i_key )
02462 {
02463 return x11keys_to_vlckeys[i].i_vlckey;
02464 }
02465 }
02466
02467 return 0;
02468 }
02469
02470
02471
02472
02473 static int WindowOnTop( vout_thread_t *p_vout, vlc_bool_t b_on_top )
02474 {
02475 if( p_vout->p_sys->b_net_wm_state_stays_on_top )
02476 {
02477 XClientMessageEvent event;
02478
02479 memset( &event, 0, sizeof( XClientMessageEvent ) );
02480
02481 event.type = ClientMessage;
02482 event.message_type = p_vout->p_sys->net_wm_state;
02483 event.display = p_vout->p_sys->p_display;
02484 event.window = p_vout->p_sys->p_win->base_window;
02485 event.format = 32;
02486 event.data.l[ 0 ] = b_on_top;
02487 event.data.l[ 1 ] = p_vout->p_sys->net_wm_state_stays_on_top;
02488
02489 XSendEvent( p_vout->p_sys->p_display,
02490 DefaultRootWindow( p_vout->p_sys->p_display ),
02491 False, SubstructureRedirectMask,
02492 (XEvent*)&event );
02493 }
02494
02495 return VLC_SUCCESS;
02496 }