28 Commits
1.0 ... 1.2.1

Author SHA1 Message Date
neon443
c0b8d2f3ed Sparkle: Auto Updates work YAYYYYYYY 2025-05-30 15:00:53 +01:00
neon443
a6f06c4e12 Merge remote-tracking branch 'refs/remotes/origin/main' 2025-05-30 13:05:30 +01:00
neon443
9ff4f67e33 add pubkey 2025-05-30 10:44:23 +01:00
neon443
5bfeef66ab sparke menu item 2025-05-30 10:42:54 +01:00
Nihaal Sharma
58c834f1ed Update README.md 2025-05-29 17:29:27 +01:00
Nihaal Sharma
84326f7e15 Update README.md 2025-05-29 17:28:33 +01:00
Nihaal Sharma
27e410ae76 Update README.md 2025-05-29 17:25:54 +01:00
neon443
d943415b98 add mouse moves count
tweak the aligment of the pinch
added mouse move count to menu bar,
grammar fix
2025-05-29 16:11:41 +01:00
neon443
83efb14bd5 fix 2x pinchs 2025-05-29 16:03:28 +01:00
neon443
d60d90bc60 got a pinch lollll 2025-05-29 16:00:21 +01:00
neon443
4e55cc4516 we have a square following the mouse 2025-05-29 15:38:54 +01:00
neon443
1a0d3c2e38 YESSS 2025-05-29 15:33:19 +01:00
neon443
e46edecec7 xcode 12.0 compat 2025-05-29 14:00:18 +01:00
neon443
22c825dbb2 gitignore 2025-05-29 13:54:10 +01:00
neon443
5357ce8443 large rewrite of dpsettings to use an init and handle failed decodes
make moveMouse() use dpsettings' values
skyhigh moves faster
skyhigh uses dpsettings' values
extended NSScreen for safe access to main?.frame
customising the width height of the mouse move rect should be possible? now just neeed a prefs windo
2025-05-29 13:47:20 +01:00
neon443
853fc2a2db skyhigh: shows a window above everythign else
now just shows wherre the mouse can be warped
2025-05-29 11:21:08 +01:00
neon443
6a68713ad5 refactoring 2025-05-28 17:56:59 +01:00
neon443
b15116b292 refactoring 2025-05-28 17:54:01 +01:00
neon443
e4c41c4a58 get started on move mouse instead 2025-05-28 17:40:35 +01:00
neon443
c099d4bec3 Merge remote-tracking branch 'refs/remotes/origin/main' 2025-05-28 15:53:28 +01:00
neon443
5718e42f41 added settings: saves dock moves, smaller deathzone in fullscreeen etc 2025-05-28 15:52:40 +01:00
neon443
936f18d714 add fullscreen support, fix dock moving to the right when hovering over menu bar icon 2025-05-27 16:34:01 +01:00
Nihaal Sharma
3e7a7c2ac2 README.md 2025-05-27 15:05:28 +01:00
neon443
43863d3827 _ 2025-05-26 19:22:05 +01:00
neon443
f18874deb3 version bump 2025-05-26 17:26:24 +01:00
neon443
7ba2e84cb1 fix quit button 2025-05-26 17:24:19 +01:00
Nihaal Sharma
bc2bc9bb6d Update README.md 2025-05-26 13:47:13 +01:00
neon443
d954730117 icon stuff 2025-05-26 13:43:42 +01:00
19 changed files with 598 additions and 138 deletions

3
.gitignore vendored
View File

@@ -1 +1,2 @@
.DS_Store **.DS_Store
**DockPhobia.dmg

View File

@@ -5,8 +5,8 @@
// Created by neon443 on 26/05/2025. // Created by neon443 on 26/05/2025.
// //
VERSION = 1.0 VERSION = 1.2.1
BUILD_ID = 4 BUILD_ID = 3
TEAM_ID = 8JGND254B7 TEAM_ID = 8JGND254B7
BUNDLE_ID = com.neon443.DockPhobia BUNDLE_ID = com.neon443.DockPhobia

View File

@@ -3,7 +3,7 @@
archiveVersion = 1; archiveVersion = 1;
classes = { classes = {
}; };
objectVersion = 77; objectVersion = 63;
objects = { objects = {
/* Begin PBXBuildFile section */ /* Begin PBXBuildFile section */
@@ -11,6 +11,11 @@
A966B4F42DE0842500C721A5 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = A966B4EE2DE0842400C721A5 /* AppDelegate.swift */; }; A966B4F42DE0842500C721A5 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = A966B4EE2DE0842400C721A5 /* AppDelegate.swift */; };
A966B4F52DE0842500C721A5 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = A966B4EF2DE0842400C721A5 /* Assets.xcassets */; }; A966B4F52DE0842500C721A5 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = A966B4EF2DE0842400C721A5 /* Assets.xcassets */; };
A966B4F82DE0852900C721A5 /* MouseTracker.swift in Sources */ = {isa = PBXBuildFile; fileRef = A966B4F72DE0852900C721A5 /* MouseTracker.swift */; }; A966B4F82DE0852900C721A5 /* MouseTracker.swift in Sources */ = {isa = PBXBuildFile; fileRef = A966B4F72DE0852900C721A5 /* MouseTracker.swift */; };
A98C20C62DE614180008D61C /* DPSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = A98C20C52DE614180008D61C /* DPSettings.swift */; };
A9C9AF812DE7776A0039D7A5 /* DockSide.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9C9AF802DE777530039D7A5 /* DockSide.swift */; };
A9C9AF832DE77CB70039D7A5 /* SkyHigh.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9C9AF822DE77CB70039D7A5 /* SkyHigh.swift */; };
A9C9B0682DE888B20039D7A5 /* Preferences.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9C9B0672DE888B20039D7A5 /* Preferences.swift */; };
A9C9B06D2DE99E5F0039D7A5 /* Sparkle in Frameworks */ = {isa = PBXBuildFile; productRef = A9C9B06C2DE99E5F0039D7A5 /* Sparkle */; };
/* End PBXBuildFile section */ /* End PBXBuildFile section */
/* Begin PBXFileReference section */ /* Begin PBXFileReference section */
@@ -21,6 +26,11 @@
A966B4F02DE0842400C721A5 /* DockPhobia.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = DockPhobia.entitlements; sourceTree = "<group>"; }; A966B4F02DE0842400C721A5 /* DockPhobia.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = DockPhobia.entitlements; sourceTree = "<group>"; };
A966B4F72DE0852900C721A5 /* MouseTracker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MouseTracker.swift; sourceTree = "<group>"; }; A966B4F72DE0852900C721A5 /* MouseTracker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MouseTracker.swift; sourceTree = "<group>"; };
A97798072DE485F200B6CB13 /* Config.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Config.xcconfig; sourceTree = "<group>"; }; A97798072DE485F200B6CB13 /* Config.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Config.xcconfig; sourceTree = "<group>"; };
A98C20C52DE614180008D61C /* DPSettings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DPSettings.swift; sourceTree = "<group>"; };
A9C9AF802DE777530039D7A5 /* DockSide.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DockSide.swift; sourceTree = "<group>"; };
A9C9AF822DE77CB70039D7A5 /* SkyHigh.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SkyHigh.swift; sourceTree = "<group>"; };
A9C9B0672DE888B20039D7A5 /* Preferences.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Preferences.swift; sourceTree = "<group>"; };
A9C9B06E2DE9B55F0039D7A5 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = Info.plist; sourceTree = "<group>"; };
/* End PBXFileReference section */ /* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */ /* Begin PBXFrameworksBuildPhase section */
@@ -28,6 +38,7 @@
isa = PBXFrameworksBuildPhase; isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
A9C9B06D2DE99E5F0039D7A5 /* Sparkle in Frameworks */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
}; };
@@ -46,6 +57,7 @@
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
A94BEC0E2DE23E8500D4811D /* MainMenu.xib */, A94BEC0E2DE23E8500D4811D /* MainMenu.xib */,
A9C9B0672DE888B20039D7A5 /* Preferences.swift */,
); );
path = Views; path = Views;
sourceTree = "<group>"; sourceTree = "<group>";
@@ -70,8 +82,12 @@
A966B4F32DE0842400C721A5 /* DockPhobia */ = { A966B4F32DE0842400C721A5 /* DockPhobia */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
A9C9B06E2DE9B55F0039D7A5 /* Info.plist */,
A966B4EE2DE0842400C721A5 /* AppDelegate.swift */, A966B4EE2DE0842400C721A5 /* AppDelegate.swift */,
A966B4F72DE0852900C721A5 /* MouseTracker.swift */, A966B4F72DE0852900C721A5 /* MouseTracker.swift */,
A9C9AF822DE77CB70039D7A5 /* SkyHigh.swift */,
A98C20C52DE614180008D61C /* DPSettings.swift */,
A9C9AF802DE777530039D7A5 /* DockSide.swift */,
A94BEC102DE23ECE00D4811D /* Views */, A94BEC102DE23ECE00D4811D /* Views */,
A94BEC0A2DE21F8100D4811D /* Resources */, A94BEC0A2DE21F8100D4811D /* Resources */,
A966B4F02DE0842400C721A5 /* DockPhobia.entitlements */, A966B4F02DE0842400C721A5 /* DockPhobia.entitlements */,
@@ -96,6 +112,7 @@
); );
name = DockPhobia; name = DockPhobia;
packageProductDependencies = ( packageProductDependencies = (
A9C9B06C2DE99E5F0039D7A5 /* Sparkle */,
); );
productName = DockPhobia; productName = DockPhobia;
productReference = A966B4D62DE0841000C721A5 /* DockPhobia.app */; productReference = A966B4D62DE0841000C721A5 /* DockPhobia.app */;
@@ -117,6 +134,7 @@
}; };
}; };
buildConfigurationList = A966B4D12DE0841000C721A5 /* Build configuration list for PBXProject "DockPhobia" */; buildConfigurationList = A966B4D12DE0841000C721A5 /* Build configuration list for PBXProject "DockPhobia" */;
compatibilityVersion = "Xcode 12.0";
developmentRegion = en; developmentRegion = en;
hasScannedForEncodings = 0; hasScannedForEncodings = 0;
knownRegions = ( knownRegions = (
@@ -125,7 +143,9 @@
); );
mainGroup = A966B4CD2DE0841000C721A5; mainGroup = A966B4CD2DE0841000C721A5;
minimizedProjectReferenceProxies = 1; minimizedProjectReferenceProxies = 1;
preferredProjectObjectVersion = 77; packageReferences = (
A9C9B06B2DE99E5F0039D7A5 /* XCRemoteSwiftPackageReference "Sparkle" */,
);
productRefGroup = A966B4D72DE0841000C721A5 /* Products */; productRefGroup = A966B4D72DE0841000C721A5 /* Products */;
projectDirPath = ""; projectDirPath = "";
projectRoot = ""; projectRoot = "";
@@ -152,8 +172,12 @@
isa = PBXSourcesBuildPhase; isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
A98C20C62DE614180008D61C /* DPSettings.swift in Sources */,
A9C9AF832DE77CB70039D7A5 /* SkyHigh.swift in Sources */,
A9C9B0682DE888B20039D7A5 /* Preferences.swift in Sources */,
A966B4F82DE0852900C721A5 /* MouseTracker.swift in Sources */, A966B4F82DE0852900C721A5 /* MouseTracker.swift in Sources */,
A966B4F42DE0842500C721A5 /* AppDelegate.swift in Sources */, A966B4F42DE0842500C721A5 /* AppDelegate.swift in Sources */,
A9C9AF812DE7776A0039D7A5 /* DockSide.swift in Sources */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
}; };
@@ -294,6 +318,8 @@
ENABLE_HARDENED_RUNTIME = YES; ENABLE_HARDENED_RUNTIME = YES;
ENABLE_USER_SCRIPT_SANDBOXING = NO; ENABLE_USER_SCRIPT_SANDBOXING = NO;
GENERATE_INFOPLIST_FILE = YES; GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_FILE = DockPhobia/Info.plist;
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.entertainment";
INFOPLIST_KEY_LSUIElement = YES; INFOPLIST_KEY_LSUIElement = YES;
INFOPLIST_KEY_NSAppleEventsUsageDescription = _; INFOPLIST_KEY_NSAppleEventsUsageDescription = _;
INFOPLIST_KEY_NSHumanReadableCopyright = ""; INFOPLIST_KEY_NSHumanReadableCopyright = "";
@@ -328,6 +354,8 @@
ENABLE_HARDENED_RUNTIME = YES; ENABLE_HARDENED_RUNTIME = YES;
ENABLE_USER_SCRIPT_SANDBOXING = NO; ENABLE_USER_SCRIPT_SANDBOXING = NO;
GENERATE_INFOPLIST_FILE = YES; GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_FILE = DockPhobia/Info.plist;
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.entertainment";
INFOPLIST_KEY_LSUIElement = YES; INFOPLIST_KEY_LSUIElement = YES;
INFOPLIST_KEY_NSAppleEventsUsageDescription = _; INFOPLIST_KEY_NSAppleEventsUsageDescription = _;
INFOPLIST_KEY_NSHumanReadableCopyright = ""; INFOPLIST_KEY_NSHumanReadableCopyright = "";
@@ -370,6 +398,25 @@
defaultConfigurationName = Release; defaultConfigurationName = Release;
}; };
/* End XCConfigurationList section */ /* End XCConfigurationList section */
/* Begin XCRemoteSwiftPackageReference section */
A9C9B06B2DE99E5F0039D7A5 /* XCRemoteSwiftPackageReference "Sparkle" */ = {
isa = XCRemoteSwiftPackageReference;
repositoryURL = "https://github.com/sparkle-project/Sparkle";
requirement = {
kind = upToNextMajorVersion;
minimumVersion = 2.7.0;
};
};
/* End XCRemoteSwiftPackageReference section */
/* Begin XCSwiftPackageProductDependency section */
A9C9B06C2DE99E5F0039D7A5 /* Sparkle */ = {
isa = XCSwiftPackageProductDependency;
package = A9C9B06B2DE99E5F0039D7A5 /* XCRemoteSwiftPackageReference "Sparkle" */;
productName = Sparkle;
};
/* End XCSwiftPackageProductDependency section */
}; };
rootObject = A966B4CE2DE0841000C721A5 /* Project object */; rootObject = A966B4CE2DE0841000C721A5 /* Project object */;
} }

View File

@@ -0,0 +1,15 @@
{
"originHash" : "e721da7f9826abdffcb6185e886155efa2514bd6234475f1afa893e29eb258d6",
"pins" : [
{
"identity" : "sparkle",
"kind" : "remoteSourceControl",
"location" : "https://github.com/sparkle-project/Sparkle",
"state" : {
"revision" : "0ca3004e98712ea2b39dd881d28448630cce1c99",
"version" : "2.7.0"
}
}
],
"version" : 3
}

BIN
DockPhobia/.DS_Store vendored
View File

Binary file not shown.

View File

@@ -6,36 +6,58 @@
// //
import AppKit import AppKit
import Sparkle
@main @NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate { class AppDelegate: NSObject, NSApplicationDelegate {
public var statusItem: NSStatusItem! public var statusItem: NSStatusItem!
var mouseTracker = MouseTracker() var settings = DPSettingsModel()
var mouseTracker: MouseTracker
let updateController: SPUStandardUpdaterController
override init() {
self.mouseTracker = MouseTracker(settings: settings)
//call .startUpdater() later
updateController = SPUStandardUpdaterController(
startingUpdater: true,
updaterDelegate: nil,
userDriverDelegate: nil
)
super.init()
}
func applicationDidFinishLaunching(_ aNotification: Notification) { func applicationDidFinishLaunching(_ aNotification: Notification) {
statusItem = NSStatusBar.system.statusItem(withLength: NSStatusItem.variableLength) statusItem = NSStatusBar.system.statusItem(withLength: NSStatusItem.variableLength)
if let button = statusItem.button { if let button = statusItem.button {
button.image = NSImage(named: "cursor.slash") button.image = NSImage(named: "cursor.slash")
} }
setupMenus() refreshMenus()
} }
func applicationWillTerminate(_ aNotification: Notification) { func applicationWillTerminate(_ aNotification: Notification) {
// Insert code here to tear down your application settings.saveSettings()
} }
func applicationSupportsSecureRestorableState(_ app: NSApplication) -> Bool { func applicationSupportsSecureRestorableState(_ app: NSApplication) -> Bool {
return true return true
} }
//MARK: menu bar stuff
func setupMenus() { func setupMenus() {
let menu = NSMenu() let menu = NSMenu()
let start = NSMenuItem(title: describeStartButton(), action: #selector(didTapStart), keyEquivalent: "") let start = NSMenuItem(title: describeStartButton(), action: #selector(didTapStart), keyEquivalent: "")
menu.addItem(start) menu.addItem(start)
let checkforUpdatesMenuItem = NSMenuItem(
title: "Check for Updates...",
action: #selector(SPUStandardUpdaterController.checkForUpdates(_:)),
keyEquivalent: ""
)
checkforUpdatesMenuItem.target = updateController
menu.addItem(checkforUpdatesMenuItem)
let screen = NSMenuItem( let screen = NSMenuItem(
title: "\(mouseTracker.screen.width)x\(mouseTracker.screen.height)", title: "\(mouseTracker.screen.width)x\(mouseTracker.screen.height)",
action: nil, action: nil,
@@ -43,37 +65,58 @@ class AppDelegate: NSObject, NSApplicationDelegate {
) )
menu.addItem(screen) menu.addItem(screen)
let dockMoves = NSMenuItem(
title: "Moved the Dock \(settings.settings.dockMoves) time\(settings.settings.dockMoves.plural)",
action: nil,
keyEquivalent: ""
)
menu.addItem(dockMoves)
let mouseMoves = NSMenuItem(
title: "Moved the cursor \(settings.settings.mouseMoves) time\(settings.settings.mouseMoves.plural)",
action: nil,
keyEquivalent: ""
)
menu.addItem(mouseMoves)
menu.addItem(NSMenuItem.separator()) menu.addItem(NSMenuItem.separator())
menu.addItem( let moveMouseButton = NSMenuItem(
NSMenuItem( title: "Move cursor instead",
title: "Move Dock to left", action: #selector(moveMouseToggle),
keyEquivalent: ""
)
moveMouseButton.state = NSControl.StateValue(rawValue: settings.settings.moveMouseInstead ? 1 : 0)
menu.addItem(moveMouseButton)
menu.addItem(NSMenuItem.separator())
let checkfullscreenButton = NSMenuItem(
title: "Smaller deathzone in fullscreen",
action: #selector(checkFullscreenToggle),
keyEquivalent: ""
)
checkfullscreenButton.state = NSControl.StateValue(rawValue: settings.settings.checkFullscreen ? 1 : 0)
menu.addItem(checkfullscreenButton)
menu.addItem(NSMenuItem.separator())
menu.addItem(NSMenuItem(
title: "Move Dock to the left",
action: #selector(moveDockObjcLeft), action: #selector(moveDockObjcLeft),
keyEquivalent: "" keyEquivalent: ""))
) menu.addItem(NSMenuItem(
) title: "Move Dock to the bottom",
menu.addItem(
NSMenuItem(
title: "Move Dock to bottom",
action: #selector(moveDockObjcBottom), action: #selector(moveDockObjcBottom),
keyEquivalent: "" keyEquivalent: ""))
) menu.addItem(NSMenuItem(
) title: "Move Dock to the right",
menu.addItem(
NSMenuItem(
title: "Move Dock to right",
action: #selector(moveDockObjcRight), action: #selector(moveDockObjcRight),
keyEquivalent: "" keyEquivalent: ""))
)
)
menu.addItem(NSMenuItem.separator()) menu.addItem(NSMenuItem.separator())
let quit = NSMenuItem(title: "Quit", action: #selector(didTapStart), keyEquivalent: "q") let quit = NSMenuItem(title: "Quit", action: #selector(quit), keyEquivalent: "q")
menu.addItem(quit) menu.addItem(quit)
statusItem.menu = menu statusItem.menu = menu
} }
func changeMenuIcon(running: Bool) { func changeMenuIcon(running: Bool) {
guard let button = statusItem.button else { return } guard let button = statusItem.button else { return }
switch running { switch running {
@@ -83,7 +126,6 @@ class AppDelegate: NSObject, NSApplicationDelegate {
button.image = NSImage(named: "cursor.slash") button.image = NSImage(named: "cursor.slash")
} }
} }
@objc func didTapStart() { @objc func didTapStart() {
if mouseTracker.running { if mouseTracker.running {
mouseTracker.stop() mouseTracker.stop()
@@ -92,13 +134,22 @@ class AppDelegate: NSObject, NSApplicationDelegate {
mouseTracker.start() mouseTracker.start()
changeMenuIcon(running: true) changeMenuIcon(running: true)
} }
setupMenus() refreshMenus()
}
@objc func quit() {
NSApplication.shared.terminate(self)
} }
@objc func moveDockObjcLeft() { mouseTracker.moveDock(.left) } @objc func moveDockObjcLeft() { mouseTracker.moveDock(.left) }
@objc func moveDockObjcRight() { mouseTracker.moveDock(.right) } @objc func moveDockObjcRight() { mouseTracker.moveDock(.right) }
@objc func moveDockObjcBottom() { mouseTracker.moveDock(.bottom) } @objc func moveDockObjcBottom() { mouseTracker.moveDock(.bottom) }
@objc func checkFullscreenToggle() {
settings.settings.checkFullscreen.toggle()
refreshMenus()
}
@objc func moveMouseToggle() {
settings.settings.moveMouseInstead.toggle()
refreshMenus()
}
func describeStartButton() -> String { func describeStartButton() -> String {
if mouseTracker.running { if mouseTracker.running {
return "Stop tracking" return "Stop tracking"
@@ -107,3 +158,14 @@ class AppDelegate: NSObject, NSApplicationDelegate {
} }
} }
} }
func refreshMenus() {
guard let delegate = NSApp.delegate as? AppDelegate else { return }
delegate.setupMenus()
}
extension Numeric {
var plural: String {
return self == 1 ? "" : "s"
}
}

114
DockPhobia/DPSettings.swift Normal file
View File

@@ -0,0 +1,114 @@
//
// Persistence.swift
// DockPhobia
//
// Created by neon443 on 27/05/2025.
//
import Foundation
import AppKit
extension NSScreen {
static var mainFrame: CGRect {
main?.frame ?? CGRect(x: 0, y: 0, width: 1920, height: 1080)
}
static var mainFrameWidth: CGFloat {
main?.frame.width ?? 1920
}
static var mainFrameHeight: CGFloat {
main?.frame.height ?? 1080
}
}
struct DPSettings: Codable {
var dockMoves: Int
var mouseMoves: Int
var checkFullscreen: Bool
var moveMouseInstead: Bool
var mouseInsetLeading: CGFloat {
NSScreen.mainFrameWidth*insetHorizontal
}
var mouseInsetBottom: CGFloat {
NSScreen.mainFrameHeight*insetVertical
}
var mouseInsetTop: CGFloat {
NSScreen.mainFrameHeight*(1-(insetVertical))
}
var mouseInsetTrailing: CGFloat {
NSScreen.mainFrameWidth*(1-(insetHorizontal))
}
var insetHorizontal: CGFloat
var insetVertical: CGFloat
var mouseMoveRect: CGRect {
return CGRect(
x: mouseInsetLeading,
y: mouseInsetBottom,
width: mouseInsetTrailing - mouseInsetLeading,
height: mouseInsetTop - mouseInsetBottom
)
}
init(
dockMoves: Int = 0,
mouseMoves: Int = 0,
checkFullscreen: Bool = false,
moveMouseInstead: Bool = false,
insetHorizontal: CGFloat = 0.05,
insetVertical: CGFloat = 0.1
) {
self.dockMoves = dockMoves
self.mouseMoves = mouseMoves
self.checkFullscreen = checkFullscreen
self.moveMouseInstead = moveMouseInstead
self.insetHorizontal = insetHorizontal
self.insetVertical = insetVertical
}
init(from decoder: any Decoder) throws {
let defaults = DPSettings()
let container = try decoder.container(keyedBy: CodingKeys.self)
dockMoves = try container.decodeIfPresent(Int.self, forKey: .dockMoves)
?? defaults.dockMoves
mouseMoves = try container.decodeIfPresent(Int.self, forKey: .mouseMoves)
?? defaults.mouseMoves
checkFullscreen = try container.decodeIfPresent(Bool.self, forKey: .checkFullscreen)
?? defaults.checkFullscreen
moveMouseInstead = try container.decodeIfPresent(Bool.self, forKey: .moveMouseInstead)
?? defaults.moveMouseInstead
insetHorizontal = try container.decodeIfPresent(CGFloat.self, forKey: .insetHorizontal)
?? defaults.insetHorizontal
insetVertical = try container.decodeIfPresent(CGFloat.self, forKey: .insetVertical)
?? defaults.insetVertical
}
}
class DPSettingsModel {
var settings = DPSettings()
let userDefaults = UserDefaults.standard
init() {
guard let data = userDefaults.data(forKey: "settings") else { return }
let decoder = JSONDecoder()
guard let decoded = try? decoder.decode(DPSettings.self, from: data) else {
return
}
self.settings = decoded
refreshMenus()
}
func saveSettings() {
let encoder = JSONEncoder()
guard let encoded = try? encoder.encode(settings) else {
return
}
userDefaults.set(encoded, forKey: "settings")
}
}

59
DockPhobia/DockSide.swift Normal file
View File

@@ -0,0 +1,59 @@
//
// DockSide.swift
// DockPhobia
//
// Created by neon443 on 28/05/2025.
//
import Foundation
enum DockSide: Int, RawRepresentable {
case left
case bottom
case right
public typealias RawValue = String
public var rawValue: RawValue {
switch self {
case .left:
return "left"
case .right:
return "right"
case .bottom:
return "bottom"
}
}
/// Random Dock Side
/// - will return a random Dock Side when calling DockSide()
public init() {
self = DockSide(rawValue: Int.random(in: 1...3))!
}
public init?(rawValue: String) {
switch rawValue {
case "left":
self = .left
case "right":
self = .right
case "bottom":
self = .bottom
default:
return nil
}
}
public init?(rawValue: Int) {
switch rawValue {
case 1:
self = .left
case 2:
self = .bottom
case 3:
self = .right
default:
return nil
}
}
}

12
DockPhobia/Info.plist Normal file
View File

@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>SUFeedURL</key>
<string>https://neon443.github.io/appcasts/DockPhobia/appcast.xml</string>
<key>SUpublicEDKey</key>
<string>ahgIyJGs4MCQ6UXwQ11aknk3a6GwOodHKSmVv4bw6KY=</string>
<key>SUEnableAutomaticChecks</key>
<true/>
</dict>
</plist>

View File

@@ -7,128 +7,125 @@
import Foundation import Foundation
import AppKit import AppKit
import Cocoa
import ApplicationServices
extension NSEvent {
var mouseLocationCG: CGPoint {
var loc = NSEvent.mouseLocation
loc.y = NSScreen.mainFrameHeight - loc.y
return loc
}
}
extension CGPoint {
var invertedForScreen: CGPoint {
return CGPoint(
x: self.x,
y: NSScreen.mainFrameHeight - self.y
)
}
}
struct Screen { struct Screen {
var width: CGFloat var width: CGFloat
var height: CGFloat var height: CGFloat
} }
enum DockSide: Int, RawRepresentable {
case left
case bottom
case right
public typealias RawValue = String
public var rawValue: RawValue {
switch self {
case .left:
return "left"
case .right:
return "right"
case .bottom:
return "bottom"
}
}
/// Random Dock Side
/// - will return a random Dock Side when calling DockSide()
public init() {
self = DockSide(rawValue: Int.random(in: 1...3))!
}
public init?(rawValue: String) {
switch rawValue {
case "left":
self = .left
case "right":
self = .right
case "bottom":
self = .bottom
default:
return nil
}
}
public init?(rawValue: Int) {
switch rawValue {
case 1:
self = .left
case 2:
self = .bottom
case 3:
self = .right
default:
return nil
}
}
}
class MouseTracker { class MouseTracker {
var screen: Screen var screen: Screen
var monitor: Any? var monitor: Any?
var running: Bool = false var running: Bool = false
var currentDockSide: DockSide var currentDockSide: DockSide
var dockHeight: CGFloat = 0 var dockHeight: CGFloat = 0
init() { var settings: DPSettingsModel
var skyHigh: SkyHigh
private var timer: Timer?
private var loopIteration: Double = 0
init(settings: DPSettingsModel) {
print(DockSide()) print(DockSide())
if let screen = NSScreen.main {
let rect = screen.frame
self.screen = Screen( self.screen = Screen(
width: rect.width, width: NSScreen.mainFrameWidth,
height: rect.height height: NSScreen.mainFrameHeight
) )
print(self.screen) print(self.screen)
} else {
fatalError("no screen wtf???") self.settings = settings
} self.skyHigh = SkyHigh(settings: settings)
self.currentDockSide = .left self.currentDockSide = .left
moveDock(.bottom) moveDock(.bottom)
getDockSize() getDockSize()
} }
func checkMouse(_ event: NSEvent) { func checkMouse(_ event: NSEvent) {
var location = event.locationInWindow let location = event.mouseLocationCG
location.y = screen.height - location.y
#if DEBUG #if DEBUG
print(location) var cgpointForSkyHigh = NSEvent.mouseLocation
cgpointForSkyHigh.x -= 20
cgpointForSkyHigh.y -= 5
skyHigh.move(to: cgpointForSkyHigh)
#endif #endif
switch currentDockSide {
guard settings.settings.checkFullscreen else {
handleDockValue(dockIsAt: currentDockSide, location: location)
return
}
guard isFrontmostFullscreen() else {
if location.x < 1 ||
location.x < screen.width-1 ||
location.y > screen.height-1 {
handleDockValue(dockIsAt: currentDockSide, location: location)
}
return
}
}
func handleDockValue(dockIsAt: DockSide, location: NSPoint) {
switch dockIsAt {
case .left: case .left:
guard location.x < dockHeight else { return } guard location.x < dockHeight else { return }
if location.y < screen.height/2 { if location.y < screen.height/2 {
moveDock(.bottom) moveDockOrMouse(.bottom)
return return
} else { } else {
moveDock(.right) moveDockOrMouse(.right)
return return
} }
case .bottom: case .bottom:
guard location.y > screen.height - dockHeight else { return } guard location.y > screen.height - dockHeight else { return }
if location.x < screen.width/2 { if location.x < screen.width/2 {
moveDock(.right) moveDockOrMouse(.right)
return return
} else { } else {
moveDock(.left) moveDockOrMouse(.left)
return return
} }
case .right: case .right:
guard location.x > screen.width - dockHeight else { return } guard location.x > screen.width - dockHeight else { return }
if location.y < screen.height/2 { if location.y < screen.height/2 {
moveDock(.bottom) moveDockOrMouse(.bottom)
return return
} else { } else {
moveDock(.left) moveDockOrMouse(.left)
return return
} }
} }
} }
func moveDockOrMouse(_ dockTo: DockSide) {
if settings.settings.moveMouseInstead {
moveMouse()
} else {
moveDock(dockTo)
}
}
func start() { func start() {
self.monitor = NSEvent.addGlobalMonitorForEvents(matching: .mouseMoved, handler: checkMouse) self.monitor = NSEvent.addGlobalMonitorForEvents(matching: .mouseMoved, handler: checkMouse)
self.running = true self.running = true
@@ -144,6 +141,40 @@ class MouseTracker {
print("stop tracking") print("stop tracking")
} }
func moveMouse() {
let prevPoint = NSEvent().mouseLocationCG
let rangeW = settings.settings.mouseInsetLeading...settings.settings.mouseInsetTrailing
let posX = CGFloat.random(in: rangeW)
let rangeH = settings.settings.mouseInsetBottom...settings.settings.mouseInsetTop
let posY = CGFloat.random(in: rangeH)
timer?.invalidate()
loopIteration = 0
skyHigh.move(to: prevPoint.invertedForScreen)
skyHigh.show()
timer = Timer(timeInterval: 0.005, repeats: true) { [weak self] _ in
guard let self = self else { return }
guard loopIteration < 500 else {
skyHigh.hide()
settings.settings.mouseMoves += 1
refreshMenus()
timer?.invalidate()
return
}
let newPosX = (prevPoint.x > posX ? prevPoint.x-loopIteration : prevPoint.x+loopIteration)
let newPosY = (prevPoint.y > posY ? prevPoint.y-loopIteration : prevPoint.y+loopIteration)
let cgpoint = CGPoint(x: newPosX, y: newPosY)
CGWarpMouseCursorPosition(cgpoint)
var cgpointForSkyHigh = cgpoint
cgpointForSkyHigh.x -= 20
cgpointForSkyHigh.y += 5
skyHigh.move(to: cgpointForSkyHigh.invertedForScreen)
self.loopIteration += 1
}
RunLoop.main.add(timer!, forMode: .common)
}
func moveDock(_ toSide: DockSide) { func moveDock(_ toSide: DockSide) {
guard currentDockSide != toSide else { return } guard currentDockSide != toSide else { return }
// let scriptHide = """ // let scriptHide = """
@@ -167,10 +198,11 @@ class MouseTracker {
applescript(scriptMove) applescript(scriptMove)
// applescript(scriptShow) // applescript(scriptShow)
currentDockSide = toSide currentDockSide = toSide
settings.settings.dockMoves += 1
refreshMenus()
} }
func getDockSize() { func getDockSize() {
guard let screen = NSScreen.main?.frame else { fatalError() }
guard let screenVisible = NSScreen.main?.visibleFrame else { fatalError() } guard let screenVisible = NSScreen.main?.visibleFrame else { fatalError() }
self.dockHeight = screen.height - screenVisible.height self.dockHeight = screen.height - screenVisible.height
} }
@@ -187,3 +219,27 @@ class MouseTracker {
return nil return nil
} }
} }
func isFrontmostFullscreen() -> Bool {
guard let frontmostApp = NSWorkspace.shared.frontmostApplication,
let appPID = frontmostApp.processIdentifier as pid_t? else {
return false
}
let appElement = AXUIElementCreateApplication(appPID)
var frontWindo: AnyObject?
let result = AXUIElementCopyAttributeValue(appElement, kAXFocusedWindowAttribute as CFString, &frontWindo)
guard result == .success, let windowElement = frontWindo else {
return false
}
var fullscreenValue: AnyObject?
let fullscreenAttr = AXUIElementCopyAttributeValue(windowElement as! AXUIElement, "AXFullScreen" as CFString, &fullscreenValue)
if fullscreenAttr == .success,
let isFullscreen = fullscreenValue as? Bool {
return isFullscreen
}
return false
}

View File

@@ -55,7 +55,7 @@
"size" : "512x512" "size" : "512x512"
}, },
{ {
"filename" : "DockPhobiaAppIcon1024.png", "filename" : "DockPhobiaAppIcon.png",
"idiom" : "mac", "idiom" : "mac",
"scale" : "2x", "scale" : "2x",
"size" : "512x512" "size" : "512x512"

View File

Before

Width:  |  Height:  |  Size: 560 KiB

After

Width:  |  Height:  |  Size: 560 KiB

View File

@@ -0,0 +1,23 @@
{
"images" : [
{
"filename" : "pinch.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "pinch.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "pinch.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.8 KiB

54
DockPhobia/SkyHigh.swift Normal file
View File

@@ -0,0 +1,54 @@
//
// SkyHigh.swift
// DockPhobia
//
// Created by neon443 on 28/05/2025.
//
import Foundation
import Cocoa
class SkyHigh {
private var window: NSWindow
private var x = 1
private var timer: Timer?
var settings: DPSettingsModel
init(settings: DPSettingsModel) {
self.settings = settings
self.window = NSWindow(
contentRect: CGRect(
x: NSScreen.mainFrameWidth/2,
y: NSScreen.mainFrameHeight/2,
width: 100,
height: 100
),
styleMask: .borderless,
backing: .buffered,
defer: false
)
window.backgroundColor = .init(srgbRed: 1, green: 1, blue: 1, alpha: 0)
window.contentView = NSImageView(image: NSImage(named: "pinch")!)
window.isOpaque = false
window.level = NSWindow.Level.statusBar + 1
window.ignoresMouseEvents = true
window.hasShadow = true
window.collectionBehavior = NSWindow.CollectionBehavior.canJoinAllSpaces.union(.stationary)
#if DEBUG
show()
#endif
}
func move(to: CGPoint) {
self.window.setFrameOrigin(to)
}
func show() {
window.orderFront(nil)
}
func hide() {
window.orderOut(nil)
}
}

View File

@@ -414,19 +414,6 @@
</items> </items>
<point key="canvasLocation" x="200" y="121"/> <point key="canvasLocation" x="200" y="121"/>
</menu> </menu>
<menu id="ONX-cK-IuT"> <userDefaultsController representsSharedInstance="YES" id="KLo-tU-Av3"/>
<items>
<menuItem title="Item 1" id="6WY-F1-Y6A">
<modifierMask key="keyEquivalentModifierMask"/>
</menuItem>
<menuItem title="Item 2" id="Vew-Im-EWB">
<modifierMask key="keyEquivalentModifierMask"/>
</menuItem>
<menuItem title="Item 3" id="dVu-3p-SKK">
<modifierMask key="keyEquivalentModifierMask"/>
</menuItem>
</items>
<point key="canvasLocation" x="-160" y="321"/>
</menu>
</objects> </objects>
</document> </document>

View File

@@ -0,0 +1,8 @@
//
// Preferences.swift
// DockPhobia
//
// Created by neon443 on 29/05/2025.
//
import Foundation

BIN
DockPhobiaPy/.DS_Store vendored
View File

Binary file not shown.

View File

@@ -1,4 +1,26 @@
# DockPhobia <div align="center">
<br/>
<p>
<img src="https://github.com/neon443/DockPhobia/blob/main/DockPhobia/Resources/Assets.xcassets/AppIcon.appiconset/DockPhobiaAppIcon.png?raw=true" title="dockphobia" alt="dockphobia icon" width="100" />
</p>
<h3>DockPhobia</h3>
<p>
<a href="https://github.com/neon443/DockPhobia/releases/latest/download/DockPhobia.dmg">
download
<img alt="GitHub Release" src="https://img.shields.io/github/v/release/neon443/DockPhobia">
</a>
</p>
<p>
make your Dock scared of the mouse
<br/>
<a href="https://neon443.github.io">
made by neon443
</a>
</p>
<br/>
</div>
![GitHub Downloads (all assets, all releases)](https://img.shields.io/github/downloads/neon443/DockPhobia/total)
Have you ever wanted to use your Dock? Have you ever wanted to use your Dock?
well now you cant well now you cant
@@ -8,17 +30,17 @@ well now you cant
- calculates the size of your screen & Dock - calculates the size of your screen & Dock
- when your cursor is on the Dock (+ extra 5% of screen), the Dock moves to a different side of the screen - when your cursor is on the Dock (+ extra 5% of screen), the Dock moves to a different side of the screen
- it also figures out the furthest it can be, for example if your cursor is at the top left quarter of the screen and near the Dock on the left, the dock moves to the bottom as that is the furthest, etc - it also figures out the furthest it can be, for example if your cursor is at the top left quarter of the screen and near the Dock on the left, the dock moves to the bottom as that is the furthest, etc
- -
## Quick start Guide (Swift Mac App) ## Quick start Guide (Mac App)
(Currently not functional) - Go to [releases](https://github.com/neon443/DockPhobia/releases)
``` - Download the latest version
git clone https://github.com/neon443/DockPhobia - That's it!
cd DockPhobia
open DockPhobia.xcodeproj ## Contributing
``` PRs welcome, as long as you use tabs instead of spaces lol
## Quick start Guide (Python version) ## Quick start Guide (Python version)
Dont use this, still here purely for archival purposes, use the native Mac app instead.
``` ```
xcode-select --install xcode-select --install
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"