Skip to content
This repository
Browse code

[atv2] - rewrite the XBMCAppliance and XBMCController for using obj-c…

… runtime class definition and hooking. This is needed for supporting atv2 on ios6 (see the comments in the impl.)
  • Loading branch information...
commit 71a68133ced1ec3a3e7ea8e198a71b159bd36885 1 parent e49ab72
Memphiz authored February 20, 2013
8  XBMC-ATV2.xcodeproj/project.pbxproj
@@ -896,7 +896,7 @@
896 896
 		F56C7B89131EC155000AD0F6 /* Util.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F56C780A131EC154000AD0F6 /* Util.cpp */; };
897 897
 		F56C7B8B131EC155000AD0F6 /* XBApplicationEx.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F56C780E131EC154000AD0F6 /* XBApplicationEx.cpp */; };
898 898
 		F56C7B9B131EC1B4000AD0F6 /* AutoPool.mm in Sources */ = {isa = PBXBuildFile; fileRef = F56C7B9A131EC1B4000AD0F6 /* AutoPool.mm */; };
899  
-		F56C7BC9131EC2DB000AD0F6 /* XBMCAppliance.m in Sources */ = {isa = PBXBuildFile; fileRef = F56C7BC2131EC2DB000AD0F6 /* XBMCAppliance.m */; };
  899
+		F56C7BC9131EC2DB000AD0F6 /* XBMCAppliance.mm in Sources */ = {isa = PBXBuildFile; fileRef = F56C7BC2131EC2DB000AD0F6 /* XBMCAppliance.mm */; };
900 900
 		F56C7BCA131EC2DB000AD0F6 /* XBMCController.mm in Sources */ = {isa = PBXBuildFile; fileRef = F56C7BC5131EC2DB000AD0F6 /* XBMCController.mm */; };
901 901
 		F56C7BD0131EC301000AD0F6 /* XBMC.png in Resources */ = {isa = PBXBuildFile; fileRef = F56C7BCD131EC301000AD0F6 /* XBMC.png */; };
902 902
 		F56C7BDC131EC390000AD0F6 /* WinEventsIOS.mm in Sources */ = {isa = PBXBuildFile; fileRef = F56C7BD9131EC390000AD0F6 /* WinEventsIOS.mm */; };
@@ -2973,7 +2973,7 @@
2973 2973
 		F56C780F131EC154000AD0F6 /* XBApplicationEx.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = XBApplicationEx.h; sourceTree = "<group>"; };
2974 2974
 		F56C7B99131EC1B4000AD0F6 /* AutoPool.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AutoPool.h; sourceTree = "<group>"; };
2975 2975
 		F56C7B9A131EC1B4000AD0F6 /* AutoPool.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = AutoPool.mm; sourceTree = "<group>"; };
2976  
-		F56C7BC2131EC2DB000AD0F6 /* XBMCAppliance.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = XBMCAppliance.m; sourceTree = "<group>"; };
  2976
+		F56C7BC2131EC2DB000AD0F6 /* XBMCAppliance.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = XBMCAppliance.mm; sourceTree = "<group>"; };
2977 2977
 		F56C7BC3131EC2DB000AD0F6 /* XBMCAppliance.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = XBMCAppliance.h; sourceTree = "<group>"; };
2978 2978
 		F56C7BC4131EC2DB000AD0F6 /* XBMCController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = XBMCController.h; sourceTree = "<group>"; };
2979 2979
 		F56C7BC5131EC2DB000AD0F6 /* XBMCController.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = XBMCController.mm; sourceTree = "<group>"; };
@@ -6015,7 +6015,7 @@
6015 6015
 				F56C7F2D131F0BB4000AD0F6 /* English.lproj */,
6016 6016
 				F56C7BCD131EC301000AD0F6 /* XBMC.png */,
6017 6017
 				F56C7BC3131EC2DB000AD0F6 /* XBMCAppliance.h */,
6018  
-				F56C7BC2131EC2DB000AD0F6 /* XBMCAppliance.m */,
  6018
+				F56C7BC2131EC2DB000AD0F6 /* XBMCAppliance.mm */,
6019 6019
 				F56C7BCE131EC301000AD0F6 /* XBMCATV2-Info.plist */,
6020 6020
 				F56C7BC4131EC2DB000AD0F6 /* XBMCController.h */,
6021 6021
 				F56C7BC5131EC2DB000AD0F6 /* XBMCController.mm */,
@@ -7323,7 +7323,7 @@
7323 7323
 				F56C7B89131EC155000AD0F6 /* Util.cpp in Sources */,
7324 7324
 				F56C7B8B131EC155000AD0F6 /* XBApplicationEx.cpp in Sources */,
7325 7325
 				F56C7B9B131EC1B4000AD0F6 /* AutoPool.mm in Sources */,
7326  
-				F56C7BC9131EC2DB000AD0F6 /* XBMCAppliance.m in Sources */,
  7326
+				F56C7BC9131EC2DB000AD0F6 /* XBMCAppliance.mm in Sources */,
7327 7327
 				F56C7BCA131EC2DB000AD0F6 /* XBMCController.mm in Sources */,
7328 7328
 				F56C7BDC131EC390000AD0F6 /* WinEventsIOS.mm in Sources */,
7329 7329
 				F56C7BDD131EC390000AD0F6 /* WinSystemIOS.mm in Sources */,
6  xbmc/osx/atv2/XBMCAppliance.h
@@ -28,4 +28,10 @@
28 28
   XBMCTopShelfController *_topShelfController;
29 29
 }
30 30
 @property(nonatomic, readonly, retain) id topShelfController;
  31
+
  32
+- (id) initWithApplianceInfo:(id) applianceInfo;
  33
+- (void) setTopShelfController:(id) topShelfControl;
  34
+- (void) setApplianceCategories:(id) applianceCategories;
  35
+- (void) XBMCfixUIDevice;
  36
+- (id) init;
31 37
 @end
218  xbmc/osx/atv2/XBMCAppliance.m
... ...
@@ -1,218 +0,0 @@
1  
-/*
2  
- *      Copyright (C) 2010-2013 Team XBMC
3  
- *      http://www.xbmc.org
4  
- *
5  
- *  This Program is free software; you can redistribute it and/or modify
6  
- *  it under the terms of the GNU General Public License as published by
7  
- *  the Free Software Foundation; either version 2, or (at your option)
8  
- *  any later version.
9  
- *
10  
- *  This Program is distributed in the hope that it will be useful,
11  
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  
- *  GNU General Public License for more details.
14  
- *
15  
- *  You should have received a copy of the GNU General Public License
16  
- *  along with XBMC; see the file COPYING.  If not, see
17  
- *  <http://www.gnu.org/licenses/>.
18  
- *
19  
- */
20  
- 
21  
-#import <Foundation/Foundation.h>
22  
-#import <UIKit/UIKit.h>
23  
-#import <BackRow/BackRow.h>
24  
-// objc-runtime.h is missing from iPhoneOS4.2SDK but present in iPhoneSimulator4.2.sdk
25  
-// pull it from runtime system for now
26  
-#import "/usr/include/objc/objc-runtime.h"
27  
-
28  
-#import "XBMCAppliance.h"
29  
-#import "XBMCController.h"
30  
-
31  
-#define XBMCAppliance_CAT [BRApplianceCategory categoryWithName:@"XBMC" identifier:@"xbmc" preferredOrder:-5]
32  
-
33  
-// ATVVersionInfo declare to shut up compiler warning
34  
-@interface ATVVersionInfo : NSObject
35  
-{
36  
-}
37  
-+ (id)currentOSVersion;
38  
-@end
39  
-//--------------------------------------------------------------
40  
-//--------------------------------------------------------------
41  
-@interface BRTopShelfView (specialAdditions)
42  
-//
43  
-- (BRImageControl *)productImage;
44  
-
45  
-@end
46  
-
47  
-@implementation BRTopShelfView (specialAdditions)
48  
-- (BRImageControl *)productImage
49  
-{
50  
-  Ivar ivar = object_getInstanceVariable(self, "_productImage", NULL);
51  
-  id result = object_getIvar(self, ivar);
52  
-  return result;
53  
-}
54  
-@end
55  
-
56  
-//--------------------------------------------------------------
57  
-//--------------------------------------------------------------
58  
-@interface XBMCTopShelfController : NSObject
59  
-{
60  
-}
61  
-- (void) selectCategoryWithIdentifier:(id)identifier;
62  
-- (id) topShelfView;
63  
-// added in 4.1+
64  
-- (void) refresh;
65  
-@end
66  
-
67  
-@implementation XBMCTopShelfController
68  
-//
69  
-- (void) selectCategoryWithIdentifier:(id)identifier 
70  
-{
71  
-}
72  
-
73  
-- (BRTopShelfView *)topShelfView {
74  
-	BRTopShelfView *topShelf = [[BRTopShelfView alloc] init];
75  
-	BRImageControl *imageControl = [topShelf productImage];
76  
-	BRImage *gpImage = [BRImage imageWithPath:[[NSBundle bundleForClass:[XBMCAppliance class]] pathForResource:@"XBMC" ofType:@"png"]];
77  
-	[imageControl setImage:gpImage];
78  
-	
79  
-	return topShelf;
80  
-}
81  
-- (void) refresh
82  
-{
83  
-}
84  
-@end
85  
-
86  
-//--------------------------------------------------------------
87  
-//--------------------------------------------------------------
88  
-@implementation XBMCAppliance
89  
-@synthesize topShelfController=_topShelfController;
90  
-
91  
--(void)XBMCfixUIDevice
92  
-{
93  
-  // iOS 5.x has removed the internal load of UIKit in AppleTV app
94  
-  // and there is an overlap of some UIKit and AppleTV methods.
95  
-  // This voodoo seems to clear up the wonkiness. :)
96  
-  Class cls = NSClassFromString(@"ATVVersionInfo");
97  
-  if (cls != nil && [[cls currentOSVersion] rangeOfString:@"5."].location != NSNotFound)
98  
-  {
99  
-    id cd = nil;
100  
-
101  
-    @try
102  
-    {
103  
-      cd = [UIDevice currentDevice];
104  
-    }
105  
-    
106  
-    @catch (NSException *e)
107  
-    {
108  
-      NSLog(@"exception: %@", e);
109  
-    }
110  
-    
111  
-    @finally
112  
-    {
113  
-      //NSLog(@"will it work the second try?");
114  
-      cd = [UIDevice currentDevice];
115  
-      NSLog(@"current device fixed: %@", cd);
116  
-    }
117  
-  }
118  
-}
119  
-
120  
--(id) init
121  
-{
122  
-  //NSLog(@"%s", __PRETTY_FUNCTION__);
123  
-
124  
-  if ((self = [super init]) != nil) 
125  
-  {
126  
-    _topShelfController = [[XBMCTopShelfController alloc] init];
127  
-    _applianceCategories = [[NSArray alloc] initWithObjects:XBMCAppliance_CAT ,nil];
128  
-	}
129  
-
130  
-  return self;
131  
-}
132  
-
133  
-- (void) dealloc
134  
-{
135  
-  //NSLog(@"%s", __PRETTY_FUNCTION__);
136  
-
137  
-  [_applianceCategories release];
138  
-  [_topShelfController release];
139  
-
140  
-	[super dealloc];
141  
-}
142  
-
143  
-- (id) applianceCategories
144  
-{
145  
-  // on ios 5.x this gets called whenever a user hits the xbmc icon
146  
-  // in the frontrow mainmenu
147  
-  // we use this indication for faking the "select" key.
148  
-  // This leads to a one click start of XBMC instead of needing
149  
-  // to hit select on the only XBMC category called "XBMC" again ;)
150  
-  Class cls = NSClassFromString(@"ATVVersionInfo");
151  
-  if (cls != nil && [[cls currentOSVersion] rangeOfString:@"5."].location != NSNotFound)
152  
-  {
153  
-    // eventaction 5 == kBREventRemoteActionPlay from XBMCController.m
154  
-    // value == 1 meanse we pressed that key
155  
-    BREvent *eventKeySelect = [BREvent eventWithAction:5 value:1];
156  
-    // when we suppress the sound below
157  
-    // this will even suppress the initial click
158  
-    // sound because this is threaded
159  
-    // thats why we just play that first click sound
160  
-    // directly here before suppressing the sounds
161  
-    // and doing the fake click (which would result in an unwanted
162  
-    // second click sound without that hack)
163  
-    [BRSoundHandler playSound:1];// sound number 1 is the ios click sound
164  
-    // ios >= 5 only - so ignore the compiler warning on older SDKs
165  
-    // since we guarded that code with the currentOSVersion above
166  
-    [BRSoundHandler setSoundSuppressed:TRUE];
167  
-    [[BRApplication sharedApplication] postEvent:eventKeySelect];
168  
-  }
169  
-
170  
-  return _applianceCategories;
171  
-}
172  
-
173  
-- (id) identifierForContentAlias:(id)contentAlias
174  
-{
175  
-	return @"xbmc";
176  
-}
177  
-
178  
-- (id) selectCategoryWithIdentifier:(id)ident
179  
-{
180  
-	//NSLog(@"eglv2:selecteCategoryWithIdentifier: %@", ident);
181  
-
182  
-	return nil;
183  
-}
184  
-- (BOOL) handleObjectSelection:(id)fp8 userInfo:(id)fp12
185  
-{
186  
-  //NSLog(@"%s", __PRETTY_FUNCTION__);
187  
-
188  
-	return YES;
189  
-}
190  
-
191  
-- (id) applianceSpecificControllerForIdentifier:(id)arg1 args:(id)arg2
192  
-{
193  
-  return nil;
194  
-}
195  
-- (BOOL) handlePlay:(id)play userInfo:(id)info
196  
-{
197  
-  //NSLog(@"%s", __PRETTY_FUNCTION__);
198  
-
199  
-  return YES;
200  
-}
201  
-
202  
-- (id) controllerForIdentifier:(id)identifier args:(id)args
203  
-{
204  
-  //NSLog(@"%s", __PRETTY_FUNCTION__);
205  
-  
206  
-  [self XBMCfixUIDevice];
207  
-  XBMCController *controller = [[[XBMCController alloc] init] autorelease];
208  
-  //XBMCController *controller = [XBMCController sharedInstance];
209  
-  return controller;
210  
-}
211  
-
212  
-- (id) localizedSearchTitle { return @"xbmc"; }
213  
-- (id) applianceName { return @"xbmc"; }
214  
-- (id) moduleName { return @"xbmc"; }
215  
-- (id) applianceKey { return @"xbmc"; }
216  
-
217  
-@end
218  
-
433  xbmc/osx/atv2/XBMCAppliance.mm
... ...
@@ -0,0 +1,433 @@
  1
+/*
  2
+ *      Copyright (C) 2010-2013 Team XBMC
  3
+ *      http://www.xbmc.org
  4
+ *
  5
+ *  This Program is free software; you can redistribute it and/or modify
  6
+ *  it under the terms of the GNU General Public License as published by
  7
+ *  the Free Software Foundation; either version 2, or (at your option)
  8
+ *  any later version.
  9
+ *
  10
+ *  This Program is distributed in the hope that it will be useful,
  11
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  12
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13
+ *  GNU General Public License for more details.
  14
+ *
  15
+ *  You should have received a copy of the GNU General Public License
  16
+ *  along with XBMC; see the file COPYING.  If not, see
  17
+ *  <http://www.gnu.org/licenses/>.
  18
+ *
  19
+ */
  20
+
  21
+
  22
+/* HowTo code in this file:
  23
+ * Since AppleTV/iOS6.x (atv2 version 5.2) Apple removed the AppleTV.framework and put all those classes into the
  24
+ * AppleTV.app. So we can't use standard obj-c coding here anymore. Instead we need to use the obj-c runtime
  25
+ * functions for subclassing and adding methods to our instances during runtime (hooking).
  26
+ * 
  27
+ * 1. For implementing a method of a base class:
  28
+ *  a) declare it in the form <XBMCAppliance$nameOfMethod> like the others 
  29
+ *  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. 
  30
+ *  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).
  31
+ *  d) in initApplianceRuntimeClasses exchange the base class implementation with ours by calling MSHookMessageEx
  32
+ *  e) if we need to call the base class implementation as well we have to save the original implementation (see initWithApplianceInfo$Orig for reference)
  33
+ *
  34
+ * 2. For implementing a new method which is not part of the base class:
  35
+ *  a) same as 1.a
  36
+ *  b) same as 1.b
  37
+ *  c) same as 1.c
  38
+ *  d) in initApplianceRuntimeClasses add the method to our class via class_addMethod
  39
+ *
  40
+ * 3. Never access any BackRow classes directly - but always get the class via objc_getClass - if the class is used in multiple places 
  41
+ *    save it as static (see BRApplianceCategoryCls)
  42
+ * 
  43
+ * 4. Keep the structure of this file based on the section comments (marked with // SECTIONCOMMENT).
  44
+ * 5. really - obey 4.!
  45
+ *
  46
+ * 6. for adding class members use associated objects - see topShelfControllerKey
  47
+ *
  48
+ * For further reference see https://developer.apple.com/library/mac/#documentation/Cocoa/Reference/ObjCRuntimeRef/Reference/reference.html
  49
+ */
  50
+
  51
+#import <Foundation/Foundation.h>
  52
+#import <UIKit/UIKit.h>
  53
+// objc-runtime.h is missing from iPhoneOS4.2SDK but present in iPhoneSimulator4.2.sdk
  54
+// pull it from runtime system for now
  55
+#import "/usr/include/objc/objc-runtime.h"
  56
+
  57
+#import "XBMCAppliance.h"
  58
+#import "XBMCController.h"
  59
+#include "substrate.h"
  60
+
  61
+// SECTIONCOMMENT
  62
+// classes we need multiple times
  63
+static Class BRApplianceCategoryCls;
  64
+
  65
+// category for ios5.x and higher is just a short text before xbmc auto starts
  66
+#define XBMCAppliance_CAT_5andhigher [BRApplianceCategoryCls categoryWithName:@"XBMC is starting..." identifier:@"xbmc" preferredOrder:0]
  67
+// category for ios4.x is the menu entry
  68
+#define XBMCAppliance_CAT_4 [BRApplianceCategoryCls categoryWithName:@"XBMC" identifier:@"xbmc" preferredOrder:0]
  69
+
  70
+// SECTIONCOMMENT
  71
+// forward declaration all referenced classes
  72
+@class XBMCAppliance;
  73
+@class BRTopShelfView;
  74
+@class XBMCApplianceInfo;
  75
+
  76
+// SECTIONCOMMENT
  77
+// orig method handlers we wanna call in hooked methods
  78
+static id (*XBMCAppliance$initWithApplianceInfo$Orig)(XBMCAppliance*, SEL, id);
  79
+static id (*XBMCAppliance$init$Orig)(XBMCAppliance*, SEL);
  80
+static id (*XBMCAppliance$applianceInfo$Orig)(XBMCAppliance*, SEL);
  81
+
  82
+//--------------------------------------------------------------
  83
+//--------------------------------------------------------------
  84
+// ATVVersionInfo declare to shut up compiler warning
  85
+@interface ATVVersionInfo : NSObject
  86
+{
  87
+}
  88
++ (id)currentOSVersion;
  89
+
  90
+@end
  91
+
  92
+@interface XBMCATV2Detector : NSObject{}
  93
++ (BOOL) hasOldGui;
  94
++ (BOOL) isIos5;
  95
++ (BOOL) needsApplianceInfoHack;
  96
+@end
  97
+
  98
+//--------------------------------------------------------------
  99
+//--------------------------------------------------------------
  100
+// We need a real implementation (not a runtime generated one)
  101
+// for getting our NSBundle instance by calling
  102
+// [[NSBundle bundleForClass:objc_getClass("XBMCATV2Detector")]
  103
+// so we just implement some usefull helpers here
  104
+// and use those
  105
+@implementation XBMCATV2Detector : NSObject{}
  106
++ (BOOL) hasOldGui
  107
+{
  108
+  Class cls = NSClassFromString(@"ATVVersionInfo");  
  109
+  if (cls != nil && [[cls currentOSVersion] rangeOfString:@"4."].location != NSNotFound)
  110
+    return TRUE;
  111
+  if (cls != nil && [[cls currentOSVersion] rangeOfString:@"5.0"].location != NSNotFound)
  112
+    return TRUE;
  113
+  return FALSE;
  114
+}
  115
+
  116
++ (BOOL) isIos5
  117
+{
  118
+  Class cls = NSClassFromString(@"ATVVersionInfo");  
  119
+  if (cls != nil && [[cls currentOSVersion] rangeOfString:@"5."].location != NSNotFound)
  120
+    return TRUE;
  121
+  return FALSE;
  122
+}
  123
+
  124
++ (BOOL) needsApplianceInfoHack
  125
+{
  126
+  // if the runtime base class (BRBaseAppliance) doesn't have the initWithApplianceInfo selector
  127
+  // we need to hack the appliance info in (id) applianceInfo (XBMCAppliance$applianceInfo)
  128
+  if (class_respondsToSelector(objc_getClass("BRBaseAppliance"),@selector(initWithApplianceInfo:)))
  129
+    return FALSE;
  130
+  return TRUE;
  131
+}
  132
+@end
  133
+
  134
+//--------------------------------------------------------------
  135
+//--------------------------------------------------------------
  136
+// XBMCApplication declare to shut up compiler warning of BRApplication
  137
+@interface XBMCApplication : NSObject
  138
+{
  139
+}
  140
+- (void)setFirstResponder:(id)responder;
  141
+@end
  142
+
  143
+//--------------------------------------------------------------
  144
+//--------------------------------------------------------------
  145
+@interface XBMCTopShelfController : NSObject
  146
+{
  147
+}
  148
+- (void) selectCategoryWithIdentifier:(id)identifier;
  149
+- (id) topShelfView;
  150
+// added in 4.1+
  151
+- (void) refresh;
  152
+@end
  153
+
  154
+//--------------------------------------------------------------
  155
+//--------------------------------------------------------------
  156
+@implementation XBMCTopShelfController
  157
+
  158
+- (void) selectCategoryWithIdentifier:(id)identifier 
  159
+{
  160
+}
  161
+
  162
+- (BRTopShelfView *)topShelfView 
  163
+{
  164
+  Class cls = objc_getClass("BRTopShelfView");
  165
+  id topShelf = [[cls alloc] init];
  166
+  
  167
+  // diddle the topshelf logo on old gui
  168
+  if ([XBMCATV2Detector hasOldGui])
  169
+  {
  170
+    Class cls = objc_getClass("BRImage");
  171
+    BRImageControl *imageControl = (BRImageControl *)MSHookIvar<id>(topShelf, "_productImage");// hook the productImage so we can diddle with it
  172
+    BRImage *gpImage = [cls imageWithPath:[[NSBundle bundleForClass:[XBMCATV2Detector class]] pathForResource:@"XBMC" ofType:@"png"]];
  173
+    [imageControl setImage:gpImage];
  174
+  }
  175
+
  176
+  return topShelf;
  177
+}
  178
+
  179
+- (void) refresh
  180
+{
  181
+}
  182
+@end
  183
+
  184
+//--------------------------------------------------------------
  185
+//--------------------------------------------------------------
  186
+// SECTIONCOMMENT
  187
+// since we can't inject ivars we need to use associated objects
  188
+// these are the keys for XBMCAppliance
  189
+//implementation XBMCAppliance
  190
+static char const * const topShelfControllerKey = "topShelfController";
  191
+static char const * const applianceCategoriesKey = "applianceCategories";
  192
+
  193
+static NSString* XBMCApplianceInfo$key(XBMCApplianceInfo* self, SEL _cmd)
  194
+{
  195
+  return [[[NSBundle bundleForClass:objc_getClass("XBMCATV2Detector")] infoDictionary] objectForKey:(NSString*)kCFBundleIdentifierKey];
  196
+}
  197
+
  198
+static NSString* XBMCApplianceInfo$name(XBMCApplianceInfo* self, SEL _cmd)
  199
+{
  200
+  return [[[NSBundle bundleForClass:objc_getClass("XBMCATV2Detector")] infoDictionary] objectForKey:(NSString*)kCFBundleNameKey];
  201
+}
  202
+
  203
+static id XBMCApplianceInfo$localizedStringsFileName(XBMCApplianceInfo* self, SEL _cmd)
  204
+{
  205
+  return @"xbmc";
  206
+}
  207
+
  208
+static void XBMCAppliance$XBMCfixUIDevice(XBMCAppliance* self, SEL _cmd)
  209
+{
  210
+  // iOS 5.x has removed the internal load of UIKit in AppleTV app
  211
+  // and there is an overlap of some UIKit and AppleTV methods.
  212
+  // This voodoo seems to clear up the wonkiness. :)
  213
+  if ([XBMCATV2Detector isIos5])
  214
+ {
  215
+    id cd = nil;
  216
+
  217
+   @try
  218
+   {
  219
+      cd = [UIDevice currentDevice];
  220
+    }
  221
+    
  222
+   @catch (NSException *e)
  223
+   {
  224
+      NSLog(@"exception: %@", e);
  225
+    }
  226
+    
  227
+   @finally
  228
+   {     
  229
+     //NSLog(@"will it work the second try?");
  230
+      cd = [UIDevice currentDevice];
  231
+      NSLog(@"current device fixed: %@", cd);
  232
+    }
  233
+  }
  234
+}
  235
+
  236
+
  237
+static id XBMCAppliance$init(XBMCAppliance* self, SEL _cmd)
  238
+{
  239
+   //NSLog(@"%s", __PRETTY_FUNCTION__);
  240
+  if ([XBMCATV2Detector needsApplianceInfoHack])
  241
+  {
  242
+    NSLog(@"%s for ios 4", __PRETTY_FUNCTION__);
  243
+    if ((self = XBMCAppliance$init$Orig(self, _cmd))!= nil)
  244
+    {
  245
+      id topShelfControl = [[XBMCTopShelfController alloc] init];
  246
+      [self setTopShelfController:topShelfControl];
  247
+      
  248
+      NSArray *catArray = [[NSArray alloc] initWithObjects:XBMCAppliance_CAT_4,nil];
  249
+      [self setApplianceCategories:catArray];
  250
+      return self;
  251
+    }    
  252
+  }
  253
+  else// ios >= 5
  254
+  {
  255
+    NSLog(@"%s for ios 5 and newer", __PRETTY_FUNCTION__);
  256
+    return [self initWithApplianceInfo:nil]; // legacy for ios < 6
  257
+  }
  258
+  return self;
  259
+}
  260
+
  261
+static id XBMCAppliance$identifierForContentAlias(XBMCAppliance* self, SEL _cmd, id contentAlias)
  262
+{
  263
+  return@"xbmc";
  264
+}
  265
+
  266
+static BOOL XBMCAppliance$handleObjectSelection(XBMCAppliance* self, SEL _cmd, id fp8, id fp12)
  267
+{
  268
+  //NSLog(@"%s", __PRETTY_FUNCTION__);
  269
+  return YES;
  270
+}              
  271
+
  272
+static id XBMCAppliance$applianceInfo(XBMCAppliance* self, SEL _cmd)
  273
+{
  274
+  //NSLog(@"%s", __PRETTY_FUNCTION)
  275
+  
  276
+  // load our plist into memory and merge it with
  277
+  // the dict from the baseclass if needed
  278
+  // cause ios seems to fail on that somehow (at least on 4.x)
  279
+  if ([XBMCATV2Detector needsApplianceInfoHack] && self != nil)
  280
+  {
  281
+    id original = XBMCAppliance$applianceInfo$Orig(self, _cmd);
  282
+    id info =  MSHookIvar<id>(original, "_info");// hook the infoDictionary so we can diddle with it
  283
+    
  284
+    NSString *plistPath = [[NSBundle bundleForClass:objc_getClass("XBMCATV2Detector")] pathForResource:@"Info" ofType:@"plist"];
  285
+    NSString *bundlePath = [[NSBundle bundleForClass:objc_getClass("XBMCATV2Detector")] bundlePath];
  286
+    NSMutableDictionary *ourInfoDict = [[NSMutableDictionary alloc] initWithContentsOfFile:plistPath];
  287
+
  288
+    if (ourInfoDict != nil && bundlePath != nil)
  289
+    {
  290
+      // inject this or we won't get shown up properly on ios4
  291
+      [ourInfoDict setObject:bundlePath forKey:@"NSBundleInitialPath"];
  292
+      
  293
+      // add our plist info to the baseclass info and return it
  294
+      [(NSMutableDictionary *)info addEntriesFromDictionary:ourInfoDict];
  295
+      [ourInfoDict release];
  296
+    }
  297
+    return original;
  298
+  }
  299
+  else
  300
+  {
  301
+    Class cls = objc_getClass("XBMCApplianceInfo");
  302
+    return [[[cls alloc] init] autorelease];
  303
+  }
  304
+  return nil;
  305
+}
  306
+
  307
+
  308
+static id XBMCAppliance$topShelfController(XBMCAppliance* self, SEL _cmd) 
  309
+{ 
  310
+  return objc_getAssociatedObject(self, topShelfControllerKey);
  311
+}
  312
+
  313
+
  314
+static void XBMCAppliance$setTopShelfController(XBMCAppliance* self, SEL _cmd, id topShelfControl) 
  315
+{ 
  316
+  objc_setAssociatedObject(self, topShelfControllerKey, topShelfControl, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
  317
+}
  318
+
  319
+static id XBMCAppliance$applianceCategories(XBMCAppliance* self, SEL _cmd) 
  320
+{
  321
+  return objc_getAssociatedObject(self, applianceCategoriesKey);
  322
+}
  323
+
  324
+static void XBMCAppliance$setApplianceCategories(XBMCAppliance* self, SEL _cmd, id applianceCategories)
  325
+{ 
  326
+  objc_setAssociatedObject(self, applianceCategoriesKey, applianceCategories, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
  327
+}
  328
+
  329
+static id XBMCAppliance$initWithApplianceInfo(XBMCAppliance* self, SEL _cmd, id applianceInfo) 
  330
+{ 
  331
+  //NSLog(@"%s", __PRETTY_FUNCTION__);
  332
+  if((self = XBMCAppliance$initWithApplianceInfo$Orig(self, _cmd, applianceInfo)) != nil) 
  333
+  {
  334
+    id topShelfControl = [[XBMCTopShelfController alloc] init];
  335
+    [self setTopShelfController:topShelfControl];
  336
+
  337
+    NSArray *catArray = [[NSArray alloc] initWithObjects:XBMCAppliance_CAT_5andhigher,nil];
  338
+    [self setApplianceCategories:catArray];
  339
+  } 
  340
+  return self;
  341
+}
  342
+
  343
+static id XBMCAppliance$controllerForIdentifier(XBMCAppliance* self, SEL _cmd, id identifier, id args)
  344
+{
  345
+  //NSLog(@"%s", __PRETTY_FUNCTION__);
  346
+  id menuController = nil;
  347
+  Class cls = objc_getClass("BRApplication");
  348
+  if ([identifier isEqualToString:@"xbmc"])
  349
+  {
  350
+    [self XBMCfixUIDevice];
  351
+    menuController = [[objc_getClass("XBMCController") alloc] init];
  352
+    if (menuController == nil)
  353
+      NSLog(@"initialise controller - fail");
  354
+  }
  355
+  XBMCApplication *brapp = (XBMCApplication *)[cls sharedApplication];
  356
+  [brapp setFirstResponder:menuController];
  357
+  return menuController;
  358
+}
  359
+
  360
+// SECTIONCOMMENT
  361
+// c'tor - this sets up our class at runtime by 
  362
+// 1. subclassing from the base classes
  363
+// 2. adding new methods to our class
  364
+// 3. exchanging (hooking) base class methods with ours
  365
+// 4. register the classes to the objc runtime system
  366
+static __attribute__((constructor)) void initApplianceRuntimeClasses()
  367
+{
  368
+  // subclass BRApplianceInfo into XBMCApplianceInfo
  369
+  Class XBMCApplianceInfoCls = objc_allocateClassPair(objc_getClass("BRApplianceInfo"), "XBMCApplianceInfo", 0);
  370
+
  371
+  // and hook up our methods (implementation of the base class methods)
  372
+  // XBMCApplianceInfo::key
  373
+  MSHookMessageEx(XBMCApplianceInfoCls,@selector(key), (IMP)&XBMCApplianceInfo$key, nil);
  374
+  // XBMCApplianceInfo::name
  375
+  MSHookMessageEx(XBMCApplianceInfoCls,@selector(name), (IMP)&XBMCApplianceInfo$name, nil);
  376
+  
  377
+  //not available in ios4.x - so probe or crash&burn
  378
+  if (class_respondsToSelector(objc_getClass("BRApplianceInfo"),@selector(localizedStringsFileName)))
  379
+  {
  380
+    // XBMCApplianceInfo::localizedStringsFileName
  381
+    MSHookMessageEx(XBMCApplianceInfoCls,@selector(localizedStringsFileName), (IMP)&XBMCApplianceInfo$localizedStringsFileName, nil);
  382
+  }
  383
+  else// else we need to add it
  384
+  {
  385
+    class_addMethod(XBMCApplianceInfoCls,@selector(localizedStringsFileName), (IMP)&XBMCApplianceInfo$localizedStringsFileName, "@@:");
  386
+  }
  387
+  // and register the class to the runtime
  388
+  objc_registerClassPair(XBMCApplianceInfoCls);
  389
+
  390
+  // subclass BRBaseAppliance into XBMCAppliance
  391
+  Class XBMCApplianceCls = objc_allocateClassPair(objc_getClass("BRBaseAppliance"), "XBMCAppliance", 0);
  392
+  // add our custom methods which are not part of the baseclass
  393
+  // XBMCAppliance::XBMCfixUIDevice
  394
+  class_addMethod(XBMCApplianceCls,@selector(XBMCfixUIDevice), (IMP)XBMCAppliance$XBMCfixUIDevice, "v@:");
  395
+  class_addMethod(XBMCApplianceCls,@selector(setTopShelfController:), (IMP)&XBMCAppliance$setTopShelfController, "v@:@");
  396
+  class_addMethod(XBMCApplianceCls,@selector(setApplianceCategories:), (IMP)&XBMCAppliance$setApplianceCategories, "v@:@");
  397
+
  398
+  // and hook up our methods (implementation of the base class methods)
  399
+  // XBMCAppliance::init
  400
+  MSHookMessageEx(XBMCApplianceCls,@selector(init), (IMP)&XBMCAppliance$init, (IMP*)&XBMCAppliance$init$Orig);
  401
+  // XBMCAppliance::identifierForContentAlias
  402
+  MSHookMessageEx(XBMCApplianceCls,@selector(identifierForContentAlias:), (IMP)&XBMCAppliance$identifierForContentAlias, nil);
  403
+
  404
+  // not there in ios6 - probing for getting rid of the syslog warning
  405
+  if (class_respondsToSelector(objc_getClass("BRBaseAppliance"),@selector(handleObjectSelection:userInfo:)))
  406
+  {
  407
+    // XBMCAppliance::handleObjectSelection
  408
+    MSHookMessageEx(XBMCApplianceCls,@selector(handleObjectSelection:userInfo:), (IMP)&XBMCAppliance$handleObjectSelection, nil);
  409
+  }
  410
+
  411
+  // XBMCAppliance::applianceInfo
  412
+  MSHookMessageEx(XBMCApplianceCls,@selector(applianceInfo), (IMP)&XBMCAppliance$applianceInfo, (IMP *)&XBMCAppliance$applianceInfo$Orig);
  413
+  // XBMCAppliance::topShelfController
  414
+  MSHookMessageEx(XBMCApplianceCls,@selector(topShelfController), (IMP)&XBMCAppliance$topShelfController, nil);
  415
+  // XBMCAppliance::applianceCategories
  416
+  MSHookMessageEx(XBMCApplianceCls,@selector(applianceCategories), (IMP)&XBMCAppliance$applianceCategories, nil);
  417
+  
  418
+  // not there on ios 4.x - probing ...
  419
+  if (class_respondsToSelector(objc_getClass("BRBaseAppliance"),@selector(initWithApplianceInfo:)))
  420
+  {
  421
+    // XBMCAppliance::initWithApplianceInfo
  422
+    MSHookMessageEx(XBMCApplianceCls,@selector(initWithApplianceInfo:), (IMP)&XBMCAppliance$initWithApplianceInfo, (IMP*)&XBMCAppliance$initWithApplianceInfo$Orig);
  423
+  }
  424
+
  425
+  // XBMCAppliance::controllerForIdentifier
  426
+  MSHookMessageEx(XBMCApplianceCls,@selector(controllerForIdentifier:args:), (IMP)&XBMCAppliance$controllerForIdentifier, nil);
  427
+
  428
+  // and register the class to the runtime
  429
+  objc_registerClassPair(XBMCApplianceCls);
  430
+ 
  431
+  // save this as static for referencing it in the macro at the top of the file
  432
+  BRApplianceCategoryCls = objc_getClass("BRApplianceCategory");
  433
+}
13  xbmc/osx/atv2/XBMCController.h
@@ -58,7 +58,18 @@
58 58
 - (void) stopAnimation;
59 59
 - (bool) changeScreen: (unsigned int)screenIdx withMode:(UIScreenMode *)mode;
60 60
 - (void) activateScreen: (UIScreen *)screen;
61  
-
  61
+- (id) glView;
  62
+- (void) setGlView:(id)view;
  63
+- (BOOL) ATVClientEventFromBREvent:(id)event Repeatable:(bool *)isRepeatable ButtonState:(bool *)isPressed Result:(int *)xbmc_ir_key;
  64
+- (void) setUserEvent:(int) eventId withHoldTime:(unsigned int) holdTime;
  65
+- (void) startKeyPressTimer:(int) keyId;
  66
+- (void) stopKeyPressTimer;
  67
+- (void) setSystemSleepTimeout:(id) timeout;
  68
+- (id) systemSleepTimeout;
  69
+- (void) setKeyTimer:(id) timer;
  70
+- (id) keyTimer;
  71
+- (void) setSystemScreenSaverTimeout:(id) timeout;
  72
+- (id) systemScreenSaverTimeout;
62 73
 
63 74
 @end
64 75
 
1,376  xbmc/osx/atv2/XBMCController.mm
@@ -18,6 +18,36 @@
18 18
  *
19 19
  */
20 20
 
  21
+
  22
+/* HowTo code in this file:
  23
+ * Since AppleTV/iOS6.x (atv2 version 5.2) Apple removed the AppleTV.framework and put all those classes into the
  24
+ * AppleTV.app. So we can't use standard obj-c coding here anymore. Instead we need to use the obj-c runtime
  25
+ * functions for subclassing and adding methods to our instances during runtime (hooking).
  26
+ * 
  27
+ * 1. For implementing a method of a base class:
  28
+ *  a) declare it in the form <XBMCController$nameOfMethod> like the others 
  29
+ *  b) these methods need to be static and have XBMCController* self, SEL _cmd (replace XBMCAppliance with the class the method gets implemented for) as minimum params. 
  30
+ *  c) add the method to the XBMCController.h for getting rid of the compiler warnings of unresponsive selectors (declare the method like done in the baseclass).
  31
+ *  d) in initControllerRuntimeClasses exchange the base class implementation with ours by calling MSHookMessageEx
  32
+ *  e) if we need to call the base class implementation as well we have to save the original implementation (see brEventAction$Orig for reference)
  33
+ *
  34
+ * 2. For implementing a new method which is not part of the base class:
  35
+ *  a) same as 1.a
  36
+ *  b) same as 1.b
  37
+ *  c) same as 1.c
  38
+ *  d) in initControllerRuntimeClasses add the method to our class via class_addMethod
  39
+ *
  40
+ * 3. Never access any BackRow classes directly - but always get the class via objc_getClass - if the class is used in multiple places 
  41
+ *    save it as static (see BRWindowCls)
  42
+ * 
  43
+ * 4. Keep the structure of this file based on the section comments (marked with // SECTIONCOMMENT).
  44
+ * 5. really - obey 4.!
  45
+ *
  46
+ * 6. for adding class members use associated objects - see timerKey
  47
+ *
  48
+ * For further reference see https://developer.apple.com/library/mac/#documentation/Cocoa/Reference/ObjCRuntimeRef/Reference/reference.html
  49
+ */
  50
+
21 51
 //hack around problem with xbmc's typedef int BOOL
22 52
 // and obj-c's typedef unsigned char BOOL
23 53
 #define BOOL XBMC_BOOL 
@@ -31,13 +61,17 @@
31 61
 
32 62
 #import <Foundation/Foundation.h>
33 63
 #import <UIKit/UIKit.h>
34  
-#import <BackRow/BackRow.h>
35 64
 
36 65
 #import "XBMCController.h"
37 66
 #import "XBMCDebugHelpers.h"
38 67
 
  68
+#import "IOSEAGLView.h"
  69
+#import "IOSSCreenManager.h"
  70
+#include "XBMC_keysym.h"
  71
+#include "substrate.h"
  72
+
39 73
 //start repeating after 0.5s
40  
-#define REPEATED_KEYPRESS_DELAY_S     0.5
  74
+#define REPEATED_KEYPRESS_DELAY_S 0.5
41 75
 //pause 0.01s (10ms) between keypresses
42 76
 #define REPEATED_KEYPRESS_PAUSE_S 0.01
43 77
 
@@ -58,7 +92,7 @@
58 92
   ATV_ALUMINIUM_PLAY            = 12,
59 93
   ATV_ALUMINIUM_PLAY_H          = 11,
60 94
 
61  
-  //newly added remote buttons  
  95
+  //newly added remote buttons
62 96
   ATV_BUTTON_PAGEUP             = 13,
63 97
   ATV_BUTTON_PAGEDOWN           = 14,
64 98
   ATV_BUTTON_PAUSE              = 15,
@@ -102,6 +136,7 @@
102 136
   ATV_INVALID_BUTTON
103 137
 } eATVClientEvent;
104 138
 
  139
+
105 140
 typedef enum {
106 141
   // for originator kBREventOriginatorRemote
107 142
   kBREventRemoteActionMenu      = 1,
@@ -157,410 +192,504 @@
157 192
   kBREventRemoteActionHoldDown,
158 193
 } BREventRemoteAction;
159 194
 
  195
+
160 196
 XBMCController *g_xbmcController;
161 197
 
162 198
 //--------------------------------------------------------------
163 199
 // so we don't have to include AppleTV.frameworks/PrivateHeaders/ATVSettingsFacade.h
164  
-@interface ATVSettingsFacade : BRSettingsFacade {}
  200
+@interface XBMCSettingsFacade : NSObject
165 201
 -(int)screenSaverTimeout;
166 202
 -(void)setScreenSaverTimeout:(int) f_timeout;
167 203
 -(void)setSleepTimeout:(int)timeout;
168 204
 -(int)sleepTimeout;
  205
+-(void)flushDiskChanges;
169 206
 @end
170 207
 
171 208
 // notification messages
172 209
 extern NSString* kBRScreenSaverActivated;
173 210
 extern NSString* kBRScreenSaverDismissed;
  211
+
174 212
 //--------------------------------------------------------------
175 213
 //--------------------------------------------------------------
176  
-@interface XBMCController (PrivateMethods)
177  
-- (void) observeDefaultCenterStuff: (NSNotification *) notification;
178  
-- (void) keyPressTimerCallback: (NSTimer*)theTimer;
179  
-- (void) startKeyPressTimer: (int) keyId;
180  
-- (void) stopKeyPressTimer;
181  
-- (void) setUserEvent:(int) id withHoldTime:(unsigned int) holdTime;
182  
-@end
  214
+// SECTIONCOMMENT
  215
+// orig method handlers we wanna call in hooked methods ([super method])
  216
+static BOOL (*XBMCController$brEventAction$Orig)(XBMCController*, SEL, BREvent*);
  217
+static id (*XBMCController$init$Orig)(XBMCController*, SEL);
  218
+static void (*XBMCController$dealloc$Orig)(XBMCController*, SEL);
  219
+static void (*XBMCController$controlWasActivated$Orig)(XBMCController*, SEL);
  220
+static void (*XBMCController$controlWasDeactivated$Orig)(XBMCController*, SEL);
  221
+
  222
+// SECTIONCOMMENT
  223
+// classes we need multiple times
  224
+static Class BRWindowCls;
  225
+
  226
+int padding[16];//obsolete? - was commented with "credit is due here to SapphireCompatibilityClasses!!"
  227
+  
  228
+//--------------------------------------------------------------
  229
+//--------------------------------------------------------------
  230
+// SECTIONCOMMENT
  231
+// since we can't inject ivars we need to use associated objects
  232
+// these are the keys for XBMCController
  233
+static char const * const timerKey = "m_keyTimer";
  234
+static char const * const glviewKey = "m_glView";
  235
+static char const * const screensaverKey = "m_screenSaverTimeout";
  236
+static char const * const systemsleepKey = "m_systemsleepTimeout";
  237
+
183 238
 //
184 239
 //
185  
-@implementation XBMCController
  240
+// SECTIONCOMMENT
  241
+//implementation XBMCController
  242
+ 
  243
+static id XBMCController$keyTimer(XBMCController* self, SEL _cmd) 
  244
+{ 
  245
+  return objc_getAssociatedObject(self, timerKey);
  246
+}
186 247
 
187  
-/*
188  
-+ (XBMCController*) sharedInstance
189  
-{
190  
-  // the instance of this class is stored here
191  
-  static XBMCController *myInstance = nil;
  248
+static void XBMCController$setKeyTimer(XBMCController* self, SEL _cmd, id timer) 
  249
+{ 
  250
+  objc_setAssociatedObject(self, timerKey, timer, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
  251
+}
192 252
 
193  
-  // check to see if an instance already exists
194  
-  if (nil == myInstance)
195  
-    myInstance  = [[[[self class] alloc] init] autorelease];
  253
+static id XBMCController$glView(XBMCController* self, SEL _cmd) 
  254
+{ 
  255
+  return objc_getAssociatedObject(self, glviewKey);
  256
+}
  257
+
  258
+static void XBMCController$setGlView(XBMCController* self, SEL _cmd, id view) 
  259
+{ 
  260
+  objc_setAssociatedObject(self, glviewKey, view, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
  261
+}
196 262
 
197  
-  // return the instance of this class
198  
-  return myInstance;
  263
+static id XBMCController$systemScreenSaverTimeout(XBMCController* self, SEL _cmd) 
  264
+{ 
  265
+  return objc_getAssociatedObject(self, screensaverKey);
199 266
 }
200  
-*/
201 267
 
202  
-- (void) applicationDidExit
  268
+static void XBMCController$setSystemScreenSaverTimeout(XBMCController* self, SEL _cmd, id timeout) 
  269
+{ 
  270
+  objc_setAssociatedObject(self, screensaverKey, timeout, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
  271
+}
  272
+
  273
+static id XBMCController$systemSleepTimeout(XBMCController* self, SEL _cmd) 
  274
+{ 
  275
+  return objc_getAssociatedObject(self, systemsleepKey);
  276
+}
  277
+
  278
+static void XBMCController$setSystemSleepTimeout(XBMCController* self, SEL _cmd, id timeout) 
  279
+{ 
  280
+  objc_setAssociatedObject(self, systemsleepKey, timeout, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
  281
+}
  282
+
  283
+static void XBMCController$applicationDidExit(XBMCController* self, SEL _cmd) 
203 284
 {
204  
-  [m_glView stopAnimation];
  285
+  //NSLog(@"%s", __PRETTY_FUNCTION__);
205 286
 
  287
+  [[self glView] stopAnimation];
206 288
   [self enableScreenSaver];
207 289
   [self enableSystemSleep];
208  
-
209 290
   [[self stack] popController];
210 291
 }
211  
-- (void) initDisplayLink
  292
+
  293
+static void XBMCController$initDisplayLink(XBMCController* self, SEL _cmd) 
212 294
 {
213  
-  [m_glView initDisplayLink];
  295
+  //NSLog(@"%s", __PRETTY_FUNCTION__);
  296
+
  297
+  [[self glView] initDisplayLink];
214 298
 }
215  
-- (void) deinitDisplayLink
  299
+
  300
+static void XBMCController$deinitDisplayLink(XBMCController* self, SEL _cmd) 
216 301
 {
217  
-  [m_glView deinitDisplayLink];
  302
+  //NSLog(@"%s", __PRETTY_FUNCTION__);
  303
+
  304
+  [[self glView] deinitDisplayLink];
218 305
 }
219  
-- (double) getDisplayLinkFPS
  306
+
  307
+static double XBMCController$getDisplayLinkFPS(XBMCController* self, SEL _cmd) 
220 308
 {
221  
-  return [m_glView getDisplayLinkFPS];
  309
+  //NSLog(@"%s", __PRETTY_FUNCTION__);
  310
+
  311
+  return [[self glView] getDisplayLinkFPS];
222 312
 }
223  
-- (void) setFramebuffer
224  
-{
225  
-  [m_glView setFramebuffer];
  313
+
  314
+static void XBMCController$setFramebuffer(XBMCController* self, SEL _cmd) 
  315
+{   
  316
+  [[self glView] setFramebuffer];
226 317
 }
227  
-- (bool) presentFramebuffer
228  
-{
229  
-  return [m_glView presentFramebuffer];
  318
+
  319
+static bool XBMCController$presentFramebuffer(XBMCController* self, SEL _cmd) 
  320
+{    
  321
+  return [[self glView] presentFramebuffer];
230 322
 }
231  
-- (CGSize) getScreenSize
  323
+
  324
+static CGSize XBMCController$getScreenSize(XBMCController* self, SEL _cmd) 
232 325
 {
233 326
   CGSize screensize;
234  
-
235  
-  screensize.width  = [BRWindow interfaceFrame].size.width;
236  
-  screensize.height = [BRWindow interfaceFrame].size.height;
237  
-
  327
+  screensize.width  = [BRWindowCls interfaceFrame].size.width;
  328
+  screensize.height = [BRWindowCls interfaceFrame].size.height;
238 329
   //NSLog(@"%s UpdateResolutions width=%f, height=%f", 
239  
-	//	__PRETTY_FUNCTION__, screensize.width, screensize.height);
240  
-
  330
+  //__PRETTY_FUNCTION__, screensize.width, screensize.height);
241 331
   return screensize;
242 332
 }
243  
-- (void) sendKey: (XBMCKey) key
  333
+
  334
+static void XBMCController$sendKey(XBMCController* self, SEL _cmd, XBMCKey key) 
244 335
 {
245 336
   //empty because its not used here. Only implemented for getting rid
246 337
   //of "may not respond to selector" compile warnings in IOSExternalTouchController
247 338
 }
248 339
 
249  
-
250  
-- (id) init
251  
-{  
252  
-  //NSLog(@"%s", __PRETTY_FUNCTION__);
253  
-
254  
-  self = [super init];
255  
-  if ( !self )
256  
-    return ( nil );
257  
-
258  
-  NSNotificationCenter *center;
259  
-  // first the default notification center, which is all
260  
-  // notifications that only happen inside of our program
261  
-  center = [NSNotificationCenter defaultCenter];
262  
-  [center addObserver: self
263  
-    selector: @selector(observeDefaultCenterStuff:)
264  
-    name: nil
265  
-    object: nil];
266  
-
267  
-  m_glView = [[IOSEAGLView alloc] initWithFrame:[BRWindow interfaceFrame] withScreen:[UIScreen mainScreen]];
268  
-  [[IOSScreenManager sharedInstance] setView:m_glView];
269  
-
270  
-  g_xbmcController = self;
271  
-
  340
+static id XBMCController$init(XBMCController* self, SEL _cmd) 
  341
+{
  342
+  if((self = XBMCController$init$Orig(self, _cmd)) != nil)  
  343
+  {
  344
+    //NSLog(@"%s", __PRETTY_FUNCTION__);
  345
+
  346
+    NSNotificationCenter *center;
  347
+    // first the default notification center, which is all
  348
+    // notifications that only happen inside of our program
  349
+    center = [NSNotificationCenter defaultCenter];
  350
+    [center addObserver: self
  351
+      selector: @selector(observeDefaultCenterStuff:)
  352
+      name: nil
  353
+      object: nil];
  354
+
  355
+    IOSEAGLView *view = [[IOSEAGLView alloc] initWithFrame:[BRWindowCls interfaceFrame] withScreen:[UIScreen mainScreen]];
  356
+    [self setGlView:view];
  357
+ 
  358
+    [[IOSScreenManager sharedInstance] setView:[self glView]];
  359
+
  360
+    g_xbmcController = self;
  361
+  }
272 362
   return self;
273 363
 }
274 364
 
275  
-- (void)dealloc
  365
+static void XBMCController$dealloc(XBMCController* self, SEL _cmd) 
276 366
 {
277 367
   //NSLog(@"%s", __PRETTY_FUNCTION__);
278  
-  [m_glView stopAnimation];
279  
-  [m_glView release];
280  
-
  368
+  [[self glView] stopAnimation];
  369
+  [[self glView] release];
281 370
 
282 371
   NSNotificationCenter *center;
283 372
   // take us off the default center for our app
284 373
   center = [NSNotificationCenter defaultCenter];
285 374
   [center removeObserver: self];
286 375
 
287  
-  [super dealloc];
  376
+  XBMCController$dealloc$Orig(self, _cmd);
288 377
 }
289 378
 
290  
-- (void)controlWasActivated
  379
+static void XBMCController$controlWasActivated(XBMCController* self, SEL _cmd) 
291 380
 {
292 381
   //NSLog(@"%s", __PRETTY_FUNCTION__);
293  
-  
294  
-  [super controlWasActivated];
  382
+
  383
+  XBMCController$controlWasActivated$Orig(self, _cmd);
295 384
 
296 385
   [self disableSystemSleep];
297 386
   [self disableScreenSaver];
298  
-
  387
+  
  388
+  IOSEAGLView *view = [self glView];
299 389
   //inject our gles layer into the backrow root layer
300  
-  [[BRWindow rootLayer] addSublayer:m_glView.layer];
  390
+  [[BRWindowCls rootLayer] addSublayer:view.layer];
301 391
 
302  
-  [m_glView startAnimation];
  392
+  [[self glView] startAnimation];
303 393
 }
304 394
 
305  
-- (void)controlWasDeactivated
  395
+static void XBMCController$controlWasDeactivated(XBMCController* self, SEL _cmd) 
306 396
 {
307 397
   NSLog(@"XBMC was forced by FrontRow to exit via controlWasDeactivated");
308 398
 
309  
-  [m_glView stopAnimation];
310  
-  [m_glView.layer removeFromSuperlayer];
  399
+  [[self glView] stopAnimation];
  400
+  [[[self glView] layer] removeFromSuperlayer];
311 401
 
312 402
   [self enableScreenSaver];
313 403
   [self enableSystemSleep];
314 404
 
315  
-  [super controlWasDeactivated];
  405
+  XBMCController$controlWasDeactivated$Orig(self, _cmd);
316 406
 }
317 407
 
318  
-- (BOOL) recreateOnReselect
319  
-{ 
  408
+static BOOL XBMCController$recreateOnReselect(XBMCController* self, SEL _cmd) 
  409
+{
320 410
   //NSLog(@"%s", __PRETTY_FUNCTION__);
321 411
   return YES;
322 412
 }
323 413
 
324  
-- (eATVClientEvent) ATVClientEventFromBREvent:(BREvent*) f_event 
325  
-                    Repeatable:(bool &) isRepeatable
326  
-                    ButtonState:(bool &) isPressed
  414
+static void XBMCController$ATVClientEventFromBREvent(XBMCController* self, SEL _cmd, BREvent* f_event, bool * isRepeatable, bool * isPressed, int * result) 
327 415
 {
  416
+  if(f_event == nil)// paranoia
  417
+    return;
  418
+
328 419
   int remoteAction = [f_event remoteAction];
329 420
   CLog::Log(LOGDEBUG,"XBMCPureController: Button press remoteAction = %i", remoteAction);
330  
-  isRepeatable = false;
331  
-  isPressed = false;
  421
+  *isRepeatable = false;
  422
+  *isPressed = false;
332 423
 
333 424
   switch (remoteAction)
334 425
   {
335 426
     // tap up
336 427
     case kBREventRemoteActionUp:
337 428
     case 65676:
338  
-      isRepeatable = true;
  429
+      *isRepeatable = true;
339 430
       if([f_event value] == 1)
340  
-        isPressed = true;
341  
-      return ATV_BUTTON_UP;
  431
+        *isPressed = true;
  432
+      *result = ATV_BUTTON_UP;
  433
+      return;
342 434
 
343 435
     // tap down
344 436
     case kBREventRemoteActionDown:
345 437
     case 65677:
346  
-      isRepeatable = true;
  438
+      *isRepeatable = true;
347 439
       if([f_event value] == 1)
348  
-        isPressed = true;
349  
-      return ATV_BUTTON_DOWN;
350  
-
  440
+        *isPressed = true;
  441
+      *result = ATV_BUTTON_DOWN;
  442
+      return;
  443