From d9c4e8bdfee646cad71c8385fe5348e085b92020 Mon Sep 17 00:00:00 2001 From: Sveinbjorn Thordarson <sveinbjorn@sveinbjorn.org> Date: Sun, 19 Nov 2023 18:20:52 +0000 Subject: [PATCH] Improvements in path control + changed default kill signal to SIGTERM, w. SIGKILL being optional via Prefs or by holding the Ctrl button --- resources/Defaults.plist | 2 ++ resources/MainMenu.xib | 3 ++ resources/Prefs.xib | 63 ++++++++++++++++++++++---------------- source/PrefsController.m | 2 ++ source/SlothController.m | 30 +++++++++++++++--- source/Util/ProcessUtils.h | 4 ++- source/Util/ProcessUtils.m | 5 +-- 7 files changed, 76 insertions(+), 33 deletions(-) diff --git a/resources/Defaults.plist b/resources/Defaults.plist index ac752ad..8eb83ce 100644 --- a/resources/Defaults.plist +++ b/resources/Defaults.plist @@ -46,5 +46,7 @@ <string>Any</string> <key>showPathBar</key> <true/> + <key>alwaysUseSigkill</key> + <false/> </dict> </plist> diff --git a/resources/MainMenu.xib b/resources/MainMenu.xib index d34d235..472b5cd 100644 --- a/resources/MainMenu.xib +++ b/resources/MainMenu.xib @@ -1049,6 +1049,9 @@ DQ <font key="font" metaFont="smallSystem"/> <url key="url" string="file://localhost/Applications/"/> </pathCell> + <connections> + <outlet property="menu" destination="3w8-wK-AmU" id="3bg-rX-0me"/> + </connections> </pathControl> <box verticalHuggingPriority="750" fixedFrame="YES" boxType="separator" translatesAutoresizingMaskIntoConstraints="NO" id="OFP-8q-4oL"> <rect key="frame" x="22" y="77" width="849" height="5"/> diff --git a/resources/Prefs.xib b/resources/Prefs.xib index 74a71f0..e802eb0 100644 --- a/resources/Prefs.xib +++ b/resources/Prefs.xib @@ -20,35 +20,24 @@ <window title="Sloth Preferences" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" restorable="NO" releasedWhenClosed="NO" visibleAtLaunch="NO" frameAutosaveName="SlothPrefs" animationBehavior="default" tabbingMode="disallowed" id="HPx-7j-YOW"> <windowStyleMask key="styleMask" titled="YES" closable="YES" miniaturizable="YES"/> <windowCollectionBehavior key="collectionBehavior" fullScreenNone="YES"/> - <rect key="contentRect" x="131" y="159" width="398" height="289"/> + <rect key="contentRect" x="131" y="159" width="398" height="316"/> <rect key="screenRect" x="0.0" y="0.0" width="1536" height="935"/> <view key="contentView" id="637-Nx-CnL"> - <rect key="frame" x="0.0" y="0.0" width="398" height="289"/> + <rect key="frame" x="0.0" y="0.0" width="398" height="316"/> <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> <subviews> - <button toolTip="Restore default preferences" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="3fT-Oj-lxR"> - <rect key="frame" x="13" y="13" width="141" height="32"/> - <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/> - <buttonCell key="cell" type="push" title="Restore Defaults" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="VbG-cb-dRB"> - <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/> - <font key="font" metaFont="system"/> - </buttonCell> - <connections> - <action selector="restoreDefaults:" target="-2" id="6Sf-Ia-Uex"/> - </connections> - </button> <tabView fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="XmJ-qI-dIi"> - <rect key="frame" x="13" y="50" width="372" height="225"/> + <rect key="frame" x="13" y="50" width="372" height="252"/> <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/> <font key="font" metaFont="system"/> <tabViewItems> <tabViewItem label="General" identifier="" id="SR9-mp-GET"> <view key="view" id="386-Tt-Q3Z"> - <rect key="frame" x="10" y="33" width="352" height="179"/> + <rect key="frame" x="10" y="33" width="352" height="206"/> <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> <subviews> <button verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="sDi-2n-kah"> - <rect key="frame" x="22" y="143" width="320" height="20"/> + <rect key="frame" x="22" y="170" width="320" height="20"/> <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/> <string key="toolTip">Perform DNS lookup for all IP addresses and port lookup for port numbers. This is slow. Don't use it. The Info Panel does DNS lookup when you double-click an IP socket item.</string> <buttonCell key="cell" type="check" title="DNS and port lookup for IP sockets (slow!)" bezelStyle="regularSquare" imagePosition="left" inset="2" id="Kkb-zj-8Vf"> @@ -60,7 +49,7 @@ </connections> </button> <button toolTip="Show current working directories for all processes." verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="QfZ-5B-OQO"> - <rect key="frame" x="22" y="82" width="320" height="25"/> + <rect key="frame" x="22" y="109" width="320" height="25"/> <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/> <buttonCell key="cell" type="check" title="Show current working directories (CWD)" bezelStyle="regularSquare" imagePosition="left" inset="2" id="vvB-Ny-MRM"> <behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/> @@ -71,7 +60,7 @@ </connections> </button> <button toolTip="Show process binary and open files in shared libaries." verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="0lg-UF-HXc"> - <rect key="frame" x="22" y="112" width="320" height="24"/> + <rect key="frame" x="22" y="139" width="320" height="24"/> <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/> <buttonCell key="cell" type="check" title="Show process binaries & shared libraries (TXT)" bezelStyle="regularSquare" imagePosition="left" inset="2" id="8Xc-bW-SGR"> <behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/> @@ -82,7 +71,7 @@ </connections> </button> <button verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="4zm-NG-tlO"> - <rect key="frame" x="22" y="47" width="320" height="35"/> + <rect key="frame" x="22" y="74" width="320" height="35"/> <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/> <string key="toolTip">Show "Mac-friendly" process names from the Carbon Process Manager (e.g. "Safari Web Content" instead of "com.apple.WebKit.WebContent")</string> <buttonCell key="cell" type="check" title="Display Mac-friendly process names" bezelStyle="regularSquare" imagePosition="left" inset="2" id="jz8-VI-cXW"> @@ -94,7 +83,7 @@ </connections> </button> <button toolTip="Prompt for authentication to run as root before launching lsof on launch." verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="duf-F0-KT3"> - <rect key="frame" x="22" y="16" width="320" height="35"/> + <rect key="frame" x="22" y="43" width="320" height="35"/> <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/> <buttonCell key="cell" type="check" title="Authenticate immediately when launched" bezelStyle="regularSquare" imagePosition="left" inset="2" id="PBX-8y-ZLU"> <behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/> @@ -104,16 +93,27 @@ <binding destination="Fml-Xt-HVp" name="value" keyPath="values.authenticateOnLaunch" id="Inw-Hr-O2O"/> </connections> </button> + <button toolTip="When killing a process, always send the SIGKILL signal rather than SIGTERM" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="G7B-Y9-PMg"> + <rect key="frame" x="22" y="12" width="320" height="35"/> + <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/> + <buttonCell key="cell" type="check" title="Always send SIGKILL instead of SIGTERM" bezelStyle="regularSquare" imagePosition="left" inset="2" id="YS2-CO-i7k"> + <behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/> + <font key="font" metaFont="system"/> + </buttonCell> + <connections> + <binding destination="Fml-Xt-HVp" name="value" keyPath="values.alwaysUseSigkill" id="6IX-JW-6eq"/> + </connections> + </button> </subviews> </view> </tabViewItem> <tabViewItem label="Filters" identifier="" id="1Qo-Dh-B48"> <view key="view" id="icB-zg-Rgl"> - <rect key="frame" x="10" y="33" width="352" height="179"/> + <rect key="frame" x="10" y="33" width="352" height="206"/> <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> <subviews> <scrollView fixedFrame="YES" autohidesScrollers="YES" horizontalLineScroll="25" horizontalPageScroll="10" verticalLineScroll="25" verticalPageScroll="10" usesPredominantAxisScrolling="NO" translatesAutoresizingMaskIntoConstraints="NO" id="LNp-SY-fXz"> - <rect key="frame" x="17" y="39" width="318" height="137"/> + <rect key="frame" x="17" y="66" width="318" height="137"/> <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/> <clipView key="contentView" id="f5c-N0-0X2"> <rect key="frame" x="1" y="1" width="316" height="135"/> @@ -168,7 +168,7 @@ </scroller> </scrollView> <button toolTip="Add Filter" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="ET3-sC-3hU"> - <rect key="frame" x="312" y="13" width="22" height="24"/> + <rect key="frame" x="312" y="40" width="22" height="24"/> <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/> <buttonCell key="cell" type="smallSquare" bezelStyle="smallSquare" image="NSAddTemplate" imagePosition="overlaps" alignment="center" lineBreakMode="truncatingTail" state="on" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="fZb-mD-JAt"> <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/> @@ -180,7 +180,7 @@ </connections> </button> <button toolTip="Delete Selected Filter" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="RK3-7C-553"> - <rect key="frame" x="290" y="13" width="22" height="24"/> + <rect key="frame" x="290" y="40" width="22" height="24"/> <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/> <buttonCell key="cell" type="smallSquare" bezelStyle="smallSquare" image="NSRemoveTemplate" imagePosition="overlaps" alignment="center" lineBreakMode="truncatingTail" state="on" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="qjy-uK-oYA"> <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/> @@ -194,7 +194,7 @@ CA </connections> </button> <textField focusRingType="none" horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="d1O-Cm-meW"> - <rect key="frame" x="17" y="17" width="182" height="14"/> + <rect key="frame" x="17" y="44" width="182" height="14"/> <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/> <textFieldCell key="cell" controlSize="small" lineBreakMode="clipping" title="Supports regular expressions" id="s3j-6l-ysb"> <font key="font" metaFont="smallSystem"/> @@ -207,6 +207,17 @@ CA </tabViewItem> </tabViewItems> </tabView> + <button toolTip="Restore default preferences" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="3fT-Oj-lxR"> + <rect key="frame" x="13" y="13" width="141" height="32"/> + <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/> + <buttonCell key="cell" type="push" title="Restore Defaults" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="VbG-cb-dRB"> + <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/> + <font key="font" metaFont="system"/> + </buttonCell> + <connections> + <action selector="restoreDefaults:" target="-2" id="6Sf-Ia-Uex"/> + </connections> + </button> <button toolTip="Save and apply preferences" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="85E-cu-yPP"> <rect key="frame" x="292" y="13" width="93" height="32"/> <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/> @@ -226,7 +237,7 @@ DQ <connections> <outlet property="delegate" destination="-2" id="c9m-jL-0FT"/> </connections> - <point key="canvasLocation" x="-292" y="-730.5"/> + <point key="canvasLocation" x="-292" y="-717"/> </window> <userDefaultsController representsSharedInstance="YES" id="Fml-Xt-HVp"/> </objects> diff --git a/source/PrefsController.m b/source/PrefsController.m index f78641c..05c90b9 100644 --- a/source/PrefsController.m +++ b/source/PrefsController.m @@ -84,6 +84,8 @@ - (IBAction)restoreDefaults:(id)sender { [DEFAULTS setBool:NO forKey:@"showCurrentWorkingDirectories"]; [DEFAULTS setBool:YES forKey:@"friendlyProcessNames"]; [DEFAULTS setBool:NO forKey:@"authenticateOnLaunch"]; + [DEFAULTS setBool:NO forKey:@"alwaysUseSigkill"]; + [DEFAULTS setObject:@[@[@NO, DEFAULT_FILTER]] forKey:@"filters"]; [DEFAULTS synchronize]; diff --git a/source/SlothController.m b/source/SlothController.m index cb0dd5b..1f1eb2b 100644 --- a/source/SlothController.m +++ b/source/SlothController.m @@ -647,17 +647,23 @@ - (IBAction)kill:(id)sender { // Confirm BOOL optionKeyDown = (([[NSApp currentEvent] modifierFlags] & NSAlternateKeyMask) == NSAlternateKeyMask); + BOOL ctrlKeyDown = (([[NSApp currentEvent] modifierFlags] & NSControlKeyMask) == NSControlKeyMask); + BOOL useSigKill = (ctrlKeyDown || [DEFAULTS boolForKey:@"alwaysUseSigkill"]); if (optionKeyDown == NO) { - if ([Alerts proceedAlert:[NSString stringWithFormat:@"Are you sure you want to kill “%@” (%d)?", item[@"pname"], pid] - subText:@"This will send the process a SIGKILL signal. Hold the option key (⌥) to avoid this prompt." - withActionNamed:@"Kill"] == NO) { + NSString *p = [NSString stringWithFormat:@"Are you sure you want to kill “%@” (%d)?", item[@"pname"], pid]; + NSString *s = @"This will send the process a SIGTERM signal. Hold the down option key (⌥) to avoid this prompt. Hold down the Control key if you want to send a SIGKILL signal."; + if (useSigKill) { + s = @"This will send the process a SIGKILL signal. Hold the down option key (⌥) to avoid this prompt."; + } + if ([Alerts proceedAlert:p subText:s withActionNamed:@"Kill"] == NO) { return; } } // Kill it BOOL ownsProcess = [ProcessUtils isProcessOwnedByCurrentUser:pid]; - if ([ProcessUtils killProcess:pid asRoot:!ownsProcess] == NO) { + BOOL killSuccess = [ProcessUtils killProcess:pid asRoot:!ownsProcess usingSIGKILL:useSigKill]; + if (killSuccess == NO) { [Alerts alert:@"Failed to kill process" subTextFormat:@"Could not kill process %@ (PID: %d)", item[@"pname"], pid]; return; @@ -1100,6 +1106,22 @@ - (void)showPathControl { [v setFrame:r]; } +- (BOOL)pathControl:(NSPathControl *)pathControl shouldDragItem:(NSPathControlItem *)pathItem withPasteboard:(NSPasteboard *)pboard { + NSString *draggedFile = [[pathItem URL] path]; + [self copyFiles:@[draggedFile] toPasteboard:pboard]; + return YES; +} + +- (void)copyFiles:(NSArray *)files toPasteboard:(NSPasteboard *)pboard { + [pboard clearContents]; + [pboard declareTypes:@[NSFilenamesPboardType] owner:nil]; + [pboard setPropertyList:files forType:NSFilenamesPboardType]; + + NSString *strRep = [files componentsJoinedByString:@"\n"]; + [pboard setString:strRep forType:NSStringPboardType]; +} + + #pragma mark - Menus - (void)menuWillOpen:(NSMenu *)menu { diff --git a/source/Util/ProcessUtils.h b/source/Util/ProcessUtils.h index 4e70de1..2f39dd3 100644 --- a/source/Util/ProcessUtils.h +++ b/source/Util/ProcessUtils.h @@ -44,6 +44,8 @@ + (NSString *)procNameForPID:(pid_t)pid; + (NSString *)fullKernelProcessNameForPID:(pid_t)pid; + (NSString *)executablePathForPID:(pid_t)pid; -+ (BOOL)killProcess:(int)pid asRoot:(BOOL)asRoot; ++ (BOOL)killProcess:(int)pid + asRoot:(BOOL)asRoot + usingSIGKILL:(BOOL)useSigkill; @end diff --git a/source/Util/ProcessUtils.m b/source/Util/ProcessUtils.m index 6c86a2b..378b202 100644 --- a/source/Util/ProcessUtils.m +++ b/source/Util/ProcessUtils.m @@ -208,9 +208,10 @@ + (NSString *)executablePathForPID:(pid_t)pid { return path; } -+ (BOOL)killProcess:(int)pid asRoot:(BOOL)asRoot { ++ (BOOL)killProcess:(int)pid asRoot:(BOOL)asRoot usingSIGKILL:(BOOL)useSigkill { + int signal = useSigkill ? SIGKILL : SIGTERM; if (!asRoot) { - return (kill(pid, SIGKILL) == 0); + return (kill(pid, signal) == 0); } // Kill process as root