Prefer DMO Windows Media codecs over the DShow ones. They are considerably
[mplayer/greg.git] / libvo / vo_macosx.m
bloba2f335adf00fe9398d1ce979a9a8902106a5f28a
1 /*
2         vo_macosx.m
3         by Nicolas Plourde <nicolasplourde@gmail.com>
4         
5         MPlayer Mac OSX video out module.
6         Copyright (c) Nicolas Plourde - 2005
7 */
9 #import "vo_macosx.h"
10 #include <sys/types.h>
11 #include <sys/ipc.h>
12 #include <sys/shm.h>
14 //MPLAYER
15 #include "config.h"
16 #include "fastmemcpy.h"
17 #include "video_out.h"
18 #include "video_out_internal.h"
19 #include "aspect.h"
20 #include "mp_msg.h"
21 #include "m_option.h"
23 #include "input/input.h"
24 #include "input/mouse.h"
26 #include "osdep/keycodes.h"
28 //Cocoa
29 NSProxy *mplayerosxProxy;
30 MPlayerOpenGLView *mpGLView;
31 NSAutoreleasePool *autoreleasepool;
32 OSType pixelFormat;
34 //shared memory
35 int shm_id;
36 struct shmid_ds shm_desc;
37 BOOL shared_buffer = false;
39 //Screen
40 int screen_id;
41 BOOL screen_force;
42 NSRect screen_frame;
43 NSScreen *screen_handle;
44 NSArray *screen_array;
46 //image
47 unsigned char *image_data;
48 static uint32_t image_width;
49 static uint32_t image_height;
50 static uint32_t image_depth;
51 static uint32_t image_bytes;
52 static uint32_t image_format;
54 //vo
55 static int isFullscreen;
56 static int isOntop;
57 static int isRootwin;
58 extern float monitor_aspect;
59 extern float movie_aspect;
60 static float old_movie_aspect;
62 static float winAlpha = 1;
63 static int int_pause = 0;
65 static vo_info_t info = 
67         "Mac OSX Core Video",
68         "macosx",
69         "Nicolas Plourde <nicolas.plourde@gmail.com>",
70         ""
73 LIBVO_EXTERN(macosx)
75 extern void mplayer_put_key(int code);
76 extern void vo_draw_text(int dxs,int dys,void (*draw_alpha)(int x0,int y0, int w,int h, unsigned char* src, unsigned char *srca, int stride));
78 static void draw_alpha(int x0, int y0, int w, int h, unsigned char *src, unsigned char *srca, int stride)
80         switch (image_format)
81         {
82                 case IMGFMT_RGB32:
83                         vo_draw_alpha_rgb32(w,h,src,srca,stride,image_data+4*(y0*image_width+x0),4*image_width);
84                         break;
85                 case IMGFMT_YUY2:
86                         vo_draw_alpha_yuy2(w,h,src,srca,stride,image_data + (x0 + y0 * image_width) * 2,image_width*2);
87                         break;
88         }
91 static int config(uint32_t width, uint32_t height, uint32_t d_width, uint32_t d_height, uint32_t flags, char *title, uint32_t format)
93         
94         //init screen
95         screen_array = [NSScreen screens];
96         if(screen_id < [screen_array count])
97         {
98                 screen_handle = [screen_array objectAtIndex:screen_id];
99         }
100         else
101         {
102                 mp_msg(MSGT_VO, MSGL_FATAL, "Get device error: Device ID %d do not exist, falling back to main device.\n", screen_id);
103                 screen_handle = [screen_array objectAtIndex:0];
104                 screen_id = 0;
105         }
106         screen_frame = [screen_handle frame];
108         //misc mplayer setup
109         image_width = width;
110         image_height = height;
111         switch (image_format) 
112         {
113                 case IMGFMT_BGR32:
114                 case IMGFMT_RGB32:
115                         image_depth = 32;
116                         break;
117                 case IMGFMT_YUY2:
118                         image_depth = 16;
119                         break;
120         }
121         image_bytes = (image_depth + 7) / 8;
122         image_data = malloc(image_width*image_height*image_bytes);
123                 
124         if(!shared_buffer)
125         {               
126                 monitor_aspect = (float)screen_frame.size.width/(float)screen_frame.size.height;
127                 
128                 //set aspect
129                 panscan_init();
130                 aspect_save_orig(width,height);
131                 aspect_save_prescale(d_width,d_height);
132                 aspect_save_screenres(screen_frame.size.width, screen_frame.size.height);
133                 aspect((int *)&d_width,(int *)&d_height,A_NOZOOM);
134                 
135                 movie_aspect = (float)d_width/(float)d_height;
136                 old_movie_aspect = movie_aspect;
137                 
138                 vo_fs = flags & VOFLAG_FULLSCREEN;
139                         
140                 //config OpenGL View
141                 [mpGLView config];
142                 [mpGLView reshape];
143         }
144         else
145         {
146                 movie_aspect = (float)d_width/(float)d_height;
147                                 
148                 shm_id = shmget(9849, image_width*image_height*image_bytes, IPC_CREAT | 0666);
149                 if (shm_id == -1)
150                 {
151                         perror("vo_mplayer shmget: ");
152                         return 1;
153                 }
154                 
155                 image_data = shmat(shm_id, NULL, 0);
156                 if (!image_data)
157                 {       
158                         perror("vo_mplayer shmat: ");
159                         return 1;
160                 }
161                 
162                 //connnect to mplayerosx
163                 mplayerosxProxy=[NSConnection rootProxyForConnectionWithRegisteredName:@"mplayerosx" host:nil];
164                 [mplayerosxProxy startWithWidth: image_width withHeight: image_height withBytes: image_bytes withAspect:(int)(movie_aspect*100)];
165         }
166         return 0;
169 static void check_events(void)
171         [mpGLView check_events];
174 static void draw_osd(void)
176         vo_draw_text(image_width, image_height, draw_alpha);
179 static void flip_page(void)
181         if(shared_buffer)
182                 [mplayerosxProxy render];
183         else
184                 [mpGLView render];
187 static int draw_slice(uint8_t *src[], int stride[], int w,int h,int x,int y)
189         [mpGLView setCurrentTexture];
190         return 0;
194 static int draw_frame(uint8_t *src[])
196         switch (image_format)
197         {
198                 case IMGFMT_BGR32:
199                 case IMGFMT_RGB32:
200                         fast_memcpy(image_data, src[0], image_width*image_height*image_bytes);
201                         break;
203                 case IMGFMT_YUY2:
204                         memcpy_pic(image_data, src[0], image_width * 2, image_height, image_width * 2, image_width * 2);
205                         break;
206         }
207         
208         if(!shared_buffer)
209                 [mpGLView setCurrentTexture];
210         
211         return 0;
214 static int query_format(uint32_t format)
216         image_format = format;
217         
218     switch(format)
219         {
220                 case IMGFMT_YUY2:
221                         pixelFormat = kYUVSPixelFormat;
222                         return VFCAP_CSP_SUPPORTED | VFCAP_CSP_SUPPORTED_BY_HW | VFCAP_OSD | VFCAP_HWSCALE_UP | VFCAP_HWSCALE_DOWN;
223                 
224                 case IMGFMT_RGB32:
225                 case IMGFMT_BGR32:
226                         pixelFormat = k32ARGBPixelFormat;
227                         return VFCAP_CSP_SUPPORTED | VFCAP_CSP_SUPPORTED_BY_HW | VFCAP_OSD | VFCAP_HWSCALE_UP | VFCAP_HWSCALE_DOWN;
228     }
229     return 0;
232 static void uninit(void)
234         if(shared_buffer)
235         {
236                 [mplayerosxProxy stop];
238                 if (shmdt(image_data) == -1)
239                         mp_msg(MSGT_VO, MSGL_FATAL, "uninit: shmdt failed\n");
240         
241                 if (shmctl(shm_id, IPC_RMID, &shm_desc) == -1)
242                         mp_msg(MSGT_VO, MSGL_FATAL, "uninit: shmctl failed\n");
243         }
245     SetSystemUIMode( kUIModeNormal, 0);
246     CGDisplayShowCursor(kCGDirectMainDisplay);
247     
248     if(mpGLView)
249     {
250         mpGLView = nil;
251         [autoreleasepool release];
252     }
255 static int preinit(const char *arg)
257         int parse_err = 0;
259     if(arg) 
260     {
261         char *parse_pos = (char *)&arg[0];
262         while (parse_pos[0] && !parse_err) 
263                 {
264                         if (strncmp (parse_pos, "device_id=", 10) == 0)
265                         {
266                                 parse_pos = &parse_pos[10];
267                                 screen_id = strtol(parse_pos, &parse_pos, 0);
268                                 screen_force = YES;
269             }
270                         if (strncmp (parse_pos, "shared_buffer", 13) == 0)
271                         {
272                                 parse_pos = &parse_pos[13];
273                                 shared_buffer = YES;
274             }
275             if (parse_pos[0] == ':') parse_pos = &parse_pos[1];
276             else if (parse_pos[0]) parse_err = 1;
277         }
278     }
280         NSApplicationLoad();
281         autoreleasepool = [[NSAutoreleasePool alloc] init];
282         NSApp = [NSApplication sharedApplication];
283         
284         if(!shared_buffer)
285         {
286                 #if !defined (MACOSX_FINDER_SUPPORT) || !defined (HAVE_SDL)
287                 //this chunk of code is heavily based off SDL_macosx.m from SDL 
288                 //it uses an Apple private function to request foreground operation
289                 void CPSEnableForegroundOperation(ProcessSerialNumber* psn);
290                 ProcessSerialNumber myProc, frProc;
291                 Boolean sameProc;
293                 if (GetFrontProcess(&frProc) == noErr)
294                 {
295                         if (GetCurrentProcess(&myProc) == noErr)
296                         {
297                                 if (SameProcess(&frProc, &myProc, &sameProc) == noErr && !sameProc)
298                                 {
299                                         CPSEnableForegroundOperation(&myProc);
300                                 }
301                                 SetFrontProcess(&myProc);
302                         }
303                 }
304                 #endif
306                 if(!mpGLView)
307                 {
308                         mpGLView = [[MPlayerOpenGLView alloc] initWithFrame:NSMakeRect(0, 0, 100, 100) pixelFormat:[MPlayerOpenGLView defaultPixelFormat]];
309                         [mpGLView autorelease];
310                 }
311         
312                 [mpGLView display];
313                 [mpGLView preinit];
314         }
315         
316     return 0;
319 static int control(uint32_t request, void *data, ...)
321         switch (request)
322         {
323                 case VOCTRL_PAUSE: return (int_pause=1);
324                 case VOCTRL_RESUME: return (int_pause=0);
325                 case VOCTRL_QUERY_FORMAT: return query_format(*((uint32_t*)data));
326                 case VOCTRL_ONTOP: vo_ontop = (!(vo_ontop)); if(!shared_buffer){ [mpGLView ontop]; } else { [mplayerosxProxy ontop]; } return VO_TRUE;
327                 case VOCTRL_ROOTWIN: vo_rootwin = (!(vo_rootwin)); [mpGLView rootwin]; return VO_TRUE;
328                 case VOCTRL_FULLSCREEN: vo_fs = (!(vo_fs)); if(!shared_buffer){ [mpGLView fullscreen: NO]; } else { [mplayerosxProxy toggleFullscreen]; } return VO_TRUE;
329                 case VOCTRL_GET_PANSCAN: return VO_TRUE;
330                 case VOCTRL_SET_PANSCAN: [mpGLView panscan]; return VO_TRUE;
331         }
332         return VO_NOTIMPL;
335 //////////////////////////////////////////////////////////////////////////
336 // NSOpenGLView Subclass
337 //////////////////////////////////////////////////////////////////////////
338 @implementation MPlayerOpenGLView
339 - (void) preinit
341         //init menu
342         [self initMenu];
343         
344         //create window
345         window = [[NSWindow alloc]      initWithContentRect:NSMakeRect(0, 0, 100, 100) 
346                                                                 styleMask:NSTitledWindowMask|NSTexturedBackgroundWindowMask|NSClosableWindowMask|NSMiniaturizableWindowMask|NSResizableWindowMask
347                                                                 backing:NSBackingStoreBuffered defer:NO];
349         [window autorelease];
350         [window setDelegate:mpGLView];
351         [window setContentView:mpGLView];
352         [window setInitialFirstResponder:mpGLView];
353         [window setAcceptsMouseMovedEvents:YES];
354     [window setTitle:@"MPlayer - The Movie Player"];
355         
356         isFullscreen = 0;
357         winSizeMult = 1;
360 - (void) config
362         uint32_t d_width;
363         uint32_t d_height;
364         
365         long swapInterval = 1;
366         
367         NSRect frame;
368         CVReturn error = kCVReturnSuccess;
369         
370         //config window
371         aspect((int *)&d_width, (int *)&d_height,A_NOZOOM);
372         frame = NSMakeRect(0, 0, d_width, d_height);
373         [window setContentSize: frame.size];
374         
375         //create OpenGL Context
376         glContext = [[NSOpenGLContext alloc] initWithFormat:[NSOpenGLView defaultPixelFormat] shareContext:nil];        
377         
378         [self setOpenGLContext:glContext];
379         [glContext setValues:&swapInterval forParameter:NSOpenGLCPSwapInterval];
380         [glContext setView:self];
381         [glContext makeCurrentContext]; 
382         
383         error = CVPixelBufferCreateWithBytes( NULL, image_width, image_height, pixelFormat, image_data, image_width*image_bytes, NULL, NULL, NULL, &currentFrameBuffer);
384         if(error != kCVReturnSuccess)
385                 mp_msg(MSGT_VO, MSGL_ERR,"Failed to create Pixel Buffer(%d)\n", error);
386         
387         error = CVOpenGLTextureCacheCreate(NULL, 0, [glContext CGLContextObj], [[self pixelFormat] CGLPixelFormatObj], 0, &textureCache);
388         if(error != kCVReturnSuccess)
389                 mp_msg(MSGT_VO, MSGL_ERR,"Failed to create OpenGL texture Cache(%d)\n", error);
390         
391         error = CVOpenGLTextureCacheCreateTextureFromImage(     NULL, textureCache, currentFrameBuffer, 0, &texture);
392         if(error != kCVReturnSuccess)
393                 mp_msg(MSGT_VO, MSGL_ERR,"Failed to create OpenGL texture(%d)\n", error);
394         
395         //show window
396         [window center];
397         [window makeKeyAndOrderFront:mpGLView];
398         
399         if(vo_rootwin)
400                 [mpGLView rootwin];     
402         if(vo_fs)
403                 [mpGLView fullscreen: NO];
404         
405         if(vo_ontop)
406                 [mpGLView ontop];
410         Init Menu
412 - (void)initMenu
414         NSMenu *menu, *aspectMenu;
415         NSMenuItem *menuItem;
416         
417         [NSApp setMainMenu:[[NSMenu alloc] init]];
419 //Create Movie Menu
420         menu = [[NSMenu alloc] initWithTitle:@"Movie"];
421         menuItem = [[NSMenuItem alloc] initWithTitle:@"Half Size" action:@selector(menuAction:) keyEquivalent:@"0"]; [menu addItem:menuItem];
422         kHalfScreenCmd = menuItem;
423         menuItem = [[NSMenuItem alloc] initWithTitle:@"Normal Size" action:@selector(menuAction:) keyEquivalent:@"1"]; [menu addItem:menuItem];
424         kNormalScreenCmd = menuItem;
425         menuItem = [[NSMenuItem alloc] initWithTitle:@"Double Size" action:@selector(menuAction:) keyEquivalent:@"2"]; [menu addItem:menuItem];
426         kDoubleScreenCmd = menuItem;
427         menuItem = [[NSMenuItem alloc] initWithTitle:@"Full Size" action:@selector(menuAction:) keyEquivalent:@"f"]; [menu addItem:menuItem];
428         kFullScreenCmd = menuItem;
429         menuItem = (NSMenuItem *)[NSMenuItem separatorItem]; [menu addItem:menuItem];
430         
431                 aspectMenu = [[NSMenu alloc] initWithTitle:@"Aspect Ratio"];
432                 menuItem = [[NSMenuItem alloc] initWithTitle:@"Keep" action:@selector(menuAction:) keyEquivalent:@""]; [aspectMenu addItem:menuItem];
433                 if(vo_keepaspect) [menuItem setState:NSOnState];
434                 kKeepAspectCmd = menuItem;
435                 menuItem = [[NSMenuItem alloc] initWithTitle:@"Pan-Scan" action:@selector(menuAction:) keyEquivalent:@""]; [aspectMenu addItem:menuItem];
436                 if(vo_panscan) [menuItem setState:NSOnState];
437                 kPanScanCmd = menuItem;
438                 menuItem = (NSMenuItem *)[NSMenuItem separatorItem]; [aspectMenu addItem:menuItem];
439                 menuItem = [[NSMenuItem alloc] initWithTitle:@"Original" action:@selector(menuAction:) keyEquivalent:@""]; [aspectMenu addItem:menuItem];
440                 kAspectOrgCmd = menuItem;
441                 menuItem = [[NSMenuItem alloc] initWithTitle:@"4:3" action:@selector(menuAction:) keyEquivalent:@""]; [aspectMenu addItem:menuItem];
442                 kAspectFullCmd = menuItem;
443                 menuItem = [[NSMenuItem alloc] initWithTitle:@"16:9" action:@selector(menuAction:) keyEquivalent:@""];  [aspectMenu addItem:menuItem];
444                 kAspectWideCmd = menuItem;
445                 menuItem = [[NSMenuItem alloc] initWithTitle:@"Aspect Ratio" action:nil keyEquivalent:@""];
446                 [menuItem setSubmenu:aspectMenu];
447                 [menu addItem:menuItem];
448                 [aspectMenu release];
449         
450         //Add to menubar
451         menuItem = [[NSMenuItem alloc] initWithTitle:@"Movie" action:nil keyEquivalent:@""];
452         [menuItem setSubmenu:menu];
453         [[NSApp mainMenu] addItem:menuItem];
454         
455 //Create Window Menu
456         menu = [[NSMenu alloc] initWithTitle:@"Window"];
457         
458         menuItem = [[NSMenuItem alloc] initWithTitle:@"Minimize" action:@selector(performMiniaturize:) keyEquivalent:@"m"]; [menu addItem:menuItem];
459         menuItem = [[NSMenuItem alloc] initWithTitle:@"Zoom" action:@selector(performZoom:) keyEquivalent:@""]; [menu addItem:menuItem];
461         //Add to menubar
462         menuItem = [[NSMenuItem alloc] initWithTitle:@"Window" action:nil keyEquivalent:@""];
463         [menuItem setSubmenu:menu];
464         [[NSApp mainMenu] addItem:menuItem];
465         [NSApp setWindowsMenu:menu];
466         
467         [menu release];
468         [menuItem release];
472         Menu Action
473  */
474 - (void)menuAction:(id)sender
476         uint32_t d_width;
477         uint32_t d_height;
478         NSRect frame;
479         
480         aspect((int *)&d_width, (int *)&d_height,A_NOZOOM);
481         
482         if(sender == kQuitCmd)
483         {
484                 mplayer_put_key(KEY_ESC);
485         }
486         
487         if(sender == kHalfScreenCmd)
488         {
489                 if(isFullscreen) {
490                         vo_fs = (!(vo_fs)); [self fullscreen:NO];
491                 }
492                 
493                 winSizeMult = 0.5;
494                 frame.size.width = (d_width*winSizeMult);
495                 frame.size.height = ((d_width/movie_aspect)*winSizeMult);
496                 [window setContentSize: frame.size];
497                 [self reshape];
498         }
499         if(sender == kNormalScreenCmd)
500         {
501                 if(isFullscreen) {
502                         vo_fs = (!(vo_fs)); [self fullscreen:NO];
503                 }
504                 
505                 winSizeMult = 1;
506                 frame.size.width = d_width;
507                 frame.size.height = d_width/movie_aspect;
508                 [window setContentSize: frame.size];
509                 [self reshape];
510         }
511         if(sender == kDoubleScreenCmd)
512         {
513                 if(isFullscreen) {
514                         vo_fs = (!(vo_fs)); [self fullscreen:NO];
515                 }
516                 
517                 winSizeMult = 2;
518                 frame.size.width = d_width*winSizeMult;
519                 frame.size.height = (d_width/movie_aspect)*winSizeMult;
520                 [window setContentSize: frame.size];
521                 [self reshape];
522         }
523         if(sender == kFullScreenCmd)
524         {
525                 vo_fs = (!(vo_fs));
526                 [self fullscreen:NO];
527         }
529         if(sender == kKeepAspectCmd)
530         {
531                 vo_keepaspect = (!(vo_keepaspect));
532                 if(vo_keepaspect)
533                         [kKeepAspectCmd setState:NSOnState];
534                 else
535                         [kKeepAspectCmd setState:NSOffState];
536                         
537                 [self reshape];
538         }
539         
540         if(sender == kPanScanCmd)
541         {
542                 vo_panscan = (!(vo_panscan));
543                 if(vo_panscan)
544                         [kPanScanCmd setState:NSOnState];
545                 else
546                         [kPanScanCmd setState:NSOffState];
547                         
548                 [self panscan];
549         }
550         
551         if(sender == kAspectOrgCmd)
552         {
553                 movie_aspect = old_movie_aspect;
554                 
555                 if(isFullscreen)
556                 {
557                         [self reshape];
558                 }
559                 else
560                 {
561                         frame.size.width = d_width*winSizeMult;
562                         frame.size.height = (d_width/movie_aspect)*winSizeMult;
563                         [window setContentSize: frame.size];
564                         [self reshape];
565                 }
566         }
567         
568         if(sender == kAspectFullCmd)
569         {
570                 movie_aspect = 4.0f/3.0f;
571                 
572                 if(isFullscreen)
573                 {
574                         [self reshape];
575                 }
576                 else
577                 {
578                         frame.size.width = d_width*winSizeMult;
579                         frame.size.height = (d_width/movie_aspect)*winSizeMult;
580                         [window setContentSize: frame.size];
581                         [self reshape];
582                 }
583         }
584                 
585         if(sender == kAspectWideCmd)
586         {
587                 movie_aspect = 16.0f/9.0f;
589                 if(isFullscreen)
590                 {
591                         [self reshape];
592                 }
593                 else
594                 {
595                         frame.size.width = d_width*winSizeMult;
596                         frame.size.height = (d_width/movie_aspect)*winSizeMult;
597                         [window setContentSize: frame.size];
598                         [self reshape];
599                 }
600         }
604         Setup OpenGL
606 - (void)prepareOpenGL
608         glEnable(GL_BLEND); 
609         glDisable(GL_DEPTH_TEST);
610         glDepthMask(GL_FALSE);
611         glDisable(GL_CULL_FACE);
612         [self reshape];
616         reshape OpenGL viewport
617 */ 
618 - (void)reshape
620         uint32_t d_width;
621         uint32_t d_height;
622         float aspectX;
623         float aspectY;
624         int padding = 0;
625         
626         NSRect frame = [self frame];
627         
628         glViewport(0, 0, frame.size.width, frame.size.height);
629         glMatrixMode(GL_PROJECTION);
630         glLoadIdentity();
631         glOrtho(0, frame.size.width, frame.size.height, 0, -1.0, 1.0);
632         glMatrixMode(GL_MODELVIEW);
633         glLoadIdentity();
634         
635         //set texture frame
636         if(vo_keepaspect)
637         {
638                 aspect( (int *)&d_width, (int *)&d_height, A_NOZOOM);
639                 d_height = ((float)d_width/movie_aspect);
640                 
641                 aspectX = (float)((float)frame.size.width/(float)d_width);
642                 aspectY = (float)((float)(frame.size.height)/(float)d_height);
643                 
644                 if((d_height*aspectX)>(frame.size.height))
645                 {
646                         padding = (frame.size.width - d_width*aspectY)/2;
647                         textureFrame = NSMakeRect(padding, 0, d_width*aspectY+padding, d_height*aspectY);
648                 }
649                 else
650                 {
651                         padding = ((frame.size.height) - d_height*aspectX)/2;
652                         textureFrame = NSMakeRect(0, padding, d_width*aspectX, d_height*aspectX+padding);
653                 }
654         }
655         else
656         {
657                 textureFrame = frame;
658         }
662         Render frame
663 */ 
664 - (void) render
666         int curTime;
667         static int lastTime = 0;
669         glClear(GL_COLOR_BUFFER_BIT);   
670         
671         glEnable(CVOpenGLTextureGetTarget(texture));
672         glBindTexture(CVOpenGLTextureGetTarget(texture), CVOpenGLTextureGetName(texture));
673         
674         glColor3f(1,1,1);
675         glBegin(GL_QUADS);
676         glTexCoord2f(upperLeft[0], upperLeft[1]); glVertex2i(   textureFrame.origin.x-(vo_panscan_x >> 1), textureFrame.origin.y-(vo_panscan_y >> 1));
677         glTexCoord2f(lowerLeft[0], lowerLeft[1]); glVertex2i(   textureFrame.origin.x-(vo_panscan_x >> 1), textureFrame.size.height+(vo_panscan_y >> 1));
678         glTexCoord2f(lowerRight[0], lowerRight[1]); glVertex2i( textureFrame.size.width+(vo_panscan_x >> 1), textureFrame.size.height+(vo_panscan_y >> 1));
679         glTexCoord2f(upperRight[0], upperRight[1]); glVertex2i( textureFrame.size.width+(vo_panscan_x >> 1), textureFrame.origin.y-(vo_panscan_y >> 1));
680         glEnd();
681         glDisable(CVOpenGLTextureGetTarget(texture));
682         
683         //render resize box
684         if(!isFullscreen)
685         {
686                 NSRect frame = [self frame];
687                 
688                 glBegin(GL_LINES);
689                 glColor4f(0.2, 0.2, 0.2, 0.5);
690                 glVertex2i(frame.size.width-1, frame.size.height-1); glVertex2i(frame.size.width-1, frame.size.height-1);
691                 glVertex2i(frame.size.width-1, frame.size.height-5); glVertex2i(frame.size.width-5, frame.size.height-1);
692                 glVertex2i(frame.size.width-1, frame.size.height-9); glVertex2i(frame.size.width-9, frame.size.height-1);
694                 glColor4f(0.4, 0.4, 0.4, 0.5);
695                 glVertex2i(frame.size.width-1, frame.size.height-2); glVertex2i(frame.size.width-2, frame.size.height-1);
696                 glVertex2i(frame.size.width-1, frame.size.height-6); glVertex2i(frame.size.width-6, frame.size.height-1);
697                 glVertex2i(frame.size.width-1, frame.size.height-10); glVertex2i(frame.size.width-10, frame.size.height-1);
698                 
699                 glColor4f(0.6, 0.6, 0.6, 0.5);
700                 glVertex2i(frame.size.width-1, frame.size.height-3); glVertex2i(frame.size.width-3, frame.size.height-1);
701                 glVertex2i(frame.size.width-1, frame.size.height-7); glVertex2i(frame.size.width-7, frame.size.height-1);
702                 glVertex2i(frame.size.width-1, frame.size.height-11); glVertex2i(frame.size.width-11, frame.size.height-1);
703                 glEnd();
704         }
705         
706         glFlush();
707         
708         //auto hide mouse cursor and futur on-screen control?
709         if(isFullscreen && !mouseHide && !isRootwin)
710         {
711                 int curTime = TickCount()/60;
712                 static int lastTime = 0;
713                 
714                 if( ((curTime - lastTime) >= 5) || (lastTime == 0) )
715                 {
716                         CGDisplayHideCursor(kCGDirectMainDisplay);
717                         mouseHide = YES;
718                         lastTime = curTime;
719                 }
720         }
721         
722         //update activity every 30 seconds to prevent
723         //screensaver from starting up.
724         curTime  = TickCount()/60;
725                 
726         if( ((curTime - lastTime) >= 30) || (lastTime == 0) )
727         {
728                 UpdateSystemActivity(UsrActivity);
729                 lastTime = curTime;
730         }
734         Create OpenGL texture from current frame & set texco 
735 */ 
736 - (void) setCurrentTexture
738         CVReturn error = kCVReturnSuccess;
739         
740         error = CVOpenGLTextureCacheCreateTextureFromImage (NULL, textureCache,  currentFrameBuffer,  0, &texture);
741         if(error != kCVReturnSuccess)
742                 mp_msg(MSGT_VO, MSGL_ERR,"Failed to create OpenGL texture(%d)\n", error);
744     CVOpenGLTextureGetCleanTexCoords(texture, lowerLeft, lowerRight, upperRight, upperLeft);
748         redraw win rect
749 */ 
750 - (void) drawRect: (NSRect *) bounds
752         [self render];
756         Toggle Fullscreen
758 - (void) fullscreen: (BOOL) animate
760         static NSRect old_frame;
761         static NSRect old_view_frame;
762         
763         if(screen_force)
764                 screen_frame = [screen_handle frame];
765         else
766                 screen_frame = [[window screen] frame];
768         panscan_calc();
769                         
770         //go fullscreen
771         if(vo_fs)
772         {
773                 if(!isRootwin)
774                 {
775                         SetSystemUIMode( kUIModeAllHidden, kUIOptionAutoShowMenuBar);
776                         CGDisplayHideCursor(kCGDirectMainDisplay);
777                         mouseHide = YES;
778                 }
779                 
780                 old_frame = [window frame];     //save main window size & position
781                 [window setFrame:screen_frame display:YES animate:animate]; //zoom-in window with nice useless sfx
782                 old_view_frame = [self bounds];
783                 
784                 //fix origin for multi screen setup
785                 screen_frame.origin.x = 0;
786                 screen_frame.origin.y = 0;
787                 [self setFrame:screen_frame];
788                 [self setNeedsDisplay:YES];
789                 [window setHasShadow:NO];
790                 isFullscreen = 1;
791         }
792         else
793         {       
794                 SetSystemUIMode( kUIModeNormal, 0);
795                 
796                 isFullscreen = 0;
797                 CGDisplayShowCursor(kCGDirectMainDisplay);
798                 mouseHide = NO;
800                 //revert window to previous setting
801                 [self setFrame:old_view_frame];
802                 [self setNeedsDisplay:YES];
803                 [window setHasShadow:YES];
804                 [window setFrame:old_frame display:YES animate:animate];//zoom-out window with nice useless sfx
805         }
809         Toggle ontop
811 - (void) ontop
813         if(vo_ontop)
814         {
815                 [window setLevel:NSScreenSaverWindowLevel];
816                 isOntop = YES;
817         }
818         else
819         {
820                 [window setLevel:NSNormalWindowLevel];
821                 isOntop = NO;
822         }
826         Toggle panscan
828 - (void) panscan
830         panscan_calc();
834         Toggle rootwin
835  */
836 - (void) rootwin
838         if(vo_rootwin)
839         {
840                 [window setLevel:CGWindowLevelForKey(kCGDesktopWindowLevelKey)];
841                 [window orderBack:self];
842                 isRootwin = YES;
843         }
844         else
845         {
846                 [window setLevel:NSNormalWindowLevel];
847                 isRootwin = NO;
848         }
852         Check event for new event
853 */ 
854 - (void) check_events
856         event = [NSApp nextEventMatchingMask:NSAnyEventMask untilDate:[NSDate dateWithTimeIntervalSinceNow:0.0001] inMode:NSEventTrackingRunLoopMode dequeue:YES];
857         [NSApp sendEvent:event];
861         From NSView, respond to key equivalents.
863 - (BOOL)performKeyEquivalent:(NSEvent *)theEvent
865         switch([theEvent keyCode])
866     {
867                 case 0x21: [window setAlphaValue: winAlpha-=0.05]; return YES;
868                 case 0x1e: [window setAlphaValue: winAlpha+=0.05]; return YES;
869     }
870         return NO;
874         Process key event
876 - (void) keyDown: (NSEvent *) theEvent
878         unsigned int key;
879         
880         switch([theEvent keyCode])
881     {
882                 case 0x34:
883                 case 0x24: key = KEY_ENTER; break;
884                 case 0x35: key = KEY_ESC; break;
885                 case 0x33: key = KEY_BACKSPACE; break;
886                 case 0x3A: key = KEY_BACKSPACE; break;
887                 case 0x3B: key = KEY_BACKSPACE; break;
888                 case 0x38: key = KEY_BACKSPACE; break;
889                 case 0x7A: key = KEY_F+1; break;
890                 case 0x78: key = KEY_F+2; break;
891                 case 0x63: key = KEY_F+3; break;
892                 case 0x76: key = KEY_F+4; break;
893                 case 0x60: key = KEY_F+5; break;
894                 case 0x61: key = KEY_F+6; break;
895                 case 0x62: key = KEY_F+7; break;
896                 case 0x64: key = KEY_F+8; break;
897                 case 0x65: key = KEY_F+9; break;
898                 case 0x6D: key = KEY_F+10; break;
899                 case 0x67: key = KEY_F+11; break;
900                 case 0x6F: key = KEY_F+12; break;
901                 case 0x72: key = KEY_INSERT; break;
902                 case 0x75: key = KEY_DELETE; break;
903                 case 0x73: key = KEY_HOME; break;
904                 case 0x77: key = KEY_END; break;
905                 case 0x45: key = '+'; break;
906                 case 0x4E: key = '-'; break;
907                 case 0x30: key = KEY_TAB; break;
908                 case 0x74: key = KEY_PAGE_UP; break;
909                 case 0x79: key = KEY_PAGE_DOWN; break;  
910                 case 0x7B: key = KEY_LEFT; break;
911                 case 0x7C: key = KEY_RIGHT; break;
912                 case 0x7D: key = KEY_DOWN; break;
913                 case 0x7E: key = KEY_UP; break;
914                 case 0x43: key = '*'; break;
915                 case 0x4B: key = '/'; break;
916                 case 0x4C: key = KEY_KPENTER; break;
917                 case 0x41: key = KEY_KPDEC; break;
918                 case 0x52: key = KEY_KP0; break;
919                 case 0x53: key = KEY_KP1; break;
920                 case 0x54: key = KEY_KP2; break;
921                 case 0x55: key = KEY_KP3; break;
922                 case 0x56: key = KEY_KP4; break;
923                 case 0x57: key = KEY_KP5; break;
924                 case 0x58: key = KEY_KP6; break;
925                 case 0x59: key = KEY_KP7; break;
926                 case 0x5B: key = KEY_KP8; break;
927                 case 0x5C: key = KEY_KP9; break;
928                 default: key = *[[theEvent characters] UTF8String]; break;
929     }
930         mplayer_put_key(key);
934         Process mouse button event
936 - (void) mouseMoved: (NSEvent *) theEvent
938         if(isFullscreen && !isRootwin)
939         {
940                 CGDisplayShowCursor(kCGDirectMainDisplay);
941                 mouseHide = NO;
942         }
945 - (void) mouseDown: (NSEvent *) theEvent
947         [self mouseEvent: theEvent];
950 - (void) mouseUp: (NSEvent *) theEvent
952         [self mouseEvent: theEvent];
955 - (void) rightMouseDown: (NSEvent *) theEvent
957         [self mouseEvent: theEvent];
960 - (void) rightMouseUp: (NSEvent *) theEvent
962         [self mouseEvent: theEvent];
965 - (void) otherMouseDown: (NSEvent *) theEvent
967         [self mouseEvent: theEvent];
970 - (void) otherMouseUp: (NSEvent *) theEvent
972         [self mouseEvent: theEvent];
975 - (void) scrollWheel: (NSEvent *) theEvent
977         if([theEvent deltaY] > 0)
978                 mplayer_put_key(MOUSE_BTN3);
979         else
980                 mplayer_put_key(MOUSE_BTN4);
983 - (void) mouseEvent: (NSEvent *) theEvent
985         if ( [theEvent buttonNumber] >= 0 && [theEvent buttonNumber] <= 9 )
986         {
987                 switch([theEvent type])
988                 {
989                         case NSLeftMouseDown:
990                         case NSRightMouseDown:
991                         case NSOtherMouseDown:
992                                 mplayer_put_key((MOUSE_BTN0 + [theEvent buttonNumber]) | MP_KEY_DOWN);
993                                 break;
994                         case NSLeftMouseUp:
995                         case NSRightMouseUp:
996                         case NSOtherMouseUp:
997                                 mplayer_put_key(MOUSE_BTN0 + [theEvent buttonNumber]);
998                                 break;
999                 }
1000         }
1004         NSResponder
1005 */ 
1006 - (BOOL) acceptsFirstResponder
1008         return YES;
1011 - (BOOL) becomeFirstResponder
1013         return YES;
1016 - (BOOL) resignFirstResponder
1018         return YES;
1021 - (void)windowWillClose:(NSNotification *)aNotification
1023     mpGLView = NULL;
1024         mplayer_put_key(KEY_ESC);
1026 @end