├── .gitignore ├── LICENSE ├── MG.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ ├── xcshareddata │ │ ├── IDEWorkspaceChecks.plist │ │ └── MG.xccheckout │ └── xcuserdata │ │ ├── Tim.xcuserdatad │ │ ├── UserInterfaceState.xcuserstate │ │ └── WorkspaceSettings.xcsettings │ │ └── jeffh.xcuserdatad │ │ └── UserInterfaceState.xcuserstate └── xcuserdata │ ├── Tim.xcuserdatad │ ├── xcdebugger │ │ └── Breakpoints_v2.xcbkptlist │ └── xcschemes │ │ ├── MG.xcscheme │ │ └── xcschememanagement.plist │ └── jeffh.xcuserdatad │ └── xcschemes │ └── xcschememanagement.plist ├── MacGap ├── AppDelegate.h ├── AppDelegate.m ├── Base.lproj │ ├── MainMenu.xib │ └── MainWindow.xib ├── Categories │ ├── JSON.h │ ├── JSON.m │ ├── NSData+Base64.h │ └── NSData+Base64.m ├── Classes │ ├── Commands │ │ ├── App.h │ │ ├── App.m │ │ ├── Clipboard.h │ │ ├── Clipboard.m │ │ ├── Command.h │ │ ├── Command.m │ │ ├── Defaults.h │ │ ├── Defaults.m │ │ ├── Dialog.h │ │ ├── Dialog.m │ │ ├── Dock.h │ │ ├── Dock.m │ │ ├── Event.h │ │ ├── Event.m │ │ ├── File.h │ │ ├── File.m │ │ ├── Fonts.h │ │ ├── Fonts.m │ │ ├── MacGap.h │ │ ├── Menu.h │ │ ├── Menu.m │ │ ├── MenuItem.h │ │ ├── MenuItem.m │ │ ├── Notify.h │ │ ├── Notify.m │ │ ├── Sound.h │ │ ├── Sound.m │ │ ├── StatusItem.h │ │ ├── StatusItem.m │ │ ├── Task.h │ │ ├── Task.m │ │ ├── Window.h │ │ └── Window.m │ ├── DraggableView.h │ ├── DraggableView.m │ ├── NotificationProvider.h │ ├── NotificationProvider.m │ ├── Utils.h │ ├── Utils.m │ ├── WebNotification.h │ ├── WebViewDelegate.h │ ├── WebViewDelegate.m │ ├── WindowController.h │ └── WindowController.m ├── Constants.h ├── Images.xcassets │ └── AppIcon.appiconset │ │ └── Contents.json ├── MG-Info.plist ├── MG-Prefix.pch ├── en.lproj │ ├── Credits.rtf │ └── InfoPlist.strings └── main.m ├── README.md └── public ├── config.json └── index.html /.gitignore: -------------------------------------------------------------------------------- 1 | public/status.png 2 | .DS_Store -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /MG.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /MG.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /MG.xcodeproj/project.xcworkspace/xcuserdata/Tim.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MacGapProject/MacGap2/7edaead8cce0b0d3058da423897a61ad7c1aad80/MG.xcodeproj/project.xcworkspace/xcuserdata/Tim.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /MG.xcodeproj/project.xcworkspace/xcuserdata/Tim.xcuserdatad/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | HasAskedToTakeAutomaticSnapshotBeforeSignificantChanges 6 | 7 | SnapshotAutomaticallyBeforeSignificantChanges 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /MG.xcodeproj/project.xcworkspace/xcuserdata/jeffh.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MacGapProject/MacGap2/7edaead8cce0b0d3058da423897a61ad7c1aad80/MG.xcodeproj/project.xcworkspace/xcuserdata/jeffh.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /MG.xcodeproj/xcuserdata/Tim.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 8 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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/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/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/Base.lproj/MainMenu.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 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | 309 | 310 | 311 | 312 | 313 | 314 | 315 | 316 | 317 | 318 | 319 | 320 | 321 | 322 | 323 | 324 | 325 | 326 | 327 | 328 | 329 | 330 | 331 | 332 | 333 | 334 | 335 | 336 | 337 | 338 | 339 | 340 | 341 | 342 | 343 | 344 | 345 | 346 | 347 | 348 | 349 | 350 | 351 | 352 | 353 | 354 | 355 | 356 | 357 | 358 | 359 | 360 | 361 | 362 | 363 | 364 | 365 | 366 | 367 | 368 | 369 | 370 | 371 | 372 | 373 | 374 | 375 | 376 | 377 | 378 | 379 | 380 | 381 | 382 | 383 | 384 | 385 | 386 | 387 | 388 | 389 | 390 | 391 | 392 | 393 | 394 | 395 | 396 | 397 | 398 | 399 | 400 | 401 | 402 | 403 | 404 | 405 | 406 | 407 | 408 | 409 | 410 | 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | 419 | 420 | 421 | 422 | 423 | 424 | 425 | 426 | 427 | 428 | 429 | 430 | 431 | 432 | 433 | 434 | 435 | 436 | 437 | 438 | 439 | 440 | 441 | 442 | 443 | 444 | 445 | 446 | 447 | 448 | 449 | 450 | 451 | 452 | 453 | 454 | 455 | 456 | 457 | 458 | 459 | 460 | 461 | 462 | 463 | 464 | 465 | 466 | 467 | 468 | 469 | 470 | 471 | 472 | 473 | 474 | 475 | 476 | 477 | 478 | 479 | 480 | 481 | 482 | 483 | 484 | 485 | 486 | 487 | 488 | 489 | 490 | 491 | 492 | 493 | 494 | 495 | 496 | 497 | 498 | 499 | 500 | 501 | 502 | 503 | 504 | 505 | 506 | 507 | 508 | 509 | 510 | 511 | 512 | 513 | 514 | 515 | 516 | 517 | 518 | 519 | 520 | 521 | 522 | 523 | 524 | 525 | 526 | 527 | 528 | 529 | 530 | 531 | 532 | 533 | 534 | Default 535 | 536 | 537 | 538 | 539 | 540 | 541 | Left to Right 542 | 543 | 544 | 545 | 546 | 547 | 548 | Right to Left 549 | 550 | 551 | 552 | 553 | 554 | 555 | 556 | 557 | 558 | 559 | Default 560 | 561 | 562 | 563 | 564 | 565 | 566 | Left to Right 567 | 568 | 569 | 570 | 571 | 572 | 573 | Right to Left 574 | 575 | 576 | 577 | 578 | 579 | 580 | 581 | 582 | 583 | 584 | 585 | 586 | 587 | 588 | 589 | 590 | 591 | 592 | 593 | 594 | 595 | 596 | 597 | 598 | 599 | 600 | 601 | 602 | 603 | 604 | 605 | 606 | 607 | 608 | 609 | 610 | 611 | 612 | 613 | 614 | 615 | 616 | 617 | 618 | 619 | 620 | 621 | 622 | 623 | 624 | 625 | 626 | 627 | 628 | 629 | 630 | 631 | 632 | 633 | 634 | 635 | 636 | 637 | 638 | 639 | 640 | 641 | 642 | 643 | 644 | 645 | 646 | 647 | 648 | 649 | 650 | 651 | 652 | 653 | 654 | 655 | 656 | 657 | 658 | 659 | 660 | 661 | 662 | 663 | 664 | 665 | 666 | 667 | -------------------------------------------------------------------------------- /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/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/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/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/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 | -------------------------------------------------------------------------------- /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/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/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/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/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/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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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/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/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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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 | -------------------------------------------------------------------------------- /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/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 | -------------------------------------------------------------------------------- /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/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/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/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/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/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/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/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/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/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/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/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/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 | -------------------------------------------------------------------------------- /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/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 | -------------------------------------------------------------------------------- /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/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/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Gitter chat](https://badges.gitter.im/MacGapProject/MacGap2.png)](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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | MacGap 5 | 6 | 7 | 25 | 26 | 27 | 28 | 29 | 31 | 32 |

MacGap

33 | 34 | --------------------------------------------------------------------------------