1 /*****************************************************************************
2 * vout.m: MacOS X video output module
3 *****************************************************************************
4 * Copyright (C) 2001-2003 VideoLAN
5 * $Id: vout.m,v 1.81 2004/02/12 17:35:05 titer Exp $
7 * Authors: Colin Delacroix <colin@zoy.org>
8 * Florian G. Pflug <fgp@phlo.org>
9 * Jon Lech Johansen <jon-vl@nanocrew.net>
10 * Derk-Jan Hartman <thedj@users.sourceforge.net>
11 * Eric Petit <titer@m0k.org>
13 * This program is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published by
15 * the Free Software Foundation; either version 2 of the License, or
16 * (at your option) any later version.
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, write to the Free Software
25 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
26 *****************************************************************************/
28 /*****************************************************************************
30 *****************************************************************************/
31 #include <errno.h> /* ENOMEM */
32 #include <stdlib.h> /* free() */
33 #include <string.h> /* strerror() */
35 #include <QuickTime/QuickTime.h>
37 #include <OpenGL/OpenGL.h>
38 #include <OpenGL/gl.h>
39 #include <OpenGL/glext.h>
46 #define QT_MAX_DIRECTBUFFERS 10
47 #define VL_MAX_DISPLAYS 16
49 #define OPENGL_EFFECT_NONE 1
50 #define OPENGL_EFFECT_CUBE 2
51 #define OPENGL_EFFECT_TRANSPARENT_CUBE 4
58 /* When using I420 output */
59 PlanarPixmapInfoYUV420 pixmap_i420;
62 /*****************************************************************************
64 *****************************************************************************/
66 static int vout_Init ( vout_thread_t * );
67 static void vout_End ( vout_thread_t * );
68 static int vout_Manage ( vout_thread_t * );
69 static void vout_Display ( vout_thread_t *, picture_t * );
71 static int CoSendRequest ( vout_thread_t *, SEL );
72 static int CoCreateWindow ( vout_thread_t * );
73 static int CoDestroyWindow ( vout_thread_t * );
74 static int CoToggleFullscreen ( vout_thread_t * );
76 static void VLCHideMouse ( vout_thread_t *, BOOL );
78 static void QTScaleMatrix ( vout_thread_t * );
79 static int QTCreateSequence ( vout_thread_t * );
80 static void QTDestroySequence ( vout_thread_t * );
81 static int QTNewPicture ( vout_thread_t *, picture_t * );
82 static void QTFreePicture ( vout_thread_t *, picture_t * );
84 /*****************************************************************************
85 * OpenVideo: allocates MacOS X video thread output method
86 *****************************************************************************
87 * This function allocates and initializes a MacOS X vout method.
88 *****************************************************************************/
89 int E_(OpenVideo) ( vlc_object_t *p_this )
91 vout_thread_t * p_vout = (vout_thread_t *)p_this;
95 p_vout->p_sys = malloc( sizeof( vout_sys_t ) );
96 if( p_vout->p_sys == NULL )
98 msg_Err( p_vout, "out of memory" );
102 memset( p_vout->p_sys, 0, sizeof( vout_sys_t ) );
104 /* Wait for a MacOS X interface to appear. Timeout is 2 seconds. */
105 for( i_timeout = 20 ; i_timeout-- ; )
109 msleep( INTF_IDLE_SLEEP );
115 /* no MacOS X intf, unable to communicate with MT */
116 msg_Err( p_vout, "no MacOS X interface present" );
117 free( p_vout->p_sys );
121 if( [NSApp respondsToSelector: @selector(getIntf)] )
123 intf_thread_t * p_intf;
125 for( i_timeout = 10 ; i_timeout-- ; )
127 if( ( p_intf = [NSApp getIntf] ) == NULL )
129 msleep( INTF_IDLE_SLEEP );
135 msg_Err( p_vout, "MacOS X intf has getIntf, but is NULL" );
136 free( p_vout->p_sys );
141 p_vout->p_sys->b_mouse_moved = VLC_TRUE;
142 p_vout->p_sys->i_time_mouse_last_moved = mdate();
144 /* set window size */
145 p_vout->p_sys->s_rect.size.width = p_vout->i_window_width;
146 p_vout->p_sys->s_rect.size.height = p_vout->i_window_height;
148 /* Check if we should use QuickTime or OpenGL */
149 p_vout->p_sys->i_opengl = config_GetInt( p_vout, "macosx-opengl" );
151 if( !p_vout->p_sys->i_opengl )
153 /* Initialize QuickTime */
154 p_vout->p_sys->h_img_descr =
155 (ImageDescriptionHandle)NewHandleClear( sizeof(ImageDescription) );
156 p_vout->p_sys->p_matrix =
157 (MatrixRecordPtr)malloc( sizeof(MatrixRecord) );
158 p_vout->p_sys->p_fullscreen_state = NULL;
160 if( ( err = EnterMovies() ) != noErr )
162 msg_Err( p_vout, "EnterMovies failed: %d", err );
163 free( p_vout->p_sys->p_matrix );
164 DisposeHandle( (Handle)p_vout->p_sys->h_img_descr );
165 free( p_vout->p_sys );
169 /* Damn QT isn't thread safe. so keep a lock in the p_vlc object */
170 vlc_mutex_lock( &p_vout->p_vlc->quicktime_lock );
172 err = FindCodec( kYUV420CodecType, bestSpeedCodec,
173 nil, &p_vout->p_sys->img_dc );
175 vlc_mutex_unlock( &p_vout->p_vlc->quicktime_lock );
176 if( err == noErr && p_vout->p_sys->img_dc != 0 )
178 p_vout->output.i_chroma = VLC_FOURCC('I','4','2','0');
179 p_vout->p_sys->i_codec = kYUV420CodecType;
183 msg_Err( p_vout, "failed to find an appropriate codec" );
186 if( p_vout->p_sys->img_dc == 0 )
188 free( p_vout->p_sys->p_matrix );
189 DisposeHandle( (Handle)p_vout->p_sys->h_img_descr );
190 free( p_vout->p_sys );
195 NSAutoreleasePool * o_pool = [[NSAutoreleasePool alloc] init];
196 NSArray * o_screens = [NSScreen screens];
197 if( [o_screens count] > 0 && var_Type( p_vout, "video-device" ) == 0 )
200 vlc_value_t val, text;
203 int i_option = config_GetInt( p_vout, "macosx-vdev" );
205 var_Create( p_vout, "video-device", VLC_VAR_INTEGER |
207 text.psz_string = _("Video device");
208 var_Change( p_vout, "video-device", VLC_VAR_SETTEXT, &text, NULL );
210 NSEnumerator * o_enumerator = [o_screens objectEnumerator];
212 while( (o_screen = [o_enumerator nextObject]) != NULL )
215 NSRect s_rect = [o_screen frame];
217 snprintf( psz_temp, sizeof(psz_temp)/sizeof(psz_temp[0])-1,
218 "%s %d (%dx%d)", _("Screen"), i,
219 (int)s_rect.size.width, (int)s_rect.size.height );
221 text.psz_string = psz_temp;
223 var_Change( p_vout, "video-device",
224 VLC_VAR_ADDCHOICE, &val, &text );
226 if( ( i - 1 ) == i_option )
228 var_Set( p_vout, "video-device", val );
233 var_AddCallback( p_vout, "video-device", vout_VarCallback,
236 val.b_bool = VLC_TRUE;
237 var_Set( p_vout, "intf-change", val );
241 if( CoCreateWindow( p_vout ) )
243 msg_Err( p_vout, "unable to create window" );
244 if( !p_vout->p_sys->i_opengl )
246 free( p_vout->p_sys->p_matrix );
247 DisposeHandle( (Handle)p_vout->p_sys->h_img_descr );
249 free( p_vout->p_sys );
253 p_vout->pf_init = vout_Init;
254 p_vout->pf_end = vout_End;
255 p_vout->pf_manage = vout_Manage;
256 p_vout->pf_render = NULL;
257 p_vout->pf_display = vout_Display;
262 /*****************************************************************************
263 * vout_Init: initialize video thread output method
264 *****************************************************************************/
265 static int vout_Init( vout_thread_t *p_vout )
270 I_OUTPUTPICTURES = 0;
272 /* Initialize the output structure; we already found a codec,
273 * and the corresponding chroma we will be using. Since we can
274 * arbitrary scale, stick to the coordinates and aspect. */
275 p_vout->output.i_width = p_vout->render.i_width;
276 p_vout->output.i_height = p_vout->render.i_height;
277 p_vout->output.i_aspect = p_vout->render.i_aspect;
279 if( !p_vout->p_sys->i_opengl )
281 SetPort( p_vout->p_sys->p_qdport );
282 QTScaleMatrix( p_vout );
284 if( QTCreateSequence( p_vout ) )
286 msg_Err( p_vout, "unable to create sequence" );
292 p_vout->output.i_chroma = VLC_FOURCC('Y','U','Y','2');
293 p_vout->output.i_rmask = 0xFF0000;
294 p_vout->output.i_gmask = 0x00FF00;
295 p_vout->output.i_bmask = 0x0000FF;
298 /* Try to initialize up to QT_MAX_DIRECTBUFFERS direct buffers */
299 while( I_OUTPUTPICTURES <
300 p_vout->p_sys->i_opengl ? 1 : QT_MAX_DIRECTBUFFERS )
304 /* Find an empty picture slot */
305 for( i_index = 0; i_index < VOUT_MAX_PICTURES; i_index++ )
307 if( p_vout->p_picture[ i_index ].i_status == FREE_PICTURE )
309 p_pic = p_vout->p_picture + i_index;
314 /* Allocate the picture */
320 if( !p_vout->p_sys->i_opengl )
322 if( QTNewPicture( p_vout, p_pic ) )
329 /* Nothing special to do, we just need a basic allocated
331 vout_AllocatePicture( p_vout, p_pic, p_vout->output.i_chroma,
332 p_vout->output.i_width, p_vout->output.i_height,
333 p_vout->output.i_aspect );
336 p_pic->i_status = DESTROYED_PICTURE;
337 p_pic->i_type = DIRECT_PICTURE;
339 PP_OUTPUTPICTURE[ I_OUTPUTPICTURES ] = p_pic;
344 if( p_vout->p_sys->i_opengl )
346 [p_vout->p_sys->o_glview lockFocus];
347 [p_vout->p_sys->o_glview initTextures];
348 [p_vout->p_sys->o_glview unlockFocus];
354 /*****************************************************************************
355 * vout_End: terminate video thread output method
356 *****************************************************************************/
357 static void vout_End( vout_thread_t *p_vout )
361 if( !p_vout->p_sys->i_opengl )
363 QTDestroySequence( p_vout );
366 /* Free the direct buffers we allocated */
367 for( i_index = I_OUTPUTPICTURES; i_index; )
370 if( !p_vout->p_sys->i_opengl )
372 QTFreePicture( p_vout, PP_OUTPUTPICTURE[ i_index ] );
376 free( PP_OUTPUTPICTURE[ i_index ]->p_data_orig );
381 /*****************************************************************************
382 * CloseVideo: destroy video thread output method
383 *****************************************************************************/
384 void E_(CloseVideo) ( vlc_object_t *p_this )
386 vout_thread_t * p_vout = (vout_thread_t *)p_this;
388 if( CoDestroyWindow( p_vout ) )
390 msg_Err( p_vout, "unable to destroy window" );
393 if( !p_vout->p_sys->i_opengl )
395 if ( p_vout->p_sys->p_fullscreen_state != NULL )
396 EndFullScreen ( p_vout->p_sys->p_fullscreen_state, NULL );
400 free( p_vout->p_sys->p_matrix );
401 DisposeHandle( (Handle)p_vout->p_sys->h_img_descr );
404 free( p_vout->p_sys );
407 /*****************************************************************************
408 * vout_Manage: handle events
409 *****************************************************************************
410 * This function should be called regularly by video output thread. It manages
411 * console events. It returns a non null value on error.
412 *****************************************************************************/
413 static int vout_Manage( vout_thread_t *p_vout )
415 if( p_vout->i_changes & VOUT_FULLSCREEN_CHANGE )
417 if( CoToggleFullscreen( p_vout ) )
422 p_vout->i_changes &= ~VOUT_FULLSCREEN_CHANGE;
425 if( p_vout->i_changes & VOUT_SIZE_CHANGE )
427 if( !p_vout->p_sys->i_opengl )
429 QTScaleMatrix( p_vout );
430 SetDSequenceMatrix( p_vout->p_sys->i_seq,
431 p_vout->p_sys->p_matrix );
434 p_vout->i_changes &= ~VOUT_SIZE_CHANGE;
437 /* hide/show mouse cursor
438 * this code looks unnecessarily complicated, but is necessary like this.
439 * it has to deal with multiple monitors and therefore checks a lot */
440 if( !p_vout->p_sys->b_mouse_moved && p_vout->b_fullscreen )
442 if( mdate() - p_vout->p_sys->i_time_mouse_last_moved > 3000000 )
444 VLCHideMouse( p_vout, YES );
447 else if ( p_vout->p_sys->b_mouse_moved && p_vout->b_fullscreen )
449 VLCHideMouse( p_vout, NO );
452 /* disable screen saver */
453 UpdateSystemActivity( UsrActivity );
458 /*****************************************************************************
459 * vout_Display: displays previously rendered output
460 *****************************************************************************
461 * This function sends the currently rendered image to the display.
462 *****************************************************************************/
463 static void vout_Display( vout_thread_t *p_vout, picture_t *p_pic )
465 if( !p_vout->p_sys->i_opengl )
470 if( ( err = DecompressSequenceFrameS(
471 p_vout->p_sys->i_seq,
472 p_pic->p_sys->p_info,
473 p_pic->p_sys->i_size,
474 codecFlagUseImageBuffer, &flags, nil ) != noErr ) )
476 msg_Warn( p_vout, "DecompressSequenceFrameS failed: %d", err );
480 QDFlushPortBuffer( p_vout->p_sys->p_qdport, nil );
485 if( [p_vout->p_sys->o_glview lockFocusIfCanDraw] )
487 /* Texture gotta be reload before the buffer is filled
488 (thanks to gcc from arstechnica forums) */
489 [p_vout->p_sys->o_glview drawRect:
490 [p_vout->p_sys->o_glview bounds]];
491 [p_vout->p_sys->o_glview reloadTexture];
492 [p_vout->p_sys->o_glview unlockFocus];
497 /*****************************************************************************
498 * CoSendRequest: send request to interface thread
499 *****************************************************************************
500 * Returns 0 on success, 1 otherwise
501 *****************************************************************************/
502 static int CoSendRequest( vout_thread_t *p_vout, SEL sel )
506 intf_thread_t * p_intf;
508 VLCVout * o_vlv = [[VLCVout alloc] init];
510 if( ( i_ret = ExecuteOnMainThread( o_vlv, sel, (void *)p_vout ) ) )
512 msg_Err( p_vout, "SendRequest: no way to communicate with mt" );
517 /*This makes this function dependant of the presence of a macosx
518 interface. We do not check if this interface exists, since it has
519 already been done before.*/
521 p_intf = [NSApp getIntf];
523 val.b_bool = VLC_TRUE;
524 var_Create(p_intf,"intf-change",VLC_VAR_BOOL);
525 var_Set(p_intf, "intf-change",val);
530 /*****************************************************************************
531 * CoCreateWindow: create new window
532 *****************************************************************************
533 * Returns 0 on success, 1 otherwise
534 *****************************************************************************/
535 static int CoCreateWindow( vout_thread_t *p_vout )
537 if( CoSendRequest( p_vout, @selector(createWindow:) ) )
539 msg_Err( p_vout, "CoSendRequest (createWindow) failed" );
546 /*****************************************************************************
547 * CoDestroyWindow: destroy window
548 *****************************************************************************
549 * Returns 0 on success, 1 otherwise
550 *****************************************************************************/
551 static int CoDestroyWindow( vout_thread_t *p_vout )
554 VLCHideMouse( p_vout, NO );
556 if( CoSendRequest( p_vout, @selector(destroyWindow:) ) )
558 msg_Err( p_vout, "CoSendRequest (destroyWindow) failed" );
565 /*****************************************************************************
566 * CoToggleFullscreen: toggle fullscreen
567 *****************************************************************************
568 * Returns 0 on success, 1 otherwise
569 *****************************************************************************/
570 static int CoToggleFullscreen( vout_thread_t *p_vout )
572 if( p_vout->p_sys->i_opengl )
578 QTDestroySequence( p_vout );
580 if( CoDestroyWindow( p_vout ) )
582 msg_Err( p_vout, "unable to destroy window" );
586 p_vout->b_fullscreen = !p_vout->b_fullscreen;
588 if( CoCreateWindow( p_vout ) )
590 msg_Err( p_vout, "unable to create window" );
594 SetPort( p_vout->p_sys->p_qdport );
595 QTScaleMatrix( p_vout );
597 if( QTCreateSequence( p_vout ) )
599 msg_Err( p_vout, "unable to create sequence" );
606 /*****************************************************************************
607 * VLCHideMouse: if b_hide then hide the cursor
608 *****************************************************************************/
609 static void VLCHideMouse ( vout_thread_t *p_vout, BOOL b_hide )
614 NSWindow *o_window = p_vout->p_sys->o_window;
615 NSView *o_contents = [o_window contentView];
617 s_rect = [o_contents bounds];
618 ml = [o_window convertScreenToBase:[NSEvent mouseLocation]];
619 ml = [o_contents convertPoint:ml fromView:nil];
620 b_inside = [o_contents mouse: ml inRect: s_rect];
622 if ( b_hide && b_inside )
624 /* only hide if mouse over VLCQTView */
625 [NSCursor setHiddenUntilMouseMoves: YES];
629 [NSCursor setHiddenUntilMouseMoves: NO];
631 p_vout->p_sys->b_mouse_moved = NO;
632 p_vout->p_sys->i_time_mouse_last_moved = mdate();
636 /*****************************************************************************
637 * QTScaleMatrix: scale matrix
638 *****************************************************************************/
639 static void QTScaleMatrix( vout_thread_t *p_vout )
642 unsigned int i_width, i_height;
643 Fixed factor_x, factor_y;
644 unsigned int i_offset_x = 0;
645 unsigned int i_offset_y = 0;
647 GetPortBounds( p_vout->p_sys->p_qdport, &s_rect );
649 i_width = s_rect.right - s_rect.left;
650 i_height = s_rect.bottom - s_rect.top;
652 if( i_height * p_vout->output.i_aspect < i_width * VOUT_ASPECT_FACTOR )
654 int i_adj_width = i_height * p_vout->output.i_aspect /
657 factor_x = FixDiv( Long2Fix( i_adj_width ),
658 Long2Fix( p_vout->output.i_width ) );
659 factor_y = FixDiv( Long2Fix( i_height ),
660 Long2Fix( p_vout->output.i_height ) );
662 i_offset_x = (i_width - i_adj_width) / 2;
666 int i_adj_height = i_width * VOUT_ASPECT_FACTOR /
667 p_vout->output.i_aspect;
669 factor_x = FixDiv( Long2Fix( i_width ),
670 Long2Fix( p_vout->output.i_width ) );
671 factor_y = FixDiv( Long2Fix( i_adj_height ),
672 Long2Fix( p_vout->output.i_height ) );
674 i_offset_y = (i_height - i_adj_height) / 2;
677 SetIdentityMatrix( p_vout->p_sys->p_matrix );
679 ScaleMatrix( p_vout->p_sys->p_matrix,
681 Long2Fix(0), Long2Fix(0) );
683 TranslateMatrix( p_vout->p_sys->p_matrix,
684 Long2Fix(i_offset_x),
685 Long2Fix(i_offset_y) );
689 /*****************************************************************************
690 * QTCreateSequence: create a new sequence
691 *****************************************************************************
692 * Returns 0 on success, 1 otherwise
693 *****************************************************************************/
694 static int QTCreateSequence( vout_thread_t *p_vout )
697 ImageDescriptionPtr p_descr;
699 HLock( (Handle)p_vout->p_sys->h_img_descr );
700 p_descr = *p_vout->p_sys->h_img_descr;
702 p_descr->idSize = sizeof(ImageDescription);
703 p_descr->cType = p_vout->p_sys->i_codec;
704 p_descr->version = 1;
705 p_descr->revisionLevel = 0;
706 p_descr->vendor = 'appl';
707 p_descr->width = p_vout->output.i_width;
708 p_descr->height = p_vout->output.i_height;
709 p_descr->hRes = Long2Fix(72);
710 p_descr->vRes = Long2Fix(72);
711 p_descr->spatialQuality = codecLosslessQuality;
712 p_descr->frameCount = 1;
713 p_descr->clutID = -1;
714 p_descr->dataSize = 0;
717 HUnlock( (Handle)p_vout->p_sys->h_img_descr );
719 if( ( err = DecompressSequenceBeginS(
720 &p_vout->p_sys->i_seq,
721 p_vout->p_sys->h_img_descr,
723 p_vout->p_sys->p_qdport,
725 p_vout->p_sys->p_matrix,
727 codecFlagUseImageBuffer,
728 codecLosslessQuality,
729 p_vout->p_sys->img_dc ) ) )
731 msg_Err( p_vout, "DecompressSequenceBeginS failed: %d", err );
738 /*****************************************************************************
739 * QTDestroySequence: destroy sequence
740 *****************************************************************************/
741 static void QTDestroySequence( vout_thread_t *p_vout )
743 CDSequenceEnd( p_vout->p_sys->i_seq );
746 /*****************************************************************************
747 * QTNewPicture: allocate a picture
748 *****************************************************************************
749 * Returns 0 on success, 1 otherwise
750 *****************************************************************************/
751 static int QTNewPicture( vout_thread_t *p_vout, picture_t *p_pic )
753 int i_width = p_vout->output.i_width;
754 int i_height = p_vout->output.i_height;
756 /* We know the chroma, allocate a buffer which will be used
757 * directly by the decoder */
758 p_pic->p_sys = malloc( sizeof( picture_sys_t ) );
760 if( p_pic->p_sys == NULL )
765 switch( p_vout->output.i_chroma )
767 case VLC_FOURCC('I','4','2','0'):
769 p_pic->p_sys->p_info = (void *)&p_pic->p_sys->pixmap_i420;
770 p_pic->p_sys->i_size = sizeof(PlanarPixmapInfoYUV420);
772 /* Allocate the memory buffer */
773 p_pic->p_data = vlc_memalign( &p_pic->p_data_orig,
774 16, i_width * i_height * 3 / 2 );
777 p_pic->Y_PIXELS = p_pic->p_data;
778 p_pic->p[Y_PLANE].i_lines = i_height;
779 p_pic->p[Y_PLANE].i_pitch = i_width;
780 p_pic->p[Y_PLANE].i_pixel_pitch = 1;
781 p_pic->p[Y_PLANE].i_visible_pitch = i_width;
784 p_pic->U_PIXELS = p_pic->Y_PIXELS + i_height * i_width;
785 p_pic->p[U_PLANE].i_lines = i_height / 2;
786 p_pic->p[U_PLANE].i_pitch = i_width / 2;
787 p_pic->p[U_PLANE].i_pixel_pitch = 1;
788 p_pic->p[U_PLANE].i_visible_pitch = i_width / 2;
791 p_pic->V_PIXELS = p_pic->U_PIXELS + i_height * i_width / 4;
792 p_pic->p[V_PLANE].i_lines = i_height / 2;
793 p_pic->p[V_PLANE].i_pitch = i_width / 2;
794 p_pic->p[V_PLANE].i_pixel_pitch = 1;
795 p_pic->p[V_PLANE].i_visible_pitch = i_width / 2;
797 /* We allocated 3 planes */
800 #define P p_pic->p_sys->pixmap_i420
801 P.componentInfoY.offset = (void *)p_pic->Y_PIXELS
802 - p_pic->p_sys->p_info;
803 P.componentInfoCb.offset = (void *)p_pic->U_PIXELS
804 - p_pic->p_sys->p_info;
805 P.componentInfoCr.offset = (void *)p_pic->V_PIXELS
806 - p_pic->p_sys->p_info;
808 P.componentInfoY.rowBytes = i_width;
809 P.componentInfoCb.rowBytes = i_width / 2;
810 P.componentInfoCr.rowBytes = i_width / 2;
816 /* Unknown chroma, tell the guy to get lost */
817 free( p_pic->p_sys );
818 msg_Err( p_vout, "never heard of chroma 0x%.8x (%4.4s)",
819 p_vout->output.i_chroma, (char*)&p_vout->output.i_chroma );
827 /*****************************************************************************
828 * QTFreePicture: destroy a picture allocated with QTNewPicture
829 *****************************************************************************/
830 static void QTFreePicture( vout_thread_t *p_vout, picture_t *p_pic )
832 switch( p_vout->output.i_chroma )
834 case VLC_FOURCC('I','4','2','0'):
835 free( p_pic->p_data_orig );
839 free( p_pic->p_sys );
842 /*****************************************************************************
843 * VLCWindow implementation
844 *****************************************************************************/
845 @implementation VLCWindow
847 - (void)setVout:(vout_thread_t *)_p_vout
852 - (vout_thread_t *)getVout
857 - (void)scaleWindowWithFactor: (float)factor
860 int i_corrected_height, i_corrected_width;
862 NSPoint topleftscreen;
864 if ( !p_vout->b_fullscreen )
867 topleftbase.y = [self frame].size.height;
868 topleftscreen = [self convertBaseToScreen: topleftbase];
870 if( p_vout->output.i_height * p_vout->output.i_aspect >
871 p_vout->output.i_width * VOUT_ASPECT_FACTOR )
873 i_corrected_width = p_vout->output.i_height * p_vout->output.i_aspect /
875 newsize.width = (int) ( i_corrected_width * factor );
876 newsize.height = (int) ( p_vout->render.i_height * factor );
880 i_corrected_height = p_vout->output.i_width * VOUT_ASPECT_FACTOR /
881 p_vout->output.i_aspect;
882 newsize.width = (int) ( p_vout->render.i_width * factor );
883 newsize.height = (int) ( i_corrected_height * factor );
886 [self setContentSize: newsize];
888 [self setFrameTopLeftPoint: topleftscreen];
889 p_vout->i_changes |= VOUT_SIZE_CHANGE;
893 - (void)toggleFloatOnTop
895 if( config_GetInt( p_vout, "video-on-top" ) )
897 config_PutInt( p_vout, "video-on-top", 0 );
898 [p_vout->p_sys->o_window setLevel: NSNormalWindowLevel];
902 config_PutInt( p_vout, "video-on-top", 1 );
903 [p_vout->p_sys->o_window setLevel: NSStatusWindowLevel];
907 - (void)toggleFullscreen
909 config_PutInt(p_vout, "fullscreen", !p_vout->b_fullscreen);
910 p_vout->i_changes |= VOUT_FULLSCREEN_CHANGE;
915 return( p_vout->b_fullscreen );
918 - (BOOL)canBecomeKeyWindow
923 - (void)keyDown:(NSEvent *)o_event
927 unsigned int i_pressed_modifiers = 0;
930 i_pressed_modifiers = [o_event modifierFlags];
932 if( i_pressed_modifiers & NSShiftKeyMask )
933 val.i_int |= KEY_MODIFIER_SHIFT;
934 if( i_pressed_modifiers & NSControlKeyMask )
935 val.i_int |= KEY_MODIFIER_CTRL;
936 if( i_pressed_modifiers & NSAlternateKeyMask )
937 val.i_int |= KEY_MODIFIER_ALT;
938 if( i_pressed_modifiers & NSCommandKeyMask )
939 val.i_int |= KEY_MODIFIER_COMMAND;
941 key = [[o_event charactersIgnoringModifiers] characterAtIndex: 0];
945 /* Escape should always get you out of fullscreen */
946 if( key == (unichar) 0x1b )
948 if( [self isFullscreen] )
950 [self toggleFullscreen];
953 else if ( key == ' ' )
955 playlist_t *p_playlist = vlc_object_find( p_vout, VLC_OBJECT_PLAYLIST,
957 if ( p_playlist != NULL )
959 playlist_Pause( p_playlist );
960 vlc_object_release( p_playlist);
965 val.i_int |= CocoaKeyToVLC( key );
966 var_Set( p_vout->p_vlc, "key-pressed", val );
971 [super keyDown: o_event];
977 NSMutableString * o_title;
978 playlist_t * p_playlist = vlc_object_find( p_vout, VLC_OBJECT_PLAYLIST,
981 if( p_playlist == NULL )
986 vlc_mutex_lock( &p_playlist->object_lock );
987 o_title = [NSMutableString stringWithUTF8String:
988 p_playlist->pp_items[p_playlist->i_index]->psz_uri];
989 vlc_mutex_unlock( &p_playlist->object_lock );
991 vlc_object_release( p_playlist );
995 NSRange prefix_range = [o_title rangeOfString: @"file:"];
996 if( prefix_range.location != NSNotFound )
998 [o_title deleteCharactersInRange: prefix_range];
1001 [self setTitleWithRepresentedFilename: o_title];
1006 [NSString stringWithCString: VOUT_TITLE " (QuickTime)"]];
1010 /* This is actually the same as VLCControls::stop. */
1011 - (BOOL)windowShouldClose:(id)sender
1013 playlist_t * p_playlist = vlc_object_find( p_vout, VLC_OBJECT_PLAYLIST,
1015 if( p_playlist == NULL )
1020 playlist_Stop( p_playlist );
1021 vlc_object_release( p_playlist );
1023 /* The window will be closed by the intf later. */
1029 /*****************************************************************************
1030 * VLCQTView implementation
1031 *****************************************************************************/
1032 @implementation VLCQTView
1034 - (void)drawRect:(NSRect)rect
1036 vout_thread_t * p_vout;
1037 id o_window = [self window];
1038 p_vout = (vout_thread_t *)[o_window getVout];
1040 [[NSColor blackColor] set];
1042 [super drawRect: rect];
1044 p_vout->i_changes |= VOUT_SIZE_CHANGE;
1047 - (BOOL)acceptsFirstResponder
1052 - (BOOL)becomeFirstResponder
1054 vout_thread_t * p_vout;
1055 id o_window = [self window];
1056 p_vout = (vout_thread_t *)[o_window getVout];
1058 [o_window setAcceptsMouseMovedEvents: YES];
1062 - (BOOL)resignFirstResponder
1064 vout_thread_t * p_vout;
1065 id o_window = [self window];
1066 p_vout = (vout_thread_t *)[o_window getVout];
1068 [o_window setAcceptsMouseMovedEvents: NO];
1069 VLCHideMouse( p_vout, NO );
1073 - (void)mouseDown:(NSEvent *)o_event
1075 vout_thread_t * p_vout;
1076 id o_window = [self window];
1077 p_vout = (vout_thread_t *)[o_window getVout];
1080 switch( [o_event type] )
1082 case NSLeftMouseDown:
1084 var_Get( p_vout, "mouse-button-down", &val );
1086 var_Set( p_vout, "mouse-button-down", val );
1091 [super mouseDown: o_event];
1096 - (void)otherMouseDown:(NSEvent *)o_event
1098 /* This is not the the wheel button. you need to poll the
1099 * mouseWheel event for that. other is a third, forth or fifth button */
1100 vout_thread_t * p_vout;
1101 id o_window = [self window];
1102 p_vout = (vout_thread_t *)[o_window getVout];
1105 switch( [o_event type] )
1107 case NSOtherMouseDown:
1109 var_Get( p_vout, "mouse-button-down", &val );
1111 var_Set( p_vout, "mouse-button-down", val );
1116 [super mouseDown: o_event];
1121 - (void)rightMouseDown:(NSEvent *)o_event
1123 vout_thread_t * p_vout;
1124 id o_window = [self window];
1125 p_vout = (vout_thread_t *)[o_window getVout];
1128 switch( [o_event type] )
1130 case NSRightMouseDown:
1132 var_Get( p_vout, "mouse-button-down", &val );
1134 var_Set( p_vout, "mouse-button-down", val );
1139 [super mouseDown: o_event];
1144 - (void)mouseUp:(NSEvent *)o_event
1146 vout_thread_t * p_vout;
1147 id o_window = [self window];
1148 p_vout = (vout_thread_t *)[o_window getVout];
1151 switch( [o_event type] )
1156 b_val.b_bool = VLC_TRUE;
1157 var_Set( p_vout, "mouse-clicked", b_val );
1159 var_Get( p_vout, "mouse-button-down", &val );
1161 var_Set( p_vout, "mouse-button-down", val );
1166 [super mouseUp: o_event];
1171 - (void)otherMouseUp:(NSEvent *)o_event
1173 vout_thread_t * p_vout;
1174 id o_window = [self window];
1175 p_vout = (vout_thread_t *)[o_window getVout];
1178 switch( [o_event type] )
1180 case NSOtherMouseUp:
1182 var_Get( p_vout, "mouse-button-down", &val );
1184 var_Set( p_vout, "mouse-button-down", val );
1189 [super mouseUp: o_event];
1194 - (void)rightMouseUp:(NSEvent *)o_event
1196 vout_thread_t * p_vout;
1197 id o_window = [self window];
1198 p_vout = (vout_thread_t *)[o_window getVout];
1201 switch( [o_event type] )
1203 case NSRightMouseUp:
1205 var_Get( p_vout, "mouse-button-down", &val );
1207 var_Set( p_vout, "mouse-button-down", val );
1212 [super mouseUp: o_event];
1217 - (void)mouseDragged:(NSEvent *)o_event
1219 [self mouseMoved:o_event];
1222 - (void)otherMouseDragged:(NSEvent *)o_event
1224 [self mouseMoved:o_event];
1227 - (void)rightMouseDragged:(NSEvent *)o_event
1229 [self mouseMoved:o_event];
1232 - (void)mouseMoved:(NSEvent *)o_event
1238 vout_thread_t * p_vout;
1239 id o_window = [self window];
1240 p_vout = (vout_thread_t *)[o_window getVout];
1242 s_rect = [self bounds];
1243 ml = [self convertPoint: [o_event locationInWindow] fromView: nil];
1244 b_inside = [self mouse: ml inRect: s_rect];
1249 int i_width, i_height, i_x, i_y;
1251 vout_PlacePicture( p_vout, (unsigned int)s_rect.size.width,
1252 (unsigned int)s_rect.size.height,
1253 &i_x, &i_y, &i_width, &i_height );
1255 val.i_int = ( ((int)ml.x) - i_x ) *
1256 p_vout->render.i_width / i_width;
1257 var_Set( p_vout, "mouse-x", val );
1259 val.i_int = ( ((int)ml.y) - i_y ) *
1260 p_vout->render.i_height / i_height;
1261 var_Set( p_vout, "mouse-y", val );
1263 val.b_bool = VLC_TRUE;
1264 var_Set( p_vout, "mouse-moved", val );
1265 p_vout->p_sys->i_time_mouse_last_moved = mdate();
1266 p_vout->p_sys->b_mouse_moved = YES;
1269 [super mouseMoved: o_event];
1274 /*****************************************************************************
1275 * VLCGLView implementation
1276 *****************************************************************************/
1277 @implementation VLCGLView
1280 - (id) initWithFrame: (NSRect) frame vout: (vout_thread_t*) _p_vout
1285 NSOpenGLPixelFormatAttribute attribs[] =
1287 NSOpenGLPFAAccelerated,
1288 NSOpenGLPFANoRecovery,
1289 NSOpenGLPFADoubleBuffer,
1290 NSOpenGLPFAColorSize, 24,
1291 NSOpenGLPFAAlphaSize, 8,
1292 NSOpenGLPFADepthSize, 24,
1297 NSOpenGLPixelFormat * fmt = [[NSOpenGLPixelFormat alloc]
1298 initWithAttributes: attribs];
1302 fprintf( stderr, "Cannot create NSOpenGLPixelFormat\n" );
1306 self = [super initWithFrame:frame pixelFormat: fmt];
1308 [[self openGLContext] makeCurrentContext];
1309 [[self openGLContext] update];
1311 /* Black background */
1312 glClearColor( 0.0, 0.0, 0.0, 0.0 );
1314 /* Check if the user asked for useless visual effects */
1315 psz_effect = config_GetPsz( p_vout, "macosx-opengl-effect" );
1316 if( !strcmp( psz_effect, "none" ) )
1318 i_effect = OPENGL_EFFECT_NONE;
1320 else if( !strcmp( psz_effect, "cube" ) )
1322 i_effect = OPENGL_EFFECT_CUBE;
1324 glEnable( GL_DEPTH_TEST );
1326 else if( !strcmp( psz_effect, "transparent-cube" ) )
1328 i_effect = OPENGL_EFFECT_TRANSPARENT_CUBE;
1330 glDisable( GL_DEPTH_TEST );
1331 glEnable( GL_BLEND );
1332 glBlendFunc( GL_SRC_ALPHA, GL_ONE );
1336 msg_Warn( p_vout, "no valid opengl effect provided, using "
1338 i_effect = OPENGL_EFFECT_NONE;
1341 if( i_effect & ( OPENGL_EFFECT_CUBE |
1342 OPENGL_EFFECT_TRANSPARENT_CUBE ) )
1344 /* Set the perpective */
1345 glMatrixMode( GL_PROJECTION );
1347 glFrustum( -1.0, 1.0, -1.0, 1.0, 3.0, 20.0 );
1348 glMatrixMode( GL_MODELVIEW );
1350 glTranslatef( 0.0, 0.0, - 5.0 );
1360 [[self openGLContext] makeCurrentContext];
1362 NSRect bounds = [self bounds];
1364 glViewport( 0, 0, (GLint) bounds.size.width,
1365 (GLint) bounds.size.height );
1367 /* Quad size is set in order to preserve the aspect ratio */
1368 if( bounds.size.height * p_vout->output.i_aspect <
1369 bounds.size.width * VOUT_ASPECT_FACTOR )
1371 f_x = bounds.size.height * p_vout->render.i_aspect /
1372 VOUT_ASPECT_FACTOR / bounds.size.width;
1378 f_y = bounds.size.width * VOUT_ASPECT_FACTOR /
1379 p_vout->render.i_aspect / bounds.size.height;
1383 - (void) initTextures
1385 [[self openGLContext] makeCurrentContext];
1387 /* Create textures */
1388 glGenTextures( 1, &i_texture );
1390 glEnable( GL_TEXTURE_RECTANGLE_EXT );
1391 glEnable( GL_UNPACK_CLIENT_STORAGE_APPLE );
1393 glBindTexture( GL_TEXTURE_RECTANGLE_EXT, i_texture );
1395 /* Use VRAM texturing */
1396 glTexParameteri( GL_TEXTURE_RECTANGLE_EXT,
1397 GL_TEXTURE_STORAGE_HINT_APPLE, GL_STORAGE_CACHED_APPLE );
1399 /* Tell the driver not to make a copy of the texture but to use
1401 glPixelStorei( GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE );
1403 /* Linear interpolation */
1404 glTexParameteri( GL_TEXTURE_RECTANGLE_EXT,
1405 GL_TEXTURE_MIN_FILTER, GL_LINEAR );
1406 glTexParameteri( GL_TEXTURE_RECTANGLE_EXT,
1407 GL_TEXTURE_MAG_FILTER, GL_LINEAR );
1409 /* I have no idea what this exactly does, but it seems to be
1410 necessary for scaling */
1411 glTexParameteri( GL_TEXTURE_RECTANGLE_EXT,
1412 GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
1413 glTexParameteri( GL_TEXTURE_RECTANGLE_EXT,
1414 GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
1415 glPixelStorei( GL_UNPACK_ROW_LENGTH, 0 );
1417 glTexImage2D( GL_TEXTURE_RECTANGLE_EXT, 0, GL_RGBA,
1418 p_vout->output.i_width, p_vout->output.i_height, 0,
1419 GL_YCBCR_422_APPLE, GL_UNSIGNED_SHORT_8_8_APPLE,
1420 PP_OUTPUTPICTURE[0]->p_data );
1425 - (void) reloadTexture
1427 [[self openGLContext] makeCurrentContext];
1429 glBindTexture( GL_TEXTURE_RECTANGLE_EXT, i_texture );
1431 /* glTexSubImage2D is faster than glTexImage2D
1432 http://developer.apple.com/samplecode/Sample_Code/Graphics_3D/
1433 TextureRange/MainOpenGLView.m.htm */
1434 glTexSubImage2D( GL_TEXTURE_RECTANGLE_EXT, 0, 0, 0,
1435 p_vout->output.i_width, p_vout->output.i_height,
1436 GL_YCBCR_422_APPLE, GL_UNSIGNED_SHORT_8_8_APPLE,
1437 PP_OUTPUTPICTURE[0]->p_data );
1442 glBegin( GL_QUADS );
1444 glTexCoord2f( 0.0, 0.0 );
1445 glVertex2f( - f_x, f_y );
1447 glTexCoord2f( 0.0, (float) p_vout->output.i_height );
1448 glVertex2f( - f_x, - f_y );
1450 glTexCoord2f( (float) p_vout->output.i_width,
1451 (float) p_vout->output.i_height );
1452 glVertex2f( f_x, - f_y );
1454 glTexCoord2f( (float) p_vout->output.i_width, 0.0 );
1455 glVertex2f( f_x, f_y );
1461 glBegin( GL_QUADS );
1463 glTexCoord2f( 0.0, 0.0 );
1464 glVertex3f( - 1.0, 1.0, 1.0 );
1465 glTexCoord2f( 0.0, (float) p_vout->output.i_height );
1466 glVertex3f( - 1.0, - 1.0, 1.0 );
1467 glTexCoord2f( (float) p_vout->output.i_width,
1468 (float) p_vout->output.i_height );
1469 glVertex3f( 1.0, - 1.0, 1.0 );
1470 glTexCoord2f( (float) p_vout->output.i_width, 0.0 );
1471 glVertex3f( 1.0, 1.0, 1.0 );
1474 glTexCoord2f( 0.0, 0.0 );
1475 glVertex3f( - 1.0, 1.0, - 1.0 );
1476 glTexCoord2f( 0.0, (float) p_vout->output.i_height );
1477 glVertex3f( - 1.0, - 1.0, - 1.0 );
1478 glTexCoord2f( (float) p_vout->output.i_width,
1479 (float) p_vout->output.i_height );
1480 glVertex3f( - 1.0, - 1.0, 1.0 );
1481 glTexCoord2f( (float) p_vout->output.i_width, 0.0 );
1482 glVertex3f( - 1.0, 1.0, 1.0 );
1485 glTexCoord2f( 0.0, 0.0 );
1486 glVertex3f( 1.0, 1.0, - 1.0 );
1487 glTexCoord2f( 0.0, (float) p_vout->output.i_height );
1488 glVertex3f( 1.0, - 1.0, - 1.0 );
1489 glTexCoord2f( (float) p_vout->output.i_width,
1490 (float) p_vout->output.i_height );
1491 glVertex3f( - 1.0, - 1.0, - 1.0 );
1492 glTexCoord2f( (float) p_vout->output.i_width, 0.0 );
1493 glVertex3f( - 1.0, 1.0, - 1.0 );
1496 glTexCoord2f( 0.0, 0.0 );
1497 glVertex3f( 1.0, 1.0, 1.0 );
1498 glTexCoord2f( 0.0, (float) p_vout->output.i_height );
1499 glVertex3f( 1.0, - 1.0, 1.0 );
1500 glTexCoord2f( (float) p_vout->output.i_width,
1501 (float) p_vout->output.i_height );
1502 glVertex3f( 1.0, - 1.0, - 1.0 );
1503 glTexCoord2f( (float) p_vout->output.i_width, 0.0 );
1504 glVertex3f( 1.0, 1.0, - 1.0 );
1507 glTexCoord2f( 0.0, 0.0 );
1508 glVertex3f( - 1.0, 1.0, - 1.0 );
1509 glTexCoord2f( 0.0, (float) p_vout->output.i_height );
1510 glVertex3f( - 1.0, 1.0, 1.0 );
1511 glTexCoord2f( (float) p_vout->output.i_width,
1512 (float) p_vout->output.i_height );
1513 glVertex3f( 1.0, 1.0, 1.0 );
1514 glTexCoord2f( (float) p_vout->output.i_width, 0.0 );
1515 glVertex3f( 1.0, 1.0, - 1.0 );
1518 glTexCoord2f( 0.0, 0.0 );
1519 glVertex3f( - 1.0, - 1.0, 1.0 );
1520 glTexCoord2f( 0.0, (float) p_vout->output.i_height );
1521 glVertex3f( - 1.0, - 1.0, - 1.0 );
1522 glTexCoord2f( (float) p_vout->output.i_width,
1523 (float) p_vout->output.i_height );
1524 glVertex3f( 1.0, - 1.0, - 1.0 );
1525 glTexCoord2f( (float) p_vout->output.i_width, 0.0 );
1526 glVertex3f( 1.0, - 1.0, 1.0 );
1530 - (void) drawRect: (NSRect) rect
1532 [[self openGLContext] makeCurrentContext];
1534 /* Swap buffers only during the vertical retrace of the monitor.
1535 http://developer.apple.com/documentation/GraphicsImaging/
1536 Conceptual/OpenGL/chap5/chapter_5_section_44.html */
1537 long params[] = { 1 };
1538 CGLSetParameter( CGLGetCurrentContext(), kCGLCPSwapInterval,
1541 /* Black background */
1542 glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
1546 [[self openGLContext] flushBuffer];
1551 glBindTexture( GL_TEXTURE_RECTANGLE_EXT, i_texture );
1552 if( i_effect & ( OPENGL_EFFECT_CUBE |
1553 OPENGL_EFFECT_TRANSPARENT_CUBE ) )
1555 glRotatef( 1.0, 0.3, 0.5, 0.7 );
1563 /* Wait for the job to be done */
1564 [[self openGLContext] flushBuffer];
1569 /*****************************************************************************
1570 * VLCVout implementation
1571 *****************************************************************************/
1572 @implementation VLCVout
1574 - (void)createWindow:(NSValue *)o_value
1578 NSScreen * o_screen;
1579 vout_thread_t * p_vout;
1580 vlc_bool_t b_main_screen;
1582 p_vout = (vout_thread_t *)[o_value pointerValue];
1584 p_vout->p_sys->o_window = [VLCWindow alloc];
1585 [p_vout->p_sys->o_window setVout: p_vout];
1586 [p_vout->p_sys->o_window setReleasedWhenClosed: YES];
1588 if( var_Get( p_vout, "video-device", &val ) < 0 )
1590 o_screen = [NSScreen mainScreen];
1595 NSArray *o_screens = [NSScreen screens];
1596 unsigned int i_index = val.i_int;
1598 if( [o_screens count] < i_index )
1600 o_screen = [NSScreen mainScreen];
1606 o_screen = [o_screens objectAtIndex: i_index];
1607 config_PutInt( p_vout, "macosx-vdev", i_index );
1608 b_main_screen = (i_index == 0);
1612 if( p_vout->p_sys->i_opengl )
1614 /* XXX Fix fullscreen mode */
1615 p_vout->b_fullscreen = 0;
1618 if( p_vout->b_fullscreen )
1620 NSRect screen_rect = [o_screen frame];
1621 screen_rect.origin.x = screen_rect.origin.y = 0;
1623 if ( b_main_screen && p_vout->p_sys->p_fullscreen_state == NULL )
1624 BeginFullScreen( &p_vout->p_sys->p_fullscreen_state, NULL, 0, 0,
1625 NULL, NULL, fullScreenAllowEvents );
1627 [p_vout->p_sys->o_window
1628 initWithContentRect: screen_rect
1629 styleMask: NSBorderlessWindowMask
1630 backing: NSBackingStoreBuffered
1631 defer: NO screen: o_screen];
1633 //[p_vout->p_sys->o_window setLevel: NSPopUpMenuWindowLevel - 1];
1634 p_vout->p_sys->b_mouse_moved = YES;
1635 p_vout->p_sys->i_time_mouse_last_moved = mdate();
1639 unsigned int i_stylemask = NSTitledWindowMask |
1640 NSMiniaturizableWindowMask |
1641 NSClosableWindowMask |
1642 NSResizableWindowMask;
1644 if( !p_vout->p_sys->i_opengl )
1646 if ( p_vout->p_sys->p_fullscreen_state != NULL )
1647 EndFullScreen ( p_vout->p_sys->p_fullscreen_state, NULL );
1648 p_vout->p_sys->p_fullscreen_state = NULL;
1651 [p_vout->p_sys->o_window
1652 initWithContentRect: p_vout->p_sys->s_rect
1653 styleMask: i_stylemask
1654 backing: NSBackingStoreBuffered
1655 defer: NO screen: o_screen];
1657 [p_vout->p_sys->o_window setAlphaValue: config_GetFloat( p_vout, "macosx-opaqueness" )];
1659 if( config_GetInt( p_vout, "video-on-top" ) )
1661 [p_vout->p_sys->o_window setLevel: NSStatusWindowLevel];
1664 if( !p_vout->p_sys->b_pos_saved )
1666 [p_vout->p_sys->o_window center];
1670 if( !p_vout->p_sys->i_opengl )
1672 o_view = [[VLCQTView alloc] init];
1673 /* FIXME: [o_view setMenu:] */
1674 [p_vout->p_sys->o_window setContentView: o_view];
1675 [o_view autorelease];
1678 p_vout->p_sys->p_qdport = [o_view qdPort];
1679 [o_view unlockFocus];
1683 #define o_glview p_vout->p_sys->o_glview
1684 o_glview = [[VLCGLView alloc] initWithFrame: p_vout->p_sys->s_rect vout: p_vout];
1685 [p_vout->p_sys->o_window setContentView: o_glview];
1686 [o_glview autorelease];
1690 [p_vout->p_sys->o_window updateTitle];
1691 [p_vout->p_sys->o_window makeKeyAndOrderFront: nil];
1695 - (void)destroyWindow:(NSValue *)o_value
1697 vout_thread_t * p_vout;
1699 p_vout = (vout_thread_t *)[o_value pointerValue];
1701 if( !p_vout->b_fullscreen )
1705 s_rect = [[p_vout->p_sys->o_window contentView] frame];
1706 p_vout->p_sys->s_rect.size = s_rect.size;
1708 s_rect = [p_vout->p_sys->o_window frame];
1709 p_vout->p_sys->s_rect.origin = s_rect.origin;
1711 p_vout->p_sys->b_pos_saved = YES;
1714 p_vout->p_sys->p_qdport = nil;
1715 [p_vout->p_sys->o_window close];
1716 p_vout->p_sys->o_window = nil;