Skip to content
Browse files

Merge pull request #2268 from Memphiz/ios6

[atv2] - support for ios6

signed-off 10 times by memphis@machzwo.de
  • Loading branch information...
2 parents 77ede9a + 71a6813 commit 42e3b066badb0b8d89ec3d8e71ec9d963bdad580 @Memphiz Memphiz committed
View
8 XBMC-ATV2.xcodeproj/project.pbxproj
@@ -896,7 +896,7 @@
F56C7B89131EC155000AD0F6 /* Util.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F56C780A131EC154000AD0F6 /* Util.cpp */; };
F56C7B8B131EC155000AD0F6 /* XBApplicationEx.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F56C780E131EC154000AD0F6 /* XBApplicationEx.cpp */; };
F56C7B9B131EC1B4000AD0F6 /* AutoPool.mm in Sources */ = {isa = PBXBuildFile; fileRef = F56C7B9A131EC1B4000AD0F6 /* AutoPool.mm */; };
- F56C7BC9131EC2DB000AD0F6 /* XBMCAppliance.m in Sources */ = {isa = PBXBuildFile; fileRef = F56C7BC2131EC2DB000AD0F6 /* XBMCAppliance.m */; };
+ F56C7BC9131EC2DB000AD0F6 /* XBMCAppliance.mm in Sources */ = {isa = PBXBuildFile; fileRef = F56C7BC2131EC2DB000AD0F6 /* XBMCAppliance.mm */; };
F56C7BCA131EC2DB000AD0F6 /* XBMCController.mm in Sources */ = {isa = PBXBuildFile; fileRef = F56C7BC5131EC2DB000AD0F6 /* XBMCController.mm */; };
F56C7BD0131EC301000AD0F6 /* XBMC.png in Resources */ = {isa = PBXBuildFile; fileRef = F56C7BCD131EC301000AD0F6 /* XBMC.png */; };
F56C7BDC131EC390000AD0F6 /* WinEventsIOS.mm in Sources */ = {isa = PBXBuildFile; fileRef = F56C7BD9131EC390000AD0F6 /* WinEventsIOS.mm */; };
@@ -2973,7 +2973,7 @@
F56C780F131EC154000AD0F6 /* XBApplicationEx.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = XBApplicationEx.h; sourceTree = "<group>"; };
F56C7B99131EC1B4000AD0F6 /* AutoPool.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AutoPool.h; sourceTree = "<group>"; };
F56C7B9A131EC1B4000AD0F6 /* AutoPool.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = AutoPool.mm; sourceTree = "<group>"; };
- F56C7BC2131EC2DB000AD0F6 /* XBMCAppliance.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = XBMCAppliance.m; sourceTree = "<group>"; };
+ F56C7BC2131EC2DB000AD0F6 /* XBMCAppliance.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = XBMCAppliance.mm; sourceTree = "<group>"; };
F56C7BC3131EC2DB000AD0F6 /* XBMCAppliance.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = XBMCAppliance.h; sourceTree = "<group>"; };
F56C7BC4131EC2DB000AD0F6 /* XBMCController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = XBMCController.h; sourceTree = "<group>"; };
F56C7BC5131EC2DB000AD0F6 /* XBMCController.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = XBMCController.mm; sourceTree = "<group>"; };
@@ -6015,7 +6015,7 @@
F56C7F2D131F0BB4000AD0F6 /* English.lproj */,
F56C7BCD131EC301000AD0F6 /* XBMC.png */,
F56C7BC3131EC2DB000AD0F6 /* XBMCAppliance.h */,
- F56C7BC2131EC2DB000AD0F6 /* XBMCAppliance.m */,
+ F56C7BC2131EC2DB000AD0F6 /* XBMCAppliance.mm */,
F56C7BCE131EC301000AD0F6 /* XBMCATV2-Info.plist */,
F56C7BC4131EC2DB000AD0F6 /* XBMCController.h */,
F56C7BC5131EC2DB000AD0F6 /* XBMCController.mm */,
@@ -7323,7 +7323,7 @@
F56C7B89131EC155000AD0F6 /* Util.cpp in Sources */,
F56C7B8B131EC155000AD0F6 /* XBApplicationEx.cpp in Sources */,
F56C7B9B131EC1B4000AD0F6 /* AutoPool.mm in Sources */,
- F56C7BC9131EC2DB000AD0F6 /* XBMCAppliance.m in Sources */,
+ F56C7BC9131EC2DB000AD0F6 /* XBMCAppliance.mm in Sources */,
F56C7BCA131EC2DB000AD0F6 /* XBMCController.mm in Sources */,
F56C7BDC131EC390000AD0F6 /* WinEventsIOS.mm in Sources */,
F56C7BDD131EC390000AD0F6 /* WinSystemIOS.mm in Sources */,
View
1 tools/darwin/packaging/xbmc-atv2/mkdeb-xbmc-atv2.sh
@@ -79,6 +79,7 @@ chmod +x $DIRNAME/$PACKAGE/DEBIAN/prerm
# postinst: symlink XBMC.frappliance into correct location and reload Lowtide/AppleTV.
echo "#!/bin/sh" > $DIRNAME/$PACKAGE/DEBIAN/postinst
echo "chown -R mobile:mobile /Applications/XBMC.frappliance" >> $DIRNAME/$PACKAGE/DEBIAN/postinst
+echo "cp /Applications/XBMC.frappliance/AppIcon.png /Applications/AppleTV.app/com.apple.frontrow.appliance.xbmc\@720p.png" >> $DIRNAME/$PACKAGE/DEBIAN/postinst
echo "if [ \"\`uname -r\`\" = \"10.3.1\" ]; then" >> $DIRNAME/$PACKAGE/DEBIAN/postinst
echo " ln -sf /Applications/XBMC.frappliance /Applications/Lowtide.app/Appliances/XBMC.frappliance" >> $DIRNAME/$PACKAGE/DEBIAN/postinst
echo " killall Lowtide" >> $DIRNAME/$PACKAGE/DEBIAN/postinst
View
BIN tools/darwin/packaging/xbmc-seatbeltunlock/f387cee7d7d302ec9e740632f44f1352.patch
Binary file not shown.
View
12 tools/darwin/packaging/xbmc-seatbeltunlock/mkdeb-xbmc-seatbeltunlock.sh
@@ -12,7 +12,7 @@ fi
PACKAGE=org.xbmc.xbmc-seatbeltunlock
VERSION=1.0
-REVISION=4
+REVISION=5
ARCHIVE=${PACKAGE}_${VERSION}-${REVISION}_iphoneos-arm.deb
echo Creating $PACKAGE package version $VERSION revision $REVISION
@@ -77,6 +77,15 @@ echo " chmod 755 /var/tmp/AppleTV-nosb" >> $PACKAGE/DEBIAN/posti
echo " mv -f /Applications/AppleTV.app/AppleTV /Applications/AppleTV.app/AppleTV_org" >> $PACKAGE/DEBIAN/postinst
echo " mv /var/tmp/AppleTV-nosb /Applications/AppleTV.app/AppleTV" >> $PACKAGE/DEBIAN/postinst
echo " killall AppleTV ;;" >> $PACKAGE/DEBIAN/postinst
+echo " f387cee7d7d302ec9e740632f44f1352 )" >> $PACKAGE/DEBIAN/postinst
+echo " echo \"Found 6.1 (10B144b):Removing seatbelt profile key from AppleTV\"" >> $PACKAGE/DEBIAN/postinst
+echo " bspatch /Applications/AppleTV.app/AppleTV /var/tmp/AppleTV-nosb /var/tmp/f387cee7d7d302ec9e740632f44f1352.patch" >> $PACKAGE/DEBIAN/postinst
+echo " rm /var/tmp/f387cee7d7d302ec9e740632f44f1352.patch" >> $PACKAGE/DEBIAN/postinst
+echo " chmod 755 /var/tmp/AppleTV-nosb" >> $PACKAGE/DEBIAN/postinst
+echo " mv -f /Applications/AppleTV.app/AppleTV /Applications/AppleTV.app/AppleTV_org" >> $PACKAGE/DEBIAN/postinst
+echo " mv /var/tmp/AppleTV-nosb /Applications/AppleTV.app/AppleTV" >> $PACKAGE/DEBIAN/postinst
+echo " killall AppleTV ;;" >> $PACKAGE/DEBIAN/postinst
+
echo " * )" >> $PACKAGE/DEBIAN/postinst
echo " echo \"Frontrow app md5sum is unknown, not patching\" ;;" >> $PACKAGE/DEBIAN/postinst
echo "esac" >> $PACKAGE/DEBIAN/postinst
@@ -88,6 +97,7 @@ cp 12313417e3afeba6531255af58cb5283.patch $PACKAGE/var/tmp/
cp 5a28620a15c15d41e1ae836dd1f95f8d.patch $PACKAGE/var/tmp/
cp 03e48c66a9cae1ff768eb3fe7981c499.patch $PACKAGE/var/tmp/
cp 42d00865f281bb662b6ce447c9815e59.patch $PACKAGE/var/tmp/
+cp f387cee7d7d302ec9e740632f44f1352.patch $PACKAGE/var/tmp/
# set ownership to root:root
${SUDO} chown -R 0:0 $PACKAGE
View
6 xbmc/osx/DarwinUtils.mm
@@ -177,7 +177,7 @@ int GetDarwinFrameworkPath(bool forPython, char* path, uint32_t *pathsize)
*pathsize = 0;
// a) XBMC frappliance running under ATV2
- Class XBMCfrapp = NSClassFromString(@"XBMCAppliance");
+ Class XBMCfrapp = NSClassFromString(@"XBMCATV2Detector");
if (XBMCfrapp != NULL)
{
pathname = [[NSBundle bundleForClass:XBMCfrapp] pathForResource:@"Frameworks" ofType:@""];
@@ -234,7 +234,7 @@ int GetDarwinExecutablePath(char* path, uint32_t *pathsize)
NSString *pathname;
// a) XBMC frappliance running under ATV2
- Class XBMCfrapp = NSClassFromString(@"XBMCAppliance");
+ Class XBMCfrapp = NSClassFromString(@"XBMCATV2Detector");
if (XBMCfrapp != NULL)
{
pathname = [[NSBundle bundleForClass:XBMCfrapp] pathForResource:@"XBMC" ofType:@""];
@@ -260,7 +260,7 @@ bool DarwinHasVideoToolboxDecoder(void)
if (DecoderAvailable == -1)
{
- Class XBMCfrapp = NSClassFromString(@"XBMCAppliance");
+ Class XBMCfrapp = NSClassFromString(@"XBMCATV2Detector");
if (XBMCfrapp != NULL)
{
// atv2 has seatbelt profile key removed so nothing to do here
View
4 xbmc/osx/IOSScreenManager.mm
@@ -31,6 +31,7 @@
#undef BOOL
#import <Foundation/Foundation.h>
+#include <objc/runtime.h>
#import "IOSScreenManager.h"
#import "XBMCController.h"
@@ -218,7 +219,8 @@ + (CGRect) getLandscapeResolution:(UIScreen *)screen
#if __IPHONE_OS_VERSION_MIN_REQUIRED > __IPHONE_4_2
res.size = screen.preferredMode.size;
#else
- res.size = [BRWindow interfaceFrame].size;
+ Class brwin = objc_getClass("BRWindow");
+ res.size = [brwin interfaceFrame].size;
#endif
#else
//main screen is in portrait mode (physically) so exchange height and width
View
2 xbmc/osx/atv2/XBMCATV2-Info.plist
@@ -40,5 +40,7 @@
<string>4.1</string>
<key>NSPrincipalClass</key>
<string>XBMCAppliance</string>
+ <key>FRApplianceName</key>
+ <string>XBMC</string>
</dict>
</plist>
View
6 xbmc/osx/atv2/XBMCAppliance.h
@@ -28,4 +28,10 @@
XBMCTopShelfController *_topShelfController;
}
@property(nonatomic, readonly, retain) id topShelfController;
+
+- (id) initWithApplianceInfo:(id) applianceInfo;
+- (void) setTopShelfController:(id) topShelfControl;
+- (void) setApplianceCategories:(id) applianceCategories;
+- (void) XBMCfixUIDevice;
+- (id) init;
@end
View
218 xbmc/osx/atv2/XBMCAppliance.m
@@ -1,218 +0,0 @@
-/*
- * Copyright (C) 2010-2013 Team XBMC
- * http://www.xbmc.org
- *
- * This Program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * This Program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with XBMC; see the file COPYING. If not, see
- * <http://www.gnu.org/licenses/>.
- *
- */
-
-#import <Foundation/Foundation.h>
-#import <UIKit/UIKit.h>
-#import <BackRow/BackRow.h>
-// objc-runtime.h is missing from iPhoneOS4.2SDK but present in iPhoneSimulator4.2.sdk
-// pull it from runtime system for now
-#import "/usr/include/objc/objc-runtime.h"
-
-#import "XBMCAppliance.h"
-#import "XBMCController.h"
-
-#define XBMCAppliance_CAT [BRApplianceCategory categoryWithName:@"XBMC" identifier:@"xbmc" preferredOrder:-5]
-
-// ATVVersionInfo declare to shut up compiler warning
-@interface ATVVersionInfo : NSObject
-{
-}
-+ (id)currentOSVersion;
-@end
-//--------------------------------------------------------------
-//--------------------------------------------------------------
-@interface BRTopShelfView (specialAdditions)
-//
-- (BRImageControl *)productImage;
-
-@end
-
-@implementation BRTopShelfView (specialAdditions)
-- (BRImageControl *)productImage
-{
- Ivar ivar = object_getInstanceVariable(self, "_productImage", NULL);
- id result = object_getIvar(self, ivar);
- return result;
-}
-@end
-
-//--------------------------------------------------------------
-//--------------------------------------------------------------
-@interface XBMCTopShelfController : NSObject
-{
-}
-- (void) selectCategoryWithIdentifier:(id)identifier;
-- (id) topShelfView;
-// added in 4.1+
-- (void) refresh;
-@end
-
-@implementation XBMCTopShelfController
-//
-- (void) selectCategoryWithIdentifier:(id)identifier
-{
-}
-
-- (BRTopShelfView *)topShelfView {
- BRTopShelfView *topShelf = [[BRTopShelfView alloc] init];
- BRImageControl *imageControl = [topShelf productImage];
- BRImage *gpImage = [BRImage imageWithPath:[[NSBundle bundleForClass:[XBMCAppliance class]] pathForResource:@"XBMC" ofType:@"png"]];
- [imageControl setImage:gpImage];
-
- return topShelf;
-}
-- (void) refresh
-{
-}
-@end
-
-//--------------------------------------------------------------
-//--------------------------------------------------------------
-@implementation XBMCAppliance
-@synthesize topShelfController=_topShelfController;
-
--(void)XBMCfixUIDevice
-{
- // iOS 5.x has removed the internal load of UIKit in AppleTV app
- // and there is an overlap of some UIKit and AppleTV methods.
- // This voodoo seems to clear up the wonkiness. :)
- Class cls = NSClassFromString(@"ATVVersionInfo");
- if (cls != nil && [[cls currentOSVersion] rangeOfString:@"5."].location != NSNotFound)
- {
- id cd = nil;
-
- @try
- {
- cd = [UIDevice currentDevice];
- }
-
- @catch (NSException *e)
- {
- NSLog(@"exception: %@", e);
- }
-
- @finally
- {
- //NSLog(@"will it work the second try?");
- cd = [UIDevice currentDevice];
- NSLog(@"current device fixed: %@", cd);
- }
- }
-}
-
--(id) init
-{
- //NSLog(@"%s", __PRETTY_FUNCTION__);
-
- if ((self = [super init]) != nil)
- {
- _topShelfController = [[XBMCTopShelfController alloc] init];
- _applianceCategories = [[NSArray alloc] initWithObjects:XBMCAppliance_CAT ,nil];
- }
-
- return self;
-}
-
-- (void) dealloc
-{
- //NSLog(@"%s", __PRETTY_FUNCTION__);
-
- [_applianceCategories release];
- [_topShelfController release];
-
- [super dealloc];
-}
-
-- (id) applianceCategories
-{
- // on ios 5.x this gets called whenever a user hits the xbmc icon
- // in the frontrow mainmenu
- // we use this indication for faking the "select" key.
- // This leads to a one click start of XBMC instead of needing
- // to hit select on the only XBMC category called "XBMC" again ;)
- Class cls = NSClassFromString(@"ATVVersionInfo");
- if (cls != nil && [[cls currentOSVersion] rangeOfString:@"5."].location != NSNotFound)
- {
- // eventaction 5 == kBREventRemoteActionPlay from XBMCController.m
- // value == 1 meanse we pressed that key
- BREvent *eventKeySelect = [BREvent eventWithAction:5 value:1];
- // when we suppress the sound below
- // this will even suppress the initial click
- // sound because this is threaded
- // thats why we just play that first click sound
- // directly here before suppressing the sounds
- // and doing the fake click (which would result in an unwanted
- // second click sound without that hack)
- [BRSoundHandler playSound:1];// sound number 1 is the ios click sound
- // ios >= 5 only - so ignore the compiler warning on older SDKs
- // since we guarded that code with the currentOSVersion above
- [BRSoundHandler setSoundSuppressed:TRUE];
- [[BRApplication sharedApplication] postEvent:eventKeySelect];
- }
-
- return _applianceCategories;
-}
-
-- (id) identifierForContentAlias:(id)contentAlias
-{
- return @"xbmc";
-}
-
-- (id) selectCategoryWithIdentifier:(id)ident
-{
- //NSLog(@"eglv2:selecteCategoryWithIdentifier: %@", ident);
-
- return nil;
-}
-- (BOOL) handleObjectSelection:(id)fp8 userInfo:(id)fp12
-{
- //NSLog(@"%s", __PRETTY_FUNCTION__);
-
- return YES;
-}
-
-- (id) applianceSpecificControllerForIdentifier:(id)arg1 args:(id)arg2
-{
- return nil;
-}
-- (BOOL) handlePlay:(id)play userInfo:(id)info
-{
- //NSLog(@"%s", __PRETTY_FUNCTION__);
-
- return YES;
-}
-
-- (id) controllerForIdentifier:(id)identifier args:(id)args
-{
- //NSLog(@"%s", __PRETTY_FUNCTION__);
-
- [self XBMCfixUIDevice];
- XBMCController *controller = [[[XBMCController alloc] init] autorelease];
- //XBMCController *controller = [XBMCController sharedInstance];
- return controller;
-}
-
-- (id) localizedSearchTitle { return @"xbmc"; }
-- (id) applianceName { return @"xbmc"; }
-- (id) moduleName { return @"xbmc"; }
-- (id) applianceKey { return @"xbmc"; }
-
-@end
-
View
433 xbmc/osx/atv2/XBMCAppliance.mm
@@ -0,0 +1,433 @@
+/*
+ * Copyright (C) 2010-2013 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ */
+
+
+/* HowTo code in this file:
+ * Since AppleTV/iOS6.x (atv2 version 5.2) Apple removed the AppleTV.framework and put all those classes into the
+ * AppleTV.app. So we can't use standard obj-c coding here anymore. Instead we need to use the obj-c runtime
+ * functions for subclassing and adding methods to our instances during runtime (hooking).
+ *
+ * 1. For implementing a method of a base class:
+ * a) declare it in the form <XBMCAppliance$nameOfMethod> like the others
+ * b) these methods need to be static and have XBMCAppliance* self, SEL _cmd (replace XBMCAppliance with the class the method gets implemented for) as minimum params.
+ * c) add the method to the XBMCAppliance.h for getting rid of the compiler warnings of unresponsive selectors (declare the method like done in the baseclass).
+ * d) in initApplianceRuntimeClasses exchange the base class implementation with ours by calling MSHookMessageEx
+ * e) if we need to call the base class implementation as well we have to save the original implementation (see initWithApplianceInfo$Orig for reference)
+ *
+ * 2. For implementing a new method which is not part of the base class:
+ * a) same as 1.a
+ * b) same as 1.b
+ * c) same as 1.c
+ * d) in initApplianceRuntimeClasses add the method to our class via class_addMethod
+ *
+ * 3. Never access any BackRow classes directly - but always get the class via objc_getClass - if the class is used in multiple places
+ * save it as static (see BRApplianceCategoryCls)
+ *
+ * 4. Keep the structure of this file based on the section comments (marked with // SECTIONCOMMENT).
+ * 5. really - obey 4.!
+ *
+ * 6. for adding class members use associated objects - see topShelfControllerKey
+ *
+ * For further reference see https://developer.apple.com/library/mac/#documentation/Cocoa/Reference/ObjCRuntimeRef/Reference/reference.html
+ */
+
+#import <Foundation/Foundation.h>
+#import <UIKit/UIKit.h>
+// objc-runtime.h is missing from iPhoneOS4.2SDK but present in iPhoneSimulator4.2.sdk
+// pull it from runtime system for now
+#import "/usr/include/objc/objc-runtime.h"
+
+#import "XBMCAppliance.h"
+#import "XBMCController.h"
+#include "substrate.h"
+
+// SECTIONCOMMENT
+// classes we need multiple times
+static Class BRApplianceCategoryCls;
+
+// category for ios5.x and higher is just a short text before xbmc auto starts
+#define XBMCAppliance_CAT_5andhigher [BRApplianceCategoryCls categoryWithName:@"XBMC is starting..." identifier:@"xbmc" preferredOrder:0]
+// category for ios4.x is the menu entry
+#define XBMCAppliance_CAT_4 [BRApplianceCategoryCls categoryWithName:@"XBMC" identifier:@"xbmc" preferredOrder:0]
+
+// SECTIONCOMMENT
+// forward declaration all referenced classes
+@class XBMCAppliance;
+@class BRTopShelfView;
+@class XBMCApplianceInfo;
+
+// SECTIONCOMMENT
+// orig method handlers we wanna call in hooked methods
+static id (*XBMCAppliance$initWithApplianceInfo$Orig)(XBMCAppliance*, SEL, id);
+static id (*XBMCAppliance$init$Orig)(XBMCAppliance*, SEL);
+static id (*XBMCAppliance$applianceInfo$Orig)(XBMCAppliance*, SEL);
+
+//--------------------------------------------------------------
+//--------------------------------------------------------------
+// ATVVersionInfo declare to shut up compiler warning
+@interface ATVVersionInfo : NSObject
+{
+}
++ (id)currentOSVersion;
+
+@end
+
+@interface XBMCATV2Detector : NSObject{}
++ (BOOL) hasOldGui;
++ (BOOL) isIos5;
++ (BOOL) needsApplianceInfoHack;
+@end
+
+//--------------------------------------------------------------
+//--------------------------------------------------------------
+// We need a real implementation (not a runtime generated one)
+// for getting our NSBundle instance by calling
+// [[NSBundle bundleForClass:objc_getClass("XBMCATV2Detector")]
+// so we just implement some usefull helpers here
+// and use those
+@implementation XBMCATV2Detector : NSObject{}
++ (BOOL) hasOldGui
+{
+ Class cls = NSClassFromString(@"ATVVersionInfo");
+ if (cls != nil && [[cls currentOSVersion] rangeOfString:@"4."].location != NSNotFound)
+ return TRUE;
+ if (cls != nil && [[cls currentOSVersion] rangeOfString:@"5.0"].location != NSNotFound)
+ return TRUE;
+ return FALSE;
+}
+
++ (BOOL) isIos5
+{
+ Class cls = NSClassFromString(@"ATVVersionInfo");
+ if (cls != nil && [[cls currentOSVersion] rangeOfString:@"5."].location != NSNotFound)
+ return TRUE;
+ return FALSE;
+}
+
++ (BOOL) needsApplianceInfoHack
+{
+ // if the runtime base class (BRBaseAppliance) doesn't have the initWithApplianceInfo selector
+ // we need to hack the appliance info in (id) applianceInfo (XBMCAppliance$applianceInfo)
+ if (class_respondsToSelector(objc_getClass("BRBaseAppliance"),@selector(initWithApplianceInfo:)))
+ return FALSE;
+ return TRUE;
+}
+@end
+
+//--------------------------------------------------------------
+//--------------------------------------------------------------
+// XBMCApplication declare to shut up compiler warning of BRApplication
+@interface XBMCApplication : NSObject
+{
+}
+- (void)setFirstResponder:(id)responder;
+@end
+
+//--------------------------------------------------------------
+//--------------------------------------------------------------
+@interface XBMCTopShelfController : NSObject
+{
+}
+- (void) selectCategoryWithIdentifier:(id)identifier;
+- (id) topShelfView;
+// added in 4.1+
+- (void) refresh;
+@end
+
+//--------------------------------------------------------------
+//--------------------------------------------------------------
+@implementation XBMCTopShelfController
+
+- (void) selectCategoryWithIdentifier:(id)identifier
+{
+}
+
+- (BRTopShelfView *)topShelfView
+{
+ Class cls = objc_getClass("BRTopShelfView");
+ id topShelf = [[cls alloc] init];
+
+ // diddle the topshelf logo on old gui
+ if ([XBMCATV2Detector hasOldGui])
+ {
+ Class cls = objc_getClass("BRImage");
+ BRImageControl *imageControl = (BRImageControl *)MSHookIvar<id>(topShelf, "_productImage");// hook the productImage so we can diddle with it
+ BRImage *gpImage = [cls imageWithPath:[[NSBundle bundleForClass:[XBMCATV2Detector class]] pathForResource:@"XBMC" ofType:@"png"]];
+ [imageControl setImage:gpImage];
+ }
+
+ return topShelf;
+}
+
+- (void) refresh
+{
+}
+@end
+
+//--------------------------------------------------------------
+//--------------------------------------------------------------
+// SECTIONCOMMENT
+// since we can't inject ivars we need to use associated objects
+// these are the keys for XBMCAppliance
+//implementation XBMCAppliance
+static char const * const topShelfControllerKey = "topShelfController";
+static char const * const applianceCategoriesKey = "applianceCategories";
+
+static NSString* XBMCApplianceInfo$key(XBMCApplianceInfo* self, SEL _cmd)
+{
+ return [[[NSBundle bundleForClass:objc_getClass("XBMCATV2Detector")] infoDictionary] objectForKey:(NSString*)kCFBundleIdentifierKey];
+}
+
+static NSString* XBMCApplianceInfo$name(XBMCApplianceInfo* self, SEL _cmd)
+{
+ return [[[NSBundle bundleForClass:objc_getClass("XBMCATV2Detector")] infoDictionary] objectForKey:(NSString*)kCFBundleNameKey];
+}
+
+static id XBMCApplianceInfo$localizedStringsFileName(XBMCApplianceInfo* self, SEL _cmd)
+{
+ return @"xbmc";
+}
+
+static void XBMCAppliance$XBMCfixUIDevice(XBMCAppliance* self, SEL _cmd)
+{
+ // iOS 5.x has removed the internal load of UIKit in AppleTV app
+ // and there is an overlap of some UIKit and AppleTV methods.
+ // This voodoo seems to clear up the wonkiness. :)
+ if ([XBMCATV2Detector isIos5])
+ {
+ id cd = nil;
+
+ @try
+ {
+ cd = [UIDevice currentDevice];
+ }
+
+ @catch (NSException *e)
+ {
+ NSLog(@"exception: %@", e);
+ }
+
+ @finally
+ {
+ //NSLog(@"will it work the second try?");
+ cd = [UIDevice currentDevice];
+ NSLog(@"current device fixed: %@", cd);
+ }
+ }
+}
+
+
+static id XBMCAppliance$init(XBMCAppliance* self, SEL _cmd)
+{
+ //NSLog(@"%s", __PRETTY_FUNCTION__);
+ if ([XBMCATV2Detector needsApplianceInfoHack])
+ {
+ NSLog(@"%s for ios 4", __PRETTY_FUNCTION__);
+ if ((self = XBMCAppliance$init$Orig(self, _cmd))!= nil)
+ {
+ id topShelfControl = [[XBMCTopShelfController alloc] init];
+ [self setTopShelfController:topShelfControl];
+
+ NSArray *catArray = [[NSArray alloc] initWithObjects:XBMCAppliance_CAT_4,nil];
+ [self setApplianceCategories:catArray];
+ return self;
+ }
+ }
+ else// ios >= 5
+ {
+ NSLog(@"%s for ios 5 and newer", __PRETTY_FUNCTION__);
+ return [self initWithApplianceInfo:nil]; // legacy for ios < 6
+ }
+ return self;
+}
+
+static id XBMCAppliance$identifierForContentAlias(XBMCAppliance* self, SEL _cmd, id contentAlias)
+{
+ return@"xbmc";
+}
+
+static BOOL XBMCAppliance$handleObjectSelection(XBMCAppliance* self, SEL _cmd, id fp8, id fp12)
+{
+ //NSLog(@"%s", __PRETTY_FUNCTION__);
+ return YES;
+}
+
+static id XBMCAppliance$applianceInfo(XBMCAppliance* self, SEL _cmd)
+{
+ //NSLog(@"%s", __PRETTY_FUNCTION)
+
+ // load our plist into memory and merge it with
+ // the dict from the baseclass if needed
+ // cause ios seems to fail on that somehow (at least on 4.x)
+ if ([XBMCATV2Detector needsApplianceInfoHack] && self != nil)
+ {
+ id original = XBMCAppliance$applianceInfo$Orig(self, _cmd);
+ id info = MSHookIvar<id>(original, "_info");// hook the infoDictionary so we can diddle with it
+
+ NSString *plistPath = [[NSBundle bundleForClass:objc_getClass("XBMCATV2Detector")] pathForResource:@"Info" ofType:@"plist"];
+ NSString *bundlePath = [[NSBundle bundleForClass:objc_getClass("XBMCATV2Detector")] bundlePath];
+ NSMutableDictionary *ourInfoDict = [[NSMutableDictionary alloc] initWithContentsOfFile:plistPath];
+
+ if (ourInfoDict != nil && bundlePath != nil)
+ {
+ // inject this or we won't get shown up properly on ios4
+ [ourInfoDict setObject:bundlePath forKey:@"NSBundleInitialPath"];
+
+ // add our plist info to the baseclass info and return it
+ [(NSMutableDictionary *)info addEntriesFromDictionary:ourInfoDict];
+ [ourInfoDict release];
+ }
+ return original;
+ }
+ else
+ {
+ Class cls = objc_getClass("XBMCApplianceInfo");
+ return [[[cls alloc] init] autorelease];
+ }
+ return nil;
+}
+
+
+static id XBMCAppliance$topShelfController(XBMCAppliance* self, SEL _cmd)
+{
+ return objc_getAssociatedObject(self, topShelfControllerKey);
+}
+
+
+static void XBMCAppliance$setTopShelfController(XBMCAppliance* self, SEL _cmd, id topShelfControl)
+{
+ objc_setAssociatedObject(self, topShelfControllerKey, topShelfControl, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
+}
+
+static id XBMCAppliance$applianceCategories(XBMCAppliance* self, SEL _cmd)
+{
+ return objc_getAssociatedObject(self, applianceCategoriesKey);
+}
+
+static void XBMCAppliance$setApplianceCategories(XBMCAppliance* self, SEL _cmd, id applianceCategories)
+{
+ objc_setAssociatedObject(self, applianceCategoriesKey, applianceCategories, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
+}
+
+static id XBMCAppliance$initWithApplianceInfo(XBMCAppliance* self, SEL _cmd, id applianceInfo)
+{
+ //NSLog(@"%s", __PRETTY_FUNCTION__);
+ if((self = XBMCAppliance$initWithApplianceInfo$Orig(self, _cmd, applianceInfo)) != nil)
+ {
+ id topShelfControl = [[XBMCTopShelfController alloc] init];
+ [self setTopShelfController:topShelfControl];
+
+ NSArray *catArray = [[NSArray alloc] initWithObjects:XBMCAppliance_CAT_5andhigher,nil];
+ [self setApplianceCategories:catArray];
+ }
+ return self;
+}
+
+static id XBMCAppliance$controllerForIdentifier(XBMCAppliance* self, SEL _cmd, id identifier, id args)
+{
+ //NSLog(@"%s", __PRETTY_FUNCTION__);
+ id menuController = nil;
+ Class cls = objc_getClass("BRApplication");
+ if ([identifier isEqualToString:@"xbmc"])
+ {
+ [self XBMCfixUIDevice];
+ menuController = [[objc_getClass("XBMCController") alloc] init];
+ if (menuController == nil)
+ NSLog(@"initialise controller - fail");
+ }
+ XBMCApplication *brapp = (XBMCApplication *)[cls sharedApplication];
+ [brapp setFirstResponder:menuController];
+ return menuController;
+}
+
+// SECTIONCOMMENT
+// c'tor - this sets up our class at runtime by
+// 1. subclassing from the base classes
+// 2. adding new methods to our class
+// 3. exchanging (hooking) base class methods with ours
+// 4. register the classes to the objc runtime system
+static __attribute__((constructor)) void initApplianceRuntimeClasses()
+{
+ // subclass BRApplianceInfo into XBMCApplianceInfo
+ Class XBMCApplianceInfoCls = objc_allocateClassPair(objc_getClass("BRApplianceInfo"), "XBMCApplianceInfo", 0);
+
+ // and hook up our methods (implementation of the base class methods)
+ // XBMCApplianceInfo::key
+ MSHookMessageEx(XBMCApplianceInfoCls,@selector(key), (IMP)&XBMCApplianceInfo$key, nil);
+ // XBMCApplianceInfo::name
+ MSHookMessageEx(XBMCApplianceInfoCls,@selector(name), (IMP)&XBMCApplianceInfo$name, nil);
+
+ //not available in ios4.x - so probe or crash&burn
+ if (class_respondsToSelector(objc_getClass("BRApplianceInfo"),@selector(localizedStringsFileName)))
+ {
+ // XBMCApplianceInfo::localizedStringsFileName
+ MSHookMessageEx(XBMCApplianceInfoCls,@selector(localizedStringsFileName), (IMP)&XBMCApplianceInfo$localizedStringsFileName, nil);
+ }
+ else// else we need to add it
+ {
+ class_addMethod(XBMCApplianceInfoCls,@selector(localizedStringsFileName), (IMP)&XBMCApplianceInfo$localizedStringsFileName, "@@:");
+ }
+ // and register the class to the runtime
+ objc_registerClassPair(XBMCApplianceInfoCls);
+
+ // subclass BRBaseAppliance into XBMCAppliance
+ Class XBMCApplianceCls = objc_allocateClassPair(objc_getClass("BRBaseAppliance"), "XBMCAppliance", 0);
+ // add our custom methods which are not part of the baseclass
+ // XBMCAppliance::XBMCfixUIDevice
+ class_addMethod(XBMCApplianceCls,@selector(XBMCfixUIDevice), (IMP)XBMCAppliance$XBMCfixUIDevice, "v@:");
+ class_addMethod(XBMCApplianceCls,@selector(setTopShelfController:), (IMP)&XBMCAppliance$setTopShelfController, "v@:@");
+ class_addMethod(XBMCApplianceCls,@selector(setApplianceCategories:), (IMP)&XBMCAppliance$setApplianceCategories, "v@:@");
+
+ // and hook up our methods (implementation of the base class methods)
+ // XBMCAppliance::init
+ MSHookMessageEx(XBMCApplianceCls,@selector(init), (IMP)&XBMCAppliance$init, (IMP*)&XBMCAppliance$init$Orig);
+ // XBMCAppliance::identifierForContentAlias
+ MSHookMessageEx(XBMCApplianceCls,@selector(identifierForContentAlias:), (IMP)&XBMCAppliance$identifierForContentAlias, nil);
+
+ // not there in ios6 - probing for getting rid of the syslog warning
+ if (class_respondsToSelector(objc_getClass("BRBaseAppliance"),@selector(handleObjectSelection:userInfo:)))
+ {
+ // XBMCAppliance::handleObjectSelection
+ MSHookMessageEx(XBMCApplianceCls,@selector(handleObjectSelection:userInfo:), (IMP)&XBMCAppliance$handleObjectSelection, nil);
+ }
+
+ // XBMCAppliance::applianceInfo
+ MSHookMessageEx(XBMCApplianceCls,@selector(applianceInfo), (IMP)&XBMCAppliance$applianceInfo, (IMP *)&XBMCAppliance$applianceInfo$Orig);
+ // XBMCAppliance::topShelfController
+ MSHookMessageEx(XBMCApplianceCls,@selector(topShelfController), (IMP)&XBMCAppliance$topShelfController, nil);
+ // XBMCAppliance::applianceCategories
+ MSHookMessageEx(XBMCApplianceCls,@selector(applianceCategories), (IMP)&XBMCAppliance$applianceCategories, nil);
+
+ // not there on ios 4.x - probing ...
+ if (class_respondsToSelector(objc_getClass("BRBaseAppliance"),@selector(initWithApplianceInfo:)))
+ {
+ // XBMCAppliance::initWithApplianceInfo
+ MSHookMessageEx(XBMCApplianceCls,@selector(initWithApplianceInfo:), (IMP)&XBMCAppliance$initWithApplianceInfo, (IMP*)&XBMCAppliance$initWithApplianceInfo$Orig);
+ }
+
+ // XBMCAppliance::controllerForIdentifier
+ MSHookMessageEx(XBMCApplianceCls,@selector(controllerForIdentifier:args:), (IMP)&XBMCAppliance$controllerForIdentifier, nil);
+
+ // and register the class to the runtime
+ objc_registerClassPair(XBMCApplianceCls);
+
+ // save this as static for referencing it in the macro at the top of the file
+ BRApplianceCategoryCls = objc_getClass("BRApplianceCategory");
+}
View
13 xbmc/osx/atv2/XBMCController.h
@@ -58,7 +58,18 @@
- (void) stopAnimation;
- (bool) changeScreen: (unsigned int)screenIdx withMode:(UIScreenMode *)mode;
- (void) activateScreen: (UIScreen *)screen;
-
+- (id) glView;
+- (void) setGlView:(id)view;
+- (BOOL) ATVClientEventFromBREvent:(id)event Repeatable:(bool *)isRepeatable ButtonState:(bool *)isPressed Result:(int *)xbmc_ir_key;
+- (void) setUserEvent:(int) eventId withHoldTime:(unsigned int) holdTime;
+- (void) startKeyPressTimer:(int) keyId;
+- (void) stopKeyPressTimer;
+- (void) setSystemSleepTimeout:(id) timeout;
+- (id) systemSleepTimeout;
+- (void) setKeyTimer:(id) timer;
+- (id) keyTimer;
+- (void) setSystemScreenSaverTimeout:(id) timeout;
+- (id) systemScreenSaverTimeout;
@end
View
1,376 xbmc/osx/atv2/XBMCController.mm
853 additions, 523 deletions not shown because the diff is too large. Please use a local Git client to view these changes.
View
31 xbmc/osx/atv2/substrate.h
@@ -0,0 +1,31 @@
+#include <string.h>
+#include <sys/types.h>
+#include <objc/runtime.h>
+#ifdef __cplusplus
+#define _default(x) = x
+extern "C" {
+#else
+#define _default(x)
+#endif
+typedef const void *MSImageRef;
+void MSHookFunction(void *symbol, void *replace, void **result);
+void *MSFindSymbol(const void *image, const char *name);
+MSImageRef MSGetImageByName(const char *file);
+
+#ifdef __APPLE__
+#ifdef __arm__
+IMP MSHookMessage(Class _class, SEL sel, IMP imp, const char *prefix _default(NULL));
+#endif
+void MSHookMessageEx(Class _class, SEL sel, IMP imp, IMP *result);
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+template <typename Type_> Type_ &MSHookIvar(id self, const char *name) {
+ Ivar ivar(class_getInstanceVariable(object_getClass(self), name));
+ void *pointer(ivar == NULL ? NULL : reinterpret_cast<char *>(self) + ivar_getOffset(ivar));
+ return *reinterpret_cast<Type_ *>(pointer);
+}
+
+

0 comments on commit 42e3b06

Please sign in to comment.
Something went wrong with that request. Please try again.