Skip to content

Commit

Permalink
Version 1.2: adding private window capabilities
Browse files Browse the repository at this point in the history
  • Loading branch information
AlexPerathoner committed Jan 24, 2020
1 parent fa9c9bb commit d6bb51e
Show file tree
Hide file tree
Showing 11 changed files with 144 additions and 43 deletions.
18 changes: 14 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,22 @@ Safari extension to save your working sessions
Have you ever been working on a project, with dozens of tabs open, and wondered how to save that window?
With *Sessions* you can easily save them, to re-open them whenever you'll want to!

## Features:
## Features

<img align="right" margin="10px" src="https://raw.githubusercontent.com/AlexPerathoner/Sessions/master/Screens/PrivateDemonstration.mov" width="40%"></img>
### New in 1.2:
- Save and open **private** sessions! <sup>[1](#note1)</sup>
- Open non-private sessions in private windows!

<br />
### New in 1.1:
- Export as json
- Rename sessions
- Search

<img src="https://raw.githubusercontent.com/AlexPerathoner/Sessions/master/Screens/Registrazione%20schermo%202019-11-26%20alle%2001.14.21.mov" width="50%"></img>

<a name="note2"></a><sup>2</sup>: Note that since there are no public APIs avaible to open a private window I used the stratagem of sending a keystroke event to safari. This means that the function could sometimes fail and restore the session in a different window from the one opened.</mark>


## Installation
Download and compile. Copy the file Sessions.app into your Application's folder. Open it.
Expand All @@ -21,7 +31,7 @@ Safari will warn you that this extension can read sensible information from ever
As you enable the extension from the Safari's settings window you should see a new icon appear in the bar.

### Actions
* **Click** on the **save** button to store the current working session <sup>[1](#note1)</sup>
* **Click** on the **save** button to store the current working session <sup>[2](#note2)</sup>
* **Double click** on a previously saved to re-open it
* **Click** on the **settings icon** next to the name of the session to view some other actions:
* **Restore** - Same as double-click action
Expand All @@ -30,7 +40,7 @@ As you enable the extension from the Safari's settings window you should see a n
* **Export** - Creates a .json file in the Downloads folder with every information *Sessions* has stored concerning about that session


<a name="note1"></a><sup>1</sup>: Note that a session only includes the tabs of your current window. <mark>**Other windows won't be included.**</mark>
<a name="note2"></a><sup>2</sup>: Note that a session only includes the tabs of your current window. <mark>**Other windows won't be included.**</mark>

## License

Expand Down
Binary file added Screens/PrivateDemonstration.mov
Binary file not shown.
15 changes: 11 additions & 4 deletions Sessions Extension/Base.lproj/SafariExtensionViewController.xib
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="15504" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="15705" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
<dependencies>
<deployment identifier="macosx"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="15504"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="15705"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
Expand Down Expand Up @@ -53,7 +53,7 @@
<tableColumns>
<tableColumn identifier="nameColumn" width="156" minWidth="40" maxWidth="1000" id="e7Y-MQ-FFZ">
<tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border">
<font key="font" metaFont="label" size="11"/>
<font key="font" metaFont="controlContent" size="11"/>
<color key="textColor" name="headerTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="headerColor" catalog="System" colorSpace="catalog"/>
</tableHeaderCell>
Expand Down Expand Up @@ -94,7 +94,7 @@
</tableColumn>
<tableColumn identifier="deleteColumn" width="33" minWidth="10" maxWidth="3.4028234663852886e+38" id="cBK-EV-8h9">
<tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border" alignment="left">
<font key="font" metaFont="label" size="11"/>
<font key="font" metaFont="controlContent" size="11"/>
<color key="textColor" name="headerTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
</tableHeaderCell>
Expand Down Expand Up @@ -180,6 +180,12 @@
<action selector="restoreMenuItemWithSender:" target="-2" id="uge-dh-s2o"/>
</connections>
</menuItem>
<menuItem title="Private" image="NSQuickLookTemplate" id="8Vc-2n-Zyp">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="restoreAsPrivate:" target="-2" id="JvQ-ax-An2"/>
</connections>
</menuItem>
<menuItem title="Remove" image="NSTouchBarDeleteTemplate" id="Tsg-EC-kx9">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
Expand All @@ -203,6 +209,7 @@
</menu>
</objects>
<resources>
<image name="NSQuickLookTemplate" width="19" height="12"/>
<image name="NSSmartBadgeTemplate" width="14" height="14"/>
<image name="NSTouchBarComposeTemplate" width="21" height="30"/>
<image name="NSTouchBarDeleteTemplate" width="15" height="30"/>
Expand Down
48 changes: 48 additions & 0 deletions Sessions Extension/KeyPress.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
//
// KeyPress.swift
// Sessions Extension
//
// Created by Alex Perathoner on 24/01/2020.
// Copyright © 2020 Alex Perathoner. All rights reserved.
//

import Foundation
import AppKit
//import ScriptingBridge


class KeyPress {
static let src = CGEventSource(stateID: .hidSystemState)
static let commandControlMask = (CGEventFlags.maskCommand.rawValue | CGEventFlags.maskShift.rawValue)
static let commandControlMaskFlags = CGEventFlags(rawValue: commandControlMask)

static let loc: CGEventTapLocation = .cghidEventTap // kCGSessionEventTap also works

static func simulateCmdShiftN() { //should open new private window

//safari.activate() //just to be sure -> replace by the postToPid

let ndown = CGEvent(keyboardEventSource: src, virtualKey: CGKeyCode(0x2d), keyDown: true)
let nup = CGEvent(keyboardEventSource: src, virtualKey: CGKeyCode(0x2d), keyDown: false)

ndown!.flags = commandControlMaskFlags
nup!.flags = commandControlMaskFlags

let pid = getPid("com.apple.Safari")!
if let ndown = ndown {
ndown.postToPid(pid)
}
if let nup = nup {
nup.postToPid(pid)
}
}

static func getPid(_ ofAppWithBundleID: String) -> pid_t? {
for i in NSWorkspace.shared.runningApplications {
if (i.bundleIdentifier == ofAppWithBundleID) {
return i.processIdentifier
}
}
return nil
}
}
69 changes: 55 additions & 14 deletions Sessions Extension/SafariExtensionViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,8 @@ class SafariExtensionViewController: SFSafariExtensionViewController, NSTableVie
}

@objc func tableDoubleClick(_ sender: Any?) {
restoreSession(index: tableView.selectedRow) //gets index of item clicked
let index = tableView.selectedRow
restoreSession(index: index, asPrivate: isSessionsPrivate(index: index)) //gets index of item clicked
}


Expand Down Expand Up @@ -185,6 +186,7 @@ class SafariExtensionViewController: SFSafariExtensionViewController, NSTableVie
}
return sessions.count
}

@IBAction func searching(_ sender: NSSearchField) {
if(sender.stringValue != "") {
isSearching = true
Expand All @@ -201,7 +203,6 @@ class SafariExtensionViewController: SFSafariExtensionViewController, NSTableVie
tableView.reloadData()
}


func tableView(_ tableView: NSTableView, objectValueFor tableColumn: NSTableColumn?, row: Int) -> Any?
{
var item: Session
Expand All @@ -212,8 +213,6 @@ class SafariExtensionViewController: SFSafariExtensionViewController, NSTableVie
}
return item.name
}



@IBAction func cellTitleChanged(_ sender: NSTextField) {
let newName = sender.stringValue
Expand All @@ -235,10 +234,26 @@ class SafariExtensionViewController: SFSafariExtensionViewController, NSTableVie

@IBAction func restoreMenuItem(sender: NSMenuItem) {
if(indexClicked == -1) { return }
restoreSession(index: indexClicked)
restoreSession(index: indexClicked, asPrivate: false)
indexClicked = -1
}


@IBAction func restoreAsPrivate(_ sender: NSMenuItem) {
if(indexClicked == -1) { return }
if(!readPrivileges(prompt: true)) {return}
restoreSession(index: indexClicked, asPrivate: true)
indexClicked = -1
}


private func readPrivileges(prompt: Bool) -> Bool {
let options: NSDictionary = [kAXTrustedCheckOptionPrompt.takeRetainedValue() as NSString: prompt]
let status = AXIsProcessTrustedWithOptions(options)
//print("Reading Accessibility privileges - Current access status " + String(status))
return status
}

@IBAction func removeMenuItem(_ sender: Any) {
if(indexClicked == -1) { return }
if(isSearching) {
Expand Down Expand Up @@ -271,25 +286,51 @@ class SafariExtensionViewController: SFSafariExtensionViewController, NSTableVie
indexClicked = -1
}

func restoreSession(index: Int) {



func isSessionsPrivate(index: Int) -> Bool {
var interestingSession: Session
if(isSearching) {
interestingSession = filteredSessions[index]
} else {
interestingSession = sessions[index]
}
let we: WebPage = interestingSession.pages.first!
return we.privat
}

func restoreSession(index: Int, asPrivate: Bool) {
var interestingSession: Session
if(isSearching) {
interestingSession = filteredSessions[index]
} else {
interestingSession = sessions[index]
}
//opens new window with first url, removes first item from list and opens other urls in new tabs
//interestingSession.pages.first!.privat


SFSafariApplication.openWindow(with: (interestingSession.pages.first!.url)) { (window) in
for i in 1 ..< interestingSession.pages.count {
window?.openTab(with: interestingSession.pages[i].url, makeActiveIfPossible: false, completionHandler: { (tab) in
if(asPrivate) {
//press cmd + shift + n (new private window)
KeyPress.simulateCmdShiftN()
SFSafariApplication.getActiveWindow { (window) in
//keyevent isn't dispatched synchroniously. A sleep is needed to not open the urls before the window is open
usleep(700000) //sleep for 0.7 seconds
window?.getAllTabs(completionHandler: { (tabs) in
tabs[0].navigate(to: interestingSession.pages.first!.url)
})
for i in 1 ..< interestingSession.pages.count {
window?.openTab(with: interestingSession.pages[i].url, makeActiveIfPossible: false, completionHandler: { _ in})
}
print("Session \"\(String(describing: interestingSession.name))\" restored - \(interestingSession.pages.count) tabs opened in PRIVATE mode")
}
} else {
SFSafariApplication.openWindow(with: (interestingSession.pages.first!.url)) { (window) in
for i in 1 ..< interestingSession.pages.count {
window?.openTab(with: interestingSession.pages[i].url, makeActiveIfPossible: false, completionHandler: { (tab) in
})
}
}
print("Session \"\(String(describing: interestingSession.name))\" restored - \(interestingSession.pages.count) tabs opened")
}

print("Session \"\(String(describing: interestingSession.name))\" restored - \(interestingSession.pages.count) tabs opened")
}
//
// @IBAction func restoreSession(_ sender: Any) {
Expand Down
2 changes: 0 additions & 2 deletions Sessions Extension/Sessions_Extension.entitlements
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,5 @@
<true/>
<key>com.apple.security.files.downloads.read-write</key>
<true/>
<key>com.apple.security.files.user-selected.read-write</key>
<true/>
</dict>
</plist>
5 changes: 5 additions & 0 deletions Sessions Extension/Todo.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,8 @@ DONE
### search sessions
DONE
#### modify sessions


## open in incognito

## right click on save button to get more options
22 changes: 6 additions & 16 deletions Sessions.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
FAAEE322230474D60022C8BC /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = FAAEE320230474D60022C8BC /* Main.storyboard */; };
FAAEE324230474D60022C8BC /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = FAAEE323230474D60022C8BC /* ViewController.swift */; };
FAAEE326230474D70022C8BC /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = FAAEE325230474D70022C8BC /* Assets.xcassets */; };
FAAEE331230474D70022C8BC /* SessionsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = FAAEE330230474D70022C8BC /* SessionsTests.swift */; };
FAAEE338230474D70022C8BC /* Sessions Extension.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = FAAEE337230474D70022C8BC /* Sessions Extension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
FAAEE33D230474D70022C8BC /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FAAEE33C230474D70022C8BC /* Cocoa.framework */; };
FAAEE340230474D70022C8BC /* SafariExtensionHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = FAAEE33F230474D70022C8BC /* SafariExtensionHandler.swift */; };
Expand All @@ -23,6 +22,7 @@
FAAEE348230474D70022C8BC /* script.js in Resources */ = {isa = PBXBuildFile; fileRef = FAAEE347230474D70022C8BC /* script.js */; };
FABDCBD1230755A2001B240C /* XML.swift in Sources */ = {isa = PBXBuildFile; fileRef = FABDCBD0230755A2001B240C /* XML.swift */; };
FABDCBD62309EE88001B240C /* Session.swift in Sources */ = {isa = PBXBuildFile; fileRef = FABDCBD52309EE88001B240C /* Session.swift */; };
FAE2486B23DB6E4300B82591 /* KeyPress.swift in Sources */ = {isa = PBXBuildFile; fileRef = FAE2486A23DB6E4300B82591 /* KeyPress.swift */; };
/* End PBXBuildFile section */

/* Begin PBXContainerItemProxy section */
Expand Down Expand Up @@ -68,8 +68,6 @@
FAAEE325230474D70022C8BC /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
FAAEE327230474D70022C8BC /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
FAAEE32C230474D70022C8BC /* SessionsTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = SessionsTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
FAAEE330230474D70022C8BC /* SessionsTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SessionsTests.swift; sourceTree = "<group>"; };
FAAEE332230474D70022C8BC /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
FAAEE337230474D70022C8BC /* Sessions Extension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = "Sessions Extension.appex"; sourceTree = BUILT_PRODUCTS_DIR; };
FAAEE33C230474D70022C8BC /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; };
FAAEE33F230474D70022C8BC /* SafariExtensionHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SafariExtensionHandler.swift; sourceTree = "<group>"; };
Expand All @@ -80,6 +78,7 @@
FAAEE34B230474D70022C8BC /* Sessions_Extension.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Sessions_Extension.entitlements; sourceTree = "<group>"; };
FABDCBD0230755A2001B240C /* XML.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = XML.swift; sourceTree = "<group>"; };
FABDCBD52309EE88001B240C /* Session.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Session.swift; sourceTree = "<group>"; };
FAE2486A23DB6E4300B82591 /* KeyPress.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeyPress.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */

/* Begin PBXFrameworksBuildPhase section */
Expand Down Expand Up @@ -112,7 +111,6 @@
isa = PBXGroup;
children = (
FAAEE31B230474D60022C8BC /* Sessions */,
FAAEE32F230474D70022C8BC /* SessionsTests */,
FAAEE33E230474D70022C8BC /* Sessions Extension */,
FAAEE33B230474D70022C8BC /* Frameworks */,
FAAEE31A230474D60022C8BC /* Products */,
Expand Down Expand Up @@ -142,15 +140,6 @@
path = Sessions;
sourceTree = "<group>";
};
FAAEE32F230474D70022C8BC /* SessionsTests */ = {
isa = PBXGroup;
children = (
FAAEE330230474D70022C8BC /* SessionsTests.swift */,
FAAEE332230474D70022C8BC /* Info.plist */,
);
path = SessionsTests;
sourceTree = "<group>";
};
FAAEE33B230474D70022C8BC /* Frameworks */ = {
isa = PBXGroup;
children = (
Expand All @@ -164,6 +153,7 @@
children = (
FAAEE33F230474D70022C8BC /* SafariExtensionHandler.swift */,
FAAEE341230474D70022C8BC /* SafariExtensionViewController.swift */,
FAE2486A23DB6E4300B82591 /* KeyPress.swift */,
FABDCBD52309EE88001B240C /* Session.swift */,
FA200144238C8D65006B31C0 /* WebPage.swift */,
FABDCBD0230755A2001B240C /* XML.swift */,
Expand Down Expand Up @@ -320,7 +310,6 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
FAAEE331230474D70022C8BC /* SessionsTests.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand All @@ -333,6 +322,7 @@
FA200145238C8D65006B31C0 /* WebPage.swift in Sources */,
FABDCBD1230755A2001B240C /* XML.swift in Sources */,
FAAEE340230474D70022C8BC /* SafariExtensionHandler.swift in Sources */,
FAE2486B23DB6E4300B82591 /* KeyPress.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down Expand Up @@ -543,7 +533,7 @@
"$(inherited)",
"@executable_path/../Frameworks",
);
MARKETING_VERSION = 1.1;
MARKETING_VERSION = 1.2;
PRODUCT_BUNDLE_IDENTIFIER = AlexP.Sessions;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 5.0;
Expand All @@ -565,7 +555,7 @@
"$(inherited)",
"@executable_path/../Frameworks",
);
MARKETING_VERSION = 1.1;
MARKETING_VERSION = 1.2;
PRODUCT_BUNDLE_IDENTIFIER = AlexP.Sessions;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 5.0;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,12 @@
<key>Sessions Extension.xcscheme_^#shared#^_</key>
<dict>
<key>orderHint</key>
<integer>1</integer>
<integer>0</integer>
</dict>
<key>Sessions.xcscheme_^#shared#^_</key>
<dict>
<key>orderHint</key>
<integer>0</integer>
<integer>1</integer>
</dict>
</dict>
<key>SuppressBuildableAutocreation</key>
Expand Down
Loading

0 comments on commit d6bb51e

Please sign in to comment.