├── .gitignore ├── Gestr.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ ├── xcshareddata │ │ ├── Gestr.xccheckout │ │ └── IDEWorkspaceChecks.plist │ └── xcuserdata │ │ └── mhuusko.xcuserdatad │ │ └── WorkspaceSettings.xcsettings └── xcuserdata │ ├── mhuusko.xcuserdatad │ ├── xcdebugger │ │ └── Breakpoints_v2.xcbkptlist │ └── xcschemes │ │ ├── Gestr.xcscheme │ │ └── xcschememanagement.plist │ └── mhuusko5.xcuserdatad │ └── xcschemes │ └── xcschememanagement.plist ├── Gestr ├── AppButtonCell.h ├── AppButtonCell.m ├── AppController.h ├── AppController.m ├── AppSegmentedCell.h ├── AppSegmentedCell.m ├── AppTableCellView.h ├── AppTableCellView.m ├── AppTableView.h ├── AppTableView.m ├── AppTextFieldCell.h ├── AppTextFieldCell.m ├── Application.h ├── Application.m ├── ChromePage.h ├── ChromePage.m ├── Gestr-Info.plist ├── Gestr-Prefix.pch ├── Gestr.entitlements ├── Gesture.h ├── Gesture.m ├── GesturePoint.h ├── GesturePoint.m ├── GestureRecognitionController.h ├── GestureRecognitionController.m ├── GestureRecognitionModel.h ├── GestureRecognitionModel.m ├── GestureRecognitionView.h ├── GestureRecognitionView.m ├── GestureRecognitionWindow.h ├── GestureRecognitionWindow.m ├── GestureRecognizer.h ├── GestureRecognizer.m ├── GestureResult.h ├── GestureResult.m ├── GestureSetupController.h ├── GestureSetupController.m ├── GestureSetupModel.h ├── GestureSetupModel.m ├── GestureSetupView.h ├── GestureSetupView.m ├── GestureSetupWindow.h ├── GestureSetupWindow.m ├── GestureStroke.h ├── GestureStroke.m ├── GestureTemplate.h ├── GestureTemplate.m ├── GestureUtils.h ├── GestureUtils.m ├── Images.xcassets │ ├── AppIcon.appiconset │ │ ├── 128.png │ │ ├── 16.png │ │ ├── 256.png │ │ ├── 32.png │ │ ├── 512.png │ │ ├── 64.png │ │ └── Contents.json │ └── MenuIcon.imageset │ │ ├── 32.png │ │ ├── 64.png │ │ └── Contents.json ├── Launchable.h ├── Launchable.m ├── MainMenu.xib ├── MultitouchEvent.h ├── MultitouchEvent.m ├── MultitouchListener.h ├── MultitouchListener.m ├── MultitouchManager.h ├── MultitouchManager.m ├── MultitouchSupport.h ├── MultitouchTouch.h ├── MultitouchTouch.m ├── NSBezierPath+MCAdditions.h ├── NSBezierPath+MCAdditions.m ├── NSColor+ColorExtensions.h ├── NSColor+ColorExtensions.m ├── NSImage+M5Darkable.h ├── NSImage+M5Darkable.m ├── NSStatusItemPrioritizer.h ├── NSStatusItemPrioritizer.m ├── PFMoveApplication.h ├── PFMoveApplication.m ├── RepeatedImageView.h ├── RepeatedImageView.m ├── RoundedCornerView.h ├── RoundedCornerView.m ├── SafariPage.h ├── SafariPage.m ├── Script.h ├── Script.m ├── Scripts │ ├── Close Current Window or Tab.scpt │ ├── Current Application - Quit.scpt │ ├── Go To Last Active App.scpt │ ├── Screen Brightness - Decrease.scpt │ ├── Screen Brightness - Increase.scpt │ ├── Spotify - Next Track.scpt │ ├── Spotify - Play:Pause.scpt │ ├── Spotify - Previous Track.scpt │ ├── iTunes - Next Track.scpt │ ├── iTunes - Play:Pause.scpt │ └── iTunes - Previous Track.scpt ├── ShadowTextFieldCell.h ├── ShadowTextFieldCell.m ├── Sparkle.framework │ ├── Headers │ ├── Modules │ ├── Resources │ ├── Sparkle │ └── Versions │ │ ├── A │ │ ├── Headers │ │ │ ├── SUAppcast.h │ │ │ ├── SUAppcastItem.h │ │ │ ├── SUErrors.h │ │ │ ├── SUExport.h │ │ │ ├── SUStandardVersionComparator.h │ │ │ ├── SUUpdater.h │ │ │ ├── SUVersionComparisonProtocol.h │ │ │ ├── SUVersionDisplayProtocol.h │ │ │ └── Sparkle.h │ │ ├── Modules │ │ │ └── module.modulemap │ │ ├── Resources │ │ │ ├── Autoupdate.app │ │ │ │ └── Contents │ │ │ │ │ ├── Info.plist │ │ │ │ │ ├── MacOS │ │ │ │ │ └── Autoupdate │ │ │ │ │ ├── PkgInfo │ │ │ │ │ └── Resources │ │ │ │ │ ├── AppIcon.icns │ │ │ │ │ ├── SUStatus.nib │ │ │ │ │ ├── ar.lproj │ │ │ │ │ └── Sparkle.strings │ │ │ │ │ ├── cs.lproj │ │ │ │ │ └── Sparkle.strings │ │ │ │ │ ├── da.lproj │ │ │ │ │ └── Sparkle.strings │ │ │ │ │ ├── de.lproj │ │ │ │ │ └── Sparkle.strings │ │ │ │ │ ├── el.lproj │ │ │ │ │ └── Sparkle.strings │ │ │ │ │ ├── en.lproj │ │ │ │ │ └── Sparkle.strings │ │ │ │ │ ├── es.lproj │ │ │ │ │ └── Sparkle.strings │ │ │ │ │ ├── fr.lproj │ │ │ │ │ └── Sparkle.strings │ │ │ │ │ ├── is.lproj │ │ │ │ │ └── Sparkle.strings │ │ │ │ │ ├── it.lproj │ │ │ │ │ └── Sparkle.strings │ │ │ │ │ ├── ja.lproj │ │ │ │ │ └── Sparkle.strings │ │ │ │ │ ├── ko.lproj │ │ │ │ │ └── Sparkle.strings │ │ │ │ │ ├── nb.lproj │ │ │ │ │ └── Sparkle.strings │ │ │ │ │ ├── nl.lproj │ │ │ │ │ └── Sparkle.strings │ │ │ │ │ ├── pl.lproj │ │ │ │ │ └── Sparkle.strings │ │ │ │ │ ├── pt_BR.lproj │ │ │ │ │ └── Sparkle.strings │ │ │ │ │ ├── pt_PT.lproj │ │ │ │ │ └── Sparkle.strings │ │ │ │ │ ├── ro.lproj │ │ │ │ │ └── Sparkle.strings │ │ │ │ │ ├── ru.lproj │ │ │ │ │ └── Sparkle.strings │ │ │ │ │ ├── sk.lproj │ │ │ │ │ └── Sparkle.strings │ │ │ │ │ ├── sl.lproj │ │ │ │ │ └── Sparkle.strings │ │ │ │ │ ├── sv.lproj │ │ │ │ │ └── Sparkle.strings │ │ │ │ │ ├── th.lproj │ │ │ │ │ └── Sparkle.strings │ │ │ │ │ ├── tr.lproj │ │ │ │ │ └── Sparkle.strings │ │ │ │ │ ├── uk.lproj │ │ │ │ │ └── Sparkle.strings │ │ │ │ │ ├── zh_CN.lproj │ │ │ │ │ └── Sparkle.strings │ │ │ │ │ └── zh_TW.lproj │ │ │ │ │ └── Sparkle.strings │ │ │ ├── Info.plist │ │ │ ├── SUModelTranslation.plist │ │ │ ├── SUStatus.nib │ │ │ ├── ar.lproj │ │ │ │ ├── SUAutomaticUpdateAlert.nib │ │ │ │ ├── SUUpdateAlert.nib │ │ │ │ ├── SUUpdatePermissionPrompt.nib │ │ │ │ └── Sparkle.strings │ │ │ ├── cs.lproj │ │ │ │ ├── SUAutomaticUpdateAlert.nib │ │ │ │ ├── SUUpdateAlert.nib │ │ │ │ ├── SUUpdatePermissionPrompt.nib │ │ │ │ └── Sparkle.strings │ │ │ ├── da.lproj │ │ │ │ ├── SUAutomaticUpdateAlert.nib │ │ │ │ ├── SUUpdateAlert.nib │ │ │ │ ├── SUUpdatePermissionPrompt.nib │ │ │ │ └── Sparkle.strings │ │ │ ├── de.lproj │ │ │ │ ├── SUAutomaticUpdateAlert.nib │ │ │ │ ├── SUUpdateAlert.nib │ │ │ │ ├── SUUpdatePermissionPrompt.nib │ │ │ │ └── Sparkle.strings │ │ │ ├── el.lproj │ │ │ │ ├── SUAutomaticUpdateAlert.nib │ │ │ │ ├── SUUpdateAlert.nib │ │ │ │ ├── SUUpdatePermissionPrompt.nib │ │ │ │ └── Sparkle.strings │ │ │ ├── en.lproj │ │ │ │ ├── SUAutomaticUpdateAlert.nib │ │ │ │ ├── SUUpdateAlert.nib │ │ │ │ ├── SUUpdatePermissionPrompt.nib │ │ │ │ └── Sparkle.strings │ │ │ ├── es.lproj │ │ │ │ ├── SUAutomaticUpdateAlert.nib │ │ │ │ ├── SUUpdateAlert.nib │ │ │ │ ├── SUUpdatePermissionPrompt.nib │ │ │ │ └── Sparkle.strings │ │ │ ├── fr.lproj │ │ │ │ ├── SUAutomaticUpdateAlert.nib │ │ │ │ ├── SUUpdateAlert.nib │ │ │ │ ├── SUUpdatePermissionPrompt.nib │ │ │ │ └── Sparkle.strings │ │ │ ├── fr_CA.lproj │ │ │ ├── is.lproj │ │ │ │ ├── SUAutomaticUpdateAlert.nib │ │ │ │ ├── SUUpdateAlert.nib │ │ │ │ ├── SUUpdatePermissionPrompt.nib │ │ │ │ └── Sparkle.strings │ │ │ ├── it.lproj │ │ │ │ ├── SUAutomaticUpdateAlert.nib │ │ │ │ ├── SUUpdateAlert.nib │ │ │ │ ├── SUUpdatePermissionPrompt.nib │ │ │ │ └── Sparkle.strings │ │ │ ├── ja.lproj │ │ │ │ ├── SUAutomaticUpdateAlert.nib │ │ │ │ ├── SUUpdateAlert.nib │ │ │ │ ├── SUUpdatePermissionPrompt.nib │ │ │ │ └── Sparkle.strings │ │ │ ├── ko.lproj │ │ │ │ ├── SUAutomaticUpdateAlert.nib │ │ │ │ ├── SUUpdateAlert.nib │ │ │ │ ├── SUUpdatePermissionPrompt.nib │ │ │ │ └── Sparkle.strings │ │ │ ├── nb.lproj │ │ │ │ ├── SUAutomaticUpdateAlert.nib │ │ │ │ ├── SUUpdateAlert.nib │ │ │ │ ├── SUUpdatePermissionPrompt.nib │ │ │ │ └── Sparkle.strings │ │ │ ├── nl.lproj │ │ │ │ ├── SUAutomaticUpdateAlert.nib │ │ │ │ ├── SUUpdateAlert.nib │ │ │ │ ├── SUUpdatePermissionPrompt.nib │ │ │ │ └── Sparkle.strings │ │ │ ├── pl.lproj │ │ │ │ ├── SUAutomaticUpdateAlert.nib │ │ │ │ ├── SUUpdateAlert.nib │ │ │ │ ├── SUUpdatePermissionPrompt.nib │ │ │ │ └── Sparkle.strings │ │ │ ├── pt.lproj │ │ │ ├── pt_BR.lproj │ │ │ │ ├── SUAutomaticUpdateAlert.nib │ │ │ │ ├── SUUpdateAlert.nib │ │ │ │ ├── SUUpdatePermissionPrompt.nib │ │ │ │ └── Sparkle.strings │ │ │ ├── pt_PT.lproj │ │ │ │ ├── SUAutomaticUpdateAlert.nib │ │ │ │ ├── SUUpdateAlert.nib │ │ │ │ ├── SUUpdatePermissionPrompt.nib │ │ │ │ └── Sparkle.strings │ │ │ ├── ro.lproj │ │ │ │ ├── SUAutomaticUpdateAlert.nib │ │ │ │ ├── SUUpdateAlert.nib │ │ │ │ ├── SUUpdatePermissionPrompt.nib │ │ │ │ └── Sparkle.strings │ │ │ ├── ru.lproj │ │ │ │ ├── SUAutomaticUpdateAlert.nib │ │ │ │ ├── SUUpdateAlert.nib │ │ │ │ ├── SUUpdatePermissionPrompt.nib │ │ │ │ └── Sparkle.strings │ │ │ ├── sk.lproj │ │ │ │ ├── SUAutomaticUpdateAlert.nib │ │ │ │ ├── SUUpdateAlert.nib │ │ │ │ ├── SUUpdatePermissionPrompt.nib │ │ │ │ └── Sparkle.strings │ │ │ ├── sl.lproj │ │ │ │ ├── SUAutomaticUpdateAlert.nib │ │ │ │ ├── SUUpdateAlert.nib │ │ │ │ ├── SUUpdatePermissionPrompt.nib │ │ │ │ └── Sparkle.strings │ │ │ ├── sv.lproj │ │ │ │ ├── SUAutomaticUpdateAlert.nib │ │ │ │ ├── SUUpdateAlert.nib │ │ │ │ ├── SUUpdatePermissionPrompt.nib │ │ │ │ └── Sparkle.strings │ │ │ ├── th.lproj │ │ │ │ ├── SUAutomaticUpdateAlert.nib │ │ │ │ ├── SUUpdateAlert.nib │ │ │ │ ├── SUUpdatePermissionPrompt.nib │ │ │ │ └── Sparkle.strings │ │ │ ├── tr.lproj │ │ │ │ ├── SUAutomaticUpdateAlert.nib │ │ │ │ ├── SUUpdateAlert.nib │ │ │ │ ├── SUUpdatePermissionPrompt.nib │ │ │ │ └── Sparkle.strings │ │ │ ├── uk.lproj │ │ │ │ ├── SUAutomaticUpdateAlert.nib │ │ │ │ ├── SUUpdateAlert.nib │ │ │ │ ├── SUUpdatePermissionPrompt.nib │ │ │ │ └── Sparkle.strings │ │ │ ├── zh_CN.lproj │ │ │ │ ├── SUAutomaticUpdateAlert.nib │ │ │ │ ├── SUUpdateAlert.nib │ │ │ │ ├── SUUpdatePermissionPrompt.nib │ │ │ │ └── Sparkle.strings │ │ │ └── zh_TW.lproj │ │ │ │ ├── SUAutomaticUpdateAlert.nib │ │ │ │ ├── SUUpdateAlert.nib │ │ │ │ ├── SUUpdatePermissionPrompt.nib │ │ │ │ └── Sparkle.strings │ │ └── Sparkle │ │ └── Current ├── WebPage.h ├── WebPage.m ├── background2.png ├── main.m ├── niceLine.png ├── niceLineFlipped.png ├── tableCellBack.png └── trackpadBackground.png ├── LICENSE ├── README.md ├── Sparkle.xml └── Sparkle2.xml /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | 3 | *.xcuserstate 4 | *.xccheckout 5 | *.xcscheme 6 | *.xcsettings 7 | 8 | xcuserdata/ 9 | 10 | Pods/ 11 | Podfile.lock 12 | -------------------------------------------------------------------------------- /Gestr.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Gestr.xcodeproj/project.xcworkspace/xcshareddata/Gestr.xccheckout: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDESourceControlProjectFavoriteDictionaryKey 6 | 7 | IDESourceControlProjectIdentifier 8 | FEA89BFB-3B99-4EBE-A4D5-AF6E581AF68B 9 | IDESourceControlProjectName 10 | Gestr 11 | IDESourceControlProjectOriginsDictionary 12 | 13 | 9F5B72516961C41DD7382622640ABC197CA6F2F8 14 | https://github.com/mhuusko5/Gestr.git 15 | 16 | IDESourceControlProjectPath 17 | Gestr.xcodeproj 18 | IDESourceControlProjectRelativeInstallPathDictionary 19 | 20 | 9F5B72516961C41DD7382622640ABC197CA6F2F8 21 | ../.. 22 | 23 | IDESourceControlProjectURL 24 | https://github.com/mhuusko5/Gestr.git 25 | IDESourceControlProjectVersion 26 | 111 27 | IDESourceControlProjectWCCIdentifier 28 | 9F5B72516961C41DD7382622640ABC197CA6F2F8 29 | IDESourceControlProjectWCConfigurations 30 | 31 | 32 | IDESourceControlRepositoryExtensionIdentifierKey 33 | public.vcs.git 34 | IDESourceControlWCCIdentifierKey 35 | 9F5B72516961C41DD7382622640ABC197CA6F2F8 36 | IDESourceControlWCCName 37 | Gestr 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /Gestr.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Gestr.xcodeproj/project.xcworkspace/xcuserdata/mhuusko.xcuserdatad/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | HasAskedToTakeAutomaticSnapshotBeforeSignificantChanges 6 | 7 | SnapshotAutomaticallyBeforeSignificantChanges 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /Gestr.xcodeproj/xcuserdata/mhuusko.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | -------------------------------------------------------------------------------- /Gestr.xcodeproj/xcuserdata/mhuusko.xcuserdatad/xcschemes/Gestr.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 39 | 40 | 41 | 42 | 51 | 52 | 58 | 59 | 60 | 61 | 62 | 63 | 69 | 70 | 76 | 77 | 78 | 79 | 81 | 82 | 85 | 86 | 87 | -------------------------------------------------------------------------------- /Gestr.xcodeproj/xcuserdata/mhuusko.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | Gestr.xcscheme 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | SuppressBuildableAutocreation 14 | 15 | 00D15EB31855520C00336935 16 | 17 | primary 18 | 19 | 20 | 00D15ED41855520D00336935 21 | 22 | primary 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /Gestr.xcodeproj/xcuserdata/mhuusko5.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | Gestr.xcscheme 8 | 9 | orderHint 10 | 0 11 | 12 | Gestr.xcscheme_^#shared#^_ 13 | 14 | orderHint 15 | 0 16 | 17 | 18 | SuppressBuildableAutocreation 19 | 20 | 00D15EB31855520C00336935 21 | 22 | primary 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /Gestr/AppButtonCell.h: -------------------------------------------------------------------------------- 1 | #import "NSColor+ColorExtensions.h" 2 | 3 | #define AppButtonBlackGradientBottomColor [NSColor colorWithDeviceWhite:0.150 alpha:1.000] 4 | #define AppButtonBlackGradientTopColor [NSColor colorWithDeviceWhite:0.220 alpha:1.000] 5 | #define AppButtonBlackHighlightColor [NSColor colorWithDeviceWhite:1.000 alpha:0.050] 6 | #define AppButtonBlueGradientBottomColor [NSColor colorWithDeviceRed:0.000 green:0.310 blue:0.780 alpha:1.000] 7 | #define AppButtonBlueGradientTopColor [NSColor colorWithDeviceRed:0.000 green:0.530 blue:0.870 alpha:1.000] 8 | #define AppButtonBlueHighlightColor [NSColor colorWithDeviceWhite:1.000 alpha:0.250] 9 | 10 | #define AppButtonTextFont [NSFont systemFontOfSize:12.f] 11 | #define AppButtonBlackTextShadowOffset NSMakeSize(0.f, 1.f) 12 | #define AppButtonBlackTextShadowBlurRadius 1.f 13 | #define AppButtonBlackTextShadowColor [NSColor blackColor] 14 | #define AppButtonBlueTextShadowOffset NSMakeSize(0.f, -1.f) 15 | #define AppButtonBlueTextShadowBlurRadius 2.f 16 | #define AppButtonBlueTextShadowColor [NSColor colorWithDeviceWhite:0.000 alpha:0.600] 17 | 18 | #define AppButtonDisabledAlpha 0.7f 19 | #define AppButtonCornerRadius 3.f 20 | #define AppButtonDropShadowColor [NSColor colorWithDeviceWhite:1.000 alpha:0.050] 21 | #define AppButtonDropShadowBlurRadius 1.f 22 | #define AppButtonDropShadowOffset NSMakeSize(0.f, -1.f) 23 | #define AppButtonBorderColor [NSColor blackColor] 24 | #define AppButtonHighlightOverlayColor [NSColor colorWithDeviceWhite:0.000 alpha:0.300] 25 | 26 | #define AppButtonCheckboxTextOffset 3.f 27 | #define AppButtonCheckboxCheckmarkColor [NSColor colorWithDeviceWhite:0.780 alpha:1.000] 28 | #define AppButtonCheckboxCheckmarkLeftOffset 4.f 29 | #define AppButtonCheckboxCheckmarkTopOffset 1.f 30 | #define AppButtonCheckboxCheckmarkShadowOffset NSMakeSize(0.f, 0.f) 31 | #define AppButtonCheckboxCheckmarkShadowBlurRadius 3.f 32 | #define AppButtonCheckboxCheckmarkShadowColor [NSColor colorWithDeviceWhite:0.000 alpha:0.750] 33 | #define AppButtonCheckboxCheckmarkLineWidth 2.f 34 | 35 | @interface AppButtonCell : NSButtonCell 36 | 37 | @end 38 | -------------------------------------------------------------------------------- /Gestr/AppButtonCell.m: -------------------------------------------------------------------------------- 1 | #import "AppButtonCell.h" 2 | 3 | static NSString *const AppButtonReturnKeyEquivalent = @"\r"; 4 | 5 | @interface AppButtonCell () 6 | 7 | @property NSBezierPath *appButtonBezelPath; 8 | @property NSButtonType appButtonType; 9 | 10 | - (BOOL)App_shouldDrawBlueButton; 11 | - (void)App_drawButtonBezelWithFrame:(NSRect)frame inView:(NSView *)controlView; 12 | - (void)App_drawCheckboxBezelWithFrame:(NSRect)frame inView:(NSView *)controlView; 13 | - (NSRect)App_drawButtonTitle:(NSAttributedString *)title withFrame:(NSRect)frame inView:(NSView *)controlView; 14 | - (NSRect)App_drawCheckboxTitle:(NSAttributedString *)title withFrame:(NSRect)frame inView:(NSView *)controlView; 15 | - (NSBezierPath *)App_checkmarkPathForRect:(NSRect)rect mixed:(BOOL)mixed; 16 | 17 | @end 18 | 19 | @implementation AppButtonCell 20 | 21 | - (id)initWithCoder:(NSCoder *)aDecoder { 22 | if ((self = [super initWithCoder:aDecoder])) { 23 | _appButtonType = (NSButtonType)[[self valueForKey:@"buttonType"] unsignedIntegerValue]; 24 | } 25 | 26 | return self; 27 | } 28 | 29 | - (void)setButtonType:(NSButtonType)aType { 30 | _appButtonType = aType; 31 | [super setButtonType:aType]; 32 | } 33 | 34 | - (void)drawWithFrame:(NSRect)cellFrame inView:(NSView *)controlView { 35 | if (![self isEnabled]) { 36 | CGContextSetAlpha([[NSGraphicsContext currentContext] graphicsPort], AppButtonDisabledAlpha); 37 | } 38 | 39 | [super drawWithFrame:cellFrame inView:controlView]; 40 | if (_appButtonBezelPath && [self isHighlighted]) { 41 | [AppButtonHighlightOverlayColor set]; 42 | [_appButtonBezelPath fill]; 43 | } 44 | } 45 | 46 | - (void)drawBezelWithFrame:(NSRect)frame inView:(NSView *)controlView { 47 | [self App_drawButtonBezelWithFrame:frame inView:controlView]; 48 | } 49 | 50 | - (NSRect)drawTitle:(NSAttributedString *)title withFrame:(NSRect)frame inView:(NSView *)controlView { 51 | switch (_appButtonType) { 52 | case NSSwitchButton: 53 | return [self App_drawCheckboxTitle:title withFrame:frame inView:controlView]; 54 | break; 55 | 56 | default: 57 | return [self App_drawButtonTitle:title withFrame:frame inView:controlView]; 58 | break; 59 | } 60 | } 61 | 62 | - (void)drawImage:(NSImage *)image withFrame:(NSRect)frame inView:(NSView *)controlView { 63 | if (_appButtonType == NSSwitchButton) { 64 | [self App_drawCheckboxBezelWithFrame:frame inView:controlView]; 65 | } 66 | } 67 | 68 | - (void)App_drawButtonBezelWithFrame:(NSRect)frame inView:(NSView *)controlView { 69 | frame = NSInsetRect(frame, 0.5f, 0.5f); 70 | frame.size.height -= AppButtonDropShadowBlurRadius; 71 | BOOL blue = [self App_shouldDrawBlueButton]; 72 | _appButtonBezelPath = [NSBezierPath bezierPathWithRoundedRect:frame xRadius:AppButtonCornerRadius yRadius:AppButtonCornerRadius]; 73 | NSGradient *gradientFill = [[NSGradient alloc] initWithStartingColor:blue ? AppButtonBlueGradientBottomColor:AppButtonBlackGradientBottomColor endingColor:blue ? AppButtonBlueGradientTopColor:AppButtonBlackGradientTopColor]; 74 | 75 | [gradientFill drawInBezierPath:_appButtonBezelPath angle:270.f]; 76 | 77 | [NSGraphicsContext saveGraphicsState]; 78 | [AppButtonBorderColor set]; 79 | NSShadow *dropShadow = [NSShadow new]; 80 | [dropShadow setShadowColor:AppButtonDropShadowColor]; 81 | [dropShadow setShadowBlurRadius:AppButtonDropShadowBlurRadius]; 82 | [dropShadow setShadowOffset:AppButtonDropShadowOffset]; 83 | [dropShadow set]; 84 | [_appButtonBezelPath stroke]; 85 | [NSGraphicsContext restoreGraphicsState]; 86 | 87 | NSRect highlightRect = NSInsetRect(frame, -0.5f, 1.f); 88 | 89 | highlightRect.size.height *= 2.f; 90 | [NSGraphicsContext saveGraphicsState]; 91 | NSBezierPath *highlightPath = [NSBezierPath bezierPathWithRoundedRect:highlightRect xRadius:AppButtonCornerRadius yRadius:AppButtonCornerRadius]; 92 | [_appButtonBezelPath addClip]; 93 | [blue ? AppButtonBlueHighlightColor:AppButtonBlackHighlightColor set]; 94 | [highlightPath stroke]; 95 | [NSGraphicsContext restoreGraphicsState]; 96 | } 97 | 98 | - (void)App_drawCheckboxBezelWithFrame:(NSRect)frame inView:(NSView *)controlView { 99 | frame.size.width -= 2.f; 100 | frame.size.height -= 1.f; 101 | [self App_drawButtonBezelWithFrame:frame inView:controlView]; 102 | 103 | if ([self state] == NSOffState) { 104 | return; 105 | } 106 | 107 | NSBezierPath *path = [self App_checkmarkPathForRect:frame mixed:[self state] == NSMixedState]; 108 | [path setLineWidth:AppButtonCheckboxCheckmarkLineWidth]; 109 | [myGreenColor set]; 110 | NSShadow *shadow = [NSShadow new]; 111 | [shadow setShadowColor:AppButtonCheckboxCheckmarkShadowColor]; 112 | [shadow setShadowBlurRadius:AppButtonCheckboxCheckmarkShadowBlurRadius]; 113 | [shadow setShadowOffset:AppButtonCheckboxCheckmarkShadowOffset]; 114 | [NSGraphicsContext saveGraphicsState]; 115 | [shadow set]; 116 | [path stroke]; 117 | [NSGraphicsContext restoreGraphicsState]; 118 | } 119 | 120 | - (NSBezierPath *)App_checkmarkPathForRect:(NSRect)rect mixed:(BOOL)mixed { 121 | NSBezierPath *path = [NSBezierPath bezierPath]; 122 | if (mixed) { 123 | NSPoint left = NSMakePoint(rect.origin.x + AppButtonCheckboxCheckmarkLeftOffset, round(NSMidY(rect))); 124 | NSPoint right = NSMakePoint(NSMaxX(rect) - AppButtonCheckboxCheckmarkLeftOffset, left.y); 125 | [path moveToPoint:left]; 126 | [path lineToPoint:right]; 127 | } 128 | else { 129 | NSPoint top = NSMakePoint(NSMaxX(rect), rect.origin.y); 130 | NSPoint bottom = NSMakePoint(round(NSMidX(rect)), round(NSMidY(rect)) + AppButtonCheckboxCheckmarkTopOffset); 131 | NSPoint left = NSMakePoint(rect.origin.x + AppButtonCheckboxCheckmarkLeftOffset, round(bottom.y / 2.f)); 132 | [path moveToPoint:top]; 133 | [path lineToPoint:bottom]; 134 | [path lineToPoint:left]; 135 | } 136 | 137 | return path; 138 | } 139 | 140 | - (NSRect)App_drawButtonTitle:(NSAttributedString *)title withFrame:(NSRect)frame inView:(NSView *)controlView { 141 | BOOL blue = [self App_shouldDrawBlueButton]; 142 | NSString *label = [title string]; 143 | NSShadow *textShadow = [NSShadow new]; 144 | [textShadow setShadowOffset:blue ? AppButtonBlueTextShadowOffset:AppButtonBlackTextShadowOffset]; 145 | [textShadow setShadowColor:blue ? AppButtonBlueTextShadowColor:AppButtonBlackTextShadowColor]; 146 | [textShadow setShadowBlurRadius:blue ? AppButtonBlueTextShadowBlurRadius:AppButtonBlackTextShadowBlurRadius]; 147 | NSColor *textColor; 148 | if ([self isEnabled]) { 149 | textColor = myGreenColor; 150 | } 151 | else { 152 | textColor = [myWhiteColor lightenColorByValue:0.6]; 153 | } 154 | 155 | NSDictionary *attributes = @{ NSFontAttributeName : AppButtonTextFont, NSForegroundColorAttributeName : textColor, NSShadowAttributeName : textShadow }; 156 | NSAttributedString *attrLabel = [[NSAttributedString alloc] initWithString:label attributes:attributes]; 157 | NSSize labelSize = attrLabel.size; 158 | NSRect labelRect = NSMakeRect(NSMidX(frame) - (labelSize.width / 2.f), 1 + NSMidY(frame) - (labelSize.height / 2.f), labelSize.width, labelSize.height); 159 | [attrLabel drawInRect:NSIntegralRect(labelRect)]; 160 | return labelRect; 161 | } 162 | 163 | - (NSRect)App_drawCheckboxTitle:(NSAttributedString *)title withFrame:(NSRect)frame inView:(NSView *)controlView { 164 | NSString *label = [title string]; 165 | NSShadow *textShadow = [NSShadow new]; 166 | [textShadow setShadowOffset:AppButtonBlackTextShadowOffset]; 167 | [textShadow setShadowColor:AppButtonBlackTextShadowColor]; 168 | [textShadow setShadowBlurRadius:AppButtonBlackTextShadowBlurRadius]; 169 | NSColor *textColor; 170 | if ([self isEnabled]) { 171 | textColor = myGreenColor; 172 | } 173 | else { 174 | textColor = [myWhiteColor lightenColorByValue:0.6]; 175 | } 176 | 177 | NSDictionary *attributes = @{ NSFontAttributeName : AppButtonTextFont, NSForegroundColorAttributeName : textColor, NSShadowAttributeName : textShadow }; 178 | NSAttributedString *attrLabel = [[NSAttributedString alloc] initWithString:label attributes:attributes]; 179 | NSSize labelSize = attrLabel.size; 180 | NSRect labelRect = NSMakeRect(frame.origin.x + AppButtonCheckboxTextOffset, NSMidY(frame) - (labelSize.height / 2.f), labelSize.width, labelSize.height); 181 | [attrLabel drawInRect:NSIntegralRect(labelRect)]; 182 | return labelRect; 183 | } 184 | 185 | #pragma mark - Private 186 | 187 | - (BOOL)App_shouldDrawBlueButton { 188 | return [[self keyEquivalent] isEqualToString:AppButtonReturnKeyEquivalent] && (_appButtonType != NSSwitchButton); 189 | } 190 | 191 | @end 192 | -------------------------------------------------------------------------------- /Gestr/AppController.h: -------------------------------------------------------------------------------- 1 | #import "GestureSetupController.h" 2 | #import "GestureRecognitionController.h" 3 | #import "MultitouchManager.h" 4 | #import "PFMoveApplication.h" 5 | @class GestureSetupController, GestureRecognitionController; 6 | 7 | @interface AppController : NSObject 8 | 9 | @property GestureSetupController *gestureSetupController; 10 | @property GestureRecognitionController *gestureRecognitionController; 11 | 12 | - (void)awakeFromNib; 13 | - (IBAction)closeAndQuit:(id)sender; 14 | - (void)applicationWillFinishLaunching:(NSNotification *)notification; 15 | - (void)applicationDidFinishLaunching:(NSNotification *)notification; 16 | - (BOOL)applicationShouldHandleReopen:(NSApplication *)sender hasVisibleWindows:(BOOL)flag; 17 | 18 | @end 19 | -------------------------------------------------------------------------------- /Gestr/AppController.m: -------------------------------------------------------------------------------- 1 | #import "AppController.h" 2 | 3 | @interface AppController () 4 | 5 | @property BOOL awakedFromNib; 6 | 7 | @end 8 | 9 | @implementation AppController 10 | 11 | - (void)awakeFromNib { 12 | if (!_awakedFromNib) { 13 | _awakedFromNib = YES; 14 | 15 | int instancesOfCurrentApplication = 0; 16 | for (NSRunningApplication *application in[[NSWorkspace sharedWorkspace] runningApplications]) { 17 | if ([application.bundleIdentifier isEqualToString:[[NSBundle mainBundle] bundleIdentifier]]) { 18 | if (++instancesOfCurrentApplication > 1) { 19 | [NSApp terminate:self]; 20 | } 21 | } 22 | } 23 | 24 | _gestureSetupController.appController = self; 25 | _gestureRecognitionController.appController = self; 26 | 27 | [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(closeAndQuit:) name:NSApplicationWillTerminateNotification object:NSApp]; 28 | } 29 | } 30 | 31 | - (IBAction)closeAndQuit:(id)sender { 32 | [[MultitouchManager sharedMultitouchManager] stopForwardingMultitouchEventsToListeners]; 33 | 34 | [NSApp terminate:self]; 35 | } 36 | 37 | - (void)applicationWillFinishLaunching:(NSNotification *)notification { 38 | PFMoveToApplicationsFolderIfNecessary(); 39 | } 40 | 41 | - (void)applicationDidFinishLaunching:(NSNotification *)notification { 42 | [_gestureRecognitionController applicationDidFinishLaunching]; 43 | [_gestureSetupController applicationDidFinishLaunching]; 44 | } 45 | 46 | - (BOOL)applicationShouldHandleReopen:(NSApplication *)sender hasVisibleWindows:(BOOL)flag { 47 | [_gestureSetupController toggleSetupWindow:nil]; 48 | return NO; 49 | } 50 | 51 | @end 52 | -------------------------------------------------------------------------------- /Gestr/AppSegmentedCell.h: -------------------------------------------------------------------------------- 1 | #import "NSBezierPath+MCAdditions.h" 2 | #import "NSColor+ColorExtensions.h" 3 | 4 | @interface AppSegmentedCell : NSSegmentedCell 5 | 6 | @end 7 | -------------------------------------------------------------------------------- /Gestr/AppSegmentedCell.m: -------------------------------------------------------------------------------- 1 | #import "AppSegmentedCell.h" 2 | 3 | #define AppSegControlGradientBottomColor [NSColor colorWithDeviceWhite:0.150 alpha:1.000] 4 | #define AppSegControlGradientTopColor [NSColor colorWithDeviceWhite:0.220 alpha:1.000] 5 | #define AppSegControlSelectedGradientBottomColor [NSColor colorWithDeviceWhite:0.130 alpha:1.000] 6 | #define AppSegControlSelectedGradientTopColor [NSColor colorWithDeviceWhite:0.120 alpha:1.000] 7 | 8 | #define AppSegControlDividerGradientBottomColor [NSColor colorWithDeviceWhite:0.120 alpha:1.000] 9 | #define AppSegControlDividerGradientTopColor [NSColor colorWithDeviceWhite:0.160 alpha:1.000] 10 | 11 | #define AppSegControlHighlightColor [NSColor colorWithDeviceWhite:1.000 alpha:0.050] 12 | #define AppSegControlHighlightOverlayColor [NSColor colorWithDeviceWhite:0.000 alpha:0.300] 13 | #define AppSegControlBorderColor [NSColor blackColor] 14 | #define AppSegControlCornerRadius 3.f 15 | 16 | #define AppSegControlInnerShadowColor [NSColor colorWithDeviceWhite:0.000 alpha:1.000] 17 | #define AppSegControlInnerShadowBlurRadius 3.f 18 | #define AppSegControlInnerShadowOffset NSMakeSize(0.f, -1.f) 19 | 20 | #define AppSegControlDropShadowColor [NSColor colorWithDeviceWhite:1.000 alpha:0.050] 21 | #define AppSegControlDropShadowBlurRadius 1.f 22 | #define AppSegControlDropShadowOffset NSMakeSize(0.f, -1.f) 23 | 24 | #define AppSegControlTextFont [NSFont systemFontOfSize:11.f] 25 | #define AppSegControlTextColor [NSColor colorWithDeviceWhite:0.700 alpha:1.000] 26 | #define AppSegControlSelectedTextColor [NSColor whiteColor] 27 | #define AppSegControlSelectedTextShadowOffset NSMakeSize(0.f, -1.f) 28 | #define AppSegControlTextShadowOffset NSMakeSize(0.f, 1.f) 29 | #define AppSegControlTextShadowBlurRadius 1.f 30 | #define AppSegControlTextShadowColor [NSColor blackColor] 31 | 32 | #define AppSegControlDisabledAlpha 0.5f 33 | 34 | #define AppSegControlXEdgeMargin 10.f 35 | #define AppSegControlYEdgeMargin 5.f 36 | #define AppSegControlImageLabelMargin 5.f 37 | 38 | // This is a value that is set internally by AppKit, used for layout purposes in this code 39 | // Don't change this 40 | #define AppSegControlDivderWidth 3.f 41 | 42 | @interface AppSegmentedCell () 43 | // Returns the bezier path that the border was drawn in 44 | - (NSBezierPath *)App_drawBackgroundWithFrame:(NSRect)cellFrame inView:(NSView *)controlView; 45 | - (NSRect)App_widthForSegment:(NSInteger)segment; 46 | - (void)App_drawInteriorOfSegment:(NSInteger)segment inFrame:(NSRect)frame inView:(NSView *)controlView; 47 | @end 48 | 49 | @implementation AppSegmentedCell 50 | 51 | - (void)drawWithFrame:(NSRect)cellFrame inView:(NSView *)controlView { 52 | cellFrame.size.height += 5; 53 | 54 | CGContextRef ctx = [[NSGraphicsContext currentContext] graphicsPort]; 55 | if (![self isEnabled]) { 56 | CGContextSetAlpha(ctx, AppSegControlDisabledAlpha); 57 | } 58 | 59 | // The frame needs to be inset 0.5px to make the border line crisp 60 | // because NSBezierPath draws the stroke centered on the bounds of the rect 61 | // This means that 0.5px of the 1px stroke line will be outside the rect and the other half will be inside 62 | NSInteger segmentCount = [self segmentCount]; 63 | cellFrame = NSInsetRect(cellFrame, 0.5f, 0.5f); 64 | cellFrame.size.height -= AppSegControlDropShadowBlurRadius; // Make room for the drop shadow 65 | // OS X seems to add 3px of extra space in the frame per segment for the dividers 66 | // but we get rid of this 67 | NSBezierPath *path = [self App_drawBackgroundWithFrame:cellFrame inView:controlView]; 68 | NSRect bounds = [path bounds]; 69 | if (!segmentCount) { 70 | return; 71 | } // Stop drawing if there are no segments 72 | 73 | [path addClip]; 74 | // Need to improvise a bit here because there is no public API to get the 75 | // drawing rect of a specific segment 76 | CGFloat currentOrigin = 0.0; 77 | for (NSInteger i = 0; i < segmentCount; i++) { 78 | CGFloat width = [self widthForSegment:i]; 79 | 80 | // widthForSegment: returns 0 for autosized segments 81 | // so we need to divide the width of the cell evenly between all the segments 82 | // It will still break if one segment is much wider than the others 83 | if (width == 0) { 84 | width = (cellFrame.size.width - (AppSegControlDivderWidth * (segmentCount - 1))) / segmentCount; 85 | } 86 | 87 | if (i != (segmentCount - 1)) { 88 | width += AppSegControlDivderWidth; 89 | } 90 | 91 | NSRect frame = NSMakeRect(bounds.origin.x + currentOrigin, bounds.origin.y, width, bounds.size.height); 92 | [NSGraphicsContext saveGraphicsState]; 93 | if ([self isEnabled] && ![self isEnabledForSegment:i]) { 94 | CGContextSetAlpha(ctx, AppSegControlDisabledAlpha); 95 | } 96 | 97 | [self drawSegment:i inFrame:frame withView:controlView]; 98 | [NSGraphicsContext restoreGraphicsState]; 99 | currentOrigin += width; 100 | } 101 | } 102 | 103 | - (NSBezierPath *)App_drawBackgroundWithFrame:(NSRect)cellFrame inView:(NSView *)controlView { 104 | NSBezierPath *borderPath = [NSBezierPath bezierPathWithRoundedRect:cellFrame xRadius:AppSegControlCornerRadius yRadius:AppSegControlCornerRadius]; 105 | NSGradient *gradientFill = [[NSGradient alloc] initWithStartingColor:AppSegControlGradientBottomColor endingColor:AppSegControlGradientTopColor]; 106 | // Draw the gradient fill 107 | [gradientFill drawInBezierPath:borderPath angle:270.f]; 108 | // Draw the border and drop shadow 109 | [NSGraphicsContext saveGraphicsState]; 110 | [AppSegControlBorderColor set]; 111 | NSShadow *dropShadow = [NSShadow new]; 112 | [dropShadow setShadowColor:AppSegControlDropShadowColor]; 113 | [dropShadow setShadowBlurRadius:AppSegControlDropShadowBlurRadius]; 114 | [dropShadow setShadowOffset:AppSegControlDropShadowOffset]; 115 | [dropShadow set]; 116 | [borderPath stroke]; 117 | [NSGraphicsContext restoreGraphicsState]; 118 | // Draw the highlight line around the top edge of the pill 119 | // Outset the width of the rectangle by 0.5px so that the highlight "bleeds" around the rounded corners 120 | // Outset the height by 1px so that the line is drawn right below the border 121 | NSRect highlightRect = NSInsetRect(cellFrame, -0.5f, 1.f); 122 | // Make the height of the highlight rect something bigger than the bounds so that it won't show up on the bottom 123 | highlightRect.size.height *= 2.f; 124 | [NSGraphicsContext saveGraphicsState]; 125 | NSBezierPath *highlightPath = [NSBezierPath bezierPathWithRoundedRect:highlightRect xRadius:AppSegControlCornerRadius yRadius:AppSegControlCornerRadius]; 126 | [borderPath addClip]; 127 | [AppSegControlHighlightColor set]; 128 | [highlightPath stroke]; 129 | [NSGraphicsContext restoreGraphicsState]; 130 | return borderPath; 131 | } 132 | 133 | - (void)drawSegment:(NSInteger)segment inFrame:(NSRect)frame withView:(NSView *)controlView { 134 | BOOL selected = [self isSelectedForSegment:segment]; 135 | // Only draw the divider if it's not selected and it isn't the last segment 136 | BOOL drawDivider = !selected && (segment < ([self segmentCount] - 1)) && ([self selectedSegment] != (segment + 1)); 137 | if (selected) { 138 | NSGradient *gradientFill = [[NSGradient alloc] initWithStartingColor:AppSegControlSelectedGradientBottomColor endingColor:AppSegControlSelectedGradientTopColor]; 139 | [gradientFill drawInRect:frame angle:270.f]; 140 | NSShadow *innerShadow = [NSShadow new]; 141 | [innerShadow setShadowColor:AppSegControlInnerShadowColor]; 142 | [innerShadow setShadowBlurRadius:AppSegControlInnerShadowBlurRadius]; 143 | [innerShadow setShadowOffset:AppSegControlInnerShadowOffset]; 144 | NSBezierPath *path = [NSBezierPath bezierPathWithRect:frame]; 145 | [path fillWithInnerShadow:innerShadow]; 146 | } 147 | 148 | [self App_drawInteriorOfSegment:segment inFrame:frame inView:controlView]; 149 | NSEvent *currentEvent = [NSApp currentEvent]; // This is probably a dirty way of figuring out whether to highlight 150 | if (currentEvent.type == NSLeftMouseDown && [self isEnabledForSegment:segment]) { 151 | NSPoint location = [controlView convertPoint:[currentEvent locationInWindow] fromView:nil]; 152 | if (NSPointInRect(location, frame)) { 153 | [AppSegControlHighlightOverlayColor set]; 154 | [NSBezierPath fillRect:frame]; 155 | } 156 | } 157 | 158 | if (drawDivider) { 159 | NSRect highlightRect = NSMakeRect(round(NSMaxX(frame) - 1.f), frame.origin.y, 1.f, frame.size.height); 160 | [AppSegControlHighlightColor set]; 161 | [NSBezierPath fillRect:highlightRect]; 162 | NSRect dividerRect = highlightRect; 163 | dividerRect.origin.x -= 1.f; 164 | NSGradient *dividerFill = [[NSGradient alloc] initWithStartingColor:AppSegControlDividerGradientBottomColor endingColor:AppSegControlDividerGradientTopColor]; 165 | [dividerFill drawInRect:NSIntegralRect(dividerRect) angle:270.f]; 166 | } 167 | } 168 | 169 | - (void)App_drawInteriorOfSegment:(NSInteger)segment inFrame:(NSRect)frame inView:(NSView *)controlView { 170 | BOOL selected = [self isSelectedForSegment:segment]; 171 | NSString *label = [self labelForSegment:segment]; 172 | NSImage *image = [self imageForSegment:segment]; 173 | NSRect imageRect = NSZeroRect; 174 | if (image) { 175 | NSSize imageSize = [image size]; 176 | CGFloat maxImageHeight = frame.size.height - (AppSegControlYEdgeMargin * 2.f); 177 | CGFloat imageHeight = MIN(maxImageHeight, imageSize.height); 178 | imageRect = NSMakeRect(round(NSMidX(frame) - (imageSize.width / 2.f)), round(NSMidY(frame) - (imageHeight / 2.f)), imageSize.width, imageHeight); 179 | } 180 | 181 | if (label) { 182 | NSShadow *textShadow = [NSShadow new]; 183 | [textShadow setShadowOffset:selected ? AppSegControlSelectedTextShadowOffset:AppSegControlTextShadowOffset]; 184 | [textShadow setShadowColor:AppSegControlTextShadowColor]; 185 | [textShadow setShadowBlurRadius:AppSegControlTextShadowBlurRadius]; 186 | 187 | NSColor *textColor; 188 | if (selected) { 189 | textColor = myGreenColor; 190 | } 191 | else { 192 | textColor = [myWhiteColor darkenColorByValue:0.1]; 193 | } 194 | 195 | NSDictionary *attributes = @{ NSFontAttributeName : AppSegControlTextFont, NSForegroundColorAttributeName: textColor, NSShadowAttributeName: textShadow }; 196 | NSAttributedString *attrLabel = [[NSAttributedString alloc] initWithString:label attributes:attributes]; 197 | NSSize labelSize = attrLabel.size; 198 | if (image) { 199 | CGFloat totalContentWidth = labelSize.width + imageRect.size.width + AppSegControlImageLabelMargin; 200 | imageRect.origin.x = round(NSMidX(frame) - (totalContentWidth / 2.f)); 201 | } 202 | 203 | NSRect labelRect = NSMakeRect((image == nil) ? (NSMidX(frame) - (labelSize.width / 2.f)) : (NSMaxX(imageRect) + AppSegControlImageLabelMargin), -4 + NSMidY(frame) - (labelSize.height / 2.f), labelSize.width, labelSize.height); 204 | [attrLabel drawInRect:NSIntegralRect(labelRect)]; 205 | } 206 | 207 | NSImageCell *imageCell = [[NSImageCell alloc] init]; 208 | [imageCell setImage:image]; 209 | [imageCell setImageScaling:[self imageScalingForSegment:segment]]; 210 | [imageCell setHighlighted:[self isHighlighted]]; 211 | [imageCell drawWithFrame:imageRect inView:controlView]; 212 | } 213 | 214 | - (NSRect)App_widthForSegment:(NSInteger)segment { 215 | return NSZeroRect; 216 | } 217 | 218 | @end 219 | -------------------------------------------------------------------------------- /Gestr/AppTableCellView.h: -------------------------------------------------------------------------------- 1 | #import "AppButtonCell.h" 2 | 3 | @interface AppTableCellView : NSTableCellView 4 | 5 | - (void)setBackgroundStyle:(NSBackgroundStyle)backgroundStyle; 6 | 7 | @end 8 | -------------------------------------------------------------------------------- /Gestr/AppTableCellView.m: -------------------------------------------------------------------------------- 1 | #import "AppTableCellView.h" 2 | 3 | @implementation AppTableCellView 4 | 5 | - (void)setBackgroundStyle:(NSBackgroundStyle)backgroundStyle { 6 | self.textField.textColor = (backgroundStyle == NSBackgroundStyleDark) ? myGreenColor : [myWhiteColor darkenColorByValue:0.1]; 7 | 8 | [super setBackgroundStyle:backgroundStyle]; 9 | } 10 | 11 | - (void)drawRect:(NSRect)dirtyRect { 12 | [super drawRect:dirtyRect]; 13 | } 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /Gestr/AppTableView.h: -------------------------------------------------------------------------------- 1 | #import "GestureSetupController.h" 2 | 3 | @interface AppTableView : NSTableView 4 | 5 | - (BOOL)resignFirstResponder; 6 | 7 | @end 8 | -------------------------------------------------------------------------------- /Gestr/AppTableView.m: -------------------------------------------------------------------------------- 1 | #import "AppTableView.h" 2 | 3 | @implementation AppTableView 4 | 5 | - (BOOL)resignFirstResponder { 6 | [(GestureSetupController *)self.delegate tableViewFocus : YES]; 7 | return YES; 8 | } 9 | 10 | - (BOOL)becomeFirstResponder { 11 | [(GestureSetupController *)self.delegate tableViewFocus : NO]; 12 | return YES; 13 | } 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /Gestr/AppTextFieldCell.h: -------------------------------------------------------------------------------- 1 | #import "AppButtonCell.h" 2 | 3 | @interface AppTextFieldCell : NSTextFieldCell 4 | 5 | - (void)drawWithFrame:(NSRect)cellFrame inView:(NSView *)controlView; 6 | 7 | @end 8 | -------------------------------------------------------------------------------- /Gestr/AppTextFieldCell.m: -------------------------------------------------------------------------------- 1 | #import "AppTextFieldCell.h" 2 | 3 | @implementation AppTextFieldCell 4 | 5 | - (void)drawWithFrame:(NSRect)cellFrame inView:(NSView *)controlView { 6 | cellFrame = NSInsetRect(cellFrame, 0.5f, 0.5f); 7 | cellFrame.size.height -= AppButtonDropShadowBlurRadius; 8 | cellFrame.origin.y += AppButtonDropShadowBlurRadius; 9 | 10 | NSBezierPath *__bezelPath = [NSBezierPath bezierPathWithRoundedRect:cellFrame xRadius:AppButtonCornerRadius yRadius:AppButtonCornerRadius]; 11 | NSGradient *gradientFill = [[NSGradient alloc] initWithStartingColor:AppButtonBlackGradientBottomColor endingColor:AppButtonBlackGradientTopColor]; 12 | 13 | [gradientFill drawInBezierPath:__bezelPath angle:270.f]; 14 | 15 | [NSGraphicsContext saveGraphicsState]; 16 | [AppButtonBorderColor set]; 17 | NSShadow *dropShadow = [NSShadow new]; 18 | [dropShadow setShadowColor:AppButtonDropShadowColor]; 19 | [dropShadow setShadowBlurRadius:AppButtonDropShadowBlurRadius]; 20 | [dropShadow setShadowOffset:AppButtonDropShadowOffset]; 21 | [dropShadow set]; 22 | [__bezelPath stroke]; 23 | [NSGraphicsContext restoreGraphicsState]; 24 | 25 | NSRect highlightRect = NSInsetRect(cellFrame, -0.5f, 1.f); 26 | 27 | highlightRect.size.height *= 2.f; 28 | [NSGraphicsContext saveGraphicsState]; 29 | NSBezierPath *highlightPath = [NSBezierPath bezierPathWithRoundedRect:highlightRect xRadius:AppButtonCornerRadius yRadius:AppButtonCornerRadius]; 30 | [__bezelPath addClip]; 31 | [AppButtonBlackHighlightColor set]; 32 | [highlightPath stroke]; 33 | [NSGraphicsContext restoreGraphicsState]; 34 | 35 | NSMutableAttributedString *attrString = [[NSMutableAttributedString alloc] initWithAttributedString:[self attributedStringValue]]; 36 | 37 | NSShadow *textShadow = [NSShadow new]; 38 | [textShadow setShadowOffset:AppButtonBlackTextShadowOffset]; 39 | [textShadow setShadowColor:AppButtonBlackTextShadowColor]; 40 | [textShadow setShadowBlurRadius:AppButtonBlackTextShadowBlurRadius]; 41 | 42 | [attrString addAttribute:NSShadowAttributeName value:textShadow range:(NSRange) {0, [attrString length] } 43 | ]; 44 | [attrString addAttribute:NSForegroundColorAttributeName value:myGreenColor range:(NSRange) {0, [attrString length] } 45 | ]; 46 | 47 | NSSize labelSize = attrString.size; 48 | NSRect labelRect = NSMakeRect(NSMidX(cellFrame) - (labelSize.width / 2.f), NSMidY(cellFrame) - (labelSize.height / 2.f), labelSize.width, labelSize.height); 49 | [attrString drawInRect:NSIntegralRect(labelRect)]; 50 | } 51 | 52 | @end 53 | -------------------------------------------------------------------------------- /Gestr/Application.h: -------------------------------------------------------------------------------- 1 | #import "Launchable.h" 2 | 3 | @interface Application : Launchable 4 | 5 | @property NSString *bundleId; 6 | 7 | - (id)initWithDisplayName:(NSString *)displayName icon:(NSImage *)icon bundleId:(NSString *)bundleId; 8 | - (void)launch; 9 | 10 | @end 11 | -------------------------------------------------------------------------------- /Gestr/Application.m: -------------------------------------------------------------------------------- 1 | #import "Application.h" 2 | 3 | @implementation Application 4 | 5 | - (id)initWithDisplayName:(NSString *)displayName icon:(NSImage *)icon bundleId:(NSString *)bundleId { 6 | NSString *launchId = bundleId; 7 | 8 | self = [super initWithDisplayName:displayName launchId:launchId icon:icon]; 9 | 10 | _bundleId = bundleId; 11 | 12 | return self; 13 | } 14 | 15 | - (void)launch { 16 | [[NSWorkspace sharedWorkspace] launchAppWithBundleIdentifier:_bundleId options:NSWorkspaceLaunchDefault additionalEventParamDescriptor:nil launchIdentifier:nil]; 17 | } 18 | 19 | @end 20 | -------------------------------------------------------------------------------- /Gestr/ChromePage.h: -------------------------------------------------------------------------------- 1 | #import "WebPage.h" 2 | 3 | @interface ChromePage : WebPage 4 | 5 | - (id)initWithDisplayName:(NSString *)displayName icon:(NSImage *)icon url:(NSString *)url; 6 | 7 | @end 8 | -------------------------------------------------------------------------------- /Gestr/ChromePage.m: -------------------------------------------------------------------------------- 1 | #import "ChromePage.h" 2 | 3 | @implementation ChromePage 4 | 5 | - (id)initWithDisplayName:(NSString *)displayName icon:(NSImage *)icon url:(NSString *)url { 6 | return (self = [super initWithDisplayName:displayName icon:icon url:url targetBrowserId:@"com.google.Chrome"]); 7 | } 8 | 9 | @end 10 | -------------------------------------------------------------------------------- /Gestr/Gestr-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | ${PRODUCT_NAME} 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | $(MARKETING_VERSION) 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | $(CURRENT_PROJECT_VERSION) 23 | LSApplicationCategoryType 24 | public.app-category.utilities 25 | LSMinimumSystemVersion 26 | ${MACOSX_DEPLOYMENT_TARGET} 27 | LSUIElement 28 | 29 | NSAppleEventsUsageDescription 30 | Gestr requires Apple Events permission to run some custom Apple Scripts. 31 | NSHumanReadableCopyright 32 | Copyright © 2020 Mathew Huusko V. All rights reserved. 33 | NSMainNibFile 34 | MainMenu 35 | NSPrincipalClass 36 | NSApplication 37 | SUEnableAutomaticChecks 38 | 39 | SUFeedURL 40 | https://raw.githubusercontent.com/mhuusko5/Gestr/master/Sparkle2.xml 41 | 42 | 43 | -------------------------------------------------------------------------------- /Gestr/Gestr-Prefix.pch: -------------------------------------------------------------------------------- 1 | #ifdef __OBJC__ 2 | #import 3 | #import 4 | #import 5 | #endif 6 | 7 | #define myGreenColor [NSColor colorWithDeviceRed : (49.0f / 255.0f)green : (212.0f / 255.0f)blue : (74.0f / 255.0f)alpha : 1.0] 8 | #define myWhiteColor [[NSColorList colorListNamed : @ "Crayons"] colorWithKey : @ "Silver"] 9 | -------------------------------------------------------------------------------- /Gestr/Gestr.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.security.automation.apple-events 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Gestr/Gesture.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import "GestureUtils.h" 3 | #import "GestureTemplate.h" 4 | 5 | @interface Gesture : NSObject 6 | 7 | @property NSString *identity; 8 | @property NSMutableArray *strokes; 9 | @property NSMutableArray *templates; 10 | 11 | - (id)initWithIdentity:(NSString *)identity andStrokes:(NSMutableArray *)strokes; 12 | - (void)generateTemplates; 13 | - (void)encodeWithCoder:(NSCoder *)coder; 14 | - (id)initWithCoder:(NSCoder *)coder; 15 | - (id)copyWithZone:(NSZone *)zone; 16 | - (NSString *)description; 17 | 18 | @end 19 | -------------------------------------------------------------------------------- /Gestr/Gesture.m: -------------------------------------------------------------------------------- 1 | #import "Gesture.h" 2 | 3 | @implementation Gesture 4 | 5 | - (id)initWithIdentity:(NSString *)identity andStrokes:(NSMutableArray *)strokes { 6 | self = [super init]; 7 | 8 | _identity = identity; 9 | _strokes = strokes; 10 | 11 | return self; 12 | } 13 | 14 | - (void)generateTemplates { 15 | GestureStroke *allPoints = [[GestureStroke alloc] init]; 16 | for (GestureStroke *stroke in _strokes) { 17 | for (GesturePoint *point in stroke.points) { 18 | [allPoints addPoint:point]; 19 | } 20 | } 21 | 22 | NSMutableArray *order = [NSMutableArray array]; 23 | for (int i = 0; i < _strokes.count; i++) { 24 | [order insertObject:@(i) atIndex:i]; 25 | } 26 | 27 | NSMutableArray *unistrokes = GUMakeUnistrokes(_strokes, GUHeapPermute((int)_strokes.count, order, [NSMutableArray array])); 28 | 29 | _templates = [NSMutableArray array]; 30 | for (int j = 0; j < unistrokes.count; j++) { 31 | [_templates addObject:[[GestureTemplate alloc] initWithPoints:unistrokes[j]]]; 32 | } 33 | } 34 | 35 | - (void)encodeWithCoder:(NSCoder *)coder { 36 | [coder encodeObject:_strokes forKey:@"strokes"]; 37 | [coder encodeObject:_identity forKey:@"identity"]; 38 | } 39 | 40 | - (id)initWithCoder:(NSCoder *)coder { 41 | self = [super init]; 42 | 43 | _strokes = [coder decodeObjectForKey:@"strokes"]; 44 | _identity = [coder decodeObjectForKey:@"identity"]; 45 | 46 | return self; 47 | } 48 | 49 | - (id)copyWithZone:(NSZone *)zone { 50 | Gesture *copy = [[Gesture allocWithZone:zone] initWithIdentity:[_identity copy] andStrokes:[_strokes copy]]; 51 | 52 | return copy; 53 | } 54 | 55 | - (NSString *)description { 56 | NSMutableString *desc = [[NSMutableString alloc] init]; 57 | for (GestureStroke *stroke in _strokes) { 58 | [desc appendFormat:@"%@ \r", [stroke description]]; 59 | } 60 | 61 | return desc; 62 | } 63 | 64 | @end 65 | -------------------------------------------------------------------------------- /Gestr/GesturePoint.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | @interface GesturePoint : NSObject 4 | 5 | @property float x, y; 6 | @property int strokeId; 7 | 8 | - (id)initWithX:(float)x andY:(float)y andStrokeId:(int)strokeId; 9 | - (void)encodeWithCoder:(NSCoder *)coder; 10 | - (id)initWithCoder:(NSCoder *)coder; 11 | - (id)copyWithZone:(NSZone *)zone; 12 | - (NSString *)description; 13 | 14 | @end 15 | -------------------------------------------------------------------------------- /Gestr/GesturePoint.m: -------------------------------------------------------------------------------- 1 | #import "GesturePoint.h" 2 | 3 | @implementation GesturePoint 4 | 5 | - (id)initWithX:(float)x andY:(float)y andStrokeId:(int)strokeId { 6 | self = [super init]; 7 | 8 | _x = x; 9 | _y = y; 10 | _strokeId = strokeId; 11 | 12 | return self; 13 | } 14 | 15 | - (void)encodeWithCoder:(NSCoder *)coder { 16 | [coder encodeFloat:_x forKey:@"x"]; 17 | [coder encodeFloat:_y forKey:@"y"]; 18 | [coder encodeInt:_strokeId forKey:@"strokeId"]; 19 | } 20 | 21 | - (id)initWithCoder:(NSCoder *)coder { 22 | self = [super init]; 23 | 24 | _x = [coder decodeFloatForKey:@"x"]; 25 | _y = [coder decodeFloatForKey:@"y"]; 26 | _strokeId = [coder decodeIntForKey:@"strokeId"]; 27 | 28 | return self; 29 | } 30 | 31 | - (id)copyWithZone:(NSZone *)zone { 32 | GesturePoint *copy = [[GesturePoint allocWithZone:zone] initWithX:_x andY:_y andStrokeId:_strokeId]; 33 | 34 | return copy; 35 | } 36 | 37 | - (NSString *)description { 38 | return [NSString stringWithFormat:@"X: %f Y: %f Stroke: %i", _x, _y, _strokeId]; 39 | } 40 | 41 | @end 42 | -------------------------------------------------------------------------------- /Gestr/GestureRecognitionController.h: -------------------------------------------------------------------------------- 1 | #import "GestureRecognitionModel.h" 2 | #import "AppController.h" 3 | #import "GestureRecognitionWindow.h" 4 | #import "GestureRecognitionView.h" 5 | #import "GestureRecognizer.h" 6 | #import "Launchable.h" 7 | #import "MultitouchManager.h" 8 | #import "RoundedCornerView.h" 9 | @class GestureRecognitionView, GestureRecognizer, AppController, RepeatedImageView; 10 | 11 | @interface GestureRecognitionController : NSObject 12 | 13 | @property GestureRecognitionModel *recognitionModel; 14 | @property AppController *appController; 15 | @property IBOutlet GestureRecognitionWindow *recognitionWindow; 16 | @property IBOutlet GestureRecognitionView *recognitionView; 17 | 18 | #pragma mark - 19 | #pragma mark Initialization 20 | - (void)awakeFromNib; 21 | - (void)applicationDidFinishLaunching; 22 | #pragma mark - 23 | 24 | #pragma mark - 25 | #pragma mark Recognition Utilities 26 | - (void)checkPartialGestureWithStrokes:(NSMutableArray *)strokes; 27 | - (void)recognizeGestureWithStrokes:(NSMutableArray *)strokes; 28 | - (void)shouldStartDetectingGesture:(BOOL)quick; 29 | - (void)disableScrollEventBlocking; 30 | #pragma mark - 31 | 32 | #pragma mark - 33 | #pragma mark Activation Event Handling 34 | - (void)handleMultitouchEvent:(MultitouchEvent *)event; 35 | - (CGEventRef)handleEvent:(CGEventRef)event withType:(int)type; 36 | CGEventRef handleEvent(CGEventTapProxy proxy, CGEventType type, CGEventRef eventRef, void *refcon); 37 | 38 | #pragma mark - 39 | 40 | #pragma mark - 41 | #pragma mark Window Methods 42 | - (void)fadeOutRecognitionWindow; 43 | - (void)toggleOutRecognitionWindow:(BOOL)fadeOut; 44 | - (void)toggleInRecognitionWindow; 45 | - (void)hideRecognitionWindow; 46 | - (void)windowDidResignKey:(NSNotification *)notification; 47 | - (void)layoutRecognitionWindow; 48 | #pragma mark - 49 | 50 | @end 51 | -------------------------------------------------------------------------------- /Gestr/GestureRecognitionModel.h: -------------------------------------------------------------------------------- 1 | #import "GestureRecognizer.h" 2 | 3 | @interface GestureRecognitionModel : NSObject 4 | 5 | @property GestureRecognizer *gestureDetector; 6 | 7 | #pragma mark - 8 | #pragma mark Setup 9 | - (void)setup; 10 | #pragma mark - 11 | 12 | #pragma mark - 13 | #pragma mark Gesture Data 14 | - (void)fetchAndLoadGestures; 15 | - (BOOL)fetchGestureDictionary; 16 | - (void)saveGestureDictionary; 17 | #pragma mark - 18 | 19 | #pragma mark - 20 | #pragma mark Setup Utilities 21 | - (void)saveGestureWithStrokes:(NSMutableArray *)gestureStrokes andIdentity:(NSString *)identity; 22 | - (Gesture *)getGestureWithIdentity:(NSString *)identity; 23 | - (void)deleteGestureWithName:(NSString *)identity; 24 | #pragma mark - 25 | 26 | @end 27 | -------------------------------------------------------------------------------- /Gestr/GestureRecognitionModel.m: -------------------------------------------------------------------------------- 1 | #import "GestureRecognitionModel.h" 2 | 3 | @interface GestureRecognitionModel () 4 | 5 | @property NSUserDefaults *storage; 6 | 7 | @property NSMutableDictionary *gestureDictionary; 8 | 9 | @end 10 | 11 | @implementation GestureRecognitionModel 12 | 13 | - (id)init { 14 | self = [super init]; 15 | 16 | _storage = [NSUserDefaults standardUserDefaults]; 17 | 18 | return self; 19 | } 20 | 21 | #pragma mark - 22 | #pragma mark Setup 23 | - (void)setup { 24 | [self fetchAndLoadGestures]; 25 | } 26 | 27 | #pragma mark - 28 | 29 | #pragma mark - 30 | #pragma mark Gesture Data 31 | - (void)fetchAndLoadGestures { 32 | [self fetchGestureDictionary]; 33 | 34 | _gestureDetector = [[GestureRecognizer alloc] init]; 35 | 36 | @try { 37 | for (id plistGestureKey in _gestureDictionary) { 38 | Gesture *plistGesture = [self getGestureWithIdentity:plistGestureKey]; 39 | if (plistGesture) { 40 | [_gestureDetector addGesture:plistGesture]; 41 | } 42 | else { 43 | @throw [NSException exceptionWithName:@"InvalidGesture" reason:@"Corrupted gesture data." userInfo:nil]; 44 | } 45 | } 46 | } 47 | @catch (NSException *exception) 48 | { 49 | _gestureDictionary = [NSMutableDictionary dictionary]; 50 | [self saveGestureDictionary]; 51 | 52 | _gestureDetector = [[GestureRecognizer alloc] init]; 53 | } 54 | } 55 | 56 | - (BOOL)fetchGestureDictionary { 57 | NSMutableDictionary *gestures; 58 | @try { 59 | NSData *gestureData; 60 | if ((gestureData = [_storage objectForKey:@"Gestures"])) { 61 | gestures = [((NSDictionary *)[NSKeyedUnarchiver unarchiveObjectWithData:gestureData])mutableCopy]; 62 | } 63 | else { 64 | gestures = [NSMutableDictionary dictionary]; 65 | } 66 | } 67 | @catch (NSException *exception) 68 | { 69 | gestures = [NSMutableDictionary dictionary]; 70 | } 71 | 72 | _gestureDictionary = gestures; 73 | } 74 | 75 | - (void)saveGestureDictionary { 76 | [_storage setObject:[NSKeyedArchiver archivedDataWithRootObject:_gestureDictionary] forKey:@"Gestures"]; 77 | [_storage synchronize]; 78 | } 79 | 80 | #pragma mark - 81 | 82 | #pragma mark - 83 | #pragma mark Setup Utilities 84 | - (void)saveGestureWithStrokes:(NSMutableArray *)gestureStrokes andIdentity:(NSString *)identity { 85 | int inputPointCount = 0; 86 | for (GestureStroke *stroke in gestureStrokes) { 87 | inputPointCount += stroke.pointCount; 88 | } 89 | if (inputPointCount > GUMinimumPointCount) { 90 | Gesture *gestureToSave = [[Gesture alloc] initWithIdentity:identity andStrokes:gestureStrokes]; 91 | 92 | _gestureDictionary[identity] = gestureToSave; 93 | [self saveGestureDictionary]; 94 | 95 | [_gestureDetector addGesture:gestureToSave]; 96 | } 97 | } 98 | 99 | - (Gesture *)getGestureWithIdentity:(NSString *)identity { 100 | Gesture *gesture = _gestureDictionary[identity]; 101 | if (gesture && gesture.identity && gesture.strokes && gesture.strokes.count > 0) { 102 | return gesture; 103 | } 104 | else { 105 | return nil; 106 | } 107 | } 108 | 109 | - (void)deleteGestureWithName:(NSString *)identity { 110 | [_gestureDictionary removeObjectForKey:identity]; 111 | [self saveGestureDictionary]; 112 | 113 | [_gestureDetector removeGestureWithIdentity:identity]; 114 | } 115 | 116 | #pragma mark - 117 | 118 | @end 119 | -------------------------------------------------------------------------------- /Gestr/GestureRecognitionView.h: -------------------------------------------------------------------------------- 1 | #import "GestureRecognitionController.h" 2 | #import "MultitouchEvent.h" 3 | @class GestureRecognitionController; 4 | 5 | @interface GestureRecognitionView : NSView 6 | 7 | @property GestureRecognitionController *recognitionController; 8 | @property BOOL detectingInput; 9 | 10 | - (id)initWithFrame:(NSRect)frame; 11 | 12 | - (void)dealWithMouseEvent:(NSEvent *)event ofType:(NSString *)mouseType; 13 | - (void)dealWithMultitouchEvent:(MultitouchEvent *)event; 14 | 15 | - (void)startMultitouchInput; 16 | - (void)startDetectingGesture:(BOOL)quick; 17 | 18 | - (void)finishDetectingGesture; 19 | - (void)finishDetectingGestureIgnore; 20 | - (void)finishDetectingGesture:(BOOL)ignore; 21 | 22 | - (void)checkPartialGesture; 23 | - (void)checkPartialGestureOnNewThread; 24 | 25 | - (void)resetInputTimers; 26 | - (void)resetAll; 27 | - (BOOL)acceptsFirstResponder; 28 | - (BOOL)canBecomeKeyView; 29 | - (void)drawRect:(NSRect)dirtyRect; 30 | 31 | @end 32 | -------------------------------------------------------------------------------- /Gestr/GestureRecognitionView.m: -------------------------------------------------------------------------------- 1 | #import "GestureRecognitionView.h" 2 | 3 | @interface GestureRecognitionView () 4 | 5 | @property NSMutableDictionary *touchPaths; 6 | @property NSMutableDictionary *gestureStrokes; 7 | @property NSMutableArray *orderedStrokeIds; 8 | 9 | @property NSTimer *startInputTimer; 10 | @property NSTimer *noInputTimer; 11 | @property NSTimer *detectInputTimer; 12 | @property NSTimer *checkPartialGestureTimer; 13 | 14 | @property int mouseStrokeIndex; 15 | @property BOOL quickdrawMode; 16 | 17 | @property NSDate *lastMultitouchRedraw; 18 | @property NSNumber *initialMultitouchDeviceId; 19 | 20 | @end 21 | 22 | @implementation GestureRecognitionView 23 | 24 | - (id)initWithFrame:(NSRect)frame { 25 | self = [super initWithFrame:frame]; 26 | 27 | _touchPaths = [NSMutableDictionary dictionary]; 28 | _gestureStrokes = [NSMutableDictionary dictionary]; 29 | _orderedStrokeIds = [NSMutableArray array]; 30 | 31 | _lastMultitouchRedraw = [NSDate date]; 32 | 33 | return self; 34 | } 35 | 36 | - (void)dealWithMouseEvent:(NSEvent *)event ofType:(NSString *)mouseType { 37 | if (!_recognitionController.appController.gestureSetupController.setupModel.multitouchOption && _detectingInput) { 38 | [self resetInputTimers]; 39 | 40 | NSPoint drawPoint = [self convertPoint:[event locationInWindow] fromView:nil]; 41 | 42 | if ([mouseType isEqualToString:@"down"]) { 43 | _mouseStrokeIndex++; 44 | } 45 | 46 | NSNumber *identity = @(_mouseStrokeIndex); 47 | 48 | if (!_gestureStrokes[identity]) { 49 | [_orderedStrokeIds addObject:identity]; 50 | _gestureStrokes[identity] = [[GestureStroke alloc] init]; 51 | } 52 | 53 | GesturePoint *detectorPoint = 54 | [[GesturePoint alloc] initWithX:(drawPoint.x / self.frame.size.width) * GUBoundingBoxSize andY:(drawPoint.y / self.frame.size.height) * GUBoundingBoxSize andStrokeId:[identity intValue]]; 55 | 56 | [_gestureStrokes[identity] addPoint:detectorPoint]; 57 | 58 | if ([mouseType isEqualToString:@"down"]) { 59 | NSBezierPath *tempPath = [NSBezierPath bezierPath]; 60 | [tempPath setLineWidth:self.frame.size.width / 95]; 61 | [tempPath setLineCapStyle:NSRoundLineCapStyle]; 62 | [tempPath setLineJoinStyle:NSRoundLineJoinStyle]; 63 | [tempPath moveToPoint:drawPoint]; 64 | 65 | _touchPaths[identity] = tempPath; 66 | } 67 | else if ([mouseType isEqualToString:@"drag"]) { 68 | NSBezierPath *tempPath = _touchPaths[identity]; 69 | [tempPath lineToPoint:drawPoint]; 70 | } 71 | else if ([mouseType isEqualToString:@"up"]) { 72 | if (_mouseStrokeIndex < 3) { 73 | if (!_detectInputTimer) { 74 | _detectInputTimer = [NSTimer scheduledTimerWithTimeInterval:((float)_recognitionController.appController.gestureSetupController.setupModel.readingDelayTime) / 1000.0 target:self selector:@selector(finishDetectingGesture) userInfo:nil repeats:NO]; 75 | } 76 | } 77 | else { 78 | [self finishDetectingGesture]; 79 | return; 80 | } 81 | 82 | NSBezierPath *tempPath = _touchPaths[identity]; 83 | [tempPath lineToPoint:drawPoint]; 84 | } 85 | 86 | [self setNeedsDisplay:YES]; 87 | } 88 | } 89 | 90 | - (void)mouseDown:(NSEvent *)theEvent { 91 | [self dealWithMouseEvent:theEvent ofType:@"down"]; 92 | } 93 | 94 | - (void)mouseDragged:(NSEvent *)theEvent { 95 | [self dealWithMouseEvent:theEvent ofType:@"drag"]; 96 | } 97 | 98 | - (void)mouseUp:(NSEvent *)theEvent { 99 | [self dealWithMouseEvent:theEvent ofType:@"up"]; 100 | } 101 | 102 | - (void)dealWithMultitouchEvent:(MultitouchEvent *)event { 103 | if (_recognitionController.appController.gestureSetupController.setupModel.multitouchOption && _detectingInput) { 104 | if (!_initialMultitouchDeviceId) { 105 | _initialMultitouchDeviceId = event.deviceIdentifier; 106 | } 107 | 108 | if ([event.deviceIdentifier isEqualToNumber:_initialMultitouchDeviceId]) { 109 | [self resetInputTimers]; 110 | 111 | if (!_detectInputTimer && event.touches.count == 0) { 112 | _detectInputTimer = [NSTimer scheduledTimerWithTimeInterval:((float)_recognitionController.appController.gestureSetupController.setupModel.readingDelayTime) / 1000.0 target:self selector:@selector(finishDetectingGesture) userInfo:nil repeats:NO]; 113 | } 114 | else { 115 | int shouldDrawLimit = _recognitionController.appController.gestureSetupController.setupModel.fullscreenOption ? 32 : 16; 116 | BOOL shouldDraw = ([_lastMultitouchRedraw timeIntervalSinceNow] * -1000.0 > shouldDrawLimit); 117 | 118 | if (_quickdrawMode && event.touches.count == 3) { 119 | MultitouchTouch *touch1 = event.touches[0]; 120 | MultitouchTouch *touch2 = event.touches[1]; 121 | MultitouchTouch *touch3 = event.touches[2]; 122 | MultitouchTouch *middleTouch; 123 | if ((touch1.x > touch2.x && touch1.x < touch3.x) || (touch1.x > touch3.x && touch1.x < touch2.x)) { 124 | middleTouch = touch1; 125 | } 126 | else if ((touch2.x > touch1.x && touch2.x < touch3.x) || (touch2.x > touch3.x && touch2.x < touch1.x)) { 127 | middleTouch = touch2; 128 | } 129 | else { 130 | middleTouch = touch3; 131 | } 132 | 133 | NSMutableArray *rearrangedTouches = [event.touches mutableCopy]; 134 | [rearrangedTouches removeObject:middleTouch]; 135 | [rearrangedTouches insertObject:middleTouch atIndex:0]; 136 | 137 | event.touches = rearrangedTouches; 138 | } 139 | 140 | for (MultitouchTouch *touch in event.touches) { 141 | float combinedTouchVelocity = fabs(touch.velX) + fabs(touch.velY); 142 | if (touch.state == MTTouchStateTouching && combinedTouchVelocity > 0.06) { 143 | NSPoint drawPoint = NSMakePoint(touch.x, touch.y); 144 | 145 | NSNumber *identity = touch.identifier; 146 | 147 | if (!_gestureStrokes[identity]) { 148 | if (_orderedStrokeIds.count < (_quickdrawMode ? 1 : 3)) { 149 | [_orderedStrokeIds addObject:identity]; 150 | _gestureStrokes[identity] = [[GestureStroke alloc] init]; 151 | } 152 | else { 153 | continue; 154 | } 155 | } 156 | 157 | GesturePoint *detectorPoint = [[GesturePoint alloc] initWithX:drawPoint.x * GUBoundingBoxSize andY:drawPoint.y * GUBoundingBoxSize andStrokeId:[identity intValue]]; 158 | 159 | [_gestureStrokes[identity] addPoint:detectorPoint]; 160 | 161 | drawPoint.x *= self.frame.size.width; 162 | drawPoint.y *= self.frame.size.height; 163 | 164 | NSBezierPath *tempPath; 165 | if ((tempPath = _touchPaths[identity])) { 166 | [tempPath lineToPoint:drawPoint]; 167 | } 168 | else { 169 | tempPath = [NSBezierPath bezierPath]; 170 | [tempPath setLineWidth:self.frame.size.width / 95]; 171 | [tempPath setLineCapStyle:NSRoundLineCapStyle]; 172 | [tempPath setLineJoinStyle:NSRoundLineJoinStyle]; 173 | [tempPath moveToPoint:drawPoint]; 174 | 175 | _touchPaths[identity] = tempPath; 176 | } 177 | } 178 | } 179 | 180 | if (shouldDraw) { 181 | [self setNeedsDisplay:YES]; 182 | _lastMultitouchRedraw = [NSDate date]; 183 | } 184 | } 185 | } 186 | else if (!_detectInputTimer) { 187 | _detectInputTimer = [NSTimer scheduledTimerWithTimeInterval:((float)_recognitionController.appController.gestureSetupController.setupModel.readingDelayTime) / 1000.0 target:self selector:@selector(finishDetectingGesture) userInfo:nil repeats:NO]; 188 | } 189 | } 190 | } 191 | 192 | - (void)startMultitouchInput { 193 | [[MultitouchManager sharedMultitouchManager] addMultitouchListenerWithTarget:self callback:@selector(dealWithMultitouchEvent:) andThread:nil]; 194 | } 195 | 196 | - (void)startDetectingGesture:(BOOL)quick { 197 | [self resetAll]; 198 | 199 | _mouseStrokeIndex = 0; 200 | 201 | _quickdrawMode = quick; 202 | 203 | _initialMultitouchDeviceId = nil; 204 | 205 | _checkPartialGestureTimer = [NSTimer scheduledTimerWithTimeInterval:0.25 target:self selector:@selector(checkPartialGesture) userInfo:nil repeats:YES]; 206 | [[NSRunLoop mainRunLoop] addTimer:_checkPartialGestureTimer forMode:NSEventTrackingRunLoopMode]; 207 | 208 | _noInputTimer = [NSTimer scheduledTimerWithTimeInterval:1.5 target:self selector:@selector(finishDetectingGestureIgnore) userInfo:nil repeats:NO]; 209 | 210 | [self becomeFirstResponder]; 211 | 212 | if (_recognitionController.appController.gestureSetupController.setupModel.multitouchOption) { 213 | [NSApp activateIgnoringOtherApps:YES]; 214 | CGAssociateMouseAndMouseCursorPosition(NO); 215 | 216 | if (quick) { 217 | [self startMultitouchInput]; 218 | } 219 | else { 220 | _startInputTimer = [NSTimer scheduledTimerWithTimeInterval:0.1 target:self selector:@selector(startMultitouchInput) userInfo:nil repeats:NO]; 221 | } 222 | } 223 | 224 | _detectingInput = YES; 225 | } 226 | 227 | - (void)finishDetectingGesture { 228 | [self finishDetectingGesture:NO]; 229 | } 230 | 231 | - (void)finishDetectingGestureIgnore { 232 | [self finishDetectingGesture:YES]; 233 | } 234 | 235 | - (void)finishDetectingGesture:(BOOL)ignore { 236 | _detectingInput = NO; 237 | 238 | if (_recognitionController.appController.gestureSetupController.setupModel.multitouchOption) { 239 | [[MultitouchManager sharedMultitouchManager] removeMultitouchListenersWithTarget:self andCallback:@selector(dealWithMultitouchEvent:)]; 240 | CGAssociateMouseAndMouseCursorPosition(YES); 241 | } 242 | 243 | NSMutableArray *orderedStrokes = [NSMutableArray array]; 244 | if (!ignore) { 245 | for (int i = 0; i < _orderedStrokeIds.count; i++) { 246 | [orderedStrokes addObject:_gestureStrokes[_orderedStrokeIds[i]]]; 247 | } 248 | } 249 | 250 | [self resetAll]; 251 | 252 | [_recognitionController recognizeGestureWithStrokes:orderedStrokes]; 253 | } 254 | 255 | - (void)checkPartialGesture { 256 | if (_orderedStrokeIds.count > 0) { 257 | [self performSelectorInBackground:@selector(checkPartialGestureOnNewThread) withObject:nil]; 258 | } 259 | } 260 | 261 | - (void)checkPartialGestureOnNewThread { 262 | NSMutableArray *partialOrderedStrokeIds = [_orderedStrokeIds copy]; 263 | NSMutableDictionary *partialGestureStrokes = [_gestureStrokes copy]; 264 | 265 | NSMutableArray *partialOrderedStrokes = [NSMutableArray array]; 266 | for (int i = 0; i < partialOrderedStrokeIds.count; i++) { 267 | [partialOrderedStrokes addObject:partialGestureStrokes[partialOrderedStrokeIds[i]]]; 268 | } 269 | 270 | [_recognitionController checkPartialGestureWithStrokes:partialOrderedStrokes]; 271 | } 272 | 273 | - (void)resetInputTimers { 274 | if (_startInputTimer) { 275 | [_startInputTimer invalidate]; 276 | _startInputTimer = nil; 277 | } 278 | 279 | if (_noInputTimer) { 280 | [_noInputTimer invalidate]; 281 | _noInputTimer = nil; 282 | } 283 | 284 | if (_detectInputTimer) { 285 | [_detectInputTimer invalidate]; 286 | _detectInputTimer = nil; 287 | } 288 | } 289 | 290 | - (void)resetAll { 291 | [self resetInputTimers]; 292 | 293 | if (_checkPartialGestureTimer) { 294 | [_checkPartialGestureTimer invalidate]; 295 | _checkPartialGestureTimer = nil; 296 | } 297 | 298 | _gestureStrokes = [NSMutableDictionary dictionary]; 299 | _orderedStrokeIds = [NSMutableArray array]; 300 | _touchPaths = [NSMutableDictionary dictionary]; 301 | 302 | _lastMultitouchRedraw = [NSDate date]; 303 | 304 | [self setNeedsDisplay:YES]; 305 | } 306 | 307 | - (BOOL)acceptsFirstResponder { 308 | return YES; 309 | } 310 | 311 | - (BOOL)canBecomeKeyView { 312 | return YES; 313 | } 314 | 315 | - (void)drawRect:(NSRect)dirtyRect { 316 | if (_detectingInput) { 317 | for (NSBezierPath *path in[_touchPaths allValues]) { 318 | [[NSColor colorWithCalibratedRed:0 green:0 blue:0 alpha:0.36] setStroke]; 319 | path.lineWidth *= 1.5; 320 | [path stroke]; 321 | 322 | [myGreenColor setStroke]; 323 | path.lineWidth /= 1.5; 324 | [path stroke]; 325 | } 326 | } 327 | } 328 | 329 | @end 330 | -------------------------------------------------------------------------------- /Gestr/GestureRecognitionWindow.h: -------------------------------------------------------------------------------- 1 | @interface GestureRecognitionWindow : NSPanel 2 | 3 | - (id)initWithContentRect:(NSRect)contentRect styleMask:(NSUInteger)aStyle backing:(NSBackingStoreType)bufferingType defer:(BOOL)flag; 4 | - (BOOL)canBecomeKeyWindow; 5 | 6 | @end 7 | -------------------------------------------------------------------------------- /Gestr/GestureRecognitionWindow.m: -------------------------------------------------------------------------------- 1 | #import "GestureRecognitionWindow.h" 2 | 3 | @implementation GestureRecognitionWindow 4 | 5 | - (id)initWithContentRect:(NSRect)contentRect styleMask:(NSUInteger)aStyle backing:(NSBackingStoreType)bufferingType defer:(BOOL)flag { 6 | self = [super initWithContentRect:contentRect styleMask:(NSBorderlessWindowMask | NSNonactivatingPanelMask) backing:bufferingType defer:flag]; 7 | 8 | /* 9 | NSNormalWindowLevel 10 | NSFloatingWindowLevel 11 | NSSubmenuWindowLevel 12 | NSTornOffMenuWindowLevel 13 | NSMainMenuWindowLevel 14 | NSStatusWindowLevel 15 | NSModalPanelWindowLevel 16 | NSPopUpMenuWindowLevel 17 | NSScreenSaverWindowLevel 18 | */ 19 | 20 | [self setLevel:NSPopUpMenuWindowLevel]; 21 | [self setCollectionBehavior:NSWindowCollectionBehaviorCanJoinAllSpaces]; 22 | [self setMovableByWindowBackground:NO]; 23 | [self setAlphaValue:0.0]; 24 | [self setOpaque:NO]; 25 | [self setHasShadow:NO]; 26 | [self setBackgroundColor:[NSColor clearColor]]; 27 | 28 | return self; 29 | } 30 | 31 | - (BOOL)canBecomeKeyWindow { 32 | return YES; 33 | } 34 | 35 | @end 36 | -------------------------------------------------------------------------------- /Gestr/GestureRecognizer.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import "GestureUtils.h" 3 | #import "Gesture.h" 4 | #import "GestureTemplate.h" 5 | #import "GestureResult.h" 6 | 7 | @interface GestureRecognizer : NSObject 8 | 9 | @property NSMutableArray *loadedGestures; 10 | 11 | - (GestureResult *)recognizeGestureWithStrokes:(NSMutableArray *)strokes; 12 | - (void)removeGestureWithIdentity:(NSString *)identity; 13 | - (void)addGesture:(Gesture *)gesture; 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /Gestr/GestureRecognizer.m: -------------------------------------------------------------------------------- 1 | #import "GestureRecognizer.h" 2 | 3 | @implementation GestureRecognizer 4 | 5 | - (id)init { 6 | self = [super init]; 7 | 8 | _loadedGestures = [NSMutableArray array]; 9 | 10 | return self; 11 | } 12 | 13 | - (GestureResult *)recognizeGestureWithStrokes:(NSMutableArray *)strokes { 14 | @try { 15 | GestureStroke *currentPoints = [[GestureStroke alloc] init]; 16 | for (GestureStroke *stroke in strokes) { 17 | for (GesturePoint *point in stroke.points) { 18 | [currentPoints addPoint:point]; 19 | } 20 | } 21 | 22 | GestureResult *result = [[GestureResult alloc] init]; 23 | 24 | if (currentPoints.pointCount > GUMinimumPointCount) { 25 | GestureTemplate *inputTemplate = [[GestureTemplate alloc] initWithPoints:currentPoints]; 26 | 27 | float lowestDistance = FLT_MAX; 28 | for (int i = 0; i < _loadedGestures.count; i++) { 29 | Gesture *gestureToMatch = _loadedGestures[i]; 30 | 31 | if (gestureToMatch.strokes.count == strokes.count) { 32 | NSMutableArray *loadedGestureTemplates = [gestureToMatch templates]; 33 | 34 | for (GestureTemplate *templateToMatch in loadedGestureTemplates) { 35 | if (GUAngleBetweenUnitVectors(inputTemplate.startUnitVector, templateToMatch.startUnitVector) <= GUDegreesToRadians(GUStartAngleLeniency)) { 36 | float distance = GUDistanceAtBestAngle(inputTemplate.stroke, templateToMatch.stroke); 37 | if (distance < lowestDistance) { 38 | lowestDistance = distance; 39 | 40 | result.gestureIdentity = gestureToMatch.identity; 41 | result.score = (int)ceilf(100.0 * (1.0 - (lowestDistance / (0.5 * sqrt(2 * pow(GUBoundingBoxSize, 2)))))); 42 | } 43 | } 44 | } 45 | } 46 | } 47 | } 48 | 49 | if (result.gestureIdentity.length > 0 && result.score > 0) { 50 | return result; 51 | } 52 | } 53 | @catch (NSException *exception) 54 | { 55 | return nil; 56 | } 57 | 58 | return nil; 59 | } 60 | 61 | - (void)removeGestureWithIdentity:(NSString *)identity { 62 | for (int i = 0; i < _loadedGestures.count; i++) { 63 | if ([((Gesture *)_loadedGestures[i]).identity isEqualToString:identity]) { 64 | [_loadedGestures removeObjectAtIndex:i]; 65 | return; 66 | } 67 | } 68 | } 69 | 70 | - (void)addGesture:(Gesture *)gesture { 71 | [self removeGestureWithIdentity:gesture.identity]; 72 | 73 | [gesture generateTemplates]; 74 | 75 | [_loadedGestures addObject:gesture]; 76 | } 77 | 78 | @end 79 | -------------------------------------------------------------------------------- /Gestr/GestureResult.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | @interface GestureResult : NSObject 4 | 5 | @property NSString *gestureIdentity; 6 | @property int score; 7 | 8 | @end 9 | -------------------------------------------------------------------------------- /Gestr/GestureResult.m: -------------------------------------------------------------------------------- 1 | #import "GestureResult.h" 2 | 3 | @implementation GestureResult 4 | 5 | @end 6 | -------------------------------------------------------------------------------- /Gestr/GestureSetupController.h: -------------------------------------------------------------------------------- 1 | #import "GestureSetupModel.h" 2 | #import "AppController.h" 3 | #import "GestureSetupWindow.h" 4 | #import "GestureSetupView.h" 5 | #import "Launchable.h" 6 | #import "MultitouchManager.h" 7 | #import "NSStatusItemPrioritizer.h" 8 | #import "NSImage+M5Darkable.h" 9 | @class GestureSetupView, AppController; 10 | 11 | @interface GestureSetupController : NSObject 12 | 13 | @property GestureSetupModel *setupModel; 14 | @property AppController *appController; 15 | @property IBOutlet GestureSetupWindow *setupWindow; 16 | @property IBOutlet GestureSetupView *setupView; 17 | 18 | #pragma mark - 19 | #pragma mark Initialization 20 | - (void)awakeFromNib; 21 | - (void)applicationDidFinishLaunching; 22 | #pragma mark - 23 | 24 | #pragma mark - 25 | #pragma mark Tableview Management 26 | - (NSMutableArray *)currentLaunchableArray; 27 | - (NSTableView *)currentLaunchableTableView; 28 | - (IBAction)launchableTypeChanged:(id)sender; 29 | - (void)tableViewFocus:(BOOL)lost; 30 | - (void)tableViewSelectionDidChange:(NSNotification *)aNotification; 31 | - (NSView *)tableView:(NSTableView *)tableView viewForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row; 32 | #pragma mark - 33 | 34 | #pragma mark - 35 | #pragma mark Interface Control 36 | - (void)updateSetupControls; 37 | - (void)showDrawNotification:(BOOL)show; 38 | #pragma mark - 39 | 40 | #pragma mark - 41 | #pragma mark Setup Utilities 42 | - (void)saveGestureWithStrokes:(NSMutableArray *)gestureStrokes; 43 | #pragma mark - 44 | 45 | #pragma mark - 46 | #pragma mark Setup Actions 47 | - (IBAction)assignSelectedGesture:(id)sender; 48 | - (IBAction)showSelectedGesture:(id)sender; 49 | - (IBAction)clearSelectedGesture:(id)sender; 50 | #pragma mark - 51 | 52 | #pragma mark - 53 | #pragma mark Custom Scripts 54 | - (void)shouldShowCustomScriptsAlert; 55 | - (void)finishShowingCustomScriptsAlert; 56 | #pragma mark - 57 | 58 | #pragma mark - 59 | #pragma mark Window Methods 60 | - (void)positionSetupWindow; 61 | - (IBAction)toggleSetupWindow:(id)sender; 62 | - (void)hideSetupWindow; 63 | - (void)windowDidResignKey:(NSNotification *)notification; 64 | - (void)repositionSetupWindow:(NSNotification *)notification; 65 | #pragma mark - 66 | 67 | #pragma mark - 68 | #pragma mark Recognition Options 69 | - (IBAction)minimumRecognitionScoreChanged:(id)sender; 70 | - (IBAction)readingDelayTimeChanged:(id)sender; 71 | - (IBAction)multitouchOptionChanged:(id)sender; 72 | - (IBAction)fullscreenOptionChanged:(id)sender; 73 | - (IBAction)loginStartOptionChanged:(id)sender; 74 | - (IBAction)quickdrawOptionChanged:(id)sender; 75 | #pragma mark - 76 | 77 | @end 78 | -------------------------------------------------------------------------------- /Gestr/GestureSetupModel.h: -------------------------------------------------------------------------------- 1 | #import "MultitouchManager.h" 2 | #import "Script.h" 3 | #import "Application.h" 4 | #import "ChromePage.h" 5 | #import "SafariPage.h" 6 | 7 | @interface GestureSetupModel : NSObject 8 | 9 | @property NSMutableArray *scriptArray; 10 | @property NSMutableArray *webPageArray; 11 | @property NSMutableArray *normalAppArray, *utilitiesAppArray, *systemAppArray; 12 | @property int readingDelayTime, minimumRecognitionScore; 13 | @property BOOL multitouchOption, fullscreenOption, loginStartOption, quickdrawOption; 14 | 15 | #pragma mark - 16 | #pragma mark Setup 17 | - (void)setup; 18 | #pragma mark - 19 | 20 | #pragma mark - 21 | #pragma mark Launchable Management 22 | - (Launchable *)findLaunchableWithId:(NSString *)identity; 23 | #pragma mark - 24 | 25 | #pragma mark - 26 | #pragma mark Script Managmeent 27 | - (NSMutableArray *)fetchScriptArray; 28 | #pragma mark - 29 | 30 | #pragma mark - 31 | #pragma mark Web Page Management 32 | - (NSMutableArray *)fetchWebPageArray; 33 | - (NSMutableArray *)fetchChromePages; 34 | - (NSMutableArray *)fetchSafariPages; 35 | #pragma mark - 36 | 37 | #pragma mark - 38 | #pragma mark Applications Management 39 | - (NSMutableArray *)fetchNormalAppArray; 40 | - (NSMutableArray *)fetchUtilitiesAppArray; 41 | - (NSMutableArray *)fetchSystemAppArray; 42 | - (NSMutableArray *)addApplicationsAtPath:(NSString *)path toArray:(NSMutableArray *)arr depth:(int)depth; 43 | #pragma mark - 44 | 45 | #pragma mark - 46 | #pragma mark Recognition Options 47 | - (int)fetchMinimumRecognitionScore; 48 | - (void)saveMinimumRecognitionScore:(int)newScore; 49 | - (int)fetchReadingDelayTime; 50 | - (void)saveReadingDelayTime:(int)newTime; 51 | - (BOOL)fetchMultitouchOption; 52 | - (void)saveMultitouchOption:(BOOL)newChoice; 53 | - (BOOL)fetchFullscreenOption; 54 | - (void)saveFullscreenOption:(BOOL)newChoice; 55 | - (BOOL)fetchLoginStartOption; 56 | - (void)saveLoginStartOption:(BOOL)newChoice; 57 | - (BOOL)fetchQuickdrawOption; 58 | - (void)saveQuickdrawOption:(BOOL)newChoice; 59 | #pragma mark - 60 | 61 | @end 62 | -------------------------------------------------------------------------------- /Gestr/GestureSetupView.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import "GestureSetupController.h" 3 | #import "Gesture.h" 4 | #import "MultitouchManager.h" 5 | @class GestureSetupController; 6 | 7 | @interface GestureSetupView : NSView 8 | 9 | @property GestureSetupController *setupController; 10 | @property BOOL detectingInput; 11 | 12 | - (id)initWithFrame:(NSRect)frame; 13 | 14 | - (void)dealWithMouseEvent:(NSEvent *)event ofType:(NSString *)mouseType; 15 | - (void)dealWithMultitouchEvent:(MultitouchEvent *)event; 16 | 17 | - (void)startMultitouchInput; 18 | - (void)startDetectingGesture; 19 | 20 | - (void)finishDetectingGesture; 21 | - (void)finishDetectingGestureIgnore; 22 | - (void)finishDetectingGesture:(BOOL)ignore; 23 | 24 | - (void)showGesture:(Gesture *)gesture; 25 | 26 | - (BOOL)resignFirstResponder; 27 | 28 | - (void)resetInputTimers; 29 | - (void)resetAll; 30 | - (BOOL)acceptsFirstResponder; 31 | - (BOOL)canBecomeKeyView; 32 | - (void)drawRect:(NSRect)dirtyRect; 33 | 34 | @end 35 | -------------------------------------------------------------------------------- /Gestr/GestureSetupView.m: -------------------------------------------------------------------------------- 1 | #import "GestureSetupView.h" 2 | 3 | @interface GestureSetupView () 4 | 5 | @property NSMutableDictionary *touchPaths; 6 | @property NSMutableDictionary *gestureStrokes; 7 | @property NSMutableArray *orderedStrokeIds; 8 | 9 | @property NSTimer *startInputTimer; 10 | @property NSTimer *noInputTimer; 11 | @property NSTimer *detectInputTimer; 12 | 13 | @property int mouseStrokeIndex; 14 | 15 | @property BOOL showingStoredGesture; 16 | 17 | @property NSDate *lastMultitouchRedraw; 18 | @property NSNumber *initialMultitouchDeviceId; 19 | 20 | @end 21 | 22 | @implementation GestureSetupView 23 | 24 | - (id)initWithFrame:(NSRect)frame { 25 | self = [super initWithFrame:frame]; 26 | 27 | _touchPaths = [NSMutableDictionary dictionary]; 28 | _gestureStrokes = [NSMutableDictionary dictionary]; 29 | _orderedStrokeIds = [NSMutableArray array]; 30 | 31 | _lastMultitouchRedraw = [NSDate date]; 32 | 33 | return self; 34 | } 35 | 36 | - (void)dealWithMouseEvent:(NSEvent *)event ofType:(NSString *)mouseType { 37 | if (!_setupController.setupModel.multitouchOption && _detectingInput) { 38 | [_setupController showDrawNotification:NO]; 39 | 40 | [self resetInputTimers]; 41 | 42 | NSPoint drawPoint = [self convertPoint:[event locationInWindow] fromView:nil]; 43 | 44 | if ([mouseType isEqualToString:@"down"]) { 45 | _mouseStrokeIndex++; 46 | } 47 | 48 | NSNumber *identity = @(_mouseStrokeIndex); 49 | 50 | if (!_gestureStrokes[identity]) { 51 | [_orderedStrokeIds addObject:identity]; 52 | _gestureStrokes[identity] = [[GestureStroke alloc] init]; 53 | } 54 | 55 | GesturePoint *detectorPoint = [[GesturePoint alloc] initWithX:(drawPoint.x / self.frame.size.width) * GUBoundingBoxSize andY:(drawPoint.y / self.frame.size.height) * GUBoundingBoxSize andStrokeId:[identity intValue]]; 56 | 57 | [_gestureStrokes[identity] addPoint:detectorPoint]; 58 | 59 | if ([mouseType isEqualToString:@"down"]) { 60 | NSBezierPath *tempPath = [NSBezierPath bezierPath]; 61 | [tempPath setLineWidth:6.0]; 62 | [tempPath setLineCapStyle:NSRoundLineCapStyle]; 63 | [tempPath setLineJoinStyle:NSRoundLineJoinStyle]; 64 | [tempPath moveToPoint:drawPoint]; 65 | 66 | _touchPaths[identity] = tempPath; 67 | } 68 | else if ([mouseType isEqualToString:@"drag"]) { 69 | NSBezierPath *tempPath = _touchPaths[identity]; 70 | [tempPath lineToPoint:drawPoint]; 71 | } 72 | else if ([mouseType isEqualToString:@"up"]) { 73 | if (_mouseStrokeIndex < 3) { 74 | if (!_detectInputTimer) { 75 | _detectInputTimer = [NSTimer scheduledTimerWithTimeInterval:((float)_setupController.setupModel.readingDelayTime) / 1000.0 target:self selector:@selector(finishDetectingGesture) userInfo:nil repeats:NO]; 76 | } 77 | } 78 | else { 79 | [self finishDetectingGesture]; 80 | return; 81 | } 82 | 83 | NSBezierPath *tempPath = _touchPaths[identity]; 84 | [tempPath lineToPoint:drawPoint]; 85 | } 86 | 87 | [self setNeedsDisplay:YES]; 88 | } 89 | } 90 | 91 | - (void)mouseDown:(NSEvent *)theEvent { 92 | [self dealWithMouseEvent:theEvent ofType:@"down"]; 93 | } 94 | 95 | - (void)mouseDragged:(NSEvent *)theEvent { 96 | [self dealWithMouseEvent:theEvent ofType:@"drag"]; 97 | } 98 | 99 | - (void)mouseUp:(NSEvent *)theEvent { 100 | [self dealWithMouseEvent:theEvent ofType:@"up"]; 101 | } 102 | 103 | - (void)dealWithMultitouchEvent:(MultitouchEvent *)event { 104 | if (_setupController.setupModel.multitouchOption && _detectingInput) { 105 | [_setupController showDrawNotification:NO]; 106 | 107 | if (!_initialMultitouchDeviceId) { 108 | _initialMultitouchDeviceId = event.deviceIdentifier; 109 | } 110 | 111 | if ([event.deviceIdentifier isEqualToNumber:_initialMultitouchDeviceId]) { 112 | [self resetInputTimers]; 113 | 114 | if (!_detectInputTimer && event.touches.count == 0) { 115 | _detectInputTimer = [NSTimer scheduledTimerWithTimeInterval:((float)_setupController.setupModel.readingDelayTime) / 1000.0 target:self selector:@selector(finishDetectingGesture) userInfo:nil repeats:NO]; 116 | } 117 | else { 118 | BOOL shouldDraw = ([_lastMultitouchRedraw timeIntervalSinceNow] * -1000.0 > 16); 119 | 120 | for (MultitouchTouch *touch in event.touches) { 121 | float combinedTouchVelocity = fabs(touch.velX) + fabs(touch.velY); 122 | if (touch.state == MTTouchStateTouching && combinedTouchVelocity > 0.06) { 123 | NSPoint drawPoint = NSMakePoint(touch.x, touch.y); 124 | 125 | NSNumber *identity = touch.identifier; 126 | 127 | if (!_gestureStrokes[identity]) { 128 | if (_orderedStrokeIds.count < 3) { 129 | [_orderedStrokeIds addObject:identity]; 130 | _gestureStrokes[identity] = [[GestureStroke alloc] init]; 131 | } 132 | else { 133 | continue; 134 | } 135 | } 136 | 137 | GesturePoint *detectorPoint = [[GesturePoint alloc] initWithX:drawPoint.x * GUBoundingBoxSize andY:drawPoint.y * GUBoundingBoxSize andStrokeId:[identity intValue]]; 138 | 139 | [_gestureStrokes[identity] addPoint:detectorPoint]; 140 | 141 | drawPoint.x *= self.frame.size.width; 142 | drawPoint.y *= self.frame.size.height; 143 | 144 | NSBezierPath *tempPath; 145 | if ((tempPath = _touchPaths[identity])) { 146 | [tempPath lineToPoint:drawPoint]; 147 | } 148 | else { 149 | tempPath = [NSBezierPath bezierPath]; 150 | [tempPath setLineWidth:6.0]; 151 | [tempPath setLineCapStyle:NSRoundLineCapStyle]; 152 | [tempPath setLineJoinStyle:NSRoundLineJoinStyle]; 153 | [tempPath moveToPoint:drawPoint]; 154 | 155 | _touchPaths[identity] = tempPath; 156 | } 157 | } 158 | } 159 | 160 | if (shouldDraw) { 161 | [self setNeedsDisplay:YES]; 162 | _lastMultitouchRedraw = [NSDate date]; 163 | } 164 | } 165 | } 166 | else if (!_detectInputTimer) { 167 | _detectInputTimer = [NSTimer scheduledTimerWithTimeInterval:((float)_setupController.setupModel.readingDelayTime) / 1000.0 target:self selector:@selector(finishDetectingGesture) userInfo:nil repeats:NO]; 168 | } 169 | } 170 | } 171 | 172 | - (void)startMultitouchInput { 173 | [[MultitouchManager sharedMultitouchManager] addMultitouchListenerWithTarget:self callback:@selector(dealWithMultitouchEvent:) andThread:nil]; 174 | } 175 | 176 | - (void)startDetectingGesture { 177 | [self resetAll]; 178 | 179 | _mouseStrokeIndex = 0; 180 | 181 | _initialMultitouchDeviceId = nil; 182 | 183 | [_setupController showDrawNotification:YES]; 184 | 185 | _noInputTimer = [NSTimer scheduledTimerWithTimeInterval:4.0 target:self selector:@selector(finishDetectingGestureIgnore) userInfo:nil repeats:NO]; 186 | 187 | [self becomeFirstResponder]; 188 | 189 | if (_setupController.setupModel.multitouchOption) { 190 | [NSApp activateIgnoringOtherApps:YES]; 191 | CGAssociateMouseAndMouseCursorPosition(NO); 192 | 193 | _startInputTimer = [NSTimer scheduledTimerWithTimeInterval:0.1 target:self selector:@selector(startMultitouchInput) userInfo:nil repeats:NO]; 194 | } 195 | 196 | _detectingInput = YES; 197 | } 198 | 199 | - (void)finishDetectingGesture { 200 | [self finishDetectingGesture:NO]; 201 | } 202 | 203 | - (void)finishDetectingGestureIgnore { 204 | [self finishDetectingGesture:YES]; 205 | } 206 | 207 | - (void)finishDetectingGesture:(BOOL)ignore { 208 | _detectingInput = NO; 209 | 210 | if (_setupController.setupModel.multitouchOption) { 211 | [[MultitouchManager sharedMultitouchManager] removeMultitouchListenersWithTarget:self andCallback:@selector(dealWithMultitouchEvent:)]; 212 | CGAssociateMouseAndMouseCursorPosition(YES); 213 | } 214 | 215 | if (!ignore) { 216 | NSMutableArray *orderedStrokes = [NSMutableArray array]; 217 | for (int i = 0; i < _orderedStrokeIds.count; i++) { 218 | [orderedStrokes addObject:_gestureStrokes[_orderedStrokeIds[i]]]; 219 | } 220 | 221 | [_setupController saveGestureWithStrokes:orderedStrokes]; 222 | } 223 | 224 | [self resetAll]; 225 | } 226 | 227 | - (void)showGesture:(Gesture *)gesture { 228 | __block CGFloat width; 229 | __block CGFloat height; 230 | 231 | dispatch_sync(dispatch_get_main_queue(), ^{ 232 | [self resetAll]; 233 | 234 | width = self.frame.size.width; 235 | height = self.frame.size.height; 236 | }); 237 | 238 | _showingStoredGesture = YES; 239 | 240 | if (gesture) { 241 | int pointIndex = 0; 242 | while (YES) { 243 | if ([[NSThread currentThread] isCancelled] || _detectingInput) { 244 | [NSThread exit]; 245 | break; 246 | } 247 | 248 | if (pointIndex % 2 == 0) { 249 | dispatch_async(dispatch_get_main_queue(), ^{ 250 | [self setNeedsDisplay:YES]; 251 | }); 252 | } 253 | 254 | pointIndex++; 255 | 256 | BOOL contin = NO; 257 | for (GestureStroke *stroke in gesture.strokes) { 258 | if (pointIndex < stroke.pointCount) { 259 | contin = YES; 260 | break; 261 | } 262 | } 263 | 264 | if (!contin) { 265 | [NSThread exit]; 266 | break; 267 | } 268 | 269 | for (int strokeIndex = 0; strokeIndex < gesture.strokes.count; strokeIndex++) { 270 | GestureStroke *cStroke = gesture.strokes[strokeIndex]; 271 | if (pointIndex < cStroke.pointCount) { 272 | GesturePoint *cPoint = cStroke.points[pointIndex]; 273 | 274 | NSPoint drawPoint = NSMakePoint(cPoint.x / GUBoundingBoxSize * width, cPoint.y / GUBoundingBoxSize * height); 275 | 276 | NSString *ident = [NSString stringWithFormat:@"%i", strokeIndex]; 277 | 278 | if (pointIndex == 1) { 279 | NSBezierPath *tempPath = [NSBezierPath bezierPath]; 280 | [tempPath setLineWidth:6.0]; 281 | [tempPath setLineCapStyle:NSRoundLineCapStyle]; 282 | [tempPath setLineJoinStyle:NSRoundLineJoinStyle]; 283 | [tempPath moveToPoint:drawPoint]; 284 | _touchPaths[ident] = tempPath; 285 | } 286 | else if (pointIndex > 1 && pointIndex < cStroke.pointCount) { 287 | NSBezierPath *tempPath = _touchPaths[ident]; 288 | [tempPath lineToPoint:drawPoint]; 289 | } 290 | else if (pointIndex == cStroke.pointCount) { 291 | NSBezierPath *tempPath = _touchPaths[ident]; 292 | [tempPath lineToPoint:drawPoint]; 293 | [_touchPaths removeObjectForKey:ident]; 294 | } 295 | } 296 | } 297 | 298 | [NSThread sleepForTimeInterval:0.006]; 299 | } 300 | } 301 | } 302 | 303 | - (BOOL)resignFirstResponder { 304 | [self finishDetectingGesture:YES]; 305 | 306 | return YES; 307 | } 308 | 309 | - (void)resetInputTimers { 310 | if (_startInputTimer) { 311 | [_startInputTimer invalidate]; 312 | _startInputTimer = nil; 313 | } 314 | 315 | if (_noInputTimer) { 316 | [_noInputTimer invalidate]; 317 | _noInputTimer = nil; 318 | } 319 | 320 | if (_detectInputTimer) { 321 | [_detectInputTimer invalidate]; 322 | _detectInputTimer = nil; 323 | } 324 | } 325 | 326 | - (void)resetAll { 327 | [_setupController showDrawNotification:NO]; 328 | 329 | [self resetInputTimers]; 330 | 331 | _gestureStrokes = [NSMutableDictionary dictionary]; 332 | _orderedStrokeIds = [NSMutableArray array]; 333 | _touchPaths = [NSMutableDictionary dictionary]; 334 | 335 | _lastMultitouchRedraw = [NSDate date]; 336 | 337 | _showingStoredGesture = NO; 338 | 339 | [self setNeedsDisplay:YES]; 340 | } 341 | 342 | - (BOOL)acceptsFirstResponder { 343 | return YES; 344 | } 345 | 346 | - (BOOL)canBecomeKeyView { 347 | return YES; 348 | } 349 | 350 | - (void)drawRect:(NSRect)dirtyRect { 351 | if (_detectingInput || _showingStoredGesture) { 352 | for (NSBezierPath *path in[_touchPaths allValues]) { 353 | [[NSColor colorWithCalibratedRed:0 green:0 blue:0 alpha:0.36] setStroke]; 354 | path.lineWidth *= 1.5; 355 | [path stroke]; 356 | 357 | [myGreenColor setStroke]; 358 | path.lineWidth /= 1.5; 359 | [path stroke]; 360 | } 361 | } 362 | } 363 | 364 | @end 365 | -------------------------------------------------------------------------------- /Gestr/GestureSetupWindow.h: -------------------------------------------------------------------------------- 1 | @interface GestureSetupWindow : NSPanel 2 | 3 | - (id)initWithContentRect:(NSRect)contentRect styleMask:(NSUInteger)aStyle backing:(NSBackingStoreType)bufferingType defer:(BOOL)flag; 4 | - (BOOL)canBecomeKeyWindow; 5 | 6 | @end 7 | -------------------------------------------------------------------------------- /Gestr/GestureSetupWindow.m: -------------------------------------------------------------------------------- 1 | #import "GestureSetupWindow.h" 2 | 3 | @implementation GestureSetupWindow 4 | 5 | - (id)initWithContentRect:(NSRect)contentRect styleMask:(NSUInteger)aStyle backing:(NSBackingStoreType)bufferingType defer:(BOOL)flag { 6 | self = [super initWithContentRect:contentRect styleMask:(NSBorderlessWindowMask | NSNonactivatingPanelMask) backing:NSBackingStoreBuffered defer:NO]; 7 | 8 | [self setLevel:NSPopUpMenuWindowLevel]; 9 | [self setCollectionBehavior:NSWindowCollectionBehaviorCanJoinAllSpaces]; 10 | [self setMovableByWindowBackground:NO]; 11 | [self setAlphaValue:0.0]; 12 | [self setOpaque:NO]; 13 | [self setHasShadow:YES]; 14 | [self setBackgroundColor:[NSColor clearColor]]; 15 | 16 | return self; 17 | } 18 | 19 | - (BOOL)canBecomeKeyWindow { 20 | return YES; 21 | } 22 | 23 | @end 24 | -------------------------------------------------------------------------------- /Gestr/GestureStroke.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import "GesturePoint.h" 3 | 4 | @interface GestureStroke : NSObject 5 | 6 | @property NSMutableArray *points; 7 | 8 | - (id)init; 9 | - (id)initWithPoints:(NSMutableArray *)points; 10 | - (void)addPoint:(GesturePoint *)point; 11 | - (int)pointCount; 12 | - (GesturePoint *)pointAtIndex:(int)i; 13 | - (void)insertPoint:(GesturePoint *)point atIndex:(int)i; 14 | - (void)encodeWithCoder:(NSCoder *)coder; 15 | - (id)initWithCoder:(NSCoder *)coder; 16 | - (id)copyWithZone:(NSZone *)zone; 17 | - (NSString *)description; 18 | 19 | @end 20 | -------------------------------------------------------------------------------- /Gestr/GestureStroke.m: -------------------------------------------------------------------------------- 1 | #import "GestureStroke.h" 2 | 3 | @implementation GestureStroke 4 | 5 | - (id)init { 6 | self = [super init]; 7 | 8 | _points = [NSMutableArray array]; 9 | 10 | return self; 11 | } 12 | 13 | - (id)initWithPoints:(NSMutableArray *)points { 14 | self = [super init]; 15 | 16 | _points = points; 17 | 18 | return self; 19 | } 20 | 21 | - (void)addPoint:(GesturePoint *)point { 22 | [_points addObject:point]; 23 | } 24 | 25 | - (int)pointCount { 26 | return (int)_points.count; 27 | } 28 | 29 | - (GesturePoint *)pointAtIndex:(int)i { 30 | return _points[i]; 31 | } 32 | 33 | - (void)insertPoint:(GesturePoint *)point atIndex:(int)i { 34 | [_points insertObject:point atIndex:i]; 35 | } 36 | 37 | - (void)encodeWithCoder:(NSCoder *)coder { 38 | [coder encodeObject:_points forKey:@"points"]; 39 | } 40 | 41 | - (id)initWithCoder:(NSCoder *)coder { 42 | self = [super init]; 43 | 44 | _points = [[coder decodeObjectForKey:@"points"] mutableCopy]; 45 | 46 | return self; 47 | } 48 | 49 | - (id)copyWithZone:(NSZone *)zone { 50 | GestureStroke *copy = [[GestureStroke allocWithZone:zone] initWithPoints:[_points mutableCopy]]; 51 | 52 | return copy; 53 | } 54 | 55 | - (NSString *)description { 56 | NSMutableString *desc = [[NSMutableString alloc] init]; 57 | for (GesturePoint *point in _points) { 58 | [desc appendFormat:@"%@ \r", [point description]]; 59 | } 60 | 61 | return desc; 62 | } 63 | 64 | @end 65 | -------------------------------------------------------------------------------- /Gestr/GestureTemplate.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import "GestureUtils.h" 3 | #import "GestureStroke.h" 4 | 5 | @interface GestureTemplate : NSObject 6 | 7 | @property GestureStroke *stroke; 8 | @property GestureStroke *originalStroke; 9 | @property GesturePoint *startUnitVector; 10 | 11 | - (id)initWithPoints:(GestureStroke *)points; 12 | - (void)encodeWithCoder:(NSCoder *)coder; 13 | - (id)initWithCoder:(NSCoder *)coder; 14 | - (id)copyWithZone:(NSZone *)zone; 15 | - (NSString *)description; 16 | 17 | @end 18 | -------------------------------------------------------------------------------- /Gestr/GestureTemplate.m: -------------------------------------------------------------------------------- 1 | #import "GestureTemplate.h" 2 | 3 | @implementation GestureTemplate 4 | 5 | - (id)initWithPoints:(GestureStroke *)points { 6 | self = [super init]; 7 | 8 | _originalStroke = points; 9 | 10 | _stroke = GUResample(_originalStroke); 11 | _stroke = GUScale(_stroke); 12 | _stroke = GUTranslateToOrigin(_stroke); 13 | 14 | _startUnitVector = GUCalcStartUnitVector(_stroke); 15 | 16 | return self; 17 | } 18 | 19 | - (void)encodeWithCoder:(NSCoder *)coder { 20 | [coder encodeObject:_originalStroke forKey:@"originalStroke"]; 21 | [coder encodeObject:_stroke forKey:@"stroke"]; 22 | [coder encodeObject:_startUnitVector forKey:@"startUnitVector"]; 23 | } 24 | 25 | - (id)initWithCoder:(NSCoder *)coder { 26 | self = [super init]; 27 | 28 | _originalStroke = [coder decodeObjectForKey:@"originalStroke"]; 29 | _stroke = [coder decodeObjectForKey:@"stroke"]; 30 | _startUnitVector = [coder decodeObjectForKey:@"startUnitVector"]; 31 | 32 | return self; 33 | } 34 | 35 | - (id)copyWithZone:(NSZone *)zone { 36 | GestureTemplate *copy = [[GestureTemplate allocWithZone:zone] initWithPoints:[_originalStroke copy]]; 37 | 38 | return copy; 39 | } 40 | 41 | - (NSString *)description { 42 | NSMutableString *desc = [[NSMutableString alloc] init]; 43 | for (GesturePoint *point in _stroke.points) { 44 | [desc appendFormat:@"%@ \r", [point description]]; 45 | } 46 | 47 | return desc; 48 | } 49 | 50 | @end 51 | -------------------------------------------------------------------------------- /Gestr/GestureUtils.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import "GestureStroke.h" 3 | #import "GesturePoint.h" 4 | 5 | #define GUBoundingBoxSize 1000.0f 6 | 7 | #define GUGoldenRatio (0.5 * (-1.0 + sqrt(5.0))) 8 | 9 | #define GUStartVectorDelay 2 10 | #define GUStartVectorLength 7 11 | 12 | #define GUMinimumPointCount 10 13 | 14 | #define GUScaleLeniency 0.25f 15 | 16 | #define GUResampledStrokePointCount 160 17 | 18 | #define GUGoldenRatioAngleLeniency 30.0f 19 | 20 | #define GUStartAngleLeniency 40.0f 21 | 22 | #define GUGoldenRatioDegreeConstant 2.0f 23 | 24 | float GUDistanceAtBestAngle(GestureStroke *inputPoints, GestureStroke *matchPoints); 25 | NSMutableArray *GUHeapPermute(int count, NSMutableArray *order, NSMutableArray *newOrders); 26 | NSMutableArray *GUMakeUnistrokes(NSMutableArray *strokes, NSMutableArray *orders); 27 | GestureStroke *GURotateBy(GestureStroke *points, float radians); 28 | GestureStroke *GUResample(GestureStroke *points); 29 | GestureStroke *GUScale(GestureStroke *points); 30 | GestureStroke *GUTranslateToOrigin(GestureStroke *points); 31 | float GUAngleBetweenUnitVectors(GesturePoint *unitVector1, GesturePoint *unitVector2); 32 | float GUPathDistance(GestureStroke *points1, GestureStroke *points2); 33 | GesturePoint *GUCalcStartUnitVector(GestureStroke *points); 34 | CGRect GUBoundingBox(GestureStroke *points); 35 | float GUDistanceAtAngle(GestureStroke *recognizingPoints, GestureStroke *matchPoints, float radians); 36 | float GURoundToDigits(float number, int decimals); 37 | float GUDegreesToRadians(float degrees); 38 | float GURadiansToDegrees(float radians); 39 | float GUPathLength(GestureStroke *points); 40 | float GUDistance(GesturePoint *point1, GesturePoint *point2); 41 | GesturePoint *GUCentroid(GestureStroke *points); 42 | -------------------------------------------------------------------------------- /Gestr/GestureUtils.m: -------------------------------------------------------------------------------- 1 | #import "GestureUtils.h" 2 | 3 | float GUDistanceAtBestAngle(GestureStroke *inputPoints, GestureStroke *matchPoints) { 4 | float minAngleRange = GUDegreesToRadians(-GUGoldenRatioAngleLeniency); 5 | float maxAngleRange = GUDegreesToRadians(GUGoldenRatioAngleLeniency); 6 | 7 | float x1 = GUGoldenRatio * minAngleRange + (1.0 - GUGoldenRatio) * maxAngleRange; 8 | float f1 = GUDistanceAtAngle(inputPoints, matchPoints, x1); 9 | float x2 = (1.0 - GUGoldenRatio) * minAngleRange + GUGoldenRatio * maxAngleRange; 10 | float f2 = GUDistanceAtAngle(inputPoints, matchPoints, x2); 11 | while (fabs(maxAngleRange - minAngleRange) > GUDegreesToRadians(GUGoldenRatioDegreeConstant)) { 12 | if (f1 < f2) { 13 | maxAngleRange = x2; 14 | x2 = x1; 15 | f2 = f1; 16 | x1 = GUGoldenRatio * minAngleRange + (1.0 - GUGoldenRatio) * maxAngleRange; 17 | f1 = GUDistanceAtAngle(inputPoints, matchPoints, x1); 18 | } 19 | else { 20 | minAngleRange = x1; 21 | x1 = x2; 22 | f1 = f2; 23 | x2 = (1.0 - GUGoldenRatio) * minAngleRange + GUGoldenRatio * maxAngleRange; 24 | f2 = GUDistanceAtAngle(inputPoints, matchPoints, x2); 25 | } 26 | } 27 | 28 | return MIN(f1, f2); 29 | } 30 | 31 | NSMutableArray *GUHeapPermute(int count, NSMutableArray *order, NSMutableArray *newOrders) { 32 | if (count == 1) { 33 | [newOrders addObject:[order copy]]; 34 | } 35 | else { 36 | for (int i = 0; i < count; i++) { 37 | GUHeapPermute(count - 1, order, newOrders); 38 | int last = [order[(count - 1)] intValue]; 39 | if (count % 2 == 1) { 40 | int first = [order[0] intValue]; 41 | order[0] = @(last); 42 | order[(count - 1)] = @(first); 43 | } 44 | else { 45 | int next = [order[i] intValue]; 46 | order[i] = @(last); 47 | order[(count - 1)] = @(next); 48 | } 49 | } 50 | } 51 | 52 | return newOrders; 53 | } 54 | 55 | NSMutableArray *GUMakeUnistrokes(NSMutableArray *strokes, NSMutableArray *orders) { 56 | NSMutableArray *unistrokes = [NSMutableArray array]; 57 | for (int r = 0; r < orders.count; r++) { 58 | NSMutableArray *strokeOrder = orders[r]; 59 | 60 | for (int b = 0; b < pow(2, strokeOrder.count); b++) { 61 | GestureStroke *unistroke = [[GestureStroke alloc] init]; 62 | 63 | for (int i = 0; i < strokeOrder.count; i++) { 64 | int strokeIndex = [strokeOrder[i] intValue]; 65 | GestureStroke *stroke = strokes[strokeIndex]; 66 | 67 | NSMutableArray *copyOfStrokePoints = [[stroke points] mutableCopy]; 68 | 69 | NSArray *points; 70 | if (((b >> i) & 1) == 1) { 71 | points = [[copyOfStrokePoints reverseObjectEnumerator] allObjects]; 72 | } 73 | else { 74 | points = copyOfStrokePoints; 75 | } 76 | 77 | for (int p = 0; p < points.count; p++) { 78 | [unistroke addPoint:points[p]]; 79 | } 80 | } 81 | 82 | [unistrokes addObject:unistroke]; 83 | } 84 | } 85 | 86 | return unistrokes; 87 | } 88 | 89 | GestureStroke *GURotateBy(GestureStroke *points, float radians) { 90 | GesturePoint *centroid = GUCentroid(points); 91 | float cosValue = cosf(radians); 92 | float sinValue = sinf(radians); 93 | 94 | GestureStroke *rotatedPoints = [[GestureStroke alloc] init]; 95 | for (int i = 0; i < points.pointCount; i++) { 96 | GesturePoint *point = [points pointAtIndex:i]; 97 | float rotatedX = (point.x - centroid.x) * cosValue - (point.y - centroid.y) * sinValue + centroid.x; 98 | float rotatedY = (point.x - centroid.x) * sinValue + (point.y - centroid.y) * cosValue + centroid.y; 99 | 100 | [rotatedPoints addPoint:[[GesturePoint alloc] initWithX:rotatedX andY:rotatedY andStrokeId:point.strokeId]]; 101 | } 102 | 103 | return rotatedPoints; 104 | } 105 | 106 | GestureStroke *GUResample(GestureStroke *points) { 107 | GestureStroke *currentPoints = [points copy]; 108 | GestureStroke *newPoints = [[GestureStroke alloc] init]; 109 | [newPoints addPoint:[points pointAtIndex:0]]; 110 | 111 | float newPointDistance = GUPathLength(points) / (GUResampledStrokePointCount - 1); 112 | float initialDistance = 0.0; 113 | 114 | for (int i = 1; i < currentPoints.pointCount; i++) { 115 | GesturePoint *point1 = [currentPoints pointAtIndex:(i - 1)]; 116 | GesturePoint *point2 = [currentPoints pointAtIndex:i]; 117 | float d = GUDistance(point1, point2); 118 | 119 | if ((initialDistance + d) > newPointDistance) { 120 | float x = point1.x + ((newPointDistance - initialDistance) / d) * (point2.x - point1.x); 121 | float y = point1.y + ((newPointDistance - initialDistance) / d) * (point2.y - point1.y); 122 | 123 | GesturePoint *newPoint = [[GesturePoint alloc] initWithX:x andY:y andStrokeId:point1.strokeId]; 124 | [newPoints addPoint:newPoint]; 125 | 126 | [currentPoints insertPoint:newPoint atIndex:i]; 127 | 128 | initialDistance = 0.0; 129 | } 130 | else { 131 | initialDistance += d; 132 | } 133 | } 134 | 135 | if (newPoints.pointCount < GUResampledStrokePointCount) { 136 | GesturePoint *lastPoint = [points pointAtIndex:points.pointCount - 1]; 137 | for (int j = 0; j < (GUResampledStrokePointCount - newPoints.pointCount); j++) { 138 | [newPoints addPoint:[lastPoint copy]]; 139 | } 140 | } 141 | 142 | return newPoints; 143 | } 144 | 145 | GestureStroke *GUScale(GestureStroke *points) { 146 | CGRect currentBox = GUBoundingBox(points); 147 | BOOL isLine = MIN(currentBox.size.width / currentBox.size.height, currentBox.size.height / currentBox.size.width) <= GUScaleLeniency; 148 | 149 | GestureStroke *scaled = [[GestureStroke alloc] init]; 150 | for (GesturePoint *point in points.points) { 151 | float scale; 152 | float scaledX; 153 | float scaledY; 154 | if (isLine) { 155 | scale = (GUBoundingBoxSize / MAX(currentBox.size.width, currentBox.size.height)); 156 | scaledX = point.x * scale; 157 | scaledY = point.y * scale; 158 | } 159 | else { 160 | scaledX = point.x * (GUBoundingBoxSize / currentBox.size.width); 161 | scaledY = point.y * (GUBoundingBoxSize / currentBox.size.height); 162 | } 163 | 164 | [scaled addPoint:[[GesturePoint alloc] initWithX:scaledX andY:scaledY andStrokeId:point.strokeId]]; 165 | } 166 | 167 | return scaled; 168 | } 169 | 170 | GestureStroke *GUTranslateToOrigin(GestureStroke *points) { 171 | GesturePoint *centroid = GUCentroid(points); 172 | GestureStroke *translated = [[GestureStroke alloc] init]; 173 | 174 | for (int i = 0; i < points.pointCount; i++) { 175 | GesturePoint *point = [points pointAtIndex:i]; 176 | float translatedX = point.x - centroid.x; 177 | float translatedY = point.y - centroid.y; 178 | [translated addPoint:[[GesturePoint alloc] initWithX:translatedX andY:translatedY andStrokeId:point.strokeId]]; 179 | } 180 | 181 | return translated; 182 | } 183 | 184 | float GUAngleBetweenUnitVectors(GesturePoint *unitVector1, GesturePoint *unitVector2) { 185 | float angle = (unitVector1.x * unitVector2.x + unitVector1.y * unitVector2.y); 186 | if (angle < -1.0 || angle > 1.0) { 187 | angle = GURoundToDigits(angle, 5); 188 | } 189 | 190 | return acos(angle); 191 | } 192 | 193 | float GUPathDistance(GestureStroke *points1, GestureStroke *points2) { 194 | float distance = 0.0; 195 | for (int i = 0; i < points1.pointCount && i < points2.pointCount; i++) { 196 | distance += GUDistance([points1 pointAtIndex:i], [points2 pointAtIndex:i]); 197 | } 198 | 199 | return distance / points1.pointCount; 200 | } 201 | 202 | GesturePoint *GUCalcStartUnitVector(GestureStroke *points) { 203 | int endPointIndex = GUStartVectorDelay + GUStartVectorLength; 204 | GesturePoint *pointAtIndex = [points pointAtIndex:endPointIndex]; 205 | GesturePoint *firstPoint = [points pointAtIndex:GUStartVectorDelay]; 206 | 207 | GesturePoint *unitVector = [[GesturePoint alloc] initWithX:pointAtIndex.x - firstPoint.x andY:pointAtIndex.y - firstPoint.y andStrokeId:0]; 208 | float magnitude = sqrtf(unitVector.x * unitVector.x + unitVector.y * unitVector.y); 209 | 210 | return [[GesturePoint alloc] initWithX:unitVector.x / magnitude andY:unitVector.y / magnitude andStrokeId:0]; 211 | } 212 | 213 | CGRect GUBoundingBox(GestureStroke *points) { 214 | float minX = FLT_MAX; 215 | float maxX = -FLT_MAX; 216 | float minY = FLT_MAX; 217 | float maxY = -FLT_MAX; 218 | 219 | for (GesturePoint *point in points.points) { 220 | if (point.x < minX) { 221 | minX = point.x; 222 | } 223 | 224 | if (point.y < minY) { 225 | minY = point.y; 226 | } 227 | 228 | if (point.x > maxX) { 229 | maxX = point.x; 230 | } 231 | 232 | if (point.y > maxY) { 233 | maxY = point.y; 234 | } 235 | } 236 | 237 | return CGRectMake(minX, minY, (maxX - minX), (maxY - minY)); 238 | } 239 | 240 | float GUDistanceAtAngle(GestureStroke *recognizingPoints, GestureStroke *matchPoints, float radians) { 241 | GestureStroke *newPoints = GURotateBy(recognizingPoints, radians); 242 | return GUPathDistance(newPoints, matchPoints); 243 | } 244 | 245 | float GURoundToDigits(float number, int decimals) { 246 | decimals = pow(10, decimals); 247 | return round(number * decimals) / decimals; 248 | } 249 | 250 | float GUDegreesToRadians(float degrees) { 251 | return degrees * M_PI / 180.0; 252 | } 253 | 254 | float GURadiansToDegrees(float radians) { 255 | return radians * 180.0 / M_PI; 256 | } 257 | 258 | float GUPathLength(GestureStroke *points) { 259 | float distance = 0.0; 260 | for (int i = 1; i < points.pointCount; i++) { 261 | GesturePoint *point1 = [points pointAtIndex:(i - 1)]; 262 | GesturePoint *point2 = [points pointAtIndex:i]; 263 | distance += GUDistance(point1, point2); 264 | } 265 | 266 | return distance; 267 | } 268 | 269 | float GUDistance(GesturePoint *point1, GesturePoint *point2) { 270 | int xDiff = point2.x - point1.x; 271 | int yDiff = point2.y - point1.y; 272 | float dist = sqrt(xDiff * xDiff + yDiff * yDiff); 273 | return dist; 274 | } 275 | 276 | GesturePoint *GUCentroid(GestureStroke *points) { 277 | float x = 0.0; 278 | float y = 0.0; 279 | for (GesturePoint *point in points.points) { 280 | x += point.x; 281 | y += point.y; 282 | } 283 | 284 | x /= points.pointCount; 285 | y /= points.pointCount; 286 | 287 | return [[GesturePoint alloc] initWithX:x andY:y andStrokeId:0]; 288 | } 289 | -------------------------------------------------------------------------------- /Gestr/Images.xcassets/AppIcon.appiconset/128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhuusko5/Gestr/91fd4e310b6b603757016bf14f578360797579fd/Gestr/Images.xcassets/AppIcon.appiconset/128.png -------------------------------------------------------------------------------- /Gestr/Images.xcassets/AppIcon.appiconset/16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhuusko5/Gestr/91fd4e310b6b603757016bf14f578360797579fd/Gestr/Images.xcassets/AppIcon.appiconset/16.png -------------------------------------------------------------------------------- /Gestr/Images.xcassets/AppIcon.appiconset/256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhuusko5/Gestr/91fd4e310b6b603757016bf14f578360797579fd/Gestr/Images.xcassets/AppIcon.appiconset/256.png -------------------------------------------------------------------------------- /Gestr/Images.xcassets/AppIcon.appiconset/32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhuusko5/Gestr/91fd4e310b6b603757016bf14f578360797579fd/Gestr/Images.xcassets/AppIcon.appiconset/32.png -------------------------------------------------------------------------------- /Gestr/Images.xcassets/AppIcon.appiconset/512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhuusko5/Gestr/91fd4e310b6b603757016bf14f578360797579fd/Gestr/Images.xcassets/AppIcon.appiconset/512.png -------------------------------------------------------------------------------- /Gestr/Images.xcassets/AppIcon.appiconset/64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhuusko5/Gestr/91fd4e310b6b603757016bf14f578360797579fd/Gestr/Images.xcassets/AppIcon.appiconset/64.png -------------------------------------------------------------------------------- /Gestr/Images.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "size" : "16x16", 5 | "idiom" : "mac", 6 | "filename" : "16.png", 7 | "scale" : "1x" 8 | }, 9 | { 10 | "size" : "16x16", 11 | "idiom" : "mac", 12 | "filename" : "32.png", 13 | "scale" : "2x" 14 | }, 15 | { 16 | "size" : "32x32", 17 | "idiom" : "mac", 18 | "filename" : "32.png", 19 | "scale" : "1x" 20 | }, 21 | { 22 | "size" : "32x32", 23 | "idiom" : "mac", 24 | "filename" : "64.png", 25 | "scale" : "2x" 26 | }, 27 | { 28 | "size" : "128x128", 29 | "idiom" : "mac", 30 | "filename" : "128.png", 31 | "scale" : "1x" 32 | }, 33 | { 34 | "size" : "128x128", 35 | "idiom" : "mac", 36 | "filename" : "256.png", 37 | "scale" : "2x" 38 | }, 39 | { 40 | "size" : "256x256", 41 | "idiom" : "mac", 42 | "filename" : "256.png", 43 | "scale" : "1x" 44 | }, 45 | { 46 | "size" : "256x256", 47 | "idiom" : "mac", 48 | "filename" : "512.png", 49 | "scale" : "2x" 50 | }, 51 | { 52 | "size" : "512x512", 53 | "idiom" : "mac", 54 | "filename" : "512.png", 55 | "scale" : "1x" 56 | }, 57 | { 58 | "idiom" : "mac", 59 | "size" : "512x512", 60 | "scale" : "2x" 61 | } 62 | ], 63 | "info" : { 64 | "version" : 1, 65 | "author" : "xcode" 66 | } 67 | } -------------------------------------------------------------------------------- /Gestr/Images.xcassets/MenuIcon.imageset/32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhuusko5/Gestr/91fd4e310b6b603757016bf14f578360797579fd/Gestr/Images.xcassets/MenuIcon.imageset/32.png -------------------------------------------------------------------------------- /Gestr/Images.xcassets/MenuIcon.imageset/64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhuusko5/Gestr/91fd4e310b6b603757016bf14f578360797579fd/Gestr/Images.xcassets/MenuIcon.imageset/64.png -------------------------------------------------------------------------------- /Gestr/Images.xcassets/MenuIcon.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "32.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "64.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "version" : 1, 20 | "author" : "xcode" 21 | } 22 | } -------------------------------------------------------------------------------- /Gestr/Launchable.h: -------------------------------------------------------------------------------- 1 | @interface Launchable : NSObject 2 | 3 | @property NSString *displayName; 4 | @property NSString *launchId; 5 | @property NSImage *icon; 6 | 7 | - (id)initWithDisplayName:(NSString *)displayName launchId:(NSString *)launchId icon:(NSImage *)icon; 8 | - (void)launchWithNewThread:(BOOL)newThread; 9 | 10 | @end 11 | -------------------------------------------------------------------------------- /Gestr/Launchable.m: -------------------------------------------------------------------------------- 1 | #import "Launchable.h" 2 | 3 | @implementation Launchable 4 | 5 | - (id)initWithDisplayName:(NSString *)displayName launchId:(NSString *)launchId icon:(NSImage *)icon { 6 | self = [super init]; 7 | 8 | _displayName = displayName; 9 | _launchId = launchId; 10 | _icon = icon; 11 | 12 | return self; 13 | } 14 | 15 | - (void)launchWithNewThread:(BOOL)newThread { 16 | if (newThread) { 17 | [NSThread detachNewThreadSelector:@selector(launchWithNewThread:) toTarget:self withObject:nil]; 18 | } 19 | else { 20 | @try { 21 | if ([self respondsToSelector:@selector(launch)]) { 22 | [self performSelector:@selector(launch)]; 23 | } 24 | } 25 | @catch (NSException *exception) 26 | { 27 | } 28 | } 29 | } 30 | 31 | @end 32 | -------------------------------------------------------------------------------- /Gestr/MultitouchEvent.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import "MultitouchTouch.h" 3 | 4 | @interface MultitouchEvent : NSObject 5 | 6 | @property NSNumber *deviceIdentifier; 7 | @property NSNumber *frameIdentifier; 8 | @property double timestamp; 9 | @property NSArray *touches; 10 | 11 | - (id)initWithDeviceIdentifier:(int)deviceId frameIdentifier:(int)frameId timestamp:(double)timestamp andTouches:(NSArray *)touches; 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /Gestr/MultitouchEvent.m: -------------------------------------------------------------------------------- 1 | #import "MultitouchEvent.h" 2 | 3 | @implementation MultitouchEvent 4 | 5 | - (id)initWithDeviceIdentifier:(int)deviceId frameIdentifier:(int)frameId timestamp:(double)timestamp andTouches:(NSArray *)touches { 6 | self = [super init]; 7 | 8 | _deviceIdentifier = @(deviceId); 9 | _frameIdentifier = @(frameId); 10 | _timestamp = timestamp; 11 | _touches = touches; 12 | 13 | return self; 14 | } 15 | 16 | - (NSString *)description { 17 | return [NSString stringWithFormat:@"Device: %i, Frame: %i, Time: %f, Touches: %@", [_deviceIdentifier intValue], [_frameIdentifier intValue], _timestamp, [_touches description]]; 18 | } 19 | 20 | @end 21 | -------------------------------------------------------------------------------- /Gestr/MultitouchListener.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import "MultitouchEvent.h" 3 | 4 | @interface MultitouchListener : NSObject 5 | 6 | @property id target; 7 | @property SEL callback; 8 | @property NSThread *thread; 9 | 10 | - (id)initWithTarget:(id)target callback:(SEL)callback andThread:(NSThread *)thread; 11 | - (void)sendMultitouchEvent:(MultitouchEvent *)event; 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /Gestr/MultitouchListener.m: -------------------------------------------------------------------------------- 1 | #import "MultitouchListener.h" 2 | 3 | @implementation MultitouchListener 4 | 5 | - (id)initWithTarget:(id)target callback:(SEL)callback andThread:(NSThread *)thread { 6 | self = [super init]; 7 | 8 | if (!thread) { 9 | thread = [NSThread currentThread]; 10 | } 11 | 12 | _target = target; 13 | _callback = callback; 14 | _thread = thread; 15 | 16 | return self; 17 | } 18 | 19 | - (void)sendMultitouchEvent:(MultitouchEvent *)event { 20 | [_target performSelector:_callback onThread:_thread withObject:event waitUntilDone:NO]; 21 | } 22 | 23 | @end 24 | -------------------------------------------------------------------------------- /Gestr/MultitouchManager.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import "MultitouchSupport.h" 3 | #import "MultitouchTouch.h" 4 | #import "MultitouchEvent.h" 5 | #import "MultitouchListener.h" 6 | 7 | @interface MultitouchManager : NSObject 8 | 9 | @property (readonly) BOOL forwardingMultitouchEventsToListeners; 10 | 11 | - (void)startForwardingMultitouchEventsToListeners; 12 | - (void)stopForwardingMultitouchEventsToListeners; 13 | - (void)removeMultitouchListenersWithTarget:(id)target andCallback:(SEL)callback; 14 | - (void)addMultitouchListenerWithTarget:(id)target callback:(SEL)callback andThread:(NSThread *)thread; 15 | + (BOOL)systemIsMultitouchCapable; 16 | + (MultitouchManager *)sharedMultitouchManager; 17 | 18 | @end 19 | -------------------------------------------------------------------------------- /Gestr/MultitouchManager.m: -------------------------------------------------------------------------------- 1 | #import "MultitouchManager.h" 2 | 3 | @interface MultitouchManager () 4 | 5 | @property NSMutableArray *multitouchListeners; 6 | @property NSMutableArray *multitouchDevices; 7 | @property BOOL forwardingMultitouchEventsToListeners; 8 | @property NSTimer *multitouchHardwareCheckTimer; 9 | 10 | @end 11 | 12 | @implementation MultitouchManager 13 | 14 | static BOOL laptopLidClosed = NO; 15 | - (void)checkMultitouchHardware { 16 | CGDirectDisplayID builtInDisplay = 0; 17 | CGDirectDisplayID activeDisplays[10]; 18 | uint32_t numActiveDisplays; 19 | CGGetActiveDisplayList(10, activeDisplays, &numActiveDisplays); 20 | 21 | while (numActiveDisplays-- > 0) { 22 | if (CGDisplayIsBuiltin(activeDisplays[numActiveDisplays])) { 23 | builtInDisplay = activeDisplays[numActiveDisplays]; 24 | break; 25 | } 26 | } 27 | 28 | laptopLidClosed = (builtInDisplay == 0); 29 | 30 | NSArray *mtDevices = (NSArray *)CFBridgingRelease(MTDeviceCreateList()); 31 | 32 | int mtDeviceCount = (int)mtDevices.count; 33 | if (mtDeviceCount != _multitouchDevices.count) { 34 | [_multitouchHardwareCheckTimer invalidate]; 35 | _multitouchHardwareCheckTimer = nil; 36 | 37 | [self restartMultitouchEventForwardingAfterWake:nil]; 38 | } 39 | } 40 | 41 | - (void)handleMultitouchEvent:(MultitouchEvent *)event { 42 | if (_forwardingMultitouchEventsToListeners) { 43 | int multitouchListenerCount = (int)_multitouchListeners.count; 44 | while (multitouchListenerCount-- > 0) { 45 | MultitouchListener *multitouchListenerToForwardEvent = _multitouchListeners[multitouchListenerCount]; 46 | [multitouchListenerToForwardEvent sendMultitouchEvent:event]; 47 | } 48 | } 49 | } 50 | 51 | - (void)startForwardingMultitouchEventsToListeners { 52 | if ([[NSThread currentThread] isMainThread]) { 53 | if (!_forwardingMultitouchEventsToListeners && [MultitouchManager systemIsMultitouchCapable]) { 54 | NSArray *mtDevices = (NSArray *)CFBridgingRelease(MTDeviceCreateList()); 55 | 56 | int mtDeviceCount = (int)mtDevices.count; 57 | while (mtDeviceCount-- > 0) { 58 | id device = mtDevices[mtDeviceCount]; 59 | 60 | @try { 61 | MTDeviceRef mtDevice = (__bridge MTDeviceRef)device; 62 | MTRegisterContactFrameCallback(mtDevice, mtEventHandler); 63 | MTDeviceStart(mtDevice, 0); 64 | } 65 | @catch (NSException *exception) 66 | { 67 | } 68 | 69 | [_multitouchDevices addObject:device]; 70 | } 71 | 72 | _multitouchHardwareCheckTimer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(checkMultitouchHardware) userInfo:nil repeats:YES]; 73 | 74 | _forwardingMultitouchEventsToListeners = YES; 75 | } 76 | } 77 | else { 78 | [self performSelectorOnMainThread:@selector(startForwardingMultitouchEventsToListeners) withObject:nil waitUntilDone:NO]; 79 | } 80 | } 81 | 82 | - (void)stopForwardingMultitouchEventsToListeners { 83 | if ([[NSThread currentThread] isMainThread]) { 84 | if (_forwardingMultitouchEventsToListeners) { 85 | [_multitouchHardwareCheckTimer invalidate]; 86 | _multitouchHardwareCheckTimer = nil; 87 | 88 | int multitouchDeviceCount = (int)_multitouchDevices.count; 89 | while (multitouchDeviceCount-- > 0) { 90 | id device = _multitouchDevices[multitouchDeviceCount]; 91 | 92 | [_multitouchDevices removeObject:device]; 93 | 94 | @try { 95 | MTDeviceRef mtDevice = (__bridge MTDeviceRef)device; 96 | MTUnregisterContactFrameCallback(mtDevice, mtEventHandler); 97 | MTDeviceStop(mtDevice); 98 | } 99 | @catch (NSException *exception) 100 | { 101 | } 102 | } 103 | 104 | _forwardingMultitouchEventsToListeners = NO; 105 | } 106 | } 107 | else { 108 | [self performSelectorOnMainThread:@selector(stopForwardingMultitouchEventsToListeners) withObject:nil waitUntilDone:NO]; 109 | } 110 | } 111 | 112 | - (void)restartMultitouchEventForwardingAfterWake:(NSNotification *)wakeNotification { 113 | if ([[NSThread currentThread] isMainThread]) { 114 | [self stopForwardingMultitouchEventsToListeners]; 115 | [self startForwardingMultitouchEventsToListeners]; 116 | } 117 | else { 118 | [self performSelectorOnMainThread:@selector(restartMultitouchEventForwardingAfterWake:) withObject:wakeNotification waitUntilDone:NO]; 119 | } 120 | } 121 | 122 | - (void)removeMultitouchListenersWithTarget:(id)target andCallback:(SEL)callback { 123 | int multitouchListenerCount = (int)_multitouchListeners.count; 124 | while (multitouchListenerCount-- > 0) { 125 | MultitouchListener *multitouchListenerToRemove = _multitouchListeners[multitouchListenerCount]; 126 | if ([multitouchListenerToRemove.target isEqual:target] && (!callback || multitouchListenerToRemove.callback == callback)) { 127 | [_multitouchListeners removeObject:multitouchListenerToRemove]; 128 | } 129 | } 130 | } 131 | 132 | - (void)addMultitouchListenerWithTarget:(id)target callback:(SEL)callback andThread:(NSThread *)thread { 133 | [self removeMultitouchListenersWithTarget:target andCallback:callback]; 134 | 135 | [_multitouchListeners addObject:[[MultitouchListener alloc] initWithTarget:target callback:callback andThread:thread]]; 136 | 137 | [self startForwardingMultitouchEventsToListeners]; 138 | } 139 | 140 | static void mtEventHandler(MTDeviceRef mtEventDevice, MTTouch mtEventTouches[], int mtEventTouchesNum, double mtEventTimestamp, int mtEventFrameId) { 141 | if (MTDeviceIsBuiltIn && MTDeviceIsBuiltIn(mtEventDevice) && laptopLidClosed) { 142 | /*When a Mac laptop lid is closed, it can cause the trackpad to send random 143 | multitouch input (insane, I know!). Obviously we want to ignore that input.*/ 144 | return; 145 | } 146 | 147 | NSMutableArray *multitouchTouches = [[NSMutableArray alloc] initWithCapacity:mtEventTouchesNum]; 148 | for (int i = 0; i < mtEventTouchesNum; i++) { 149 | MultitouchTouch *multitouchTouch = [[MultitouchTouch alloc] initWithMTTouch:&mtEventTouches[i]]; 150 | multitouchTouches[i] = multitouchTouch; 151 | } 152 | 153 | MultitouchEvent *multitouchEvent = [[MultitouchEvent alloc] initWithDeviceIdentifier:(int)mtEventDevice frameIdentifier:mtEventFrameId timestamp:mtEventTimestamp andTouches:multitouchTouches]; 154 | 155 | [[MultitouchManager sharedMultitouchManager] handleMultitouchEvent:multitouchEvent]; 156 | } 157 | 158 | - (id)init { 159 | self = [super init]; 160 | 161 | _multitouchListeners = [NSMutableArray array]; 162 | _multitouchDevices = [NSMutableArray array]; 163 | 164 | [[[NSWorkspace sharedWorkspace] notificationCenter] addObserver:self selector:@selector(restartMultitouchEventForwardingAfterWake:) name:NSWorkspaceDidWakeNotification object:nil]; 165 | 166 | return self; 167 | } 168 | 169 | + (BOOL)systemIsMultitouchCapable { 170 | return MTDeviceIsAvailable(); 171 | } 172 | 173 | static MultitouchManager *sharedMultitouchManager = nil; 174 | 175 | + (void)initialize { 176 | if (!sharedMultitouchManager && self == [MultitouchManager class]) { 177 | sharedMultitouchManager = [[self alloc] init]; 178 | } 179 | } 180 | 181 | + (MultitouchManager *)sharedMultitouchManager { 182 | return sharedMultitouchManager; 183 | } 184 | 185 | @end 186 | -------------------------------------------------------------------------------- /Gestr/MultitouchSupport.h: -------------------------------------------------------------------------------- 1 | #ifdef __cplusplus 2 | extern "C" { 3 | #endif 4 | 5 | typedef struct { 6 | float x; 7 | float y; 8 | } MTPoint; 9 | 10 | typedef struct { 11 | MTPoint position; 12 | MTPoint velocity; 13 | } MTVector; 14 | 15 | enum { 16 | MTTouchStateNotTracking = 0, 17 | MTTouchStateStartInRange = 1, 18 | MTTouchStateHoverInRange = 2, 19 | MTTouchStateMakeTouch = 3, 20 | MTTouchStateTouching = 4, 21 | MTTouchStateBreakTouch = 5, 22 | MTTouchStateLingerInRange = 6, 23 | MTTouchStateOutOfRange = 7 24 | }; 25 | typedef int MTTouchState; 26 | 27 | typedef struct { 28 | int frame; 29 | double timestamp; 30 | int identifier; 31 | MTTouchState state; 32 | int fingerId; 33 | int handId; 34 | MTVector normalizedPosition; 35 | float size; 36 | int field9; 37 | float angle; 38 | float majorAxis; 39 | float minorAxis; 40 | MTVector absolutePosition; 41 | int field14; 42 | int field15; 43 | float density; 44 | } MTTouch; 45 | 46 | typedef void *MTDeviceRef; 47 | 48 | typedef void (*MTFrameCallbackFunction)(MTDeviceRef device, MTTouch touches[], int numTouches, double timestamp, int frame); 49 | 50 | bool MTDeviceIsAvailable(); 51 | CFMutableArrayRef MTDeviceCreateList(); 52 | bool MTDeviceIsBuiltIn(MTDeviceRef) __attribute__((weak_import)); 53 | 54 | void MTRegisterContactFrameCallback(MTDeviceRef, MTFrameCallbackFunction); 55 | void MTUnregisterContactFrameCallback(MTDeviceRef, MTFrameCallbackFunction); 56 | 57 | void MTDeviceStart(MTDeviceRef, int); 58 | void MTDeviceStop(MTDeviceRef); 59 | void MTDeviceRelease(MTDeviceRef); 60 | 61 | #ifdef __cplusplus 62 | } 63 | #endif 64 | -------------------------------------------------------------------------------- /Gestr/MultitouchTouch.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import "MultitouchSupport.h" 3 | @class MultitouchEvent; 4 | 5 | @interface MultitouchTouch : NSObject 6 | 7 | @property NSNumber *identifier; 8 | @property int state; 9 | @property float x; 10 | @property float y; 11 | @property float minorAxis; 12 | @property float majorAxis; 13 | @property float angle; 14 | @property float size; 15 | @property float velX; 16 | @property float velY; 17 | 18 | - (id)initWithMTTouch:(MTTouch *)touch; 19 | 20 | @end 21 | -------------------------------------------------------------------------------- /Gestr/MultitouchTouch.m: -------------------------------------------------------------------------------- 1 | #import "MultitouchTouch.h" 2 | 3 | @implementation MultitouchTouch 4 | 5 | - (id)initWithMTTouch:(MTTouch *)touch { 6 | self = [super init]; 7 | 8 | _identifier = @(touch->identifier); 9 | _state = touch->state; 10 | _x = touch->normalizedPosition.position.x; 11 | _y = touch->normalizedPosition.position.y; 12 | _minorAxis = touch->minorAxis; 13 | _majorAxis = touch->majorAxis; 14 | _angle = touch->angle; 15 | _size = touch->size; 16 | _velX = touch->normalizedPosition.velocity.x; 17 | _velY = touch->normalizedPosition.velocity.y; 18 | 19 | return self; 20 | } 21 | 22 | - (NSString *)description { 23 | return [NSString stringWithFormat:@"Id: %i, State: %i, X: %f, Y: %f, MinorAxis: %f, MajorAxis: %f, Angle: %f, Size: %f, VelocityX: %f, VelocityY: %f", [_identifier intValue], _state, _x, _y, _minorAxis, _majorAxis, _angle, _size, _velX, _velY]; 24 | } 25 | 26 | @end 27 | -------------------------------------------------------------------------------- /Gestr/NSBezierPath+MCAdditions.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | @interface NSBezierPath (MCAdditions) 4 | 5 | - (void)fillWithInnerShadow:(NSShadow *)shadow; 6 | 7 | @end 8 | -------------------------------------------------------------------------------- /Gestr/NSBezierPath+MCAdditions.m: -------------------------------------------------------------------------------- 1 | #import "NSBezierPath+MCAdditions.h" 2 | 3 | @implementation NSBezierPath (MCAdditions) 4 | 5 | - (void)fillWithInnerShadow:(NSShadow *)shadow { 6 | [NSGraphicsContext saveGraphicsState]; 7 | 8 | NSSize offset = shadow.shadowOffset; 9 | NSSize originalOffset = offset; 10 | CGFloat radius = shadow.shadowBlurRadius; 11 | NSRect bounds = NSInsetRect(self.bounds, -(ABS(offset.width) + radius), -(ABS(offset.height) + radius)); 12 | offset.height += bounds.size.height; 13 | shadow.shadowOffset = offset; 14 | NSAffineTransform *transform = [NSAffineTransform transform]; 15 | if ([[NSGraphicsContext currentContext] isFlipped]) { 16 | [transform translateXBy:0 yBy:bounds.size.height]; 17 | } 18 | else { 19 | [transform translateXBy:0 yBy:-bounds.size.height]; 20 | } 21 | 22 | NSBezierPath *drawingPath = [NSBezierPath bezierPathWithRect:bounds]; 23 | [drawingPath setWindingRule:NSEvenOddWindingRule]; 24 | [drawingPath appendBezierPath:self]; 25 | [drawingPath transformUsingAffineTransform:transform]; 26 | 27 | [self addClip]; 28 | [shadow set]; 29 | [[NSColor blackColor] set]; 30 | [drawingPath fill]; 31 | 32 | shadow.shadowOffset = originalOffset; 33 | 34 | [NSGraphicsContext restoreGraphicsState]; 35 | } 36 | 37 | @end 38 | -------------------------------------------------------------------------------- /Gestr/NSColor+ColorExtensions.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | @interface NSColor (ColorExtensions) 4 | 5 | - (NSColor *)lightenColorByValue:(float)value; 6 | - (NSColor *)darkenColorByValue:(float)value; 7 | - (BOOL)isLightColor; 8 | 9 | @end 10 | -------------------------------------------------------------------------------- /Gestr/NSColor+ColorExtensions.m: -------------------------------------------------------------------------------- 1 | #import "NSColor+ColorExtensions.h" 2 | 3 | @implementation NSColor (ColorExtensions) 4 | 5 | - (NSColor *)lightenColorByValue:(float)value { 6 | float red = [self redComponent]; 7 | red += value; 8 | 9 | float green = [self greenComponent]; 10 | green += value; 11 | 12 | float blue = [self blueComponent]; 13 | blue += value; 14 | 15 | return [NSColor colorWithCalibratedRed:red green:green blue:blue alpha:1.0f]; 16 | } 17 | 18 | - (NSColor *)darkenColorByValue:(float)value { 19 | float red = [self redComponent]; 20 | red -= value; 21 | 22 | float green = [self greenComponent]; 23 | green -= value; 24 | 25 | float blue = [self blueComponent]; 26 | blue -= value; 27 | 28 | return [NSColor colorWithCalibratedRed:red green:green blue:blue alpha:1.0f]; 29 | } 30 | 31 | - (BOOL)isLightColor { 32 | NSInteger totalComponents = [self numberOfComponents]; 33 | bool isGreyscale = totalComponents == 2 ? YES : NO; 34 | 35 | CGFloat sum; 36 | 37 | if (isGreyscale) { 38 | sum = [self redComponent]; 39 | } 40 | else { 41 | sum = ([self redComponent] + [self greenComponent] + [self blueComponent]) / 3.0; 42 | } 43 | 44 | return (sum > 0.8); 45 | } 46 | 47 | @end 48 | -------------------------------------------------------------------------------- /Gestr/NSImage+M5Darkable.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSImage+M5Darkable.h 3 | // Mathew Huusko V 4 | // 5 | // Created by Mathew Huusko V on 12/6/14. 6 | // Copyright (c) 2014 Mathew Huusko V. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface NSImage (M5Darkable) 12 | 13 | @property (assign, nonatomic, readwrite) BOOL M5_darkable; 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /Gestr/NSImage+M5Darkable.m: -------------------------------------------------------------------------------- 1 | // 2 | // NSImage+M5Darkable.m 3 | // Mathew Huusko V 4 | // 5 | // Created by Mathew Huusko V on 12/6/14. 6 | // Copyright (c) 2014 Mathew Huusko V. All rights reserved. 7 | // 8 | 9 | #import "NSImage+M5Darkable.h" 10 | 11 | #import 12 | #import 13 | 14 | @implementation NSImage (M5Darkable) 15 | 16 | const void* M5_darkableKey = &M5_darkableKey; 17 | 18 | - (void)setM5_darkable:(BOOL)M5_darkable { 19 | objc_setAssociatedObject(self, M5_darkableKey, @(M5_darkable), OBJC_ASSOCIATION_RETAIN); 20 | } 21 | 22 | - (BOOL)M5_darkable { 23 | return [objc_getAssociatedObject(self, M5_darkableKey) boolValue]; 24 | } 25 | 26 | const void* InvertedSelfKey = &InvertedSelfKey; 27 | 28 | - (NSImage *)M5_invertedSelf { 29 | NSImage *invertedSelf = objc_getAssociatedObject(self, InvertedSelfKey); 30 | 31 | if (!invertedSelf) { 32 | CIImage *normalCiImage = [[CIImage alloc] initWithData:[self TIFFRepresentation]]; 33 | 34 | CIFilter *filter = [CIFilter filterWithName:@"CIColorInvert"]; 35 | [filter setDefaults]; 36 | [filter setValue:normalCiImage forKey:@"inputImage"]; 37 | 38 | CIImage *invertedCiImage = [filter valueForKey:@"outputImage"]; 39 | [invertedCiImage drawAtPoint:NSZeroPoint fromRect:NSRectFromCGRect([invertedCiImage extent]) operation:NSCompositeSourceOver fraction:1.0]; 40 | 41 | NSCIImageRep *rep = [NSCIImageRep imageRepWithCIImage:invertedCiImage]; 42 | 43 | invertedSelf = [[NSImage alloc] initWithSize:rep.size]; 44 | [invertedSelf addRepresentation:rep]; 45 | 46 | objc_setAssociatedObject(self, InvertedSelfKey, invertedSelf, OBJC_ASSOCIATION_RETAIN); 47 | } 48 | 49 | return invertedSelf; 50 | } 51 | 52 | static BOOL darkModeState = NO; 53 | 54 | + (void)RM_updateDarkModeState { 55 | NSDictionary *globalPersistentDomain = [[NSUserDefaults standardUserDefaults] persistentDomainForName:NSGlobalDomain]; 56 | @try { 57 | NSString *interfaceStyle = [globalPersistentDomain valueForKey:@"AppleInterfaceStyle"]; 58 | darkModeState = [interfaceStyle isEqualToString:@"Dark"]; 59 | } @catch (NSException *exception) { 60 | darkModeState = NO; 61 | } 62 | } 63 | 64 | + (void)M5_initialize { 65 | [self M5_initialize]; 66 | 67 | [[NSDistributedNotificationCenter defaultCenter] addObserverForName:@"AppleInterfaceThemeChangedNotification" object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *notification) { 68 | [self RM_updateDarkModeState]; 69 | }]; 70 | 71 | [self RM_updateDarkModeState]; 72 | } 73 | 74 | - (void)M5_drawInRect:(NSRect)dstSpacePortionRect fromRect:(NSRect)srcSpacePortionRect operation:(NSCompositingOperation)op fraction:(CGFloat)requestedAlpha respectFlipped:(BOOL)respectContextIsFlipped hints:(NSDictionary *)hints { 75 | if (!darkModeState || !self.M5_darkable) { 76 | return [self M5_drawInRect:dstSpacePortionRect fromRect:srcSpacePortionRect operation:op fraction:requestedAlpha respectFlipped:respectContextIsFlipped hints:hints]; 77 | } 78 | 79 | return [self.M5_invertedSelf M5_drawInRect:dstSpacePortionRect fromRect:srcSpacePortionRect operation:op fraction:requestedAlpha respectFlipped:respectContextIsFlipped hints:hints]; 80 | } 81 | 82 | + (void)load { 83 | method_exchangeImplementations(class_getClassMethod(self, @selector(initialize)), class_getClassMethod(self, @selector(M5_initialize))); 84 | 85 | method_exchangeImplementations(class_getInstanceMethod(self, @selector(drawInRect:fromRect:operation:fraction:respectFlipped:hints:)), class_getInstanceMethod(self, @selector(M5_drawInRect:fromRect:operation:fraction:respectFlipped:hints:))); 86 | } 87 | 88 | @end 89 | -------------------------------------------------------------------------------- /Gestr/NSStatusItemPrioritizer.h: -------------------------------------------------------------------------------- 1 | @interface NSStatusItemPrioritizer : NSObject 2 | 3 | + (NSStatusItem *)prioritizedStatusItem; 4 | 5 | @end 6 | -------------------------------------------------------------------------------- /Gestr/NSStatusItemPrioritizer.m: -------------------------------------------------------------------------------- 1 | #import "NSStatusItemPrioritizer.h" 2 | #import 3 | 4 | static const int NSStatusItemPriority = 8001; 5 | 6 | @interface NSStatusBar (_NSStatusBar) 7 | - (id)_statusItemWithLength:(float)l withPriority:(int)p; 8 | - (id)_insertStatusItem:(NSStatusItem *)i withPriority:(int)p; 9 | @end 10 | 11 | @implementation NSStatusItemPrioritizer 12 | 13 | + (void)restartSystemUIServer { 14 | NSTask *killSystemUITask = [[NSTask alloc] init]; 15 | NSMutableArray *args = [NSMutableArray array]; 16 | [args addObject:@"SystemUIServer"]; 17 | [args addObject:@"-HUP"]; 18 | [killSystemUITask setLaunchPath:@"/usr/bin/killall"]; 19 | [killSystemUITask setArguments:args]; 20 | [killSystemUITask launch]; 21 | } 22 | 23 | + (NSStatusItem *)prioritizedStatusItem { 24 | NSStatusItem *prioritizedStatusItem = nil; 25 | 26 | if ([[NSStatusBar systemStatusBar] respondsToSelector:@selector(_statusItemWithLength:withPriority:)]) { 27 | if (!prioritizedStatusItem) { 28 | prioritizedStatusItem = [[NSStatusBar systemStatusBar] _statusItemWithLength:0 withPriority:NSStatusItemPriority]; 29 | } 30 | [prioritizedStatusItem setLength:NSVariableStatusItemLength]; 31 | } 32 | 33 | if (!prioritizedStatusItem) { 34 | prioritizedStatusItem = [[NSStatusBar systemStatusBar] statusItemWithLength:NSVariableStatusItemLength]; 35 | } 36 | else { 37 | [[NSNotificationCenter defaultCenter] addObserver:[self class] selector:@selector(restartSystemUIServer) name:NSApplicationWillTerminateNotification object:nil]; 38 | } 39 | 40 | return prioritizedStatusItem; 41 | } 42 | 43 | @end 44 | -------------------------------------------------------------------------------- /Gestr/PFMoveApplication.h: -------------------------------------------------------------------------------- 1 | #ifdef __cplusplus 2 | extern "C" { 3 | #endif 4 | 5 | void PFMoveToApplicationsFolderIfNecessary(void); 6 | 7 | #ifdef __cplusplus 8 | } 9 | #endif 10 | -------------------------------------------------------------------------------- /Gestr/RepeatedImageView.h: -------------------------------------------------------------------------------- 1 | #import "AppController.h" 2 | #import "GestureSetupWindow.h" 3 | 4 | @interface RepeatedImageView : NSImageView 5 | 6 | @property float roundRadius; 7 | 8 | - (void)drawRect:(NSRect)dirtyRect; 9 | - (void)mouseDown:(NSEvent *)theEvent; 10 | 11 | @end 12 | -------------------------------------------------------------------------------- /Gestr/RepeatedImageView.m: -------------------------------------------------------------------------------- 1 | #import "RepeatedImageView.h" 2 | 3 | @interface RepeatedImageView () 4 | 5 | @property NSColor *backgroundColor; 6 | 7 | @end 8 | 9 | @implementation RepeatedImageView 10 | 11 | - (void)drawRect:(NSRect)dirtyRect { 12 | if (!_backgroundColor) { 13 | if (self.image) { 14 | _backgroundColor = [NSColor colorWithPatternImage:self.image]; 15 | } 16 | else { 17 | _backgroundColor = [NSColor blackColor]; 18 | } 19 | } 20 | 21 | if (_roundRadius > 0) { 22 | NSBezierPath *path = [NSBezierPath bezierPathWithRoundedRect:dirtyRect xRadius:_roundRadius yRadius:_roundRadius]; 23 | [path addClip]; 24 | } 25 | 26 | [_backgroundColor set]; 27 | NSRectFill(dirtyRect); 28 | } 29 | 30 | - (void)mouseDown:(NSEvent *)theEvent { 31 | if ([self.window isKindOfClass:[GestureSetupWindow class]]) { 32 | [((AppController *)[NSApp delegate]).gestureSetupController updateSetupControls]; 33 | } 34 | } 35 | 36 | @end 37 | -------------------------------------------------------------------------------- /Gestr/RoundedCornerView.h: -------------------------------------------------------------------------------- 1 | @interface RoundedCornerView : NSView 2 | 3 | @property float roundRadius; 4 | 5 | @end 6 | -------------------------------------------------------------------------------- /Gestr/RoundedCornerView.m: -------------------------------------------------------------------------------- 1 | #import "RoundedCornerView.h" 2 | 3 | @implementation RoundedCornerView 4 | 5 | - (void)drawRect:(NSRect)dirtyRect { 6 | [[NSColor colorWithCalibratedWhite:0.05 alpha:1] setFill]; 7 | 8 | if (_roundRadius > 0) { 9 | NSBezierPath *path = [NSBezierPath bezierPathWithRoundedRect:dirtyRect xRadius:_roundRadius yRadius:_roundRadius]; 10 | [path fill]; 11 | } 12 | else { 13 | NSRectFill(dirtyRect); 14 | } 15 | } 16 | 17 | @end 18 | -------------------------------------------------------------------------------- /Gestr/SafariPage.h: -------------------------------------------------------------------------------- 1 | #import "WebPage.h" 2 | 3 | @interface SafariPage : WebPage 4 | 5 | - (id)initWithDisplayName:(NSString *)displayName icon:(NSImage *)icon url:(NSString *)url; 6 | 7 | @end 8 | -------------------------------------------------------------------------------- /Gestr/SafariPage.m: -------------------------------------------------------------------------------- 1 | #import "SafariPage.h" 2 | 3 | @implementation SafariPage 4 | 5 | - (id)initWithDisplayName:(NSString *)displayName icon:(NSImage *)icon url:(NSString *)url { 6 | return (self = [super initWithDisplayName:displayName icon:icon url:url targetBrowserId:@"com.apple.Safari"]); 7 | } 8 | 9 | @end 10 | -------------------------------------------------------------------------------- /Gestr/Script.h: -------------------------------------------------------------------------------- 1 | #import "Launchable.h" 2 | 3 | @interface Script : Launchable 4 | 5 | @property NSAppleScript *script; 6 | 7 | - (id)initWithDisplayName:(NSString *)displayName icon:(NSImage *)icon fileURL:(NSURL *)fileURL; 8 | - (void)launch; 9 | 10 | @end 11 | -------------------------------------------------------------------------------- /Gestr/Script.m: -------------------------------------------------------------------------------- 1 | #import "Script.h" 2 | 3 | @implementation Script 4 | 5 | - (id)initWithDisplayName:(NSString *)displayName icon:(NSImage *)icon fileURL:(NSURL *)fileURL { 6 | NSString *launchId = [fileURL path]; 7 | 8 | self = [super initWithDisplayName:displayName launchId:launchId icon:icon]; 9 | 10 | _script = [[NSAppleScript alloc] initWithContentsOfURL:fileURL error:nil]; 11 | 12 | return self; 13 | } 14 | 15 | - (void)launch { 16 | @try { 17 | [_script executeAndReturnError:nil]; 18 | } 19 | @catch (NSException *exception) {} 20 | } 21 | 22 | @end 23 | -------------------------------------------------------------------------------- /Gestr/Scripts/Close Current Window or Tab.scpt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhuusko5/Gestr/91fd4e310b6b603757016bf14f578360797579fd/Gestr/Scripts/Close Current Window or Tab.scpt -------------------------------------------------------------------------------- /Gestr/Scripts/Current Application - Quit.scpt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhuusko5/Gestr/91fd4e310b6b603757016bf14f578360797579fd/Gestr/Scripts/Current Application - Quit.scpt -------------------------------------------------------------------------------- /Gestr/Scripts/Go To Last Active App.scpt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhuusko5/Gestr/91fd4e310b6b603757016bf14f578360797579fd/Gestr/Scripts/Go To Last Active App.scpt -------------------------------------------------------------------------------- /Gestr/Scripts/Screen Brightness - Decrease.scpt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhuusko5/Gestr/91fd4e310b6b603757016bf14f578360797579fd/Gestr/Scripts/Screen Brightness - Decrease.scpt -------------------------------------------------------------------------------- /Gestr/Scripts/Screen Brightness - Increase.scpt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhuusko5/Gestr/91fd4e310b6b603757016bf14f578360797579fd/Gestr/Scripts/Screen Brightness - Increase.scpt -------------------------------------------------------------------------------- /Gestr/Scripts/Spotify - Next Track.scpt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhuusko5/Gestr/91fd4e310b6b603757016bf14f578360797579fd/Gestr/Scripts/Spotify - Next Track.scpt -------------------------------------------------------------------------------- /Gestr/Scripts/Spotify - Play:Pause.scpt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhuusko5/Gestr/91fd4e310b6b603757016bf14f578360797579fd/Gestr/Scripts/Spotify - Play:Pause.scpt -------------------------------------------------------------------------------- /Gestr/Scripts/Spotify - Previous Track.scpt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhuusko5/Gestr/91fd4e310b6b603757016bf14f578360797579fd/Gestr/Scripts/Spotify - Previous Track.scpt -------------------------------------------------------------------------------- /Gestr/Scripts/iTunes - Next Track.scpt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhuusko5/Gestr/91fd4e310b6b603757016bf14f578360797579fd/Gestr/Scripts/iTunes - Next Track.scpt -------------------------------------------------------------------------------- /Gestr/Scripts/iTunes - Play:Pause.scpt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhuusko5/Gestr/91fd4e310b6b603757016bf14f578360797579fd/Gestr/Scripts/iTunes - Play:Pause.scpt -------------------------------------------------------------------------------- /Gestr/Scripts/iTunes - Previous Track.scpt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhuusko5/Gestr/91fd4e310b6b603757016bf14f578360797579fd/Gestr/Scripts/iTunes - Previous Track.scpt -------------------------------------------------------------------------------- /Gestr/ShadowTextFieldCell.h: -------------------------------------------------------------------------------- 1 | #import "AppButtonCell.h" 2 | 3 | @interface ShadowTextFieldCell : NSTextFieldCell 4 | 5 | - (void)drawWithFrame:(NSRect)cellFrame inView:(NSView *)controlView; 6 | 7 | @end 8 | -------------------------------------------------------------------------------- /Gestr/ShadowTextFieldCell.m: -------------------------------------------------------------------------------- 1 | #import "ShadowTextFieldCell.h" 2 | 3 | @implementation ShadowTextFieldCell 4 | 5 | - (void)drawWithFrame:(NSRect)cellFrame inView:(NSView *)controlView { 6 | NSMutableAttributedString *attrString = [[NSMutableAttributedString alloc] initWithAttributedString:[self attributedStringValue]]; 7 | 8 | NSShadow *textShadow = [NSShadow new]; 9 | [textShadow setShadowOffset:AppButtonBlackTextShadowOffset]; 10 | [textShadow setShadowColor:AppButtonBlackTextShadowColor]; 11 | [textShadow setShadowBlurRadius:AppButtonBlackTextShadowBlurRadius]; 12 | 13 | [attrString addAttribute:NSShadowAttributeName value:textShadow range:((NSRange) {0, [attrString length] })]; 14 | [attrString addAttribute:NSForegroundColorAttributeName value:[myWhiteColor darkenColorByValue:0.06] range:((NSRange) {0, [attrString length] })]; 15 | 16 | [attrString drawInRect:NSIntegralRect(cellFrame)]; 17 | } 18 | 19 | @end 20 | -------------------------------------------------------------------------------- /Gestr/Sparkle.framework/Headers: -------------------------------------------------------------------------------- 1 | Versions/Current/Headers -------------------------------------------------------------------------------- /Gestr/Sparkle.framework/Modules: -------------------------------------------------------------------------------- 1 | Versions/Current/Modules -------------------------------------------------------------------------------- /Gestr/Sparkle.framework/Resources: -------------------------------------------------------------------------------- 1 | Versions/Current/Resources -------------------------------------------------------------------------------- /Gestr/Sparkle.framework/Sparkle: -------------------------------------------------------------------------------- 1 | Versions/Current/Sparkle -------------------------------------------------------------------------------- /Gestr/Sparkle.framework/Versions/A/Headers/SUAppcast.h: -------------------------------------------------------------------------------- 1 | // 2 | // SUAppcast.h 3 | // Sparkle 4 | // 5 | // Created by Andy Matuschak on 3/12/06. 6 | // Copyright 2006 Andy Matuschak. All rights reserved. 7 | // 8 | 9 | #ifndef SUAPPCAST_H 10 | #define SUAPPCAST_H 11 | 12 | #import 13 | #import "SUExport.h" 14 | 15 | @protocol SUAppcastDelegate; 16 | 17 | @class SUAppcastItem; 18 | SU_EXPORT @interface SUAppcast : NSObject 19 | 20 | @property (weak) id delegate; 21 | @property (copy) NSString *userAgentString; 22 | 23 | - (void)fetchAppcastFromURL:(NSURL *)url; 24 | 25 | @property (readonly, copy) NSArray *items; 26 | @end 27 | 28 | @protocol SUAppcastDelegate 29 | - (void)appcastDidFinishLoading:(SUAppcast *)appcast; 30 | - (void)appcast:(SUAppcast *)appcast failedToLoadWithError:(NSError *)error; 31 | @end 32 | 33 | #endif 34 | -------------------------------------------------------------------------------- /Gestr/Sparkle.framework/Versions/A/Headers/SUAppcastItem.h: -------------------------------------------------------------------------------- 1 | // 2 | // SUAppcastItem.h 3 | // Sparkle 4 | // 5 | // Created by Andy Matuschak on 3/12/06. 6 | // Copyright 2006 Andy Matuschak. All rights reserved. 7 | // 8 | 9 | #ifndef SUAPPCASTITEM_H 10 | #define SUAPPCASTITEM_H 11 | 12 | #include "SUExport.h" 13 | 14 | SU_EXPORT @interface SUAppcastItem : NSObject 15 | @property (copy, readonly) NSString *title; 16 | @property (copy, readonly) NSDate *date; 17 | @property (copy, readonly) NSString *itemDescription; 18 | @property (strong, readonly) NSURL *releaseNotesURL; 19 | @property (copy, readonly) NSString *DSASignature; 20 | @property (copy, readonly) NSString *minimumSystemVersion; 21 | @property (copy, readonly) NSString *maximumSystemVersion; 22 | @property (strong, readonly) NSURL *fileURL; 23 | @property (copy, readonly) NSString *versionString; 24 | @property (copy, readonly) NSString *displayVersionString; 25 | @property (copy, readonly) NSDictionary *deltaUpdates; 26 | @property (strong, readonly) NSURL *infoURL; 27 | 28 | // Initializes with data from a dictionary provided by the RSS class. 29 | - (instancetype)initWithDictionary:(NSDictionary *)dict; 30 | - (instancetype)initWithDictionary:(NSDictionary *)dict failureReason:(NSString **)error; 31 | 32 | @property (getter=isDeltaUpdate, readonly) BOOL deltaUpdate; 33 | @property (getter=isCriticalUpdate, readonly) BOOL criticalUpdate; 34 | 35 | // Returns the dictionary provided in initWithDictionary; this might be useful later for extensions. 36 | @property (readonly, copy) NSDictionary *propertiesDictionary; 37 | 38 | - (NSURL *)infoURL; 39 | 40 | @end 41 | 42 | #endif 43 | -------------------------------------------------------------------------------- /Gestr/Sparkle.framework/Versions/A/Headers/SUErrors.h: -------------------------------------------------------------------------------- 1 | // 2 | // SUErrors.h 3 | // Sparkle 4 | // 5 | // Created by C.W. Betts on 10/13/14. 6 | // Copyright (c) 2014 Sparkle Project. All rights reserved. 7 | // 8 | 9 | #ifndef SUERRORS_H 10 | #define SUERRORS_H 11 | 12 | #import 13 | #import "SUExport.h" 14 | 15 | /** 16 | * Error domain used by Sparkle 17 | */ 18 | SU_EXPORT extern NSString *const SUSparkleErrorDomain; 19 | 20 | typedef NS_ENUM(OSStatus, SUError) { 21 | // Appcast phase errors. 22 | SUAppcastParseError = 1000, 23 | SUNoUpdateError = 1001, 24 | SUAppcastError = 1002, 25 | SURunningFromDiskImageError = 1003, 26 | 27 | // Downlaod phase errors. 28 | SUTemporaryDirectoryError = 2000, 29 | 30 | // Extraction phase errors. 31 | SUUnarchivingError = 3000, 32 | SUSignatureError = 3001, 33 | 34 | // Installation phase errors. 35 | SUFileCopyFailure = 4000, 36 | SUAuthenticationFailure = 4001, 37 | SUMissingUpdateError = 4002, 38 | SUMissingInstallerToolError = 4003, 39 | SURelaunchError = 4004, 40 | SUInstallationError = 4005, 41 | SUDowngradeError = 4006 42 | }; 43 | 44 | #endif 45 | -------------------------------------------------------------------------------- /Gestr/Sparkle.framework/Versions/A/Headers/SUExport.h: -------------------------------------------------------------------------------- 1 | // 2 | // SUExport.h 3 | // Sparkle 4 | // 5 | // Created by Jake Petroules on 2014-08-23. 6 | // Copyright (c) 2014 Sparkle Project. All rights reserved. 7 | // 8 | 9 | #ifndef SUEXPORT_H 10 | #define SUEXPORT_H 11 | 12 | #ifdef BUILDING_SPARKLE 13 | #define SU_EXPORT __attribute__((visibility("default"))) 14 | #else 15 | #define SU_EXPORT 16 | #endif 17 | 18 | #endif 19 | -------------------------------------------------------------------------------- /Gestr/Sparkle.framework/Versions/A/Headers/SUStandardVersionComparator.h: -------------------------------------------------------------------------------- 1 | // 2 | // SUStandardVersionComparator.h 3 | // Sparkle 4 | // 5 | // Created by Andy Matuschak on 12/21/07. 6 | // Copyright 2007 Andy Matuschak. All rights reserved. 7 | // 8 | 9 | #ifndef SUSTANDARDVERSIONCOMPARATOR_H 10 | #define SUSTANDARDVERSIONCOMPARATOR_H 11 | 12 | #import "SUExport.h" 13 | #import "SUVersionComparisonProtocol.h" 14 | 15 | /*! 16 | Sparkle's default version comparator. 17 | 18 | This comparator is adapted from MacPAD, by Kevin Ballard. 19 | It's "dumb" in that it does essentially string comparison, 20 | in components split by character type. 21 | */ 22 | SU_EXPORT @interface SUStandardVersionComparator : NSObject 23 | 24 | /*! 25 | Returns a singleton instance of the comparator. 26 | */ 27 | + (SUStandardVersionComparator *)defaultComparator; 28 | 29 | /*! 30 | Compares version strings through textual analysis. 31 | 32 | See the implementation for more details. 33 | */ 34 | - (NSComparisonResult)compareVersion:(NSString *)versionA toVersion:(NSString *)versionB; 35 | @end 36 | 37 | #endif 38 | -------------------------------------------------------------------------------- /Gestr/Sparkle.framework/Versions/A/Headers/SUVersionComparisonProtocol.h: -------------------------------------------------------------------------------- 1 | // 2 | // SUVersionComparisonProtocol.h 3 | // Sparkle 4 | // 5 | // Created by Andy Matuschak on 12/21/07. 6 | // Copyright 2007 Andy Matuschak. All rights reserved. 7 | // 8 | 9 | #ifndef SUVERSIONCOMPARISONPROTOCOL_H 10 | #define SUVERSIONCOMPARISONPROTOCOL_H 11 | 12 | #import 13 | #import "SUExport.h" 14 | 15 | /*! 16 | Provides version comparison facilities for Sparkle. 17 | */ 18 | @protocol SUVersionComparison 19 | 20 | /*! 21 | An abstract method to compare two version strings. 22 | 23 | Should return NSOrderedAscending if b > a, NSOrderedDescending if b < a, 24 | and NSOrderedSame if they are equivalent. 25 | */ 26 | - (NSComparisonResult)compareVersion:(NSString *)versionA toVersion:(NSString *)versionB; // *** MAY BE CALLED ON NON-MAIN THREAD! 27 | 28 | @end 29 | 30 | #endif 31 | -------------------------------------------------------------------------------- /Gestr/Sparkle.framework/Versions/A/Headers/SUVersionDisplayProtocol.h: -------------------------------------------------------------------------------- 1 | // 2 | // SUVersionDisplayProtocol.h 3 | // EyeTV 4 | // 5 | // Created by Uli Kusterer on 08.12.09. 6 | // Copyright 2009 Elgato Systems GmbH. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "SUExport.h" 11 | 12 | /*! 13 | Applies special display formatting to version numbers. 14 | */ 15 | @protocol SUVersionDisplay 16 | 17 | /*! 18 | Formats two version strings. 19 | 20 | Both versions are provided so that important distinguishing information 21 | can be displayed while also leaving out unnecessary/confusing parts. 22 | */ 23 | - (void)formatVersion:(NSString **)inOutVersionA andVersion:(NSString **)inOutVersionB; 24 | 25 | @end 26 | -------------------------------------------------------------------------------- /Gestr/Sparkle.framework/Versions/A/Headers/Sparkle.h: -------------------------------------------------------------------------------- 1 | // 2 | // Sparkle.h 3 | // Sparkle 4 | // 5 | // Created by Andy Matuschak on 3/16/06. (Modified by CDHW on 23/12/07) 6 | // Copyright 2006 Andy Matuschak. All rights reserved. 7 | // 8 | 9 | #ifndef SPARKLE_H 10 | #define SPARKLE_H 11 | 12 | // This list should include the shared headers. It doesn't matter if some of them aren't shared (unless 13 | // there are name-space collisions) so we can list all of them to start with: 14 | 15 | #import 16 | #import 17 | #import 18 | #import 19 | #import 20 | #import 21 | #import 22 | 23 | #endif 24 | -------------------------------------------------------------------------------- /Gestr/Sparkle.framework/Versions/A/Modules/module.modulemap: -------------------------------------------------------------------------------- 1 | framework module Sparkle { 2 | umbrella header "Sparkle.h" 3 | 4 | export * 5 | module * { export * } 6 | } 7 | -------------------------------------------------------------------------------- /Gestr/Sparkle.framework/Versions/A/Resources/Autoupdate.app/Contents/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | BuildMachineOSBuild 6 | 14C106a 7 | CFBundleDevelopmentRegion 8 | English 9 | CFBundleExecutable 10 | Autoupdate 11 | CFBundleIconFile 12 | AppIcon 13 | CFBundleIdentifier 14 | org.sparkle-project.Sparkle.Autoupdate 15 | CFBundleInfoDictionaryVersion 16 | 6.0 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | 1.9.0 git-ce22598 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | 1.9.0 25 | DTCompiler 26 | com.apple.compilers.llvm.clang.1_0 27 | DTPlatformBuild 28 | 6A2008a 29 | DTPlatformVersion 30 | GM 31 | DTSDKBuild 32 | 14A382 33 | DTSDKName 34 | macosx10.10 35 | DTXcode 36 | 0611 37 | DTXcodeBuild 38 | 6A2008a 39 | LSBackgroundOnly 40 | 1 41 | LSMinimumSystemVersion 42 | 10.7 43 | LSUIElement 44 | 1 45 | NSMainNibFile 46 | MainMenu 47 | NSPrincipalClass 48 | NSApplication 49 | 50 | 51 | -------------------------------------------------------------------------------- /Gestr/Sparkle.framework/Versions/A/Resources/Autoupdate.app/Contents/MacOS/Autoupdate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhuusko5/Gestr/91fd4e310b6b603757016bf14f578360797579fd/Gestr/Sparkle.framework/Versions/A/Resources/Autoupdate.app/Contents/MacOS/Autoupdate -------------------------------------------------------------------------------- /Gestr/Sparkle.framework/Versions/A/Resources/Autoupdate.app/Contents/PkgInfo: -------------------------------------------------------------------------------- 1 | APPL???? -------------------------------------------------------------------------------- /Gestr/Sparkle.framework/Versions/A/Resources/Autoupdate.app/Contents/Resources/AppIcon.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhuusko5/Gestr/91fd4e310b6b603757016bf14f578360797579fd/Gestr/Sparkle.framework/Versions/A/Resources/Autoupdate.app/Contents/Resources/AppIcon.icns -------------------------------------------------------------------------------- /Gestr/Sparkle.framework/Versions/A/Resources/Autoupdate.app/Contents/Resources/SUStatus.nib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhuusko5/Gestr/91fd4e310b6b603757016bf14f578360797579fd/Gestr/Sparkle.framework/Versions/A/Resources/Autoupdate.app/Contents/Resources/SUStatus.nib -------------------------------------------------------------------------------- /Gestr/Sparkle.framework/Versions/A/Resources/Autoupdate.app/Contents/Resources/ar.lproj/Sparkle.strings: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhuusko5/Gestr/91fd4e310b6b603757016bf14f578360797579fd/Gestr/Sparkle.framework/Versions/A/Resources/Autoupdate.app/Contents/Resources/ar.lproj/Sparkle.strings -------------------------------------------------------------------------------- /Gestr/Sparkle.framework/Versions/A/Resources/Autoupdate.app/Contents/Resources/cs.lproj/Sparkle.strings: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhuusko5/Gestr/91fd4e310b6b603757016bf14f578360797579fd/Gestr/Sparkle.framework/Versions/A/Resources/Autoupdate.app/Contents/Resources/cs.lproj/Sparkle.strings -------------------------------------------------------------------------------- /Gestr/Sparkle.framework/Versions/A/Resources/Autoupdate.app/Contents/Resources/da.lproj/Sparkle.strings: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhuusko5/Gestr/91fd4e310b6b603757016bf14f578360797579fd/Gestr/Sparkle.framework/Versions/A/Resources/Autoupdate.app/Contents/Resources/da.lproj/Sparkle.strings -------------------------------------------------------------------------------- /Gestr/Sparkle.framework/Versions/A/Resources/Autoupdate.app/Contents/Resources/de.lproj/Sparkle.strings: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhuusko5/Gestr/91fd4e310b6b603757016bf14f578360797579fd/Gestr/Sparkle.framework/Versions/A/Resources/Autoupdate.app/Contents/Resources/de.lproj/Sparkle.strings -------------------------------------------------------------------------------- /Gestr/Sparkle.framework/Versions/A/Resources/Autoupdate.app/Contents/Resources/el.lproj/Sparkle.strings: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhuusko5/Gestr/91fd4e310b6b603757016bf14f578360797579fd/Gestr/Sparkle.framework/Versions/A/Resources/Autoupdate.app/Contents/Resources/el.lproj/Sparkle.strings -------------------------------------------------------------------------------- /Gestr/Sparkle.framework/Versions/A/Resources/Autoupdate.app/Contents/Resources/en.lproj/Sparkle.strings: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhuusko5/Gestr/91fd4e310b6b603757016bf14f578360797579fd/Gestr/Sparkle.framework/Versions/A/Resources/Autoupdate.app/Contents/Resources/en.lproj/Sparkle.strings -------------------------------------------------------------------------------- /Gestr/Sparkle.framework/Versions/A/Resources/Autoupdate.app/Contents/Resources/es.lproj/Sparkle.strings: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhuusko5/Gestr/91fd4e310b6b603757016bf14f578360797579fd/Gestr/Sparkle.framework/Versions/A/Resources/Autoupdate.app/Contents/Resources/es.lproj/Sparkle.strings -------------------------------------------------------------------------------- /Gestr/Sparkle.framework/Versions/A/Resources/Autoupdate.app/Contents/Resources/fr.lproj/Sparkle.strings: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhuusko5/Gestr/91fd4e310b6b603757016bf14f578360797579fd/Gestr/Sparkle.framework/Versions/A/Resources/Autoupdate.app/Contents/Resources/fr.lproj/Sparkle.strings -------------------------------------------------------------------------------- /Gestr/Sparkle.framework/Versions/A/Resources/Autoupdate.app/Contents/Resources/is.lproj/Sparkle.strings: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhuusko5/Gestr/91fd4e310b6b603757016bf14f578360797579fd/Gestr/Sparkle.framework/Versions/A/Resources/Autoupdate.app/Contents/Resources/is.lproj/Sparkle.strings -------------------------------------------------------------------------------- /Gestr/Sparkle.framework/Versions/A/Resources/Autoupdate.app/Contents/Resources/it.lproj/Sparkle.strings: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhuusko5/Gestr/91fd4e310b6b603757016bf14f578360797579fd/Gestr/Sparkle.framework/Versions/A/Resources/Autoupdate.app/Contents/Resources/it.lproj/Sparkle.strings -------------------------------------------------------------------------------- /Gestr/Sparkle.framework/Versions/A/Resources/Autoupdate.app/Contents/Resources/ja.lproj/Sparkle.strings: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhuusko5/Gestr/91fd4e310b6b603757016bf14f578360797579fd/Gestr/Sparkle.framework/Versions/A/Resources/Autoupdate.app/Contents/Resources/ja.lproj/Sparkle.strings -------------------------------------------------------------------------------- /Gestr/Sparkle.framework/Versions/A/Resources/Autoupdate.app/Contents/Resources/ko.lproj/Sparkle.strings: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhuusko5/Gestr/91fd4e310b6b603757016bf14f578360797579fd/Gestr/Sparkle.framework/Versions/A/Resources/Autoupdate.app/Contents/Resources/ko.lproj/Sparkle.strings -------------------------------------------------------------------------------- /Gestr/Sparkle.framework/Versions/A/Resources/Autoupdate.app/Contents/Resources/nb.lproj/Sparkle.strings: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhuusko5/Gestr/91fd4e310b6b603757016bf14f578360797579fd/Gestr/Sparkle.framework/Versions/A/Resources/Autoupdate.app/Contents/Resources/nb.lproj/Sparkle.strings -------------------------------------------------------------------------------- /Gestr/Sparkle.framework/Versions/A/Resources/Autoupdate.app/Contents/Resources/nl.lproj/Sparkle.strings: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhuusko5/Gestr/91fd4e310b6b603757016bf14f578360797579fd/Gestr/Sparkle.framework/Versions/A/Resources/Autoupdate.app/Contents/Resources/nl.lproj/Sparkle.strings -------------------------------------------------------------------------------- /Gestr/Sparkle.framework/Versions/A/Resources/Autoupdate.app/Contents/Resources/pl.lproj/Sparkle.strings: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhuusko5/Gestr/91fd4e310b6b603757016bf14f578360797579fd/Gestr/Sparkle.framework/Versions/A/Resources/Autoupdate.app/Contents/Resources/pl.lproj/Sparkle.strings -------------------------------------------------------------------------------- /Gestr/Sparkle.framework/Versions/A/Resources/Autoupdate.app/Contents/Resources/pt_BR.lproj/Sparkle.strings: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhuusko5/Gestr/91fd4e310b6b603757016bf14f578360797579fd/Gestr/Sparkle.framework/Versions/A/Resources/Autoupdate.app/Contents/Resources/pt_BR.lproj/Sparkle.strings -------------------------------------------------------------------------------- /Gestr/Sparkle.framework/Versions/A/Resources/Autoupdate.app/Contents/Resources/pt_PT.lproj/Sparkle.strings: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhuusko5/Gestr/91fd4e310b6b603757016bf14f578360797579fd/Gestr/Sparkle.framework/Versions/A/Resources/Autoupdate.app/Contents/Resources/pt_PT.lproj/Sparkle.strings -------------------------------------------------------------------------------- /Gestr/Sparkle.framework/Versions/A/Resources/Autoupdate.app/Contents/Resources/ro.lproj/Sparkle.strings: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhuusko5/Gestr/91fd4e310b6b603757016bf14f578360797579fd/Gestr/Sparkle.framework/Versions/A/Resources/Autoupdate.app/Contents/Resources/ro.lproj/Sparkle.strings -------------------------------------------------------------------------------- /Gestr/Sparkle.framework/Versions/A/Resources/Autoupdate.app/Contents/Resources/ru.lproj/Sparkle.strings: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhuusko5/Gestr/91fd4e310b6b603757016bf14f578360797579fd/Gestr/Sparkle.framework/Versions/A/Resources/Autoupdate.app/Contents/Resources/ru.lproj/Sparkle.strings -------------------------------------------------------------------------------- /Gestr/Sparkle.framework/Versions/A/Resources/Autoupdate.app/Contents/Resources/sk.lproj/Sparkle.strings: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhuusko5/Gestr/91fd4e310b6b603757016bf14f578360797579fd/Gestr/Sparkle.framework/Versions/A/Resources/Autoupdate.app/Contents/Resources/sk.lproj/Sparkle.strings -------------------------------------------------------------------------------- /Gestr/Sparkle.framework/Versions/A/Resources/Autoupdate.app/Contents/Resources/sl.lproj/Sparkle.strings: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhuusko5/Gestr/91fd4e310b6b603757016bf14f578360797579fd/Gestr/Sparkle.framework/Versions/A/Resources/Autoupdate.app/Contents/Resources/sl.lproj/Sparkle.strings -------------------------------------------------------------------------------- /Gestr/Sparkle.framework/Versions/A/Resources/Autoupdate.app/Contents/Resources/sv.lproj/Sparkle.strings: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhuusko5/Gestr/91fd4e310b6b603757016bf14f578360797579fd/Gestr/Sparkle.framework/Versions/A/Resources/Autoupdate.app/Contents/Resources/sv.lproj/Sparkle.strings -------------------------------------------------------------------------------- /Gestr/Sparkle.framework/Versions/A/Resources/Autoupdate.app/Contents/Resources/th.lproj/Sparkle.strings: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhuusko5/Gestr/91fd4e310b6b603757016bf14f578360797579fd/Gestr/Sparkle.framework/Versions/A/Resources/Autoupdate.app/Contents/Resources/th.lproj/Sparkle.strings -------------------------------------------------------------------------------- /Gestr/Sparkle.framework/Versions/A/Resources/Autoupdate.app/Contents/Resources/tr.lproj/Sparkle.strings: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhuusko5/Gestr/91fd4e310b6b603757016bf14f578360797579fd/Gestr/Sparkle.framework/Versions/A/Resources/Autoupdate.app/Contents/Resources/tr.lproj/Sparkle.strings -------------------------------------------------------------------------------- /Gestr/Sparkle.framework/Versions/A/Resources/Autoupdate.app/Contents/Resources/uk.lproj/Sparkle.strings: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhuusko5/Gestr/91fd4e310b6b603757016bf14f578360797579fd/Gestr/Sparkle.framework/Versions/A/Resources/Autoupdate.app/Contents/Resources/uk.lproj/Sparkle.strings -------------------------------------------------------------------------------- /Gestr/Sparkle.framework/Versions/A/Resources/Autoupdate.app/Contents/Resources/zh_CN.lproj/Sparkle.strings: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhuusko5/Gestr/91fd4e310b6b603757016bf14f578360797579fd/Gestr/Sparkle.framework/Versions/A/Resources/Autoupdate.app/Contents/Resources/zh_CN.lproj/Sparkle.strings -------------------------------------------------------------------------------- /Gestr/Sparkle.framework/Versions/A/Resources/Autoupdate.app/Contents/Resources/zh_TW.lproj/Sparkle.strings: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhuusko5/Gestr/91fd4e310b6b603757016bf14f578360797579fd/Gestr/Sparkle.framework/Versions/A/Resources/Autoupdate.app/Contents/Resources/zh_TW.lproj/Sparkle.strings -------------------------------------------------------------------------------- /Gestr/Sparkle.framework/Versions/A/Resources/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | BuildMachineOSBuild 6 | 14C106a 7 | CFBundleDevelopmentRegion 8 | en 9 | CFBundleExecutable 10 | Sparkle 11 | CFBundleIdentifier 12 | org.andymatuschak.Sparkle 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | Sparkle 17 | CFBundlePackageType 18 | FMWK 19 | CFBundleShortVersionString 20 | 1.9.0 git-ce22598 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | 1.9.0 25 | DTCompiler 26 | com.apple.compilers.llvm.clang.1_0 27 | DTPlatformBuild 28 | 6A2008a 29 | DTPlatformVersion 30 | GM 31 | DTSDKBuild 32 | 14A382 33 | DTSDKName 34 | macosx10.10 35 | DTXcode 36 | 0611 37 | DTXcodeBuild 38 | 6A2008a 39 | SUAppendVersionNumber 40 | 1 41 | SUEnableAutomatedDowngrades 42 | 0 43 | SUNormalizeInstalledApplicationName 44 | 0 45 | SURelaunchToolName 46 | Autoupdate 47 | 48 | 49 | -------------------------------------------------------------------------------- /Gestr/Sparkle.framework/Versions/A/Resources/SUModelTranslation.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | ADP2,1 6 | Developer Transition Kit 7 | iMac1,1 8 | iMac G3 (Rev A-D) 9 | iMac4,1 10 | iMac (Core Duo) 11 | iMac4,2 12 | iMac for Education (17 inch, Core Duo) 13 | iMac5,1 14 | iMac (Core 2 Duo, 17 or 20 inch, SuperDrive) 15 | iMac5,2 16 | iMac (Core 2 Duo, 17 inch, Combo Drive) 17 | iMac6,1 18 | iMac (Core 2 Duo, 24 inch, SuperDrive) 19 | iMac8,1 20 | iMac (Core 2 Duo, 20 or 24 inch, Early 2008 ) 21 | iMac9,1 22 | iMac (Core 2 Duo, 20 or 24 inch, Early or Mid 2009 ) 23 | iMac10,1 24 | iMac (Core 2 Duo, 21.5 or 27 inch, Late 2009 ) 25 | iMac11,1 26 | iMac (Core i5 or i7, 27 inch Late 2009) 27 | iMac11,2 28 | iMac (Core i3 or i5, 27 inch Mid 2010) 29 | iMac11,3 30 | iMac (Core i5 or i7, 27 inch Mid 2010) 31 | iMac12,1 32 | iMac (Core i3 or i5 or i7, 21.5 inch Mid 2010 or Late 2011) 33 | iMac12,2 34 | iMac (Core i5 or i7, 27 inch Mid 2011) 35 | iMac13,1 36 | iMac (Core i3 or i5 or i7, 21.5 inch Late 2012 or Early 2013) 37 | iMac13,2 38 | iMac (Core i5 or i7, 27 inch Late 2012) 39 | iMac14,1 40 | iMac (Core i5, 21.5 inch Late 2013) 41 | iMac14,2 42 | iMac (Core i5 or i7, 27 inch Late 2013) 43 | iMac14,3 44 | iMac (Core i5 or i7, 21.5 inch Late 2013) 45 | MacBook1,1 46 | MacBook (Core Duo) 47 | MacBook2,1 48 | MacBook (Core 2 Duo) 49 | MacBook4,1 50 | MacBook (Core 2 Duo Feb 2008) 51 | MacBook5,1 52 | MacBook (Core 2 Duo, Late 2008, Unibody) 53 | MacBook5,2 54 | MacBook (Core 2 Duo, Early 2009, White) 55 | MacBook6,1 56 | MacBook (Core 2 Duo, Late 2009, Unibody) 57 | MacBook7,1 58 | MacBook (Core 2 Duo, Mid 2010, White) 59 | MacBookAir1,1 60 | MacBook Air (Core 2 Duo, 13 inch, Early 2008) 61 | MacBookAir2,1 62 | MacBook Air (Core 2 Duo, 13 inch, Mid 2009) 63 | MacBookAir3,1 64 | MacBook Air (Core 2 Duo, 11 inch, Late 2010) 65 | MacBookAir3,2 66 | MacBook Air (Core 2 Duo, 13 inch, Late 2010) 67 | MacBookAir4,1 68 | MacBook Air (Core i5 or i7, 11 inch, Mid 2011) 69 | MacBookAir4,2 70 | MacBook Air (Core i5 or i7, 13 inch, Mid 2011) 71 | MacBookAir5,1 72 | MacBook Air (Core i5 or i7, 11 inch, Mid 2012) 73 | MacBookAir5,2 74 | MacBook Air (Core i5 or i7, 13 inch, Mid 2012) 75 | MacBookAir6,1 76 | MacBook Air (Core i5 or i7, 11 inch, Mid 2013 or Early 2014) 77 | MacBookAir6,2 78 | MacBook Air (Core i5 or i7, 13 inch, Mid 2013 or Early 2014) 79 | MacBookPro1,1 80 | MacBook Pro Core Duo (15-inch) 81 | MacBookPro1,2 82 | MacBook Pro Core Duo (17-inch) 83 | MacBookPro2,1 84 | MacBook Pro Core 2 Duo (17-inch) 85 | MacBookPro2,2 86 | MacBook Pro Core 2 Duo (15-inch) 87 | MacBookPro3,1 88 | MacBook Pro Core 2 Duo (15-inch LED, Core 2 Duo) 89 | MacBookPro3,2 90 | MacBook Pro Core 2 Duo (17-inch HD, Core 2 Duo) 91 | MacBookPro4,1 92 | MacBook Pro (Core 2 Duo Feb 2008) 93 | Macmini1,1 94 | Mac Mini (Core Solo/Duo) 95 | MacPro1,1 96 | Mac Pro (four-core) 97 | MacPro2,1 98 | Mac Pro (eight-core) 99 | MacPro3,1 100 | Mac Pro (January 2008 4- or 8- core "Harpertown") 101 | MacPro4,1 102 | Mac Pro (March 2009) 103 | MacPro5,1 104 | Mac Pro (August 2010) 105 | PowerBook1,1 106 | PowerBook G3 107 | PowerBook2,1 108 | iBook G3 109 | PowerBook2,2 110 | iBook G3 (FireWire) 111 | PowerBook2,3 112 | iBook G3 113 | PowerBook2,4 114 | iBook G3 115 | PowerBook3,1 116 | PowerBook G3 (FireWire) 117 | PowerBook3,2 118 | PowerBook G4 119 | PowerBook3,3 120 | PowerBook G4 (Gigabit Ethernet) 121 | PowerBook3,4 122 | PowerBook G4 (DVI) 123 | PowerBook3,5 124 | PowerBook G4 (1GHz / 867MHz) 125 | PowerBook4,1 126 | iBook G3 (Dual USB, Late 2001) 127 | PowerBook4,2 128 | iBook G3 (16MB VRAM) 129 | PowerBook4,3 130 | iBook G3 Opaque 16MB VRAM, 32MB VRAM, Early 2003) 131 | PowerBook5,1 132 | PowerBook G4 (17 inch) 133 | PowerBook5,2 134 | PowerBook G4 (15 inch FW 800) 135 | PowerBook5,3 136 | PowerBook G4 (17-inch 1.33GHz) 137 | PowerBook5,4 138 | PowerBook G4 (15 inch 1.5/1.33GHz) 139 | PowerBook5,5 140 | PowerBook G4 (17-inch 1.5GHz) 141 | PowerBook5,6 142 | PowerBook G4 (15 inch 1.67GHz/1.5GHz) 143 | PowerBook5,7 144 | PowerBook G4 (17-inch 1.67GHz) 145 | PowerBook5,8 146 | PowerBook G4 (Double layer SD, 15 inch) 147 | PowerBook5,9 148 | PowerBook G4 (Double layer SD, 17 inch) 149 | PowerBook6,1 150 | PowerBook G4 (12 inch) 151 | PowerBook6,2 152 | PowerBook G4 (12 inch, DVI) 153 | PowerBook6,3 154 | iBook G4 155 | PowerBook6,4 156 | PowerBook G4 (12 inch 1.33GHz) 157 | PowerBook6,5 158 | iBook G4 (Early-Late 2004) 159 | PowerBook6,7 160 | iBook G4 (Mid 2005) 161 | PowerBook6,8 162 | PowerBook G4 (12 inch 1.5GHz) 163 | PowerMac1,1 164 | Power Macintosh G3 (Blue & White) 165 | PowerMac1,2 166 | Power Macintosh G4 (PCI Graphics) 167 | PowerMac10,1 168 | Mac Mini G4 169 | PowerMac10,2 170 | Mac Mini (Late 2005) 171 | PowerMac11,2 172 | Power Macintosh G5 (Late 2005) 173 | PowerMac12,1 174 | iMac G5 (iSight) 175 | PowerMac2,1 176 | iMac G3 (Slot-loading CD-ROM) 177 | PowerMac2,2 178 | iMac G3 (Summer 2000) 179 | PowerMac3,1 180 | Power Macintosh G4 (AGP Graphics) 181 | PowerMac3,2 182 | Power Macintosh G4 (AGP Graphics) 183 | PowerMac3,3 184 | Power Macintosh G4 (Gigabit Ethernet) 185 | PowerMac3,4 186 | Power Macintosh G4 (Digital Audio) 187 | PowerMac3,5 188 | Power Macintosh G4 (Quick Silver) 189 | PowerMac3,6 190 | Power Macintosh G4 (Mirrored Drive Door) 191 | PowerMac4,1 192 | iMac G3 (Early/Summer 2001) 193 | PowerMac4,2 194 | iMac G4 (Flat Panel) 195 | PowerMac4,4 196 | eMac 197 | PowerMac4,5 198 | iMac G4 (17-inch Flat Panel) 199 | PowerMac5,1 200 | Power Macintosh G4 Cube 201 | PowerMac6,1 202 | iMac G4 (USB 2.0) 203 | PowerMac6,3 204 | iMac G4 (20-inch Flat Panel) 205 | PowerMac6,4 206 | eMac (USB 2.0, 2005) 207 | PowerMac7,2 208 | Power Macintosh G5 209 | PowerMac7,3 210 | Power Macintosh G5 211 | PowerMac8,1 212 | iMac G5 213 | PowerMac8,2 214 | iMac G5 (Ambient Light Sensor) 215 | PowerMac9,1 216 | Power Macintosh G5 (Late 2005) 217 | RackMac1,1 218 | Xserve G4 219 | RackMac1,2 220 | Xserve G4 (slot-loading, cluster node) 221 | RackMac3,1 222 | Xserve G5 223 | Xserve1,1 224 | Xserve (Intel Xeon) 225 | Xserve2,1 226 | Xserve (January 2008 quad-core) 227 | 228 | 229 | -------------------------------------------------------------------------------- /Gestr/Sparkle.framework/Versions/A/Resources/SUStatus.nib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhuusko5/Gestr/91fd4e310b6b603757016bf14f578360797579fd/Gestr/Sparkle.framework/Versions/A/Resources/SUStatus.nib -------------------------------------------------------------------------------- /Gestr/Sparkle.framework/Versions/A/Resources/ar.lproj/SUAutomaticUpdateAlert.nib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhuusko5/Gestr/91fd4e310b6b603757016bf14f578360797579fd/Gestr/Sparkle.framework/Versions/A/Resources/ar.lproj/SUAutomaticUpdateAlert.nib -------------------------------------------------------------------------------- /Gestr/Sparkle.framework/Versions/A/Resources/ar.lproj/SUUpdateAlert.nib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhuusko5/Gestr/91fd4e310b6b603757016bf14f578360797579fd/Gestr/Sparkle.framework/Versions/A/Resources/ar.lproj/SUUpdateAlert.nib -------------------------------------------------------------------------------- /Gestr/Sparkle.framework/Versions/A/Resources/ar.lproj/SUUpdatePermissionPrompt.nib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhuusko5/Gestr/91fd4e310b6b603757016bf14f578360797579fd/Gestr/Sparkle.framework/Versions/A/Resources/ar.lproj/SUUpdatePermissionPrompt.nib -------------------------------------------------------------------------------- /Gestr/Sparkle.framework/Versions/A/Resources/ar.lproj/Sparkle.strings: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhuusko5/Gestr/91fd4e310b6b603757016bf14f578360797579fd/Gestr/Sparkle.framework/Versions/A/Resources/ar.lproj/Sparkle.strings -------------------------------------------------------------------------------- /Gestr/Sparkle.framework/Versions/A/Resources/cs.lproj/SUAutomaticUpdateAlert.nib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhuusko5/Gestr/91fd4e310b6b603757016bf14f578360797579fd/Gestr/Sparkle.framework/Versions/A/Resources/cs.lproj/SUAutomaticUpdateAlert.nib -------------------------------------------------------------------------------- /Gestr/Sparkle.framework/Versions/A/Resources/cs.lproj/SUUpdateAlert.nib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhuusko5/Gestr/91fd4e310b6b603757016bf14f578360797579fd/Gestr/Sparkle.framework/Versions/A/Resources/cs.lproj/SUUpdateAlert.nib -------------------------------------------------------------------------------- /Gestr/Sparkle.framework/Versions/A/Resources/cs.lproj/SUUpdatePermissionPrompt.nib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhuusko5/Gestr/91fd4e310b6b603757016bf14f578360797579fd/Gestr/Sparkle.framework/Versions/A/Resources/cs.lproj/SUUpdatePermissionPrompt.nib -------------------------------------------------------------------------------- /Gestr/Sparkle.framework/Versions/A/Resources/cs.lproj/Sparkle.strings: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhuusko5/Gestr/91fd4e310b6b603757016bf14f578360797579fd/Gestr/Sparkle.framework/Versions/A/Resources/cs.lproj/Sparkle.strings -------------------------------------------------------------------------------- /Gestr/Sparkle.framework/Versions/A/Resources/da.lproj/SUAutomaticUpdateAlert.nib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhuusko5/Gestr/91fd4e310b6b603757016bf14f578360797579fd/Gestr/Sparkle.framework/Versions/A/Resources/da.lproj/SUAutomaticUpdateAlert.nib -------------------------------------------------------------------------------- /Gestr/Sparkle.framework/Versions/A/Resources/da.lproj/SUUpdateAlert.nib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhuusko5/Gestr/91fd4e310b6b603757016bf14f578360797579fd/Gestr/Sparkle.framework/Versions/A/Resources/da.lproj/SUUpdateAlert.nib -------------------------------------------------------------------------------- /Gestr/Sparkle.framework/Versions/A/Resources/da.lproj/SUUpdatePermissionPrompt.nib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhuusko5/Gestr/91fd4e310b6b603757016bf14f578360797579fd/Gestr/Sparkle.framework/Versions/A/Resources/da.lproj/SUUpdatePermissionPrompt.nib -------------------------------------------------------------------------------- /Gestr/Sparkle.framework/Versions/A/Resources/da.lproj/Sparkle.strings: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhuusko5/Gestr/91fd4e310b6b603757016bf14f578360797579fd/Gestr/Sparkle.framework/Versions/A/Resources/da.lproj/Sparkle.strings -------------------------------------------------------------------------------- /Gestr/Sparkle.framework/Versions/A/Resources/de.lproj/SUAutomaticUpdateAlert.nib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhuusko5/Gestr/91fd4e310b6b603757016bf14f578360797579fd/Gestr/Sparkle.framework/Versions/A/Resources/de.lproj/SUAutomaticUpdateAlert.nib -------------------------------------------------------------------------------- /Gestr/Sparkle.framework/Versions/A/Resources/de.lproj/SUUpdateAlert.nib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhuusko5/Gestr/91fd4e310b6b603757016bf14f578360797579fd/Gestr/Sparkle.framework/Versions/A/Resources/de.lproj/SUUpdateAlert.nib -------------------------------------------------------------------------------- /Gestr/Sparkle.framework/Versions/A/Resources/de.lproj/SUUpdatePermissionPrompt.nib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhuusko5/Gestr/91fd4e310b6b603757016bf14f578360797579fd/Gestr/Sparkle.framework/Versions/A/Resources/de.lproj/SUUpdatePermissionPrompt.nib -------------------------------------------------------------------------------- /Gestr/Sparkle.framework/Versions/A/Resources/de.lproj/Sparkle.strings: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhuusko5/Gestr/91fd4e310b6b603757016bf14f578360797579fd/Gestr/Sparkle.framework/Versions/A/Resources/de.lproj/Sparkle.strings -------------------------------------------------------------------------------- /Gestr/Sparkle.framework/Versions/A/Resources/el.lproj/SUAutomaticUpdateAlert.nib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhuusko5/Gestr/91fd4e310b6b603757016bf14f578360797579fd/Gestr/Sparkle.framework/Versions/A/Resources/el.lproj/SUAutomaticUpdateAlert.nib -------------------------------------------------------------------------------- /Gestr/Sparkle.framework/Versions/A/Resources/el.lproj/SUUpdateAlert.nib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhuusko5/Gestr/91fd4e310b6b603757016bf14f578360797579fd/Gestr/Sparkle.framework/Versions/A/Resources/el.lproj/SUUpdateAlert.nib -------------------------------------------------------------------------------- /Gestr/Sparkle.framework/Versions/A/Resources/el.lproj/SUUpdatePermissionPrompt.nib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhuusko5/Gestr/91fd4e310b6b603757016bf14f578360797579fd/Gestr/Sparkle.framework/Versions/A/Resources/el.lproj/SUUpdatePermissionPrompt.nib -------------------------------------------------------------------------------- /Gestr/Sparkle.framework/Versions/A/Resources/el.lproj/Sparkle.strings: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhuusko5/Gestr/91fd4e310b6b603757016bf14f578360797579fd/Gestr/Sparkle.framework/Versions/A/Resources/el.lproj/Sparkle.strings -------------------------------------------------------------------------------- /Gestr/Sparkle.framework/Versions/A/Resources/en.lproj/SUAutomaticUpdateAlert.nib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhuusko5/Gestr/91fd4e310b6b603757016bf14f578360797579fd/Gestr/Sparkle.framework/Versions/A/Resources/en.lproj/SUAutomaticUpdateAlert.nib -------------------------------------------------------------------------------- /Gestr/Sparkle.framework/Versions/A/Resources/en.lproj/SUUpdateAlert.nib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhuusko5/Gestr/91fd4e310b6b603757016bf14f578360797579fd/Gestr/Sparkle.framework/Versions/A/Resources/en.lproj/SUUpdateAlert.nib -------------------------------------------------------------------------------- /Gestr/Sparkle.framework/Versions/A/Resources/en.lproj/SUUpdatePermissionPrompt.nib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhuusko5/Gestr/91fd4e310b6b603757016bf14f578360797579fd/Gestr/Sparkle.framework/Versions/A/Resources/en.lproj/SUUpdatePermissionPrompt.nib -------------------------------------------------------------------------------- /Gestr/Sparkle.framework/Versions/A/Resources/en.lproj/Sparkle.strings: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhuusko5/Gestr/91fd4e310b6b603757016bf14f578360797579fd/Gestr/Sparkle.framework/Versions/A/Resources/en.lproj/Sparkle.strings -------------------------------------------------------------------------------- /Gestr/Sparkle.framework/Versions/A/Resources/es.lproj/SUAutomaticUpdateAlert.nib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhuusko5/Gestr/91fd4e310b6b603757016bf14f578360797579fd/Gestr/Sparkle.framework/Versions/A/Resources/es.lproj/SUAutomaticUpdateAlert.nib -------------------------------------------------------------------------------- /Gestr/Sparkle.framework/Versions/A/Resources/es.lproj/SUUpdateAlert.nib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhuusko5/Gestr/91fd4e310b6b603757016bf14f578360797579fd/Gestr/Sparkle.framework/Versions/A/Resources/es.lproj/SUUpdateAlert.nib -------------------------------------------------------------------------------- /Gestr/Sparkle.framework/Versions/A/Resources/es.lproj/SUUpdatePermissionPrompt.nib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhuusko5/Gestr/91fd4e310b6b603757016bf14f578360797579fd/Gestr/Sparkle.framework/Versions/A/Resources/es.lproj/SUUpdatePermissionPrompt.nib -------------------------------------------------------------------------------- /Gestr/Sparkle.framework/Versions/A/Resources/es.lproj/Sparkle.strings: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhuusko5/Gestr/91fd4e310b6b603757016bf14f578360797579fd/Gestr/Sparkle.framework/Versions/A/Resources/es.lproj/Sparkle.strings -------------------------------------------------------------------------------- /Gestr/Sparkle.framework/Versions/A/Resources/fr.lproj/SUAutomaticUpdateAlert.nib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhuusko5/Gestr/91fd4e310b6b603757016bf14f578360797579fd/Gestr/Sparkle.framework/Versions/A/Resources/fr.lproj/SUAutomaticUpdateAlert.nib -------------------------------------------------------------------------------- /Gestr/Sparkle.framework/Versions/A/Resources/fr.lproj/SUUpdateAlert.nib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhuusko5/Gestr/91fd4e310b6b603757016bf14f578360797579fd/Gestr/Sparkle.framework/Versions/A/Resources/fr.lproj/SUUpdateAlert.nib -------------------------------------------------------------------------------- /Gestr/Sparkle.framework/Versions/A/Resources/fr.lproj/SUUpdatePermissionPrompt.nib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhuusko5/Gestr/91fd4e310b6b603757016bf14f578360797579fd/Gestr/Sparkle.framework/Versions/A/Resources/fr.lproj/SUUpdatePermissionPrompt.nib -------------------------------------------------------------------------------- /Gestr/Sparkle.framework/Versions/A/Resources/fr.lproj/Sparkle.strings: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhuusko5/Gestr/91fd4e310b6b603757016bf14f578360797579fd/Gestr/Sparkle.framework/Versions/A/Resources/fr.lproj/Sparkle.strings -------------------------------------------------------------------------------- /Gestr/Sparkle.framework/Versions/A/Resources/fr_CA.lproj: -------------------------------------------------------------------------------- 1 | fr.lproj -------------------------------------------------------------------------------- /Gestr/Sparkle.framework/Versions/A/Resources/is.lproj/SUAutomaticUpdateAlert.nib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhuusko5/Gestr/91fd4e310b6b603757016bf14f578360797579fd/Gestr/Sparkle.framework/Versions/A/Resources/is.lproj/SUAutomaticUpdateAlert.nib -------------------------------------------------------------------------------- /Gestr/Sparkle.framework/Versions/A/Resources/is.lproj/SUUpdateAlert.nib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhuusko5/Gestr/91fd4e310b6b603757016bf14f578360797579fd/Gestr/Sparkle.framework/Versions/A/Resources/is.lproj/SUUpdateAlert.nib -------------------------------------------------------------------------------- /Gestr/Sparkle.framework/Versions/A/Resources/is.lproj/SUUpdatePermissionPrompt.nib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhuusko5/Gestr/91fd4e310b6b603757016bf14f578360797579fd/Gestr/Sparkle.framework/Versions/A/Resources/is.lproj/SUUpdatePermissionPrompt.nib -------------------------------------------------------------------------------- /Gestr/Sparkle.framework/Versions/A/Resources/is.lproj/Sparkle.strings: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhuusko5/Gestr/91fd4e310b6b603757016bf14f578360797579fd/Gestr/Sparkle.framework/Versions/A/Resources/is.lproj/Sparkle.strings -------------------------------------------------------------------------------- /Gestr/Sparkle.framework/Versions/A/Resources/it.lproj/SUAutomaticUpdateAlert.nib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhuusko5/Gestr/91fd4e310b6b603757016bf14f578360797579fd/Gestr/Sparkle.framework/Versions/A/Resources/it.lproj/SUAutomaticUpdateAlert.nib -------------------------------------------------------------------------------- /Gestr/Sparkle.framework/Versions/A/Resources/it.lproj/SUUpdateAlert.nib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhuusko5/Gestr/91fd4e310b6b603757016bf14f578360797579fd/Gestr/Sparkle.framework/Versions/A/Resources/it.lproj/SUUpdateAlert.nib -------------------------------------------------------------------------------- /Gestr/Sparkle.framework/Versions/A/Resources/it.lproj/SUUpdatePermissionPrompt.nib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhuusko5/Gestr/91fd4e310b6b603757016bf14f578360797579fd/Gestr/Sparkle.framework/Versions/A/Resources/it.lproj/SUUpdatePermissionPrompt.nib -------------------------------------------------------------------------------- /Gestr/Sparkle.framework/Versions/A/Resources/it.lproj/Sparkle.strings: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhuusko5/Gestr/91fd4e310b6b603757016bf14f578360797579fd/Gestr/Sparkle.framework/Versions/A/Resources/it.lproj/Sparkle.strings -------------------------------------------------------------------------------- /Gestr/Sparkle.framework/Versions/A/Resources/ja.lproj/SUAutomaticUpdateAlert.nib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhuusko5/Gestr/91fd4e310b6b603757016bf14f578360797579fd/Gestr/Sparkle.framework/Versions/A/Resources/ja.lproj/SUAutomaticUpdateAlert.nib -------------------------------------------------------------------------------- /Gestr/Sparkle.framework/Versions/A/Resources/ja.lproj/SUUpdateAlert.nib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhuusko5/Gestr/91fd4e310b6b603757016bf14f578360797579fd/Gestr/Sparkle.framework/Versions/A/Resources/ja.lproj/SUUpdateAlert.nib -------------------------------------------------------------------------------- /Gestr/Sparkle.framework/Versions/A/Resources/ja.lproj/SUUpdatePermissionPrompt.nib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhuusko5/Gestr/91fd4e310b6b603757016bf14f578360797579fd/Gestr/Sparkle.framework/Versions/A/Resources/ja.lproj/SUUpdatePermissionPrompt.nib -------------------------------------------------------------------------------- /Gestr/Sparkle.framework/Versions/A/Resources/ja.lproj/Sparkle.strings: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhuusko5/Gestr/91fd4e310b6b603757016bf14f578360797579fd/Gestr/Sparkle.framework/Versions/A/Resources/ja.lproj/Sparkle.strings -------------------------------------------------------------------------------- /Gestr/Sparkle.framework/Versions/A/Resources/ko.lproj/SUAutomaticUpdateAlert.nib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhuusko5/Gestr/91fd4e310b6b603757016bf14f578360797579fd/Gestr/Sparkle.framework/Versions/A/Resources/ko.lproj/SUAutomaticUpdateAlert.nib -------------------------------------------------------------------------------- /Gestr/Sparkle.framework/Versions/A/Resources/ko.lproj/SUUpdateAlert.nib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhuusko5/Gestr/91fd4e310b6b603757016bf14f578360797579fd/Gestr/Sparkle.framework/Versions/A/Resources/ko.lproj/SUUpdateAlert.nib -------------------------------------------------------------------------------- /Gestr/Sparkle.framework/Versions/A/Resources/ko.lproj/SUUpdatePermissionPrompt.nib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhuusko5/Gestr/91fd4e310b6b603757016bf14f578360797579fd/Gestr/Sparkle.framework/Versions/A/Resources/ko.lproj/SUUpdatePermissionPrompt.nib -------------------------------------------------------------------------------- /Gestr/Sparkle.framework/Versions/A/Resources/ko.lproj/Sparkle.strings: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhuusko5/Gestr/91fd4e310b6b603757016bf14f578360797579fd/Gestr/Sparkle.framework/Versions/A/Resources/ko.lproj/Sparkle.strings -------------------------------------------------------------------------------- /Gestr/Sparkle.framework/Versions/A/Resources/nb.lproj/SUAutomaticUpdateAlert.nib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhuusko5/Gestr/91fd4e310b6b603757016bf14f578360797579fd/Gestr/Sparkle.framework/Versions/A/Resources/nb.lproj/SUAutomaticUpdateAlert.nib -------------------------------------------------------------------------------- /Gestr/Sparkle.framework/Versions/A/Resources/nb.lproj/SUUpdateAlert.nib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhuusko5/Gestr/91fd4e310b6b603757016bf14f578360797579fd/Gestr/Sparkle.framework/Versions/A/Resources/nb.lproj/SUUpdateAlert.nib -------------------------------------------------------------------------------- /Gestr/Sparkle.framework/Versions/A/Resources/nb.lproj/SUUpdatePermissionPrompt.nib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhuusko5/Gestr/91fd4e310b6b603757016bf14f578360797579fd/Gestr/Sparkle.framework/Versions/A/Resources/nb.lproj/SUUpdatePermissionPrompt.nib -------------------------------------------------------------------------------- /Gestr/Sparkle.framework/Versions/A/Resources/nb.lproj/Sparkle.strings: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhuusko5/Gestr/91fd4e310b6b603757016bf14f578360797579fd/Gestr/Sparkle.framework/Versions/A/Resources/nb.lproj/Sparkle.strings -------------------------------------------------------------------------------- /Gestr/Sparkle.framework/Versions/A/Resources/nl.lproj/SUAutomaticUpdateAlert.nib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhuusko5/Gestr/91fd4e310b6b603757016bf14f578360797579fd/Gestr/Sparkle.framework/Versions/A/Resources/nl.lproj/SUAutomaticUpdateAlert.nib -------------------------------------------------------------------------------- /Gestr/Sparkle.framework/Versions/A/Resources/nl.lproj/SUUpdateAlert.nib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhuusko5/Gestr/91fd4e310b6b603757016bf14f578360797579fd/Gestr/Sparkle.framework/Versions/A/Resources/nl.lproj/SUUpdateAlert.nib -------------------------------------------------------------------------------- /Gestr/Sparkle.framework/Versions/A/Resources/nl.lproj/SUUpdatePermissionPrompt.nib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhuusko5/Gestr/91fd4e310b6b603757016bf14f578360797579fd/Gestr/Sparkle.framework/Versions/A/Resources/nl.lproj/SUUpdatePermissionPrompt.nib -------------------------------------------------------------------------------- /Gestr/Sparkle.framework/Versions/A/Resources/nl.lproj/Sparkle.strings: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhuusko5/Gestr/91fd4e310b6b603757016bf14f578360797579fd/Gestr/Sparkle.framework/Versions/A/Resources/nl.lproj/Sparkle.strings -------------------------------------------------------------------------------- /Gestr/Sparkle.framework/Versions/A/Resources/pl.lproj/SUAutomaticUpdateAlert.nib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhuusko5/Gestr/91fd4e310b6b603757016bf14f578360797579fd/Gestr/Sparkle.framework/Versions/A/Resources/pl.lproj/SUAutomaticUpdateAlert.nib -------------------------------------------------------------------------------- /Gestr/Sparkle.framework/Versions/A/Resources/pl.lproj/SUUpdateAlert.nib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhuusko5/Gestr/91fd4e310b6b603757016bf14f578360797579fd/Gestr/Sparkle.framework/Versions/A/Resources/pl.lproj/SUUpdateAlert.nib -------------------------------------------------------------------------------- /Gestr/Sparkle.framework/Versions/A/Resources/pl.lproj/SUUpdatePermissionPrompt.nib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhuusko5/Gestr/91fd4e310b6b603757016bf14f578360797579fd/Gestr/Sparkle.framework/Versions/A/Resources/pl.lproj/SUUpdatePermissionPrompt.nib -------------------------------------------------------------------------------- /Gestr/Sparkle.framework/Versions/A/Resources/pl.lproj/Sparkle.strings: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhuusko5/Gestr/91fd4e310b6b603757016bf14f578360797579fd/Gestr/Sparkle.framework/Versions/A/Resources/pl.lproj/Sparkle.strings -------------------------------------------------------------------------------- /Gestr/Sparkle.framework/Versions/A/Resources/pt.lproj: -------------------------------------------------------------------------------- 1 | pt_BR.lproj -------------------------------------------------------------------------------- /Gestr/Sparkle.framework/Versions/A/Resources/pt_BR.lproj/SUAutomaticUpdateAlert.nib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhuusko5/Gestr/91fd4e310b6b603757016bf14f578360797579fd/Gestr/Sparkle.framework/Versions/A/Resources/pt_BR.lproj/SUAutomaticUpdateAlert.nib -------------------------------------------------------------------------------- /Gestr/Sparkle.framework/Versions/A/Resources/pt_BR.lproj/SUUpdateAlert.nib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhuusko5/Gestr/91fd4e310b6b603757016bf14f578360797579fd/Gestr/Sparkle.framework/Versions/A/Resources/pt_BR.lproj/SUUpdateAlert.nib -------------------------------------------------------------------------------- /Gestr/Sparkle.framework/Versions/A/Resources/pt_BR.lproj/SUUpdatePermissionPrompt.nib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhuusko5/Gestr/91fd4e310b6b603757016bf14f578360797579fd/Gestr/Sparkle.framework/Versions/A/Resources/pt_BR.lproj/SUUpdatePermissionPrompt.nib -------------------------------------------------------------------------------- /Gestr/Sparkle.framework/Versions/A/Resources/pt_BR.lproj/Sparkle.strings: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhuusko5/Gestr/91fd4e310b6b603757016bf14f578360797579fd/Gestr/Sparkle.framework/Versions/A/Resources/pt_BR.lproj/Sparkle.strings -------------------------------------------------------------------------------- /Gestr/Sparkle.framework/Versions/A/Resources/pt_PT.lproj/SUAutomaticUpdateAlert.nib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhuusko5/Gestr/91fd4e310b6b603757016bf14f578360797579fd/Gestr/Sparkle.framework/Versions/A/Resources/pt_PT.lproj/SUAutomaticUpdateAlert.nib -------------------------------------------------------------------------------- /Gestr/Sparkle.framework/Versions/A/Resources/pt_PT.lproj/SUUpdateAlert.nib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhuusko5/Gestr/91fd4e310b6b603757016bf14f578360797579fd/Gestr/Sparkle.framework/Versions/A/Resources/pt_PT.lproj/SUUpdateAlert.nib -------------------------------------------------------------------------------- /Gestr/Sparkle.framework/Versions/A/Resources/pt_PT.lproj/SUUpdatePermissionPrompt.nib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhuusko5/Gestr/91fd4e310b6b603757016bf14f578360797579fd/Gestr/Sparkle.framework/Versions/A/Resources/pt_PT.lproj/SUUpdatePermissionPrompt.nib -------------------------------------------------------------------------------- /Gestr/Sparkle.framework/Versions/A/Resources/pt_PT.lproj/Sparkle.strings: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhuusko5/Gestr/91fd4e310b6b603757016bf14f578360797579fd/Gestr/Sparkle.framework/Versions/A/Resources/pt_PT.lproj/Sparkle.strings -------------------------------------------------------------------------------- /Gestr/Sparkle.framework/Versions/A/Resources/ro.lproj/SUAutomaticUpdateAlert.nib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhuusko5/Gestr/91fd4e310b6b603757016bf14f578360797579fd/Gestr/Sparkle.framework/Versions/A/Resources/ro.lproj/SUAutomaticUpdateAlert.nib -------------------------------------------------------------------------------- /Gestr/Sparkle.framework/Versions/A/Resources/ro.lproj/SUUpdateAlert.nib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhuusko5/Gestr/91fd4e310b6b603757016bf14f578360797579fd/Gestr/Sparkle.framework/Versions/A/Resources/ro.lproj/SUUpdateAlert.nib -------------------------------------------------------------------------------- /Gestr/Sparkle.framework/Versions/A/Resources/ro.lproj/SUUpdatePermissionPrompt.nib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhuusko5/Gestr/91fd4e310b6b603757016bf14f578360797579fd/Gestr/Sparkle.framework/Versions/A/Resources/ro.lproj/SUUpdatePermissionPrompt.nib -------------------------------------------------------------------------------- /Gestr/Sparkle.framework/Versions/A/Resources/ro.lproj/Sparkle.strings: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhuusko5/Gestr/91fd4e310b6b603757016bf14f578360797579fd/Gestr/Sparkle.framework/Versions/A/Resources/ro.lproj/Sparkle.strings -------------------------------------------------------------------------------- /Gestr/Sparkle.framework/Versions/A/Resources/ru.lproj/SUAutomaticUpdateAlert.nib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhuusko5/Gestr/91fd4e310b6b603757016bf14f578360797579fd/Gestr/Sparkle.framework/Versions/A/Resources/ru.lproj/SUAutomaticUpdateAlert.nib -------------------------------------------------------------------------------- /Gestr/Sparkle.framework/Versions/A/Resources/ru.lproj/SUUpdateAlert.nib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhuusko5/Gestr/91fd4e310b6b603757016bf14f578360797579fd/Gestr/Sparkle.framework/Versions/A/Resources/ru.lproj/SUUpdateAlert.nib -------------------------------------------------------------------------------- /Gestr/Sparkle.framework/Versions/A/Resources/ru.lproj/SUUpdatePermissionPrompt.nib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhuusko5/Gestr/91fd4e310b6b603757016bf14f578360797579fd/Gestr/Sparkle.framework/Versions/A/Resources/ru.lproj/SUUpdatePermissionPrompt.nib -------------------------------------------------------------------------------- /Gestr/Sparkle.framework/Versions/A/Resources/ru.lproj/Sparkle.strings: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhuusko5/Gestr/91fd4e310b6b603757016bf14f578360797579fd/Gestr/Sparkle.framework/Versions/A/Resources/ru.lproj/Sparkle.strings -------------------------------------------------------------------------------- /Gestr/Sparkle.framework/Versions/A/Resources/sk.lproj/SUAutomaticUpdateAlert.nib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhuusko5/Gestr/91fd4e310b6b603757016bf14f578360797579fd/Gestr/Sparkle.framework/Versions/A/Resources/sk.lproj/SUAutomaticUpdateAlert.nib -------------------------------------------------------------------------------- /Gestr/Sparkle.framework/Versions/A/Resources/sk.lproj/SUUpdateAlert.nib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhuusko5/Gestr/91fd4e310b6b603757016bf14f578360797579fd/Gestr/Sparkle.framework/Versions/A/Resources/sk.lproj/SUUpdateAlert.nib -------------------------------------------------------------------------------- /Gestr/Sparkle.framework/Versions/A/Resources/sk.lproj/SUUpdatePermissionPrompt.nib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhuusko5/Gestr/91fd4e310b6b603757016bf14f578360797579fd/Gestr/Sparkle.framework/Versions/A/Resources/sk.lproj/SUUpdatePermissionPrompt.nib -------------------------------------------------------------------------------- /Gestr/Sparkle.framework/Versions/A/Resources/sk.lproj/Sparkle.strings: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhuusko5/Gestr/91fd4e310b6b603757016bf14f578360797579fd/Gestr/Sparkle.framework/Versions/A/Resources/sk.lproj/Sparkle.strings -------------------------------------------------------------------------------- /Gestr/Sparkle.framework/Versions/A/Resources/sl.lproj/SUAutomaticUpdateAlert.nib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhuusko5/Gestr/91fd4e310b6b603757016bf14f578360797579fd/Gestr/Sparkle.framework/Versions/A/Resources/sl.lproj/SUAutomaticUpdateAlert.nib -------------------------------------------------------------------------------- /Gestr/Sparkle.framework/Versions/A/Resources/sl.lproj/SUUpdateAlert.nib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhuusko5/Gestr/91fd4e310b6b603757016bf14f578360797579fd/Gestr/Sparkle.framework/Versions/A/Resources/sl.lproj/SUUpdateAlert.nib -------------------------------------------------------------------------------- /Gestr/Sparkle.framework/Versions/A/Resources/sl.lproj/SUUpdatePermissionPrompt.nib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhuusko5/Gestr/91fd4e310b6b603757016bf14f578360797579fd/Gestr/Sparkle.framework/Versions/A/Resources/sl.lproj/SUUpdatePermissionPrompt.nib -------------------------------------------------------------------------------- /Gestr/Sparkle.framework/Versions/A/Resources/sl.lproj/Sparkle.strings: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhuusko5/Gestr/91fd4e310b6b603757016bf14f578360797579fd/Gestr/Sparkle.framework/Versions/A/Resources/sl.lproj/Sparkle.strings -------------------------------------------------------------------------------- /Gestr/Sparkle.framework/Versions/A/Resources/sv.lproj/SUAutomaticUpdateAlert.nib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhuusko5/Gestr/91fd4e310b6b603757016bf14f578360797579fd/Gestr/Sparkle.framework/Versions/A/Resources/sv.lproj/SUAutomaticUpdateAlert.nib -------------------------------------------------------------------------------- /Gestr/Sparkle.framework/Versions/A/Resources/sv.lproj/SUUpdateAlert.nib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhuusko5/Gestr/91fd4e310b6b603757016bf14f578360797579fd/Gestr/Sparkle.framework/Versions/A/Resources/sv.lproj/SUUpdateAlert.nib -------------------------------------------------------------------------------- /Gestr/Sparkle.framework/Versions/A/Resources/sv.lproj/SUUpdatePermissionPrompt.nib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhuusko5/Gestr/91fd4e310b6b603757016bf14f578360797579fd/Gestr/Sparkle.framework/Versions/A/Resources/sv.lproj/SUUpdatePermissionPrompt.nib -------------------------------------------------------------------------------- /Gestr/Sparkle.framework/Versions/A/Resources/sv.lproj/Sparkle.strings: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhuusko5/Gestr/91fd4e310b6b603757016bf14f578360797579fd/Gestr/Sparkle.framework/Versions/A/Resources/sv.lproj/Sparkle.strings -------------------------------------------------------------------------------- /Gestr/Sparkle.framework/Versions/A/Resources/th.lproj/SUAutomaticUpdateAlert.nib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhuusko5/Gestr/91fd4e310b6b603757016bf14f578360797579fd/Gestr/Sparkle.framework/Versions/A/Resources/th.lproj/SUAutomaticUpdateAlert.nib -------------------------------------------------------------------------------- /Gestr/Sparkle.framework/Versions/A/Resources/th.lproj/SUUpdateAlert.nib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhuusko5/Gestr/91fd4e310b6b603757016bf14f578360797579fd/Gestr/Sparkle.framework/Versions/A/Resources/th.lproj/SUUpdateAlert.nib -------------------------------------------------------------------------------- /Gestr/Sparkle.framework/Versions/A/Resources/th.lproj/SUUpdatePermissionPrompt.nib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhuusko5/Gestr/91fd4e310b6b603757016bf14f578360797579fd/Gestr/Sparkle.framework/Versions/A/Resources/th.lproj/SUUpdatePermissionPrompt.nib -------------------------------------------------------------------------------- /Gestr/Sparkle.framework/Versions/A/Resources/th.lproj/Sparkle.strings: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhuusko5/Gestr/91fd4e310b6b603757016bf14f578360797579fd/Gestr/Sparkle.framework/Versions/A/Resources/th.lproj/Sparkle.strings -------------------------------------------------------------------------------- /Gestr/Sparkle.framework/Versions/A/Resources/tr.lproj/SUAutomaticUpdateAlert.nib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhuusko5/Gestr/91fd4e310b6b603757016bf14f578360797579fd/Gestr/Sparkle.framework/Versions/A/Resources/tr.lproj/SUAutomaticUpdateAlert.nib -------------------------------------------------------------------------------- /Gestr/Sparkle.framework/Versions/A/Resources/tr.lproj/SUUpdateAlert.nib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhuusko5/Gestr/91fd4e310b6b603757016bf14f578360797579fd/Gestr/Sparkle.framework/Versions/A/Resources/tr.lproj/SUUpdateAlert.nib -------------------------------------------------------------------------------- /Gestr/Sparkle.framework/Versions/A/Resources/tr.lproj/SUUpdatePermissionPrompt.nib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhuusko5/Gestr/91fd4e310b6b603757016bf14f578360797579fd/Gestr/Sparkle.framework/Versions/A/Resources/tr.lproj/SUUpdatePermissionPrompt.nib -------------------------------------------------------------------------------- /Gestr/Sparkle.framework/Versions/A/Resources/tr.lproj/Sparkle.strings: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhuusko5/Gestr/91fd4e310b6b603757016bf14f578360797579fd/Gestr/Sparkle.framework/Versions/A/Resources/tr.lproj/Sparkle.strings -------------------------------------------------------------------------------- /Gestr/Sparkle.framework/Versions/A/Resources/uk.lproj/SUAutomaticUpdateAlert.nib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhuusko5/Gestr/91fd4e310b6b603757016bf14f578360797579fd/Gestr/Sparkle.framework/Versions/A/Resources/uk.lproj/SUAutomaticUpdateAlert.nib -------------------------------------------------------------------------------- /Gestr/Sparkle.framework/Versions/A/Resources/uk.lproj/SUUpdateAlert.nib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhuusko5/Gestr/91fd4e310b6b603757016bf14f578360797579fd/Gestr/Sparkle.framework/Versions/A/Resources/uk.lproj/SUUpdateAlert.nib -------------------------------------------------------------------------------- /Gestr/Sparkle.framework/Versions/A/Resources/uk.lproj/SUUpdatePermissionPrompt.nib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhuusko5/Gestr/91fd4e310b6b603757016bf14f578360797579fd/Gestr/Sparkle.framework/Versions/A/Resources/uk.lproj/SUUpdatePermissionPrompt.nib -------------------------------------------------------------------------------- /Gestr/Sparkle.framework/Versions/A/Resources/uk.lproj/Sparkle.strings: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhuusko5/Gestr/91fd4e310b6b603757016bf14f578360797579fd/Gestr/Sparkle.framework/Versions/A/Resources/uk.lproj/Sparkle.strings -------------------------------------------------------------------------------- /Gestr/Sparkle.framework/Versions/A/Resources/zh_CN.lproj/SUAutomaticUpdateAlert.nib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhuusko5/Gestr/91fd4e310b6b603757016bf14f578360797579fd/Gestr/Sparkle.framework/Versions/A/Resources/zh_CN.lproj/SUAutomaticUpdateAlert.nib -------------------------------------------------------------------------------- /Gestr/Sparkle.framework/Versions/A/Resources/zh_CN.lproj/SUUpdateAlert.nib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhuusko5/Gestr/91fd4e310b6b603757016bf14f578360797579fd/Gestr/Sparkle.framework/Versions/A/Resources/zh_CN.lproj/SUUpdateAlert.nib -------------------------------------------------------------------------------- /Gestr/Sparkle.framework/Versions/A/Resources/zh_CN.lproj/SUUpdatePermissionPrompt.nib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhuusko5/Gestr/91fd4e310b6b603757016bf14f578360797579fd/Gestr/Sparkle.framework/Versions/A/Resources/zh_CN.lproj/SUUpdatePermissionPrompt.nib -------------------------------------------------------------------------------- /Gestr/Sparkle.framework/Versions/A/Resources/zh_CN.lproj/Sparkle.strings: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhuusko5/Gestr/91fd4e310b6b603757016bf14f578360797579fd/Gestr/Sparkle.framework/Versions/A/Resources/zh_CN.lproj/Sparkle.strings -------------------------------------------------------------------------------- /Gestr/Sparkle.framework/Versions/A/Resources/zh_TW.lproj/SUAutomaticUpdateAlert.nib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhuusko5/Gestr/91fd4e310b6b603757016bf14f578360797579fd/Gestr/Sparkle.framework/Versions/A/Resources/zh_TW.lproj/SUAutomaticUpdateAlert.nib -------------------------------------------------------------------------------- /Gestr/Sparkle.framework/Versions/A/Resources/zh_TW.lproj/SUUpdateAlert.nib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhuusko5/Gestr/91fd4e310b6b603757016bf14f578360797579fd/Gestr/Sparkle.framework/Versions/A/Resources/zh_TW.lproj/SUUpdateAlert.nib -------------------------------------------------------------------------------- /Gestr/Sparkle.framework/Versions/A/Resources/zh_TW.lproj/SUUpdatePermissionPrompt.nib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhuusko5/Gestr/91fd4e310b6b603757016bf14f578360797579fd/Gestr/Sparkle.framework/Versions/A/Resources/zh_TW.lproj/SUUpdatePermissionPrompt.nib -------------------------------------------------------------------------------- /Gestr/Sparkle.framework/Versions/A/Resources/zh_TW.lproj/Sparkle.strings: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhuusko5/Gestr/91fd4e310b6b603757016bf14f578360797579fd/Gestr/Sparkle.framework/Versions/A/Resources/zh_TW.lproj/Sparkle.strings -------------------------------------------------------------------------------- /Gestr/Sparkle.framework/Versions/A/Sparkle: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhuusko5/Gestr/91fd4e310b6b603757016bf14f578360797579fd/Gestr/Sparkle.framework/Versions/A/Sparkle -------------------------------------------------------------------------------- /Gestr/Sparkle.framework/Versions/Current: -------------------------------------------------------------------------------- 1 | A -------------------------------------------------------------------------------- /Gestr/WebPage.h: -------------------------------------------------------------------------------- 1 | #import "Launchable.h" 2 | 3 | @interface WebPage : Launchable 4 | 5 | @property NSString *url; 6 | @property NSString *targetBrowserId; 7 | 8 | - (id)initWithDisplayName:(NSString *)displayName icon:(NSImage *)icon url:(NSString *)url targetBrowserId:(NSString *)targetBrowserId; 9 | - (void)launch; 10 | 11 | @end 12 | -------------------------------------------------------------------------------- /Gestr/WebPage.m: -------------------------------------------------------------------------------- 1 | #import "WebPage.h" 2 | 3 | @implementation WebPage 4 | 5 | - (id)initWithDisplayName:(NSString *)displayName icon:(NSImage *)icon url:(NSString *)url targetBrowserId:(NSString *)targetBrowserId { 6 | NSString *launchId = [NSString stringWithFormat:@"%@:%@", targetBrowserId, url]; 7 | 8 | self = [super initWithDisplayName:displayName launchId:launchId icon:icon]; 9 | 10 | _url = url; 11 | _targetBrowserId = targetBrowserId; 12 | 13 | return self; 14 | } 15 | 16 | - (void)launch { 17 | [NSWorkspace.sharedWorkspace openURLs:@[[NSURL URLWithString:self.url]] 18 | withAppBundleIdentifier:self.targetBrowserId 19 | options:0 20 | additionalEventParamDescriptor:nil 21 | launchIdentifiers:nil]; 22 | } 23 | 24 | @end 25 | -------------------------------------------------------------------------------- /Gestr/background2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhuusko5/Gestr/91fd4e310b6b603757016bf14f578360797579fd/Gestr/background2.png -------------------------------------------------------------------------------- /Gestr/main.m: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | int main(int argc, const char *argv[]) { 4 | return NSApplicationMain(argc, (const char **)argv); 5 | } 6 | -------------------------------------------------------------------------------- /Gestr/niceLine.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhuusko5/Gestr/91fd4e310b6b603757016bf14f578360797579fd/Gestr/niceLine.png -------------------------------------------------------------------------------- /Gestr/niceLineFlipped.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhuusko5/Gestr/91fd4e310b6b603757016bf14f578360797579fd/Gestr/niceLineFlipped.png -------------------------------------------------------------------------------- /Gestr/tableCellBack.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhuusko5/Gestr/91fd4e310b6b603757016bf14f578360797579fd/Gestr/tableCellBack.png -------------------------------------------------------------------------------- /Gestr/trackpadBackground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhuusko5/Gestr/91fd4e310b6b603757016bf14f578360797579fd/Gestr/trackpadBackground.png -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Gestr 2 | 3 | Launch apps and bookmarks on your Mac with multitouch trackpad drawings. 4 | 5 | Signed/packaged/auto-updating version download [here](http://tiny.cc/gestr-mac-download). 6 | 7 | Demo video below. 8 | 9 | [![ScreenShot](https://i.vimeocdn.com/video/462178176.jpg?mw=1920&mh=1080&q=70)](http://vimeo.com/mhuusko5/gestr-demo) 10 | -------------------------------------------------------------------------------- /Sparkle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Gestr Update 5 | https://raw.githubusercontent.com/mhuusko5/Gestr/master/Sparkle.xml 6 | Gestr Update 7 | en 8 | 9 | Version 1.86 10 | *IMPORTANT*: 1.86 is a transition to a new code signing (security) profile, so it requires a fresh installer – click "Learn more..." to download this installer. Run it and Gestr will work/update as normal from now on. Thanks! 11 | 1.86 12 | https://github.com/mhuusko5/Gestr/releases/download/1.86/Gestr.pkg 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /Sparkle2.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Gestr Update 5 | https://raw.githubusercontent.com/mhuusko5/Gestr/master/Sparkle2.xml 6 | Gestr Update 7 | en 8 | 9 | Version 1.89 10 | 1.82, AppleScripts (from ~/Library/Application Support/Gestr/Scripts). 1.88, updated for Catalina!. 1.89, faster bookmark launching. 11 | 12 | 13 | 14 | 15 | --------------------------------------------------------------------------------