00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031 #include <errno.h>
00032 #include <stdlib.h>
00033 #include <string.h>
00034
00035
00036 #include <QuickTime/QuickTime.h>
00037
00038 #include <vlc_keys.h>
00039
00040 #include "intf.h"
00041 #include "vout.h"
00042
00043
00044
00045
00046
00047 int DeviceCallback( vlc_object_t *p_this, const char *psz_variable,
00048 vlc_value_t old_val, vlc_value_t new_val, void *param )
00049 {
00050 vlc_value_t val;
00051 vout_thread_t *p_vout = (vout_thread_t *)p_this;
00052
00053 msg_Dbg( p_vout, "set %d", new_val.i_int );
00054 var_Create( p_vout->p_vlc, "video-device", VLC_VAR_INTEGER );
00055 var_Set( p_vout->p_vlc, "video-device", new_val );
00056
00057 val.b_bool = VLC_TRUE;
00058 var_Set( p_vout, "intf-change", val );
00059 return VLC_SUCCESS;
00060 }
00061
00062
00063
00064
00065
00066 @implementation VLCWindow
00067
00068 - (id) initWithVout: (vout_thread_t *) vout view: (NSView *) view
00069 frame: (NSRect *) frame
00070 {
00071 p_vout = vout;
00072 o_view = view;
00073 s_frame = frame;
00074
00075 [self performSelectorOnMainThread: @selector(initReal:)
00076 withObject: NULL waitUntilDone: YES];
00077
00078 if( !b_init_ok )
00079 {
00080 return NULL;
00081 }
00082
00083 return self;
00084 }
00085
00086 - (id) initReal: (id) sender
00087 {
00088 NSAutoreleasePool *o_pool = [[NSAutoreleasePool alloc] init];
00089 NSArray *o_screens = [NSScreen screens];
00090 NSScreen *o_screen;
00091 vlc_bool_t b_menubar_screen = VLC_FALSE;
00092 int i_timeout, i_device;
00093 vlc_value_t value_drawable;
00094
00095 b_init_ok = VLC_FALSE;
00096
00097 var_Get( p_vout->p_vlc, "drawable", &value_drawable );
00098
00099
00100
00101
00102
00103 if( value_drawable.i_int == 0 )
00104 {
00105
00106 for( i_timeout = 20 ; i_timeout-- ; )
00107 {
00108 if( NSApp == NULL )
00109 {
00110 msleep( INTF_IDLE_SLEEP );
00111 }
00112 }
00113
00114 if( NSApp == NULL )
00115 {
00116
00117 msg_Err( p_vout, "no MacOS X interface present" );
00118 return NULL;
00119 }
00120 }
00121
00122 if( [o_screens count] <= 0 )
00123 {
00124 msg_Err( p_vout, "no OSX screens available" );
00125 return NULL;
00126 }
00127
00128
00129
00130
00131 if( p_vout->i_object_type == VLC_OBJECT_OPENGL )
00132 {
00133 p_real_vout = (vout_thread_t *) p_vout->p_parent;
00134 }
00135 else
00136 {
00137 p_real_vout = p_vout;
00138 }
00139
00140 p_fullscreen_state = NULL;
00141 i_time_mouse_last_moved = mdate();
00142
00143 var_Create( p_vout, "macosx-vdev", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
00144 var_Create( p_vout, "macosx-fill", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
00145 var_Create( p_vout, "macosx-stretch", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
00146 var_Create( p_vout, "macosx-opaqueness", VLC_VAR_FLOAT | VLC_VAR_DOINHERIT );
00147 var_Create( p_vout, "macosx-background", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
00148
00149
00150 if( var_Type( p_real_vout->p_vlc, "video-device" ) == 0 )
00151 {
00152 i_device = var_GetInteger( p_vout, "macosx-vdev" );
00153 }
00154 else
00155 {
00156 i_device = var_GetInteger( p_real_vout->p_vlc, "video-device" );
00157 }
00158
00159
00160 if( var_Type( p_real_vout, "video-device" ) == 0 )
00161 {
00162 int i = 1;
00163 vlc_value_t val2, text;
00164 NSScreen * o_screen;
00165
00166 var_Create( p_real_vout, "video-device", VLC_VAR_INTEGER |
00167 VLC_VAR_HASCHOICE );
00168 text.psz_string = _("Video Device");
00169 var_Change( p_real_vout, "video-device", VLC_VAR_SETTEXT, &text, NULL );
00170
00171 NSEnumerator * o_enumerator = [o_screens objectEnumerator];
00172
00173 val2.i_int = 0;
00174 text.psz_string = _("Default");
00175 var_Change( p_real_vout, "video-device",
00176 VLC_VAR_ADDCHOICE, &val2, &text );
00177 var_Set( p_real_vout, "video-device", val2 );
00178
00179 while( (o_screen = [o_enumerator nextObject]) != NULL )
00180 {
00181 char psz_temp[255];
00182 NSRect s_rect = [o_screen frame];
00183
00184 snprintf( psz_temp, sizeof(psz_temp)/sizeof(psz_temp[0])-1,
00185 "%s %d (%dx%d)", _("Screen"), i,
00186 (int)s_rect.size.width, (int)s_rect.size.height );
00187
00188 text.psz_string = psz_temp;
00189 val2.i_int = i;
00190 var_Change( p_real_vout, "video-device",
00191 VLC_VAR_ADDCHOICE, &val2, &text );
00192 if( i == i_device )
00193 {
00194 var_Set( p_real_vout, "video-device", val2 );
00195 }
00196 i++;
00197 }
00198
00199 var_AddCallback( p_real_vout, "video-device", DeviceCallback,
00200 NULL );
00201
00202 val2.b_bool = VLC_TRUE;
00203 var_Set( p_real_vout, "intf-change", val2 );
00204 }
00205
00206
00207 if( i_device <= 0 || i_device > (int)[o_screens count] )
00208 {
00209
00210 o_screen = [NSScreen mainScreen];
00211 if( o_screen == [o_screens objectAtIndex: 0] )
00212 b_menubar_screen = VLC_TRUE;
00213 }
00214 else
00215 {
00216 i_device--;
00217 o_screen = [o_screens objectAtIndex: i_device];
00218 b_menubar_screen = ( i_device == 0 );
00219 }
00220
00221 if( p_vout->b_fullscreen )
00222 {
00223 NSRect screen_rect = [o_screen frame];
00224 screen_rect.origin.x = screen_rect.origin.y = 0;
00225
00226
00227 [self initWithContentRect: screen_rect
00228 styleMask: NSBorderlessWindowMask
00229 backing: NSBackingStoreBuffered
00230 defer: YES screen: o_screen];
00231
00232 if( b_menubar_screen )
00233 {
00234 BeginFullScreen( &p_fullscreen_state, NULL, 0, 0,
00235 NULL, NULL, fullScreenAllowEvents );
00236 }
00237 }
00238 else if( var_GetBool( p_real_vout, "macosx-background" ) )
00239 {
00240 NSRect screen_rect = [o_screen frame];
00241 screen_rect.origin.x = screen_rect.origin.y = 0;
00242
00243
00244 [self initWithContentRect: screen_rect
00245 styleMask: NSBorderlessWindowMask
00246 backing: NSBackingStoreBuffered
00247 defer: YES screen: o_screen];
00248
00249 [self setLevel: CGWindowLevelForKey(kCGDesktopWindowLevelKey)];
00250 }
00251 else
00252 {
00253 unsigned int i_stylemask = NSTitledWindowMask |
00254 NSMiniaturizableWindowMask |
00255 NSClosableWindowMask |
00256 NSResizableWindowMask;
00257
00258 NSRect s_rect;
00259 if( !s_frame )
00260 {
00261 s_rect.size.width = p_vout->i_window_width;
00262 s_rect.size.height = p_vout->i_window_height;
00263 }
00264 else
00265 {
00266 s_rect = *s_frame;
00267 }
00268
00269 [self initWithContentRect: s_rect
00270 styleMask: i_stylemask
00271 backing: NSBackingStoreBuffered
00272 defer: YES screen: o_screen];
00273
00274 [self setAlphaValue: var_GetFloat( p_vout, "macosx-opaqueness" )];
00275
00276 if( var_GetBool( p_real_vout, "video-on-top" ) )
00277 {
00278 [self setLevel: NSStatusWindowLevel];
00279 }
00280
00281 if( !s_frame )
00282 {
00283 [self center];
00284 }
00285 }
00286
00287 [self updateTitle];
00288 [self makeKeyAndOrderFront: nil];
00289 [self setReleasedWhenClosed: YES];
00290
00291
00292 [self setAcceptsMouseMovedEvents: YES];
00293 [self makeFirstResponder: self];
00294
00295
00296 [self setContentView: o_view];
00297
00298 [o_pool release];
00299
00300 b_init_ok = VLC_TRUE;
00301 return self;
00302 }
00303
00304 - (void) close
00305 {
00306
00307
00308 [self setAcceptsMouseMovedEvents: NO];
00309 [self setContentView: NULL];
00310 [self performSelectorOnMainThread: @selector(closeReal:)
00311 withObject: NULL waitUntilDone: NO];
00312 }
00313
00314 - (id) closeReal: (id) sender
00315 {
00316 [super close];
00317 if( p_fullscreen_state )
00318 {
00319 EndFullScreen( p_fullscreen_state, 0 );
00320 }
00321 return NULL;
00322 }
00323
00324 - (void)setOnTop:(BOOL)b_on_top
00325 {
00326 if( b_on_top )
00327 {
00328 [self setLevel: NSStatusWindowLevel];
00329 }
00330 else
00331 {
00332 [self setLevel: NSNormalWindowLevel];
00333 }
00334 }
00335
00336 - (void)hideMouse:(BOOL)b_hide
00337 {
00338 BOOL b_inside;
00339 NSPoint ml;
00340 NSView *o_contents = [self contentView];
00341
00342 ml = [self convertScreenToBase:[NSEvent mouseLocation]];
00343 ml = [o_contents convertPoint:ml fromView:nil];
00344 b_inside = [o_contents mouse: ml inRect: [o_contents bounds]];
00345
00346 if( b_hide && b_inside )
00347 {
00348 [NSCursor setHiddenUntilMouseMoves: YES];
00349 }
00350 else if( !b_hide )
00351 {
00352 [NSCursor setHiddenUntilMouseMoves: NO];
00353 }
00354 }
00355
00356 - (void)manage
00357 {
00358 if( p_fullscreen_state )
00359 {
00360 if( mdate() - i_time_mouse_last_moved > 3000000 )
00361 {
00362 [self hideMouse: YES];
00363 }
00364 }
00365 else
00366 {
00367 [self hideMouse: NO];
00368 }
00369
00370
00371 UpdateSystemActivity( UsrActivity );
00372 }
00373
00374 - (void)scaleWindowWithFactor: (float)factor
00375 {
00376 NSSize newsize;
00377 int i_corrected_height, i_corrected_width;
00378 NSPoint topleftbase;
00379 NSPoint topleftscreen;
00380
00381 if ( !p_vout->b_fullscreen )
00382 {
00383 topleftbase.x = 0;
00384 topleftbase.y = [self frame].size.height;
00385 topleftscreen = [self convertBaseToScreen: topleftbase];
00386
00387 if( p_vout->render.i_height * p_vout->render.i_aspect >
00388 p_vout->render.i_width * VOUT_ASPECT_FACTOR )
00389 {
00390 i_corrected_width = p_vout->render.i_height * p_vout->render.i_aspect /
00391 VOUT_ASPECT_FACTOR;
00392 newsize.width = (int) ( i_corrected_width * factor );
00393 newsize.height = (int) ( p_vout->render.i_height * factor );
00394 }
00395 else
00396 {
00397 i_corrected_height = p_vout->render.i_width * VOUT_ASPECT_FACTOR /
00398 p_vout->render.i_aspect;
00399 newsize.width = (int) ( p_vout->render.i_width * factor );
00400 newsize.height = (int) ( i_corrected_height * factor );
00401 }
00402
00403 [self setContentSize: newsize];
00404
00405 [self setFrameTopLeftPoint: topleftscreen];
00406 p_vout->i_changes |= VOUT_SIZE_CHANGE;
00407 }
00408 }
00409
00410 - (void)toggleFloatOnTop
00411 {
00412 vlc_value_t val;
00413
00414 if( var_Get( p_real_vout, "video-on-top", &val )>=0 && val.b_bool)
00415 {
00416 val.b_bool = VLC_FALSE;
00417 }
00418 else
00419 {
00420 val.b_bool = VLC_TRUE;
00421 }
00422 var_Set( p_real_vout, "video-on-top", val );
00423 }
00424
00425 - (void)toggleFullscreen
00426 {
00427 vlc_value_t val;
00428 var_Get( p_real_vout, "fullscreen", &val );
00429 val.b_bool = !val.b_bool;
00430 var_Set( p_real_vout, "fullscreen", val );
00431 }
00432
00433 - (BOOL)isFullscreen
00434 {
00435 vlc_value_t val;
00436 var_Get( p_real_vout, "fullscreen", &val );
00437 return( val.b_bool );
00438 }
00439
00440 - (void)snapshot
00441 {
00442 vout_Control( p_real_vout, VOUT_SNAPSHOT );
00443 }
00444
00445 - (BOOL)canBecomeKeyWindow
00446 {
00447 return YES;
00448 }
00449
00450
00451
00452
00453
00454
00455
00456 - (void)keyDown:(NSEvent *)o_event
00457 {
00458 unichar key = 0;
00459 vlc_value_t val;
00460 unsigned int i_pressed_modifiers = 0;
00461 val.i_int = 0;
00462
00463 i_pressed_modifiers = [o_event modifierFlags];
00464
00465 if( i_pressed_modifiers & NSShiftKeyMask )
00466 val.i_int |= KEY_MODIFIER_SHIFT;
00467 if( i_pressed_modifiers & NSControlKeyMask )
00468 val.i_int |= KEY_MODIFIER_CTRL;
00469 if( i_pressed_modifiers & NSAlternateKeyMask )
00470 val.i_int |= KEY_MODIFIER_ALT;
00471 if( i_pressed_modifiers & NSCommandKeyMask )
00472 val.i_int |= KEY_MODIFIER_COMMAND;
00473
00474 key = [[o_event charactersIgnoringModifiers] characterAtIndex: 0];
00475
00476 if( key )
00477 {
00478
00479 if( key == (unichar) 0x1b )
00480 {
00481 if( [self isFullscreen] )
00482 {
00483 [self toggleFullscreen];
00484 }
00485 }
00486 else if ( key == ' ' )
00487 {
00488 vlc_value_t val;
00489 val.i_int = config_GetInt( p_vout, "key-play-pause" );
00490 var_Set( p_vout->p_vlc, "key-pressed", val );
00491 }
00492 else
00493 {
00494 val.i_int |= CocoaKeyToVLC( key );
00495 var_Set( p_vout->p_vlc, "key-pressed", val );
00496 }
00497 }
00498 else
00499 {
00500 [super keyDown: o_event];
00501 }
00502 }
00503
00504 - (void)updateTitle
00505 {
00506 NSMutableString * o_title = NULL, * o_mrl = NULL;
00507 input_thread_t * p_input;
00508
00509 if( p_vout == NULL )
00510 {
00511 return;
00512 }
00513
00514 p_input = vlc_object_find( p_vout, VLC_OBJECT_INPUT, FIND_PARENT );
00515
00516 if( p_input == NULL )
00517 {
00518 return;
00519 }
00520
00521 if( p_input->input.p_item->psz_name != NULL )
00522 o_title = [NSMutableString stringWithUTF8String:
00523 p_input->input.p_item->psz_name];
00524 if( p_input->input.p_item->psz_uri != NULL )
00525 o_mrl = [NSMutableString stringWithUTF8String:
00526 p_input->input.p_item->psz_uri];
00527 if( o_title == nil )
00528 o_title = o_mrl;
00529
00530 if( o_mrl != nil )
00531 {
00532 if( p_input->input.p_access && !strcmp( p_input->input.p_access->p_module->psz_shortname, "File" ) )
00533 {
00534 NSRange prefix_range = [o_mrl rangeOfString: @"file:"];
00535 if( prefix_range.location != NSNotFound )
00536 [o_mrl deleteCharactersInRange: prefix_range];
00537 [self setRepresentedFilename: o_mrl];
00538 }
00539 [self setTitle: o_title];
00540 }
00541 else
00542 {
00543 [self setTitle: [NSString stringWithCString: VOUT_TITLE]];
00544 }
00545 vlc_object_release( p_input );
00546 }
00547
00548
00549 - (BOOL)windowShouldClose:(id)sender
00550 {
00551 playlist_t * p_playlist = vlc_object_find( p_vout, VLC_OBJECT_PLAYLIST,
00552 FIND_ANYWHERE );
00553 if( p_playlist == NULL )
00554 {
00555 return NO;
00556 }
00557
00558 playlist_Stop( p_playlist );
00559 vlc_object_release( p_playlist );
00560
00561
00562 return NO;
00563 }
00564
00565 - (BOOL)acceptsFirstResponder
00566 {
00567 return YES;
00568 }
00569
00570 - (BOOL)becomeFirstResponder
00571 {
00572 return YES;
00573 }
00574
00575 - (BOOL)resignFirstResponder
00576 {
00577
00578
00579 return NO;
00580 }
00581
00582 - (void)mouseDown:(NSEvent *)o_event
00583 {
00584 vlc_value_t val;
00585
00586 switch( [o_event type] )
00587 {
00588 case NSLeftMouseDown:
00589 {
00590 var_Get( p_vout, "mouse-button-down", &val );
00591 val.i_int |= 1;
00592 var_Set( p_vout, "mouse-button-down", val );
00593 }
00594 break;
00595
00596 default:
00597 [super mouseDown: o_event];
00598 break;
00599 }
00600 }
00601
00602 - (void)otherMouseDown:(NSEvent *)o_event
00603 {
00604 vlc_value_t val;
00605
00606 switch( [o_event type] )
00607 {
00608 case NSOtherMouseDown:
00609 {
00610 var_Get( p_vout, "mouse-button-down", &val );
00611 val.i_int |= 2;
00612 var_Set( p_vout, "mouse-button-down", val );
00613 }
00614 break;
00615
00616 default:
00617 [super mouseDown: o_event];
00618 break;
00619 }
00620 }
00621
00622 - (void)rightMouseDown:(NSEvent *)o_event
00623 {
00624 vlc_value_t val;
00625
00626 switch( [o_event type] )
00627 {
00628 case NSRightMouseDown:
00629 {
00630 var_Get( p_vout, "mouse-button-down", &val );
00631 val.i_int |= 4;
00632 var_Set( p_vout, "mouse-button-down", val );
00633 }
00634 break;
00635
00636 default:
00637 [super mouseDown: o_event];
00638 break;
00639 }
00640 }
00641
00642 - (void)mouseUp:(NSEvent *)o_event
00643 {
00644 vlc_value_t val;
00645
00646 switch( [o_event type] )
00647 {
00648 case NSLeftMouseUp:
00649 {
00650 vlc_value_t b_val;
00651 b_val.b_bool = VLC_TRUE;
00652 var_Set( p_vout, "mouse-clicked", b_val );
00653
00654 var_Get( p_vout, "mouse-button-down", &val );
00655 val.i_int &= ~1;
00656 var_Set( p_vout, "mouse-button-down", val );
00657 }
00658 break;
00659
00660 default:
00661 [super mouseUp: o_event];
00662 break;
00663 }
00664 }
00665
00666 - (void)otherMouseUp:(NSEvent *)o_event
00667 {
00668 vlc_value_t val;
00669
00670 switch( [o_event type] )
00671 {
00672 case NSOtherMouseUp:
00673 {
00674 var_Get( p_vout, "mouse-button-down", &val );
00675 val.i_int &= ~2;
00676 var_Set( p_vout, "mouse-button-down", val );
00677 }
00678 break;
00679
00680 default:
00681 [super mouseUp: o_event];
00682 break;
00683 }
00684 }
00685
00686 - (void)rightMouseUp:(NSEvent *)o_event
00687 {
00688 vlc_value_t val;
00689
00690 switch( [o_event type] )
00691 {
00692 case NSRightMouseUp:
00693 {
00694 var_Get( p_vout, "mouse-button-down", &val );
00695 val.i_int &= ~4;
00696 var_Set( p_vout, "mouse-button-down", val );
00697 }
00698 break;
00699
00700 default:
00701 [super mouseUp: o_event];
00702 break;
00703 }
00704 }
00705
00706 - (void)mouseDragged:(NSEvent *)o_event
00707 {
00708 [self mouseMoved: o_event];
00709 }
00710
00711 - (void)otherMouseDragged:(NSEvent *)o_event
00712 {
00713 [self mouseMoved: o_event];
00714 }
00715
00716 - (void)rightMouseDragged:(NSEvent *)o_event
00717 {
00718 [self mouseMoved: o_event];
00719 }
00720
00721 - (void)mouseMoved:(NSEvent *)o_event
00722 {
00723 NSPoint ml;
00724 NSRect s_rect;
00725 BOOL b_inside;
00726
00727 i_time_mouse_last_moved = mdate();
00728
00729 s_rect = [o_view bounds];
00730 ml = [o_view convertPoint: [o_event locationInWindow] fromView: nil];
00731 b_inside = [o_view mouse: ml inRect: s_rect];
00732
00733 if( b_inside )
00734 {
00735 vlc_value_t val;
00736 unsigned int i_width, i_height, i_x, i_y;
00737
00738 vout_PlacePicture( p_vout, (unsigned int)s_rect.size.width,
00739 (unsigned int)s_rect.size.height,
00740 &i_x, &i_y, &i_width, &i_height );
00741
00742 val.i_int = ( ((int)ml.x) - i_x ) *
00743 p_vout->render.i_width / i_width;
00744 var_Set( p_vout, "mouse-x", val );
00745
00746 if( [[o_view className] isEqualToString: @"VLCGLView"] )
00747 {
00748 val.i_int = ( ((int)(s_rect.size.height - ml.y)) - i_y ) *
00749 p_vout->render.i_height / i_height;
00750 }
00751 else
00752 {
00753 val.i_int = ( ((int)ml.y) - i_y ) *
00754 p_vout->render.i_height / i_height;
00755 }
00756 var_Set( p_vout, "mouse-y", val );
00757
00758 val.b_bool = VLC_TRUE;
00759 var_Set( p_vout, "mouse-moved", val );
00760 }
00761
00762 [super mouseMoved: o_event];
00763 }
00764
00765 @end