diff options
author | Adam Ierymenko <adam.ierymenko@gmail.com> | 2016-06-29 12:00:16 -0700 |
---|---|---|
committer | Adam Ierymenko <adam.ierymenko@gmail.com> | 2016-06-29 12:00:16 -0700 |
commit | df00d3b046ee7b88eaf068b802411814ac97dfd2 (patch) | |
tree | 957fbaa9bdd3abde2a75e2f8d05c04359576bd5b /ext/installfiles/mac/mac-ui-macgap1-wrapper/src/MacGap/Classes | |
parent | 19735e70505a5f40fedede0b05764f5b1a1ef383 (diff) | |
download | infinitytier-df00d3b046ee7b88eaf068b802411814ac97dfd2.tar.gz infinitytier-df00d3b046ee7b88eaf068b802411814ac97dfd2.zip |
Going to have to continue to use the old MAC web-container-based UI on Macs prior to 10.10 even when the new UI comes out, and the new UI is not ready yet anyway, so resurrect this.
Diffstat (limited to 'ext/installfiles/mac/mac-ui-macgap1-wrapper/src/MacGap/Classes')
33 files changed, 2139 insertions, 0 deletions
diff --git a/ext/installfiles/mac/mac-ui-macgap1-wrapper/src/MacGap/Classes/CallbackDelegate.h b/ext/installfiles/mac/mac-ui-macgap1-wrapper/src/MacGap/Classes/CallbackDelegate.h new file mode 100755 index 00000000..0f31ee41 --- /dev/null +++ b/ext/installfiles/mac/mac-ui-macgap1-wrapper/src/MacGap/Classes/CallbackDelegate.h @@ -0,0 +1,20 @@ +// +// CallbackDelegate.h +// MacGap +// +// Created by Joe Hildebrand on 1/10/12. +// Copyright (c) 2012 Twitter. All rights reserved. +// + +#import "Command.h" + +@interface CallbackDelegate : Command { +} + +@property JSObjectRef callback; + +- (id) initWithContext:(JSContextRef)aContext forCallback:(WebScriptObject*)aCallback; +- (id) call; +- (id) callWithParams:(id)firstOrNil, ... NS_REQUIRES_NIL_TERMINATION; + +@end diff --git a/ext/installfiles/mac/mac-ui-macgap1-wrapper/src/MacGap/Classes/CallbackDelegate.m b/ext/installfiles/mac/mac-ui-macgap1-wrapper/src/MacGap/Classes/CallbackDelegate.m new file mode 100755 index 00000000..5ce8fbe3 --- /dev/null +++ b/ext/installfiles/mac/mac-ui-macgap1-wrapper/src/MacGap/Classes/CallbackDelegate.m @@ -0,0 +1,168 @@ +// +// CallbackDelegate.m +// MacGap +// +// Created by Joe Hildebrand on 1/10/12. +// Copyright (c) 2012 Twitter. All rights reserved. +// + +#import "CallbackDelegate.h" +#import <JavaScriptCore/JavaScript.h> + +@implementation CallbackDelegate + +@synthesize callback; + +- (id) initWithContext:(JSContextRef)aContext forCallback:(WebScriptObject*)aCallback +{ + if (!aCallback) + return nil; + if ([aCallback isKindOfClass:[WebUndefined class]]) + return nil; + + self = [super initWithContext:aContext]; + if (!self) + return nil; + + callback = [aCallback JSObject]; + JSValueProtect(context, callback); + return self; +} + +- (void) dealloc +{ + if (callback) + { + JSValueUnprotect(context, callback); + callback = nil; + } +} + +- (id) objectFromValue:(JSValueRef)val +{ + JSStringRef jstr; + NSString *rets; + + switch(JSValueGetType(context, val)) + { + case kJSTypeUndefined: + case kJSTypeNull: + return nil; + case kJSTypeBoolean: + return [NSNumber numberWithBool:JSValueToBoolean(context, val)]; + case kJSTypeNumber: + return [NSNumber numberWithDouble:JSValueToNumber(context, val, NULL)]; + case kJSTypeString: + jstr = JSValueToStringCopy(context, val, NULL); + size_t sz = JSStringGetMaximumUTF8CStringSize(jstr); + char *buf = (char*)malloc(sz); + JSStringGetUTF8CString(jstr, buf, sz); + rets = [NSString stringWithUTF8String:buf]; + free(buf); + return rets; + case kJSTypeObject: + // TODO: dictionary or something + return nil; + default: + NSAssert(false, @"Invalid JavaScript type"); + return nil; + } +} + +- (JSValueRef) valueFromObject:(id)obj +{ + JSValueRef val = nil; + if (!obj) + { + val = JSValueMakeNull(context); + } + else if ([obj isKindOfClass:[NSString class]]) + { + JSStringRef jstr = JSStringCreateWithUTF8CString([obj UTF8String]); + val = JSValueMakeString(context, jstr); + JSStringRelease(jstr); + } + else if ([obj isKindOfClass:[NSNumber class]]) + { + val = JSValueMakeNumber(context, [obj doubleValue]); + } + else if ([obj isKindOfClass:[NSDictionary class]]) + { + JSObjectRef o = JSObjectMake(context, NULL, NULL); + for (NSString *key in obj) + { + JSStringRef kstr = JSStringCreateWithUTF8CString([key UTF8String]); + JSValueRef v = [self valueFromObject:[obj objectForKey:key]]; + + JSObjectSetProperty(context, o, kstr, v, kJSPropertyAttributeNone, NULL); + JSStringRelease(kstr); + } + val = o; + } + else if ([obj isKindOfClass:[NSArray class]]) + { + NSUInteger pcount = [obj count]; + JSValueRef jsArgs[pcount]; + NSUInteger i=0; + for (id v in obj) + { + jsArgs[i++] = [self valueFromObject:v]; + } + val = JSObjectMakeArray(context, pcount, jsArgs, NULL); + } + else if ([obj isKindOfClass:[NSDate class]]) + { + NSTimeInterval secs = [obj timeIntervalSince1970]; + JSValueRef jsArgs[1]; + // call the Date(milliseconds) constructor in JS + jsArgs[0] = JSValueMakeNumber(context, secs * 1000.0); + val = JSObjectMakeDate(context, 1, jsArgs, NULL); + } + else + { + NSLog(@"Warning: unknown object type for: %@", obj); + val = JSValueMakeUndefined(context); + } + return val; +} + +- (id) call +{ + NSAssert(callback, @"Callback required"); + if (!JSObjectIsFunction(context, callback)) + return nil; + + JSValueRef jsArgs[0]; + JSValueRef ret = JSObjectCallAsFunction(context, callback, NULL, 0, jsArgs, NULL); + return [self objectFromValue:ret]; +} + +- (id) callWithParams:(id)firstOrNil, ... +{ + NSAssert(callback, @"Callback required"); + if (!JSObjectIsFunction(context, callback)) + return nil; + NSUInteger pcount = 0; + id p; + va_list args; + va_start(args, firstOrNil); + for (p=firstOrNil; p; p=va_arg(args, id)) + { + pcount++; + } + va_end(args); + + JSValueRef jsArgs[pcount]; + NSUInteger j = 0; + va_start(args, firstOrNil); + for (p=firstOrNil; p; p=va_arg(args, id)) + { + jsArgs[j++] = [self valueFromObject:p]; + } + va_end(args); + + JSValueRef ret = JSObjectCallAsFunction(context, callback, NULL, j, jsArgs, NULL); + return [self objectFromValue:ret]; +} + +@end diff --git a/ext/installfiles/mac/mac-ui-macgap1-wrapper/src/MacGap/Classes/Commands/App.h b/ext/installfiles/mac/mac-ui-macgap1-wrapper/src/MacGap/Classes/Commands/App.h new file mode 100644 index 00000000..f65ba61e --- /dev/null +++ b/ext/installfiles/mac/mac-ui-macgap1-wrapper/src/MacGap/Classes/Commands/App.h @@ -0,0 +1,21 @@ +#import <Foundation/Foundation.h> + +#import "WindowController.h" + +@interface App : NSObject { + +} + +@property (nonatomic, retain) WebView *webView; + +- (id) initWithWebView:(WebView *)view; + +- (void) terminate; +- (void) activate; +- (void) hide; +- (void) unhide; +- (void) beep; +- (void) bounce; +- (void) setCustomUserAgent:(NSString *)userAgentString; +- (NSNumber*) systemIdleTime; +@end diff --git a/ext/installfiles/mac/mac-ui-macgap1-wrapper/src/MacGap/Classes/Commands/App.m b/ext/installfiles/mac/mac-ui-macgap1-wrapper/src/MacGap/Classes/Commands/App.m new file mode 100644 index 00000000..6d47a17e --- /dev/null +++ b/ext/installfiles/mac/mac-ui-macgap1-wrapper/src/MacGap/Classes/Commands/App.m @@ -0,0 +1,128 @@ +#import "App.h" + +#import "JSEventHelper.h" + +@implementation App + +@synthesize webView; + +- (id) initWithWebView:(WebView *) view{ + self = [super init]; + + if (self) { + self.webView = view; + [[[NSWorkspace sharedWorkspace] notificationCenter] addObserver: self + selector: @selector(receiveSleepNotification:) + name: NSWorkspaceWillSleepNotification object: NULL]; + [[[NSWorkspace sharedWorkspace] notificationCenter] addObserver: self + selector: @selector(receiveWakeNotification:) + name: NSWorkspaceDidWakeNotification object: NULL]; + [[[NSWorkspace sharedWorkspace] notificationCenter] addObserver: self + selector: @selector(receiveActivateNotification:) + name: NSWorkspaceDidActivateApplicationNotification object: NULL]; + } + + return self; +} + +- (void) terminate { + [NSApp terminate:nil]; +} + +- (void) activate { + [NSApp activateIgnoringOtherApps:YES]; +} + +- (void) hide { + [NSApp hide:nil]; +} + +- (void) unhide { + [NSApp unhide:nil]; +} + +- (void)beep { + NSBeep(); +} + +- (void) bounce { + [NSApp requestUserAttention:NSInformationalRequest]; +} + +- (void)setCustomUserAgent:(NSString *)userAgentString { + [self.webView setCustomUserAgent: userAgentString]; +} + +- (void) open:(NSString*)url { + [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:url]]; +} + +- (void) launch:(NSString *)name { + [[NSWorkspace sharedWorkspace] launchApplication:name]; +} + +- (void)receiveSleepNotification:(NSNotification*)note{ + [JSEventHelper triggerEvent:@"sleep" forWebView:self.webView]; +} + +- (void) receiveWakeNotification:(NSNotification*)note{ + [JSEventHelper triggerEvent:@"wake" forWebView:self.webView]; +} + +- (void) receiveActivateNotification:(NSNotification*)notification{ + NSDictionary* userInfo = [notification userInfo]; + NSRunningApplication* runningApplication = [userInfo objectForKey:NSWorkspaceApplicationKey]; + if (runningApplication) { + NSMutableDictionary* applicationDidGetFocusDict = [[NSMutableDictionary alloc] initWithCapacity:2]; + [applicationDidGetFocusDict setObject:runningApplication.localizedName + forKey:@"localizedName"]; + [applicationDidGetFocusDict setObject:[runningApplication.bundleURL absoluteString] + forKey:@"bundleURL"]; + + [JSEventHelper triggerEvent:@"appActivated" withArgs:applicationDidGetFocusDict forWebView:self.webView]; + } +} + + + + +/* + To get the elapsed time since the previous input event—keyboard, mouse, or tablet—specify kCGAnyInputEventType. + */ +- (NSNumber*)systemIdleTime { + CFTimeInterval timeSinceLastEvent = CGEventSourceSecondsSinceLastEventType(kCGEventSourceStateHIDSystemState, kCGAnyInputEventType); + + return [NSNumber numberWithDouble:timeSinceLastEvent]; +} + + + + ++ (NSString*) webScriptNameForSelector:(SEL)selector +{ + id result = nil; + + if (selector == @selector(open:)) { + result = @"open"; + } else if (selector == @selector(launch:)) { + result = @"launch"; + } else if (selector == @selector(setCustomUserAgent:)) { + result = @"setCustomUserAgent"; + } else if (selector == @selector(systemIdleTime)) { + result = @"systemIdleTime"; + } + + return result; +} + ++ (BOOL) isSelectorExcludedFromWebScript:(SEL)selector +{ + return NO; +} + ++ (BOOL) isKeyExcludedFromWebScript:(const char*)name +{ + return YES; +} + +@end diff --git a/ext/installfiles/mac/mac-ui-macgap1-wrapper/src/MacGap/Classes/Commands/Command.h b/ext/installfiles/mac/mac-ui-macgap1-wrapper/src/MacGap/Classes/Commands/Command.h new file mode 100755 index 00000000..65d6b6d4 --- /dev/null +++ b/ext/installfiles/mac/mac-ui-macgap1-wrapper/src/MacGap/Classes/Commands/Command.h @@ -0,0 +1,18 @@ +// +// Command.h +// MacGap +// +// Created by Joe Hildebrand on 1/10/12. +// Copyright (c) 2012 Twitter. All rights reserved. +// + +#import <Foundation/Foundation.h> +#import <Webkit/WebScriptObject.h> + +@interface Command : NSObject { + JSContextRef context; +} + +- (id) initWithContext:(JSContextRef)aContext; + +@end diff --git a/ext/installfiles/mac/mac-ui-macgap1-wrapper/src/MacGap/Classes/Commands/Command.m b/ext/installfiles/mac/mac-ui-macgap1-wrapper/src/MacGap/Classes/Commands/Command.m new file mode 100755 index 00000000..39b85630 --- /dev/null +++ b/ext/installfiles/mac/mac-ui-macgap1-wrapper/src/MacGap/Classes/Commands/Command.m @@ -0,0 +1,28 @@ +// +// Command.m +// MacGap +// +// Created by Joe Hildebrand on 1/10/12. +// Copyright (c) 2012 Twitter. All rights reserved. +// + +#import "Command.h" +#import <JavaScriptCore/JSContextRef.h> + +@implementation Command + +- (id) initWithContext:(JSContextRef)aContext { + self = [super init]; + if (!self) + return nil; + context = aContext; + JSGlobalContextRetain((JSGlobalContextRef)context); + return self; +} + +- (void)dealloc +{ + if (context) + JSGlobalContextRelease((JSGlobalContextRef)context); +} +@end diff --git a/ext/installfiles/mac/mac-ui-macgap1-wrapper/src/MacGap/Classes/Commands/Dock.h b/ext/installfiles/mac/mac-ui-macgap1-wrapper/src/MacGap/Classes/Commands/Dock.h new file mode 100644 index 00000000..b3c533d7 --- /dev/null +++ b/ext/installfiles/mac/mac-ui-macgap1-wrapper/src/MacGap/Classes/Commands/Dock.h @@ -0,0 +1,11 @@ +#import <Foundation/Foundation.h> + +@interface Dock : NSObject { + +} +- (void) setBadge:(NSString*)value; +- (NSString *) badge; + +@property (readwrite, copy) NSString *badge; + +@end diff --git a/ext/installfiles/mac/mac-ui-macgap1-wrapper/src/MacGap/Classes/Commands/Dock.m b/ext/installfiles/mac/mac-ui-macgap1-wrapper/src/MacGap/Classes/Commands/Dock.m new file mode 100644 index 00000000..a4494d16 --- /dev/null +++ b/ext/installfiles/mac/mac-ui-macgap1-wrapper/src/MacGap/Classes/Commands/Dock.m @@ -0,0 +1,31 @@ +#import "Dock.h" + +@implementation Dock + +@synthesize badge; + +- (void) setBadge:(NSString *)value +{ + NSDockTile *tile = [[NSApplication sharedApplication] dockTile]; + [tile setBadgeLabel:value]; +} + +- (NSString *) badge +{ + NSDockTile *tile = [[NSApplication sharedApplication] dockTile]; + return [tile badgeLabel]; +} + +#pragma mark WebScripting Protocol + ++ (BOOL) isSelectorExcludedFromWebScript:(SEL)selector +{ + return NO; +} + ++ (BOOL) isKeyExcludedFromWebScript:(const char*)name +{ + return NO; +} + +@end diff --git a/ext/installfiles/mac/mac-ui-macgap1-wrapper/src/MacGap/Classes/Commands/MenuItemProxy.h b/ext/installfiles/mac/mac-ui-macgap1-wrapper/src/MacGap/Classes/Commands/MenuItemProxy.h new file mode 100755 index 00000000..d765978f --- /dev/null +++ b/ext/installfiles/mac/mac-ui-macgap1-wrapper/src/MacGap/Classes/Commands/MenuItemProxy.h @@ -0,0 +1,31 @@ +// +// MenuItemProxy.h +// MacGap +// +// Created by Joe Hildebrand on 1/15/12. +// Copyright (c) 2012 Twitter. All rights reserved. +// + +#import "Command.h" +#import "CallbackDelegate.h" + +@class MenuProxy; + +@interface MenuItemProxy : Command { + NSMenuItem *item; + CallbackDelegate *callback; +} + ++ (MenuItemProxy*) proxyWithContext:(JSContextRef)aContext andMenuItem:(NSMenuItem*)anItem; + +- (MenuProxy*)addSubmenu; + +- (void) remove; +- (void) setCallback:(WebScriptObject*)aCallback; +- (void) setKey:(NSString*)keyCommand; +- (void) setTitle:(NSString*)title; +- (void) enable; +- (void) disable; +- (MenuProxy*)submenu; + +@end diff --git a/ext/installfiles/mac/mac-ui-macgap1-wrapper/src/MacGap/Classes/Commands/MenuItemProxy.m b/ext/installfiles/mac/mac-ui-macgap1-wrapper/src/MacGap/Classes/Commands/MenuItemProxy.m new file mode 100755 index 00000000..7b9702cc --- /dev/null +++ b/ext/installfiles/mac/mac-ui-macgap1-wrapper/src/MacGap/Classes/Commands/MenuItemProxy.m @@ -0,0 +1,150 @@ +// +// MenuItemProxy.m +// MacGap +// +// Created by Joe Hildebrand on 1/15/12. +// Copyright (c) 2012 Twitter. All rights reserved. +// + +#import "MenuItemProxy.h" +#import "MenuProxy.h" + +@implementation MenuItemProxy + +- (id) initWithContext:(JSContextRef)aContext andMenuItem:(NSMenuItem*)anItem +{ + NSAssert(anItem, @"anItem required"); + self = [super initWithContext:aContext]; + if (!self) + return nil; + item = anItem; + item.representedObject = self; + + return self; +} + ++ (MenuItemProxy*) proxyWithContext:(JSContextRef)aContext andMenuItem:(NSMenuItem*)anItem +{ + MenuItemProxy *proxy = [anItem representedObject]; + if (proxy) + { + NSLog(@"MIP Cache hit"); + NSAssert([proxy class] == [MenuItemProxy class], @"Bad proxy"); + return proxy; + } + return [[MenuItemProxy alloc] initWithContext:aContext andMenuItem:anItem]; +} + +- (NSString*) description +{ + return [item description]; +} + +- (MenuProxy*)addSubmenu +{ + NSMenu *s = [item submenu]; + if (!s) + { + s = [[NSMenu alloc] initWithTitle:@"FFFFFFOOOOO"]; + [item setSubmenu:s]; + } + return [MenuProxy proxyWithContext:context andMenu:s]; +} + +- (void) remove +{ + NSMenu *menu = [item menu]; + [menu removeItem:item]; +} + +- (void)callCallback:(id)sender +{ + [callback callWithParams:[sender title], nil]; +} + +- (void) setCallback:(WebScriptObject*)aCallback +{ + NSAssert(item, @"item required"); + callback = [[CallbackDelegate alloc] initWithContext:context forCallback:aCallback]; + [item setAction:@selector(callCallback:)]; + [item setTarget:self]; +} + +- (void)setKey:(NSString*)keyCommand +{ + NSString *aKey = [MenuProxy getKeyFromString:keyCommand]; + [item setKeyEquivalent:aKey]; + + NSUInteger modifiers = [MenuProxy getModifiersFromString:keyCommand]; + [item setKeyEquivalentModifierMask:modifiers]; +} + +- (void) setTitle:(NSString*)title +{ + [item setTitle:title]; +} + +- (MenuProxy*)submenu; +{ + // TODO: make this work as a property + NSMenu *s = [item submenu]; + if (!s) + return nil; + return [MenuProxy proxyWithContext:context andMenu:s]; +} + +- (void) enable +{ + [item setEnabled:YES]; +} + +- (void) disable +{ + [item setEnabled:NO]; +} + +#pragma mark WebScripting protocol + ++ (BOOL) isSelectorExcludedFromWebScript:(SEL)selector +{ + return [self webScriptNameForSelector:selector] == nil; +} + ++ (BOOL) isKeyExcludedFromWebScript:(const char*)name +{ + return YES; +} + ++ (NSString*) webScriptNameForSelector:(SEL)selector +{ + id result = nil; + + if (selector == @selector(addSubmenu)) { + result = @"addSubmenu"; + } + else if (selector == @selector(remove)) { + result = @"remove"; + } + else if (selector == @selector(setCallback:)) { + result = @"setCallback"; + } + else if (selector == @selector(setKey:)) { + result = @"setKey"; + } + else if (selector == @selector(setTitle:)) { + result = @"setTitle"; + } + else if (selector == @selector(submenu)) { + result = @"submenu"; + } + else if (selector == @selector(enable)) { + result = @"enable"; + } + else if (selector == @selector(disable)) { + result = @"disable"; + } + + return result; +} + +@end diff --git a/ext/installfiles/mac/mac-ui-macgap1-wrapper/src/MacGap/Classes/Commands/MenuProxy.h b/ext/installfiles/mac/mac-ui-macgap1-wrapper/src/MacGap/Classes/Commands/MenuProxy.h new file mode 100755 index 00000000..afd6c6ed --- /dev/null +++ b/ext/installfiles/mac/mac-ui-macgap1-wrapper/src/MacGap/Classes/Commands/MenuProxy.h @@ -0,0 +1,31 @@ +// +// MenuProxy.h +// MacGap +// +// Created by Joe Hildebrand on 1/14/12. +// Copyright (c) 2012 Twitter. All rights reserved. +// + +#import "Command.h" + +@class MenuItemProxy; + +@interface MenuProxy : Command { + NSMenu *menu; +} + ++ (MenuProxy*)proxyWithContext:(JSContextRef)aContext andMenu:(NSMenu*)aMenu; + +- (MenuItemProxy*)addItemWithTitle:(NSString*)title + keyEquivalent:(NSString*)aKey + callback:(WebScriptObject*)aCallback + atIndex:(NSInteger)index; + +- (MenuItemProxy*)addSeparator; +- (MenuItemProxy*)itemForKey:(id)key; +- (MenuProxy*)removeItem:(id)key; + ++ (NSString*)getKeyFromString:(NSString*)keyCommand; ++ (NSUInteger*)getModifiersFromString:(NSString*)keyCommand; + +@end diff --git a/ext/installfiles/mac/mac-ui-macgap1-wrapper/src/MacGap/Classes/Commands/MenuProxy.m b/ext/installfiles/mac/mac-ui-macgap1-wrapper/src/MacGap/Classes/Commands/MenuProxy.m new file mode 100755 index 00000000..5bc10a76 --- /dev/null +++ b/ext/installfiles/mac/mac-ui-macgap1-wrapper/src/MacGap/Classes/Commands/MenuProxy.m @@ -0,0 +1,233 @@ +// +// MenuProxy.m +// MacGap +// +// Created by Joe Hildebrand on 1/14/12. +// Copyright (c) 2012 Twitter. All rights reserved. +// + +#import <objc/runtime.h> +#import <JavaScriptCore/JavaScript.h> + +#import "MenuProxy.h" +#import "MenuItemProxy.h" + +static char REPRESENTED_OBJECT; + +@interface NSMenu (represented) +@property (strong) id representedObject; +@end + +@implementation NSMenu (represented) + +- (id) representedObject +{ + return objc_getAssociatedObject(self, &REPRESENTED_OBJECT); +} + +- (void) setRepresentedObject:(id)representedObject +{ + objc_setAssociatedObject(self, + &REPRESENTED_OBJECT, + representedObject, + OBJC_ASSOCIATION_RETAIN); +} + +@end + +@implementation MenuProxy + +- (id) initWithContext:(JSContextRef)aContext andMenu:(NSMenu*)aMenu +{ + self = [super initWithContext:aContext]; + if (!self) + return nil; + menu = aMenu; + menu.representedObject = self; + return self; +} + ++ (MenuProxy*)proxyWithContext:(JSContextRef)aContext andMenu:(NSMenu*)aMenu +{ + // singleton-ish. + MenuProxy *ret = [aMenu representedObject]; + if (ret) + { + NSLog(@"MP cache hit"); + return ret; + } + return [[MenuProxy alloc] initWithContext:aContext andMenu:aMenu]; +} + +- (void) dealloc +{ + menu.representedObject = nil; +} + +- (NSString*) description +{ + return [menu description]; +} + +static BOOL isNullish(id o) +{ + if (!o) + return YES; + if ([o isKindOfClass:[WebUndefined class]]) + return YES; + return NO; +} + +- (MenuItemProxy*)addItemWithTitle:(NSString*)title + keyEquivalent:(NSString*)keyCommand + callback:(WebScriptObject*)aCallback + atIndex:(NSInteger)index +{ + if (isNullish(title)) + title = @""; + + NSString *aKey = [MenuProxy getKeyFromString:keyCommand]; + NSMenuItem *item = nil; + + if(index) { + item = [menu insertItemWithTitle:title action:nil keyEquivalent:aKey atIndex:index ]; + } else { + item = [menu addItemWithTitle:title action:nil keyEquivalent:aKey ]; + + } + + // Set the modifiers. + NSUInteger modifiers = [MenuProxy getModifiersFromString:keyCommand]; + [item setKeyEquivalentModifierMask:modifiers]; + + if(!menu.supermenu) { + NSMenu *s = [[NSMenu alloc] initWithTitle:title]; + [item setSubmenu:s]; + } + + MenuItemProxy *mip = [MenuItemProxy proxyWithContext:context andMenuItem:item]; + if (!isNullish(aCallback)) + [mip setCallback:aCallback]; + + + return mip; +} + ++ (NSString*)getKeyFromString:(NSString*)keyCommand { + if (isNullish(keyCommand)) + keyCommand = @""; + + // Obtain the key (if there are modifiers, it will be the last character). + NSString *aKey = @""; + if ([keyCommand length] > 0) { + aKey = [keyCommand substringFromIndex:[keyCommand length] - 1]; + } + + return aKey; +} + ++ (NSUInteger*)getModifiersFromString:(NSString*)keyCommand { + // aKeys may optionally specify one or more modifiers. + NSUInteger modifiers = 0; + + if ([keyCommand rangeOfString:@"caps"].location != NSNotFound) modifiers += NSAlphaShiftKeyMask; + if ([keyCommand rangeOfString:@"shift"].location != NSNotFound) modifiers += NSShiftKeyMask; + if ([keyCommand rangeOfString:@"cmd"].location != NSNotFound) modifiers += NSCommandKeyMask; + if ([keyCommand rangeOfString:@"ctrl"].location != NSNotFound) modifiers += NSControlKeyMask; + if ([keyCommand rangeOfString:@"opt"].location != NSNotFound) modifiers += NSAlternateKeyMask; + if ([keyCommand rangeOfString:@"alt"].location != NSNotFound) modifiers += NSAlternateKeyMask; + + return modifiers; +} + +- (MenuItemProxy*)addSeparator +{ + NSMenuItem *sep = [NSMenuItem separatorItem]; + [menu addItem:sep]; + return [MenuItemProxy proxyWithContext:context andMenuItem:sep]; +} + +- (MenuItemProxy*)itemForKey:(id)key +{ + if (isNullish(key)) + return nil; + NSMenuItem *item = nil; + if ([key isKindOfClass:[NSNumber class]]) + { + item = [menu itemAtIndex:[key intValue]]; + } + else if ([key isKindOfClass:[NSString class]]) + { + item = [menu itemWithTitle:key]; + if (!item) + { + // Try again, with ... appended. e.g. "Save..." + item = [menu itemWithTitle: + [key stringByAppendingString:@"\u2026"]]; + } + } + if (!item) + return nil; + + return [MenuItemProxy proxyWithContext:context andMenuItem:item]; +} + +- (MenuProxy*)removeItem:(id)key +{ + if (isNullish(key)) + return nil; + + NSMenuItem *item = nil; + if ([key isKindOfClass:[NSNumber class]]) + { + item = [menu itemAtIndex:[key intValue]]; + } + else if ([key isKindOfClass:[NSString class]]) + { + item = [menu itemWithTitle:key]; + if (!item) + { + // Try again, with ... appended. e.g. "Save..." + item = [menu itemWithTitle: + [key stringByAppendingString:@"\u2026"]]; + } + } + if (!item) + return nil; + + [menu removeItem:item]; + return [MenuProxy proxyWithContext:context andMenu:menu]; +} + ++ (BOOL) isSelectorExcludedFromWebScript:(SEL)selector +{ + return [self webScriptNameForSelector:selector] == nil; +} + ++ (BOOL) isKeyExcludedFromWebScript:(const char*)name +{ + return YES; +} + ++ (NSString*) webScriptNameForSelector:(SEL)selector +{ + id result = nil; + + if (selector == @selector(addItemWithTitle:keyEquivalent:callback:atIndex:)) { + result = @"addItem"; + } + else if (selector == @selector(addSeparator)) { + result = @"addSeparator"; + } + else if (selector == @selector(itemForKey:)) { + result = @"getItem"; + } + else if (selector == @selector(removeItem:)) { + result = @"removeMenu"; + } + + return result; +} + + +@end diff --git a/ext/installfiles/mac/mac-ui-macgap1-wrapper/src/MacGap/Classes/Commands/Notice.h b/ext/installfiles/mac/mac-ui-macgap1-wrapper/src/MacGap/Classes/Commands/Notice.h new file mode 100644 index 00000000..51077a43 --- /dev/null +++ b/ext/installfiles/mac/mac-ui-macgap1-wrapper/src/MacGap/Classes/Commands/Notice.h @@ -0,0 +1,26 @@ +// +// Notice.h +// MacGap +// +// Created by Christian Sullivan on 7/26/12. +// Copyright (c) 2012 Twitter. All rights reserved. +// + +#import <Foundation/Foundation.h> +#import "WindowController.h" + +#define APP_NOTICE_NOTIFICATION @"Notice" + +@interface Notice : NSObject <NSUserNotificationCenterDelegate> { + +} + +@property (nonatomic, retain) WebView *webView; + +- (id) initWithWebView:(WebView *)view; +- (void) notify:(NSDictionary*)message; +- (void) close:(NSString*)notificationId; ++ (BOOL) available; + +@end + diff --git a/ext/installfiles/mac/mac-ui-macgap1-wrapper/src/MacGap/Classes/Commands/Notice.m b/ext/installfiles/mac/mac-ui-macgap1-wrapper/src/MacGap/Classes/Commands/Notice.m new file mode 100644 index 00000000..a4095f9f --- /dev/null +++ b/ext/installfiles/mac/mac-ui-macgap1-wrapper/src/MacGap/Classes/Commands/Notice.m @@ -0,0 +1,108 @@ +// +// Notice.m +// MacGap +// +// Created by Christian Sullivan on 7/26/12. +// Copyright (c) 2012 Twitter. All rights reserved. +// + +#import "Notice.h" + +#import "JSEventHelper.h" + +@implementation Notice + +- (id) initWithWebView:(WebView*)view +{ + if(self = [super init]) { + self.webView = view; + [[NSUserNotificationCenter defaultUserNotificationCenter] setDelegate:self]; + } + return self; +} + +- (void) notify:(NSDictionary *)message { + NSUserNotification *notification = [[NSUserNotification alloc] init]; + [notification setTitle:[message valueForKey:@"title"]]; + [notification setInformativeText:[message valueForKey:@"content"]]; + [notification setDeliveryDate:[NSDate dateWithTimeInterval:0 sinceDate:[NSDate date]]]; + BOOL playSound = true; // optional parameter, false only when {sound: false} + @try { + NSNumber *s = [message valueForKey:@"sound"]; + if ([[s className] isEqual: @"__NSCFBoolean"]) { + playSound = [s boolValue]; + } + } + @catch (NSException *exception) { + } + if (playSound) { + [notification setSoundName:NSUserNotificationDefaultSoundName]; + } + NSString *id = @""; // optional, needed for close + @try { + id = [message valueForKey:@"id"]; + } + @catch (NSException *exception) { + } + [notification setUserInfo:[NSDictionary dictionaryWithObjectsAndKeys:id, @"id", nil]]; + NSUserNotificationCenter *center = [NSUserNotificationCenter defaultUserNotificationCenter]; + [center scheduleNotification:notification]; +} + +// close all notifications with id == notificationId or close all notifications if notificationId == "*" +- (void) close:(NSString*)notificationId { + NSUserNotificationCenter *center = [NSUserNotificationCenter defaultUserNotificationCenter]; + for(NSUserNotification * deliveredNote in center.deliveredNotifications) { + if ([notificationId isEqualToString:@"*"] || [deliveredNote.userInfo[@"id"] isEqualToString:notificationId]) { + [center removeDeliveredNotification: deliveredNote]; + } + } +} + ++ (BOOL) available { + if ([NSUserNotificationCenter respondsToSelector:@selector(defaultUserNotificationCenter)]) + return YES; + + return NO; +} + +- (void) userNotificationCenter:(NSUserNotificationCenter *)center didActivateNotification:(NSUserNotification *)notification +{ + NSString *notificationId = [notification.userInfo valueForKey:@"id"]; + [JSEventHelper triggerEvent:@"macgap.notify.activated" forDetail:notificationId forWebView:self.webView]; +} + +#pragma mark WebScripting Protocol + ++ (BOOL) isSelectorExcludedFromWebScript:(SEL)selector +{ + BOOL result = YES; + if (selector == @selector(notify:)) + result = NO; + if (selector == @selector(close:)) + result = NO; + + return result; +} + ++ (NSString*) webScriptNameForSelector:(SEL)selector +{ + id result = nil; + + if (selector == @selector(notify:)) { + result = @"notify"; + } + if (selector == @selector(close:)) { + result = @"close"; + } + + return result; +} + +// right now exclude all properties (eg keys) ++ (BOOL) isKeyExcludedFromWebScript:(const char*)name +{ + return YES; +} + +@end diff --git a/ext/installfiles/mac/mac-ui-macgap1-wrapper/src/MacGap/Classes/Commands/Path.h b/ext/installfiles/mac/mac-ui-macgap1-wrapper/src/MacGap/Classes/Commands/Path.h new file mode 100644 index 00000000..f931340d --- /dev/null +++ b/ext/installfiles/mac/mac-ui-macgap1-wrapper/src/MacGap/Classes/Commands/Path.h @@ -0,0 +1,21 @@ +#import <Foundation/Foundation.h> + +@interface Path : NSObject { + +} + +- (NSString *) application; +- (NSString *) resource; +- (NSString *) documents; +- (NSString *) library; +- (NSString *) home; +- (NSString *) temp; + +@property (readonly,copy) NSString* application; +@property (readonly,copy) NSString* resource; +@property (readonly,copy) NSString* documents; +@property (readonly,copy) NSString* library; +@property (readonly,copy) NSString* home; +@property (readonly,copy) NSString* temp; + +@end diff --git a/ext/installfiles/mac/mac-ui-macgap1-wrapper/src/MacGap/Classes/Commands/Path.m b/ext/installfiles/mac/mac-ui-macgap1-wrapper/src/MacGap/Classes/Commands/Path.m new file mode 100644 index 00000000..8c54100f --- /dev/null +++ b/ext/installfiles/mac/mac-ui-macgap1-wrapper/src/MacGap/Classes/Commands/Path.m @@ -0,0 +1,53 @@ +#import "Path.h" + +@implementation Path + +@synthesize application; +@synthesize resource; +@synthesize documents; +@synthesize library; +@synthesize home; +@synthesize temp; + +- (NSString *)application { + return [[NSBundle mainBundle] bundlePath]; +} + +- (NSString *)resource { + return [[NSBundle mainBundle] resourcePath]; +} + +- (NSString *)documents { + NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); + return [paths objectAtIndex:0]; +} + +- (NSString *)library { + NSArray *paths = NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES); + NSLog( @"%@", paths ); + return [paths objectAtIndex:0]; +} + +- (NSString *)home { + return NSHomeDirectory(); +} + +- (NSString *)temp { + return NSTemporaryDirectory(); +} + +#pragma mark WebScripting Protocol + +/* checks whether a selector is acceptable to be called from JavaScript */ ++ (BOOL) isSelectorExcludedFromWebScript:(SEL)selector +{ + return NO; +} + +// right now exclude all properties (eg keys) ++ (BOOL) isKeyExcludedFromWebScript:(const char*)name +{ + return NO; +} + +@end diff --git a/ext/installfiles/mac/mac-ui-macgap1-wrapper/src/MacGap/Classes/Commands/Sound.h b/ext/installfiles/mac/mac-ui-macgap1-wrapper/src/MacGap/Classes/Commands/Sound.h new file mode 100644 index 00000000..06707643 --- /dev/null +++ b/ext/installfiles/mac/mac-ui-macgap1-wrapper/src/MacGap/Classes/Commands/Sound.h @@ -0,0 +1,17 @@ +#import <Cocoa/Cocoa.h> +#import "Command.h" +#import "CallbackDelegate.h" + + +@interface Sound : Command { + +} + +// pending callbacks for sounds being played, to keep +// ARC from freeing them too early +@property (nonatomic, strong) NSMutableSet *pending; + +- (void) play:(NSString*)file onComplete:(WebScriptObject*)callback; +- (void) playSystem:(NSString*)name onComplete:(WebScriptObject*)callback; + +@end diff --git a/ext/installfiles/mac/mac-ui-macgap1-wrapper/src/MacGap/Classes/Commands/Sound.m b/ext/installfiles/mac/mac-ui-macgap1-wrapper/src/MacGap/Classes/Commands/Sound.m new file mode 100644 index 00000000..9f4a44db --- /dev/null +++ b/ext/installfiles/mac/mac-ui-macgap1-wrapper/src/MacGap/Classes/Commands/Sound.m @@ -0,0 +1,97 @@ +#import "Sound.h" + + +@interface PlayDelegate : CallbackDelegate <NSSoundDelegate> { +} + +@property (nonatomic, weak) Sound *sound; + +- (id) initWithContext:(JSContextRef)aContext + forCallback:(WebScriptObject*)aCallback + withSound:(Sound*)aSound; +@end + +@implementation PlayDelegate + +@synthesize sound; + +- (id) initWithContext:(JSContextRef)aContext + forCallback:(WebScriptObject*)aCallback + withSound:(Sound*)aSound +{ + self = [super initWithContext:aContext forCallback:aCallback]; + if (!self) + return nil; + sound = aSound; + return self; +} + +- (void)sound:(NSSound *)aSound didFinishPlaying:(BOOL)finishedPlaying { + [self callWithParams:[aSound name], nil]; + [sound.pending removeObject:self]; +} + +@end + +@implementation Sound + +@synthesize pending; + +- (id) initWithContext:(JSContextRef)aContext { + self = [super initWithContext:aContext]; + if (!self) { + return nil; + } + + pending = [NSMutableSet new]; + return self; +} + +- (void) playSound:(NSSound*)sound onComplete:(WebScriptObject*)callback { + if (callback != (id)[WebUndefined undefined]) { + PlayDelegate *d = [[PlayDelegate alloc] initWithContext:context + forCallback:callback + withSound:self]; + [pending addObject:d]; + [sound setDelegate:d]; + } + [sound play]; +} + +- (void) play:(NSString*)file onComplete:(WebScriptObject*)callback { + NSURL* fileUrl = [NSURL fileURLWithPath:[[Utils sharedInstance] pathForResource:file]]; + DebugNSLog(@"Sound file:%@", [fileUrl description]); + + NSSound* sound = [[NSSound alloc] initWithContentsOfURL:fileUrl byReference:YES]; + [self playSound:sound onComplete:callback]; +} + +- (void) playSystem:(NSString*)name onComplete:(WebScriptObject*)callback { + NSSound *systemSound = [NSSound soundNamed:name]; + [self playSound:systemSound onComplete:callback]; +} + +#pragma mark WebScripting Protocol + ++ (BOOL) isSelectorExcludedFromWebScript:(SEL)selector { + return [self webScriptNameForSelector:selector] == nil; +} + ++ (BOOL) isKeyExcludedFromWebScript:(const char*)name { + return YES; +} + ++ (NSString*) webScriptNameForSelector:(SEL)selector { + id result = nil; + + if (selector == @selector(play:onComplete:)) { + result = @"play"; + } + else if (selector == @selector(playSystem:onComplete:)) { + result = @"playSystem"; + } + + return result; +} + +@end diff --git a/ext/installfiles/mac/mac-ui-macgap1-wrapper/src/MacGap/Classes/Commands/UserDefaults.h b/ext/installfiles/mac/mac-ui-macgap1-wrapper/src/MacGap/Classes/Commands/UserDefaults.h new file mode 100644 index 00000000..269191b3 --- /dev/null +++ b/ext/installfiles/mac/mac-ui-macgap1-wrapper/src/MacGap/Classes/Commands/UserDefaults.h @@ -0,0 +1,43 @@ +// +// UserDefaults.h +// MacGap +// +// Created by Jeff Hanbury on 16/04/2014. +// Copyright (c) 2014 Twitter. All rights reserved. +// + +#import <Foundation/Foundation.h> + +#import "WindowController.h" + +@interface UserDefaults : NSObject + +@property (nonatomic, retain) WebView *webView; + +- (id) initWithWebView:(WebView *)view; +- (NSString*) getMyDefaults; +- (NSDictionary*) myDefaultsDictionary; +- (void) removeObjectForKey:(NSString*)key; +- (NSArray*) getUserDefaultsKeys; + +- (NSString*) addPrefix:(NSString*)key; + +- (void) setString:(NSString*)key withValue:(NSString*)value; +- (NSString*) getString:(NSString*)key; + +- (void) setInteger:(NSString*)key withValue:(NSString*)value; +- (NSNumber*) getInteger:(NSString*)key; + +- (void) setBool:(NSString*)key withValue:(NSString*)value; +- (NSNumber*) getBool:(NSString*)key; + +- (void) setFloat:(NSString*)key withValue:(NSString*)value; +- (NSNumber*) getFloat:(NSString*)key; + +// Could also be implemented: +//– setObject:forKey: +//– setDouble:forKey: +//– setURL:forKey: + +@end + diff --git a/ext/installfiles/mac/mac-ui-macgap1-wrapper/src/MacGap/Classes/Commands/UserDefaults.m b/ext/installfiles/mac/mac-ui-macgap1-wrapper/src/MacGap/Classes/Commands/UserDefaults.m new file mode 100644 index 00000000..48568710 --- /dev/null +++ b/ext/installfiles/mac/mac-ui-macgap1-wrapper/src/MacGap/Classes/Commands/UserDefaults.m @@ -0,0 +1,211 @@ +// +// UserDefaults.m +// MacGap +// +// Created by Jeff Hanbury on 16/04/2014. +// Copyright (c) 2014 Twitter. All rights reserved. +// + +#import "UserDefaults.h" +#import "JSEventHelper.h" + +@interface UserDefaults() { + +} + +-(void) setupNotificationCenter; + +@end + + +@implementation UserDefaults + +- (id) initWithWebView:(WebView *) view{ + self = [super init]; + + if (self) { + self.webView = view; + [self setupNotificationCenter]; + } + + return self; +} + + +-(void) setupNotificationCenter{ + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(defaultsChanged:) + name:NSUserDefaultsDidChangeNotification + object:nil]; +} + +- (void)defaultsChanged:(NSNotification *)notification { + NSDictionary* returnDict = [self myDefaultsDictionary]; + [JSEventHelper triggerEvent:@"userDefaultsChanged" withArgs:returnDict forWebView:self.webView]; +} + +- (NSString*) getMyDefaults { + NSDictionary* myDefaults = [self myDefaultsDictionary]; + + return [[Utils sharedInstance] convertDictionaryToJSON:myDefaults]; +} + +- (NSDictionary*) myDefaultsDictionary { + NSString* prefix = [kWebScriptNamespace stringByAppendingString:@"_"]; + NSMutableDictionary* returnDict = [[NSMutableDictionary alloc] init]; + + // Get the user defaults. + NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; + + // Build up a dictionary containing just the items beginning with our + // prefix. + for (NSString* key in [self getUserDefaultsKeys]) { + if ([key hasPrefix:prefix]) { + id val = [defaults valueForKey:key]; + [returnDict setObject:val forKey:key]; + } + } + + return returnDict; +} + +- (NSArray*) getUserDefaultsKeys { + NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults]; + return [[prefs dictionaryRepresentation] allKeys]; +} + +- (void) removeObjectForKey:(NSString*)key { + NSString* prefixedKey; + prefixedKey = [self addPrefix:key]; + + [[NSUserDefaults standardUserDefaults] removeObjectForKey:prefixedKey]; + [[NSUserDefaults standardUserDefaults] synchronize]; +} + +// Check we have a standard prefix for JS-modified keys, for security purposes. +// If not, add it. This stops JavaScript from ever being able to modify keys +// it did not create. +- (NSString*) addPrefix:(NSString*)key { + NSString* prefix; + prefix = [kWebScriptNamespace stringByAppendingString:@"_"]; + + if (![key hasPrefix:prefix]) { + key = [prefix stringByAppendingString:key]; + } + return key; +} + +// String + +- (void) setString:(NSString*)key withValue:(NSString*)value { + NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults]; + NSString* prefixedKey; + prefixedKey = [self addPrefix:key]; + [prefs setObject:value forKey:prefixedKey]; +} + +- (NSString*) getString:(NSString *)key { + NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults]; + return [prefs stringForKey:key]; +} + +// All the following must convert their type to NSNumber for JavaScript. + +// Integer + +- (void) setInteger:(NSString*)key withValue:(NSString*)value { + NSString* prefixedKey; + prefixedKey = [self addPrefix:key]; + + NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults]; + NSInteger myInt = [value intValue]; + [prefs setInteger:myInt forKey:prefixedKey]; +} + +- (NSNumber*) getInteger:(NSString *)key { + NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults]; + return [NSNumber numberWithInteger:[prefs integerForKey:key]]; +} + +// Boolean + +- (void) setBool:(NSString*)key withValue:(NSString*)value { + NSString* prefixedKey; + prefixedKey = [self addPrefix:key]; + + NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults]; + BOOL myBool = [value boolValue]; + [prefs setBool:myBool forKey:prefixedKey]; +} + +- (NSNumber*) getBool:(NSString *)key { + NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults]; + return [NSNumber numberWithBool:[prefs boolForKey:key]]; +} + +// Float + +- (void) setFloat:(NSString*)key withValue:(NSString*)value { + NSString* prefixedKey; + prefixedKey = [self addPrefix:key]; + + NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults]; + float myFloat = [value floatValue]; + [prefs setFloat:myFloat forKey:prefixedKey]; +} + +- (NSNumber*) getFloat:(NSString *)key { + NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults]; + return [NSNumber numberWithFloat:[prefs floatForKey:key]]; +} + + +#pragma mark WebScripting Protocol + ++ (BOOL) isSelectorExcludedFromWebScript:(SEL)selector { + return NO; +} + ++ (NSString*) webScriptNameForSelector:(SEL)selector { + id result = nil; + + if (selector == @selector(getMyDefaults)) { + result = @"getMyDefaults"; + } + + if (selector == @selector(removeObjectForKey:)) { + result = @"removeObjectForKey"; + } + + else if (selector == @selector(setString:withValue:)) { + result = @"setString"; + } else if (selector == @selector(getString:)) { + result = @"getString"; + } + + else if (selector == @selector(setInteger:withValue:)) { + result = @"setInteger"; + } else if (selector == @selector(getInteger:)) { + result = @"getInteger"; + } + + else if (selector == @selector(setBool:withValue:)) { + result = @"setBool"; + } else if (selector == @selector(getBool:)) { + result = @"getBool"; + } + + else if (selector == @selector(setFloat:withValue:)) { + result = @"setFloat"; + } else if (selector == @selector(getFloat:)) { + result = @"getFloat"; + } + + return result; +} + ++ (BOOL) isKeyExcludedFromWebScript:(const char*)name { + return NO; +} + +@end diff --git a/ext/installfiles/mac/mac-ui-macgap1-wrapper/src/MacGap/Classes/Commands/fonts.h b/ext/installfiles/mac/mac-ui-macgap1-wrapper/src/MacGap/Classes/Commands/fonts.h new file mode 100644 index 00000000..62c7b7e8 --- /dev/null +++ b/ext/installfiles/mac/mac-ui-macgap1-wrapper/src/MacGap/Classes/Commands/fonts.h @@ -0,0 +1,9 @@ +@interface Fonts : NSObject { +} + +- (NSArray*) availableFonts; +- (NSArray*) availableFontFamilies; +- (NSArray*) availableMembersOfFontFamily:(NSString*)fontFamily; +- (CGFloat) defaultLineHeightForFont:(NSString *)theFontName ofSize:(CGFloat)theFontSize; + +@end diff --git a/ext/installfiles/mac/mac-ui-macgap1-wrapper/src/MacGap/Classes/Commands/fonts.m b/ext/installfiles/mac/mac-ui-macgap1-wrapper/src/MacGap/Classes/Commands/fonts.m new file mode 100644 index 00000000..b17818a5 --- /dev/null +++ b/ext/installfiles/mac/mac-ui-macgap1-wrapper/src/MacGap/Classes/Commands/fonts.m @@ -0,0 +1,48 @@ +#import "fonts.h" + +@implementation Fonts + + +- (NSArray*) availableFonts { + return [[NSFontManager sharedFontManager] availableFonts]; +} + +- (NSArray*) availableFontFamilies { + return [[NSFontManager sharedFontManager] availableFontFamilies]; +} + +- (NSArray*) availableMembersOfFontFamily:(NSString *)fontFamily { + return [[NSFontManager sharedFontManager] availableMembersOfFontFamily:fontFamily]; +} + +- (CGFloat) defaultLineHeightForFont:(NSString*)theFontName ofSize:(CGFloat)theFontSize { + NSFont *theFont = [NSFont fontWithName:theFontName size:theFontSize]; + NSLayoutManager *lm = [[NSLayoutManager alloc] init]; + + return [lm defaultLineHeightForFont:theFont]; +} + + +#pragma mark WebScripting Protocol + ++ (BOOL) isSelectorExcludedFromWebScript:(SEL)selector { + return NO; +} + ++ (NSString*) webScriptNameForSelector:(SEL)selector { + id result = nil; + + if (selector == @selector(availableMembersOfFontFamily:)) { + result = @"availableMembersOfFontFamily"; + } else if (selector == @selector(defaultLineHeightForFont:ofSize:)) { + result = @"defaultLineHeightForFont"; + } + + return result; +} + ++ (BOOL) isKeyExcludedFromWebScript:(const char*)name { + return NO; +} + +@end diff --git a/ext/installfiles/mac/mac-ui-macgap1-wrapper/src/MacGap/Classes/Constants.h b/ext/installfiles/mac/mac-ui-macgap1-wrapper/src/MacGap/Classes/Constants.h new file mode 100644 index 00000000..1fe59d6c --- /dev/null +++ b/ext/installfiles/mac/mac-ui-macgap1-wrapper/src/MacGap/Classes/Constants.h @@ -0,0 +1,7 @@ +// Application constants + +#define kStartPage @"http://127.0.0.1:9993/" + +#define kStartFolder @"." + +#define kWebScriptNamespace @"macgap"
\ No newline at end of file diff --git a/ext/installfiles/mac/mac-ui-macgap1-wrapper/src/MacGap/Classes/ContentView.h b/ext/installfiles/mac/mac-ui-macgap1-wrapper/src/MacGap/Classes/ContentView.h new file mode 100644 index 00000000..65890a5e --- /dev/null +++ b/ext/installfiles/mac/mac-ui-macgap1-wrapper/src/MacGap/Classes/ContentView.h @@ -0,0 +1,15 @@ +#import <Cocoa/Cocoa.h> +#import <WebKit/WebKit.h> + +@class WebViewDelegate; + +@interface ContentView : NSView { + IBOutlet WebView* webView; + WebViewDelegate* delegate; +} + +@property (retain) WebView* webView; +@property (retain) WebViewDelegate* delegate; +@property (strong) IBOutlet NSMenu *mainMenu; + +@end diff --git a/ext/installfiles/mac/mac-ui-macgap1-wrapper/src/MacGap/Classes/ContentView.m b/ext/installfiles/mac/mac-ui-macgap1-wrapper/src/MacGap/Classes/ContentView.m new file mode 100644 index 00000000..6558a191 --- /dev/null +++ b/ext/installfiles/mac/mac-ui-macgap1-wrapper/src/MacGap/Classes/ContentView.m @@ -0,0 +1,68 @@ +#import "ContentView.h" +#import "WebViewDelegate.h" +#import "AppDelegate.h" +#import "JSEventHelper.h" + +@interface WebPreferences (WebPreferencesPrivate) + - (void)_setLocalStorageDatabasePath:(NSString *)path; + - (void) setLocalStorageEnabled: (BOOL) localStorageEnabled; + - (void) setDatabasesEnabled:(BOOL)databasesEnabled; + - (void) setDeveloperExtrasEnabled:(BOOL)developerExtrasEnabled; + - (void) setWebGLEnabled:(BOOL)webGLEnabled; + - (void) setOfflineWebApplicationCacheEnabled:(BOOL)offlineWebApplicationCacheEnabled; +@end + +@implementation ContentView + +@synthesize webView, delegate, mainMenu; + +- (void) awakeFromNib +{ + WebPreferences *webPrefs = [WebPreferences standardPreferences]; + + NSString *cappBundleName = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleName"]; + NSString *applicationSupportFile = [@"~/Library/Application Support/" stringByExpandingTildeInPath]; + NSString *savePath = [NSString pathWithComponents:[NSArray arrayWithObjects:applicationSupportFile, cappBundleName, @"LocalStorage", nil]]; + [webPrefs _setLocalStorageDatabasePath:savePath]; + [webPrefs setLocalStorageEnabled:YES]; + [webPrefs setDatabasesEnabled:YES]; + [webPrefs setDeveloperExtrasEnabled:[[NSUserDefaults standardUserDefaults] boolForKey: @"developer"]]; + [webPrefs setOfflineWebApplicationCacheEnabled:YES]; + [webPrefs setWebGLEnabled:YES]; + + [self.webView setPreferences:webPrefs]; + + NSHTTPCookieStorage *cookieStorage = [NSHTTPCookieStorage + sharedHTTPCookieStorage]; + [cookieStorage setCookieAcceptPolicy:NSHTTPCookieAcceptPolicyAlways]; + + [self.webView setApplicationNameForUserAgent: @"MacGap"]; + + self.delegate = [[WebViewDelegate alloc] initWithMenu:[NSApp mainMenu]]; +// [self.webView setFrameLoadDelegate:self.delegate]; +// [self.webView setUIDelegate:self.delegate]; +// [self.webView setResourceLoadDelegate:self.delegate]; +// [self.webView setDownloadDelegate:self.delegate]; +// [self.webView setPolicyDelegate:self.delegate]; + [self.webView setDrawsBackground:NO]; + [self.webView setShouldCloseWithWindow:NO]; + + [self.webView setGroupName:@"MacGap"]; + +} + +- (void) windowResized:(NSNotification*)notification; +{ + NSWindow* window = (NSWindow*)notification.object; + NSSize size = [window frame].size; + + DebugNSLog(@"window width = %f, window height = %f", size.width, size.height); + + bool isFullScreen = (window.styleMask & NSFullScreenWindowMask) == NSFullScreenWindowMask; + int titleBarHeight = isFullScreen ? 0 : [[Utils sharedInstance] titleBarHeight:window]; + + [self.webView setFrame:NSMakeRect(0, 0, size.width, size.height - titleBarHeight)]; + [JSEventHelper triggerEvent:@"orientationchange" forWebView:self.webView]; +} + +@end diff --git a/ext/installfiles/mac/mac-ui-macgap1-wrapper/src/MacGap/Classes/JSEventHelper.h b/ext/installfiles/mac/mac-ui-macgap1-wrapper/src/MacGap/Classes/JSEventHelper.h new file mode 100644 index 00000000..401f3e39 --- /dev/null +++ b/ext/installfiles/mac/mac-ui-macgap1-wrapper/src/MacGap/Classes/JSEventHelper.h @@ -0,0 +1,20 @@ +// +// Helper.h +// MacGap +// +// Created by Liam Kaufman Simpkins on 12-01-22. +// Copyright (c) 2012 Twitter. All rights reserved. +// + +#import <Foundation/Foundation.h> +#import "WindowController.h" + +@interface JSEventHelper : NSObject + ++ (void) triggerEvent:(NSString *)event forWebView:(WebView *)webView; ++ (void) triggerEvent:(NSString *)event withArgs:(NSDictionary *)args forWebView:(WebView *)webView; ++ (void) triggerEvent:(NSString *)event withArgs:(NSDictionary *)args forObject:(NSString *)objName forWebView:(WebView *)webView; ++ (void) triggerEvent:(NSString *)event forDetail:(NSString *)detail forWebView:(WebView *)webView; ++ (void) triggerEvent:(NSString *)event forDetail:(NSString *)detail forObject:(NSString *)objName forWebView:(WebView *)webView; + +@end diff --git a/ext/installfiles/mac/mac-ui-macgap1-wrapper/src/MacGap/Classes/JSEventHelper.m b/ext/installfiles/mac/mac-ui-macgap1-wrapper/src/MacGap/Classes/JSEventHelper.m new file mode 100644 index 00000000..65406b3c --- /dev/null +++ b/ext/installfiles/mac/mac-ui-macgap1-wrapper/src/MacGap/Classes/JSEventHelper.m @@ -0,0 +1,41 @@ +// +// Helper.m +// MacGap +// +// Created by Liam Kaufman Simpkins on 12-01-22. +// Copyright (c) 2012 Twitter. All rights reserved. +// + +#import "JSEventHelper.h" + +@implementation JSEventHelper + ++ (void) triggerEvent:(NSString *)event forWebView:(WebView *)webView { + [self triggerEvent:event withArgs:[NSMutableDictionary dictionary] forObject:@"document" forWebView:webView]; +} + ++ (void) triggerEvent:(NSString *)event withArgs:(NSDictionary *)args forWebView:(WebView *)webView { + [self triggerEvent:event withArgs:args forObject:@"document" forWebView:webView]; +} + ++ (void) triggerEvent:(NSString *)event withArgs:(NSDictionary *)args forObject:(NSString *)objName forWebView:(WebView *)webView { + + // Convert args Dictionary to JSON. + NSString* jsonString = [[Utils sharedInstance] convertDictionaryToJSON:args]; + + // Create the event JavaScript and run it. + NSString * str = [NSString stringWithFormat:@"var e = document.createEvent('Events'); e.initEvent('%@', true, false); e.data=%@; %@.dispatchEvent(e); ", event, jsonString, objName]; + [webView stringByEvaluatingJavaScriptFromString:str]; +} + ++ (void) triggerEvent:(NSString *)event forDetail:(NSString *)detail forWebView:(WebView *)webView { + [self triggerEvent:event forDetail:detail forObject:@"document" forWebView:webView]; +} + ++ (void) triggerEvent:(NSString *)event forDetail:(NSString *)detail forObject:(NSString *)objName forWebView:(WebView *)webView { + NSString *detailEscaped = [detail stringByAddingPercentEscapesUsingEncoding: NSUTF8StringEncoding]; + NSString *str = [NSString stringWithFormat:@"var e = new CustomEvent('%@', { 'detail': decodeURIComponent(\"%@\") }); %@.dispatchEvent(e); ", event, detailEscaped, objName]; + [webView stringByEvaluatingJavaScriptFromString:str]; +} + +@end diff --git a/ext/installfiles/mac/mac-ui-macgap1-wrapper/src/MacGap/Classes/Utils.h b/ext/installfiles/mac/mac-ui-macgap1-wrapper/src/MacGap/Classes/Utils.h new file mode 100644 index 00000000..f573d881 --- /dev/null +++ b/ext/installfiles/mac/mac-ui-macgap1-wrapper/src/MacGap/Classes/Utils.h @@ -0,0 +1,20 @@ +#import <Foundation/Foundation.h> +#import <Webkit/WebScriptObject.h> + +#define DEG_EPS 0.001 +#define fequal(a,b) (fabs((a) - (b)) < DEG_EPS) +#define fequalzero(a) (fabs(a) < DEG_EPS) + +@class LoadingView; + +@interface Utils : NSObject { +} + +- (float) titleBarHeight:(NSWindow*)aWindow; +- (NSString*) pathForResource:(NSString*)resourcepath; +- (NSString*) convertDictionaryToJSON:(NSDictionary*)dict; +- (NSArray*) convertJSarrayToNSArray:(WebScriptObject*)jsArray; + ++ (Utils*) sharedInstance; + +@end diff --git a/ext/installfiles/mac/mac-ui-macgap1-wrapper/src/MacGap/Classes/Utils.m b/ext/installfiles/mac/mac-ui-macgap1-wrapper/src/MacGap/Classes/Utils.m new file mode 100644 index 00000000..8d85c294 --- /dev/null +++ b/ext/installfiles/mac/mac-ui-macgap1-wrapper/src/MacGap/Classes/Utils.m @@ -0,0 +1,93 @@ +#import "Utils.h" +#import <Webkit/WebScriptObject.h> + +static Utils* sharedInstance = nil; + +@implementation Utils + +- (float) titleBarHeight:(NSWindow*)aWindow +{ + NSRect frame = [aWindow frame]; + NSRect contentRect = [NSWindow contentRectForFrameRect: frame + styleMask: NSTitledWindowMask]; + + return (frame.size.height - contentRect.size.height); +} + +- (NSString*) pathForResource:(NSString*)resourcepath +{ + NSBundle * mainBundle = [NSBundle mainBundle]; + NSMutableArray *directoryParts = [NSMutableArray arrayWithArray:[resourcepath componentsSeparatedByString:@"/"]]; + NSString *filename = [directoryParts lastObject]; + [directoryParts removeLastObject]; + + NSString *directoryStr = [NSString stringWithFormat:@"%@/%@", kStartFolder, [directoryParts componentsJoinedByString:@"/"]]; + return [mainBundle pathForResource:filename + ofType:@"" + inDirectory:directoryStr]; +} + +- (NSString*) convertDictionaryToJSON:(NSDictionary*)dict { + // Convert defaults Dictionary to JSON. + NSError *error; + NSData *jsonData = [NSJSONSerialization + dataWithJSONObject:dict + options:NSJSONWritingPrettyPrinted // Pass 0 if you don't care about the readability of the generated string + error:&error]; + + NSString *jsonString; + if (! jsonData) { + NSLog(@"Got an error converting to JSON: %@", error); + } + else { + jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding]; + } + + return jsonString; +} + +// Convert JavaScript array (arrives as a WebScriptObject) into an NSArray of strings. +- (NSArray*) convertJSarrayToNSArray:(WebScriptObject*)jsArray { + NSInteger count = [[jsArray valueForKey:@"length"] integerValue]; + + NSMutableArray *args = [NSMutableArray array]; + for (int i = 0; i < count; i++) { + NSString *item = [jsArray webScriptValueAtIndex:i]; + if ([item isKindOfClass:[NSString class]]) { + [args addObject:item]; + } + } + + return args; +} + +#pragma mark - +#pragma mark Singleton methods + ++ (Utils*) sharedInstance +{ + @synchronized(self) + { + if (sharedInstance == nil){ + sharedInstance = [[Utils alloc] init]; + } + } + return sharedInstance; +} + ++ (id) allocWithZone:(NSZone *)zone { + @synchronized(self) { + if (sharedInstance == nil) { + sharedInstance = [super allocWithZone:zone]; + return sharedInstance; // assignment and return on first allocation + } + } + return nil; // on subsequent allocation attempts return nil +} + +- (id) copyWithZone:(NSZone *)zone +{ + return self; +} + +@end
\ No newline at end of file diff --git a/ext/installfiles/mac/mac-ui-macgap1-wrapper/src/MacGap/Classes/WebViewDelegate.h b/ext/installfiles/mac/mac-ui-macgap1-wrapper/src/MacGap/Classes/WebViewDelegate.h new file mode 100644 index 00000000..49c6da6b --- /dev/null +++ b/ext/installfiles/mac/mac-ui-macgap1-wrapper/src/MacGap/Classes/WebViewDelegate.h @@ -0,0 +1,49 @@ +#import <Cocoa/Cocoa.h> +#import <WebKit/WebKit.h> + +@class Sound; +@class Dock; +@class Growl; +@class Notice; +@class Path; +@class App; +@class Window; +@class Clipboard; +@class Fonts; +@class MenuProxy; +@class UserDefaults; + +@class WindowController; + +@interface WebViewDelegate : NSObject { + Sound* sound; + Dock* dock; + Growl* growl; + Notice* notice; + Path* path; + App* app; + Window* window; + Clipboard* clipboard; + Fonts* fonts; + NSMenu *mainMenu; + UserDefaults* userDefaults; +} + + + +@property (nonatomic, retain) Sound* sound; +@property (nonatomic, retain) Dock* dock; +@property (nonatomic, retain) Growl* growl; +@property (nonatomic, retain) Notice* notice; +@property (nonatomic, retain) Path* path; +@property (nonatomic, retain) App* app; +@property (nonatomic, retain) Window* window; +@property (nonatomic, retain) Clipboard* clipboard; +@property (nonatomic, retain) Fonts* fonts; +@property (nonatomic, retain) MenuProxy* menu; +@property (nonatomic, retain) UserDefaults* userDefaults; + +@property (nonatomic, retain) WindowController *requestedWindow; + +- (id) initWithMenu:(NSMenu*)menu; +@end diff --git a/ext/installfiles/mac/mac-ui-macgap1-wrapper/src/MacGap/Classes/WebViewDelegate.m b/ext/installfiles/mac/mac-ui-macgap1-wrapper/src/MacGap/Classes/WebViewDelegate.m new file mode 100644 index 00000000..50578018 --- /dev/null +++ b/ext/installfiles/mac/mac-ui-macgap1-wrapper/src/MacGap/Classes/WebViewDelegate.m @@ -0,0 +1,206 @@ +#import "WebViewDelegate.h" +#import "Sound.h" +#import "Dock.h" +#import "Notice.h" +#import "Path.h" +#import "App.h" +#import "Window.h" +#import "WindowController.h" +#import "Clipboard.h" +#import "Fonts.h" +#import "MenuProxy.h" +#import "UserDefaults.h" + +@implementation WebViewDelegate + +@synthesize sound; +@synthesize dock; +@synthesize growl; +@synthesize notice; +@synthesize path; +@synthesize app; +@synthesize window; +@synthesize requestedWindow; +@synthesize clipboard; +@synthesize fonts; +@synthesize menu; +@synthesize userDefaults; + +- (id) initWithMenu:(NSMenu*)aMenu +{ + self = [super init]; + if (!self) + return nil; + + mainMenu = aMenu; + return self; +} + +- (void) webView:(WebView*)webView didClearWindowObject:(WebScriptObject*)windowScriptObject forFrame:(WebFrame *)frame +{ + JSContextRef context = [frame globalContext]; + if (self.sound == nil) { self.sound = [[Sound alloc] initWithContext:context]; } + if (self.dock == nil) { self.dock = [Dock new]; } + if (self.path == nil) { self.path = [Path new]; } + if (self.clipboard == nil) { self.clipboard = [Clipboard new]; } + if (self.fonts == nil) { self.fonts = [Fonts new]; } + + if (self.notice == nil && [Notice available] == YES) { + self.notice = [[Notice alloc] initWithWebView:webView]; + } + + if (self.app == nil) { + self.app = [[App alloc] initWithWebView:webView]; + } + + if (self.window == nil) { + self.window = [[Window alloc] initWithWebView:webView]; + } + + if (self.menu == nil) { + self.menu = [MenuProxy proxyWithContext:context andMenu:mainMenu]; + } + + if (self.userDefaults == nil) { + self.userDefaults = [[UserDefaults alloc] initWithWebView:webView]; + } + + [windowScriptObject setValue:self forKey:kWebScriptNamespace]; +} + + +- (void)webView:(WebView *)sender runOpenPanelForFileButtonWithResultListener:(id < WebOpenPanelResultListener >)resultListener allowMultipleFiles:(BOOL)allowMultipleFiles{ + + NSOpenPanel * openDlg = [NSOpenPanel openPanel]; + + [openDlg setCanChooseFiles:YES]; + [openDlg setCanChooseDirectories:NO]; + + [openDlg beginWithCompletionHandler:^(NSInteger result){ + if (result == NSFileHandlingPanelOKButton) { + NSArray * files = [[openDlg URLs] valueForKey: @"relativePath"]; + [resultListener chooseFilenames: files]; + } else { + [resultListener cancel]; + } + }]; +} + +- (void) webView:(WebView*)webView addMessageToConsole:(NSDictionary*)message +{ + if (![message isKindOfClass:[NSDictionary class]]) { + return; + } + + NSLog(@"JavaScript console: %@:%@: %@", + [[message objectForKey:@"sourceURL"] lastPathComponent], // could be nil + [message objectForKey:@"lineNumber"], + [message objectForKey:@"message"]); +} + +- (void)webView:(WebView *)sender runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WebFrame *)frame +{ + NSAlert *alert = [[NSAlert alloc] init]; + [alert addButtonWithTitle:@"OK"]; + [alert setMessageText:message]; + [alert setAlertStyle:NSWarningAlertStyle]; + [alert runModal]; +} + +- (BOOL)webView:(WebView *)sender runJavaScriptConfirmPanelWithMessage:(NSString *)message initiatedByFrame:(WebFrame *)frame +{ + NSAlert *alert = [[NSAlert alloc] init]; + [alert addButtonWithTitle:@"Yes"]; + [alert addButtonWithTitle:@"No"]; + [alert setMessageText:message]; + [alert setAlertStyle:NSWarningAlertStyle]; + + if ([alert runModal] == NSAlertFirstButtonReturn) + return YES; + else + return NO; +} + +/* + By default the size of a database is set to 0 [1]. When a database is being created + it calls this delegate method to get an increase in quota size - or call an error. + PS this method is defined in WebUIDelegatePrivate and may make it difficult, but + not impossible [2], to get an app accepted into the mac app store. + + Further reading: + [1] http://stackoverflow.com/questions/353808/implementing-a-webview-database-quota-delegate + [2] http://stackoverflow.com/questions/4527905/how-do-i-enable-local-storage-in-my-webkit-based-application/4608549#4608549 + */ +- (void)webView:(WebView *)sender frame:(WebFrame *)frame exceededDatabaseQuotaForSecurityOrigin:(id) origin database:(NSString *)databaseIdentifier +{ + static const unsigned long long defaultQuota = 5 * 1024 * 1024; + if ([origin respondsToSelector: @selector(setQuota:)]) { + [origin performSelector:@selector(setQuota:) withObject:[NSNumber numberWithLongLong: defaultQuota]]; + } else { + NSLog(@"could not increase quota for %lld", defaultQuota); + } +} + +- (NSArray *)webView:(WebView *)sender contextMenuItemsForElement:(NSDictionary *)element defaultMenuItems:(NSArray *)defaultMenuItems +{ + NSMutableArray *webViewMenuItems = [defaultMenuItems mutableCopy]; + + if (webViewMenuItems) + { + NSEnumerator *itemEnumerator = [defaultMenuItems objectEnumerator]; + NSMenuItem *menuItem = nil; + while ((menuItem = [itemEnumerator nextObject])) + { + NSInteger tag = [menuItem tag]; + + switch (tag) + { + case WebMenuItemTagOpenLinkInNewWindow: + case WebMenuItemTagDownloadLinkToDisk: + case WebMenuItemTagCopyLinkToClipboard: + case WebMenuItemTagOpenImageInNewWindow: + case WebMenuItemTagDownloadImageToDisk: + case WebMenuItemTagCopyImageToClipboard: + case WebMenuItemTagOpenFrameInNewWindow: + case WebMenuItemTagGoBack: + case WebMenuItemTagGoForward: + case WebMenuItemTagStop: + case WebMenuItemTagOpenWithDefaultApplication: + case WebMenuItemTagReload: + [webViewMenuItems removeObjectIdenticalTo: menuItem]; + } + } + } + + return webViewMenuItems; +} + +- (WebView *)webView:(WebView *)sender createWebViewWithRequest:(NSURLRequest *)request{ + requestedWindow = [[WindowController alloc] initWithRequest:request]; + return requestedWindow.contentView.webView; +} + +- (void)webViewShow:(WebView *)sender{ + [requestedWindow showWindow:sender]; +} + +- (void)webView:(WebView *)webView decidePolicyForNewWindowAction:(NSDictionary *)actionInformation request:(NSURLRequest *)request newFrameName:(NSString *)frameName decisionListener:(id < WebPolicyDecisionListener >)listener +{ + [[NSWorkspace sharedWorkspace] openURL:[request URL]]; + [listener ignore]; +} + +#pragma mark WebScripting protocol + ++ (BOOL) isSelectorExcludedFromWebScript:(SEL)selector +{ + return YES; +} + ++ (BOOL) isKeyExcludedFromWebScript:(const char*)name +{ + return NO; +} + + +@end diff --git a/ext/installfiles/mac/mac-ui-macgap1-wrapper/src/MacGap/Classes/Window.h b/ext/installfiles/mac/mac-ui-macgap1-wrapper/src/MacGap/Classes/Window.h new file mode 100644 index 00000000..f721376e --- /dev/null +++ b/ext/installfiles/mac/mac-ui-macgap1-wrapper/src/MacGap/Classes/Window.h @@ -0,0 +1,23 @@ +#import <Foundation/Foundation.h> + +#import "WindowController.h" + +@interface Window : NSObject{ + CGRect _oldRestoreFrame; +} + +@property (retain, nonatomic) WindowController *windowController; +@property (nonatomic, retain) WebView *webView; + +- (id) initWithWebView:(WebView *)view; +- (void) open:(NSDictionary *)properties; +- (void) move:(NSDictionary *)properties; +- (void) resize:(NSDictionary *) properties; +- (Boolean) isMaximized; +- (CGFloat) getX; +- (CGFloat) getY; +- (void) maximize; +- (void) restore; +- (void) toggleFullscreen; + +@end diff --git a/ext/installfiles/mac/mac-ui-macgap1-wrapper/src/MacGap/Classes/Window.m b/ext/installfiles/mac/mac-ui-macgap1-wrapper/src/MacGap/Classes/Window.m new file mode 100644 index 00000000..2444f62e --- /dev/null +++ b/ext/installfiles/mac/mac-ui-macgap1-wrapper/src/MacGap/Classes/Window.m @@ -0,0 +1,94 @@ +#import "Window.h" + +@implementation Window + +@synthesize windowController, webView; + +- (id) initWithWebView:(WebView*)view +{ + if(self = [super init]) { + self.webView = view; + } + return self; +} + +- (void) open:(NSDictionary *)properties +{ + self.windowController = [[WindowController alloc] initWithURL:[properties valueForKey:@"url"]]; + [self.windowController showWindow: [NSApplication sharedApplication].delegate]; + [self.windowController.window makeKeyWindow]; +} + +- (void) minimize { + [[NSApp mainWindow] miniaturize:[NSApp mainWindow]]; +} + +- (void) toggleFullscreen { + [[NSApp mainWindow] toggleFullScreen:[NSApp mainWindow]]; +} + +- (void) maximize { + CGRect a = [NSApp mainWindow].frame; + _oldRestoreFrame = CGRectMake(a.origin.x, a.origin.y, a.size.width, a.size.height); + [[NSApp mainWindow] setFrame:[[NSScreen mainScreen] visibleFrame] display:YES]; +} + +- (Boolean) isMaximized { + NSRect a = [NSApp mainWindow].frame; + NSRect b = [[NSScreen mainScreen] visibleFrame]; + return a.origin.x == b.origin.x && a.origin.y == b.origin.y && a.size.width == b.size.width && a.size.height == b.size.height; +} + +- (CGFloat) getX { + NSRect frame = [self.webView window].frame; + return frame.origin.x; +} + +- (CGFloat) getY { + NSRect frame = [self.webView window].frame; + return frame.origin.y; +} + +- (void) move:(NSDictionary *)properties +{ + NSRect frame = [self.webView window].frame; + frame.origin.x = [[properties valueForKey:@"x"] doubleValue]; + frame.origin.y = [[properties valueForKey:@"y"] doubleValue]; + [[self.webView window] setFrame:frame display:YES]; + +} + +- (void) resize:(NSDictionary *) properties +{ + NSRect frame = [self.webView window].frame; + frame.size.width = [[properties valueForKey:@"width"] doubleValue]; + frame.size.height = [[properties valueForKey:@"height"] doubleValue]; + [[self.webView window] setFrame:frame display:YES]; +} + + ++ (BOOL) isSelectorExcludedFromWebScript:(SEL)selector +{ + return NO; +} + ++ (NSString*) webScriptNameForSelector:(SEL)selector{ + id result = nil; + + if (selector == @selector(open:)) { + result = @"open"; + }else if (selector == @selector(move:)){ + result = @"move"; + }else if (selector == @selector(resize:)){ + result = @"resize"; + } + + return result; +} + ++ (BOOL) isKeyExcludedFromWebScript:(const char*)name +{ + return YES; +} + +@end |