├── .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 | [](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 |
--------------------------------------------------------------------------------