AceCentre/MorseWriter

Allow user to choose to run on startup

Closed this issue · 2 comments

We have this in the installer from memory but it should be in the config.

Here’s some example code.

import os
import win32com.client

def create_task(task_name, script_path):
    scheduler = win32com.client.Dispatch('Schedule.Service')
    scheduler.Connect()
    root_folder = scheduler.GetFolder('\\')
    task_def = scheduler.NewTask(0)

    # Set task settings
    task_def.RegistrationInfo.Description = 'Start Python app on startup'
    task_def.Principal.UserId = 'SYSTEM'
    task_def.Principal.LogonType = 3  # Logon interactively

    # Trigger: At logon
    trigger = task_def.Triggers.Create(1)  # 1 is for logon trigger
    trigger.UserId = os.getlogin()

    # Action: Start the Python script
    action = task_def.Actions.Create(0)  # 0 is for action to start a program
    action.Path = 'python'
    action.Arguments = f'"{script_path}"'
    action.WorkingDirectory = os.path.dirname(script_path)

    # Register the task
    root_folder.RegisterTaskDefinition(
        task_name,
        task_def,
        6,  # Replace existing task if present
        None,
        None,
        3,  # Logon interactively
        None
    )
    print(f'Task "{task_name}" created successfully.')

def delete_task(task_name):
    scheduler = win32com.client.Dispatch('Schedule.Service')
    scheduler.Connect()
    root_folder = scheduler.GetFolder('\\')
    root_folder.DeleteTask(task_name, 0)
    print(f'Task "{task_name}" deleted successfully.')

if __name__ == "__main__":
    import sys
    if len(sys.argv) != 3:
        print("Usage: python manage_startup.py <add/remove> <script_path>")
        sys.exit(1)

    action = sys.argv[1]
    script_path = sys.argv[2]
    task_name = "PythonAppStartup"

    if action == "add":
        create_task(task_name, script_path)
    elif action == "remove":
        delete_task(task_name)
    else:
        print("Invalid action. Use 'add' or 'remove'.")

Nb. Bear in mind this is cross platform.

import os
import sys
import platform
import subprocess

def create_task(task_name, script_path):
    system = platform.system()
    if system == 'Windows':
        create_windows_task(task_name, script_path)
    elif system == 'Darwin':
        create_mac_startup_item(script_path)
    elif system == 'Linux':
        create_linux_startup_item(script_path)
    else:
        raise NotImplementedError(f"Unsupported platform: {system}")

def delete_task(task_name):
    system = platform.system()
    if system == 'Windows':
        delete_windows_task(task_name)
    elif system == 'Darwin':
        remove_mac_startup_item()
    elif system == 'Linux':
        remove_linux_startup_item()
    else:
        raise NotImplementedError(f"Unsupported platform: {system}")

# Windows specific functions
def create_windows_task(task_name, script_path):
    import win32com.client
    scheduler = win32com.client.Dispatch('Schedule.Service')
    scheduler.Connect()
    root_folder = scheduler.GetFolder('\\')
    task_def = scheduler.NewTask(0)

    task_def.RegistrationInfo.Description = 'Start Python app on startup'
    task_def.Principal.UserId = 'SYSTEM'
    task_def.Principal.LogonType = 3

    trigger = task_def.Triggers.Create(1)
    trigger.UserId = os.getlogin()

    action = task_def.Actions.Create(0)
    action.Path = 'python'
    action.Arguments = f'"{script_path}"'
    action.WorkingDirectory = os.path.dirname(script_path)

    root_folder.RegisterTaskDefinition(task_name, task_def, 6, None, None, 3, None)
    print(f'Task "{task_name}" created successfully.')

def delete_windows_task(task_name):
    import win32com.client
    scheduler = win32com.client.Dispatch('Schedule.Service')
    scheduler.Connect()
    root_folder = scheduler.GetFolder('\\')
    root_folder.DeleteTask(task_name, 0)
    print(f'Task "{task_name}" deleted successfully.')

# Mac specific functions
def create_mac_startup_item(app_path):
    script = f'''
    tell application "System Events"
        if not (exists login item "PythonAppStartup") then
            make login item at end with properties {{path:"{app_path}", hidden:false}}
        end if
    end tell
    '''
    subprocess.run(["osascript", "-e", script])
    print('Startup item added.')

def remove_mac_startup_item():
    script = '''
    tell application "System Events"
        if exists login item "PythonAppStartup" then
            delete login item "PythonAppStartup"
        end if
    end tell
    '''
    subprocess.run(["osascript", "-e", script])
    print('Startup item removed.')

# Linux specific functions
def create_linux_startup_item(script_path):
    autostart_dir = os.path.expanduser("~/.config/autostart")
    if not os.path.exists(autostart_dir):
        os.makedirs(autostart_dir)

    desktop_entry = f"""
    [Desktop Entry]
    Type=Application
    Exec=python3 {script_path}
    Hidden=false
    NoDisplay=false
    X-GNOME-Autostart-enabled=true
    Name=PythonAppStartup
    Comment=Start Python app on startup
    """
    with open(os.path.join(autostart_dir, "PythonAppStartup.desktop"), 'w') as f:
        f.write(desktop_entry)
    print('Startup item added.')

def remove_linux_startup_item():
    autostart_file = os.path.expanduser("~/.config/autostart/PythonAppStartup.desktop")
    if os.path.exists(autostart_file):
        os.remove(autostart_file)
        print('Startup item removed.')

# User interaction code (can be expanded to GUI or CLI)
if __name__ == "__main__":
    if len(sys.argv) != 3:
        print("Usage: python manage_startup.py <add/remove> <script_path>")
        sys.exit(1)

    action = sys.argv[1]
    script_path = sys.argv[2]
    task_name = "PythonAppStartup"

    if action == "add":
        create_task(task_name, script_path)
    elif action == "remove":
        delete_task(task_name)
    else:
        print("Invalid action. Use 'add' or 'remove'.")

im going to close this for now - we dont need to deal with it just yet