├── .gitignore
├── MacGap
├── en.lproj
│ ├── InfoPlist.strings
│ └── Credits.rtf
├── Classes
│ ├── Utils.h
│ ├── DraggableView.h
│ ├── Commands
│ │ ├── Clipboard.h
│ │ ├── Dock.h
│ │ ├── Notify.h
│ │ ├── Dialog.h
│ │ ├── Sound.h
│ │ ├── File.h
│ │ ├── Fonts.h
│ │ ├── StatusItem.h
│ │ ├── MacGap.h
│ │ ├── Defaults.h
│ │ ├── Dock.m
│ │ ├── Command.h
│ │ ├── Task.h
│ │ ├── Clipboard.m
│ │ ├── MenuItem.h
│ │ ├── Window.h
│ │ ├── Event.h
│ │ ├── Fonts.m
│ │ ├── App.h
│ │ ├── Menu.h
│ │ ├── Event.m
│ │ ├── Command.m
│ │ ├── Sound.m
│ │ ├── Notify.m
│ │ ├── StatusItem.m
│ │ ├── MenuItem.m
│ │ ├── File.m
│ │ ├── Dialog.m
│ │ ├── Task.m
│ │ ├── Defaults.m
│ │ ├── App.m
│ │ ├── Menu.m
│ │ └── Window.m
│ ├── Utils.m
│ ├── WebViewDelegate.h
│ ├── DraggableView.m
│ ├── WindowController.h
│ ├── NotificationProvider.h
│ ├── WebNotification.h
│ ├── NotificationProvider.m
│ ├── WebViewDelegate.m
│ └── WindowController.m
├── main.m
├── Constants.h
├── AppDelegate.h
├── Categories
│ ├── JSON.h
│ ├── NSData+Base64.h
│ ├── JSON.m
│ └── NSData+Base64.m
├── MG-Prefix.pch
├── MG-Info.plist
├── AppDelegate.m
├── Images.xcassets
│ └── AppIcon.appiconset
│ │ └── Contents.json
└── Base.lproj
│ ├── MainWindow.xib
│ └── MainMenu.xib
├── MG.xcodeproj
├── project.xcworkspace
│ ├── contents.xcworkspacedata
│ ├── xcuserdata
│ │ ├── Tim.xcuserdatad
│ │ │ ├── UserInterfaceState.xcuserstate
│ │ │ └── WorkspaceSettings.xcsettings
│ │ └── jeffh.xcuserdatad
│ │ │ └── UserInterfaceState.xcuserstate
│ └── xcshareddata
│ │ ├── IDEWorkspaceChecks.plist
│ │ └── MG.xccheckout
├── xcuserdata
│ ├── jeffh.xcuserdatad
│ │ └── xcschemes
│ │ │ └── xcschememanagement.plist
│ └── Tim.xcuserdatad
│ │ ├── xcschemes
│ │ ├── xcschememanagement.plist
│ │ └── MG.xcscheme
│ │ └── xcdebugger
│ │ └── Breakpoints_v2.xcbkptlist
└── project.pbxproj
├── README.md
├── public
├── index.html
└── config.json
└── LICENSE
/.gitignore:
--------------------------------------------------------------------------------
1 | public/status.png
2 | .DS_Store
--------------------------------------------------------------------------------
/MacGap/en.lproj/InfoPlist.strings:
--------------------------------------------------------------------------------
1 | /* Localized versions of Info.plist keys */
2 |
3 |
--------------------------------------------------------------------------------
/MG.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/MG.xcodeproj/project.xcworkspace/xcuserdata/Tim.xcuserdatad/UserInterfaceState.xcuserstate:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MacGapProject/MacGap2/HEAD/MG.xcodeproj/project.xcworkspace/xcuserdata/Tim.xcuserdatad/UserInterfaceState.xcuserstate
--------------------------------------------------------------------------------
/MG.xcodeproj/project.xcworkspace/xcuserdata/jeffh.xcuserdatad/UserInterfaceState.xcuserstate:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MacGapProject/MacGap2/HEAD/MG.xcodeproj/project.xcworkspace/xcuserdata/jeffh.xcuserdatad/UserInterfaceState.xcuserstate
--------------------------------------------------------------------------------
/MacGap/Classes/Utils.h:
--------------------------------------------------------------------------------
1 | //
2 | // Utils.h
3 | // MG
4 | //
5 | // Created by Tim Debo on 5/28/14.
6 | //
7 | //
8 |
9 | #import
10 |
11 | NSString *pathForResource(NSString* resourcePath);
12 |
13 |
14 |
--------------------------------------------------------------------------------
/MacGap/main.m:
--------------------------------------------------------------------------------
1 | //
2 | // main.m
3 | // MG
4 | //
5 | // Created by Tim Debo on 5/19/14.
6 | //
7 | //
8 |
9 | #import
10 |
11 | int main(int argc, const char * argv[])
12 | {
13 | return NSApplicationMain(argc, argv);
14 | }
15 |
--------------------------------------------------------------------------------
/MacGap/Classes/DraggableView.h:
--------------------------------------------------------------------------------
1 | //
2 | // DraggableView.h
3 | // MG
4 | //
5 | // Created by Daniel Liljeberg on 2018-01-24.
6 | //
7 |
8 | #import
9 |
10 | @interface DraggableView : NSView {
11 | NSPoint initialLocation;
12 | }
13 | @end
14 |
--------------------------------------------------------------------------------
/MacGap/Constants.h:
--------------------------------------------------------------------------------
1 | //
2 | // Constants.h
3 | // MG
4 | //
5 | // Created by Tim Debo on 5/20/14.
6 | //
7 | //
8 |
9 | // Application constants
10 |
11 | #define kStartPage @"public/index.html"
12 | #define kStartFolder @"."
13 | #define kWebScriptNamespace @"MacGap"
14 |
--------------------------------------------------------------------------------
/MG.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | [](https://gitter.im/MacGapProject/MacGap2)
2 |
3 | # Welcome to MacGap 2.
4 |
5 | For usage notes and API documentation, visit https://macgapproject.github.io/documentation/.
6 |
7 | To submit an issue or ask for help, go to the GitHub issue queue at https://github.com/MacGapProject/MacGap2/issues
8 |
--------------------------------------------------------------------------------
/MacGap/Classes/Commands/Clipboard.h:
--------------------------------------------------------------------------------
1 | //
2 | // Clipboard.h
3 | // MG
4 | //
5 | // Created by Tim Debo on 5/28/14.
6 | //
7 | //
8 |
9 | #import "Command.h"
10 | @protocol ClipboardExports
11 | JSExportAs(copy, - (void) copy:(NSString*)text);
12 | - (NSString *) paste;
13 | @end
14 |
15 | @interface Clipboard : Command
16 |
17 | @end
18 |
--------------------------------------------------------------------------------
/MacGap/AppDelegate.h:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.h
3 | // MG
4 | //
5 | // Created by Tim Debo on 5/19/14.
6 | //
7 | //
8 |
9 | #import
10 |
11 | @class WindowController;
12 |
13 | @interface AppDelegate : NSObject
14 |
15 | @property (retain, nonatomic) WindowController *windowController;
16 |
17 | @end
18 |
--------------------------------------------------------------------------------
/MacGap/Categories/JSON.h:
--------------------------------------------------------------------------------
1 | //
2 | // JSON.h
3 | // MacGap
4 | //
5 | // Created by Tim Debo on 5/17/14.
6 | // Copyright (c) 2014 Raw Creative Studios LLC. All rights reserved.
7 | //
8 |
9 | @interface NSArray (MGJSON)
10 | - (NSString*)JSONString;
11 | @end
12 |
13 | @interface NSDictionary (MGJSON)
14 | - (NSString*)JSONString;
15 | @end
16 |
17 | @interface NSString (MGJSON)
18 | - (id)JSONObject;
19 | @end
20 |
--------------------------------------------------------------------------------
/MacGap/Classes/Commands/Dock.h:
--------------------------------------------------------------------------------
1 | //
2 | // Dock.h
3 | // MG
4 | //
5 | // Created by Tim Debo on 5/22/14.
6 | //
7 | //
8 | #import
9 | #import "Command.h"
10 |
11 |
12 | @protocol DockExports
13 |
14 | @property (readonly) NSString* badge;
15 | - (void) addBadge: (NSString*) badge;
16 | - (void) removeBadge;
17 | @end
18 |
19 | @interface Dock : Command
20 |
21 |
22 | @end
23 |
--------------------------------------------------------------------------------
/MG.xcodeproj/project.xcworkspace/xcuserdata/Tim.xcuserdatad/WorkspaceSettings.xcsettings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | HasAskedToTakeAutomaticSnapshotBeforeSignificantChanges
6 |
7 | SnapshotAutomaticallyBeforeSignificantChanges
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/MG.xcodeproj/xcuserdata/jeffh.xcuserdatad/xcschemes/xcschememanagement.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | SchemeUserState
6 |
7 | MG.xcscheme_^#shared#^_
8 |
9 | orderHint
10 | 0
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/MacGap/Classes/Commands/Notify.h:
--------------------------------------------------------------------------------
1 | //
2 | // Notify.h
3 | // MG
4 | //
5 | // Created by Tim Debo on 5/27/14.
6 | //
7 | //
8 |
9 | #import "Command.h"
10 | @protocol NotifyExports
11 |
12 | - (void) notify:(NSDictionary*)aNotification;
13 | - (void) close:(NSString*)notificationId;
14 |
15 | @property (readonly) NSMutableArray* notifications;
16 | @end
17 |
18 | @interface Notify : Command
19 | + (BOOL) available;
20 | @end
21 |
--------------------------------------------------------------------------------
/MacGap/Classes/Commands/Dialog.h:
--------------------------------------------------------------------------------
1 | //
2 | // Dialog.h
3 | // MG
4 | //
5 | // Created by Tim Debo on 5/27/14.
6 | //
7 | //
8 |
9 | #import
10 | #import "Command.h"
11 | #import
12 |
13 | @protocol DialogExports
14 | - (void) openDialog:(JSValue *)args;
15 | - (void) saveDialog: (JSValue*)args;
16 | @end
17 |
18 | @interface Dialog : Command
19 |
20 | @property (assign) JSContext* context;
21 |
22 | @end
23 |
--------------------------------------------------------------------------------
/MacGap/Classes/Commands/Sound.h:
--------------------------------------------------------------------------------
1 | //
2 | // Sound.h
3 | // MG
4 | //
5 | // Created by Tim Debo on 5/31/14.
6 | //
7 | //
8 |
9 | #import "Command.h"
10 |
11 | @protocol SoundExports
12 | JSExportAs(play, - (void) play:(NSString*)file onComplete:(JSValue*)callback);
13 | JSExportAs(playSystem, - (void) playSystem:(NSString*)name onComplete:(JSValue*)callback);
14 | @property (retain) JSValue* cb;
15 | @end
16 |
17 | @interface Sound : Command
18 |
19 | @end
20 |
--------------------------------------------------------------------------------
/MacGap/Classes/Commands/File.h:
--------------------------------------------------------------------------------
1 | //
2 | // File.h
3 | // MG
4 | //
5 | // Created by Tim Debo on 6/8/14.
6 | //
7 | //
8 |
9 | #import "Command.h"
10 | @protocol FileExports
11 |
12 | JSExportAs(write, - (void) writeFile:(NSString*)filePath withData: (JSValue*) data andType: (NSString*) type );
13 | JSExportAs(read, - (JSValue*) readFile:(NSString*)filePath ofType: (NSString*) type);
14 | - (BOOL) exists:(NSString*)filePath;
15 |
16 | @end
17 |
18 | @interface File : Command
19 |
20 | @end
21 |
--------------------------------------------------------------------------------
/MacGap/Classes/Commands/Fonts.h:
--------------------------------------------------------------------------------
1 | //
2 | // Fonts.h
3 | // MG
4 | //
5 | // Created by Tim Debo on 5/27/14.
6 | //
7 | //
8 |
9 | #import "Command.h"
10 | @protocol FontsExport
11 | - (JSValue*) availableFonts;
12 | - (JSValue*) availableFontFamilies;
13 | - (JSValue*) availableMembersOfFontFamily:(NSString*)fontFamily;
14 | JSExportAs(getLineHeight, - (CGFloat) defaultLineHeightForFont:(NSString *)theFontName ofSize:(CGFloat)theFontSize);
15 | @end
16 |
17 | @interface Fonts : Command
18 |
19 | @end
20 |
--------------------------------------------------------------------------------
/MacGap/Classes/Commands/StatusItem.h:
--------------------------------------------------------------------------------
1 | //
2 | // StatusItem.h
3 | // MG
4 | //
5 | // Created by Tim Debo on 5/28/14.
6 | //
7 | //
8 |
9 | #import "Command.h"
10 | @protocol StatusItemExports
11 | JSExportAs(create, - (void) createItem: (NSDictionary*) props callback: (JSValue*) cb);
12 | @property (readwrite) JSValue *menu;
13 | @property (readwrite) NSString *title;
14 | @end
15 |
16 | @interface StatusItem : Command
17 | @property (nonatomic, retain) NSStatusItem *statusItem;
18 | - (void) itemClicked: (id) sender;
19 | @end
20 |
--------------------------------------------------------------------------------
/MacGap/en.lproj/Credits.rtf:
--------------------------------------------------------------------------------
1 | {\rtf0\ansi{\fonttbl\f0\fswiss Helvetica;}
2 | {\colortbl;\red255\green255\blue255;}
3 | \paperw9840\paperh8400
4 | \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\ql\qnatural
5 |
6 | \f0\b\fs24 \cf0 Engineering:
7 | \b0 \
8 | Some people\
9 | \
10 |
11 | \b Human Interface Design:
12 | \b0 \
13 | Some other people\
14 | \
15 |
16 | \b Testing:
17 | \b0 \
18 | Hopefully not nobody\
19 | \
20 |
21 | \b Documentation:
22 | \b0 \
23 | Whoever\
24 | \
25 |
26 | \b With special thanks to:
27 | \b0 \
28 | Mom\
29 | }
30 |
--------------------------------------------------------------------------------
/MacGap/Classes/Commands/MacGap.h:
--------------------------------------------------------------------------------
1 | //
2 | // MacGap.h
3 | // MG
4 | //
5 | // Created by Tim Debo on 5/21/14.
6 | //
7 | //
8 |
9 |
10 | #import
11 | #import "WindowController.h"
12 | #import "WebViewDelegate.h"
13 | #import "Command.h"
14 | #import "App.h"
15 | #import "Window.h"
16 | #import "Menu.h"
17 | #import "MenuItem.h"
18 | #import "Dialog.h"
19 | #import "Dock.h"
20 | #import "Task.h"
21 | #import "Notify.h"
22 | #import "Fonts.h"
23 | #import "StatusItem.h"
24 | #import "Event.h"
25 |
26 |
27 | #import "NSData+Base64.h"
28 | #import "JSON.h"
29 |
30 |
31 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/MacGap/Classes/Commands/Defaults.h:
--------------------------------------------------------------------------------
1 | //
2 | // Defaults.h
3 | // MG
4 | //
5 | // Created by Tim Debo on 6/1/14.
6 | //
7 | //
8 |
9 | #import "Command.h"
10 | @protocol DefaultExports
11 | @property (readonly) NSDictionary* defaults;
12 | JSExportAs(get, - (JSValue*) get: (NSString*) key ofType: (NSString*) type);
13 | JSExportAs(set, - (void) setKey:(NSString*)key withValue: (JSValue*) value ofType: (NSString*) type);
14 | - (void) remove: (NSString*) key;
15 | @end
16 |
17 | @interface Defaults : Command
18 |
19 | - (void)defaultsChanged:(NSNotification *)notification;
20 | - (NSDictionary*) defaultsDictionary;
21 |
22 |
23 | @end
24 |
--------------------------------------------------------------------------------
/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | MacGap
5 |
6 |
7 |
25 |
26 |
27 |
28 |
29 |
31 |
32 | MacGap
33 |
34 |
--------------------------------------------------------------------------------
/MacGap/MG-Prefix.pch:
--------------------------------------------------------------------------------
1 | //
2 | // Prefix header
3 | //
4 | // The contents of this file are implicitly included at the beginning of every source file.
5 | //
6 |
7 | #ifdef __OBJC__
8 |
9 | #ifdef _DEBUG
10 | #define DebugNSLog(format, ...) NSLog(format, ## __VA_ARGS__)
11 | #define DLog(fmt, ...) NSLog((@"%s [Line %d] " fmt), __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__)
12 |
13 | #else
14 | #define DebugNSLog(format, ...)
15 | #define DLog(...)
16 | #endif
17 | #define ALog(fmt, ...) NSLog((@"%s [Line %d] " fmt), __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__)
18 |
19 | #import
20 | #import "Constants.h"
21 | #import "Utils.h"
22 |
23 |
24 | #endif
25 |
--------------------------------------------------------------------------------
/MacGap/Classes/Commands/Dock.m:
--------------------------------------------------------------------------------
1 | //
2 | // Dock.m
3 | // MG
4 | //
5 | // Created by Tim Debo on 5/22/14.
6 | //
7 | //
8 |
9 | #import "Dock.h"
10 |
11 |
12 | @implementation Dock
13 |
14 |
15 | - (JSValue*) badge
16 | {
17 | NSDockTile *tile = [[NSApplication sharedApplication] dockTile];
18 | return [JSValue valueWithObject:[tile badgeLabel] inContext: JSContext.currentContext];
19 | }
20 |
21 | - (void) addBadge: (NSString*) badge
22 | {
23 | NSDockTile *tile = [[NSApplication sharedApplication] dockTile];
24 | [tile setBadgeLabel:badge];
25 | }
26 |
27 | - (void) removeBadge
28 | {
29 | NSDockTile *tile = [[NSApplication sharedApplication] dockTile];
30 | [tile setBadgeLabel:nil];
31 | }
32 |
33 | @end
34 |
--------------------------------------------------------------------------------
/MG.xcodeproj/xcuserdata/Tim.xcuserdatad/xcschemes/xcschememanagement.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | SchemeUserState
6 |
7 | MG.xcscheme
8 |
9 | orderHint
10 | 0
11 |
12 |
13 | SuppressBuildableAutocreation
14 |
15 | 2237E645192B0177001E1393
16 |
17 | primary
18 |
19 |
20 | 2237E666192B0177001E1393
21 |
22 | primary
23 |
24 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/MacGap/Categories/NSData+Base64.h:
--------------------------------------------------------------------------------
1 | //
2 | // NSData+Base64.h
3 | // MG
4 | //
5 | // Created by Tim Debo on 5/20/14.
6 | //
7 | //
8 |
9 | #import
10 |
11 | void *NewBase64Decode(
12 | const char* inputBuffer,
13 | size_t length,
14 | size_t * outputLength);
15 |
16 | char *NewBase64Encode(
17 | const void* inputBuffer,
18 | size_t length,
19 | bool separateLines,
20 | size_t * outputLength);
21 |
22 | @interface NSData (Base64)
23 |
24 | + (NSData*)dataFromBase64String:(NSString*)aString;
25 | - (NSString*)base64EncodedString;
26 |
27 | @end
28 |
--------------------------------------------------------------------------------
/MacGap/Classes/Utils.m:
--------------------------------------------------------------------------------
1 | //
2 | // Utils.m
3 | // MG
4 | //
5 | // Created by Tim Debo on 5/28/14.
6 | //
7 | //
8 |
9 | #import "Utils.h"
10 |
11 | NSString *pathForResource(NSString* resourcePath) {
12 | NSBundle * mainBundle = [NSBundle mainBundle];
13 | NSMutableArray *directoryParts = [NSMutableArray arrayWithArray:[resourcePath componentsSeparatedByString:@"/"]];
14 | NSString *filename = [directoryParts lastObject];
15 | [directoryParts removeLastObject];
16 |
17 | NSString *directoryStr = [NSString stringWithFormat:@"%@/%@", kStartFolder, [directoryParts componentsJoinedByString:@"/"]];
18 | return [mainBundle pathForResource:filename
19 | ofType:@""
20 | inDirectory:directoryStr];
21 | }
22 |
23 |
24 |
--------------------------------------------------------------------------------
/MacGap/Classes/Commands/Command.h:
--------------------------------------------------------------------------------
1 | //
2 | // Command.h
3 | // MG
4 | //
5 | // Created by Tim Debo on 5/23/14.
6 | //
7 | //
8 |
9 | #import
10 | #import
11 |
12 |
13 | @class WindowController, WebView;
14 |
15 | @interface Command : NSObject
16 | {
17 | JSContextRef jsContext;
18 | }
19 | + (JSValue *)makeConstructor:(id)block inContext:(JSContext *)context;
20 | + (JSValue *)constructor;
21 | - (NSString*) exportName;
22 | - (void) initializePlugin;
23 | - (id) initWithWindowController: (WindowController*)aWindowController;
24 | - (id) initWithContext:(JSContext*)aContext;
25 | @property (nonatomic, weak) WebView* webView;
26 | @property (nonatomic, weak) WindowController* windowController;
27 | @end
28 |
--------------------------------------------------------------------------------
/MacGap/Classes/WebViewDelegate.h:
--------------------------------------------------------------------------------
1 | //
2 | // WebViewDelegate.h
3 | // MG
4 | //
5 | // Created by Tim Debo on 5/20/14.
6 | //
7 | //
8 |
9 | #import
10 | #import
11 |
12 | @class WindowController, Window, Menu, App;
13 |
14 | @interface WebViewDelegate : NSObject {
15 | NSMenu *mainMenu;
16 | Window* window;
17 | Menu* menu;
18 | App* app;
19 | }
20 |
21 | @property (nonatomic, retain) WindowController *windowController;
22 | @property (nonatomic, retain) Window* window;
23 | @property (nonatomic, retain) Menu* menu;
24 | @property (nonatomic, retain) App* app;
25 | - (id) initWithMenu:(NSMenu*)menu;
26 |
27 | @end
28 |
--------------------------------------------------------------------------------
/MacGap/Classes/Commands/Task.h:
--------------------------------------------------------------------------------
1 | //
2 | // Task.h
3 | // MG
4 | //
5 | // Created by Tim Debo on 5/27/14.
6 | //
7 | //
8 |
9 | #import "Command.h"
10 |
11 | @protocol TaskExports
12 |
13 | JSExportAs(create, - (JSValue*) createTask: (NSString*) path withCallback: (JSValue*) aCallback);
14 | - (void) launch;
15 | - (void) terminate;
16 |
17 | @property (readonly) BOOL isRunning;
18 | @property (readwrite) BOOL waitUntilExit;
19 | @property (readwrite) BOOL pipeOutput;
20 | @property (readwrite) NSArray* arguments;
21 | @property (readwrite) NSDictionary* environment;
22 | @property (readwrite) NSString* currentDirectoryPath;
23 | @property (strong) JSManagedValue* callback;
24 | @end
25 |
26 | @interface Task : Command
27 | @property (strong) NSTask* task;
28 | @property (strong) NSPipe *outputPipe;
29 | @property (strong) NSFileHandle *outFile;
30 | @end
31 |
--------------------------------------------------------------------------------
/MG.xcodeproj/xcuserdata/Tim.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
8 |
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/MacGap/Classes/Commands/Clipboard.m:
--------------------------------------------------------------------------------
1 | //
2 | // Clipboard.m
3 | // MG
4 | //
5 | // Created by Tim Debo on 5/28/14.
6 | //
7 | //
8 |
9 | #import "Clipboard.h"
10 |
11 | @implementation Clipboard
12 |
13 | - (void) copy:(NSString*)text {
14 | [[NSPasteboard generalPasteboard] clearContents];
15 | [[NSPasteboard generalPasteboard] setString:text forType:NSStringPboardType];
16 | }
17 |
18 | - (NSString *) paste {
19 | NSPasteboard *pasteboard = [NSPasteboard generalPasteboard];
20 | NSArray *classArray = [NSArray arrayWithObject:[NSString class]];
21 | NSDictionary *options = [NSDictionary dictionary];
22 | BOOL ok = [pasteboard canReadObjectForClasses:classArray options:options];
23 | if (ok) {
24 | NSArray *objectsToPaste = [pasteboard readObjectsForClasses:classArray options:options];
25 | return (NSString *) [objectsToPaste objectAtIndex:0];
26 | }
27 | return @"";
28 | }
29 |
30 | @end
31 |
--------------------------------------------------------------------------------
/MacGap/Classes/Commands/MenuItem.h:
--------------------------------------------------------------------------------
1 | //
2 | // MenuItem.h
3 | // MG
4 | //
5 | // Created by Tim Debo on 5/23/14.
6 | //
7 | //
8 |
9 | #import
10 | #import
11 | #import "Command.h"
12 |
13 | @protocol MenuItemExports
14 | - (void) remove;
15 | //- (void) setCallback:(JSManagedValue*)aCallback;
16 | - (void) setKey:(NSString*)keyCommand;
17 | - (void) setLabel:(NSString*)label;
18 | JSExportAs(addSubmenu, - (JSValue*)addSubmenu: (NSString*) aTitle);
19 | @property (readonly) JSValue* submenu;
20 | @property (readwrite) BOOL enabled;
21 | @property (strong) JSValue* callback;
22 | @end
23 |
24 | @interface MenuItem : Command
25 | {
26 | NSMenuItem *item;
27 | };
28 | @property (nonatomic, strong) NSMenuItem *item;
29 | + (MenuItem*) menuItemWithContext: (JSContext*) context andMenu: (NSMenuItem*) aMenuItem;
30 | - (id) initWithContext:(JSContext*)aContext andMenuItem:(NSMenuItem*)anItem;
31 | @end
32 |
--------------------------------------------------------------------------------
/MacGap/Classes/Commands/Window.h:
--------------------------------------------------------------------------------
1 | //
2 | // Window.h
3 | // MG
4 | //
5 | // Created by Tim Debo on 5/20/14.
6 | //
7 | //
8 | #import
9 |
10 | @class WindowController, WebView;
11 |
12 | @protocol WindowExports
13 |
14 | @property (readonly) BOOL isMaximized;
15 | @property (readonly) CGFloat x;
16 | @property (readonly) CGFloat y;
17 |
18 |
19 | - (void) open:(NSString *) url;
20 | - (void) reopenFirst;
21 | JSExportAs(move, - (void) move: (NSNumber*) xCoord y: (NSNumber*) yCoord);
22 | JSExportAs(resize, - (void) resize: (NSNumber*) width height: (NSNumber*) height);
23 | - (void) minimize;
24 | - (void) maximize;
25 | - (void) toggleFullscreen;
26 | - (void) title: (NSString*) title;
27 | - (void) restore;
28 | @end
29 |
30 | @interface Window : NSObject
31 |
32 | - (Window*) initWithWindowController: (WindowController*)windowController andWebview: (WebView*) webView;
33 | - (CGFloat) getX;
34 | - (CGFloat) getY;
35 |
36 | @end
37 |
38 | //@end
39 |
40 |
--------------------------------------------------------------------------------
/public/config.json:
--------------------------------------------------------------------------------
1 | {
2 | "main": "public/index.html",
3 | "name": "MacGap",
4 | "description": "",
5 | "version": "2.0.0",
6 | "plugins" : {
7 | "Dock":"Dock",
8 | "Dialog":"Dialog",
9 | "Fonts" : "Fonts",
10 | "Clipboard":"Clipboard",
11 | "StatusItem":"StatusItem",
12 | "Task" : "Task",
13 | "Sound" : "Sound",
14 | "Defaults" : "Defaults",
15 | "File" : "File"
16 | },
17 | "window" : {
18 | "title" : "MacGap",
19 | "width" : 900,
20 | "height" : 600,
21 | "position": "center",
22 | "min_width": 400,
23 | "min_height": 200,
24 | "max_width": 1200,
25 | "max_height": 800,
26 | "opaque": 1,
27 | "alpha": 1,
28 | "titlebar": {
29 | "visible": false,
30 | "draggable": true,
31 | "height": 22
32 | }
33 | }
34 |
35 | }
36 |
--------------------------------------------------------------------------------
/MacGap/Classes/Commands/Event.h:
--------------------------------------------------------------------------------
1 | //
2 | // Event.h
3 | // MG
4 | //
5 | // Created by Tim Debo on 5/23/14.
6 | //
7 | //
8 |
9 | #import
10 | #import
11 | #import "WindowController.h"
12 |
13 | @interface Event : NSObject
14 |
15 | //+ (void) triggerEvent:(NSString *)event forContext:(JSContext*) context;
16 | //+ (void) triggerEvent:(NSString *)event withArgs:(NSDictionary *)args forContext:(JSContext*) context;
17 | //+ (void) triggerEvent:(NSString *)event withArgs:(NSDictionary *)args forObject:(NSString *)objName forContext:(JSContext*) context;
18 |
19 | + (void) triggerEvent:(NSString *)event forWebView:(WebView *)webView;
20 | + (void) triggerEvent:(NSString *)event withArgs:(NSDictionary *)args forWebView:(WebView *)webView;
21 | + (void) triggerEvent:(NSString *)event withArgs:(NSDictionary *)args forObject:(NSString *)objName forWebView:(WebView *)webView;
22 | + (void) triggerDomEvent:(NSString *)event withArgs:(NSDictionary *)args forWebView:(WebView *)webView;
23 |
24 | @end
25 |
--------------------------------------------------------------------------------
/MacGap/Classes/Commands/Fonts.m:
--------------------------------------------------------------------------------
1 | //
2 | // Fonts.m
3 | // MG
4 | //
5 | // Created by Tim Debo on 5/27/14.
6 | //
7 | //
8 |
9 | #import "Fonts.h"
10 |
11 | @implementation Fonts
12 |
13 | - (JSValue*) availableFonts {
14 | return [JSValue valueWithObject:[[NSFontManager sharedFontManager] availableFonts] inContext:[JSContext currentContext]];
15 | }
16 |
17 | - (JSValue*) availableFontFamilies {
18 | return [JSValue valueWithObject:[[NSFontManager sharedFontManager] availableFontFamilies] inContext:[JSContext currentContext]];
19 | }
20 |
21 | - (JSValue*) availableMembersOfFontFamily:(NSString *)fontFamily {
22 | return [JSValue valueWithObject:[[NSFontManager sharedFontManager] availableMembersOfFontFamily:fontFamily] inContext:[JSContext currentContext]];
23 | }
24 |
25 | - (CGFloat) defaultLineHeightForFont:(NSString*)theFontName ofSize:(CGFloat)theFontSize {
26 | NSFont *theFont = [NSFont fontWithName:theFontName size:theFontSize];
27 | NSLayoutManager *lm = [[NSLayoutManager alloc] init];
28 |
29 | return [lm defaultLineHeightForFont:theFont];
30 | }
31 |
32 | @end
33 |
--------------------------------------------------------------------------------
/MacGap/MG-Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | ${EXECUTABLE_NAME}
9 | CFBundleIconFile
10 |
11 | CFBundleIdentifier
12 | $(PRODUCT_BUNDLE_IDENTIFIER)
13 | CFBundleInfoDictionaryVersion
14 | 6.0
15 | CFBundleName
16 | ${PRODUCT_NAME}
17 | CFBundlePackageType
18 | APPL
19 | CFBundleShortVersionString
20 | 2.0
21 | CFBundleSignature
22 | ????
23 | CFBundleVersion
24 | 1
25 | LSMinimumSystemVersion
26 | ${MACOSX_DEPLOYMENT_TARGET}
27 | NSMainNibFile
28 | MainMenu
29 | NSPrincipalClass
30 | NSApplication
31 |
32 |
33 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2022 MacGap
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/MacGap/AppDelegate.m:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.m
3 | // MG
4 | //
5 | // Created by Tim Debo on 5/19/14.
6 | //
7 | //
8 |
9 | #import "AppDelegate.h"
10 | #import "WindowController.h"
11 |
12 | @implementation AppDelegate
13 |
14 | - (void)applicationWillFinishLaunching:(NSNotification *)aNotification
15 | {
16 | // Insert code here to initialize your application
17 | }
18 |
19 | -(BOOL)applicationShouldHandleReopen:(NSApplication*)application
20 | hasVisibleWindows:(BOOL)visibleWindows{
21 | if(!visibleWindows){
22 | [self.windowController.window makeKeyAndOrderFront: nil];
23 | }
24 | return YES;
25 | }
26 |
27 | - (void) applicationDidFinishLaunching:(NSNotification *)aNotification {
28 | self.windowController = [[WindowController alloc] initWithURL: kStartPage];
29 | [self.windowController setWindowParams];
30 | [self.windowController showWindow:self];
31 | [[NSUserNotificationCenter defaultUserNotificationCenter] setDelegate:self];
32 | }
33 |
34 | - (BOOL)userNotificationCenter:(NSUserNotificationCenter *)center
35 | shouldPresentNotification:(NSUserNotification *)notification
36 | {
37 | return YES;
38 | }
39 | @end
40 |
--------------------------------------------------------------------------------
/MacGap/Classes/Commands/App.h:
--------------------------------------------------------------------------------
1 | //
2 | // App.h
3 | // MG
4 | //
5 | // Created by Tim Debo on 5/27/14.
6 | //
7 | //
8 |
9 | #import "Command.h"
10 |
11 |
12 | @protocol AppExports
13 |
14 | - (void) terminate;
15 | - (void) activate;
16 | - (void) hide;
17 | - (void) unhide;
18 | - (void) beep;
19 | - (void) bounce;
20 | - (void) notify:(NSDictionary*)aNotification;
21 | - (void) closeNotification:(NSString*)notificationId;
22 |
23 | JSExportAs(setUserAgent, - (void) setCustomUserAgent:(NSString *)userAgentString);
24 | - (void) openURL:(NSString*)url;
25 | - (void) launch:(NSString *)name;
26 | @property (readonly) NSNumber* idleTime;
27 | @property (readonly) NSString* applicationPath;
28 | @property (readonly) NSString* resourcePath;
29 | @property (readonly) NSString* documentsPath;
30 | @property (readonly) NSString* libraryPath;
31 | @property (readonly) NSString* homePath;
32 | @property (readonly) NSString* tempPath;
33 | @property (readonly) NSArray* droppedFiles;
34 | @property (readonly) NSMutableArray* notifications;
35 | @end
36 |
37 | @interface App : Command
38 |
39 | - (id) initWithWebView:(WebView *)view;
40 | - (void) addFiles: (NSArray*) files;
41 | @end
42 |
--------------------------------------------------------------------------------
/MacGap/Images.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "mac",
5 | "size" : "16x16",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "mac",
10 | "size" : "16x16",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "mac",
15 | "size" : "32x32",
16 | "scale" : "1x"
17 | },
18 | {
19 | "idiom" : "mac",
20 | "size" : "32x32",
21 | "scale" : "2x"
22 | },
23 | {
24 | "idiom" : "mac",
25 | "size" : "128x128",
26 | "scale" : "1x"
27 | },
28 | {
29 | "idiom" : "mac",
30 | "size" : "128x128",
31 | "scale" : "2x"
32 | },
33 | {
34 | "idiom" : "mac",
35 | "size" : "256x256",
36 | "scale" : "1x"
37 | },
38 | {
39 | "idiom" : "mac",
40 | "size" : "256x256",
41 | "scale" : "2x"
42 | },
43 | {
44 | "idiom" : "mac",
45 | "size" : "512x512",
46 | "scale" : "1x"
47 | },
48 | {
49 | "idiom" : "mac",
50 | "size" : "512x512",
51 | "scale" : "2x"
52 | }
53 | ],
54 | "info" : {
55 | "version" : 1,
56 | "author" : "xcode"
57 | }
58 | }
--------------------------------------------------------------------------------
/MacGap/Classes/Commands/Menu.h:
--------------------------------------------------------------------------------
1 | //
2 | // Menu.h
3 | // MG
4 | //
5 | // Created by Tim Debo on 5/20/14.
6 | //
7 | //
8 |
9 | #import "Command.h"
10 | #import
11 | @protocol MenuExports
12 |
13 | @property (readonly) NSString* type;
14 | @property (readonly) NSArray* menuItems;
15 |
16 | JSExportAs(create, - (JSValue*) create: (NSString*) title type: (NSString*) type);
17 |
18 | JSExportAs(addItem, - (JSValue*) addItem: (NSDictionary*) props callback: (JSValue*) aCallback);
19 |
20 | JSExportAs(getItem, - (JSValue*) itemForKey:(id)key);
21 |
22 | - (JSValue*)addSeparator;
23 |
24 | + (NSString*)getKeyFromString:(NSString*)keyCommand;
25 |
26 | @end;
27 |
28 | @interface Menu : Command
29 | {
30 | NSMenu* menu;
31 | }
32 | @property (strong) NSMenu* menu;
33 | @property (readonly) NSString* type;
34 | @property (strong) JSContext* context;
35 |
36 | + (Menu*) menuWithContext: (JSContext*) context andMenu: (NSMenu*) aMenu;
37 | - (Menu*) initWithMenu: (NSMenu*) aMenu forContext: (JSContext*) context;
38 | - (Menu*) initWithMenu: (NSMenu*) aMenu andType: (NSString*) type forContext: (JSContext*) context;
39 | - (NSMenu*)removeItem:(id)key;
40 | @end
41 |
--------------------------------------------------------------------------------
/MacGap/Classes/DraggableView.m:
--------------------------------------------------------------------------------
1 | //
2 | // DraggableView.m
3 | // MG
4 | //
5 | // Created by Daniel Liljeberg on 2018-01-24.
6 | //
7 |
8 | #import "DraggableView.h"
9 |
10 | @implementation DraggableView
11 |
12 | -(void)mouseDown:(NSEvent *)theEvent {
13 | NSRect windowFrame = [[self window] frame];
14 |
15 | initialLocation = [NSEvent mouseLocation];
16 |
17 | initialLocation.x -= windowFrame.origin.x;
18 | initialLocation.y -= windowFrame.origin.y;
19 | }
20 |
21 | - (void)mouseDragged:(NSEvent *)theEvent {
22 | NSPoint currentLocation;
23 | NSPoint newOrigin;
24 |
25 | NSRect screenFrame = [[NSScreen mainScreen] frame];
26 | NSRect windowFrame = [self frame];
27 |
28 | currentLocation = [NSEvent mouseLocation];
29 | newOrigin.x = currentLocation.x - initialLocation.x;
30 | newOrigin.y = currentLocation.y - initialLocation.y;
31 |
32 | // Don't let window get dragged up under the menu bar
33 | if( (newOrigin.y+windowFrame.size.height) > (screenFrame.origin.y+screenFrame.size.height) ){
34 | newOrigin.y=screenFrame.origin.y + (screenFrame.size.height-windowFrame.size.height);
35 | }
36 |
37 | //go ahead and move the window to the new location
38 | [[self window] setFrameOrigin:newOrigin];
39 | }
40 |
41 | @end
42 |
--------------------------------------------------------------------------------
/MacGap/Classes/Commands/Event.m:
--------------------------------------------------------------------------------
1 | //
2 | // Event.m
3 | // MG
4 | //
5 | // Created by Tim Debo on 5/23/14.
6 | //
7 | //
8 |
9 | #import "Event.h"
10 | #import "JSON.h"
11 |
12 | @implementation Event
13 |
14 | + (void) triggerEvent:(NSString *)event forWebView:(WebView *)webView {
15 | [self triggerEvent:event withArgs:[NSMutableDictionary dictionary] forObject:@"document" forWebView:webView];
16 | }
17 |
18 | + (void) triggerEvent:(NSString *)event withArgs:(NSDictionary *)args forWebView:(WebView *)webView {
19 | [self triggerEvent:event withArgs:args forObject:@"document" forWebView:webView];
20 | }
21 |
22 | + (void) triggerEvent:(NSString *)event withArgs:(NSDictionary *)args forObject:(NSString *)objName forWebView:(WebView *)webView {
23 |
24 | NSString * str = [NSString stringWithFormat:@"var e = document.createEvent('Events'); e.initEvent('%@', true, false); e.data=%@; %@.dispatchEvent(e);", event, args.JSONString, objName];
25 | [webView stringByEvaluatingJavaScriptFromString:str];
26 | }
27 |
28 | + (void) triggerDomEvent:(NSString *)event withArgs:(NSDictionary *)args forWebView:(WebView *)webView {
29 |
30 | NSString * str = [NSString stringWithFormat:@"var e = new CustomEvent('%@', %@); document.dispatchEvent(e);", event, args.JSONString];
31 | [webView stringByEvaluatingJavaScriptFromString:str];
32 | }
33 |
34 | @end
35 |
--------------------------------------------------------------------------------
/MacGap/Classes/WindowController.h:
--------------------------------------------------------------------------------
1 | //
2 | // WindowController.h
3 | // MG
4 | //
5 | // Created by Tim Debo on 5/19/14.
6 | //
7 | //
8 |
9 | #import
10 | #import
11 | #import "MacGap.h"
12 | #import "NotificationProvider.h"
13 |
14 | @class WebViewDelegate;
15 |
16 | @interface WindowController : NSWindowController
17 | {
18 | IBOutlet WebView* webView;
19 | IBOutlet NSWindow* window;
20 | WebViewDelegate* webViewDelegate;
21 | JSContext* jsContext;
22 | NotificationProvider *notificationProvider;
23 | }
24 |
25 | @property (nonatomic, readonly, strong) NSMutableDictionary* pluginObjects;
26 | @property (nonatomic, readonly, strong) NSDictionary* pluginsMap;
27 | @property (nonatomic, readonly, strong) NSMutableDictionary* settings;
28 | @property (strong) JSContext* jsContext;
29 | @property (retain) WebView* webView;
30 | @property (strong) IBOutlet NSMenu *mainMenu;
31 | @property (retain) WebViewDelegate* webViewDelegate;
32 |
33 | @property (retain) NSURL* url;
34 |
35 | @property (nonatomic, readonly) NSString* userAgent;
36 |
37 | - (id) initWithURL:(NSString *) url;
38 | - (id) initWithRequest: (NSURLRequest *)request;
39 |
40 | - (id)getCommandInstance:(NSString*)pluginName;
41 | //- (void)registerPlugin:(Plugin*)plugin withClassName:(NSString*)className;
42 | //- (void)registerPlugin:(Plugin*)plugin withPluginName:(NSString*)pluginName;
43 | - (void) setWindowParams;
44 |
45 | @end
46 |
--------------------------------------------------------------------------------
/MacGap/Classes/Commands/Command.m:
--------------------------------------------------------------------------------
1 | //
2 | // Command.m
3 | // MG
4 | //
5 | // Created by Tim Debo on 5/23/14.
6 | //
7 | //
8 |
9 | #import "Command.h"
10 | #import
11 | #import "WindowController.h"
12 |
13 | @implementation Command
14 | @synthesize webView, windowController;
15 | + (JSValue *)makeConstructor:(id)block inContext:(JSContext *)context {
16 | JSValue *fun = [context evaluateScript:@"(function () { return this.__construct.apply(this, arguments); });"];
17 | fun[@"prototype"][@"__construct"] = block;
18 | return fun;
19 | }
20 |
21 | + (JSValue *)constructor {
22 | return [self makeConstructor:^{ return [self new]; } inContext:JSContext.currentContext];
23 | }
24 |
25 | - (NSString*) exportName {
26 | return NSStringFromClass([self class]);
27 | }
28 |
29 | - (id) initWithWindowController:(WindowController *)aWindowController
30 | {
31 | self = [super init];
32 | if(self) {
33 | self.windowController = aWindowController;
34 | self.webView = aWindowController.webView;
35 | }
36 |
37 | return self;
38 |
39 | }
40 |
41 | - (id) initWithContext:(JSContext*)context {
42 | self = [super init];
43 | if (!self)
44 | return nil;
45 | jsContext = [context JSGlobalContextRef];
46 | JSGlobalContextRetain((JSGlobalContextRef)jsContext);
47 | return self;
48 | }
49 |
50 | - (void)dealloc
51 | {
52 | if (jsContext)
53 | JSGlobalContextRelease((JSGlobalContextRef)jsContext);
54 | }
55 |
56 | - (void) initializePlugin {}
57 |
58 | @end
59 |
--------------------------------------------------------------------------------
/MG.xcodeproj/project.xcworkspace/xcshareddata/MG.xccheckout:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDESourceControlProjectFavoriteDictionaryKey
6 |
7 | IDESourceControlProjectIdentifier
8 | 05DEC22A-E6E9-40FC-9B5D-1BB13B3A2394
9 | IDESourceControlProjectName
10 | MG
11 | IDESourceControlProjectOriginsDictionary
12 |
13 | 6619CA971E46A2C1689FBEA6301DFE23F3ECA032
14 | https://github.com/rawcreative/MacGap2.git
15 |
16 | IDESourceControlProjectPath
17 | MG.xcodeproj
18 | IDESourceControlProjectRelativeInstallPathDictionary
19 |
20 | 6619CA971E46A2C1689FBEA6301DFE23F3ECA032
21 | ../..
22 |
23 | IDESourceControlProjectURL
24 | https://github.com/rawcreative/MacGap2.git
25 | IDESourceControlProjectVersion
26 | 111
27 | IDESourceControlProjectWCCIdentifier
28 | 6619CA971E46A2C1689FBEA6301DFE23F3ECA032
29 | IDESourceControlProjectWCConfigurations
30 |
31 |
32 | IDESourceControlRepositoryExtensionIdentifierKey
33 | public.vcs.git
34 | IDESourceControlWCCIdentifierKey
35 | 6619CA971E46A2C1689FBEA6301DFE23F3ECA032
36 | IDESourceControlWCCName
37 | MG
38 |
39 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/MacGap/Classes/NotificationProvider.h:
--------------------------------------------------------------------------------
1 | //
2 | // NotificationProvider.h
3 | // nimbus
4 | //
5 | // Created by Johan Nordberg on 2012-10-27.
6 | // Copyright 2012 FFFF00 Agents AB. All rights reserved.
7 | //
8 |
9 | #import
10 | #import
11 | #import "WebNotification.h"
12 |
13 | typedef enum {
14 | WebNotificationPermissionAllowed,
15 | WebNotificationPermissionNotAllowed,
16 | WebNotificationPermissionDenied
17 | } WebNotificationPermission;
18 |
19 | @protocol WebNotificationProvider
20 | - (void)registerWebView:(WebView *)webView;
21 | - (void)unregisterWebView:(WebView *)webView;
22 | - (void)showNotification:(WebNotification *)notification fromWebView:(WebView *)webView;
23 | - (void)cancelNotification:(WebNotification *)notification;
24 | - (void)notificationDestroyed:(WebNotification *)notification;
25 | - (void)clearNotifications:(NSArray *)notificationIDs;
26 | - (WebNotificationPermission)policyForOrigin:(WebSecurityOrigin *)origin;
27 |
28 | - (void)webView:(WebView *)webView didShowNotification:(uint64_t)notificationID;
29 | - (void)webView:(WebView *)webView didClickNotification:(uint64_t)notificationID;
30 | - (void)webView:(WebView *)webView didCloseNotifications:(NSArray *)notificationIDs;
31 | @end
32 |
33 | @interface WebView (WebViewNotification)
34 | - (void)_setNotificationProvider:(id)notificationProvider;
35 | - (id)_notificationProvider;
36 | - (void)_notificationControllerDestroyed;
37 |
38 | - (void)_notificationDidShow:(uint64_t)notificationID;
39 | - (void)_notificationDidClick:(uint64_t)notificationID;
40 | - (void)_notificationsDidClose:(NSArray *)notificationIDs;
41 | @end
42 |
43 | @interface NotificationProvider : NSObject
44 |
45 | @end
46 |
--------------------------------------------------------------------------------
/MacGap/Classes/Commands/Sound.m:
--------------------------------------------------------------------------------
1 | //
2 | // Sound.m
3 | // MG
4 | //
5 | // Created by Tim Debo on 5/31/14.
6 | //
7 | //
8 |
9 | #import "Sound.h"
10 | #import
11 | #import "WindowController.h"
12 |
13 | @interface Sound ()
14 | {
15 | NSMutableDictionary * callbacks;
16 | }
17 | @property (readwrite) JSContext* context;
18 | @end
19 |
20 | @implementation Sound
21 | @synthesize cb, context;
22 |
23 | - (id) initWithWindowController:(WindowController *)aWindowController
24 | {
25 | self = [super init];
26 | if(self) {
27 | self.windowController = aWindowController;
28 | self.webView = aWindowController.webView;
29 | }
30 | callbacks = [NSMutableDictionary new];
31 | return self;
32 |
33 | }
34 |
35 | - (void) playSound:(NSSound*)sound onComplete:(JSValue*)callback {
36 | if (callback && ![callback isKindOfClass:[NSNull class]]) {
37 | //cb = callback;
38 | [callbacks setObject:callback forKey:[sound name]];
39 | context = [JSContext currentContext];
40 | [sound setDelegate:self];
41 | }
42 | [sound play];
43 | }
44 |
45 | - (void) play:(NSString*)file onComplete:(JSValue*)callback {
46 | NSURL* fileUrl = [NSURL fileURLWithPath:pathForResource(file)];
47 | DebugNSLog(@"Sound file:%@", [fileUrl description]);
48 |
49 | NSSound* sound = [[NSSound alloc] initWithContentsOfURL:fileUrl byReference:YES];
50 | if(!sound.name) {
51 | sound.name = fileUrl.lastPathComponent;
52 | }
53 |
54 | NSLog(@"Callback: %@, Sound: %@, Name: %@", callback, sound, [sound name]);
55 | [self playSound:sound onComplete:callback];
56 | }
57 |
58 | - (void) playSystem:(NSString*)name onComplete:(JSValue*)callback {
59 | NSSound *systemSound = [NSSound soundNamed:name];
60 | [self playSound:systemSound onComplete:callback];
61 | }
62 |
63 | - (void)sound:(NSSound *)aSound didFinishPlaying:(BOOL)finishedPlaying {
64 | cb = [callbacks valueForKey:[aSound name]];
65 | [cb callWithArguments:@[aSound.name]];
66 | cb = nil;
67 | }
68 |
69 | @end
70 |
--------------------------------------------------------------------------------
/MacGap/Categories/JSON.m:
--------------------------------------------------------------------------------
1 | //
2 | // JSON.m
3 | // MacGap
4 | //
5 | // Created by Tim Debo on 5/17/14.
6 | // Copyright (c) 2014 Raw Creative Studios LLC. All rights reserved.
7 | //
8 |
9 | #import "JSON.h"
10 | #import
11 |
12 | @implementation NSArray (MGJSON)
13 |
14 | - (NSString*)JSONString
15 | {
16 | NSError* error = nil;
17 | NSData* jsonData = [NSJSONSerialization dataWithJSONObject:self
18 | options:NSJSONWritingPrettyPrinted
19 | error:&error];
20 |
21 | if (error != nil) {
22 | NSLog(@"NSArray JSONString error: %@", [error localizedDescription]);
23 | return nil;
24 | } else {
25 | return [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
26 | }
27 | }
28 |
29 | @end
30 |
31 | @implementation NSDictionary (MGJSON)
32 |
33 | - (NSString*)JSONString
34 | {
35 | NSError* error = nil;
36 | NSData* jsonData = [NSJSONSerialization dataWithJSONObject:self
37 | options:NSJSONWritingPrettyPrinted
38 | error:&error];
39 |
40 | if (error != nil) {
41 | NSLog(@"NSDictionary JSONString error: %@", [error localizedDescription]);
42 | return nil;
43 | } else {
44 | return [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
45 | }
46 | }
47 |
48 | @end
49 |
50 | @implementation NSString (MGJSON)
51 |
52 | - (id)JSONObject
53 | {
54 | NSError* error = nil;
55 | id object = [NSJSONSerialization JSONObjectWithData:[self dataUsingEncoding:NSUTF8StringEncoding]
56 | options:kNilOptions
57 | error:&error];
58 |
59 | if (error != nil) {
60 | NSLog(@"NSString JSONObject error: %@", [error localizedDescription]);
61 | }
62 |
63 | return object;
64 | }
65 |
66 | @end
67 |
--------------------------------------------------------------------------------
/MacGap/Classes/WebNotification.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2012 Apple Computer, Inc. All rights reserved.
3 | *
4 | * Redistribution and use in source and binary forms, with or without
5 | * modification, are permitted provided that the following conditions
6 | * are met:
7 | *
8 | * 1. Redistributions of source code must retain the above copyright
9 | * notice, this list of conditions and the following disclaimer.
10 | * 2. Redistributions in binary form must reproduce the above copyright
11 | * notice, this list of conditions and the following disclaimer in the
12 | * documentation and/or other materials provided with the distribution.
13 | * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
14 | * its contributors may be used to endorse or promote products derived
15 | * from this software without specific prior written permission.
16 | *
17 | * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
18 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20 | * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
21 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 | */
28 |
29 | @class WebNotificationPrivate;
30 | @class WebSecurityOrigin;
31 |
32 | @interface WebNotification : NSObject
33 | {
34 | WebNotificationPrivate *_private;
35 | }
36 |
37 | - (NSString *)title;
38 | - (NSString *)body;
39 | - (NSString *)tag;
40 | - (WebSecurityOrigin *)origin;
41 | - (uint64_t)notificationID;
42 |
43 | - (void)dispatchShowEvent;
44 | - (void)dispatchCloseEvent;
45 | - (void)dispatchClickEvent;
46 | - (void)dispatchErrorEvent;
47 |
48 | @end
49 |
--------------------------------------------------------------------------------
/MacGap/Base.lproj/MainWindow.xib:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/MacGap/Classes/Commands/Notify.m:
--------------------------------------------------------------------------------
1 | //
2 | // Notify.m
3 | // MG
4 | //
5 | // Created by Tim Debo on 5/27/14.
6 | //
7 | //
8 |
9 | #import "Notify.h"
10 | @interface Notify ()
11 | @property (readwrite) NSMutableArray* notifications;
12 | @end
13 |
14 | @implementation Notify
15 |
16 | - (void) notify:(NSDictionary*)aNotification {
17 | NSString* type = [aNotification valueForKey:@"type"];
18 | NSString* uid = [aNotification valueForKey:@"id"];
19 |
20 | if([type isEqualToString:@"sheet"]) {
21 | NSAlert *alert = [[NSAlert alloc] init];
22 | [alert setMessageText:[aNotification valueForKey:@"title"]];
23 | [alert setInformativeText:[aNotification valueForKey:@"content"]];
24 | [alert beginSheetModalForWindow:[[NSApplication sharedApplication] mainWindow]
25 | modalDelegate:self
26 | didEndSelector:nil
27 | contextInfo:nil];
28 |
29 |
30 | } else {
31 |
32 | NSUserNotification *notification = [[NSUserNotification alloc] init];
33 |
34 | if(!uid) {
35 | uid =[[NSUUID UUID] UUIDString];
36 |
37 | }
38 |
39 | [notification setTitle:[aNotification valueForKey:@"title"]];
40 | [notification setInformativeText:[aNotification valueForKey:@"content"]];
41 | [notification setSubtitle:[aNotification valueForKey:@"subtitle"]];
42 | [notification setUserInfo:@{ @"id" : uid }];
43 |
44 | if([[aNotification valueForKey:@"sound"] boolValue] == YES || ![aNotification valueForKey:@"sound"] ) {
45 | [notification setSoundName: NSUserNotificationDefaultSoundName];
46 | }
47 | [[NSUserNotificationCenter defaultUserNotificationCenter] deliverNotification:notification];
48 |
49 | [self.notifications addObject:@{ @"id" : uid, @"title" : [aNotification valueForKey: @"title"], @"sentOn" :[NSDate date] }];
50 |
51 | }
52 |
53 |
54 |
55 | }
56 |
57 | - (void) close:(NSString*)notificationId {
58 | NSUserNotificationCenter *center = [NSUserNotificationCenter defaultUserNotificationCenter];
59 | for(NSUserNotification * deliveredNote in center.deliveredNotifications) {
60 | if ([notificationId isEqualToString:@"*"] || [deliveredNote.userInfo[@"id"] isEqualToString:notificationId]) {
61 | [center removeDeliveredNotification: deliveredNote];
62 | }
63 | }
64 | }
65 |
66 |
67 |
68 | + (BOOL) available {
69 | if ([NSUserNotificationCenter respondsToSelector:@selector(defaultUserNotificationCenter)])
70 | return YES;
71 |
72 | return NO;
73 | }
74 |
75 | @end
76 |
--------------------------------------------------------------------------------
/MacGap/Classes/Commands/StatusItem.m:
--------------------------------------------------------------------------------
1 | //
2 | // StatusItem.m
3 | // MG
4 | //
5 | // Created by Tim Debo on 5/28/14.
6 | //
7 | //
8 |
9 | #import "StatusItem.h"
10 | #import "WindowController.h"
11 | #import "Event.h"
12 |
13 | @interface StatusItem ()
14 | @property (strong) JSValue* callback;
15 | @property (strong) NSNumber* titleFontSize;
16 | @end
17 |
18 | @implementation StatusItem
19 | @synthesize menu, title;
20 | - (id) initWithWindowController:(WindowController *)aWindowController
21 | {
22 | self = [super init];
23 | if(self) {
24 | self.windowController = aWindowController;
25 | self.webView = aWindowController.webView;
26 | self.menu = nil;
27 | }
28 | return self;
29 | }
30 |
31 | - (void) createItem: (NSDictionary*) props callback: (JSValue*) cb
32 | {
33 | NSString *aTitle = [props valueForKey:@"title"];
34 | NSNumber *titleFontSize = [props valueForKey:@"titleFontSize"];
35 | NSString *image = [props valueForKey:@"image"];
36 | NSString *alternateImage = [props valueForKey:@"alternateImage"];
37 |
38 | NSURL* imgfileUrl = nil;
39 | NSURL* altImgfileUrl = nil;
40 |
41 | if(cb)
42 | _callback = cb;
43 |
44 | if(titleFontSize)
45 | _titleFontSize = titleFontSize;
46 |
47 | if(image)
48 | imgfileUrl = [NSURL fileURLWithPath:pathForResource(image)];
49 |
50 | if(alternateImage)
51 | altImgfileUrl = [NSURL fileURLWithPath:pathForResource(alternateImage)];
52 |
53 | _statusItem = [[NSStatusBar systemStatusBar] statusItemWithLength:NSVariableStatusItemLength];
54 |
55 | if(aTitle)
56 | [self setTitle:aTitle];
57 |
58 | _statusItem.image = [[NSImage alloc] initWithContentsOfURL:imgfileUrl];
59 | _statusItem.alternateImage = [[NSImage alloc] initWithContentsOfURL:altImgfileUrl];
60 | _statusItem.action = @selector(itemClicked:);
61 | _statusItem.target = self;
62 | _statusItem.highlightMode = YES;
63 | }
64 |
65 | - (void) setMenu:(JSValue*)aMenu
66 | {
67 | menu = aMenu;
68 | Menu* theMenu = [aMenu toObject];
69 | _statusItem.menu = theMenu.menu;
70 | }
71 |
72 | - (void) setTitle:(NSString*)aTitle
73 | {
74 | NSMutableAttributedString *attributedTitle=[[NSMutableAttributedString alloc] initWithString:aTitle];
75 | NSInteger _stringLength=[aTitle length];
76 | NSFont *font=[NSFont menuBarFontOfSize:[_titleFontSize floatValue]];
77 | [attributedTitle addAttribute:NSFontAttributeName value:font range:NSMakeRange(0, _stringLength)];
78 | _statusItem.attributedTitle = attributedTitle;
79 | }
80 |
81 | - (void) itemClicked:(id)sender
82 | {
83 | if(_callback) {
84 | [_callback callWithArguments:@[]];
85 | } else {
86 | [Event triggerEvent:@"statusItemClick" forWebView:self.webView];
87 | }
88 |
89 | }
90 | @end
91 |
--------------------------------------------------------------------------------
/MacGap/Classes/Commands/MenuItem.m:
--------------------------------------------------------------------------------
1 | //
2 | // MenuItem.m
3 | // MG
4 | //
5 | // Created by Tim Debo on 5/23/14.
6 | //
7 | //
8 |
9 | #import "MenuItem.h"
10 | #import "Menu.h"
11 |
12 | @interface MenuItem ()
13 | {
14 | JSContext* context;
15 | }
16 | @property (readwrite) JSValue* submenu;
17 | @property (strong) JSContext* context;
18 |
19 | - (void) fireCallback;
20 |
21 | @end;
22 |
23 | @implementation MenuItem
24 |
25 | @synthesize callback, submenu, enabled, item, context;
26 |
27 | + (MenuItem*) menuItemWithContext: (JSContext*) context andMenu: (NSMenuItem*) aMenuItem
28 | {
29 | MenuItem *ret = [aMenuItem representedObject];
30 | if (ret)
31 | {
32 | NSLog(@"MI Cache Hit");
33 | return ret;
34 | }
35 | return [[MenuItem alloc] initWithContext:context andMenuItem:aMenuItem];
36 |
37 | }
38 | - (id) initWithContext:(JSContext*)aContext andMenuItem:(NSMenuItem*)anItem
39 | {
40 | NSAssert(anItem, @"anItem required");
41 | self = [super init]; //initWithContext:aContext];
42 | if (!self)
43 | return nil;
44 | item = anItem;
45 | item.representedObject = self;
46 | self.context = aContext;
47 | self.enabled = [anItem isEnabled];
48 | NSMenu* subMenu = [item submenu];
49 | if(subMenu) {
50 |
51 | self.submenu = [JSValue valueWithObject: [Menu menuWithContext: aContext andMenu: subMenu] inContext:aContext];
52 | }
53 |
54 | return self;
55 | }
56 |
57 | - (void) fireCallback
58 | {
59 |
60 | [callback callWithArguments: @[]];
61 | }
62 |
63 | - (void) setCallback:(JSValue*)aCallback
64 | {
65 |
66 | callback = aCallback;
67 | [item setAction:@selector(fireCallback)];
68 | [item setTarget:self];
69 | }
70 | - (void) setEnabled:(BOOL) val
71 | {
72 | if(!val || val == NO) {
73 | enabled = NO;
74 | [item setEnabled: NO];
75 | }
76 | if(val == YES) {
77 | enabled = YES;
78 | [item setEnabled:enabled];
79 |
80 | }
81 |
82 | }
83 |
84 | - (JSValue*)addSubmenu: (NSString*) aTitle
85 | {
86 | NSMenu *s = [item submenu];
87 | if (!s)
88 | {
89 | NSString *title = nil;
90 | if(!aTitle || [aTitle isKindOfClass:[NSNull class]]) {
91 | title = @"";
92 | }
93 | s = [[NSMenu alloc] initWithTitle:title];
94 | [item setSubmenu:s];
95 | self.submenu = [JSValue valueWithObject: [Menu menuWithContext: self.context andMenu: s] inContext:self.context];
96 | }
97 | return self.submenu;
98 | }
99 |
100 | - (void) setLabel: (NSString*) aLabel
101 | {
102 | if(aLabel && ![aLabel isKindOfClass: [NSNull class]]) {
103 | [item setTitle: aLabel];
104 | }
105 |
106 | }
107 | - (void) remove
108 | {
109 | NSMenu *menu = [item menu];
110 | [menu removeItem:item];
111 | }
112 |
113 | - (void)setKey:(NSString *)keyCommand {
114 | //
115 | }
116 |
117 |
118 | - (void) dealloc
119 | {
120 | NSLog(@"Menu Item Deallocated");
121 | }
122 | @end
123 |
--------------------------------------------------------------------------------
/MacGap/Classes/Commands/File.m:
--------------------------------------------------------------------------------
1 | //
2 | // File.m
3 | // MG
4 | //
5 | // Created by Tim Debo on 6/8/14.
6 | //
7 | //
8 |
9 | #import "File.h"
10 | #import "WindowController.h"
11 |
12 | @interface File ()
13 |
14 | @property (nonatomic) NSArray* acceptedTypes;
15 |
16 | @end
17 |
18 | @implementation File
19 |
20 | - (id) initWithWindowController:(WindowController *)aWindowController
21 | {
22 | self = [super init];
23 |
24 | if(self) {
25 | self.windowController = aWindowController;
26 | self.webView = aWindowController.webView;
27 | _acceptedTypes = @[ @"string", @"json", @"image"];
28 |
29 | }
30 |
31 | return self;
32 | }
33 |
34 |
35 | - (void) writeFile:(NSString*)filePath withData: (JSValue*) data andType: (NSString*) type
36 | {
37 |
38 | if([_acceptedTypes containsObject:type]){
39 |
40 | if([type isEqualToString:@"string"]) {
41 | NSString* valToWrite = [data toString];
42 | [valToWrite writeToFile:filePath atomically:YES encoding:NSUTF8StringEncoding error:NULL];
43 | } else if([type isEqualToString:@"json"]) {
44 |
45 | NSDictionary* dictData = [data toDictionary];
46 | NSString* valToWrite = [dictData JSONString];
47 |
48 | [valToWrite writeToFile:filePath atomically:YES encoding:NSUTF8StringEncoding error:NULL];
49 | } else {
50 | //TODO
51 | // NSString* base64Data = [data toString];
52 | // NSData * valToWrite = [NSData dataFromBase64String:base64Data];
53 | }
54 | }
55 |
56 | }
57 |
58 |
59 | - (BOOL) exists:(NSString*)filePath {
60 | return [[NSFileManager defaultManager] fileExistsAtPath:filePath];
61 | }
62 |
63 | - (JSValue*) readFile:(NSString*)filePath ofType: (NSString*) type
64 | {
65 |
66 | if([_acceptedTypes containsObject:type]) {
67 | BOOL fileExists = [[NSFileManager defaultManager] fileExistsAtPath:filePath];
68 | if([type isEqualToString:@"string"]) {
69 |
70 | if(fileExists) {
71 | NSString* val = [NSString stringWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:NULL];
72 | return [JSValue valueWithObject:val inContext:[JSContext currentContext]];
73 | } else {
74 | DebugNSLog(@"File does not exist at the path provided.");
75 | }
76 |
77 | } else if([type isEqualToString:@"json"]) {
78 |
79 | if(fileExists) {
80 | NSDictionary* val = [[NSString stringWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:NULL] JSONObject];
81 | return [JSValue valueWithObject:val inContext:[JSContext currentContext]];
82 | } else {
83 | DebugNSLog(@"File does not exist at the path provided.");
84 | }
85 | } else {
86 | //TODO
87 | // if(fileExists) {
88 | // NSDictionary* val = [[NSString stringWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:NULL] JSONObject];
89 | // return [JSValue valueWithObject:val inContext:[JSContext currentContext]];
90 | // }
91 | }
92 | } else {
93 |
94 | DebugNSLog(@"Incorrect File Type Specified. Acceptable types are: string, json or image.");
95 |
96 | return nil;
97 | }
98 | return nil;
99 | }
100 |
101 | @end
102 |
--------------------------------------------------------------------------------
/MacGap/Classes/Commands/Dialog.m:
--------------------------------------------------------------------------------
1 | //
2 | // Dialog.m
3 | // MG
4 | //
5 | // Created by Tim Debo on 5/27/14.
6 | //
7 | //
8 |
9 | #import "Dialog.h"
10 | #import "WindowController.h"
11 |
12 | @implementation Dialog
13 | @synthesize context;
14 |
15 | - (void) openDialog:(JSValue *)args
16 | {
17 |
18 | context = [JSContext currentContext];
19 |
20 | NSOpenPanel * openDlg = [NSOpenPanel openPanel];
21 |
22 | JSValue* mult = [args valueForProperty:@"multiple"];
23 | JSValue* files = [args valueForProperty:@"files"];
24 | JSValue* dirs = [args valueForProperty:@"directories"];
25 | JSValue* cb = [args valueForProperty: @"callback"];
26 | JSValue* allowedTypes = [args valueForProperty:@"allowedTypes"];
27 | [openDlg setCanChooseFiles: [files toBool]];
28 | [openDlg setCanChooseDirectories: [dirs toBool]];
29 | [openDlg setAllowsMultipleSelection: [mult toBool]];
30 | if(allowedTypes)
31 | [openDlg setAllowedFileTypes: [allowedTypes toArray]];
32 | [openDlg beginWithCompletionHandler:^(NSInteger result){
33 |
34 | if (result == NSFileHandlingPanelOKButton) {
35 |
36 | if(cb) {
37 | NSArray* files = [[openDlg URLs] valueForKey:@"relativePath"];
38 | [cb callWithArguments: @[files]];
39 | }
40 |
41 | }
42 | }];
43 |
44 |
45 | }
46 |
47 | - (void) saveDialog:(JSValue *)args
48 | {
49 | context = [JSContext currentContext];
50 | NSSavePanel * saveDlg = [NSSavePanel savePanel];
51 | JSValue* title = [args valueForProperty:@"title"];
52 | JSValue* prompt = [args valueForProperty:@"prompt"];
53 | JSValue* message = [args valueForProperty:@"message"];
54 | JSValue* filename = [args valueForProperty:@"filename"];
55 | JSValue* directory = [args valueForProperty:@"directory"];
56 | JSValue* createDirs = [args valueForProperty:@"createDirs"];
57 | JSValue* allowedTypes = [args valueForProperty:@"allowedTypes"];
58 | JSValue* cb = [args valueForProperty: @"callback"];
59 |
60 | if(title)
61 | [saveDlg setTitle: [title toString]];
62 |
63 | if(prompt)
64 | [saveDlg setPrompt: [prompt toString]];
65 |
66 |
67 | if(message)
68 | [saveDlg setMessage: [message toString]];
69 |
70 |
71 | if(filename)
72 | [saveDlg setNameFieldStringValue: [filename toString]];
73 |
74 | if(directory)
75 | [saveDlg setDirectoryURL: [NSURL URLWithString: [directory toString]]];
76 |
77 | if(createDirs)
78 | [saveDlg setCanCreateDirectories: [createDirs toBool]];
79 |
80 | if(allowedTypes)
81 | [saveDlg setAllowedFileTypes: [allowedTypes toArray]];
82 |
83 | [saveDlg beginSheetModalForWindow: self.windowController.window completionHandler:^(NSInteger result){
84 |
85 | if (result == NSFileHandlingPanelOKButton) {
86 |
87 | if(cb) {
88 | NSDictionary* results = @{
89 | @"directory" : [[saveDlg directoryURL] valueForKey:@"relativePath"],
90 | @"filePath" : [[saveDlg URL] valueForKey:@"relativePath"],
91 | @"filename" : [saveDlg nameFieldStringValue]
92 | };
93 |
94 | [cb callWithArguments: @[results]];
95 | }
96 |
97 | }
98 | }];
99 |
100 | }
101 |
102 | @end
103 |
--------------------------------------------------------------------------------
/MG.xcodeproj/xcuserdata/Tim.xcuserdatad/xcschemes/MG.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
33 |
39 |
40 |
41 |
42 |
43 |
49 |
50 |
51 |
52 |
61 |
62 |
68 |
69 |
70 |
71 |
72 |
73 |
79 |
80 |
86 |
87 |
88 |
89 |
91 |
92 |
95 |
96 |
97 |
--------------------------------------------------------------------------------
/MacGap/Classes/NotificationProvider.m:
--------------------------------------------------------------------------------
1 | //
2 | // NotificationProvider.h
3 | // nimbus
4 | //
5 | // Created by Johan Nordberg on 2012-10-27.
6 | // Copyright 2012 FFFF00 Agents AB. All rights reserved.
7 | //
8 |
9 |
10 | #import "NotificationProvider.h"
11 |
12 | @interface NotificationProvider () {
13 | NSMutableDictionary *_userNotifications;
14 | NSMutableDictionary *_webNotifications;
15 | NSUserNotificationCenter *_notificationCenter;
16 | }
17 | @end
18 |
19 | NSString *notificationKey(WebNotification *notification) {
20 | return [NSString stringWithFormat:@"%lld", notification.notificationID];
21 | }
22 |
23 | @implementation NotificationProvider
24 |
25 | - (id)init {
26 | self = [super init];
27 | if (self) {
28 | _userNotifications = [[NSMutableDictionary alloc] init];
29 | _webNotifications = [[NSMutableDictionary alloc] init];
30 | _notificationCenter = [NSUserNotificationCenter defaultUserNotificationCenter];
31 | _notificationCenter.delegate = self;
32 | }
33 | return self;
34 | }
35 |
36 | // probably safe to ignore since we only have one webview
37 | - (void)registerWebView:(WebView *)webView {}
38 | - (void)unregisterWebView:(WebView *)webView {}
39 |
40 | - (void)showNotification:(WebNotification *)webNotification fromWebView:(WebView *)webView {
41 | NSString *key = notificationKey(webNotification);
42 | NSUserNotification *userNotification = [[NSUserNotification alloc] init];
43 |
44 | userNotification.title = webNotification.title;
45 | userNotification.informativeText = webNotification.body;
46 | userNotification.userInfo = [NSDictionary dictionaryWithObject:key forKey:@"webNotification"];
47 | userNotification.soundName = @"digit";
48 |
49 | [_webNotifications setValue:webNotification forKey:key];
50 | [_userNotifications setValue:userNotification forKey:key];
51 | [_notificationCenter deliverNotification:userNotification];
52 | }
53 |
54 | - (void)userNotificationCenter:(NSUserNotificationCenter *)center didActivateNotification:(NSUserNotification *)notification {
55 | NSString *key = [notification.userInfo objectForKey:@"webNotification"];
56 | WebNotification *webNotification = [_webNotifications valueForKey:key];
57 | [webNotification dispatchClickEvent];
58 | }
59 |
60 | - (void)userNotificationCenter:(NSUserNotificationCenter *)center didDeliverNotification:(NSUserNotification *)notification {
61 | NSString *key = [notification.userInfo objectForKey:@"webNotification"];
62 | WebNotification *webNotification = [_webNotifications valueForKey:key];
63 | [webNotification dispatchShowEvent];
64 | }
65 |
66 | - (WebNotificationPermission)policyForOrigin:(WebSecurityOrigin *)origin {
67 | return WebNotificationPermissionAllowed;
68 | }
69 |
70 | - (void)cancelNotification:(WebNotification *)webNotification {
71 | NSString *key = notificationKey(webNotification);
72 | NSUserNotification *userNotification = [_userNotifications valueForKey:key];
73 |
74 | [webNotification dispatchCloseEvent];
75 |
76 | if (userNotification) [_notificationCenter removeDeliveredNotification:userNotification];
77 |
78 | [_webNotifications removeObjectForKey:key];
79 | [_userNotifications removeObjectForKey:key];
80 | }
81 |
82 | - (void)notificationDestroyed:(WebNotification *)webNotification {
83 | // never called?
84 | NSString *key = notificationKey(webNotification);
85 | [_webNotifications removeObjectForKey:key];
86 | [_userNotifications removeObjectForKey:key];
87 | }
88 |
89 | - (void)clearNotifications:(NSArray *)notificationIDs {
90 | // never called?
91 | [_notificationCenter removeAllDeliveredNotifications];
92 | }
93 |
94 | // why does the provider have reciever methods? was never called in my tests
95 | - (void)webView:(WebView *)webView didShowNotification:(uint64_t)notificationID {}
96 | - (void)webView:(WebView *)webView didClickNotification:(uint64_t)notificationID {}
97 | - (void)webView:(WebView *)webView didCloseNotifications:(NSArray *)notificationIDs {}
98 |
99 | @end
100 |
--------------------------------------------------------------------------------
/MacGap/Classes/Commands/Task.m:
--------------------------------------------------------------------------------
1 | //
2 | // Task.m
3 | // MG
4 | //
5 | // Created by Tim Debo on 5/27/14.
6 | //
7 | //
8 |
9 | #import "Task.h"
10 | #import "WindowController.h"
11 |
12 | @interface Task ()
13 | @property (readwrite) BOOL isRunning;
14 | @property (readwrite) BOOL launched;
15 | @end
16 |
17 | @implementation Task
18 |
19 | @synthesize task, callback, isRunning,waitUntilExit,environment, arguments, pipeOutput, currentDirectoryPath;
20 |
21 | - (id) initWithWindowController:(WindowController *)aWindowController
22 | {
23 | self = [super init];
24 | if(self) {
25 | self.windowController = aWindowController;
26 | self.webView = aWindowController.webView;
27 | self.isRunning = NO;
28 | self.launched = NO;
29 | self.waitUntilExit = YES;
30 | self.arguments = nil;
31 | self.environment = nil;
32 | self.callback = nil;
33 | self.pipeOutput = NO;
34 |
35 | }
36 |
37 | return self;
38 |
39 | }
40 |
41 | - (JSValue*) createTask: (NSString*) path withCallback: (JSValue*) aCallback
42 | {
43 | task = [[NSTask alloc] init];
44 | if(aCallback && ![aCallback isKindOfClass:[NSNull class]]) {
45 | callback = [JSManagedValue managedValueWithValue:aCallback];
46 | [[[JSContext currentContext] virtualMachine] addManagedReference:callback withOwner:self];
47 | }
48 | task.launchPath = path;
49 | self.environment = task.environment;
50 | [[NSNotificationCenter defaultCenter] addObserver:self
51 | selector:@selector(taskDidTerminate:)
52 | name:NSTaskDidTerminateNotification
53 | object:nil];
54 |
55 | return [JSValue valueWithObject:self inContext:[JSContext currentContext]];
56 | }
57 | - (void) taskDidTerminate: (NSNotification*)notification
58 | {
59 |
60 | NSTask *aTask = notification.object;
61 | int status = [aTask terminationStatus];
62 | NSDictionary *result = nil;
63 |
64 |
65 | if(pipeOutput == YES) {
66 |
67 | NSData *data;
68 | data = [self.outFile readDataToEndOfFile];
69 | NSString *string;
70 | string = [[NSString alloc] initWithData: data
71 | encoding: NSUTF8StringEncoding];
72 | result = @{ @"status" : [NSNumber numberWithInt:status], @"stdOut" : string, @"stdIn" : aTask.standardInput, @"stdErr" : aTask.standardError };
73 | } else {
74 | result = @{ @"status" : [NSNumber numberWithInt:status], @"stdOut" : aTask.standardOutput, @"stdIn" : aTask.standardInput, @"stdErr" : aTask.standardError };
75 |
76 | }
77 |
78 | dispatch_sync(dispatch_get_main_queue(), ^{
79 | [self->callback.value callWithArguments:@[result]];
80 | self->task = nil;
81 | self.isRunning = NO;
82 | self.launched = NO;
83 | self.arguments = nil;
84 | self.environment = nil;
85 | self.callback = nil;
86 | self.outFile = nil;
87 | self.outputPipe = nil;
88 | self.pipeOutput = NO;
89 | });
90 |
91 | }
92 |
93 | - (void) setArguments:(NSArray *)args
94 | {
95 | if(task) {
96 | task.arguments = args;
97 | }
98 | }
99 |
100 | - (void) setCurrentDirectoryPath:(NSString *)path
101 | {
102 |
103 | if(task) {
104 | task.currentDirectoryPath = path;
105 | }
106 |
107 | }
108 |
109 | - (void) setPipeOutput:(BOOL)shouldPipe
110 | {
111 |
112 | if(task) {
113 | if(shouldPipe == YES) {
114 | self.outputPipe = [NSPipe pipe];
115 | [task setStandardOutput: self.outputPipe];
116 | self.outFile = [self.outputPipe fileHandleForReading];
117 | pipeOutput = shouldPipe;
118 | }
119 | }
120 | }
121 |
122 | - (JSValue*) arguments
123 | {
124 | if(task) {
125 | return [JSValue valueWithObject: task.arguments inContext: [JSContext currentContext] ];
126 | }
127 | return nil;
128 | }
129 |
130 | - (void) launch
131 | {
132 | if(task && self.launched == NO) {
133 |
134 | //run task on background thread to prevent UI lockup
135 | dispatch_queue_t taskQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0);
136 | dispatch_async(taskQueue, ^{
137 |
138 |
139 | self.isRunning = YES;
140 |
141 | @try {
142 |
143 | [self->task launch];
144 |
145 | self.launched = YES;
146 |
147 | if(self.waitUntilExit)
148 | {
149 | [self->task waitUntilExit];
150 | }
151 | }
152 |
153 | @catch (NSException *exception) {
154 | NSLog(@"Problem Running Task: %@", [exception description]);
155 | }
156 |
157 | @finally {
158 | self.isRunning = NO;
159 | }
160 | });
161 | }
162 |
163 | }
164 |
165 | - (void) terminate
166 | {
167 | if(self.isRunning) {
168 | [task terminate];
169 | }
170 | }
171 |
172 | - (void) dealloc
173 | {
174 | if(self.isRunning)
175 | [task terminate];
176 | }
177 |
178 | @end
179 |
--------------------------------------------------------------------------------
/MacGap/Classes/Commands/Defaults.m:
--------------------------------------------------------------------------------
1 | //
2 | // Defaults.m
3 | // MG
4 | //
5 | // Created by Tim Debo on 6/1/14.
6 | //
7 | //
8 |
9 | #import "Defaults.h"
10 | #import "WindowController.h"
11 | #import "Event.h"
12 | #import "JSON.h"
13 |
14 | typedef id (^ReturnType)();
15 | typedef void (^SetType)();
16 |
17 | @interface Defaults ()
18 | - (NSString*) addPrefix:(NSString*)key;
19 |
20 | @end
21 |
22 | @implementation Defaults
23 | @synthesize defaults;
24 |
25 | - (id) initWithWindowController:(WindowController *)aWindowController
26 | {
27 | self = [super init];
28 | if(self) {
29 | self.windowController = aWindowController;
30 | self.webView = aWindowController.webView;
31 |
32 | [[NSNotificationCenter defaultCenter] addObserver:self
33 | selector:@selector(defaultsChanged:)
34 | name:NSUserDefaultsDidChangeNotification
35 | object:nil];
36 |
37 | }
38 |
39 | return self;
40 |
41 | }
42 | - (void)dealloc
43 | {
44 | [[NSNotificationCenter defaultCenter] removeObserver: self];
45 | }
46 |
47 | - (JSValue*) defaults
48 | {
49 | return [JSValue valueWithObject: [self defaultsDictionary] inContext: [JSContext currentContext] ];
50 | }
51 |
52 | - (JSValue*) get:(NSString *)key ofType:(NSString *)type
53 | {
54 | if(!key || [key isKindOfClass:[NSNull class]])
55 | return nil;
56 |
57 | if(!type || [type isKindOfClass:[NSNull class]]) {
58 | type = @"string";
59 | }
60 |
61 | NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];
62 | NSString* pfxKey = [self addPrefix:key];
63 | NSDictionary *types = @{
64 | @"string" : ^{ return [prefs stringForKey:pfxKey];},
65 | @"int" : ^{ return [NSNumber numberWithInteger:[prefs integerForKey:pfxKey]]; },
66 | @"bool" : ^{ return [NSNumber numberWithBool:[prefs boolForKey:pfxKey]]; },
67 | @"float" : ^{ return [NSNumber numberWithFloat:[prefs floatForKey:pfxKey]]; },
68 | @"url" : ^{ return [[prefs URLForKey:pfxKey] absoluteString]; },
69 | @"object" : ^{ return [prefs dictionaryForKey:pfxKey]; }
70 | };
71 | id returnVal = nil;
72 | ReturnType theType = types[type];
73 |
74 | if(theType) {
75 | returnVal = theType();
76 | } else {
77 | //nil for now but we really should raise a JS Exception for this..
78 | return nil;
79 | }
80 | return [JSValue valueWithObject: returnVal inContext:[JSContext currentContext]];
81 | }
82 |
83 | - (void) setKey:(NSString*)key withValue: (JSValue*) value ofType: (NSString*) type
84 | {
85 | if(!key || [key isKindOfClass:[NSNull class]])
86 | return;
87 |
88 | if(!type || [type isKindOfClass:[NSNull class]]) {
89 | type = @"string";
90 | }
91 |
92 | NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];
93 | NSString* pfxKey = [self addPrefix:key];
94 |
95 | NSDictionary *types = @{
96 | @"string" : ^{ [prefs setObject: [value toString] forKey:pfxKey]; DebugNSLog(@"Set String: %@", value); },
97 | @"int" : ^{ [prefs setInteger: [value toInt32] forKey:pfxKey]; DebugNSLog(@"Set int: %@",value);},
98 | @"bool" : ^{ [prefs setBool: [value toBool] forKey:pfxKey]; DebugNSLog(@"Set bool: %@",value);},
99 | @"float" : ^{ [prefs setFloat: [[value toNumber] floatValue] forKey:pfxKey]; DebugNSLog(@"Set float: %@",value);},
100 | @"url" : ^{ [prefs setURL:[NSURL URLWithString: [value toString]] forKey:pfxKey]; DebugNSLog(@"Set url: %@",value);},
101 |
102 | };
103 |
104 | ((SetType) types[type])();
105 |
106 | }
107 |
108 | - (void) remove: (NSString*) key
109 | {
110 | NSString* prefixedKey;
111 | prefixedKey = [self addPrefix:key];
112 |
113 | [[NSUserDefaults standardUserDefaults] removeObjectForKey:prefixedKey];
114 | [[NSUserDefaults standardUserDefaults] synchronize];
115 | }
116 |
117 | // Check we have a standard prefix for JS-modified keys, for security purposes.
118 | // If not, add it. This stops JavaScript from ever being able to modify keys
119 | // it did not create.
120 | - (NSString*) addPrefix:(NSString*)key {
121 | NSString* prefix;
122 | prefix = [kWebScriptNamespace stringByAppendingString:@"_"];
123 |
124 | if (![key hasPrefix:prefix]) {
125 | key = [prefix stringByAppendingString:key];
126 | }
127 | return key;
128 | }
129 |
130 | - (void)defaultsChanged:(NSNotification *)notification {
131 | NSDictionary* returnDict = [self defaultsDictionary];
132 | [Event triggerEvent:@"userDefaultsChanged" withArgs:returnDict forWebView:self.webView];
133 | }
134 |
135 | - (NSDictionary*) defaultsDictionary {
136 | NSString* prefix = [kWebScriptNamespace stringByAppendingString:@"_"];
137 | NSMutableDictionary* returnDict = [[NSMutableDictionary alloc] init];
138 |
139 | // Get the user defaults.
140 | NSUserDefaults *defs = [NSUserDefaults standardUserDefaults];
141 | [[defs dictionaryRepresentation] enumerateKeysAndObjectsUsingBlock:^( id key, id val, BOOL *stop) {
142 | if([key hasPrefix: prefix]) {
143 | [returnDict setObject: val forKey: key];
144 | }
145 | }];
146 |
147 | return returnDict;
148 | }
149 |
150 | @end
151 |
--------------------------------------------------------------------------------
/MacGap/Classes/Commands/App.m:
--------------------------------------------------------------------------------
1 | //
2 | // App.m
3 | // MG
4 | //
5 | // Created by Tim Debo on 5/27/14.
6 | //
7 | //
8 |
9 | #import "App.h"
10 | #import "Event.h"
11 |
12 | @interface App ()
13 | @property (readwrite) NSString* applicationPath;
14 | @property (readwrite) NSString* resourcePath;
15 | @property (readwrite) NSString* documentsPath;
16 | @property (readwrite) NSString* libraryPath;
17 | @property (readwrite) NSString* homePath;
18 | @property (readwrite) NSString* tempPath;
19 | @property (readwrite) NSArray* droppedFiles;
20 | @property (readwrite) NSMutableArray* notifications;
21 | @end
22 |
23 | @implementation App
24 |
25 | @synthesize webView, applicationPath, resourcePath, libraryPath, homePath, tempPath, idleTime;
26 |
27 | - (id) initWithWebView:(WebView *) view{
28 | self = [super init];
29 |
30 | if (self) {
31 | NSArray *docPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
32 | NSArray *libPaths = NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES);
33 | self.webView = view;
34 | self.applicationPath = [[NSBundle mainBundle] bundlePath];
35 | self.resourcePath = [[NSBundle mainBundle] resourcePath];
36 | self.documentsPath = [docPaths objectAtIndex:0];
37 | self.libraryPath = [libPaths objectAtIndex:0];
38 | self.homePath = NSHomeDirectory();
39 | self.tempPath = NSTemporaryDirectory();
40 | self.droppedFiles = nil;
41 | self.notifications = [NSMutableArray arrayWithCapacity: 2];
42 |
43 | [[[NSWorkspace sharedWorkspace] notificationCenter] addObserver: self
44 | selector: @selector(receiveSleepNotification:)
45 | name: NSWorkspaceWillSleepNotification object: NULL];
46 | [[[NSWorkspace sharedWorkspace] notificationCenter] addObserver: self
47 | selector: @selector(receiveWakeNotification:)
48 | name: NSWorkspaceDidWakeNotification object: NULL];
49 | [[[NSWorkspace sharedWorkspace] notificationCenter] addObserver: self
50 | selector: @selector(receiveActivateNotification:)
51 | name: NSWorkspaceDidActivateApplicationNotification object: NULL];
52 | }
53 |
54 | return self;
55 | }
56 |
57 | - (void) terminate {
58 | [NSApp terminate:nil];
59 | }
60 |
61 | - (void) activate {
62 | [NSApp activateIgnoringOtherApps:YES];
63 | }
64 |
65 | - (void) hide {
66 | [NSApp hide:nil];
67 | }
68 |
69 | - (void) unhide {
70 | [NSApp unhide:nil];
71 | }
72 |
73 | - (void)beep {
74 | NSBeep();
75 | }
76 |
77 | - (void) bounce {
78 | [NSApp requestUserAttention:NSInformationalRequest];
79 | }
80 |
81 | - (void) addFiles: (NSArray*) files
82 | {
83 | self.droppedFiles = files;
84 | }
85 | - (void)setCustomUserAgent:(NSString *)userAgentString {
86 | [self.webView setCustomUserAgent: userAgentString];
87 | }
88 |
89 | - (void) openURL:(NSString*)url {
90 | [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:url]];
91 | }
92 |
93 | - (void) launch:(NSString *)name {
94 | [[NSWorkspace sharedWorkspace] launchApplication:name];
95 | }
96 |
97 | - (void)receiveSleepNotification:(NSNotification*)note{
98 | [Event triggerEvent:@"sleep" forWebView:self.webView];
99 | }
100 |
101 | - (void) receiveWakeNotification:(NSNotification*)note{
102 | [Event triggerEvent:@"wake" forWebView:self.webView];
103 | }
104 |
105 | - (void) receiveActivateNotification:(NSNotification*)notification{
106 | NSDictionary* userInfo = [notification userInfo];
107 | NSRunningApplication* runningApplication = [userInfo objectForKey:NSWorkspaceApplicationKey];
108 | if (runningApplication) {
109 | NSMutableDictionary* applicationDidGetFocusDict = [[NSMutableDictionary alloc] initWithCapacity:2];
110 | [applicationDidGetFocusDict setObject:runningApplication.localizedName
111 | forKey:@"localizedName"];
112 | [applicationDidGetFocusDict setObject:[runningApplication.bundleURL absoluteString]
113 | forKey:@"bundleURL"];
114 |
115 | [Event triggerEvent:@"appActivated" withArgs:applicationDidGetFocusDict forWebView:self.webView];
116 | }
117 | }
118 |
119 | - (void) notify:(NSDictionary*)aNotification {
120 | NSString* type = [aNotification valueForKey:@"type"];
121 | NSString* uid = [aNotification valueForKey:@"id"];
122 |
123 | if([type isEqualToString:@"sheet"]) {
124 | NSAlert *alert = [[NSAlert alloc] init];
125 | [alert setMessageText:[aNotification valueForKey:@"title"]];
126 | [alert setInformativeText:[aNotification valueForKey:@"content"]];
127 | [alert beginSheetModalForWindow:[[NSApplication sharedApplication] mainWindow]
128 | modalDelegate:self
129 | didEndSelector:nil
130 | contextInfo:nil];
131 |
132 |
133 | } else {
134 | NSUserNotification *notification = [[NSUserNotification alloc] init];
135 |
136 | if(!uid) {
137 | uid =[[NSUUID UUID] UUIDString];
138 |
139 | }
140 |
141 | [notification setTitle:[aNotification valueForKey:@"title"]];
142 | [notification setInformativeText:[aNotification valueForKey:@"content"]];
143 | [notification setSubtitle:[aNotification valueForKey:@"subtitle"]];
144 | [notification setUserInfo:@{ @"id" : uid }];
145 |
146 | if([[aNotification valueForKey:@"sound"] boolValue] == YES || ![aNotification valueForKey:@"sound"] ) {
147 | [notification setSoundName: NSUserNotificationDefaultSoundName];
148 | }
149 | [[NSUserNotificationCenter defaultUserNotificationCenter] deliverNotification:notification];
150 |
151 | [self.notifications addObject:@{ @"id" : uid, @"title" : [aNotification valueForKey: @"title"], @"sentOn" :[NSDate date] }];
152 |
153 | }
154 | }
155 |
156 | - (void) closeNotification:(NSString*)notificationId {
157 | NSUserNotificationCenter *center = [NSUserNotificationCenter defaultUserNotificationCenter];
158 | for(NSUserNotification * deliveredNote in center.deliveredNotifications) {
159 | if ([notificationId isEqualToString:@"*"] || [deliveredNote.userInfo[@"id"] isEqualToString:notificationId]) {
160 | [center removeDeliveredNotification: deliveredNote];
161 | //NSPredicate *predicate = [NSPredicate predicateWithFormat:@"id==%@", notificationId];
162 | NSUInteger noteIdx = [self.notifications indexOfObjectPassingTest: ^BOOL(NSDictionary* obj, NSUInteger idx, BOOL *stop) {
163 | return [[obj valueForKey:@"id"] isEqualToString:notificationId];
164 | }];
165 | if (noteIdx != NSNotFound)
166 | [self.notifications removeObjectAtIndex:noteIdx];
167 | }
168 | }
169 | }
170 |
171 | /*
172 | To get the elapsed time since the previous input event—keyboard, mouse, or tablet—specify kCGAnyInputEventType.
173 | */
174 | - (NSNumber*) idleTime {
175 | CFTimeInterval timeSinceLastEvent = CGEventSourceSecondsSinceLastEventType(kCGEventSourceStateHIDSystemState, kCGAnyInputEventType);
176 |
177 | return [NSNumber numberWithDouble:timeSinceLastEvent];
178 | }
179 |
180 |
181 | @end
182 |
--------------------------------------------------------------------------------
/MacGap/Classes/WebViewDelegate.m:
--------------------------------------------------------------------------------
1 | //
2 | // WebViewDelegate.m
3 | // MG
4 | //
5 | // Created by Tim Debo on 5/20/14.
6 | //
7 | //
8 | #import
9 |
10 | #import "WebViewDelegate.h"
11 | #import "WindowController.h"
12 | #import "MacGap.h"
13 |
14 | @implementation WebViewDelegate
15 |
16 | @synthesize windowController, app, menu, window;
17 |
18 | - (id) initWithMenu:(NSMenu*)aMenu
19 | {
20 | self = [super init];
21 | if (!self)
22 | return nil;
23 |
24 | mainMenu = aMenu;
25 |
26 | return self;
27 | }
28 |
29 |
30 | - (void)webView:(WebView *)sender runOpenPanelForFileButtonWithResultListener:(id < WebOpenPanelResultListener >)resultListener allowMultipleFiles:(BOOL)allowMultipleFiles{
31 |
32 | NSOpenPanel * openDlg = [NSOpenPanel openPanel];
33 |
34 | [openDlg setCanChooseFiles:YES];
35 | [openDlg setCanChooseDirectories:NO];
36 | [openDlg setAllowsMultipleSelection: allowMultipleFiles];
37 |
38 | [openDlg beginWithCompletionHandler:^(NSInteger result){
39 | if (result == NSFileHandlingPanelOKButton) {
40 | NSArray * files = [[openDlg URLs] valueForKey: @"relativePath"];
41 | [resultListener chooseFilenames: files];
42 | } else {
43 | [resultListener cancel];
44 | }
45 | }];
46 | }
47 |
48 | - (void)webView:(WebView *)sender willPerformDragDestinationAction:(WebDragDestinationAction)action forDraggingInfo:(id < NSDraggingInfo >)draggingInfo
49 | {
50 | NSArray *files = nil;
51 | if (action == WebDragDestinationActionDHTML) {
52 | NSPasteboard *pboard = [draggingInfo draggingPasteboard];
53 |
54 | if([[pboard types] containsObject:NSURLPboardType] ) {
55 |
56 | files = [pboard propertyListForType:NSFilenamesPboardType];
57 |
58 | }
59 | }
60 | if(files) {
61 | [app addFiles:files];
62 | }
63 | }
64 |
65 |
66 | - (void) webView:(WebView*)webView addMessageToConsole:(NSDictionary*)message
67 | {
68 | if (![message isKindOfClass:[NSDictionary class]]) {
69 | return;
70 | }
71 |
72 | NSLog(@"JavaScript console: %@:%@: %@",
73 | [[message objectForKey:@"sourceURL"] lastPathComponent], // could be nil
74 | [message objectForKey:@"lineNumber"],
75 | [message objectForKey:@"message"]);
76 | }
77 |
78 | - (void)webView:(WebView *)sender runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WebFrame *)frame
79 | {
80 | NSAlert *alert = [[NSAlert alloc] init];
81 | [alert addButtonWithTitle:@"OK"];
82 | [alert setMessageText:message];
83 | [alert setAlertStyle:NSWarningAlertStyle];
84 | [alert runModal];
85 | }
86 |
87 | - (BOOL)webView:(WebView *)sender runJavaScriptConfirmPanelWithMessage:(NSString *)message initiatedByFrame:(WebFrame *)frame
88 | {
89 | NSAlert *alert = [[NSAlert alloc] init];
90 | [alert addButtonWithTitle:@"Yes"];
91 | [alert addButtonWithTitle:@"No"];
92 | [alert setMessageText:message];
93 | [alert setAlertStyle:NSWarningAlertStyle];
94 |
95 | if ([alert runModal] == NSAlertFirstButtonReturn)
96 | return YES;
97 | else
98 | return NO;
99 | }
100 |
101 | /*
102 | By default the size of a database is set to 0 [1]. When a database is being created
103 | it calls this delegate method to get an increase in quota size - or call an error.
104 | PS this method is defined in WebUIDelegatePrivate and may make it difficult, but
105 | not impossible [2], to get an app accepted into the mac app store.
106 |
107 | Further reading:
108 | [1] http://stackoverflow.com/questions/353808/implementing-a-webview-database-quota-delegate
109 | [2] http://stackoverflow.com/questions/4527905/how-do-i-enable-local-storage-in-my-webkit-based-application/4608549#4608549
110 | */
111 | - (void)webView:(WebView *)sender frame:(WebFrame *)frame exceededDatabaseQuotaForSecurityOrigin:(id) origin database:(NSString *)databaseIdentifier
112 | {
113 | static const unsigned long long defaultQuota = 5 * 1024 * 1024;
114 | if ([origin respondsToSelector: @selector(setQuota:)]) {
115 | [origin performSelector:@selector(setQuota:) withObject:[NSNumber numberWithLongLong: defaultQuota]];
116 | } else {
117 | NSLog(@"could not increase quota for %lld", defaultQuota);
118 | }
119 | }
120 |
121 | - (NSArray *)webView:(WebView *)sender contextMenuItemsForElement:(NSDictionary *)element defaultMenuItems:(NSArray *)defaultMenuItems
122 | {
123 | NSMutableArray *webViewMenuItems = [defaultMenuItems mutableCopy];
124 |
125 | if (webViewMenuItems)
126 | {
127 | NSEnumerator *itemEnumerator = [defaultMenuItems objectEnumerator];
128 | NSMenuItem *menuItem = nil;
129 | while ((menuItem = [itemEnumerator nextObject]))
130 | {
131 | NSInteger tag = [menuItem tag];
132 |
133 | switch (tag)
134 | {
135 | case WebMenuItemTagOpenLinkInNewWindow:
136 | case WebMenuItemTagDownloadLinkToDisk:
137 | case WebMenuItemTagCopyLinkToClipboard:
138 | case WebMenuItemTagOpenImageInNewWindow:
139 | case WebMenuItemTagDownloadImageToDisk:
140 | case WebMenuItemTagCopyImageToClipboard:
141 | case WebMenuItemTagOpenFrameInNewWindow:
142 | case WebMenuItemTagGoBack:
143 | case WebMenuItemTagGoForward:
144 | case WebMenuItemTagStop:
145 | case WebMenuItemTagOpenWithDefaultApplication:
146 | case WebMenuItemTagReload:
147 | [webViewMenuItems removeObjectIdenticalTo: menuItem];
148 | }
149 | }
150 | }
151 |
152 | return webViewMenuItems;
153 | }
154 |
155 | - (WebView *)webView:(WebView *)sender createWebViewWithRequest:(NSURLRequest *)request{
156 | windowController = [[WindowController alloc] initWithRequest:request];
157 | return windowController.webView;
158 | }
159 |
160 | - (void)webViewShow:(WebView *)sender{
161 | [windowController showWindow:sender];
162 | }
163 |
164 | - (void)webView:(WebView *)webView decidePolicyForNewWindowAction:(NSDictionary *)actionInformation request:(NSURLRequest *)request newFrameName:(NSString *)frameName decisionListener:(id < WebPolicyDecisionListener >)listener
165 | {
166 | [[NSWorkspace sharedWorkspace] openURL:[request URL]];
167 | [listener ignore];
168 | }
169 |
170 |
171 | - (void) webView: (WebView*) webView didCreateJavaScriptContext:(JSContext *)context forFrame:(WebFrame *)frame
172 | {
173 | windowController.jsContext = context;
174 |
175 | //Initialize "Always On" commands
176 | if (app == nil) {
177 | app = [[App alloc] initWithWebView:webView];
178 | }
179 |
180 | if(window == nil) {
181 | window = [[Window alloc] initWithWindowController:self.windowController andWebview:webView];
182 | }
183 |
184 | if(menu == nil) {
185 | menu = [Menu menuWithContext:context andMenu:mainMenu ];
186 | }
187 |
188 | context[kWebScriptNamespace] = app;
189 | context[kWebScriptNamespace][@"Window"] = window;
190 | context[kWebScriptNamespace][@"Menu"] = menu;
191 |
192 | //Init user selected plugins
193 | for( NSString* plugin in windowController.pluginsMap) {
194 |
195 | id obj = [[NSClassFromString(plugin)alloc] initWithWindowController: windowController];
196 | NSString *exportName = [obj exportName];
197 | context[kWebScriptNamespace][exportName] = obj;
198 | }
199 | }
200 |
201 | - (void)webView:(WebView *)sender didFinishLoadForFrame:(WebFrame *)frame
202 | {
203 | [Event triggerEvent:@"MacGap.load.complete" forWebView:sender];
204 | }
205 |
206 | @end
207 |
--------------------------------------------------------------------------------
/MacGap/Classes/Commands/Menu.m:
--------------------------------------------------------------------------------
1 | //
2 | // Menu.m
3 | // MG
4 | //
5 | // Created by Tim Debo on 5/20/14.
6 | //
7 | //
8 | #import
9 | #import "Menu.h"
10 | #import "MenuItem.h"
11 |
12 | static char REPRESENTED_OBJECT;
13 |
14 | @interface NSMenu (represented)
15 | @property (strong) id representedObject;
16 | @end
17 |
18 | @implementation NSMenu (represented)
19 |
20 | - (id) representedObject
21 | {
22 | return objc_getAssociatedObject(self, &REPRESENTED_OBJECT);
23 | }
24 |
25 | - (void) setRepresentedObject:(id)representedObject
26 | {
27 | objc_setAssociatedObject(self,
28 | &REPRESENTED_OBJECT,
29 | representedObject,
30 | OBJC_ASSOCIATION_RETAIN);
31 | }
32 |
33 | @end
34 |
35 | @interface Menu ()
36 | @property (readwrite) NSString* type;
37 | @property (readwrite) NSArray* menuItems;
38 | @end;
39 |
40 | @implementation Menu
41 |
42 | @synthesize menu;
43 |
44 | + (Menu*) menuWithContext: (JSContext*) context andMenu: (NSMenu*) aMenu
45 | {
46 | Menu *ret = [aMenu representedObject];
47 | if (ret)
48 | {
49 | NSLog(@"MP cache hit");
50 | return ret;
51 | }
52 | return [[Menu alloc] initWithMenu:aMenu forContext:context];
53 | }
54 |
55 | - (Menu*) initWithMenu: (NSMenu*) aMenu forContext: (JSContext*) context{
56 |
57 | return [self initWithMenu: aMenu andType: nil forContext:context];
58 | }
59 |
60 | - (Menu*) initWithMenu: (NSMenu*) aMenu andType: (NSString*) type forContext: (JSContext*) aContext{
61 | self = [super initWithContext: aContext];
62 | if (self) {
63 |
64 | menu = aMenu;
65 | menu.representedObject = self;
66 | self.type = type;
67 | NSArray* items = aMenu.itemArray;
68 | NSMutableArray* itemsArr = nil;
69 | if(items)
70 | {
71 | itemsArr = [NSMutableArray arrayWithCapacity: items.count];
72 | for( NSMenuItem* item in items) {
73 | [itemsArr addObject: [MenuItem menuItemWithContext:aContext andMenu:item] ];
74 | }
75 |
76 | }
77 | self.menuItems = itemsArr;
78 | self.context = aContext;
79 |
80 | }
81 | return self;
82 | }
83 |
84 | - (JSValue*) create: (NSString*) title type: (NSString*) type
85 | {
86 | NSMenu* newMenu = [[NSMenu alloc] initWithTitle:title];
87 | Menu* theMenu = [[Menu alloc] initWithMenu:newMenu forContext: [JSContext currentContext]];
88 | theMenu.type = type;
89 |
90 | return [JSValue valueWithObject:theMenu inContext:[JSContext currentContext]];
91 | }
92 |
93 | - (JSValue*) addItem: (NSDictionary*) props callback: (JSValue*) aCallback
94 | {
95 |
96 | NSString* title = [props valueForKey: @"label"];
97 | NSString* cmds = [props valueForKey: @"keys"];
98 | NSNumber* index = [props valueForKey: @"index"];
99 | NSString *key = nil;
100 | NSMenuItem *item = nil;
101 |
102 | if (title == nil || [title isKindOfClass: [NSNull class]])
103 | title = @"";
104 |
105 | if (cmds != nil && ![cmds isKindOfClass: [NSNull class]]) {
106 | key = [Menu getKeyFromString:cmds];
107 | } else {
108 | key = @"";
109 | }
110 |
111 | if(index != nil && ![index isKindOfClass:[NSNull class]]) {
112 | item = [menu insertItemWithTitle:title action:nil keyEquivalent:key atIndex:[index integerValue] ];
113 | } else {
114 | item = [menu addItemWithTitle:title action:nil keyEquivalent:key ];
115 |
116 | }
117 |
118 | NSUInteger modifiers = [Menu getModifiersFromString:cmds];
119 | [item setKeyEquivalentModifierMask:modifiers];
120 |
121 | if(!menu.supermenu && ![_type isEqualToString:@"statusbar"]) {
122 | NSMenu *s = [[NSMenu alloc] initWithTitle: title];
123 |
124 | [item setSubmenu:s];
125 | }
126 |
127 | MenuItem* menuItem = [MenuItem menuItemWithContext:self.context andMenu:item];
128 |
129 | if(aCallback != nil && ![aCallback isKindOfClass: [NSNull class]]) {
130 |
131 | [menuItem setCallback:aCallback];
132 |
133 | }
134 |
135 | [menu setAutoenablesItems:NO];
136 |
137 | return [JSValue valueWithObject:menuItem inContext:self.context ];
138 |
139 | }
140 |
141 | - (JSValue*) addSeparator
142 | {
143 | NSMenuItem *sep = [NSMenuItem separatorItem];
144 | [self.menu addItem:sep];
145 | return [JSValue valueWithObject: self inContext:JSContext.currentContext];
146 |
147 | }
148 |
149 | - (JSValue*)itemForKey:(id)key
150 | {
151 | if (!key || [key isKindOfClass: [NSNull class]])
152 | return nil;
153 |
154 | NSMenuItem *item = nil;
155 | if ([key isKindOfClass:[NSNumber class]])
156 | {
157 | if([key intValue] >= [[menu itemArray] count]) {
158 | return nil;
159 | }
160 |
161 | item = [menu itemAtIndex:[key intValue]];
162 | }
163 | else if ([key isKindOfClass:[NSString class]])
164 | {
165 | item = [menu itemWithTitle:key];
166 | if (!item)
167 | {
168 | // Try again, with ... appended. e.g. "Save..."
169 | item = [menu itemWithTitle:
170 | [key stringByAppendingString:@"\u2026"]];
171 | }
172 | }
173 | if (!item)
174 | return nil;
175 |
176 | MenuItem *mi = [MenuItem menuItemWithContext:self.context andMenu:item]; //[[MenuItem alloc] initWithContext:[JSContext currentContext] andMenuItem:item];
177 |
178 | return [JSValue valueWithObject: mi inContext: self.context];
179 | }
180 |
181 |
182 | + (NSString*)getKeyFromString:(NSString*)keyCommand {
183 | if (keyCommand == nil || [keyCommand isKindOfClass: [NSNull class]])
184 | keyCommand = @"";
185 |
186 | // Obtain the key (if there are modifiers, it will be the last character).
187 | NSString *aKey = @"";
188 | if ([keyCommand length] > 0) {
189 | aKey = [keyCommand substringFromIndex:[keyCommand length] - 1];
190 | }
191 |
192 | return aKey;
193 | }
194 |
195 | + (NSUInteger)getModifiersFromString:(NSString*)keyCommand {
196 | if (keyCommand == nil || [keyCommand isKindOfClass: [NSNull class]])
197 | return 0;
198 | // aKeys may optionally specify one or more modifiers.
199 | NSUInteger modifiers = 0;
200 |
201 | if ([keyCommand rangeOfString:@"caps"].location != NSNotFound) modifiers += NSAlphaShiftKeyMask;
202 | if ([keyCommand rangeOfString:@"shift"].location != NSNotFound) modifiers += NSShiftKeyMask;
203 | if ([keyCommand rangeOfString:@"cmd"].location != NSNotFound) modifiers += NSCommandKeyMask;
204 | if ([keyCommand rangeOfString:@"ctrl"].location != NSNotFound) modifiers += NSControlKeyMask;
205 | if ([keyCommand rangeOfString:@"opt"].location != NSNotFound) modifiers += NSAlternateKeyMask;
206 | if ([keyCommand rangeOfString:@"alt"].location != NSNotFound) modifiers += NSAlternateKeyMask;
207 |
208 | return modifiers;
209 | }
210 |
211 | - (NSMenu*)removeItem:(id)key
212 | {
213 | if(key == nil || [key isKindOfClass: [NSNull class]]) {
214 | return nil;
215 | }
216 |
217 | NSMenuItem *item = nil;
218 |
219 | if ([key isKindOfClass:[NSNumber class]])
220 | {
221 | item = [menu itemAtIndex:[key intValue]];
222 | }
223 | else if ([key isKindOfClass:[NSString class]])
224 | {
225 | item = [menu itemWithTitle:key];
226 | if (!item)
227 | {
228 | // Try again, with ... appended. e.g. "Save..."
229 | item = [menu itemWithTitle:
230 | [key stringByAppendingString:@"\u2026"]];
231 | }
232 | }
233 | if (!item)
234 | return nil;
235 |
236 | [menu removeItem:item];
237 | return menu;
238 | }
239 |
240 | - (void) dealloc
241 | {
242 | NSLog(@"Menu Deallocated");
243 | menu.representedObject = nil;
244 | }
245 |
246 | @end
247 |
--------------------------------------------------------------------------------
/MacGap/Classes/Commands/Window.m:
--------------------------------------------------------------------------------
1 | //
2 | // Window.m
3 | // MG
4 | //
5 | // Created by Tim Debo on 5/20/14.
6 | //
7 | //
8 |
9 | #import "AppDelegate.h"
10 | #import "Window.h"
11 | #import "WindowController.h"
12 | #import
13 | #import "Event.h"
14 |
15 | @interface Window ()
16 | {
17 | NSRect _oldRestoreFrame;
18 | NSSize _oldMaxSize;
19 | }
20 | @property (nonatomic, retain) WindowController *windowController;
21 | @property (nonatomic, retain) WebView *webView;
22 | @property (readwrite) BOOL isMaximized;
23 | @property (readwrite) CGFloat x;
24 | @property (readwrite) CGFloat y;
25 |
26 | - (void) registerEvents;
27 | - (void) triggerEvent:(NSString*) event;
28 | - (void) triggerEvent: (NSString*) event withArgs: (NSDictionary*) args;
29 | - (void) windowResized:(NSNotification*)notification;
30 | - (void) windowMinimized:(NSNotification*)notification;
31 |
32 | @end
33 |
34 | @implementation Window
35 |
36 | @synthesize isMaximized, x, y;
37 |
38 | - (Window*) initWithWindowController: (WindowController*)windowController andWebview: (WebView*) webView
39 | {
40 | self = [super init];
41 | if(self) {
42 | self.windowController = windowController;
43 | self.webView = webView;
44 | self.x = [self getX];
45 | self.y = [self getY];
46 | self.isMaximized = NO;
47 |
48 | [self registerEvents];
49 | }
50 | return self;
51 | }
52 |
53 |
54 | - (CGFloat) getX {
55 | NSRect frame = [self.webView window].frame;
56 | return frame.origin.x;
57 | }
58 |
59 | - (CGFloat) getY {
60 | NSRect frame = [self.webView window].frame;
61 | return frame.origin.y;
62 | }
63 |
64 | - (void) open:(NSString *)url
65 | {
66 | WindowController* newWindow = [[WindowController alloc] initWithURL: url];
67 | [newWindow showWindow: [NSApplication sharedApplication].delegate];
68 | [newWindow.window makeKeyWindow];
69 | [newWindow.window setReleasedWhenClosed:YES];
70 | // self.windowController = [[WindowController alloc] initWithURL:[properties valueForKey:@"url"]];
71 | // [self.windowController showWindow: [NSApplication sharedApplication].delegate];
72 | // [self.windowController.window makeKeyWindow];
73 | }
74 |
75 |
76 | // Reopen the first window that was opened.
77 | - (void) reopenFirst
78 | {
79 | AppDelegate *appDelegate = (AppDelegate *)[[NSApplication sharedApplication] delegate];
80 | [appDelegate.windowController.window makeKeyAndOrderFront: nil];
81 | }
82 |
83 | - (void) title: (NSString*) title
84 | {
85 | [self.windowController.window setTitle:title];
86 | }
87 |
88 | - (void) minimize {
89 | [self.windowController.window miniaturize:[NSApp mainWindow]];
90 | }
91 |
92 | - (void) toggleFullscreen {
93 | [self.windowController.window toggleFullScreen:[NSApp mainWindow]];
94 | }
95 |
96 | - (void) maximize {
97 | NSRect a = self.windowController.window.frame;
98 | _oldRestoreFrame = NSMakeRect(a.origin.x, a.origin.y, a.size.width, a.size.height);
99 |
100 | [self.windowController.window setFrame:[[NSScreen mainScreen] visibleFrame] display:YES];
101 | }
102 |
103 | - (void) move: (NSNumber*) xCoord y: (NSNumber*) yCoord
104 | {
105 | NSRect frame = [self.webView window].frame;
106 | frame.origin.x = [xCoord integerValue];
107 | frame.origin.y = [yCoord integerValue];
108 | [self.windowController.window setFrame:frame display:YES];
109 | }
110 |
111 | - (void) resize: (NSNumber*) width height: (NSNumber*) height
112 | {
113 | NSRect frame = [self.webView window].frame;
114 | frame.size.width = [width integerValue];
115 | frame.size.height = [height integerValue];
116 | [self.windowController.window setFrame:frame display:YES];
117 | }
118 |
119 | - (void) restore
120 | {
121 | [self.windowController.window setFrame:_oldRestoreFrame display:YES];
122 | }
123 |
124 | - (void) registerEvents
125 | {
126 | [[NSNotificationCenter defaultCenter] addObserver:self
127 | selector:@selector(windowResized:)
128 | name:NSWindowDidResizeNotification
129 | object: self.windowController.window];
130 |
131 | [[NSNotificationCenter defaultCenter] addObserver:self
132 | selector:@selector(windowRestored:)
133 | name:NSWindowDidDeminiaturizeNotification
134 | object: self.windowController.window];
135 |
136 | [[NSNotificationCenter defaultCenter] addObserver:self
137 | selector:@selector(windowMinimized:)
138 | name:NSWindowDidMiniaturizeNotification
139 | object: self.windowController.window];
140 |
141 | [[NSNotificationCenter defaultCenter] addObserver:self
142 | selector:@selector(windowEnterFullscreen:)
143 | name:NSWindowDidEnterFullScreenNotification
144 | object: self.windowController.window];
145 |
146 | [[NSNotificationCenter defaultCenter] addObserver:self
147 | selector:@selector(windowWillEnterFullscreen:)
148 | name:NSWindowWillEnterFullScreenNotification
149 | object: self.windowController.window];
150 |
151 | [[NSNotificationCenter defaultCenter] addObserver:self
152 | selector:@selector(windowExitFullscreen:)
153 | name:NSWindowDidExitFullScreenNotification
154 | object: self.windowController.window];
155 |
156 | [[NSNotificationCenter defaultCenter] addObserver:self
157 | selector:@selector(windowClosed:)
158 | name:NSWindowWillCloseNotification
159 | object: self.windowController.window];
160 | }
161 |
162 | - (void) windowClosed: (NSNotification*)notification
163 | {
164 | self.webView = nil;
165 | self.windowController = nil;
166 | }
167 |
168 | - (void) windowResized:(NSNotification*)notification
169 | {
170 | NSWindow* window = (NSWindow*)notification.object;
171 | NSSize size = [window frame].size;
172 | bool isFullScreen = (window.styleMask & NSFullScreenWindowMask) == NSFullScreenWindowMask;
173 |
174 |
175 | NSMutableDictionary* sizes = [NSMutableDictionary dictionaryWithCapacity:3];
176 | [sizes setObject: [NSNumber numberWithInt:size.width] forKey:@"width"];
177 | [sizes setObject: [NSNumber numberWithInt:size.height] forKey:@"height"];
178 | [sizes setObject: [NSNumber numberWithBool:isFullScreen] forKey:@"fullscreen"];
179 |
180 |
181 | [self triggerEvent:@"resize" withArgs:sizes];
182 | }
183 |
184 | - (void) windowMinimized:(NSNotification*)notification
185 | {
186 | [self triggerEvent:@"minimized"];
187 | }
188 |
189 | - (void) windowRestored:(NSNotification*)notification
190 | {
191 | [self triggerEvent:@"restore"];
192 | }
193 |
194 | - (void) windowWillEnterFullscreen:(NSNotification*)notification
195 | {
196 | NSWindow* window = (NSWindow*)notification.object;
197 | _oldMaxSize = window.maxSize;
198 | [window setMaxSize: NSMakeSize(FLT_MAX, FLT_MAX)];
199 | }
200 |
201 | - (void) windowEnterFullscreen:(NSNotification*)notification
202 | {
203 | [self triggerEvent:@"enter-fullscreen"];
204 | }
205 |
206 | - (void) windowExitFullscreen:(NSNotification*)notification
207 | {
208 | NSWindow* window = (NSWindow*)notification.object;
209 |
210 | if(_oldMaxSize.width){
211 | [window setMaxSize:_oldMaxSize];
212 | }
213 |
214 | [self triggerEvent:@"leave-fullscreen"];
215 | }
216 |
217 | - (void) triggerEvent:(NSString *)event
218 | {
219 | [self triggerEvent: event withArgs: nil];
220 | }
221 |
222 | - (void) triggerEvent: (NSString*) event withArgs: (NSDictionary*) args
223 | {
224 | [Event triggerEvent: event withArgs: args forObject:@"window" forWebView:self.webView];
225 | }
226 |
227 |
228 | @end;
229 |
--------------------------------------------------------------------------------
/MacGap/Classes/WindowController.m:
--------------------------------------------------------------------------------
1 | //
2 | // WindowController.m
3 | // MG
4 | //
5 | // Created by Tim Debo on 5/19/14.
6 | //
7 | //
8 |
9 | #import "WindowController.h"
10 | #import "WebViewDelegate.h"
11 | #import "DraggableView.h"
12 | #import "JSON.h"
13 |
14 | @interface WindowController ()
15 |
16 | @property (nonatomic, readwrite, strong) NSMutableDictionary* settings;
17 | @property (nonatomic, readwrite, strong) NSMutableDictionary* pluginObjects;
18 | @property (nonatomic, readwrite, strong) NSArray* startupPluginNames;
19 | @property (nonatomic, readwrite, strong) NSDictionary* pluginsMap;
20 | @property (nonatomic, readwrite, assign) BOOL loadFromString;
21 | @property (readwrite, assign) BOOL initialized;
22 |
23 |
24 | -(void) setWindowParams;
25 |
26 | @end
27 |
28 | @interface WebPreferences (WebPreferencesPrivate)
29 | - (void)_setLocalStorageDatabasePath:(NSString *)path;
30 | - (void) setLocalStorageEnabled: (BOOL) localStorageEnabled;
31 | - (void) setDatabasesEnabled:(BOOL)databasesEnabled;
32 | - (void) setDeveloperExtrasEnabled:(BOOL)developerExtrasEnabled;
33 | - (void) setWebGLEnabled:(BOOL)webGLEnabled;
34 | - (void) setOfflineWebApplicationCacheEnabled:(BOOL)offlineWebApplicationCacheEnabled;
35 | @end
36 |
37 |
38 | @implementation WindowController
39 |
40 | @synthesize webView, url, initialized, webViewDelegate, jsContext;
41 |
42 |
43 | - (id)initWithWindow:(NSWindow *)aWindow
44 | {
45 | self = [super initWithWindow:aWindow];
46 | if (self) {
47 |
48 | }
49 | return self;
50 | }
51 |
52 | - (void)windowDidLoad
53 | {
54 | [super windowDidLoad];
55 |
56 | [self.webView setMainFrameURL:[self.url absoluteString]];
57 |
58 |
59 | }
60 |
61 | - (id) initWithURL:(NSString *) relativeURL{
62 |
63 | self = [super initWithWindowNibName:@"MainWindow"];
64 |
65 |
66 | self.url = [NSURL URLWithString:relativeURL relativeToURL:[[NSBundle mainBundle] resourceURL]];
67 |
68 | [self.window setFrameAutosaveName:@"MacGapWindow"];
69 |
70 | return self;
71 | }
72 |
73 | -(id) initWithRequest: (NSURLRequest *)request{
74 | self = [super initWithWindowNibName:@"MainWindow"];
75 |
76 | [[self.webView mainFrame] loadRequest:request];
77 |
78 | return self;
79 | }
80 |
81 |
82 | - (void) awakeFromNib
83 | {
84 | WebPreferences *webPrefs = [WebPreferences standardPreferences];
85 |
86 | NSString *cappBundleName = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleName"];
87 | NSString *applicationSupportFile = [@"~/Library/Application Support/" stringByExpandingTildeInPath];
88 | NSString *savePath = [NSString pathWithComponents:[NSArray arrayWithObjects:applicationSupportFile, cappBundleName, @"LocalStorage", nil]];
89 |
90 | NSString *configPath = [[NSBundle mainBundle] pathForResource:@"./public/config" ofType:@"json"];
91 | NSMutableDictionary *config = [[[NSString alloc] initWithContentsOfFile:configPath encoding:NSUTF8StringEncoding error:NULL] JSONObject];
92 |
93 | NSDictionary *plugins = [config objectForKey:@"plugins"];
94 | self.pluginsMap = plugins;
95 | self.settings = config;
96 |
97 | [webPrefs _setLocalStorageDatabasePath:savePath];
98 | [webPrefs setLocalStorageEnabled:YES];
99 | [webPrefs setDatabasesEnabled:YES];
100 | [webPrefs setDeveloperExtrasEnabled:[[NSUserDefaults standardUserDefaults] boolForKey: @"developer"]];
101 | [webPrefs setOfflineWebApplicationCacheEnabled:YES];
102 | [webPrefs setWebGLEnabled:YES];
103 |
104 | [self.webView setPreferences:webPrefs];
105 |
106 | NSHTTPCookieStorage *cookieStorage = [NSHTTPCookieStorage
107 | sharedHTTPCookieStorage];
108 | [cookieStorage setCookieAcceptPolicy:NSHTTPCookieAcceptPolicyAlways];
109 |
110 | [self.webView setApplicationNameForUserAgent: @"MacGap"];
111 |
112 | self.webViewDelegate = [[WebViewDelegate alloc] initWithMenu:[NSApp mainMenu]];
113 | self.webViewDelegate.windowController = self;
114 |
115 | [self.webView setFrameLoadDelegate:self.webViewDelegate];
116 | [self.webView setUIDelegate:self.webViewDelegate];
117 | [self.webView setResourceLoadDelegate:self.webViewDelegate];
118 | [self.webView setDownloadDelegate:self.webViewDelegate];
119 | [self.webView setPolicyDelegate:self.webViewDelegate];
120 | [self.webView setDrawsBackground:NO];
121 | [self.webView setShouldCloseWithWindow:NO];
122 | [self.webView setGroupName:@"MacGap"];
123 | self.pluginObjects = [[NSMutableDictionary alloc] initWithCapacity:20];
124 |
125 | notificationProvider = [[NotificationProvider alloc] init];
126 | [self.webView _setNotificationProvider:notificationProvider];
127 | }
128 |
129 | - (void) setWindowParams
130 | {
131 | NSDictionary* params = [self.settings objectForKey:@"window"];
132 |
133 | NSRect frame = [[self window] frame];
134 |
135 | if([params objectForKey:@"width"] != nil) {
136 | frame.size.width = [[params objectForKey:@"width"] doubleValue];
137 | }
138 |
139 | if([params objectForKey:@"height"]) {
140 | frame.size.height = [[params objectForKey:@"height"] doubleValue];
141 |
142 | }
143 |
144 | if([params objectForKey:@"min_width"] && [params objectForKey:@"min_height"]) {
145 | [self.window setMinSize: NSMakeSize( [[params objectForKey:@"min_width"] doubleValue], [[params objectForKey:@"min_height"] doubleValue] ) ];
146 | }
147 |
148 | if([params objectForKey:@"max_width"] && [params objectForKey:@"max_height"]) {
149 | [self.window setMaxSize: NSMakeSize( [[params objectForKey:@"max_width"] doubleValue], [[params objectForKey:@"max_height"] doubleValue] ) ];
150 | }
151 |
152 |
153 | if([params objectForKey:@"title"]) {
154 | [[self window] setTitle: [params objectForKey:@"title"]];
155 | }
156 |
157 |
158 | if([[params objectForKey:@"position"] isEqualToString:@"center"]) {
159 | [[self window] center];
160 | }
161 |
162 | if([params objectForKey:@"opaque"]) {
163 | [[self window] setOpaque: [[params objectForKey:@"opaque"] boolValue]];
164 | }
165 |
166 | if([params objectForKey:@"alpha"]) {
167 | NSColor *backgroundColor = [NSColor colorWithDeviceRed:0.0 green:0.0 blue:0.0 alpha:[[params objectForKey:@"alpha"] doubleValue]];
168 | [[self window] setBackgroundColor: backgroundColor];
169 | }
170 |
171 | NSDictionary* titlebarParams = [params objectForKey:@"titlebar"];
172 |
173 | if(![[titlebarParams objectForKey:@"visible"] boolValue]) {
174 | self.window.titleVisibility = NSWindowTitleHidden;
175 | self.window.titlebarAppearsTransparent = YES;
176 | self.window.styleMask |= NSFullSizeContentViewWindowMask;
177 | }
178 |
179 | if([[titlebarParams objectForKey:@"draggable"] boolValue]) {
180 | int height = 22;
181 | if([titlebarParams objectForKey:@"height"]) {
182 | height = [[titlebarParams objectForKey:@"height"] doubleValue];
183 | }
184 | DraggableView *draggableView = [[DraggableView alloc] initWithFrame:[[self.window contentView] bounds]];
185 | draggableView.frame = CGRectMake(0, self.window.contentView.bounds.size.height-height, draggableView.frame.size.width, height);
186 | draggableView.autoresizingMask = 1 << 1 | 1 << 3;
187 | [[self.window contentView] addSubview:draggableView];
188 | }
189 |
190 | [[self window] setFrame:frame display: YES];
191 | }
192 |
193 | #pragma mark -
194 | #pragma mark Plugin Registration
195 |
196 |
197 | - (void)registerPlugin:(Command*)plugin withClassName:(NSString*)className
198 | {
199 | if ([plugin respondsToSelector:@selector(setWindowController:)]) {
200 | [plugin setWindowController:self];
201 | }
202 |
203 |
204 | [self.pluginObjects setObject:plugin forKey:className];
205 | [plugin initializePlugin];
206 | }
207 |
208 | - (void)registerPlugin:(Command*)plugin withPluginName:(NSString*)pluginName
209 | {
210 | if ([plugin respondsToSelector:@selector(setWindowController:)]) {
211 | [plugin setWindowController:self];
212 | }
213 |
214 |
215 | NSString* className = NSStringFromClass([plugin class]);
216 | [self.pluginObjects setObject:plugin forKey:className];
217 | [self.pluginsMap setValue:className forKey:[pluginName lowercaseString]];
218 | [plugin initializePlugin];
219 | }
220 |
221 |
222 | - (id)getCommandInstance:(NSString*)pluginName
223 | {
224 |
225 | NSString* className = [self.pluginsMap objectForKey:[pluginName lowercaseString]];
226 | if (className == nil) {
227 | className = [self.pluginsMap objectForKey:pluginName];
228 |
229 | if(className == nil)
230 | return nil;
231 | }
232 |
233 | id obj = [self.pluginObjects objectForKey:className];
234 | if (!obj) {
235 | obj = [[NSClassFromString(className)alloc] initWithWebView:webView];
236 |
237 | if (obj != nil) {
238 | [self registerPlugin:obj withClassName:className];
239 | } else {
240 | NSLog(@"Plugin class %@ (pluginName: %@) does not exist.", className, pluginName);
241 | }
242 | }
243 | return obj;
244 | }
245 |
246 |
247 |
248 | @end
249 |
--------------------------------------------------------------------------------
/MacGap/Categories/NSData+Base64.m:
--------------------------------------------------------------------------------
1 | //
2 | // NSData+Base64.m
3 | // MG
4 | //
5 | // Created by Tim Debo on 5/20/14.
6 | //
7 | //
8 |
9 | #import "NSData+Base64.h"
10 |
11 | //
12 | // Mapping from 6 bit pattern to ASCII character.
13 | //
14 | static unsigned char base64EncodeLookup[65] =
15 | "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
16 |
17 | //
18 | // Definition for "masked-out" areas of the base64DecodeLookup mapping
19 | //
20 | #define xx 65
21 |
22 | //
23 | // Mapping from ASCII character to 6 bit pattern.
24 | //
25 | static unsigned char base64DecodeLookup[256] =
26 | {
27 | xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx,
28 | xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx,
29 | xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, 62, xx, xx, xx, 63,
30 | 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, xx, xx, xx, xx, xx, xx,
31 | xx, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
32 | 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, xx, xx, xx, xx, xx,
33 | xx, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
34 | 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, xx, xx, xx, xx, xx,
35 | xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx,
36 | xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx,
37 | xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx,
38 | xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx,
39 | xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx,
40 | xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx,
41 | xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx,
42 | xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx,
43 | };
44 |
45 | //
46 | // Fundamental sizes of the binary and base64 encode/decode units in bytes
47 | //
48 | #define _BINARY_UNIT_SIZE 3
49 | #define _BASE64_UNIT_SIZE 4
50 |
51 | //
52 | // NewBase64Decode
53 | //
54 | // Decodes the base64 ASCII string in the inputBuffer to a newly malloced
55 | // output buffer.
56 | //
57 | // inputBuffer - the source ASCII string for the decode
58 | // length - the length of the string or -1 (to specify strlen should be used)
59 | // outputLength - if not-NULL, on output will contain the decoded length
60 | //
61 | // returns the decoded buffer. Must be freed by caller. Length is given by
62 | // outputLength.
63 | //
64 | void *NewBase64Decode(
65 | const char* inputBuffer,
66 | size_t length,
67 | size_t * outputLength)
68 | {
69 | if (length == -1) {
70 | length = strlen(inputBuffer);
71 | }
72 |
73 | size_t outputBufferSize = (length / _BASE64_UNIT_SIZE) * _BINARY_UNIT_SIZE;
74 | unsigned char* outputBuffer = (unsigned char*)malloc(outputBufferSize);
75 |
76 | size_t i = 0;
77 | size_t j = 0;
78 |
79 | while (i < length) {
80 | //
81 | // Accumulate 4 valid characters (ignore everything else)
82 | //
83 | unsigned char accumulated[_BASE64_UNIT_SIZE];
84 | bzero(accumulated, sizeof(unsigned char) * _BASE64_UNIT_SIZE);
85 | size_t accumulateIndex = 0;
86 |
87 | while (i < length) {
88 | unsigned char decode = base64DecodeLookup[inputBuffer[i++]];
89 | if (decode != xx) {
90 | accumulated[accumulateIndex] = decode;
91 | accumulateIndex++;
92 |
93 | if (accumulateIndex == _BASE64_UNIT_SIZE) {
94 | break;
95 | }
96 | }
97 | }
98 |
99 | //
100 | // Store the 6 bits from each of the 4 characters as 3 bytes
101 | //
102 | outputBuffer[j] = (accumulated[0] << 2) | (accumulated[1] >> 4);
103 | outputBuffer[j + 1] = (accumulated[1] << 4) | (accumulated[2] >> 2);
104 | outputBuffer[j + 2] = (accumulated[2] << 6) | accumulated[3];
105 | j += accumulateIndex - 1;
106 | }
107 |
108 | if (outputLength) {
109 | *outputLength = j;
110 | }
111 | return outputBuffer;
112 | }
113 |
114 | //
115 | // NewBase64Decode
116 | //
117 | // Encodes the arbitrary data in the inputBuffer as base64 into a newly malloced
118 | // output buffer.
119 | //
120 | // inputBuffer - the source data for the encode
121 | // length - the length of the input in bytes
122 | // separateLines - if zero, no CR/LF characters will be added. Otherwise
123 | // a CR/LF pair will be added every 64 encoded chars.
124 | // outputLength - if not-NULL, on output will contain the encoded length
125 | // (not including terminating 0 char)
126 | //
127 | // returns the encoded buffer. Must be freed by caller. Length is given by
128 | // outputLength.
129 | //
130 | char *NewBase64Encode(
131 | const void* buffer,
132 | size_t length,
133 | bool separateLines,
134 | size_t * outputLength)
135 | {
136 | const unsigned char* inputBuffer = (const unsigned char*)buffer;
137 |
138 | #define MAX_NUM_PADDING_CHARS 2
139 | #define OUTPUT_LINE_LENGTH 64
140 | #define INPUT_LINE_LENGTH ((OUTPUT_LINE_LENGTH / _BASE64_UNIT_SIZE) * _BINARY_UNIT_SIZE)
141 | #define CR_LF_SIZE 0
142 |
143 | //
144 | // Byte accurate calculation of final buffer size
145 | //
146 | size_t outputBufferSize =
147 | ((length / _BINARY_UNIT_SIZE)
148 | + ((length % _BINARY_UNIT_SIZE) ? 1 : 0))
149 | * _BASE64_UNIT_SIZE;
150 | if (separateLines) {
151 | outputBufferSize +=
152 | (outputBufferSize / OUTPUT_LINE_LENGTH) * CR_LF_SIZE;
153 | }
154 |
155 | //
156 | // Include space for a terminating zero
157 | //
158 | outputBufferSize += 1;
159 |
160 | //
161 | // Allocate the output buffer
162 | //
163 | char* outputBuffer = (char*)malloc(outputBufferSize);
164 | if (!outputBuffer) {
165 | return NULL;
166 | }
167 |
168 | size_t i = 0;
169 | size_t j = 0;
170 | const size_t lineLength = separateLines ? INPUT_LINE_LENGTH : length;
171 | size_t lineEnd = lineLength;
172 |
173 | while (true) {
174 | if (lineEnd > length) {
175 | lineEnd = length;
176 | }
177 |
178 | for (; i + _BINARY_UNIT_SIZE - 1 < lineEnd; i += _BINARY_UNIT_SIZE) {
179 | //
180 | // Inner loop: turn 48 bytes into 64 base64 characters
181 | //
182 | outputBuffer[j++] = base64EncodeLookup[(inputBuffer[i] & 0xFC) >> 2];
183 | outputBuffer[j++] = base64EncodeLookup[((inputBuffer[i] & 0x03) << 4)
184 | | ((inputBuffer[i + 1] & 0xF0) >> 4)];
185 | outputBuffer[j++] = base64EncodeLookup[((inputBuffer[i + 1] & 0x0F) << 2)
186 | | ((inputBuffer[i + 2] & 0xC0) >> 6)];
187 | outputBuffer[j++] = base64EncodeLookup[inputBuffer[i + 2] & 0x3F];
188 | }
189 |
190 | if (lineEnd == length) {
191 | break;
192 | }
193 |
194 | //
195 | // Add the newline
196 | //
197 | // outputBuffer[j++] = '\r';
198 | // outputBuffer[j++] = '\n';
199 | lineEnd += lineLength;
200 | }
201 |
202 | if (i + 1 < length) {
203 | //
204 | // Handle the single '=' case
205 | //
206 | outputBuffer[j++] = base64EncodeLookup[(inputBuffer[i] & 0xFC) >> 2];
207 | outputBuffer[j++] = base64EncodeLookup[((inputBuffer[i] & 0x03) << 4)
208 | | ((inputBuffer[i + 1] & 0xF0) >> 4)];
209 | outputBuffer[j++] = base64EncodeLookup[(inputBuffer[i + 1] & 0x0F) << 2];
210 | outputBuffer[j++] = '=';
211 | } else if (i < length) {
212 | //
213 | // Handle the double '=' case
214 | //
215 | outputBuffer[j++] = base64EncodeLookup[(inputBuffer[i] & 0xFC) >> 2];
216 | outputBuffer[j++] = base64EncodeLookup[(inputBuffer[i] & 0x03) << 4];
217 | outputBuffer[j++] = '=';
218 | outputBuffer[j++] = '=';
219 | }
220 | outputBuffer[j] = 0;
221 |
222 | //
223 | // Set the output length and return the buffer
224 | //
225 | if (outputLength) {
226 | *outputLength = j;
227 | }
228 | return outputBuffer;
229 | }
230 |
231 | @implementation NSData (Base64)
232 |
233 | //
234 | // dataFromBase64String:
235 | //
236 | // Creates an NSData object containing the base64 decoded representation of
237 | // the base64 string 'aString'
238 | //
239 | // Parameters:
240 | // aString - the base64 string to decode
241 | //
242 | // returns the autoreleased NSData representation of the base64 string
243 | //
244 | + (NSData*)dataFromBase64String:(NSString*)aString
245 | {
246 | size_t outputLength = 0;
247 | void* outputBuffer = NewBase64Decode([aString UTF8String], [aString length], &outputLength);
248 |
249 | return [NSData dataWithBytesNoCopy:outputBuffer length:outputLength freeWhenDone:YES];
250 | }
251 |
252 | //
253 | // base64EncodedString
254 | //
255 | // Creates an NSString object that contains the base 64 encoding of the
256 | // receiver's data. Lines are broken at 64 characters long.
257 | //
258 | // returns an autoreleased NSString being the base 64 representation of the
259 | // receiver.
260 | //
261 | - (NSString*)base64EncodedString
262 | {
263 | size_t outputLength = 0;
264 | char* outputBuffer =
265 | NewBase64Encode([self bytes], [self length], true, &outputLength);
266 |
267 | NSString* result = [[NSString alloc] initWithBytesNoCopy:outputBuffer
268 | length:outputLength
269 | encoding:NSASCIIStringEncoding
270 | freeWhenDone:YES];
271 |
272 | return result;
273 | }
274 |
275 |
276 | @end
277 |
--------------------------------------------------------------------------------
/MG.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 46;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | 2237E64A192B0177001E1393 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2237E649192B0177001E1393 /* Cocoa.framework */; };
11 | 2237E67E192B0186001E1393 /* WebKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2237E67D192B0186001E1393 /* WebKit.framework */; };
12 | 2237E680192B018D001E1393 /* JavaScriptCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2237E67F192B018D001E1393 /* JavaScriptCore.framework */; };
13 | 2237E6EF192BAF85001E1393 /* public in Resources */ = {isa = PBXBuildFile; fileRef = 2237E6EE192BAF85001E1393 /* public */; };
14 | 226AE65D193AA8FC00B15FB7 /* Sound.m in Sources */ = {isa = PBXBuildFile; fileRef = 226AE65C193AA8FC00B15FB7 /* Sound.m */; };
15 | 22A676E71944B140002F81FB /* File.m in Sources */ = {isa = PBXBuildFile; fileRef = 22A676E61944B140002F81FB /* File.m */; };
16 | 22B1CF2B1937734B00D2C294 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 22B1CEF51937734B00D2C294 /* AppDelegate.m */; };
17 | 22B1CF2C1937734B00D2C294 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 22B1CEF61937734B00D2C294 /* MainMenu.xib */; };
18 | 22B1CF2D1937734B00D2C294 /* MainWindow.xib in Resources */ = {isa = PBXBuildFile; fileRef = 22B1CEF81937734B00D2C294 /* MainWindow.xib */; };
19 | 22B1CF2E1937734B00D2C294 /* JSON.m in Sources */ = {isa = PBXBuildFile; fileRef = 22B1CEFC1937734B00D2C294 /* JSON.m */; };
20 | 22B1CF2F1937734B00D2C294 /* NSData+Base64.m in Sources */ = {isa = PBXBuildFile; fileRef = 22B1CEFE1937734B00D2C294 /* NSData+Base64.m */; };
21 | 22B1CF301937734B00D2C294 /* App.m in Sources */ = {isa = PBXBuildFile; fileRef = 22B1CF021937734B00D2C294 /* App.m */; };
22 | 22B1CF311937734B00D2C294 /* Clipboard.m in Sources */ = {isa = PBXBuildFile; fileRef = 22B1CF041937734B00D2C294 /* Clipboard.m */; };
23 | 22B1CF321937734B00D2C294 /* Command.m in Sources */ = {isa = PBXBuildFile; fileRef = 22B1CF061937734B00D2C294 /* Command.m */; };
24 | 22B1CF331937734B00D2C294 /* Dialog.m in Sources */ = {isa = PBXBuildFile; fileRef = 22B1CF081937734B00D2C294 /* Dialog.m */; };
25 | 22B1CF341937734B00D2C294 /* Dock.m in Sources */ = {isa = PBXBuildFile; fileRef = 22B1CF0A1937734B00D2C294 /* Dock.m */; };
26 | 22B1CF351937734B00D2C294 /* Event.m in Sources */ = {isa = PBXBuildFile; fileRef = 22B1CF0C1937734B00D2C294 /* Event.m */; };
27 | 22B1CF361937734B00D2C294 /* Fonts.m in Sources */ = {isa = PBXBuildFile; fileRef = 22B1CF0E1937734B00D2C294 /* Fonts.m */; };
28 | 22B1CF371937734B00D2C294 /* Menu.m in Sources */ = {isa = PBXBuildFile; fileRef = 22B1CF111937734B00D2C294 /* Menu.m */; };
29 | 22B1CF381937734B00D2C294 /* MenuItem.m in Sources */ = {isa = PBXBuildFile; fileRef = 22B1CF131937734B00D2C294 /* MenuItem.m */; };
30 | 22B1CF391937734B00D2C294 /* Notify.m in Sources */ = {isa = PBXBuildFile; fileRef = 22B1CF151937734B00D2C294 /* Notify.m */; };
31 | 22B1CF3A1937734B00D2C294 /* StatusItem.m in Sources */ = {isa = PBXBuildFile; fileRef = 22B1CF171937734B00D2C294 /* StatusItem.m */; };
32 | 22B1CF3B1937734B00D2C294 /* Task.m in Sources */ = {isa = PBXBuildFile; fileRef = 22B1CF191937734B00D2C294 /* Task.m */; };
33 | 22B1CF3C1937734B00D2C294 /* Window.m in Sources */ = {isa = PBXBuildFile; fileRef = 22B1CF1B1937734B00D2C294 /* Window.m */; };
34 | 22B1CF3D1937734B00D2C294 /* Utils.m in Sources */ = {isa = PBXBuildFile; fileRef = 22B1CF1D1937734B00D2C294 /* Utils.m */; };
35 | 22B1CF3E1937734B00D2C294 /* WebViewDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 22B1CF1F1937734B00D2C294 /* WebViewDelegate.m */; };
36 | 22B1CF3F1937734B00D2C294 /* WindowController.m in Sources */ = {isa = PBXBuildFile; fileRef = 22B1CF211937734B00D2C294 /* WindowController.m */; };
37 | 22B1CF401937734B00D2C294 /* Credits.rtf in Resources */ = {isa = PBXBuildFile; fileRef = 22B1CF231937734B00D2C294 /* Credits.rtf */; };
38 | 22B1CF411937734B00D2C294 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 22B1CF251937734B00D2C294 /* InfoPlist.strings */; };
39 | 22B1CF421937734B00D2C294 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 22B1CF271937734B00D2C294 /* Images.xcassets */; };
40 | 22B1CF431937734B00D2C294 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 22B1CF281937734B00D2C294 /* main.m */; };
41 | 22BE36ED193B7F8800D8199F /* Defaults.m in Sources */ = {isa = PBXBuildFile; fileRef = 22BE36EC193B7F8800D8199F /* Defaults.m */; };
42 | 3EEF80B22089DF8100F569D6 /* NotificationProvider.m in Sources */ = {isa = PBXBuildFile; fileRef = 3EEF80AF2089DF8100F569D6 /* NotificationProvider.m */; };
43 | 65EAED262018C629006617FE /* DraggableView.m in Sources */ = {isa = PBXBuildFile; fileRef = 65EAED252018C629006617FE /* DraggableView.m */; };
44 | /* End PBXBuildFile section */
45 |
46 | /* Begin PBXFileReference section */
47 | 2237E646192B0177001E1393 /* MG.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = MG.app; sourceTree = BUILT_PRODUCTS_DIR; };
48 | 2237E649192B0177001E1393 /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; };
49 | 2237E64C192B0177001E1393 /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = System/Library/Frameworks/AppKit.framework; sourceTree = SDKROOT; };
50 | 2237E64D192B0177001E1393 /* CoreData.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreData.framework; path = System/Library/Frameworks/CoreData.framework; sourceTree = SDKROOT; };
51 | 2237E64E192B0177001E1393 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
52 | 2237E668192B0177001E1393 /* XCTest.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = XCTest.framework; path = Library/Frameworks/XCTest.framework; sourceTree = DEVELOPER_DIR; };
53 | 2237E67D192B0186001E1393 /* WebKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = WebKit.framework; path = System/Library/Frameworks/WebKit.framework; sourceTree = SDKROOT; };
54 | 2237E67F192B018D001E1393 /* JavaScriptCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = JavaScriptCore.framework; path = System/Library/Frameworks/JavaScriptCore.framework; sourceTree = SDKROOT; };
55 | 2237E6EE192BAF85001E1393 /* public */ = {isa = PBXFileReference; lastKnownFileType = folder; path = public; sourceTree = ""; };
56 | 226AE65B193AA8FC00B15FB7 /* Sound.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Sound.h; sourceTree = ""; };
57 | 226AE65C193AA8FC00B15FB7 /* Sound.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Sound.m; sourceTree = ""; };
58 | 22A676E51944B140002F81FB /* File.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = File.h; sourceTree = ""; };
59 | 22A676E61944B140002F81FB /* File.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = File.m; sourceTree = ""; };
60 | 22B1CEF41937734B00D2C294 /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; };
61 | 22B1CEF51937734B00D2C294 /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; };
62 | 22B1CEF71937734B00D2C294 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = ""; };
63 | 22B1CEF91937734B00D2C294 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainWindow.xib; sourceTree = ""; };
64 | 22B1CEFB1937734B00D2C294 /* JSON.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSON.h; sourceTree = ""; };
65 | 22B1CEFC1937734B00D2C294 /* JSON.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JSON.m; sourceTree = ""; };
66 | 22B1CEFD1937734B00D2C294 /* NSData+Base64.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSData+Base64.h"; sourceTree = ""; };
67 | 22B1CEFE1937734B00D2C294 /* NSData+Base64.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSData+Base64.m"; sourceTree = ""; };
68 | 22B1CF011937734B00D2C294 /* App.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = App.h; sourceTree = ""; };
69 | 22B1CF021937734B00D2C294 /* App.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = App.m; sourceTree = ""; };
70 | 22B1CF031937734B00D2C294 /* Clipboard.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Clipboard.h; sourceTree = ""; };
71 | 22B1CF041937734B00D2C294 /* Clipboard.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Clipboard.m; sourceTree = ""; };
72 | 22B1CF051937734B00D2C294 /* Command.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Command.h; sourceTree = ""; };
73 | 22B1CF061937734B00D2C294 /* Command.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Command.m; sourceTree = ""; };
74 | 22B1CF071937734B00D2C294 /* Dialog.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Dialog.h; sourceTree = ""; };
75 | 22B1CF081937734B00D2C294 /* Dialog.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Dialog.m; sourceTree = ""; };
76 | 22B1CF091937734B00D2C294 /* Dock.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Dock.h; sourceTree = ""; };
77 | 22B1CF0A1937734B00D2C294 /* Dock.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Dock.m; sourceTree = ""; };
78 | 22B1CF0B1937734B00D2C294 /* Event.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Event.h; sourceTree = ""; };
79 | 22B1CF0C1937734B00D2C294 /* Event.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Event.m; sourceTree = ""; };
80 | 22B1CF0D1937734B00D2C294 /* Fonts.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Fonts.h; sourceTree = ""; };
81 | 22B1CF0E1937734B00D2C294 /* Fonts.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Fonts.m; sourceTree = ""; };
82 | 22B1CF0F1937734B00D2C294 /* MacGap.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MacGap.h; sourceTree = ""; };
83 | 22B1CF101937734B00D2C294 /* Menu.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Menu.h; sourceTree = ""; };
84 | 22B1CF111937734B00D2C294 /* Menu.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Menu.m; sourceTree = ""; };
85 | 22B1CF121937734B00D2C294 /* MenuItem.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MenuItem.h; sourceTree = ""; };
86 | 22B1CF131937734B00D2C294 /* MenuItem.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MenuItem.m; sourceTree = ""; };
87 | 22B1CF141937734B00D2C294 /* Notify.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Notify.h; sourceTree = ""; };
88 | 22B1CF151937734B00D2C294 /* Notify.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Notify.m; sourceTree = ""; };
89 | 22B1CF161937734B00D2C294 /* StatusItem.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StatusItem.h; sourceTree = ""; };
90 | 22B1CF171937734B00D2C294 /* StatusItem.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = StatusItem.m; sourceTree = ""; };
91 | 22B1CF181937734B00D2C294 /* Task.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Task.h; sourceTree = ""; };
92 | 22B1CF191937734B00D2C294 /* Task.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Task.m; sourceTree = ""; };
93 | 22B1CF1A1937734B00D2C294 /* Window.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Window.h; sourceTree = ""; };
94 | 22B1CF1B1937734B00D2C294 /* Window.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Window.m; sourceTree = ""; };
95 | 22B1CF1C1937734B00D2C294 /* Utils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Utils.h; sourceTree = ""; };
96 | 22B1CF1D1937734B00D2C294 /* Utils.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Utils.m; sourceTree = ""; };
97 | 22B1CF1E1937734B00D2C294 /* WebViewDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WebViewDelegate.h; sourceTree = ""; };
98 | 22B1CF1F1937734B00D2C294 /* WebViewDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WebViewDelegate.m; sourceTree = ""; };
99 | 22B1CF201937734B00D2C294 /* WindowController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WindowController.h; sourceTree = ""; };
100 | 22B1CF211937734B00D2C294 /* WindowController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WindowController.m; sourceTree = ""; };
101 | 22B1CF221937734B00D2C294 /* Constants.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Constants.h; sourceTree = ""; };
102 | 22B1CF241937734B00D2C294 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.rtf; name = en; path = en.lproj/Credits.rtf; sourceTree = ""; };
103 | 22B1CF261937734B00D2C294 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; };
104 | 22B1CF271937734B00D2C294 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; };
105 | 22B1CF281937734B00D2C294 /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; };
106 | 22B1CF291937734B00D2C294 /* MG-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "MG-Info.plist"; sourceTree = ""; };
107 | 22B1CF2A1937734B00D2C294 /* MG-Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "MG-Prefix.pch"; sourceTree = ""; };
108 | 22BE36EB193B7F8800D8199F /* Defaults.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Defaults.h; sourceTree = ""; };
109 | 22BE36EC193B7F8800D8199F /* Defaults.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Defaults.m; sourceTree = ""; };
110 | 3EEF80AF2089DF8100F569D6 /* NotificationProvider.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NotificationProvider.m; sourceTree = ""; };
111 | 3EEF80B02089DF8100F569D6 /* NotificationProvider.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NotificationProvider.h; sourceTree = ""; };
112 | 3EEF80B12089DF8100F569D6 /* WebNotification.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WebNotification.h; sourceTree = ""; };
113 | 65EAED242018C629006617FE /* DraggableView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DraggableView.h; sourceTree = ""; };
114 | 65EAED252018C629006617FE /* DraggableView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DraggableView.m; sourceTree = ""; };
115 | /* End PBXFileReference section */
116 |
117 | /* Begin PBXFrameworksBuildPhase section */
118 | 2237E643192B0177001E1393 /* Frameworks */ = {
119 | isa = PBXFrameworksBuildPhase;
120 | buildActionMask = 2147483647;
121 | files = (
122 | 2237E680192B018D001E1393 /* JavaScriptCore.framework in Frameworks */,
123 | 2237E67E192B0186001E1393 /* WebKit.framework in Frameworks */,
124 | 2237E64A192B0177001E1393 /* Cocoa.framework in Frameworks */,
125 | );
126 | runOnlyForDeploymentPostprocessing = 0;
127 | };
128 | /* End PBXFrameworksBuildPhase section */
129 |
130 | /* Begin PBXGroup section */
131 | 2237E63D192B0177001E1393 = {
132 | isa = PBXGroup;
133 | children = (
134 | 2237E6EE192BAF85001E1393 /* public */,
135 | 22B1CEF31937734B00D2C294 /* MacGap */,
136 | 2237E648192B0177001E1393 /* Frameworks */,
137 | 2237E647192B0177001E1393 /* Products */,
138 | );
139 | sourceTree = "";
140 | };
141 | 2237E647192B0177001E1393 /* Products */ = {
142 | isa = PBXGroup;
143 | children = (
144 | 2237E646192B0177001E1393 /* MG.app */,
145 | );
146 | name = Products;
147 | sourceTree = "";
148 | };
149 | 2237E648192B0177001E1393 /* Frameworks */ = {
150 | isa = PBXGroup;
151 | children = (
152 | 2237E67F192B018D001E1393 /* JavaScriptCore.framework */,
153 | 2237E67D192B0186001E1393 /* WebKit.framework */,
154 | 2237E649192B0177001E1393 /* Cocoa.framework */,
155 | 2237E668192B0177001E1393 /* XCTest.framework */,
156 | 2237E64B192B0177001E1393 /* Other Frameworks */,
157 | );
158 | name = Frameworks;
159 | sourceTree = "";
160 | };
161 | 2237E64B192B0177001E1393 /* Other Frameworks */ = {
162 | isa = PBXGroup;
163 | children = (
164 | 2237E64C192B0177001E1393 /* AppKit.framework */,
165 | 2237E64D192B0177001E1393 /* CoreData.framework */,
166 | 2237E64E192B0177001E1393 /* Foundation.framework */,
167 | );
168 | name = "Other Frameworks";
169 | sourceTree = "";
170 | };
171 | 22B1CEF31937734B00D2C294 /* MacGap */ = {
172 | isa = PBXGroup;
173 | children = (
174 | 22B1CEF41937734B00D2C294 /* AppDelegate.h */,
175 | 22B1CEF51937734B00D2C294 /* AppDelegate.m */,
176 | 22B1CEFA1937734B00D2C294 /* Categories */,
177 | 22B1CEFF1937734B00D2C294 /* Classes */,
178 | 22B1CF221937734B00D2C294 /* Constants.h */,
179 | 22B1CF46193773BA00D2C294 /* Interface Builder */,
180 | 22B1CF45193773A400D2C294 /* Supporting Files */,
181 | );
182 | path = MacGap;
183 | sourceTree = "";
184 | };
185 | 22B1CEFA1937734B00D2C294 /* Categories */ = {
186 | isa = PBXGroup;
187 | children = (
188 | 22B1CEFB1937734B00D2C294 /* JSON.h */,
189 | 22B1CEFC1937734B00D2C294 /* JSON.m */,
190 | 22B1CEFD1937734B00D2C294 /* NSData+Base64.h */,
191 | 22B1CEFE1937734B00D2C294 /* NSData+Base64.m */,
192 | );
193 | path = Categories;
194 | sourceTree = "";
195 | };
196 | 22B1CEFF1937734B00D2C294 /* Classes */ = {
197 | isa = PBXGroup;
198 | children = (
199 | 3EEF80B02089DF8100F569D6 /* NotificationProvider.h */,
200 | 3EEF80AF2089DF8100F569D6 /* NotificationProvider.m */,
201 | 3EEF80B12089DF8100F569D6 /* WebNotification.h */,
202 | 22B1CF001937734B00D2C294 /* Commands */,
203 | 22B1CF1C1937734B00D2C294 /* Utils.h */,
204 | 22B1CF1D1937734B00D2C294 /* Utils.m */,
205 | 22B1CF1E1937734B00D2C294 /* WebViewDelegate.h */,
206 | 22B1CF1F1937734B00D2C294 /* WebViewDelegate.m */,
207 | 22B1CF201937734B00D2C294 /* WindowController.h */,
208 | 22B1CF211937734B00D2C294 /* WindowController.m */,
209 | 65EAED252018C629006617FE /* DraggableView.m */,
210 | 65EAED242018C629006617FE /* DraggableView.h */,
211 | );
212 | path = Classes;
213 | sourceTree = "";
214 | };
215 | 22B1CF001937734B00D2C294 /* Commands */ = {
216 | isa = PBXGroup;
217 | children = (
218 | 22B1CF011937734B00D2C294 /* App.h */,
219 | 22B1CF021937734B00D2C294 /* App.m */,
220 | 22B1CF031937734B00D2C294 /* Clipboard.h */,
221 | 22B1CF041937734B00D2C294 /* Clipboard.m */,
222 | 22B1CF051937734B00D2C294 /* Command.h */,
223 | 22B1CF061937734B00D2C294 /* Command.m */,
224 | 22B1CF071937734B00D2C294 /* Dialog.h */,
225 | 22B1CF081937734B00D2C294 /* Dialog.m */,
226 | 22B1CF091937734B00D2C294 /* Dock.h */,
227 | 22B1CF0A1937734B00D2C294 /* Dock.m */,
228 | 22B1CF0B1937734B00D2C294 /* Event.h */,
229 | 22B1CF0C1937734B00D2C294 /* Event.m */,
230 | 22B1CF0D1937734B00D2C294 /* Fonts.h */,
231 | 22B1CF0E1937734B00D2C294 /* Fonts.m */,
232 | 22B1CF0F1937734B00D2C294 /* MacGap.h */,
233 | 22B1CF101937734B00D2C294 /* Menu.h */,
234 | 22B1CF111937734B00D2C294 /* Menu.m */,
235 | 22B1CF121937734B00D2C294 /* MenuItem.h */,
236 | 22B1CF131937734B00D2C294 /* MenuItem.m */,
237 | 22B1CF141937734B00D2C294 /* Notify.h */,
238 | 22B1CF151937734B00D2C294 /* Notify.m */,
239 | 22B1CF161937734B00D2C294 /* StatusItem.h */,
240 | 22B1CF171937734B00D2C294 /* StatusItem.m */,
241 | 22B1CF181937734B00D2C294 /* Task.h */,
242 | 22B1CF191937734B00D2C294 /* Task.m */,
243 | 22B1CF1A1937734B00D2C294 /* Window.h */,
244 | 22B1CF1B1937734B00D2C294 /* Window.m */,
245 | 226AE65B193AA8FC00B15FB7 /* Sound.h */,
246 | 226AE65C193AA8FC00B15FB7 /* Sound.m */,
247 | 22BE36EB193B7F8800D8199F /* Defaults.h */,
248 | 22BE36EC193B7F8800D8199F /* Defaults.m */,
249 | 22A676E51944B140002F81FB /* File.h */,
250 | 22A676E61944B140002F81FB /* File.m */,
251 | );
252 | path = Commands;
253 | sourceTree = "";
254 | };
255 | 22B1CF45193773A400D2C294 /* Supporting Files */ = {
256 | isa = PBXGroup;
257 | children = (
258 | 22B1CF231937734B00D2C294 /* Credits.rtf */,
259 | 22B1CF251937734B00D2C294 /* InfoPlist.strings */,
260 | 22B1CF271937734B00D2C294 /* Images.xcassets */,
261 | 22B1CF281937734B00D2C294 /* main.m */,
262 | 22B1CF291937734B00D2C294 /* MG-Info.plist */,
263 | 22B1CF2A1937734B00D2C294 /* MG-Prefix.pch */,
264 | );
265 | name = "Supporting Files";
266 | sourceTree = "";
267 | };
268 | 22B1CF46193773BA00D2C294 /* Interface Builder */ = {
269 | isa = PBXGroup;
270 | children = (
271 | 22B1CEF61937734B00D2C294 /* MainMenu.xib */,
272 | 22B1CEF81937734B00D2C294 /* MainWindow.xib */,
273 | );
274 | name = "Interface Builder";
275 | sourceTree = "";
276 | };
277 | /* End PBXGroup section */
278 |
279 | /* Begin PBXNativeTarget section */
280 | 2237E645192B0177001E1393 /* MG */ = {
281 | isa = PBXNativeTarget;
282 | buildConfigurationList = 2237E677192B0177001E1393 /* Build configuration list for PBXNativeTarget "MG" */;
283 | buildPhases = (
284 | 2237E642192B0177001E1393 /* Sources */,
285 | 2237E643192B0177001E1393 /* Frameworks */,
286 | 2237E644192B0177001E1393 /* Resources */,
287 | );
288 | buildRules = (
289 | );
290 | dependencies = (
291 | );
292 | name = MG;
293 | productName = MG;
294 | productReference = 2237E646192B0177001E1393 /* MG.app */;
295 | productType = "com.apple.product-type.application";
296 | };
297 | /* End PBXNativeTarget section */
298 |
299 | /* Begin PBXProject section */
300 | 2237E63E192B0177001E1393 /* Project object */ = {
301 | isa = PBXProject;
302 | attributes = {
303 | LastUpgradeCheck = 1010;
304 | };
305 | buildConfigurationList = 2237E641192B0177001E1393 /* Build configuration list for PBXProject "MG" */;
306 | compatibilityVersion = "Xcode 3.2";
307 | developmentRegion = English;
308 | hasScannedForEncodings = 0;
309 | knownRegions = (
310 | en,
311 | Base,
312 | );
313 | mainGroup = 2237E63D192B0177001E1393;
314 | productRefGroup = 2237E647192B0177001E1393 /* Products */;
315 | projectDirPath = "";
316 | projectRoot = "";
317 | targets = (
318 | 2237E645192B0177001E1393 /* MG */,
319 | );
320 | };
321 | /* End PBXProject section */
322 |
323 | /* Begin PBXResourcesBuildPhase section */
324 | 2237E644192B0177001E1393 /* Resources */ = {
325 | isa = PBXResourcesBuildPhase;
326 | buildActionMask = 2147483647;
327 | files = (
328 | 2237E6EF192BAF85001E1393 /* public in Resources */,
329 | 22B1CF401937734B00D2C294 /* Credits.rtf in Resources */,
330 | 22B1CF421937734B00D2C294 /* Images.xcassets in Resources */,
331 | 22B1CF2D1937734B00D2C294 /* MainWindow.xib in Resources */,
332 | 22B1CF2C1937734B00D2C294 /* MainMenu.xib in Resources */,
333 | 22B1CF411937734B00D2C294 /* InfoPlist.strings in Resources */,
334 | );
335 | runOnlyForDeploymentPostprocessing = 0;
336 | };
337 | /* End PBXResourcesBuildPhase section */
338 |
339 | /* Begin PBXSourcesBuildPhase section */
340 | 2237E642192B0177001E1393 /* Sources */ = {
341 | isa = PBXSourcesBuildPhase;
342 | buildActionMask = 2147483647;
343 | files = (
344 | 22B1CF3B1937734B00D2C294 /* Task.m in Sources */,
345 | 22B1CF341937734B00D2C294 /* Dock.m in Sources */,
346 | 22B1CF2E1937734B00D2C294 /* JSON.m in Sources */,
347 | 22BE36ED193B7F8800D8199F /* Defaults.m in Sources */,
348 | 22B1CF381937734B00D2C294 /* MenuItem.m in Sources */,
349 | 22B1CF301937734B00D2C294 /* App.m in Sources */,
350 | 65EAED262018C629006617FE /* DraggableView.m in Sources */,
351 | 22B1CF371937734B00D2C294 /* Menu.m in Sources */,
352 | 22A676E71944B140002F81FB /* File.m in Sources */,
353 | 22B1CF3C1937734B00D2C294 /* Window.m in Sources */,
354 | 22B1CF3F1937734B00D2C294 /* WindowController.m in Sources */,
355 | 22B1CF3D1937734B00D2C294 /* Utils.m in Sources */,
356 | 22B1CF3E1937734B00D2C294 /* WebViewDelegate.m in Sources */,
357 | 3EEF80B22089DF8100F569D6 /* NotificationProvider.m in Sources */,
358 | 22B1CF3A1937734B00D2C294 /* StatusItem.m in Sources */,
359 | 22B1CF311937734B00D2C294 /* Clipboard.m in Sources */,
360 | 22B1CF2F1937734B00D2C294 /* NSData+Base64.m in Sources */,
361 | 22B1CF431937734B00D2C294 /* main.m in Sources */,
362 | 22B1CF321937734B00D2C294 /* Command.m in Sources */,
363 | 226AE65D193AA8FC00B15FB7 /* Sound.m in Sources */,
364 | 22B1CF331937734B00D2C294 /* Dialog.m in Sources */,
365 | 22B1CF361937734B00D2C294 /* Fonts.m in Sources */,
366 | 22B1CF2B1937734B00D2C294 /* AppDelegate.m in Sources */,
367 | 22B1CF391937734B00D2C294 /* Notify.m in Sources */,
368 | 22B1CF351937734B00D2C294 /* Event.m in Sources */,
369 | );
370 | runOnlyForDeploymentPostprocessing = 0;
371 | };
372 | /* End PBXSourcesBuildPhase section */
373 |
374 | /* Begin PBXVariantGroup section */
375 | 22B1CEF61937734B00D2C294 /* MainMenu.xib */ = {
376 | isa = PBXVariantGroup;
377 | children = (
378 | 22B1CEF71937734B00D2C294 /* Base */,
379 | );
380 | name = MainMenu.xib;
381 | sourceTree = "";
382 | };
383 | 22B1CEF81937734B00D2C294 /* MainWindow.xib */ = {
384 | isa = PBXVariantGroup;
385 | children = (
386 | 22B1CEF91937734B00D2C294 /* Base */,
387 | );
388 | name = MainWindow.xib;
389 | sourceTree = "";
390 | };
391 | 22B1CF231937734B00D2C294 /* Credits.rtf */ = {
392 | isa = PBXVariantGroup;
393 | children = (
394 | 22B1CF241937734B00D2C294 /* en */,
395 | );
396 | name = Credits.rtf;
397 | sourceTree = "";
398 | };
399 | 22B1CF251937734B00D2C294 /* InfoPlist.strings */ = {
400 | isa = PBXVariantGroup;
401 | children = (
402 | 22B1CF261937734B00D2C294 /* en */,
403 | );
404 | name = InfoPlist.strings;
405 | sourceTree = "";
406 | };
407 | /* End PBXVariantGroup section */
408 |
409 | /* Begin XCBuildConfiguration section */
410 | 2237E675192B0177001E1393 /* Debug */ = {
411 | isa = XCBuildConfiguration;
412 | buildSettings = {
413 | ALWAYS_SEARCH_USER_PATHS = NO;
414 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
415 | CLANG_CXX_LIBRARY = "libc++";
416 | CLANG_ENABLE_MODULES = YES;
417 | CLANG_ENABLE_OBJC_ARC = YES;
418 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
419 | CLANG_WARN_BOOL_CONVERSION = YES;
420 | CLANG_WARN_COMMA = YES;
421 | CLANG_WARN_CONSTANT_CONVERSION = YES;
422 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
423 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
424 | CLANG_WARN_EMPTY_BODY = YES;
425 | CLANG_WARN_ENUM_CONVERSION = YES;
426 | CLANG_WARN_INFINITE_RECURSION = YES;
427 | CLANG_WARN_INT_CONVERSION = YES;
428 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
429 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
430 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
431 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
432 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
433 | CLANG_WARN_STRICT_PROTOTYPES = YES;
434 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
435 | CLANG_WARN_UNREACHABLE_CODE = YES;
436 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
437 | COPY_PHASE_STRIP = NO;
438 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
439 | ENABLE_STRICT_OBJC_MSGSEND = YES;
440 | ENABLE_TESTABILITY = YES;
441 | GCC_C_LANGUAGE_STANDARD = gnu99;
442 | GCC_DYNAMIC_NO_PIC = NO;
443 | GCC_ENABLE_OBJC_EXCEPTIONS = YES;
444 | GCC_NO_COMMON_BLOCKS = YES;
445 | GCC_OPTIMIZATION_LEVEL = 0;
446 | GCC_PREPROCESSOR_DEFINITIONS = (
447 | "DEBUG=1",
448 | "$(inherited)",
449 | );
450 | GCC_SYMBOLS_PRIVATE_EXTERN = NO;
451 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
452 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
453 | GCC_WARN_UNDECLARED_SELECTOR = YES;
454 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
455 | GCC_WARN_UNUSED_FUNCTION = YES;
456 | GCC_WARN_UNUSED_VARIABLE = YES;
457 | MACOSX_DEPLOYMENT_TARGET = 10.9;
458 | ONLY_ACTIVE_ARCH = YES;
459 | SDKROOT = macosx;
460 | };
461 | name = Debug;
462 | };
463 | 2237E676192B0177001E1393 /* Release */ = {
464 | isa = XCBuildConfiguration;
465 | buildSettings = {
466 | ALWAYS_SEARCH_USER_PATHS = NO;
467 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
468 | CLANG_CXX_LIBRARY = "libc++";
469 | CLANG_ENABLE_MODULES = YES;
470 | CLANG_ENABLE_OBJC_ARC = YES;
471 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
472 | CLANG_WARN_BOOL_CONVERSION = YES;
473 | CLANG_WARN_COMMA = YES;
474 | CLANG_WARN_CONSTANT_CONVERSION = YES;
475 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
476 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
477 | CLANG_WARN_EMPTY_BODY = YES;
478 | CLANG_WARN_ENUM_CONVERSION = YES;
479 | CLANG_WARN_INFINITE_RECURSION = YES;
480 | CLANG_WARN_INT_CONVERSION = YES;
481 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
482 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
483 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
484 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
485 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
486 | CLANG_WARN_STRICT_PROTOTYPES = YES;
487 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
488 | CLANG_WARN_UNREACHABLE_CODE = YES;
489 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
490 | COPY_PHASE_STRIP = YES;
491 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
492 | ENABLE_NS_ASSERTIONS = NO;
493 | ENABLE_STRICT_OBJC_MSGSEND = YES;
494 | GCC_C_LANGUAGE_STANDARD = gnu99;
495 | GCC_ENABLE_OBJC_EXCEPTIONS = YES;
496 | GCC_NO_COMMON_BLOCKS = YES;
497 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
498 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
499 | GCC_WARN_UNDECLARED_SELECTOR = YES;
500 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
501 | GCC_WARN_UNUSED_FUNCTION = YES;
502 | GCC_WARN_UNUSED_VARIABLE = YES;
503 | MACOSX_DEPLOYMENT_TARGET = 10.9;
504 | SDKROOT = macosx;
505 | };
506 | name = Release;
507 | };
508 | 2237E678192B0177001E1393 /* Debug */ = {
509 | isa = XCBuildConfiguration;
510 | buildSettings = {
511 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
512 | COMBINE_HIDPI_IMAGES = YES;
513 | GCC_PRECOMPILE_PREFIX_HEADER = YES;
514 | GCC_PREFIX_HEADER = "MacGap/MG-Prefix.pch";
515 | GCC_WARN_UNDECLARED_SELECTOR = NO;
516 | INFOPLIST_FILE = "MacGap/MG-Info.plist";
517 | PRODUCT_BUNDLE_IDENTIFIER = "com.${PRODUCT_NAME:rfc1034identifier}";
518 | PRODUCT_NAME = "$(TARGET_NAME)";
519 | WRAPPER_EXTENSION = app;
520 | };
521 | name = Debug;
522 | };
523 | 2237E679192B0177001E1393 /* Release */ = {
524 | isa = XCBuildConfiguration;
525 | buildSettings = {
526 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
527 | COMBINE_HIDPI_IMAGES = YES;
528 | GCC_PRECOMPILE_PREFIX_HEADER = YES;
529 | GCC_PREFIX_HEADER = "MacGap/MG-Prefix.pch";
530 | GCC_WARN_UNDECLARED_SELECTOR = NO;
531 | INFOPLIST_FILE = "MacGap/MG-Info.plist";
532 | PRODUCT_BUNDLE_IDENTIFIER = "com.${PRODUCT_NAME:rfc1034identifier}";
533 | PRODUCT_NAME = "$(TARGET_NAME)";
534 | WRAPPER_EXTENSION = app;
535 | };
536 | name = Release;
537 | };
538 | /* End XCBuildConfiguration section */
539 |
540 | /* Begin XCConfigurationList section */
541 | 2237E641192B0177001E1393 /* Build configuration list for PBXProject "MG" */ = {
542 | isa = XCConfigurationList;
543 | buildConfigurations = (
544 | 2237E675192B0177001E1393 /* Debug */,
545 | 2237E676192B0177001E1393 /* Release */,
546 | );
547 | defaultConfigurationIsVisible = 0;
548 | defaultConfigurationName = Release;
549 | };
550 | 2237E677192B0177001E1393 /* Build configuration list for PBXNativeTarget "MG" */ = {
551 | isa = XCConfigurationList;
552 | buildConfigurations = (
553 | 2237E678192B0177001E1393 /* Debug */,
554 | 2237E679192B0177001E1393 /* Release */,
555 | );
556 | defaultConfigurationIsVisible = 0;
557 | defaultConfigurationName = Release;
558 | };
559 | /* End XCConfigurationList section */
560 | };
561 | rootObject = 2237E63E192B0177001E1393 /* Project object */;
562 | }
563 |
--------------------------------------------------------------------------------
/MacGap/Base.lproj/MainMenu.xib:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
665 |
666 |
667 |
--------------------------------------------------------------------------------