improved actions, update logic, and uninstaller
Actions now populated by browse pane (ensures path/item is valid) Update logic now supports OS checking (min supported OS version) Uninstaller resets/removes preferences file
This commit is contained in:
parent
58c78d24c6
commit
aefbf06fd3
|
@ -371,21 +371,28 @@ bail:
|
||||||
switch (result)
|
switch (result)
|
||||||
{
|
{
|
||||||
//error
|
//error
|
||||||
case -1:
|
case Update_Error:
|
||||||
|
|
||||||
//err msg
|
//err msg
|
||||||
os_log_error(logHandle, "ERROR: update check failed");
|
os_log_error(logHandle, "ERROR: update check failed");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
//no updates
|
//no updates
|
||||||
case 0:
|
case Update_None:
|
||||||
|
|
||||||
//dbg msg
|
//dbg msg
|
||||||
os_log_debug(logHandle, "no updates available");
|
os_log_debug(logHandle, "no updates available");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
//this version of macOS, not supported
|
||||||
|
case Update_NotSupported:
|
||||||
|
|
||||||
|
//dbg msg
|
||||||
|
os_log_debug(logHandle, "update available, but not for this version of macOS");
|
||||||
|
break;
|
||||||
|
|
||||||
//new version
|
//new version
|
||||||
case 1:
|
case Update_Available:
|
||||||
|
|
||||||
//dbg msg
|
//dbg msg
|
||||||
os_log_debug(logHandle, "a new version (%@) is available", newVersion);
|
os_log_debug(logHandle, "a new version (%@) is available", newVersion);
|
||||||
|
|
|
@ -1,14 +1,15 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="18122" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
|
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="21225" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<deployment identifier="macosx"/>
|
<deployment identifier="macosx"/>
|
||||||
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="18122"/>
|
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="21225"/>
|
||||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
<objects>
|
<objects>
|
||||||
<customObject id="-2" userLabel="File's Owner" customClass="PrefsWindowController">
|
<customObject id="-2" userLabel="File's Owner" customClass="PrefsWindowController">
|
||||||
<connections>
|
<connections>
|
||||||
<outlet property="actionView" destination="Jpg-nC-dWd" id="WHf-rQ-BXU"/>
|
<outlet property="actionView" destination="Jpg-nC-dWd" id="WHf-rQ-BXU"/>
|
||||||
|
<outlet property="browseButton" destination="gVP-Ih-dFA" id="j7F-V3-hEq"/>
|
||||||
<outlet property="executeArgsButton" destination="YqA-7j-gYp" id="tbC-AW-etO"/>
|
<outlet property="executeArgsButton" destination="YqA-7j-gYp" id="tbC-AW-etO"/>
|
||||||
<outlet property="executePath" destination="z32-0s-dpb" id="HAL-Mg-ygB"/>
|
<outlet property="executePath" destination="z32-0s-dpb" id="HAL-Mg-ygB"/>
|
||||||
<outlet property="modesView" destination="K6i-xr-27e" id="DOb-L3-eeR"/>
|
<outlet property="modesView" destination="K6i-xr-27e" id="DOb-L3-eeR"/>
|
||||||
|
@ -25,7 +26,7 @@
|
||||||
<window title="Window" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" releasedWhenClosed="NO" animationBehavior="default" id="F0z-JX-Cv5">
|
<window title="Window" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" releasedWhenClosed="NO" animationBehavior="default" id="F0z-JX-Cv5">
|
||||||
<windowStyleMask key="styleMask" titled="YES" closable="YES" miniaturizable="YES"/>
|
<windowStyleMask key="styleMask" titled="YES" closable="YES" miniaturizable="YES"/>
|
||||||
<rect key="contentRect" x="196" y="240" width="600" height="365"/>
|
<rect key="contentRect" x="196" y="240" width="600" height="365"/>
|
||||||
<rect key="screenRect" x="0.0" y="0.0" width="1440" height="875"/>
|
<rect key="screenRect" x="0.0" y="0.0" width="3440" height="1415"/>
|
||||||
<view key="contentView" wantsLayer="YES" id="se5-gp-TjO">
|
<view key="contentView" wantsLayer="YES" id="se5-gp-TjO">
|
||||||
<rect key="frame" x="0.0" y="0.0" width="600" height="365"/>
|
<rect key="frame" x="0.0" y="0.0" width="600" height="365"/>
|
||||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||||
|
@ -41,21 +42,21 @@
|
||||||
<allowedToolbarItems>
|
<allowedToolbarItems>
|
||||||
<toolbarItem implicitItemIdentifier="NSToolbarSpaceItem" id="J66-tT-qAf"/>
|
<toolbarItem implicitItemIdentifier="NSToolbarSpaceItem" id="J66-tT-qAf"/>
|
||||||
<toolbarItem implicitItemIdentifier="NSToolbarFlexibleSpaceItem" id="6nW-4K-zf4"/>
|
<toolbarItem implicitItemIdentifier="NSToolbarFlexibleSpaceItem" id="6nW-4K-zf4"/>
|
||||||
<toolbarItem implicitItemIdentifier="3F78D487-BA4D-4E1B-8FC6-A844D292C69B" explicitItemIdentifier="mode" label="mode" paletteLabel="mode" image="PrefsMode" selectable="YES" id="k0w-Oi-kwd" userLabel="mode">
|
<toolbarItem implicitItemIdentifier="3F78D487-BA4D-4E1B-8FC6-A844D292C69B" explicitItemIdentifier="mode" label="Mode" paletteLabel="Mode" image="PrefsMode" selectable="YES" id="k0w-Oi-kwd" userLabel="mode">
|
||||||
<size key="minSize" width="22" height="22"/>
|
<size key="minSize" width="22" height="22"/>
|
||||||
<size key="maxSize" width="22" height="22"/>
|
<size key="maxSize" width="22" height="22"/>
|
||||||
<connections>
|
<connections>
|
||||||
<action selector="toolbarButtonHandler:" target="-2" id="5Bh-RO-nSN"/>
|
<action selector="toolbarButtonHandler:" target="-2" id="5Bh-RO-nSN"/>
|
||||||
</connections>
|
</connections>
|
||||||
</toolbarItem>
|
</toolbarItem>
|
||||||
<toolbarItem implicitItemIdentifier="F54FFA8D-5F3A-4A92-BCB5-F0200A133E49" explicitItemIdentifier="action" label="action" paletteLabel="action" tag="1" image="PrefsAction" selectable="YES" id="gji-hP-t04">
|
<toolbarItem implicitItemIdentifier="F54FFA8D-5F3A-4A92-BCB5-F0200A133E49" explicitItemIdentifier="action" label="Action" paletteLabel="Action" tag="1" image="PrefsAction" selectable="YES" id="gji-hP-t04">
|
||||||
<size key="minSize" width="22" height="22"/>
|
<size key="minSize" width="22" height="22"/>
|
||||||
<size key="maxSize" width="22" height="22"/>
|
<size key="maxSize" width="22" height="22"/>
|
||||||
<connections>
|
<connections>
|
||||||
<action selector="toolbarButtonHandler:" target="-2" id="c6F-yA-Qd8"/>
|
<action selector="toolbarButtonHandler:" target="-2" id="c6F-yA-Qd8"/>
|
||||||
</connections>
|
</connections>
|
||||||
</toolbarItem>
|
</toolbarItem>
|
||||||
<toolbarItem implicitItemIdentifier="384D69C6-2351-417E-9C93-B14039FE440F" explicitItemIdentifier="update" label="update" paletteLabel="update" tag="2" image="PrefsUpdate" selectable="YES" id="rrF-xj-cXp">
|
<toolbarItem implicitItemIdentifier="384D69C6-2351-417E-9C93-B14039FE440F" explicitItemIdentifier="update" label="Update" paletteLabel="Update" tag="2" image="PrefsUpdate" selectable="YES" id="rrF-xj-cXp">
|
||||||
<size key="minSize" width="22" height="22"/>
|
<size key="minSize" width="22" height="22"/>
|
||||||
<size key="maxSize" width="22" height="22"/>
|
<size key="maxSize" width="22" height="22"/>
|
||||||
<connections>
|
<connections>
|
||||||
|
@ -197,25 +198,16 @@
|
||||||
</connections>
|
</connections>
|
||||||
</button>
|
</button>
|
||||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" preferredMaxLayoutWidth="117" translatesAutoresizingMaskIntoConstraints="NO" id="8Tb-Ih-SsC">
|
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" preferredMaxLayoutWidth="117" translatesAutoresizingMaskIntoConstraints="NO" id="8Tb-Ih-SsC">
|
||||||
<rect key="frame" x="72" y="224" width="114" height="15"/>
|
<rect key="frame" x="72" y="224" width="59" height="15"/>
|
||||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||||
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="Execute Action" id="ncJ-bF-dAA">
|
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="Execute" id="ncJ-bF-dAA">
|
||||||
<font key="font" size="13" name="Menlo-Bold"/>
|
<font key="font" size="13" name="Menlo-Bold"/>
|
||||||
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
|
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
|
||||||
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
|
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
|
||||||
</textFieldCell>
|
</textFieldCell>
|
||||||
</textField>
|
</textField>
|
||||||
<textField verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" fixedFrame="YES" allowsCharacterPickerTouchBarItem="YES" preferredMaxLayoutWidth="471" translatesAutoresizingMaskIntoConstraints="NO" id="GyI-og-F35">
|
|
||||||
<rect key="frame" x="72" y="202" width="318" height="15"/>
|
|
||||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
|
||||||
<textFieldCell key="cell" sendsActionOnEndEditing="YES" title="Perform an action (script, binary, etc)." id="bky-MW-yBn">
|
|
||||||
<font key="font" size="13" name="Menlo-Regular"/>
|
|
||||||
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
|
|
||||||
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
|
|
||||||
</textFieldCell>
|
|
||||||
</textField>
|
|
||||||
<button fixedFrame="YES" tag="5" translatesAutoresizingMaskIntoConstraints="NO" id="YqA-7j-gYp">
|
<button fixedFrame="YES" tag="5" translatesAutoresizingMaskIntoConstraints="NO" id="YqA-7j-gYp">
|
||||||
<rect key="frame" x="39" y="161" width="29" height="18"/>
|
<rect key="frame" x="39" y="151" width="29" height="18"/>
|
||||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||||
<buttonCell key="cell" type="check" bezelStyle="regularSquare" imagePosition="left" alignment="left" inset="2" id="egX-c0-Flf">
|
<buttonCell key="cell" type="check" bezelStyle="regularSquare" imagePosition="left" alignment="left" inset="2" id="egX-c0-Flf">
|
||||||
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
|
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
|
||||||
|
@ -226,7 +218,7 @@
|
||||||
</connections>
|
</connections>
|
||||||
</button>
|
</button>
|
||||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="dH0-Xi-Qnd">
|
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="dH0-Xi-Qnd">
|
||||||
<rect key="frame" x="72" y="162" width="114" height="15"/>
|
<rect key="frame" x="72" y="152" width="114" height="15"/>
|
||||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||||
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="Pass Arguments" id="WL4-fV-4Wq">
|
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="Pass Arguments" id="WL4-fV-4Wq">
|
||||||
<font key="font" size="13" name="Menlo-Bold"/>
|
<font key="font" size="13" name="Menlo-Bold"/>
|
||||||
|
@ -235,7 +227,7 @@
|
||||||
</textFieldCell>
|
</textFieldCell>
|
||||||
</textField>
|
</textField>
|
||||||
<textField verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" fixedFrame="YES" allowsCharacterPickerTouchBarItem="YES" preferredMaxLayoutWidth="471" translatesAutoresizingMaskIntoConstraints="NO" id="GP0-UX-66J">
|
<textField verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" fixedFrame="YES" allowsCharacterPickerTouchBarItem="YES" preferredMaxLayoutWidth="471" translatesAutoresizingMaskIntoConstraints="NO" id="GP0-UX-66J">
|
||||||
<rect key="frame" x="72" y="98" width="427" height="60"/>
|
<rect key="frame" x="72" y="82" width="427" height="60"/>
|
||||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||||
<textFieldCell key="cell" sendsActionOnEndEditing="YES" id="7Ah-kZ-gGe">
|
<textFieldCell key="cell" sendsActionOnEndEditing="YES" id="7Ah-kZ-gGe">
|
||||||
<font key="font" size="13" name="Menlo-Regular"/>
|
<font key="font" size="13" name="Menlo-Regular"/>
|
||||||
|
@ -245,9 +237,9 @@
|
||||||
</textFieldCell>
|
</textFieldCell>
|
||||||
</textField>
|
</textField>
|
||||||
<textField verticalHuggingPriority="750" fixedFrame="YES" preferredMaxLayoutWidth="382" translatesAutoresizingMaskIntoConstraints="NO" id="z32-0s-dpb">
|
<textField verticalHuggingPriority="750" fixedFrame="YES" preferredMaxLayoutWidth="382" translatesAutoresizingMaskIntoConstraints="NO" id="z32-0s-dpb">
|
||||||
<rect key="frame" x="198" y="221" width="382" height="20"/>
|
<rect key="frame" x="143" y="221" width="437" height="20"/>
|
||||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||||
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" state="on" borderStyle="bezel" placeholderString="path" drawsBackground="YES" id="Oe0-3Y-Srk">
|
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" allowsUndo="NO" state="on" borderStyle="bezel" placeholderString="path" drawsBackground="YES" id="Oe0-3Y-Srk">
|
||||||
<font key="font" size="13" name="Menlo-Regular"/>
|
<font key="font" size="13" name="Menlo-Regular"/>
|
||||||
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
|
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
|
||||||
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||||
|
@ -256,7 +248,35 @@
|
||||||
<outlet property="delegate" destination="-2" id="dSg-PZ-Igl"/>
|
<outlet property="delegate" destination="-2" id="dSg-PZ-Igl"/>
|
||||||
</connections>
|
</connections>
|
||||||
</textField>
|
</textField>
|
||||||
|
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="gVP-Ih-dFA">
|
||||||
|
<rect key="frame" x="498" y="187" width="89" height="33"/>
|
||||||
|
<constraints>
|
||||||
|
<constraint firstAttribute="width" constant="75" id="0GJ-HY-4cb"/>
|
||||||
|
<constraint firstAttribute="height" constant="21" id="J0H-v3-Re0"/>
|
||||||
|
</constraints>
|
||||||
|
<buttonCell key="cell" type="push" title="Browse" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="BTl-QV-9GT">
|
||||||
|
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
|
||||||
|
<font key="font" size="13" name="Menlo-Regular"/>
|
||||||
|
</buttonCell>
|
||||||
|
<connections>
|
||||||
|
<action selector="browseButtonHandler:" target="-2" id="gXE-0h-DRz"/>
|
||||||
|
</connections>
|
||||||
|
</button>
|
||||||
|
<textField verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" fixedFrame="YES" allowsCharacterPickerTouchBarItem="YES" preferredMaxLayoutWidth="471" translatesAutoresizingMaskIntoConstraints="NO" id="GyI-og-F35">
|
||||||
|
<rect key="frame" x="72" y="181" width="427" height="30"/>
|
||||||
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||||
|
<textFieldCell key="cell" sendsActionOnEndEditing="YES" title="Execute a script or binary when an event is detected." id="bky-MW-yBn">
|
||||||
|
<font key="font" size="13" name="Menlo-Regular"/>
|
||||||
|
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
|
||||||
|
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
|
||||||
|
</textFieldCell>
|
||||||
|
</textField>
|
||||||
</subviews>
|
</subviews>
|
||||||
|
<constraints>
|
||||||
|
<constraint firstAttribute="trailing" secondItem="gVP-Ih-dFA" secondAttribute="trailing" constant="20" symbolic="YES" id="CvO-h8-LQr"/>
|
||||||
|
<constraint firstItem="gVP-Ih-dFA" firstAttribute="top" secondItem="Jpg-nC-dWd" secondAttribute="top" constant="60" id="nxN-h0-hTd"/>
|
||||||
|
<constraint firstAttribute="trailing" secondItem="gVP-Ih-dFA" secondAttribute="trailing" constant="20" symbolic="YES" id="wdb-4c-5GF"/>
|
||||||
|
</constraints>
|
||||||
<point key="canvasLocation" x="-166" y="738.5"/>
|
<point key="canvasLocation" x="-166" y="738.5"/>
|
||||||
</customView>
|
</customView>
|
||||||
<customView id="1OV-sl-cSe" userLabel="Update">
|
<customView id="1OV-sl-cSe" userLabel="Update">
|
||||||
|
@ -303,21 +323,21 @@
|
||||||
<action selector="check4Update:" target="-2" id="GJb-mB-UIz"/>
|
<action selector="check4Update:" target="-2" id="GJb-mB-UIz"/>
|
||||||
</connections>
|
</connections>
|
||||||
</button>
|
</button>
|
||||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Oe2-Ye-1s6">
|
<progressIndicator wantsLayer="YES" horizontalHuggingPriority="750" verticalHuggingPriority="750" fixedFrame="YES" maxValue="100" displayedWhenStopped="NO" bezeled="NO" indeterminate="YES" controlSize="small" style="spinning" translatesAutoresizingMaskIntoConstraints="NO" id="o0T-ra-4H0">
|
||||||
<rect key="frame" x="201" y="101" width="216" height="34"/>
|
<rect key="frame" x="378" y="145" width="16" height="16"/>
|
||||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||||
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="center" id="5gt-xh-Ti5">
|
</progressIndicator>
|
||||||
|
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Oe2-Ye-1s6">
|
||||||
|
<rect key="frame" x="118" y="60" width="383" height="74"/>
|
||||||
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||||
|
<textFieldCell key="cell" sendsActionOnEndEditing="YES" alignment="center" id="5gt-xh-Ti5">
|
||||||
<font key="font" size="13" name="Menlo-Bold"/>
|
<font key="font" size="13" name="Menlo-Bold"/>
|
||||||
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
|
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
|
||||||
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
|
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
|
||||||
</textFieldCell>
|
</textFieldCell>
|
||||||
</textField>
|
</textField>
|
||||||
<progressIndicator wantsLayer="YES" horizontalHuggingPriority="750" verticalHuggingPriority="750" fixedFrame="YES" maxValue="100" displayedWhenStopped="NO" bezeled="NO" indeterminate="YES" controlSize="small" style="spinning" translatesAutoresizingMaskIntoConstraints="NO" id="o0T-ra-4H0">
|
|
||||||
<rect key="frame" x="378" y="145" width="16" height="16"/>
|
|
||||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
|
||||||
</progressIndicator>
|
|
||||||
</subviews>
|
</subviews>
|
||||||
<point key="canvasLocation" x="694" y="709"/>
|
<point key="canvasLocation" x="694" y="708.5"/>
|
||||||
</customView>
|
</customView>
|
||||||
</objects>
|
</objects>
|
||||||
<resources>
|
<resources>
|
||||||
|
|
|
@ -47,6 +47,9 @@
|
||||||
//path to action
|
//path to action
|
||||||
@property (weak) IBOutlet NSTextField *executePath;
|
@property (weak) IBOutlet NSTextField *executePath;
|
||||||
|
|
||||||
|
//browse button
|
||||||
|
@property (weak) IBOutlet NSButton *browseButton;
|
||||||
|
|
||||||
//execute args button
|
//execute args button
|
||||||
@property (weak) IBOutlet NSButton *executeArgsButton;
|
@property (weak) IBOutlet NSButton *executeArgsButton;
|
||||||
|
|
||||||
|
|
|
@ -97,9 +97,9 @@ extern os_log_t logHandle;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
//modes
|
//actions
|
||||||
case TOOLBAR_ACTION:
|
case TOOLBAR_ACTION:
|
||||||
|
{
|
||||||
//set view
|
//set view
|
||||||
view = self.actionView;
|
view = self.actionView;
|
||||||
|
|
||||||
|
@ -122,8 +122,18 @@ extern os_log_t logHandle;
|
||||||
//set state of 'execute action' to match
|
//set state of 'execute action' to match
|
||||||
self.executeArgsButton.enabled = [NSUserDefaults.standardUserDefaults boolForKey:PREF_EXECUTE_ACTION];
|
self.executeArgsButton.enabled = [NSUserDefaults.standardUserDefaults boolForKey:PREF_EXECUTE_ACTION];
|
||||||
|
|
||||||
break;
|
//make 'Browse' button first responder
|
||||||
|
// calling this without a timeout, sometimes fails :/
|
||||||
|
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (100 * NSEC_PER_MSEC)), dispatch_get_main_queue(),
|
||||||
|
^{
|
||||||
|
|
||||||
|
//set first responder
|
||||||
|
[self.window makeFirstResponder:self.browseButton];
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
//update
|
//update
|
||||||
case TOOLBAR_UPDATE:
|
case TOOLBAR_UPDATE:
|
||||||
|
@ -153,26 +163,6 @@ bail:
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//automatically called when 'enter' is hit
|
|
||||||
// save values that were entered in text field
|
|
||||||
-(void)controlTextDidEndEditing:(NSNotification *)notification
|
|
||||||
{
|
|
||||||
//execute path?
|
|
||||||
if([notification object] != self.executePath)
|
|
||||||
{
|
|
||||||
//bail
|
|
||||||
goto bail;
|
|
||||||
}
|
|
||||||
|
|
||||||
//save & sync
|
|
||||||
[NSUserDefaults.standardUserDefaults setObject:self.executePath.stringValue forKey:PREF_EXECUTE_PATH];
|
|
||||||
[NSUserDefaults.standardUserDefaults synchronize];
|
|
||||||
|
|
||||||
bail:
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
//invoked when user toggles button
|
//invoked when user toggles button
|
||||||
// update preferences for that button
|
// update preferences for that button
|
||||||
-(IBAction)togglePreference:(id)sender
|
-(IBAction)togglePreference:(id)sender
|
||||||
|
@ -237,6 +227,15 @@ bail:
|
||||||
//set path field state to match
|
//set path field state to match
|
||||||
self.executeArgsButton.enabled = state;
|
self.executeArgsButton.enabled = state;
|
||||||
|
|
||||||
|
//enabled, but no path?
|
||||||
|
// launch 'browse' pane for user to select
|
||||||
|
if( (NSControlStateValueOn == state) &&
|
||||||
|
(0 == self.executePath.stringValue.length) )
|
||||||
|
{
|
||||||
|
//show 'browse'
|
||||||
|
[self browseButtonHandler:nil];
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -277,6 +276,7 @@ bail:
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//TODO: supported OS
|
||||||
//'check for update' button handler
|
//'check for update' button handler
|
||||||
-(IBAction)check4Update:(id)sender
|
-(IBAction)check4Update:(id)sender
|
||||||
{
|
{
|
||||||
|
@ -308,7 +308,7 @@ bail:
|
||||||
}
|
}
|
||||||
|
|
||||||
//process update response
|
//process update response
|
||||||
// error, no update, update/new version
|
// error, no update, update not compatible, update/new version
|
||||||
-(void)updateResponse:(NSInteger)result newVersion:(NSString*)newVersion
|
-(void)updateResponse:(NSInteger)result newVersion:(NSString*)newVersion
|
||||||
{
|
{
|
||||||
//re-enable button
|
//re-enable button
|
||||||
|
@ -320,15 +320,15 @@ bail:
|
||||||
switch(result)
|
switch(result)
|
||||||
{
|
{
|
||||||
//error
|
//error
|
||||||
case -1:
|
case Update_Error:
|
||||||
|
|
||||||
//set label
|
//set label
|
||||||
self.updateLabel.stringValue = @"error: update check failed";
|
self.updateLabel.stringValue = @"Error: update check failed";
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
//no updates
|
//no updates
|
||||||
case 0:
|
case Update_None:
|
||||||
|
|
||||||
//dbg msg
|
//dbg msg
|
||||||
os_log_debug(logHandle, "no updates available");
|
os_log_debug(logHandle, "no updates available");
|
||||||
|
@ -338,9 +338,19 @@ bail:
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
//this version of macOS, not supported
|
||||||
|
case Update_NotSupported:
|
||||||
|
|
||||||
|
//dbg msg
|
||||||
|
os_log_debug(logHandle, "update available, but not for this version of macOS");
|
||||||
|
|
||||||
|
//set label
|
||||||
|
self.updateLabel.stringValue = [NSString stringWithFormat:@"Update available, but isn't supported on macOS %ld.%ld", NSProcessInfo.processInfo.operatingSystemVersion.majorVersion, NSProcessInfo.processInfo.operatingSystemVersion.minorVersion];
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
//new version
|
//new version
|
||||||
case 1:
|
case Update_Available:
|
||||||
|
|
||||||
//dbg msg
|
//dbg msg
|
||||||
os_log_debug(logHandle, "a new version (%@) is available", newVersion);
|
os_log_debug(logHandle, "a new version (%@) is available", newVersion);
|
||||||
|
@ -391,4 +401,54 @@ bail:
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//'browse' button handler
|
||||||
|
// open a panel for user to select file
|
||||||
|
-(IBAction)browseButtonHandler:(id)sender
|
||||||
|
{
|
||||||
|
//'browse' panel
|
||||||
|
NSOpenPanel *panel = nil;
|
||||||
|
|
||||||
|
//response to 'browse' panel
|
||||||
|
NSInteger response = 0;
|
||||||
|
|
||||||
|
//init panel
|
||||||
|
panel = [NSOpenPanel openPanel];
|
||||||
|
|
||||||
|
//allow files
|
||||||
|
panel.canChooseFiles = YES;
|
||||||
|
|
||||||
|
//don't allow directories
|
||||||
|
panel.canChooseDirectories = NO;
|
||||||
|
|
||||||
|
//disable multiple selections
|
||||||
|
panel.allowsMultipleSelection = NO;
|
||||||
|
|
||||||
|
//can open app bundles
|
||||||
|
panel.treatsFilePackagesAsDirectories = YES;
|
||||||
|
|
||||||
|
//start in user's home directory
|
||||||
|
panel.directoryURL = [NSURL fileURLWithPath:NSHomeDirectory()];
|
||||||
|
|
||||||
|
//show it
|
||||||
|
response = [panel runModal];
|
||||||
|
|
||||||
|
//ignore cancel
|
||||||
|
if(NSModalResponseCancel == response)
|
||||||
|
{
|
||||||
|
//bail
|
||||||
|
goto bail;
|
||||||
|
}
|
||||||
|
|
||||||
|
//set path in ui
|
||||||
|
self.executePath.stringValue = panel.URL.path;
|
||||||
|
|
||||||
|
//save path & sync
|
||||||
|
[NSUserDefaults.standardUserDefaults setObject:self.executePath.stringValue forKey:PREF_EXECUTE_PATH];
|
||||||
|
[NSUserDefaults.standardUserDefaults synchronize];
|
||||||
|
|
||||||
|
bail:
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
|
@ -25,25 +25,66 @@ extern os_log_t logHandle;
|
||||||
// ->will invoke app delegate method to update UI when check completes
|
// ->will invoke app delegate method to update UI when check completes
|
||||||
-(void)checkForUpdate:(void (^)(NSUInteger result, NSString* latestVersion))completionHandler
|
-(void)checkForUpdate:(void (^)(NSUInteger result, NSString* latestVersion))completionHandler
|
||||||
{
|
{
|
||||||
//latest version
|
//info
|
||||||
__block NSString* latestVersion = nil;
|
__block NSDictionary* productInfo = nil;
|
||||||
|
|
||||||
//result
|
//result
|
||||||
__block NSInteger result = -1;
|
__block NSInteger result = Update_None;
|
||||||
|
|
||||||
//get latest version in background
|
//get latest version in background
|
||||||
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
|
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
|
||||||
|
|
||||||
//grab latest version
|
//latest version
|
||||||
latestVersion = [self getLatestVersion];
|
NSString* latestVersion = nil;
|
||||||
if(nil != latestVersion)
|
|
||||||
|
//supported OS
|
||||||
|
NSOperatingSystemVersion supportedOS = {0};
|
||||||
|
|
||||||
|
//get product info
|
||||||
|
productInfo = [self getProductInfo:PRODUCT_NAME];
|
||||||
|
if(nil == productInfo)
|
||||||
{
|
{
|
||||||
//check
|
//err msg
|
||||||
result = (NSOrderedAscending == [getAppVersion() compare:latestVersion options:NSNumericSearch]);
|
os_log_error(logHandle, "ERROR: failed retrieve product info (for update check) from %{public}@", PRODUCT_VERSIONS_URL);
|
||||||
|
|
||||||
|
//error
|
||||||
|
result = Update_Error;
|
||||||
|
}
|
||||||
|
//got remote product info
|
||||||
|
// check supported OS and latest version
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//init supported OS
|
||||||
|
supportedOS.majorVersion = [productInfo[SUPPORTED_OS_MAJOR] intValue];
|
||||||
|
supportedOS.minorVersion = [productInfo[SUPPORTED_OS_MINOR] intValue];
|
||||||
|
|
||||||
|
//extract latest version
|
||||||
|
latestVersion = productInfo[LATEST_VERSION];
|
||||||
|
|
||||||
|
//supported version of macOS?
|
||||||
|
if(YES != [NSProcessInfo.processInfo isOperatingSystemAtLeastVersion:supportedOS])
|
||||||
|
{
|
||||||
|
//dbg msg
|
||||||
|
os_log_debug(logHandle, "latest version requires macOS %ld.%ld ...but current macOS is %{public}@", supportedOS.majorVersion, supportedOS.minorVersion, NSProcessInfo.processInfo.operatingSystemVersionString);
|
||||||
|
|
||||||
|
//unsupported
|
||||||
|
result = Update_NotSupported;
|
||||||
|
}
|
||||||
|
|
||||||
|
//latest version is new(er)?
|
||||||
|
else if(nil != latestVersion)
|
||||||
|
{
|
||||||
|
//check app version and latest version
|
||||||
|
if(NSOrderedAscending == [getAppVersion() compare:latestVersion options:NSNumericSearch])
|
||||||
|
{
|
||||||
|
//new update!
|
||||||
|
result = Update_Available;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//invoke app delegate method
|
//invoke app delegate method
|
||||||
// ->will update UI/show popup if necessart
|
// will update UI/show popup if necessary
|
||||||
dispatch_async(dispatch_get_main_queue(),
|
dispatch_async(dispatch_get_main_queue(),
|
||||||
^{
|
^{
|
||||||
completionHandler(result, latestVersion);
|
completionHandler(result, latestVersion);
|
||||||
|
@ -53,53 +94,27 @@ extern os_log_t logHandle;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//query interwebz to get latest version
|
//read JSON file w/ products
|
||||||
-(NSString*)getLatestVersion
|
// return dictionary w/ info about this product
|
||||||
|
-(NSDictionary*)getProductInfo:(NSString*)product
|
||||||
{
|
{
|
||||||
//product version(s) data
|
//product version(s) data
|
||||||
NSData* productsVersionData = nil;
|
NSDictionary* products = nil;
|
||||||
|
|
||||||
//version dictionary
|
//get json file (products) from remote URL
|
||||||
NSDictionary* productsVersionDictionary = nil;
|
|
||||||
|
|
||||||
//latest version
|
|
||||||
NSString* latestVersion = nil;
|
|
||||||
|
|
||||||
//get version from remote URL
|
|
||||||
productsVersionData = [[NSData alloc] initWithContentsOfURL:[NSURL URLWithString:PRODUCT_VERSIONS_URL]];
|
|
||||||
if(nil == productsVersionData)
|
|
||||||
{
|
|
||||||
//bail
|
|
||||||
goto bail;
|
|
||||||
}
|
|
||||||
|
|
||||||
//convert JSON to dictionary
|
|
||||||
// ->wrap as may throw exception
|
|
||||||
@try
|
@try
|
||||||
{
|
{
|
||||||
//convert
|
//convert
|
||||||
productsVersionDictionary = [NSJSONSerialization JSONObjectWithData:productsVersionData options:0 error:nil];
|
products = [NSJSONSerialization JSONObjectWithData:[[NSData alloc] initWithContentsOfURL:[NSURL URLWithString:PRODUCT_VERSIONS_URL]] options:0 error:nil];
|
||||||
if(nil == productsVersionDictionary)
|
|
||||||
{
|
|
||||||
//bail
|
|
||||||
goto bail;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@catch(NSException* exception)
|
@catch(NSException* exception)
|
||||||
{
|
{
|
||||||
//bail
|
;
|
||||||
goto bail;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//extract latest version
|
|
||||||
latestVersion = [[productsVersionDictionary objectForKey:@"OverSight"] objectForKey:@"version"];
|
|
||||||
|
|
||||||
//dbg msg
|
|
||||||
os_log_debug(logHandle, "latest version: %{public}@", latestVersion);
|
|
||||||
|
|
||||||
bail:
|
bail:
|
||||||
|
|
||||||
return latestVersion;
|
return products[product];
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
|
@ -441,6 +441,9 @@ bail:
|
||||||
//path to preferences dir
|
//path to preferences dir
|
||||||
NSString* prefsDirectory = nil;
|
NSString* prefsDirectory = nil;
|
||||||
|
|
||||||
|
//preferences file
|
||||||
|
NSString* preferences = nil;
|
||||||
|
|
||||||
//path to login item
|
//path to login item
|
||||||
NSURL* loginItem = nil;
|
NSURL* loginItem = nil;
|
||||||
|
|
||||||
|
@ -522,14 +525,25 @@ bail:
|
||||||
}
|
}
|
||||||
|
|
||||||
//full?
|
//full?
|
||||||
// delete prefs / allowed items
|
// delete preferences
|
||||||
if(YES == full)
|
if(YES == full)
|
||||||
{
|
{
|
||||||
//dbg msg
|
//init prefs file
|
||||||
os_log_debug(logHandle, "removing preferences/allowed items");
|
preferences = [NSHomeDirectory() stringByAppendingPathComponent:PREFERENCES];
|
||||||
|
|
||||||
//delete prefs via defaults
|
//dbg msg
|
||||||
execTask(DEFAULTS, @[@"delete", @BUNDLE_ID], YES, NO);
|
os_log_debug(logHandle, "deleting preferences");
|
||||||
|
|
||||||
|
//delete preferences file
|
||||||
|
// and if this fails, reset
|
||||||
|
if(YES != [NSFileManager.defaultManager removeItemAtPath:preferences error:nil])
|
||||||
|
{
|
||||||
|
//dbg msg
|
||||||
|
os_log_debug(logHandle, "deleting failed, will reset preferences");
|
||||||
|
|
||||||
|
//reset
|
||||||
|
[NSUserDefaults.standardUserDefaults removePersistentDomainForName:@BUNDLE_ID];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//always remove application
|
//always remove application
|
||||||
|
|
|
@ -70,6 +70,15 @@
|
||||||
//error(s) url
|
//error(s) url
|
||||||
#define ERRORS_URL @"https://objective-see.com/errors.html"
|
#define ERRORS_URL @"https://objective-see.com/errors.html"
|
||||||
|
|
||||||
|
//os major
|
||||||
|
#define SUPPORTED_OS_MAJOR @"OSMajor"
|
||||||
|
|
||||||
|
//os minor
|
||||||
|
#define SUPPORTED_OS_MINOR @"OSMinor"
|
||||||
|
|
||||||
|
//latest version
|
||||||
|
#define LATEST_VERSION @"version"
|
||||||
|
|
||||||
//close category
|
//close category
|
||||||
#define CATEGORY_CLOSE @"close"
|
#define CATEGORY_CLOSE @"close"
|
||||||
|
|
||||||
|
@ -110,6 +119,9 @@
|
||||||
//add rule, allow
|
//add rule, allow
|
||||||
#define BUTTON_ALLOW 1
|
#define BUTTON_ALLOW 1
|
||||||
|
|
||||||
|
//preferences file
|
||||||
|
#define PREFERENCES @"/Library/Preferences/com.objective-see.oversight.plist"
|
||||||
|
|
||||||
//prefs
|
//prefs
|
||||||
// disabled status
|
// disabled status
|
||||||
#define PREF_IS_DISABLED @"disabled"
|
#define PREF_IS_DISABLED @"disabled"
|
||||||
|
@ -198,9 +210,6 @@
|
||||||
//path to launchctl
|
//path to launchctl
|
||||||
#define LAUNCHCTL @"/bin/launchctl"
|
#define LAUNCHCTL @"/bin/launchctl"
|
||||||
|
|
||||||
//path to defaults
|
|
||||||
#define DEFAULTS @"/usr/bin/defaults"
|
|
||||||
|
|
||||||
//path to kill all
|
//path to kill all
|
||||||
#define KILL_ALL @"/usr/bin/killall"
|
#define KILL_ALL @"/usr/bin/killall"
|
||||||
|
|
||||||
|
@ -237,6 +246,9 @@
|
||||||
//av devices
|
//av devices
|
||||||
typedef enum {Device_Camera, Device_Microphone} AVDevice;
|
typedef enum {Device_Camera, Device_Microphone} AVDevice;
|
||||||
|
|
||||||
|
//updates
|
||||||
|
typedef enum {Update_Error, Update_None, Update_NotSupported, Update_Available} UpdateStatus;
|
||||||
|
|
||||||
//log levels
|
//log levels
|
||||||
typedef enum {Log_Level_Default, Log_Level_Info, Log_Level_Debug} LogLevels;
|
typedef enum {Log_Level_Default, Log_Level_Info, Log_Level_Debug} LogLevels;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue