Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Restore only missing programs #64

Merged
merged 1 commit into from
Nov 17, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions i3_resurrect/layout.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ def read(workspace, directory, profile):
if profile is not None:
filename = f'{profile}_layout.json'
layout_file = Path(directory) / filename

layout = None
try:
layout = json.loads(layout_file.read_text())
Expand Down
3 changes: 2 additions & 1 deletion i3_resurrect/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,8 @@ def restore_workspace(workspace, numeric, directory, profile, target):

if target != 'layout_only':
# Restore programs.
programs.restore(workspace, directory, profile)
saved_programs = programs.read(workspace, directory, profile)
programs.restore(workspace_name, saved_programs)


@main.command('ls')
Expand Down
111 changes: 67 additions & 44 deletions i3_resurrect/programs.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,6 @@ def save(workspace, numeric, directory, profile):
filename = f'{profile}_programs.json'
programs_file = Path(directory) / filename

terminals = config.get('terminals', [])

# Print deprecation warning if using old dictionary method of writing
# window command mappings.
# TODO: Remove in 2.0.0
Expand All @@ -34,60 +32,23 @@ def save(workspace, numeric, directory, profile):
'is deprecated and will be removed in favour of the list method '
'in the next major version.')

# Loop through windows and save commands to launch programs on saved
# workspace.
programs = []
for (con, pid) in windows_in_workspace(workspace, numeric):
if pid == 0:
continue

# Get process info for the window.
procinfo = psutil.Process(pid)

# Create command to launch program.
command = get_window_command(
con['window_properties'],
procinfo.cmdline(),
)
if command in ([], ''):
continue

# Remove empty string arguments from command.
command = [arg for arg in command if arg != '']

try:
# Obtain working directory using psutil.
if con['window_properties']['class'] in terminals:
# If the program is a terminal emulator, get the working
# directory from its first subprocess.
working_directory = procinfo.children()[0].cwd()
else:
working_directory = procinfo.cwd()
except Exception:
working_directory = str(Path.home())

# Add the command to the list.
programs.append({
'command': command,
'working_directory': working_directory
})
programs = get_programs(workspace, numeric)

# Write list of commands to file as JSON.
with programs_file.open('w') as f:
f.write(json.dumps(programs, indent=2))


def restore(workspace, directory, profile):
def read(workspace, directory, profile):
"""
Restore the running programs from an i3 workspace.
Read saved programs file.
"""
workspace_id = util.filename_filter(workspace)
filename = f'workspace_{workspace_id}_programs.json'
if profile is not None:
filename = f'{profile}_programs.json'
programs_file = Path(directory) / filename

# Read saved programs file.
programs = None
try:
programs = json.loads(programs_file.read_text())
Expand All @@ -99,8 +60,20 @@ def restore(workspace, directory, profile):
util.eprint('Could not find saved programs for workspace '
f'"{workspace}"')
sys.exit(1)
return programs


for entry in programs:
def restore(workspace_name, saved_programs):
"""
Restore the running programs from an i3 workspace.
"""
# Remove already running programs from the list of program to restore.
running_programs = get_programs(workspace_name, False)
for program in running_programs:
saved_programs.remove(program)

i3 = i3ipc.Connection()
for entry in saved_programs:
cmdline = entry['command']
working_directory = entry['working_directory']

Expand All @@ -120,10 +93,60 @@ def restore(workspace, directory, profile):
command = cmdline

# Execute command via i3 exec.
i3 = i3ipc.Connection()
i3.command(f'exec cd "{working_directory}" && {command}')


def get_programs(workspace, numeric):
"""
Get running programs in specified workspace.
Args:
workspace: The workspace to search.
numeric: Identify workspace by number instead of name.
"""
# Loop through windows and save commands to launch programs on saved
# workspace.
programs = []
for (con, pid) in windows_in_workspace(workspace, numeric):
if pid == 0:
continue

# Get process info for the window.
procinfo = psutil.Process(pid)

# Create command to launch program.
command = get_window_command(
con['window_properties'],
procinfo.cmdline(),
)
if command in ([], ''):
continue

# Remove empty string arguments from command.
command = [arg for arg in command if arg != '']

terminals = config.get('terminals', [])

try:
# Obtain working directory using psutil.
if con['window_properties']['class'] in terminals:
# If the program is a terminal emulator, get the working
# directory from its first subprocess.
working_directory = procinfo.children()[0].cwd()
else:
working_directory = procinfo.cwd()
except Exception:
working_directory = str(Path.home())

# Add the command to the list.
programs.append({
'command': command,
'working_directory': working_directory
})

return programs


def windows_in_workspace(workspace, numeric):
"""
Generator to iterate over windows in a workspace.
Expand Down