1000l, play_tree_parser_stop_keeping broke 0-termination of buffer
[mplayer/glamo.git] / libvo / vo_quartz.c
blobb649c442b46b00a2e2d75785c227a7e63a204098
1 /**
2 \author Nicolas Plourde <nicolasplourde@gmail.com>
4 Copyright (c) Nicolas Plourde - April 2004
6 YUV support Copyright (C) 2004 Romain Dolbeau <romain@dolbeau.org>
8 \brief MPlayer Mac OSX Quartz video out module.
10 \todo: -screen overlay output
11 -fit osd in black bar when available
12 -fix RGB32
13 -(add sugestion here)
16 //SYS
17 #include <stdio.h>
19 //OSX
20 #include <Carbon/Carbon.h>
21 #include <QuickTime/QuickTime.h>
23 //MPLAYER
24 #include "config.h"
25 #include "fastmemcpy.h"
26 #include "video_out.h"
27 #include "video_out_internal.h"
28 #include "aspect.h"
29 #include "mp_msg.h"
30 #include "m_option.h"
31 #include "mp_fifo.h"
32 #include "mpbswap.h"
33 #include "sub.h"
35 #include "input/input.h"
36 #include "input/mouse.h"
38 #include "vo_quartz.h"
40 static const vo_info_t info =
42 "Mac OSX (Quartz)",
43 "quartz",
44 "Nicolas Plourde <nicolasplourde@hotmail.com>, Romain Dolbeau <romain@dolbeau.org>",
48 const LIBVO_EXTERN(quartz)
50 static uint32_t image_depth;
51 static uint32_t image_format;
52 static uint32_t image_size;
53 static uint32_t image_buffer_size;
54 static char *image_data;
56 static ImageSequence seqId;
57 static CodecType image_qtcodec;
58 static PlanarPixmapInfoYUV420 *P = NULL;
59 static struct
61 ImageDescriptionHandle desc;
62 Handle extension_colr;
63 Handle extension_fiel;
64 Handle extension_clap;
65 Handle extension_pasp;
66 } yuv_qt_stuff;
67 static MatrixRecord matrix;
68 static int EnterMoviesDone = 0;
69 static int get_image_done = 0;
71 static int vo_quartz_fs; // we are in fullscreen
72 extern float monitor_aspect;
73 extern float movie_aspect;
74 static float old_movie_aspect;
76 static int winLevel = 1;
77 int levelList[] =
79 kCGDesktopWindowLevelKey,
80 kCGNormalWindowLevelKey,
81 kCGScreenSaverWindowLevelKey
84 static int int_pause = 0;
85 static float winAlpha = 1;
86 static int mouseHide = FALSE;
88 static int device_id = 0;
90 static short fs_res_x = 0;
91 static short fs_res_y = 0;
93 static WindowRef theWindow = NULL;
94 static WindowGroupRef winGroup = NULL;
95 static CGRect bounds;
96 static CGDirectDisplayID displayId = 0;
97 static CFDictionaryRef originalMode = NULL;
99 static CGDataProviderRef dataProviderRef = NULL;
100 static CGImageRef image = NULL;
102 static Rect imgRect; // size of the original image (unscaled)
103 static Rect dstRect; // size of the displayed image (after scaling)
104 static Rect winRect; // size of the window containg the displayed image (include padding)
105 static Rect oldWinRect; // size of the window containg the displayed image (include padding) when NOT in FS mode
106 static CGRect displayRect; // size of the display device
107 static Rect oldWinBounds;
109 static MenuRef windMenu;
110 static MenuRef movMenu;
111 static MenuRef aspectMenu;
113 static int lastScreensaverUpdate = 0;
114 static int lastMouseHide = 0;
116 enum
118 kQuitCmd = 1,
119 kHalfScreenCmd = 2,
120 kNormalScreenCmd = 3,
121 kDoubleScreenCmd = 4,
122 kFullScreenCmd = 5,
123 kKeepAspectCmd = 6,
124 kAspectOrgCmd = 7,
125 kAspectFullCmd = 8,
126 kAspectWideCmd = 9,
127 kPanScanCmd = 10
130 #include "osdep/keycodes.h"
132 //PROTOTYPE/////////////////////////////////////////////////////////////////
133 static OSStatus KeyEventHandler(EventHandlerCallRef nextHandler, EventRef event, void *userData);
134 static OSStatus MouseEventHandler(EventHandlerCallRef nextHandler, EventRef event, void *userData);
135 static OSStatus WindowEventHandler(EventHandlerCallRef nextHandler, EventRef event, void *userData);
136 void window_resized();
137 void window_ontop();
138 void window_fullscreen();
139 void window_panscan();
141 static inline int convert_key(UInt32 key, UInt32 charcode)
143 switch (key)
145 case QZ_IBOOK_ENTER:
146 case QZ_RETURN: return KEY_ENTER;
147 case QZ_ESCAPE: return KEY_ESC;
148 case QZ_BACKSPACE: return KEY_BACKSPACE;
149 case QZ_LALT: return KEY_BACKSPACE;
150 case QZ_LCTRL: return KEY_BACKSPACE;
151 case QZ_LSHIFT: return KEY_BACKSPACE;
152 case QZ_F1: return KEY_F + 1;
153 case QZ_F2: return KEY_F + 2;
154 case QZ_F3: return KEY_F + 3;
155 case QZ_F4: return KEY_F + 4;
156 case QZ_F5: return KEY_F + 5;
157 case QZ_F6: return KEY_F + 6;
158 case QZ_F7: return KEY_F + 7;
159 case QZ_F8: return KEY_F + 8;
160 case QZ_F9: return KEY_F + 9;
161 case QZ_F10: return KEY_F + 10;
162 case QZ_F11: return KEY_F + 11;
163 case QZ_F12: return KEY_F + 12;
164 case QZ_INSERT: return KEY_INSERT;
165 case QZ_DELETE: return KEY_DELETE;
166 case QZ_HOME: return KEY_HOME;
167 case QZ_END: return KEY_END;
168 case QZ_KP_PLUS: return '+';
169 case QZ_KP_MINUS: return '-';
170 case QZ_TAB: return KEY_TAB;
171 case QZ_PAGEUP: return KEY_PAGE_UP;
172 case QZ_PAGEDOWN: return KEY_PAGE_DOWN;
173 case QZ_UP: return KEY_UP;
174 case QZ_DOWN: return KEY_DOWN;
175 case QZ_LEFT: return KEY_LEFT;
176 case QZ_RIGHT: return KEY_RIGHT;
177 case QZ_KP_MULTIPLY: return '*';
178 case QZ_KP_DIVIDE: return '/';
179 case QZ_KP_ENTER: return KEY_KPENTER;
180 case QZ_KP_PERIOD: return KEY_KPDEC;
181 case QZ_KP0: return KEY_KP0;
182 case QZ_KP1: return KEY_KP1;
183 case QZ_KP2: return KEY_KP2;
184 case QZ_KP3: return KEY_KP3;
185 case QZ_KP4: return KEY_KP4;
186 case QZ_KP5: return KEY_KP5;
187 case QZ_KP6: return KEY_KP6;
188 case QZ_KP7: return KEY_KP7;
189 case QZ_KP8: return KEY_KP8;
190 case QZ_KP9: return KEY_KP9;
191 default: return charcode;
195 static void draw_alpha(int x0, int y0, int w, int h, unsigned char *src, unsigned char *srca, int stride)
197 switch (image_format)
199 case IMGFMT_RGB32:
200 vo_draw_alpha_rgb32(w, h, src, srca, stride, image_data + 4 * (y0 * imgRect.right + x0), 4 * imgRect.right);
201 break;
202 case IMGFMT_YV12:
203 case IMGFMT_IYUV:
204 case IMGFMT_I420:
205 vo_draw_alpha_yv12(w, h, src, srca, stride, ((char *)P) + be2me_32(P->componentInfoY.offset) + x0 + y0 * imgRect.right, imgRect.right);
206 break;
207 case IMGFMT_UYVY:
208 vo_draw_alpha_uyvy(w, h, src, srca, stride, ((char *)P) + (x0 + y0 * imgRect.right) * 2, imgRect.right * 2);
209 break;
210 case IMGFMT_YUY2:
211 vo_draw_alpha_yuy2(w, h, src, srca, stride, ((char *)P) + (x0 + y0 * imgRect.right) * 2, imgRect.right * 2);
212 break;
216 //default keyboard event handler
217 static OSStatus KeyEventHandler(EventHandlerCallRef nextHandler, EventRef event, void *userData)
219 OSStatus result = noErr;
220 UInt32 class = GetEventClass(event);
221 UInt32 kind = GetEventKind(event);
223 result = CallNextEventHandler(nextHandler, event);
225 if (class == kEventClassKeyboard)
227 char macCharCodes;
228 UInt32 macKeyCode;
229 UInt32 macKeyModifiers;
231 GetEventParameter(event, kEventParamKeyMacCharCodes, typeChar, NULL, sizeof(macCharCodes), NULL, &macCharCodes);
232 GetEventParameter(event, kEventParamKeyCode, typeUInt32, NULL, sizeof(macKeyCode), NULL, &macKeyCode);
233 GetEventParameter(event, kEventParamKeyModifiers, typeUInt32, NULL, sizeof(macKeyModifiers), NULL, &macKeyModifiers);
235 if (macKeyModifiers != 256)
237 if (kind == kEventRawKeyRepeat || kind == kEventRawKeyDown)
239 int key = convert_key(macKeyCode, macCharCodes);
241 if (key != -1)
242 mplayer_put_key(key);
245 else if (macKeyModifiers == 256)
247 switch (macCharCodes)
249 case '[': SetWindowAlpha(theWindow, winAlpha -= 0.05); break;
250 case ']': SetWindowAlpha(theWindow, winAlpha += 0.05); break;
253 else
254 result = eventNotHandledErr;
257 return result;
260 //default mouse event handler
261 static OSStatus MouseEventHandler(EventHandlerCallRef nextHandler, EventRef event, void *userData)
263 OSStatus result = noErr;
264 UInt32 class = GetEventClass(event);
265 UInt32 kind = GetEventKind(event);
267 result = CallNextEventHandler(nextHandler, event);
269 if (class == kEventClassMouse)
271 WindowPtr tmpWin;
272 Point mousePos;
273 Point winMousePos;
275 GetEventParameter(event, kEventParamMouseLocation, typeQDPoint, 0, sizeof(Point), 0, &mousePos);
276 GetEventParameter(event, kEventParamWindowMouseLocation, typeQDPoint, 0, sizeof(Point), 0, &winMousePos);
278 switch (kind)
280 case kEventMouseMoved:
282 if (vo_quartz_fs)
284 CGDisplayShowCursor(displayId);
285 mouseHide = FALSE;
288 break;
290 case kEventMouseWheelMoved:
292 int wheel;
293 short part;
295 GetEventParameter(event, kEventParamMouseWheelDelta, typeSInt32, 0, sizeof(int), 0, &wheel);
297 part = FindWindow(mousePos, &tmpWin);
299 if (part == inContent)
301 if (wheel > 0)
302 mplayer_put_key(MOUSE_BTN3);
303 else
304 mplayer_put_key(MOUSE_BTN4);
307 break;
309 case kEventMouseDown:
310 case kEventMouseUp:
312 EventMouseButton button;
313 short part;
314 Rect bounds;
316 GetWindowPortBounds(theWindow, &bounds);
317 GetEventParameter(event, kEventParamMouseButton, typeMouseButton, 0, sizeof(EventMouseButton), 0, &button);
319 part = FindWindow(mousePos, &tmpWin);
320 if (kind == kEventMouseUp)
322 if (part != inContent)
323 break;
324 switch (button)
326 case kEventMouseButtonPrimary:
327 mplayer_put_key(MOUSE_BTN0);
328 break;
329 case kEventMouseButtonSecondary:
330 mplayer_put_key(MOUSE_BTN2);
331 break;
332 case kEventMouseButtonTertiary:
333 mplayer_put_key(MOUSE_BTN1);
334 break;
336 default:
337 result = eventNotHandledErr;
338 break;
340 break;
342 if ((winMousePos.h > (bounds.right - 15)) && (winMousePos.v > (bounds.bottom)))
344 if (!vo_quartz_fs)
346 Rect newSize;
348 ResizeWindow(theWindow, mousePos, NULL, &newSize);
351 else if (part == inMenuBar)
353 MenuSelect(mousePos);
354 HiliteMenu(0);
356 else if (part == inContent)
358 switch (button)
360 case kEventMouseButtonPrimary:
361 mplayer_put_key(MOUSE_BTN0 | MP_KEY_DOWN);
362 break;
363 case kEventMouseButtonSecondary:
364 mplayer_put_key(MOUSE_BTN2 | MP_KEY_DOWN);
365 break;
366 case kEventMouseButtonTertiary:
367 mplayer_put_key(MOUSE_BTN1 | MP_KEY_DOWN);
368 break;
370 default:
371 result = eventNotHandledErr;
372 break;
376 break;
378 case kEventMouseDragged:
379 break;
381 default:
382 result = eventNotHandledErr;
383 break;
387 return result;
390 //default window event handler
391 static OSStatus WindowEventHandler(EventHandlerCallRef nextHandler, EventRef event, void *userData)
393 OSStatus result = noErr;
394 uint32_t d_width;
395 uint32_t d_height;
396 UInt32 class = GetEventClass(event);
397 UInt32 kind = GetEventKind(event);
399 result = CallNextEventHandler(nextHandler, event);
401 aspect(&d_width, &d_height, A_NOZOOM);
403 if (class == kEventClassCommand)
405 HICommand theHICommand;
407 GetEventParameter(event, kEventParamDirectObject, typeHICommand, NULL, sizeof(HICommand), NULL, &theHICommand);
409 switch (theHICommand.commandID)
411 case kHICommandQuit:
412 mplayer_put_key(KEY_CLOSE_WIN);
413 break;
415 case kHalfScreenCmd:
416 if (vo_quartz_fs)
418 vo_fs = (!(vo_fs));
419 window_fullscreen();
422 SizeWindow(theWindow, (d_width / 2), ((d_width / movie_aspect) / 2), 1);
423 window_resized();
424 break;
426 case kNormalScreenCmd:
427 if (vo_quartz_fs)
429 vo_fs = (!(vo_fs));
430 window_fullscreen();
433 SizeWindow(theWindow, d_width, (d_width / movie_aspect), 1);
434 window_resized();
435 break;
437 case kDoubleScreenCmd:
438 if (vo_quartz_fs)
440 vo_fs = (!(vo_fs));
441 window_fullscreen();
444 SizeWindow(theWindow, (d_width * 2), ((d_width / movie_aspect) * 2), 1);
445 window_resized();
446 break;
448 case kFullScreenCmd:
449 vo_fs = (!(vo_fs));
450 window_fullscreen();
451 break;
453 case kKeepAspectCmd:
454 vo_keepaspect = (!(vo_keepaspect));
455 CheckMenuItem(aspectMenu, 1, vo_keepaspect);
456 window_resized();
457 break;
459 case kAspectOrgCmd:
460 movie_aspect = old_movie_aspect;
461 if (!vo_quartz_fs)
463 SizeWindow(theWindow, dstRect.right, (dstRect.right / movie_aspect), 1);
465 window_resized();
466 break;
468 case kAspectFullCmd:
469 movie_aspect = 4.0f / 3.0f;
470 if (!vo_quartz_fs)
472 SizeWindow(theWindow, dstRect.right, (dstRect.right / movie_aspect), 1);
474 window_resized();
475 break;
477 case kAspectWideCmd:
478 movie_aspect = 16.0f / 9.0f;
479 if (!vo_quartz_fs)
481 SizeWindow(theWindow, dstRect.right, (dstRect.right / movie_aspect), 1);
483 window_resized();
484 break;
486 case kPanScanCmd:
487 vo_panscan = (!(vo_panscan));
488 CheckMenuItem(aspectMenu, 2, vo_panscan);
489 window_panscan();
490 window_resized();
491 break;
493 default:
494 result = eventNotHandledErr;
495 break;
498 else if (class == kEventClassWindow)
500 WindowRef window;
501 Rect rectWindow = { 0, 0, 0, 0 };
503 GetEventParameter(event, kEventParamDirectObject, typeWindowRef, NULL, sizeof(WindowRef), NULL, &window);
505 if (window)
507 GetWindowBounds(window, kWindowGlobalPortRgn, &rectWindow);
510 switch (kind)
512 case kEventWindowClosed:
513 theWindow = NULL;
514 mplayer_put_key(KEY_CLOSE_WIN);
515 break;
517 // resize window
518 case kEventWindowZoomed:
519 case kEventWindowBoundsChanged:
520 window_resized();
521 flip_page();
522 window_resized();
523 break;
525 default:
526 result = eventNotHandledErr;
527 break;
531 return result;
534 static void quartz_CreateWindow(uint32_t d_width, uint32_t d_height, WindowAttributes windowAttrs)
536 CFStringRef titleKey;
537 CFStringRef windowTitle;
538 OSStatus result;
540 MenuItemIndex index;
541 CFStringRef movMenuTitle;
542 CFStringRef aspMenuTitle;
544 const EventTypeSpec win_events[] = {
545 {kEventClassWindow, kEventWindowClosed},
546 {kEventClassWindow, kEventWindowBoundsChanged},
547 {kEventClassCommand, kEventCommandProcess}
550 const EventTypeSpec key_events[] = {
551 {kEventClassKeyboard, kEventRawKeyDown},
552 {kEventClassKeyboard, kEventRawKeyRepeat}
555 const EventTypeSpec mouse_events[] = {
556 {kEventClassMouse, kEventMouseMoved},
557 {kEventClassMouse, kEventMouseWheelMoved},
558 {kEventClassMouse, kEventMouseDown},
559 {kEventClassMouse, kEventMouseUp},
560 {kEventClassMouse, kEventMouseDragged}
563 SetRect(&winRect, 0, 0, d_width, d_height);
564 SetRect(&oldWinRect, 0, 0, d_width, d_height);
565 SetRect(&dstRect, 0, 0, d_width, d_height);
567 // Clear Menu Bar
568 ClearMenuBar();
570 // Create Window Menu
571 CreateStandardWindowMenu(0, &windMenu);
572 InsertMenu(windMenu, 0);
574 // Create Movie Menu
575 CreateNewMenu(1004, 0, &movMenu);
576 movMenuTitle = CFSTR("Movie");
577 SetMenuTitleWithCFString(movMenu, movMenuTitle);
579 AppendMenuItemTextWithCFString(movMenu, CFSTR("Half Size"), 0, kHalfScreenCmd, &index);
580 SetMenuItemCommandKey(movMenu, index, 0, '0');
582 AppendMenuItemTextWithCFString(movMenu, CFSTR("Normal Size"), 0, kNormalScreenCmd, &index);
583 SetMenuItemCommandKey(movMenu, index, 0, '1');
585 AppendMenuItemTextWithCFString(movMenu, CFSTR("Double Size"), 0, kDoubleScreenCmd, &index);
586 SetMenuItemCommandKey(movMenu, index, 0, '2');
588 AppendMenuItemTextWithCFString(movMenu, CFSTR("Full Size"), 0, kFullScreenCmd, &index);
589 SetMenuItemCommandKey(movMenu, index, 0, 'F');
591 AppendMenuItemTextWithCFString(movMenu, NULL, kMenuItemAttrSeparator, 0, &index);
593 AppendMenuItemTextWithCFString(movMenu, CFSTR("Aspect Ratio"), 0, 0, &index);
595 //// Create Aspect Ratio Sub Menu
596 CreateNewMenu(0, 0, &aspectMenu);
597 aspMenuTitle = CFSTR("Aspect Ratio");
598 SetMenuTitleWithCFString(aspectMenu, aspMenuTitle);
599 SetMenuItemHierarchicalMenu(movMenu, 6, aspectMenu);
601 AppendMenuItemTextWithCFString(aspectMenu, CFSTR("Keep"), 0, kKeepAspectCmd, &index);
602 CheckMenuItem(aspectMenu, 1, vo_keepaspect);
603 AppendMenuItemTextWithCFString(aspectMenu, CFSTR("Pan-Scan"), 0, kPanScanCmd, &index);
604 CheckMenuItem(aspectMenu, 2, vo_panscan);
605 AppendMenuItemTextWithCFString(aspectMenu, NULL, kMenuItemAttrSeparator, 0, &index);
606 AppendMenuItemTextWithCFString(aspectMenu, CFSTR("Original"), 0, kAspectOrgCmd, &index);
607 AppendMenuItemTextWithCFString(aspectMenu, CFSTR("4:3"), 0, kAspectFullCmd, &index);
608 AppendMenuItemTextWithCFString(aspectMenu, CFSTR("16:9"), 0, kAspectWideCmd, &index);
610 InsertMenu(movMenu, GetMenuID(windMenu)); //insert before Window menu
612 DrawMenuBar();
614 // create window
615 CreateNewWindow(kDocumentWindowClass, windowAttrs, &winRect, &theWindow);
617 CreateWindowGroup(0, &winGroup);
618 SetWindowGroup(theWindow, winGroup);
620 // Set window title
621 titleKey = CFSTR("MPlayer - The Movie Player");
622 windowTitle = CFCopyLocalizedString(titleKey, NULL);
623 result = SetWindowTitleWithCFString(theWindow, windowTitle);
624 CFRelease(titleKey);
625 CFRelease(windowTitle);
627 // Install event handler
628 InstallApplicationEventHandler(NewEventHandlerUPP(KeyEventHandler), GetEventTypeCount(key_events), key_events, NULL, NULL);
629 InstallApplicationEventHandler(NewEventHandlerUPP(MouseEventHandler), GetEventTypeCount(mouse_events), mouse_events, NULL, NULL);
630 InstallWindowEventHandler(theWindow, NewEventHandlerUPP(WindowEventHandler), GetEventTypeCount(win_events), win_events, theWindow, NULL);
633 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)
635 WindowAttributes windowAttrs;
636 OSErr qterr;
637 CGRect tmpBounds;
638 CGDisplayCount displayCount;
639 CGDirectDisplayID *displays;
641 // Get Main device info///////////////////////////////////////////////////
643 // Display IDs might not be consecutive, get the list of all devices up to # device_id
644 displayCount = device_id + 1;
645 displays = malloc(sizeof(CGDirectDisplayID) * displayCount);
646 if (kCGErrorSuccess != CGGetActiveDisplayList(displayCount, displays, &displayCount) || displayCount < device_id + 1) {
647 mp_msg(MSGT_VO, MSGL_FATAL, "Quartz error: Device ID %d do not exist, falling back to main device.\n", device_id);
648 displayId = kCGDirectMainDisplay;
649 device_id = 0;
651 else
653 displayId = displays[device_id];
655 free(displays);
657 displayRect = CGDisplayBounds(displayId);
659 monitor_aspect = (float)displayRect.size.width / (float)displayRect.size.height;
661 // misc mplayer setup/////////////////////////////////////////////////////
662 SetRect(&imgRect, 0, 0, width, height);
663 switch (image_format)
665 case IMGFMT_RGB32:
666 image_depth = 32;
667 break;
668 case IMGFMT_YV12:
669 case IMGFMT_IYUV:
670 case IMGFMT_I420:
671 case IMGFMT_UYVY:
672 case IMGFMT_YUY2:
673 image_depth = 16;
674 break;
676 image_size = ((imgRect.right * imgRect.bottom * image_depth) + 7) / 8;
678 vo_fs = flags & VOFLAG_FULLSCREEN;
680 // get movie aspect
681 panscan_init();
682 aspect_save_orig(width, height);
683 aspect_save_prescale(d_width, d_height);
684 aspect_save_screenres(displayRect.size.width, displayRect.size.height);
686 aspect(&d_width, &d_height, A_NOZOOM);
688 movie_aspect = (float)d_width / (float)d_height;
689 old_movie_aspect = movie_aspect;
691 if (image_data)
692 free(image_data);
694 image_data = malloc(image_size);
696 // Create player window//////////////////////////////////////////////////
697 windowAttrs = kWindowStandardDocumentAttributes
698 | kWindowStandardHandlerAttribute
699 | kWindowLiveResizeAttribute;
701 windowAttrs &= (~kWindowResizableAttribute);
703 if (theWindow == NULL)
705 CGContextRef context;
707 quartz_CreateWindow(d_width, d_height, windowAttrs);
709 if (theWindow == NULL)
711 mp_msg(MSGT_VO, MSGL_FATAL, "Quartz error: Couldn't create window !!!!!\n");
712 return -1;
714 tmpBounds = CGRectMake(0, 0, winRect.right, winRect.bottom);
715 QDBeginCGContext(GetWindowPort(theWindow), &context);
716 CGContextFillRect(context, tmpBounds);
717 QDEndCGContext(GetWindowPort(theWindow), &context);
719 else
721 HideWindow(theWindow);
722 ChangeWindowAttributes(theWindow, ~windowAttrs, windowAttrs);
723 SetRect(&winRect, 0, 0, d_width, d_height);
724 SetRect(&oldWinRect, 0, 0, d_width, d_height);
725 SizeWindow(theWindow, d_width, d_height, 1);
728 switch (image_format)
730 case IMGFMT_RGB32:
732 CGContextRef context;
734 QDBeginCGContext(GetWindowPort(theWindow), &context);
736 dataProviderRef = CGDataProviderCreateWithData(0, image_data, imgRect.right * imgRect.bottom * 4, 0);
738 image = CGImageCreate(imgRect.right,
739 imgRect.bottom,
741 image_depth,
742 ((imgRect.right * 32) + 7) / 8,
743 CGColorSpaceCreateDeviceRGB(),
744 kCGImageAlphaNoneSkipFirst,
745 dataProviderRef, 0, 1, kCGRenderingIntentDefault);
747 QDEndCGContext(GetWindowPort(theWindow), &context);
748 break;
751 case IMGFMT_YV12:
752 case IMGFMT_IYUV:
753 case IMGFMT_I420:
754 case IMGFMT_UYVY:
755 case IMGFMT_YUY2:
757 get_image_done = 0;
759 if (!EnterMoviesDone)
761 qterr = EnterMovies();
762 EnterMoviesDone = 1;
764 else
765 qterr = 0;
767 if (qterr)
769 mp_msg(MSGT_VO, MSGL_FATAL, "Quartz error: EnterMovies (%d)\n", qterr);
770 return -1;
774 SetIdentityMatrix(&matrix);
776 if ((d_width != width) || (d_height != height))
778 ScaleMatrix(&matrix, FixDiv(Long2Fix(d_width), Long2Fix(width)), FixDiv(Long2Fix(d_height), Long2Fix(height)), 0, 0);
781 yuv_qt_stuff.desc = (ImageDescriptionHandle) NewHandleClear(sizeof(ImageDescription));
783 yuv_qt_stuff.extension_colr = NewHandleClear(sizeof(NCLCColorInfoImageDescriptionExtension));
784 ((NCLCColorInfoImageDescriptionExtension *) (*yuv_qt_stuff.extension_colr))->colorParamType = kVideoColorInfoImageDescriptionExtensionType;
785 ((NCLCColorInfoImageDescriptionExtension *) (*yuv_qt_stuff.extension_colr))->primaries = 2;
786 ((NCLCColorInfoImageDescriptionExtension *) (*yuv_qt_stuff.extension_colr))->transferFunction = 2;
787 ((NCLCColorInfoImageDescriptionExtension *) (*yuv_qt_stuff.extension_colr))->matrix = 2;
789 yuv_qt_stuff.extension_fiel = NewHandleClear(sizeof(FieldInfoImageDescriptionExtension));
790 ((FieldInfoImageDescriptionExtension *) (*yuv_qt_stuff.extension_fiel))->fieldCount = 1;
791 ((FieldInfoImageDescriptionExtension *) (*yuv_qt_stuff.extension_fiel))->fieldOrderings = 0;
793 yuv_qt_stuff.extension_clap = NewHandleClear(sizeof(CleanApertureImageDescriptionExtension));
794 ((CleanApertureImageDescriptionExtension *) (*yuv_qt_stuff.extension_clap))->cleanApertureWidthN = imgRect.right;
795 ((CleanApertureImageDescriptionExtension *) (*yuv_qt_stuff.extension_clap))->cleanApertureWidthD = 1;
796 ((CleanApertureImageDescriptionExtension *) (*yuv_qt_stuff.extension_clap))->cleanApertureHeightN = imgRect.bottom;
797 ((CleanApertureImageDescriptionExtension *) (*yuv_qt_stuff.extension_clap))->cleanApertureHeightD = 1;
798 ((CleanApertureImageDescriptionExtension *) (*yuv_qt_stuff.extension_clap))->horizOffN = 0;
799 ((CleanApertureImageDescriptionExtension *) (*yuv_qt_stuff.extension_clap))->horizOffD = 1;
800 ((CleanApertureImageDescriptionExtension *) (*yuv_qt_stuff.extension_clap))->vertOffN = 0;
801 ((CleanApertureImageDescriptionExtension *) (*yuv_qt_stuff.extension_clap))->vertOffD = 1;
803 yuv_qt_stuff.extension_pasp = NewHandleClear(sizeof(PixelAspectRatioImageDescriptionExtension));
804 ((PixelAspectRatioImageDescriptionExtension *) (*yuv_qt_stuff.extension_pasp))->hSpacing = 1;
805 ((PixelAspectRatioImageDescriptionExtension *) (*yuv_qt_stuff.extension_pasp))->vSpacing = 1;
807 (*yuv_qt_stuff.desc)->idSize = sizeof(ImageDescription);
808 (*yuv_qt_stuff.desc)->cType = image_qtcodec;
809 (*yuv_qt_stuff.desc)->version = 2;
810 (*yuv_qt_stuff.desc)->revisionLevel = 0;
811 (*yuv_qt_stuff.desc)->vendor = 'mpla';
812 (*yuv_qt_stuff.desc)->width = imgRect.right;
813 (*yuv_qt_stuff.desc)->height = imgRect.bottom;
814 (*yuv_qt_stuff.desc)->hRes = Long2Fix(72);
815 (*yuv_qt_stuff.desc)->vRes = Long2Fix(72);
816 (*yuv_qt_stuff.desc)->temporalQuality = 0;
817 (*yuv_qt_stuff.desc)->spatialQuality = codecLosslessQuality;
818 (*yuv_qt_stuff.desc)->frameCount = 1;
819 (*yuv_qt_stuff.desc)->dataSize = 0;
820 (*yuv_qt_stuff.desc)->depth = 24;
821 (*yuv_qt_stuff.desc)->clutID = -1;
823 qterr = AddImageDescriptionExtension(yuv_qt_stuff.desc, yuv_qt_stuff.extension_colr, kColorInfoImageDescriptionExtension);
824 if (qterr)
826 mp_msg(MSGT_VO, MSGL_ERR, "Quartz error: AddImageDescriptionExtension [colr] (%d)\n", qterr);
829 qterr = AddImageDescriptionExtension(yuv_qt_stuff.desc, yuv_qt_stuff.extension_fiel, kFieldInfoImageDescriptionExtension);
830 if (qterr)
832 mp_msg(MSGT_VO, MSGL_ERR, "Quartz error: AddImageDescriptionExtension [fiel] (%d)\n", qterr);
835 qterr = AddImageDescriptionExtension(yuv_qt_stuff.desc, yuv_qt_stuff.extension_clap, kCleanApertureImageDescriptionExtension);
836 if (qterr)
838 mp_msg(MSGT_VO, MSGL_ERR, "Quartz error: AddImageDescriptionExtension [clap] (%d)\n", qterr);
841 qterr = AddImageDescriptionExtension(yuv_qt_stuff.desc, yuv_qt_stuff.extension_pasp, kCleanApertureImageDescriptionExtension);
842 if (qterr)
844 mp_msg(MSGT_VO, MSGL_ERR, "Quartz error: AddImageDescriptionExtension [pasp] (%d)\n", qterr);
846 if (P != NULL) { // second or subsequent movie
847 free(P);
849 P = calloc(sizeof(PlanarPixmapInfoYUV420) + image_size, 1);
850 switch (image_format)
852 case IMGFMT_YV12:
853 case IMGFMT_IYUV:
854 case IMGFMT_I420:
855 P->componentInfoY.offset = be2me_32(sizeof(PlanarPixmapInfoYUV420));
856 P->componentInfoCb.offset = be2me_32(be2me_32(P->componentInfoY.offset) + image_size / 2);
857 P->componentInfoCr.offset = be2me_32(be2me_32(P->componentInfoCb.offset) + image_size / 4);
858 P->componentInfoY.rowBytes = be2me_32(imgRect.right);
859 P->componentInfoCb.rowBytes = be2me_32(imgRect.right / 2);
860 P->componentInfoCr.rowBytes = be2me_32(imgRect.right / 2);
861 image_buffer_size = image_size + sizeof(PlanarPixmapInfoYUV420);
862 break;
863 case IMGFMT_UYVY:
864 case IMGFMT_YUY2:
865 image_buffer_size = image_size;
866 break;
869 qterr = DecompressSequenceBeginS(&seqId,
870 yuv_qt_stuff.desc,
871 (char *)P,
872 image_buffer_size,
873 GetWindowPort(theWindow),
874 NULL,
875 NULL,
876 ((d_width != width) || (d_height != height)) ?
877 &matrix : NULL,
878 srcCopy,
879 NULL,
881 codecLosslessQuality,
882 bestSpeedCodec);
884 if (qterr)
886 mp_msg(MSGT_VO, MSGL_FATAL, "Quartz error: DecompressSequenceBeginS (%d)\n", qterr);
887 return -1;
890 break;
893 // Show window
894 RepositionWindow(theWindow, NULL, kWindowCenterOnMainScreen);
895 ShowWindow(theWindow);
897 if (vo_fs)
898 window_fullscreen();
900 if (vo_ontop)
901 window_ontop();
903 if (vo_rootwin)
905 vo_fs = TRUE;
906 winLevel = 0;
907 SetWindowGroupLevel(winGroup, CGWindowLevelForKey(levelList[winLevel]));
908 window_fullscreen();
911 window_resized();
913 return 0;
916 static void check_events(void)
918 EventRef theEvent;
919 EventTargetRef theTarget;
920 OSStatus theErr;
922 // Get event
923 theTarget = GetEventDispatcherTarget();
924 theErr = ReceiveNextEvent(0, 0, kEventDurationNoWait, true, &theEvent);
925 if (theErr == noErr && theEvent != NULL)
927 SendEventToEventTarget(theEvent, theTarget);
928 ReleaseEvent(theEvent);
932 static void draw_osd(void)
934 vo_draw_text(imgRect.right, imgRect.bottom, draw_alpha);
937 static void flip_page(void)
939 int curTime;
941 if (theWindow == NULL)
942 return;
944 switch (image_format)
946 case IMGFMT_RGB32:
948 CGContextRef context;
950 QDBeginCGContext(GetWindowPort(theWindow), &context);
951 CGContextDrawImage(context, bounds, image);
952 QDEndCGContext(GetWindowPort(theWindow), &context);
954 break;
956 case IMGFMT_YV12:
957 case IMGFMT_IYUV:
958 case IMGFMT_I420:
959 case IMGFMT_UYVY:
960 case IMGFMT_YUY2:
961 if (EnterMoviesDone)
963 OSErr qterr;
964 CodecFlags flags = 0;
966 qterr = DecompressSequenceFrameWhen(seqId,
967 (char *)P,
968 image_buffer_size,
969 0, //codecFlagUseImageBuffer,
970 &flags,
971 NULL,
972 NULL);
973 if (qterr)
975 mp_msg(MSGT_VO, MSGL_ERR, "Quartz error: DecompressSequenceFrameWhen in flip_page (%d) flags:0x%08x\n", qterr, flags);
978 break;
981 if (!vo_quartz_fs)
983 CGContextRef context;
985 QDBeginCGContext(GetWindowPort(theWindow), &context);
986 // render resize box
987 CGContextBeginPath(context);
988 CGContextSetAllowsAntialiasing(context, false);
989 //CGContextSaveGState(context);
991 // line white
992 CGContextSetRGBStrokeColor(context, 0.2, 0.2, 0.2, 0.5);
993 CGContextMoveToPoint(context, winRect.right - 1, 1); CGContextAddLineToPoint(context, winRect.right - 1, 1);
994 CGContextMoveToPoint(context, winRect.right - 1, 5); CGContextAddLineToPoint(context, winRect.right - 5, 1);
995 CGContextMoveToPoint(context, winRect.right - 1, 9); CGContextAddLineToPoint(context, winRect.right - 9, 1);
996 CGContextStrokePath(context);
998 // line gray
999 CGContextSetRGBStrokeColor(context, 0.4, 0.4, 0.4, 0.5);
1000 CGContextMoveToPoint(context, winRect.right - 1, 2); CGContextAddLineToPoint(context, winRect.right - 2, 1);
1001 CGContextMoveToPoint(context, winRect.right - 1, 6); CGContextAddLineToPoint(context, winRect.right - 6, 1);
1002 CGContextMoveToPoint(context, winRect.right - 1, 10); CGContextAddLineToPoint(context, winRect.right - 10, 1);
1003 CGContextStrokePath(context);
1005 // line black
1006 CGContextSetRGBStrokeColor(context, 0.6, 0.6, 0.6, 0.5);
1007 CGContextMoveToPoint(context, winRect.right - 1, 3); CGContextAddLineToPoint(context, winRect.right - 3, 1);
1008 CGContextMoveToPoint(context, winRect.right - 1, 7); CGContextAddLineToPoint(context, winRect.right - 7, 1);
1009 CGContextMoveToPoint(context, winRect.right - 1, 11); CGContextAddLineToPoint(context, winRect.right - 11, 1);
1010 CGContextStrokePath(context);
1012 // CGContextRestoreGState( context );
1013 CGContextFlush(context);
1014 QDEndCGContext(GetWindowPort(theWindow), &context);
1017 curTime = TickCount() / 60;
1019 // auto hide mouse cursor (and future on-screen control?)
1020 if (vo_quartz_fs && !mouseHide)
1022 if (((curTime - lastMouseHide) >= 5) || (lastMouseHide == 0))
1024 CGDisplayHideCursor(displayId);
1025 mouseHide = TRUE;
1026 lastMouseHide = curTime;
1029 // update activity every 30 seconds to prevent
1030 // screensaver from starting up.
1031 if (((curTime - lastScreensaverUpdate) >= 30) || (lastScreensaverUpdate == 0))
1033 UpdateSystemActivity(UsrActivity);
1034 lastScreensaverUpdate = curTime;
1038 static int draw_slice(uint8_t * src[], int stride[], int w, int h, int x, int y)
1040 switch (image_format)
1042 case IMGFMT_YV12:
1043 case IMGFMT_I420:
1044 memcpy_pic(((char *)P) + be2me_32(P->componentInfoY.offset) + x + imgRect.right * y, src[0], w, h, imgRect.right, stride[0]);
1045 x=x/2;y=y/2;w=w/2;h=h/2;
1047 memcpy_pic(((char *)P) + be2me_32(P->componentInfoCb.offset) + x + imgRect.right / 2 * y, src[1], w, h, imgRect.right / 2, stride[1]);
1048 memcpy_pic(((char *)P) + be2me_32(P->componentInfoCr.offset) + x + imgRect.right / 2 * y, src[2], w, h, imgRect.right / 2, stride[2]);
1049 return 0;
1051 case IMGFMT_IYUV:
1052 memcpy_pic(((char *)P) + be2me_32(P->componentInfoY.offset) + x + imgRect.right * y, src[0], w, h, imgRect.right, stride[0]);
1053 x=x/2;y=y/2;w=w/2;h=h/2;
1055 memcpy_pic(((char *)P) + be2me_32(P->componentInfoCr.offset) + x + imgRect.right / 2 * y, src[1], w, h, imgRect.right / 2, stride[1]);
1056 memcpy_pic(((char *)P) + be2me_32(P->componentInfoCb.offset) + x + imgRect.right / 2 * y, src[2], w, h, imgRect.right / 2, stride[2]);
1057 return 0;
1059 return -1;
1062 static int draw_frame(uint8_t * src[])
1064 switch (image_format)
1066 case IMGFMT_RGB32:
1067 fast_memcpy(image_data, src[0], image_size);
1068 return 0;
1070 case IMGFMT_UYVY:
1071 case IMGFMT_YUY2:
1072 memcpy_pic(((char *)P), src[0], imgRect.right * 2, imgRect.bottom, imgRect.right * 2, imgRect.right * 2);
1073 return 0;
1075 return -1;
1078 static int query_format(uint32_t format)
1080 image_format = format;
1081 image_qtcodec = 0;
1083 if (format == IMGFMT_RGB32)
1085 return VFCAP_CSP_SUPPORTED | VFCAP_OSD | VFCAP_HWSCALE_UP | VFCAP_HWSCALE_DOWN;
1088 if ((format == IMGFMT_YV12) || (format == IMGFMT_IYUV) || (format == IMGFMT_I420))
1090 image_qtcodec = kMpegYUV420CodecType; //kYUV420CodecType ?;
1091 return VFCAP_CSP_SUPPORTED | VFCAP_OSD | VFCAP_HWSCALE_UP | VFCAP_HWSCALE_DOWN | VFCAP_ACCEPT_STRIDE;
1094 if (format == IMGFMT_YUY2)
1096 image_qtcodec = kComponentVideoUnsigned;
1097 return VFCAP_CSP_SUPPORTED | VFCAP_OSD | VFCAP_HWSCALE_UP | VFCAP_HWSCALE_DOWN;
1100 if (format == IMGFMT_UYVY)
1102 image_qtcodec = k422YpCbCr8CodecType;
1103 return VFCAP_CSP_SUPPORTED | VFCAP_OSD | VFCAP_HWSCALE_UP | VFCAP_HWSCALE_DOWN;
1106 return 0;
1109 static void uninit(void)
1111 OSErr qterr;
1113 switch (image_format)
1115 case IMGFMT_YV12:
1116 case IMGFMT_IYUV:
1117 case IMGFMT_I420:
1118 case IMGFMT_UYVY:
1119 case IMGFMT_YUY2:
1121 if (EnterMoviesDone)
1123 qterr = CDSequenceEnd(seqId);
1124 if (qterr)
1126 mp_msg(MSGT_VO, MSGL_ERR, "Quartz error: CDSequenceEnd (%d)\n", qterr);
1129 break;
1131 default:
1132 break;
1135 ShowMenuBar();
1138 static int preinit(const char *arg)
1140 int parse_err = 0;
1142 if(arg)
1144 char *parse_pos = (char *)&arg[0];
1146 while (parse_pos[0] && !parse_err)
1148 if (strncmp(parse_pos, "device_id=", 10) == 0)
1150 parse_pos = &parse_pos[10];
1151 device_id = strtol(parse_pos, &parse_pos, 0);
1153 if (strncmp(parse_pos, "fs_res=", 7) == 0)
1155 parse_pos = &parse_pos[7];
1156 fs_res_x = strtol(parse_pos, &parse_pos, 0);
1157 parse_pos = &parse_pos[1];
1158 fs_res_y = strtol(parse_pos, &parse_pos, 0);
1160 if (parse_pos[0] == ':')
1161 parse_pos = &parse_pos[1];
1162 else if (parse_pos[0])
1163 parse_err = 1;
1167 #if !defined (CONFIG_MACOSX_FINDER) || !defined (CONFIG_SDL)
1168 // this chunk of code is heavily based off SDL_macosx.m from SDL
1169 // the CPSEnableForegroundOperation that was here before is private and shouldn't be used
1170 // replaced by a call to the 10.3+ TransformProcessType
1172 ProcessSerialNumber myProc, frProc;
1173 Boolean sameProc;
1175 if (GetFrontProcess(&frProc) == noErr)
1177 if (GetCurrentProcess(&myProc) == noErr)
1179 if (SameProcess(&frProc, &myProc, &sameProc) == noErr && !sameProc)
1181 TransformProcessType(&myProc, kProcessTransformToForegroundApplication);
1183 SetFrontProcess(&myProc);
1187 #endif
1189 return 0;
1192 static uint32_t draw_yuv_image(mp_image_t * mpi)
1194 // ATM we're only called for planar IMGFMT
1195 // drawing is done directly in P
1196 // and displaying is in flip_page.
1197 return get_image_done ? VO_TRUE : VO_FALSE;
1200 static uint32_t get_yuv_image(mp_image_t * mpi)
1202 if (mpi->type != MP_IMGTYPE_EXPORT) return VO_FALSE;
1204 if (mpi->imgfmt != image_format) return VO_FALSE;
1206 if (mpi->flags & MP_IMGFLAG_PLANAR)
1208 if (mpi->num_planes != 3)
1210 mp_msg(MSGT_VO, MSGL_ERR, "Quartz error: only 3 planes allowed in get_yuv_image for planar (%d) \n", mpi->num_planes);
1211 return VO_FALSE;
1214 mpi->planes[0] = ((char *)P) + be2me_32(P->componentInfoY.offset);
1215 mpi->stride[0] = imgRect.right;
1216 mpi->width = imgRect.right;
1218 if (mpi->flags & MP_IMGFLAG_SWAPPED)
1220 // I420
1221 mpi->planes[1] = ((char *)P) + be2me_32(P->componentInfoCb.offset);
1222 mpi->planes[2] = ((char *)P) + be2me_32(P->componentInfoCr.offset);
1223 mpi->stride[1] = imgRect.right / 2;
1224 mpi->stride[2] = imgRect.right / 2;
1226 else
1228 // YV12
1229 mpi->planes[1] = ((char *)P) + be2me_32(P->componentInfoCr.offset);
1230 mpi->planes[2] = ((char *)P) + be2me_32(P->componentInfoCb.offset);
1231 mpi->stride[1] = imgRect.right / 2;
1232 mpi->stride[2] = imgRect.right / 2;
1235 mpi->flags |= MP_IMGFLAG_DIRECT;
1236 get_image_done = 1;
1237 return VO_TRUE;
1239 else
1241 // doesn't work yet
1242 if (mpi->num_planes != 1)
1244 mp_msg(MSGT_VO, MSGL_ERR, "Quartz error: only 1 plane allowed in get_yuv_image for packed (%d) \n", mpi->num_planes);
1245 return VO_FALSE;
1248 mpi->planes[0] = (char *)P;
1249 mpi->stride[0] = imgRect.right * 2;
1250 mpi->width = imgRect.right;
1251 mpi->flags |= MP_IMGFLAG_DIRECT;
1252 get_image_done = 1;
1253 return VO_TRUE;
1255 return VO_FALSE;
1258 static int control(uint32_t request, void *data, ...)
1260 switch (request)
1262 case VOCTRL_PAUSE: return int_pause = 1;
1263 case VOCTRL_RESUME: return int_pause = 0;
1264 case VOCTRL_FULLSCREEN: vo_fs = (!(vo_fs)); window_fullscreen(); return VO_TRUE;
1265 case VOCTRL_ONTOP: vo_ontop = (!(vo_ontop)); window_ontop(); return VO_TRUE;
1266 case VOCTRL_QUERY_FORMAT: return query_format(*((uint32_t *) data));
1267 case VOCTRL_GET_PANSCAN: return VO_TRUE;
1268 case VOCTRL_SET_PANSCAN: window_panscan(); return VO_TRUE;
1270 case VOCTRL_GET_IMAGE:
1271 switch (image_format)
1273 case IMGFMT_YV12:
1274 case IMGFMT_IYUV:
1275 case IMGFMT_I420:
1276 case IMGFMT_UYVY:
1277 case IMGFMT_YUY2:
1278 return get_yuv_image(data);
1279 break;
1280 default:
1281 break;
1283 case VOCTRL_DRAW_IMAGE:
1284 switch (image_format)
1286 case IMGFMT_YV12:
1287 case IMGFMT_IYUV:
1288 case IMGFMT_I420:
1289 case IMGFMT_UYVY:
1290 case IMGFMT_YUY2:
1291 return draw_yuv_image(data);
1292 break;
1293 default:
1294 break;
1297 return VO_NOTIMPL;
1300 void window_resized()
1302 float aspectX;
1303 float aspectY;
1305 int padding = 0;
1307 uint32_t d_width;
1308 uint32_t d_height;
1310 CGRect tmpBounds;
1312 CGContextRef context;
1314 GetWindowPortBounds(theWindow, &winRect);
1316 if (vo_keepaspect)
1318 aspect(&d_width, &d_height, A_NOZOOM);
1319 d_height = ((float)d_width / movie_aspect);
1321 aspectX = (float)((float)winRect.right / (float)d_width);
1322 aspectY = (float)((float)(winRect.bottom) / (float)d_height);
1324 if ((d_height * aspectX) > (winRect.bottom))
1326 padding = (winRect.right - d_width * aspectY) / 2;
1327 SetRect(&dstRect, padding, 0, d_width * aspectY + padding, d_height * aspectY);
1329 else
1331 padding = ((winRect.bottom) - d_height * aspectX) / 2;
1332 SetRect(&dstRect, 0, padding, (d_width * aspectX), d_height * aspectX + padding);
1335 else
1337 SetRect(&dstRect, 0, 0, winRect.right, winRect.bottom);
1340 switch (image_format)
1342 case IMGFMT_RGB32:
1344 bounds = CGRectMake(dstRect.left, dstRect.top, dstRect.right - dstRect.left, dstRect.bottom - dstRect.top);
1345 break;
1347 case IMGFMT_YV12:
1348 case IMGFMT_IYUV:
1349 case IMGFMT_I420:
1350 case IMGFMT_UYVY:
1351 case IMGFMT_YUY2:
1353 long scale_X = FixDiv(Long2Fix(dstRect.right - dstRect.left), Long2Fix(imgRect.right));
1354 long scale_Y = FixDiv(Long2Fix(dstRect.bottom - dstRect.top), Long2Fix(imgRect.bottom));
1356 SetIdentityMatrix(&matrix);
1357 if (((dstRect.right - dstRect.left) != imgRect.right) || ((dstRect.bottom - dstRect.right) != imgRect.bottom))
1359 ScaleMatrix(&matrix, scale_X, scale_Y, 0, 0);
1361 if (padding > 0)
1363 TranslateMatrix(&matrix, Long2Fix(dstRect.left), Long2Fix(dstRect.top));
1367 SetDSequenceMatrix(seqId, &matrix);
1368 break;
1370 default:
1371 break;
1374 // Clear Background
1375 tmpBounds = CGRectMake(0, 0, winRect.right, winRect.bottom);
1376 QDBeginCGContext(GetWindowPort(theWindow), &context);
1377 CGContextFillRect(context, tmpBounds);
1378 QDEndCGContext(GetWindowPort(theWindow), &context);
1381 void window_ontop()
1383 if (!vo_quartz_fs)
1385 // Cycle between level
1386 winLevel++;
1387 if (winLevel > 2)
1388 winLevel = 1;
1390 SetWindowGroupLevel(winGroup, CGWindowLevelForKey(levelList[winLevel]));
1393 void window_fullscreen()
1395 // go fullscreen
1396 if (vo_fs)
1398 if (winLevel != 0)
1400 if (displayId == kCGDirectMainDisplay)
1402 SetSystemUIMode(kUIModeAllHidden, kUIOptionAutoShowMenuBar);
1403 CGDisplayHideCursor(displayId);
1404 mouseHide = TRUE;
1407 if (fs_res_x != 0 || fs_res_y != 0)
1409 CFDictionaryRef mode;
1410 size_t desiredBitDepth = 32;
1411 boolean_t exactMatch;
1413 originalMode = CGDisplayCurrentMode(displayId);
1415 mode = CGDisplayBestModeForParameters(displayId, desiredBitDepth, fs_res_x, fs_res_y, &exactMatch);
1417 if (mode != NULL)
1419 if (!exactMatch)
1421 // Warn if the mode doesn't match exactly
1422 mp_msg(MSGT_VO, MSGL_WARN, "Quartz warning: did not get exact mode match (got %dx%d) \n", (int)CFDictionaryGetValue(mode, kCGDisplayWidth), (int)CFDictionaryGetValue(mode, kCGDisplayHeight));
1425 CGDisplayCapture(displayId);
1426 CGDisplaySwitchToMode(displayId, mode);
1428 else
1430 mp_msg(MSGT_VO, MSGL_ERR, "Quartz error: can't switch to fullscreen \n");
1433 // Get Main device info///////////////////////////////////////////////////
1434 displayRect = CGDisplayBounds(displayId);
1437 // save old window size
1438 if (!vo_quartz_fs)
1440 GetWindowPortBounds(theWindow, &oldWinRect);
1441 GetWindowBounds(theWindow, kWindowContentRgn, &oldWinBounds);
1443 // go fullscreen
1444 panscan_calc();
1445 ChangeWindowAttributes(theWindow, kWindowNoShadowAttribute, 0);
1446 MoveWindow(theWindow, displayRect.origin.x - (vo_panscan_x >> 1), displayRect.origin.y - (vo_panscan_y >> 1), 1);
1447 SizeWindow(theWindow, displayRect.size.width + vo_panscan_x, displayRect.size.height + vo_panscan_y, 1);
1449 vo_quartz_fs = 1;
1451 else //go back to windowed mode
1453 vo_quartz_fs = 0;
1454 if (originalMode != NULL)
1456 CGDisplaySwitchToMode(displayId, originalMode);
1457 CGDisplayRelease(displayId);
1459 // Get Main device info///////////////////////////////////////////////////
1460 displayRect = CGDisplayBounds(displayId);
1462 originalMode = NULL;
1464 SetSystemUIMode(kUIModeNormal, 0);
1466 // show mouse cursor
1467 CGDisplayShowCursor(displayId);
1468 mouseHide = FALSE;
1470 // revert window to previous setting
1471 ChangeWindowAttributes(theWindow, 0, kWindowNoShadowAttribute);
1472 SizeWindow(theWindow, oldWinRect.right, oldWinRect.bottom, 1);
1473 MoveWindow(theWindow, oldWinBounds.left, oldWinBounds.top, 1);
1475 window_resized();
1478 void window_panscan()
1480 panscan_calc();
1482 if (vo_panscan > 0)
1483 CheckMenuItem(aspectMenu, 2, 1);
1484 else
1485 CheckMenuItem(aspectMenu, 2, 0);
1487 if (vo_quartz_fs)
1489 MoveWindow(theWindow, displayRect.origin.x - (vo_panscan_x >> 1), displayRect.origin.y - (vo_panscan_y >> 1), 1);
1490 SizeWindow(theWindow, displayRect.size.width + vo_panscan_x, displayRect.size.height + vo_panscan_y, 1);