X-Git-Url: https://git.saurik.com/cydia.git/blobdiff_plain/2634b249a36b79a5c11dcdda3edc7161e9f92c2b..ed637e66d7f4af4b8f81fc897f89a0775cb957f6:/UICaboodle/BrowserView.mm diff --git a/UICaboodle/BrowserView.mm b/UICaboodle/BrowserView.mm index 8b361f5e..43f2905a 100644 --- a/UICaboodle/BrowserView.mm +++ b/UICaboodle/BrowserView.mm @@ -27,6 +27,25 @@ extern NSString * const kCAFilterNearest; #include "substrate.h" #define ForSaurik 0 +#define DefaultTimeout_ 120.0 + +#define ShowInternals 0 +#define LogBrowser 0 +#define LogMessages 0 + +#define lprintf(args...) fprintf(stderr, args) + +// WebThreadLocked {{{ +struct WebThreadLocked { + _finline WebThreadLocked() { + WebThreadLock(); + } + + _finline ~WebThreadLocked() { + WebThreadUnlock(); + } +}; +// }}} template static inline void CYRelease(Type_ &value) { @@ -36,8 +55,11 @@ static inline void CYRelease(Type_ &value) { } } +float CYScrollViewDecelerationRateNormal; + @interface WebView (Apple) - (void) _setLayoutInterval:(float)interval; +- (void) _setAllowsMessaging:(BOOL)allows; @end @interface WebPreferences (Apple) @@ -83,18 +105,28 @@ static inline void CYRelease(Type_ &value) { - (BOOL) respondsToSelector:(SEL)sel { if ([super respondsToSelector:sel]) return YES; + // XXX: WebThreadCreateNSInvocation returns nil - //fprintf(stderr, "[%s]R?%s\n", class_getName(self->isa), sel_getName(sel)); + +#if ShowInternals + fprintf(stderr, "[%s]R?%s\n", class_getName(self->isa), sel_getName(sel)); +#endif + return delegate_ == nil ? NO : [delegate_ respondsToSelector:sel]; } - (NSMethodSignature *) methodSignatureForSelector:(SEL)sel { if (NSMethodSignature *method = [super methodSignatureForSelector:sel]) return method; - //fprintf(stderr, "[%s]S?%s\n", class_getName(self->isa), sel_getName(sel)); + +#if ShowInternals + fprintf(stderr, "[%s]S?%s\n", class_getName(self->isa), sel_getName(sel)); +#endif + if (delegate_ != nil) if (NSMethodSignature *sig = [delegate_ methodSignatureForSelector:sel]) return sig; + // XXX: I fucking hate Apple so very very bad return [NSMethodSignature signatureWithObjCTypes:"v@:"]; } @@ -167,6 +199,7 @@ enum CYWebPolicyDecision { switch (decision_) { case CYWebPolicyDecisionUnknown: default: + NSLog(@"CYWebPolicyDecisionUnknown"); return false; case CYWebPolicyDecisionDownload: [listener_ download]; break; @@ -194,6 +227,10 @@ enum CYWebPolicyDecision { @implementation CYWebView : UIWebView +#if ShowInternals +#include "UICaboodle/UCInternal.h" +#endif + - (id) initWithFrame:(CGRect)frame { if ((self = [super initWithFrame:frame]) != nil) { } return self; @@ -208,104 +245,212 @@ enum CYWebPolicyDecision { } /*- (WebView *) webView:(WebView *)view createWebViewWithRequest:(NSURLRequest *)request { - NSLog(@"createWebViewWithRequest:%@", request); - WebView *created(nil); // XXX - if (created == nil && [super respondsToSelector:@selector(webView:createWebViewWithRequest:)]) - return [super webView:view createWebViewWithRequest:request]; - else - return created; + id delegate([self delegate]); + WebView *created(nil); + if (created == nil && [delegate respondsToSelector:@selector(webView:createWebViewWithRequest:)]) + created = [delegate webView:view createWebViewWithRequest:request]; + if (created == nil && [UIWebView instancesRespondToSelector:@selector(webView:createWebViewWithRequest:)]) + created = [super webView:view createWebViewWithRequest:request]; + return created; }*/ +// webView:addMessageToConsole: (X.Xx) {{{ +static void $UIWebViewWebViewDelegate$webView$addMessageToConsole$(UIWebViewWebViewDelegate *self, SEL sel, WebView *view, NSDictionary *message) { + UIWebView *uiWebView(MSHookIvar(self, "uiWebView")); + if ([uiWebView respondsToSelector:@selector(webView:addMessageToConsole:)]) + [uiWebView webView:view addMessageToConsole:message]; +} + +- (void) webView:(WebView *)view addMessageToConsole:(NSDictionary *)message { + id delegate([self delegate]); + if ([delegate respondsToSelector:@selector(webView:addMessageToConsole:)]) + [delegate webView:view addMessageToConsole:message]; + if ([UIWebView instancesRespondToSelector:@selector(webView:addMessageToConsole:)]) + [super webView:view addMessageToConsole:message]; +} +// }}} +// webView:decidePolicyForNavigationAction:request:frame:decisionListener: (2.0+) {{{ - (void) webView:(WebView *)view decidePolicyForNavigationAction:(NSDictionary *)action request:(NSURLRequest *)request frame:(WebFrame *)frame decisionListener:(id)listener { + id delegate([self delegate]); CYWebPolicyDecisionMediator *mediator([[[CYWebPolicyDecisionMediator alloc] initWithListener:listener] autorelease]); - [[self delegate] webView:view decidePolicyForNavigationAction:action request:request frame:frame decisionListener:mediator]; - if (![mediator decided] && [super respondsToSelector:@selector(webView:decidePolicyForNavigationAction:request:frame:decisionListener:)]) + if (![mediator decided] && [delegate respondsToSelector:@selector(webView:decidePolicyForNavigationAction:request:frame:decisionListener:)]) + [delegate webView:view decidePolicyForNavigationAction:action request:request frame:frame decisionListener:mediator]; + if (![mediator decided] && [UIWebView instancesRespondToSelector:@selector(webView:decidePolicyForNavigationAction:request:frame:decisionListener:)]) [super webView:view decidePolicyForNavigationAction:action request:request frame:frame decisionListener:mediator]; [mediator decide]; } +// }}} +// webView:decidePolicyForNewWindowAction:request:newFrameName:decisionListener: (3.0+) {{{ +static void $UIWebViewWebViewDelegate$webView$decidePolicyForNewWindowAction$request$newFrameName$decisionListener$(UIWebViewWebViewDelegate *self, SEL sel, WebView *view, NSDictionary *action, NSURLRequest *request, NSString *frame, id listener) { + UIWebView *uiWebView(MSHookIvar(self, "uiWebView")); + if ([uiWebView respondsToSelector:@selector(webView:decidePolicyForNewWindowAction:request:newFrameName:decisionListener:)]) + [uiWebView webView:view decidePolicyForNewWindowAction:action request:request newFrameName:frame decisionListener:listener]; +} - (void) webView:(WebView *)view decidePolicyForNewWindowAction:(NSDictionary *)action request:(NSURLRequest *)request newFrameName:(NSString *)frame decisionListener:(id)listener { + id delegate([self delegate]); CYWebPolicyDecisionMediator *mediator([[[CYWebPolicyDecisionMediator alloc] initWithListener:listener] autorelease]); - [[self delegate] webView:view decidePolicyForNewWindowAction:action request:request newFrameName:frame decisionListener:mediator]; - if (![mediator decided] && [super respondsToSelector:@selector(webView:decidePolicyForNewWindowAction:request:newFrameName:decisionListener:)]) + if (![mediator decided] && [delegate respondsToSelector:@selector(webView:decidePolicyForNewWindowAction:request:newFrameName:decisionListener:)]) + [delegate webView:view decidePolicyForNewWindowAction:action request:request newFrameName:frame decisionListener:mediator]; + if (![mediator decided] && [UIWebView instancesRespondToSelector:@selector(webView:decidePolicyForNewWindowAction:request:newFrameName:decisionListener:)]) [super webView:view decidePolicyForNewWindowAction:action request:request newFrameName:frame decisionListener:mediator]; [mediator decide]; } +// }}} +// webView:didClearWindowObject:forFrame: (3.2+) {{{ +static void $UIWebViewWebViewDelegate$webView$didClearWindowObject$forFrame$(UIWebViewWebViewDelegate *self, SEL sel, WebView *view, WebScriptObject *window, WebFrame *frame) { + UIWebView *uiWebView(MSHookIvar(self, "uiWebView")); + if ([uiWebView respondsToSelector:@selector(webView:didClearWindowObject:forFrame:)]) + [uiWebView webView:view didClearWindowObject:window forFrame:frame]; +} - (void) webView:(WebView *)view didClearWindowObject:(WebScriptObject *)window forFrame:(WebFrame *)frame { - [[self delegate] webView:view didClearWindowObject:window forFrame:frame]; - if ([super respondsToSelector:@selector(webView:didClearWindowObject:forFrame:)]) + id delegate([self delegate]); + if ([delegate respondsToSelector:@selector(webView:didClearWindowObject:forFrame:)]) + [delegate webView:view didClearWindowObject:window forFrame:frame]; + if ([UIWebView instancesRespondToSelector:@selector(webView:didClearWindowObject:forFrame:)]) [super webView:view didClearWindowObject:window forFrame:frame]; } - +// }}} +// webView:didFailLoadWithError:forFrame: (2.0+) {{{ - (void) webView:(WebView *)view didFailLoadWithError:(NSError *)error forFrame:(WebFrame *)frame { - [[self delegate] webView:view didFailLoadWithError:error forFrame:frame]; - if ([super respondsToSelector:@selector(webView:didFailLoadWithError:forFrame:)]) + id delegate([self delegate]); + if ([delegate respondsToSelector:@selector(webView:didFailLoadWithError:forFrame:)]) + [delegate webView:view didFailLoadWithError:error forFrame:frame]; + if ([UIWebView instancesRespondToSelector:@selector(webView:didFailLoadWithError:forFrame:)]) [super webView:view didFailLoadWithError:error forFrame:frame]; } - +// }}} +// webView:didFailProvisionalLoadWithError:forFrame: (2.0+) {{{ - (void) webView:(WebView *)view didFailProvisionalLoadWithError:(NSError *)error forFrame:(WebFrame *)frame { - [[self delegate] webView:view didFailProvisionalLoadWithError:error forFrame:frame]; - if ([super respondsToSelector:@selector(webView:didFailProvisionalLoadWithError:forFrame:)]) + id delegate([self delegate]); + if ([delegate respondsToSelector:@selector(webView:didFailProvisionalLoadWithError:forFrame:)]) + [delegate webView:view didFailProvisionalLoadWithError:error forFrame:frame]; + if ([UIWebView instancesRespondToSelector:@selector(webView:didFailProvisionalLoadWithError:forFrame:)]) [super webView:view didFailProvisionalLoadWithError:error forFrame:frame]; } - +// }}} +// webView:didFinishLoadForFrame: (2.0+) {{{ - (void) webView:(WebView *)view didFinishLoadForFrame:(WebFrame *)frame { - [[self delegate] webView:view didFinishLoadForFrame:frame]; - if ([super respondsToSelector:@selector(webView:didFinishLoadForFrame:)]) + id delegate([self delegate]); + if ([delegate respondsToSelector:@selector(webView:didFinishLoadForFrame:)]) + [delegate webView:view didFinishLoadForFrame:frame]; + if ([UIWebView instancesRespondToSelector:@selector(webView:didFinishLoadForFrame:)]) [super webView:view didFinishLoadForFrame:frame]; } +// }}} +// webView:didReceiveTitle:forFrame: (3.2+) {{{ +static void $UIWebViewWebViewDelegate$webView$didReceiveTitle$forFrame$(UIWebViewWebViewDelegate *self, SEL sel, WebView *view, NSString *title, WebFrame *frame) { + UIWebView *uiWebView(MSHookIvar(self, "uiWebView")); + if ([uiWebView respondsToSelector:@selector(webView:didReceiveTitle:forFrame:)]) + [uiWebView webView:view didReceiveTitle:title forFrame:frame]; +} - (void) webView:(WebView *)view didReceiveTitle:(NSString *)title forFrame:(WebFrame *)frame { - [[self delegate] webView:view didReceiveTitle:title forFrame:frame]; - if ([super respondsToSelector:@selector(webView:didReceiveTitle:forFrame:)]) + id delegate([self delegate]); + if ([delegate respondsToSelector:@selector(webView:didReceiveTitle:forFrame:)]) + [delegate webView:view didReceiveTitle:title forFrame:frame]; + if ([UIWebView instancesRespondToSelector:@selector(webView:didReceiveTitle:forFrame:)]) [super webView:view didReceiveTitle:title forFrame:frame]; } - +// }}} +// webView:didStartProvisionalLoadForFrame: (2.0+) {{{ - (void) webView:(WebView *)view didStartProvisionalLoadForFrame:(WebFrame *)frame { - [[self delegate] webView:view didStartProvisionalLoadForFrame:frame]; - if ([super respondsToSelector:@selector(webView:didStartProvisionalLoadForFrame:)]) + id delegate([self delegate]); + if ([delegate respondsToSelector:@selector(webView:didStartProvisionalLoadForFrame:)]) + [delegate webView:view didStartProvisionalLoadForFrame:frame]; + if ([UIWebView instancesRespondToSelector:@selector(webView:didStartProvisionalLoadForFrame:)]) [super webView:view didStartProvisionalLoadForFrame:frame]; } +// }}} +// webView:resource:willSendRequest:redirectResponse:fromDataSource: (3.2+) {{{ +static NSURLRequest *$UIWebViewWebViewDelegate$webView$resource$willSendRequest$redirectResponse$fromDataSource$(UIWebViewWebViewDelegate *self, SEL sel, WebView *view, id identifier, NSURLRequest *request, NSURLResponse *response, WebDataSource *source) { + UIWebView *uiWebView(MSHookIvar(self, "uiWebView")); + if ([uiWebView respondsToSelector:@selector(webView:resource:willSendRequest:redirectResponse:fromDataSource:)]) + request = [uiWebView webView:view resource:identifier willSendRequest:request redirectResponse:response fromDataSource:source]; + return request; +} - (NSURLRequest *) webView:(WebView *)view resource:(id)identifier willSendRequest:(NSURLRequest *)request redirectResponse:(NSURLResponse *)response fromDataSource:(WebDataSource *)source { - if ([super respondsToSelector:@selector(webView:resource:willSendRequest:redirectResponse:)]) + id delegate([self delegate]); + if ([UIWebView instancesRespondToSelector:@selector(webView:resource:willSendRequest:redirectResponse:fromDataSource:)]) request = [super webView:view resource:identifier willSendRequest:request redirectResponse:response fromDataSource:source]; - return [[self delegate] webView:view resource:identifier willSendRequest:request redirectResponse:response fromDataSource:source]; + if ([delegate respondsToSelector:@selector(webView:resource:willSendRequest:redirectResponse:fromDataSource:)]) + request = [delegate webView:view resource:identifier willSendRequest:request redirectResponse:response fromDataSource:source]; + return request; } - +// }}} +// webView:runJavaScriptAlertPanelWithMessage:initiatedByFrame: (2.1+) {{{ - (void) webView:(WebView *)view runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WebFrame *)frame { - if ([super respondsToSelector:@selector(webView:runJavaScriptAlertPanelWithMessage:initiatedByFrame:)]) - if ([[self delegate] webView:view shouldRunJavaScriptAlertPanelWithMessage:message initiatedByFrame:frame]) + id delegate([self delegate]); + if ([UIWebView instancesRespondToSelector:@selector(webView:runJavaScriptAlertPanelWithMessage:initiatedByFrame:)]) + if ( + ![delegate respondsToSelector:@selector(webView:shouldRunJavaScriptAlertPanelWithMessage:initiatedByFrame:)] || + [delegate webView:view shouldRunJavaScriptAlertPanelWithMessage:message initiatedByFrame:frame] + ) [super webView:view runJavaScriptAlertPanelWithMessage:message initiatedByFrame:frame]; } - +// }}} +// webView:runJavaScriptConfirmPanelWithMessage:initiatedByFrame: (2.1+) {{{ - (BOOL) webView:(WebView *)view runJavaScriptConfirmPanelWithMessage:(NSString *)message initiatedByFrame:(WebFrame *)frame { - if ([super respondsToSelector:@selector(webView:runJavaScriptConfirmPanelWithMessage:initiatedByFrame:)]) - if ([[self delegate] webView:view shouldRunJavaScriptConfirmPanelWithMessage:message initiatedByFrame:frame]) + id delegate([self delegate]); + if ([UIWebView instancesRespondToSelector:@selector(webView:runJavaScriptConfirmPanelWithMessage:initiatedByFrame:)]) + if ( + ![delegate respondsToSelector:@selector(webView:shouldRunJavaScriptConfirmPanelWithMessage:initiatedByFrame:)] || + [delegate webView:view shouldRunJavaScriptConfirmPanelWithMessage:message initiatedByFrame:frame] + ) return [super webView:view runJavaScriptConfirmPanelWithMessage:message initiatedByFrame:frame]; return NO; } - +// }}} +// webView:runJavaScriptTextInputPanelWithPrompt:defaultText:initiatedByFrame: (2.1+) {{{ - (NSString *) webView:(WebView *)view runJavaScriptTextInputPanelWithPrompt:(NSString *)prompt defaultText:(NSString *)text initiatedByFrame:(WebFrame *)frame { - if ([super respondsToSelector:@selector(webView:runJavaScriptTextInputPanelWithPrompt:defaultText:initiatedByFrame:)]) - if ([[self delegate] webView:view shouldRunJavaScriptTextInputPanelWithPrompt:prompt defaultText:text initiatedByFrame:frame]) + id delegate([self delegate]); + if ([UIWebView instancesRespondToSelector:@selector(webView:runJavaScriptTextInputPanelWithPrompt:defaultText:initiatedByFrame:)]) + if ( + ![delegate respondsToSelector:@selector(webView:shouldRunJavaScriptTextInputPanelWithPrompt:defaultText:initiatedByFrame:)] || + [delegate webView:view shouldRunJavaScriptTextInputPanelWithPrompt:prompt defaultText:text initiatedByFrame:frame] + ) return [super webView:view runJavaScriptTextInputPanelWithPrompt:prompt defaultText:text initiatedByFrame:frame]; return nil; } +// }}} +// webViewClose: (3.2+) {{{ +static void $UIWebViewWebViewDelegate$webViewClose$(UIWebViewWebViewDelegate *self, SEL sel, WebView *view) { + UIWebView *uiWebView(MSHookIvar(self, "uiWebView")); + if ([uiWebView respondsToSelector:@selector(webViewClose:)]) + [uiWebView webViewClose:view]; +} - (void) webViewClose:(WebView *)view { - [[self delegate] webViewClose:view]; - if ([super respondsToSelector:@selector(webViewClose:)]) + id delegate([self delegate]); + if ([delegate respondsToSelector:@selector(webViewClose:)]) + [delegate webViewClose:view]; + if ([UIWebView instancesRespondToSelector:@selector(webViewClose:)]) [super webViewClose:view]; } +// }}} -@end +- (void) _updateViewSettings { + [super _updateViewSettings]; -#define ShowInternals 0 -#define LogBrowser 1 + id delegate([self delegate]); + if ([delegate respondsToSelector:@selector(webViewUpdateViewSettings:)]) + [delegate webViewUpdateViewSettings:self]; +} -#define lprintf(args...) fprintf(stderr, args) ++ (void) initialize { + if (Class $UIWebViewWebViewDelegate = objc_getClass("UIWebViewWebViewDelegate")) { + class_addMethod($UIWebViewWebViewDelegate, @selector(webView:addMessageToConsole:), (IMP) &$UIWebViewWebViewDelegate$webView$addMessageToConsole$, "v16@0:4@8@12"); + class_addMethod($UIWebViewWebViewDelegate, @selector(webView:decidePolicyForNewWindowAction:request:newFrameName:decisionListener:), (IMP) &$UIWebViewWebViewDelegate$webView$decidePolicyForNewWindowAction$request$newFrameName$decisionListener$, "v28@0:4@8@12@16@20@24"); + class_addMethod($UIWebViewWebViewDelegate, @selector(webView:didClearWindowObject:forFrame:), (IMP) &$UIWebViewWebViewDelegate$webView$didClearWindowObject$forFrame$, "v20@0:4@8@12@16"); + class_addMethod($UIWebViewWebViewDelegate, @selector(webView:didReceiveTitle:forFrame:), (IMP) &$UIWebViewWebViewDelegate$webView$didReceiveTitle$forFrame$, "v20@0:4@8@12@16"); + class_addMethod($UIWebViewWebViewDelegate, @selector(webView:resource:willSendRequest:redirectResponse:fromDataSource:), (IMP) &$UIWebViewWebViewDelegate$webView$resource$willSendRequest$redirectResponse$fromDataSource$, "@28@0:4@8@12@16@20@24"); + class_addMethod($UIWebViewWebViewDelegate, @selector(webViewClose:), (IMP) &$UIWebViewWebViewDelegate$webViewClose$, "v12@0:4@8"); + } +} + +@end @implementation BrowserController @@ -315,6 +460,11 @@ enum CYWebPolicyDecision { + (void) _initialize { [WebPreferences _setInitialDefaultTextEncodingToSystemEncoding]; + + if (float *_UIScrollViewDecelerationRateNormal = reinterpret_cast(dlsym(RTLD_DEFAULT, "UIScrollViewDecelerationRateNormal"))) + CYScrollViewDecelerationRateNormal = *_UIScrollViewDecelerationRateNormal; + else // XXX: this actually might be fast on some older systems: we should look into this + CYScrollViewDecelerationRateNormal = 0.998; } - (void) dealloc { @@ -330,7 +480,8 @@ enum CYWebPolicyDecision { if (challenge_ != nil) [challenge_ release]; - //NSNotificationCenter *center = [NSNotificationCenter defaultCenter]; + if (request_ != nil) + [request_ release]; if (custom_ != nil) [custom_ release]; @@ -342,11 +493,13 @@ enum CYWebPolicyDecision { if (closer_ != nil) [closer_ release]; - if (sensitive_ != nil) - [sensitive_ release]; if (title_ != nil) [title_ release]; + if ([loading_ count] != 0) + [delegate_ releaseNetworkActivityIndicator]; + [loading_ release]; + [reloaditem_ release]; [loadingitem_ release]; @@ -355,11 +508,21 @@ enum CYWebPolicyDecision { [super dealloc]; } +- (void) setURL:(NSURL *)url { + _assert(request_ == nil); + + request_ = [[NSURLRequest + requestWithURL:url + cachePolicy:NSURLRequestUseProtocolCachePolicy + timeoutInterval:DefaultTimeout_ + ] retain]; +} + - (void) loadURL:(NSURL *)url cachePolicy:(NSURLRequestCachePolicy)policy { [self loadRequest:[NSURLRequest requestWithURL:url cachePolicy:policy - timeoutInterval:120.0 + timeoutInterval:DefaultTimeout_ ]]; } @@ -368,17 +531,26 @@ enum CYWebPolicyDecision { } - (void) loadRequest:(NSURLRequest *)request { +#if LogBrowser + NSLog(@"loadRequest:%@", request); +#endif + error_ = false; - WebThreadLock(); + WebThreadLocked lock; [webview_ loadRequest:request]; - WebThreadUnlock(); } -- (void) reloadURL { +- (void) reloadURLWithCache:(BOOL)cache { if (request_ == nil) return; + NSMutableURLRequest *request([request_ mutableCopy]); + [request setCachePolicy:(cache ? NSURLRequestUseProtocolCachePolicy : NSURLRequestReloadIgnoringLocalCacheData)]; + + [request_ autorelease]; + request_ = [request retain]; + if ([request_ HTTPBody] == nil && [request_ HTTPBodyStream] == nil) [self loadRequest:request_]; else { @@ -387,7 +559,9 @@ enum CYWebPolicyDecision { message:nil delegate:self cancelButtonTitle:UCLocalize("CANCEL") - otherButtonTitles:UCLocalize("SUBMIT"), nil + otherButtonTitles: + UCLocalize("SUBMIT"), + nil ] autorelease]; [alert setContext:@"submit"]; @@ -395,47 +569,93 @@ enum CYWebPolicyDecision { } } +- (void) reloadURL { + [self reloadURLWithCache:YES]; +} + +- (void) reloadData { + [super reloadData]; + [self reloadURLWithCache:YES]; +} + - (void) setButtonImage:(NSString *)button withStyle:(NSString *)style toFunction:(id)function { if (custom_ != nil) [custom_ autorelease]; - custom_ = button == nil ? nil : [[UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:button]]] retain]; + if (button == nil) + custom_ = nil; + else + custom_ = [[UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:button]]] retain]; if (style_ != nil) [style_ autorelease]; - style_ = style == nil ? nil : [style retain]; + if (style == nil) + style_ = nil; + else + style_ = [style retain]; if (function_ != nil) [function_ autorelease]; - function_ = function == nil ? nil : [function retain]; + if (function == nil) + function_ = nil; + else + function_ = [function retain]; - [self applyRightButton]; + [self performSelectorOnMainThread:@selector(applyRightButton) withObject:nil waitUntilDone:NO]; } - (void) setButtonTitle:(NSString *)button withStyle:(NSString *)style toFunction:(id)function { if (custom_ != nil) [custom_ autorelease]; - custom_ = button == nil ? nil : [button retain]; + if (button == nil) + custom_ = nil; + else + custom_ = [button retain]; if (style_ != nil) [style_ autorelease]; - style_ = style == nil ? nil : [style retain]; + if (style == nil) + style_ = nil; + else + style_ = [style retain]; if (function_ != nil) [function_ autorelease]; - function_ = function == nil ? nil : [function retain]; + if (function == nil) + function_ = nil; + else + function_ = [function retain]; - [self applyRightButton]; + [self performSelectorOnMainThread:@selector(applyRightButton) withObject:nil waitUntilDone:NO]; } - (void) setPopupHook:(id)function { if (closer_ != nil) [closer_ autorelease]; - closer_ = function == nil ? nil : [function retain]; + if (function == nil) + closer_ = nil; + else + closer_ = [function retain]; +} + +- (void) _setViewportWidth { + [[webview_ _documentView] setViewportSize:CGSizeMake(width_, UIWebViewGrowsAndShrinksToFitHeight) forDocumentTypes:0x10]; } - (void) setViewportWidth:(float)width { width_ = width != 0 ? width : [[self class] defaultWidth]; - [[webview_ _documentView] setViewportSize:CGSizeMake(width_, UIWebViewGrowsAndShrinksToFitHeight) forDocumentTypes:0x10]; + [self _setViewportWidth]; +} + +- (void) _setViewportWidthOnMainThread:(NSNumber *)width { + [self setViewportWidth:[width floatValue]]; +} + +- (void) setViewportWidthOnMainThread:(float)width { + [self performSelectorOnMainThread:@selector(_setViewportWidthOnMainThread:) withObject:[NSNumber numberWithFloat:width] waitUntilDone:NO]; +} + +- (void) webViewUpdateViewSettings:(UIWebView *)view { + [self _setViewportWidth]; } - (void) _openMailToURL:(NSURL *)url { @@ -464,18 +684,26 @@ enum CYWebPolicyDecision { } // CYWebViewDelegate {{{ +- (void) webView:(WebView *)view addMessageToConsole:(NSDictionary *)message { +#if LogMessages + NSLog(@"addMessageToConsole:%@", message); +#endif +} + - (void) webView:(WebView *)view decidePolicyForNavigationAction:(NSDictionary *)action request:(NSURLRequest *)request frame:(WebFrame *)frame decisionListener:(id)listener { #if LogBrowser NSLog(@"decidePolicyForNavigationAction:%@ request:%@ frame:%@", action, request, frame); #endif - if (!error_ && [frame parentFrame] == nil) { - if (request_ != nil) - [request_ autorelease]; - if (request == nil) - request_ = nil; - else - request_ = [request retain]; + if ([frame parentFrame] == nil) { + if (!error_) { + if (request_ != nil) + [request_ autorelease]; + if (request == nil) + request_ = nil; + else + request_ = [request retain]; + } } } @@ -495,7 +723,8 @@ enum CYWebPolicyDecision { if ([scheme isEqualToString:@"mailto"]) [self _openMailToURL:url]; - CYViewController *page([delegate_ pageForURL:url hasTag:NULL]); + // XXX: filter to internal usage? + CYViewController *page([delegate_ pageForURL:url forExternal:NO]); if (page == nil) { BrowserController *browser([[[class_ alloc] init] autorelease]); @@ -510,13 +739,11 @@ enum CYWebPolicyDecision { [[self navigationController] pushViewController:page animated:YES]; } else { - UCNavigationController *navigation([[[UCNavigationController alloc] init] autorelease]); + UCNavigationController *navigation([[[UCNavigationController alloc] initWithRootViewController:page] autorelease]); [navigation setHook:indirect_]; [navigation setDelegate:delegate_]; - [navigation setViewControllers:[NSArray arrayWithObject:page]]; - [[page navigationItem] setLeftBarButtonItem:[[[UIBarButtonItem alloc] initWithTitle:UCLocalize("CLOSE") style:UIBarButtonItemStylePlain @@ -601,7 +828,10 @@ enum CYWebPolicyDecision { if ([frame parentFrame] != nil) return; + if (title_ != nil) + [title_ autorelease]; title_ = [title retain]; + [[self navigationItem] setTitle:title_]; } @@ -623,6 +853,10 @@ enum CYWebPolicyDecision { } - (NSURLRequest *) webView:(WebView *)view resource:(id)identifier willSendRequest:(NSURLRequest *)request redirectResponse:(NSURLResponse *)response fromDataSource:(WebDataSource *)source { +#if LogBrowser + NSLog(@"resource:%@ willSendRequest:%@ redirectResponse:%@ fromDataSource:%@", identifier, request, response, source); +#endif + return request; } @@ -687,19 +921,12 @@ enum CYWebPolicyDecision { [alert dismissWithClickedButtonIndex:-1 animated:YES]; } else if ([context isEqualToString:@"submit"]) { - switch (button) { - case 1: - break; - - case 2: - if (request_ != nil) { - WebThreadLock(); - [webview_ loadRequest:request_]; - WebThreadUnlock(); - } - break; - - _nodefault + if (button == [alert cancelButtonIndex]) { + } else if (button == [alert firstOtherButtonIndex]) { + if (request_ != nil) { + WebThreadLocked lock; + [webview_ loadRequest:request_]; + } } [alert dismissWithClickedButtonIndex:-1 animated:YES]; @@ -733,21 +960,43 @@ enum CYWebPolicyDecision { [[self navigationItem] setTitle:UCLocalize("LOADING")]; } +- (void) layoutRightButton { + [[loadingitem_ view] addSubview:indicator_]; + [[loadingitem_ view] bringSubviewToFront:indicator_]; +} + - (void) applyRightButton { if ([self isLoading]) { [[self navigationItem] setRightBarButtonItem:loadingitem_ animated:YES]; - // XXX: why do we do this again here? - [[loadingitem_ view] addSubview:indicator_]; + [self performSelector:@selector(layoutRightButton) withObject:nil afterDelay:0]; + + [indicator_ startAnimating]; [self applyLoadingTitle]; - } else if (custom_ != nil) { - [[self navigationItem] setRightBarButtonItem:[self customButton] animated:YES]; } else { - [[self navigationItem] setRightBarButtonItem:[self rightButton] animated:YES]; + [indicator_ stopAnimating]; + + [[self navigationItem] setRightBarButtonItem:( + custom_ != nil ? [self customButton] : [self rightButton] + ) animated:YES]; } } +- (void) didStartLoading { + // Overridden in subclasses. +} + - (void) _didStartLoading { [self applyRightButton]; + + if ([loading_ count] != 1) + return; + + [delegate_ retainNetworkActivityIndicator]; + [self didStartLoading]; +} + +- (void) didFinishLoading { + // Overridden in subclasses. } - (void) _didFinishLoading { @@ -755,10 +1004,10 @@ enum CYWebPolicyDecision { return; [self applyRightButton]; + [[self navigationItem] setTitle:title_]; - // XXX: wtf? - if (![self isLoading]) - [[self navigationItem] setTitle:title_]; + [delegate_ releaseNetworkActivityIndicator]; + [self didFinishLoading]; } - (bool) isLoading { @@ -789,6 +1038,8 @@ enum CYWebPolicyDecision { [document setTileSize:CGSizeMake(320, 500)]; [document setBackgroundColor:[UIColor clearColor]]; + + // XXX: this is terribly (too?) expensive [document setDrawsBackground:NO]; WebView *webview([document webView]); @@ -803,11 +1054,18 @@ enum CYWebPolicyDecision { [preferences setCacheModel:WebCacheModelDocumentBrowser]; [preferences setOfflineWebApplicationCacheEnabled:YES]; +#if LogMessages + if ([document respondsToSelector:@selector(setAllowsMessaging:)]) + [document setAllowsMessaging:YES]; + if ([webview respondsToSelector:@selector(_setAllowsMessaging:)]) + [webview _setAllowsMessaging:YES]; +#endif + if ([webview_ respondsToSelector:@selector(_scrollView)]) { scroller_ = [webview_ _scrollView]; [scroller_ setDirectionalLockEnabled:YES]; - [scroller_ setDecelerationRate:UIScrollViewDecelerationRateNormal]; + [scroller_ setDecelerationRate:CYScrollViewDecelerationRateNormal]; [scroller_ setDelaysContentTouches:NO]; [scroller_ setCanCancelContentTouches:YES]; @@ -816,7 +1074,8 @@ enum CYWebPolicyDecision { scroller_ = (UIScrollView *) scroller; [scroller setDirectionalScrolling:YES]; - [scroller setScrollDecelerationFactor:UIScrollViewDecelerationRateNormal]; /* 0.989324 */ + // XXX: we might be better off /not/ setting this on older systems + [scroller setScrollDecelerationFactor:CYScrollViewDecelerationRateNormal]; /* 0.989324 */ [scroller setScrollHysteresis:0]; /* 8 */ [scroller setThumbDetectionEnabled:NO]; @@ -852,11 +1111,8 @@ enum CYWebPolicyDecision { action:@selector(reloadButtonClicked) ]; - CGSize indsize = [UIProgressIndicator defaultSizeForStyle:UIProgressIndicatorStyleMediumWhite]; - indicator_ = [[UIProgressIndicator alloc] initWithFrame:CGRectMake(15, 5, indsize.width, indsize.height)]; - [indicator_ setStyle:UIProgressIndicatorStyleMediumWhite]; - [indicator_ startAnimation]; - [[loadingitem_ view] addSubview:indicator_]; + indicator_ = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhite]; + [indicator_ setFrame:CGRectMake(15, 5, [indicator_ frame].size.width, [indicator_ frame].size.height)]; [webview_ setAutoresizingMask:(UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight)]; [indicator_ setAutoresizingMask:UIViewAutoresizingFlexibleLeftMargin]; @@ -871,13 +1127,19 @@ enum CYWebPolicyDecision { return [self initWithWidth:0]; } +- (id) initWithURL:(NSURL *)url { + if ((self = [self init]) != nil) { + [self setURL:url]; + } return self; +} + - (void) didDismissModalViewController { if (closer_ != nil) [self callFunction:closer_]; } - (void) callFunction:(WebScriptObject *)function { - WebThreadLock(); + WebThreadLocked lock; WebView *webview([[webview_ _documentView] webView]); WebFrame *frame([webview mainFrame]); @@ -910,12 +1172,10 @@ enum CYWebPolicyDecision { settings->setJavaScriptCanOpenWindowsAutomatically(no);*/ [preferences setJavaScriptCanOpenWindowsAutomatically:maybe]; - - WebThreadUnlock(); } - (void) reloadButtonClicked { - [self reloadURL]; + [self reloadURLWithCache:YES]; } - (void) _customButtonClicked { @@ -935,4 +1195,47 @@ enum CYWebPolicyDecision { return 980; } +- (void) dispatchEvent:(NSString *)event { + WebThreadLocked lock; + + NSString *script([NSString stringWithFormat:@ + "(function() {" + "var event = this.document.createEvent('Events');" + "event.initEvent('%@', false, false);" + "this.document.dispatchEvent(event);" + "})();" + , event]); + + NSMutableArray *frames([NSMutableArray arrayWithObjects: + [[[webview_ _documentView] webView] mainFrame] + , nil]); + + while (WebFrame *frame = [frames lastObject]) { + WebScriptObject *object([frame windowObject]); + [object evaluateWebScript:script]; + [frames removeLastObject]; + [frames addObjectsFromArray:[frame childFrames]]; + } +} + +- (void) viewWillAppear:(BOOL)animated { + [self dispatchEvent:@"CydiaViewWillAppear"]; + [super viewWillAppear:animated]; +} + +- (void) viewDidAppear:(BOOL)animated { + [self dispatchEvent:@"CydiaViewDidAppear"]; + [super viewDidAppear:animated]; +} + +- (void) viewWillDisappear:(BOOL)animated { + [self dispatchEvent:@"CydiaViewWillDisappear"]; + [super viewWillDisappear:animated]; +} + +- (void) viewDidDisappear:(BOOL)animated { + [self dispatchEvent:@"CydiaViewDidDisappear"]; + [super viewDidDisappear:animated]; +} + @end