Skip to content

Commit ccbc281

Browse files
author
Ryan Hanson
committed
Adding the foundation of the Rectangle app
1 parent db75734 commit ccbc281

File tree

67 files changed

+5143
-0
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

67 files changed

+5143
-0
lines changed

.gitignore

+36
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
.idea
2+
**/.DS_Store
3+
*/xcuserdata/
4+
xcuserdata/
5+
**.xcuserstate
6+
*.xcworkspace
7+
Pods
8+
9+
## Xcode per-user config
10+
*.mode1
11+
*.mode1v3
12+
*.mode2v3
13+
*.perspective
14+
*.perspectivev3
15+
*.pbxuser
16+
17+
## Xcode Patch
18+
*.xcodeproj/*
19+
!*.xcodeproj/project.pbxproj
20+
!*.xcodeproj/xcshareddata/
21+
!*.xcworkspace/contents.xcworkspacedata
22+
/*.gcno
23+
24+
## Build products
25+
build/
26+
*.o
27+
*.LinkFileList
28+
*.hmap
29+
30+
## Automatic backup files
31+
*~.nib/
32+
*.swp
33+
*~
34+
*.dat
35+
*.dep
36+

Podfile

+36
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
# Uncomment the next line to define a global platform for your project
2+
platform :osx, '10.12'
3+
4+
inhibit_all_warnings!
5+
6+
target 'Rectangle' do
7+
# Comment the next line if you don't want to use dynamic frameworks
8+
use_frameworks!
9+
10+
# Pods for Rectangle
11+
pod 'MASShortcut'
12+
pod 'Sparkle'
13+
14+
target 'RectangleTests' do
15+
inherit! :search_paths
16+
# Pods for testing
17+
end
18+
19+
end
20+
21+
target 'RectangleMAS' do
22+
# Comment the next line if you don't want to use dynamic frameworks
23+
use_frameworks!
24+
25+
# Pods for Rectangle
26+
pod 'MASShortcut'
27+
28+
end
29+
30+
target 'RectangleLauncher' do
31+
# Comment the next line if you don't want to use dynamic frameworks
32+
use_frameworks!
33+
34+
# Pods for RectangleLauncher
35+
36+
end

Podfile.lock

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
PODS:
2+
- MASShortcut (2.3.6)
3+
- Sparkle (1.21.3)
4+
5+
DEPENDENCIES:
6+
- MASShortcut
7+
- Sparkle
8+
9+
SPEC REPOS:
10+
https://github.com/cocoapods/specs.git:
11+
- MASShortcut
12+
- Sparkle
13+
14+
SPEC CHECKSUMS:
15+
MASShortcut: 9c215e8a8a78f3d01ce56da48e2730ab66b538fa
16+
Sparkle: 3f75576db8b0265adef36c43249d747f22d0b708
17+
18+
PODFILE CHECKSUM: 9d924c34b8abce32760985160284c3feccaedcd7
19+
20+
COCOAPODS: 1.7.0

Rectangle.xcodeproj/project.pbxproj

+954
Large diffs are not rendered by default.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
//
2+
// AccessibilityAuthorization.swift
3+
// Rectangle
4+
//
5+
// Created by Ryan Hanson on 6/11/19.
6+
// Copyright © 2019 Ryan Hanson. All rights reserved.
7+
//
8+
9+
import Foundation
10+
import Cocoa
11+
12+
class AccessibilityAuthorization {
13+
14+
private var accessibilityWindow: AccessibilityWindow?
15+
16+
public func checkAccessibility(completion: @escaping () -> Void) -> Bool {
17+
if !AXIsProcessTrusted() {
18+
accessibilityWindow = AccessibilityWindow(windowNibName: "AccessibilityWindow")
19+
accessibilityWindow?.showWindow(nil)
20+
NSApp.activate(ignoringOtherApps: true)
21+
pollAccessibility(completion: completion)
22+
return false
23+
} else {
24+
return true
25+
}
26+
}
27+
28+
private func pollAccessibility(completion: @escaping () -> Void) {
29+
DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) {
30+
if AXIsProcessTrusted() {
31+
self.accessibilityWindow?.close()
32+
completion()
33+
} else {
34+
self.pollAccessibility(completion: completion)
35+
}
36+
}
37+
}
38+
39+
func generateUnauthorizedMenu() -> NSMenu {
40+
let unauthMenu = NSMenu()
41+
unauthMenu.addItem(withTitle: "Not Authorized to Control Your Computer", action: nil, keyEquivalent: "")
42+
unauthMenu.addItem(withTitle: "Authorize...", action: #selector(bringWindowToFront), keyEquivalent: "")
43+
unauthMenu.addItem(NSMenuItem.separator())
44+
unauthMenu.addItem(withTitle: "Quit", action: #selector(quit), keyEquivalent: "q")
45+
unauthMenu.items.forEach { $0.target = self }
46+
return unauthMenu
47+
}
48+
49+
@objc func bringWindowToFront() {
50+
NSApp.activate(ignoringOtherApps: true)
51+
}
52+
53+
@objc func quit() {
54+
exit(0)
55+
}
56+
57+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
//
2+
// AccessibilityWindow.swift
3+
// Rectangle
4+
//
5+
// Created by Ryan Hanson on 6/13/19.
6+
// Copyright © 2019 Ryan Hanson. All rights reserved.
7+
//
8+
9+
import Cocoa
10+
11+
class AccessibilityWindow: NSWindowController {
12+
13+
override func windowDidLoad() {
14+
super.windowDidLoad()
15+
self.window?.titlebarAppearsTransparent = true
16+
let closeButton = self.window?.standardWindowButton(.closeButton)
17+
closeButton?.target = self
18+
closeButton?.action = #selector(quit)
19+
}
20+
21+
@objc func quit() {
22+
exit(1)
23+
}
24+
25+
}
26+
27+
class AccessibilityBox: NSBox {
28+
29+
override func acceptsFirstMouse(for event: NSEvent?) -> Bool {
30+
return true
31+
}
32+
33+
override func mouseDown(with event: NSEvent) {
34+
openSystemPrefs()
35+
}
36+
37+
override func mouseEntered(with event: NSEvent) {
38+
super.mouseEntered(with: event)
39+
NSCursor.pointingHand.set()
40+
}
41+
42+
override func mouseExited(with event: NSEvent) {
43+
super.mouseExited(with: event)
44+
NSCursor.arrow.set()
45+
}
46+
47+
override func updateTrackingAreas() {
48+
for trackingArea in self.trackingAreas {
49+
self.removeTrackingArea(trackingArea)
50+
}
51+
52+
let options: NSTrackingArea.Options = [.mouseEnteredAndExited, .activeAlways]
53+
let trackingArea = NSTrackingArea(rect: self.bounds, options: options, owner: self, userInfo: nil)
54+
self.addTrackingArea(trackingArea)
55+
}
56+
57+
func openSystemPrefs() {
58+
NSWorkspace.shared.open(URL(string:"x-apple.systempreferences:com.apple.preference.security?Privacy_Accessibility")!)
59+
}
60+
61+
}

0 commit comments

Comments
 (0)