Move workspace startup to its own script
The startup from within the sway autostart script that I had failed to keep things on the correct workspaces and started things out of order. This moves that to a bash script that calls everything with i3-toolwait (https://gitlab.com/wef/dotfiles/-/blob/master/bin/i3-toolwait) to attempt to control that better.
This commit is contained in:
		
					parent
					
						
							
								0a0ec0242b
							
						
					
				
			
			
				commit
				
					
						e11c55c8f6
					
				
			
		
					 3 changed files with 198 additions and 31 deletions
				
			
		| 
						 | 
				
			
			@ -7,49 +7,21 @@ exec /usr/bin/swaync
 | 
			
		|||
exec export YDOTOOL_SOCKET=/tmp/.ydotool_socket
 | 
			
		||||
exec ydotoold
 | 
			
		||||
 | 
			
		||||
#password keyring unlock
 | 
			
		||||
##password keyring unlock
 | 
			
		||||
#exec --no-startup-id /home/kellya/projects/public/gnome-keyring-yubikey-unlock/unlock_keyrings.sh /home/kellya/gnome-secret
 | 
			
		||||
 | 
			
		||||
# start nm-applet for network tray icon
 | 
			
		||||
exec nm-applet
 | 
			
		||||
 | 
			
		||||
# Set screen lock
 | 
			
		||||
#exec xset s 300 5
 | 
			
		||||
#exec xss-lock -n /usr/libexec/xsecurelock/dimmer -l -- xsecurelock
 | 
			
		||||
#exec --no-startup-id xss-lock --transfer-sleep-lock -- i3lock -c 04090e --nofork
 | 
			
		||||
 | 
			
		||||
# use gnome settings to set gnome things to dark mode by default
 | 
			
		||||
exec /usr/libexec/gsd-xsettings
 | 
			
		||||
 | 
			
		||||
workspace $ws6
 | 
			
		||||
exec  /usr/bin/thunderbird
 | 
			
		||||
exec /home/kellya/bin/logseq
 | 
			
		||||
 | 
			
		||||
# Start spotify from the stupid flatpak
 | 
			
		||||
workspace $ws5
 | 
			
		||||
exec "/usr/bin/flatpak run --branch=stable --arch=x86_64 --command=spotify --file-forwarding com.spotify.Client"
 | 
			
		||||
 | 
			
		||||
workspace $ws3
 | 
			
		||||
exec kitty
 | 
			
		||||
exec /home/kellya/.config/sway/scripts/i3-toolwait --nocheck --waitfor 1password 1password
 | 
			
		||||
 | 
			
		||||
workspace $ws2
 | 
			
		||||
exec "flatpak run com.slack.Slack"
 | 
			
		||||
exec "/opt/teams-for-linux/teams-for-linux --optInTeamsV2 true"
 | 
			
		||||
# Always need firefox, so let's just start it
 | 
			
		||||
workspace $ws1
 | 
			
		||||
exec firefox
 | 
			
		||||
#exec "swaymsg workspace $ws1; /home/kellya/.config/sway/scripts/i3-toolwait --nocheck --waitfor firefox firefox"
 | 
			
		||||
# Force order and screens for app startup
 | 
			
		||||
exec /home/kellya/.config/sway/scripts/workspaces.sh
 | 
			
		||||
 | 
			
		||||
# start the auto run .desktop files
 | 
			
		||||
exec dex-autostart --autostart --environment sway
 | 
			
		||||
 | 
			
		||||
# Start redshift, becuase I like not being blinded at night
 | 
			
		||||
#exec --no-startup-id redshift
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# Switch to the terminal/email workspace by default
 | 
			
		||||
workspace $ws3
 | 
			
		||||
exec /home/kellya/bin/bg_rotate_sway.sh
 | 
			
		||||
exec ~/.local/bin/solaar -w hide -b symbolic
 | 
			
		||||
exec swayosd-server
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										156
									
								
								scripts/i3-toolwait
									
										
									
									
									
										Executable file
									
								
							
							
						
						
									
										156
									
								
								scripts/i3-toolwait
									
										
									
									
									
										Executable file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,156 @@
 | 
			
		|||
#!/usr/bin/env -S python3 -B
 | 
			
		||||
# https://gitlab.com/wef/dotfiles/-/blob/master/bin/i3-toolwait
 | 
			
		||||
TIME_STAMP="20241206.184437"
 | 
			
		||||
 | 
			
		||||
# dependencies: i3ipc: https://i3ipc-python.readthedocs.io/en/latest/
 | 
			
		||||
 | 
			
		||||
# Copyright (C) 2020-2024 Bob Hepple <bob dot hepple at gmail dot com>
 | 
			
		||||
 | 
			
		||||
# This program is free software: you can redistribute it and/or modify
 | 
			
		||||
# it under the terms of the GNU General Public License as published by
 | 
			
		||||
# the Free Software Foundation, either version 3 of the License, or (at
 | 
			
		||||
# your option) any later version.
 | 
			
		||||
#
 | 
			
		||||
# This program is distributed in the hope that it will be useful, but
 | 
			
		||||
# WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 | 
			
		||||
# General Public License for more details.
 | 
			
		||||
#
 | 
			
		||||
# You should have received a copy of the GNU General Public License
 | 
			
		||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
 | 
			
		||||
# https://www.reddit.com/r/swaywm/comments/ru3rn9/a_feeble_version_of_toolwait_to_start_a_session/
 | 
			
		||||
# https://www.reddit.com/r/swaywm/comments/skpcmo/method_for_starting_applications_on_startup_on/
 | 
			
		||||
 | 
			
		||||
from i3ipc import Connection
 | 
			
		||||
import argparse
 | 
			
		||||
import subprocess, os, sys
 | 
			
		||||
import time
 | 
			
		||||
from multiprocessing import Process
 | 
			
		||||
 | 
			
		||||
sys.dont_write_bytecode = True
 | 
			
		||||
 | 
			
		||||
global parser, i3, retval, args, start_time, count
 | 
			
		||||
 | 
			
		||||
def verbose(msg):
 | 
			
		||||
    if args.verbose:
 | 
			
		||||
        elapsed_time = time.time() - start_time
 | 
			
		||||
        sys.stderr.write(f"{elapsed_time}s: {parser.prog}: {msg}\n")
 | 
			
		||||
 | 
			
		||||
def sleep_and_run_command():
 | 
			
		||||
    "This runs in a separate process"
 | 
			
		||||
    s = 0.1 # just enough to let i3ipc.main() loop start
 | 
			
		||||
    verbose(f"Runner process sleeping for {s}s")
 | 
			
		||||
    time.sleep(s)
 | 
			
		||||
    verbose(f"Running: {args.command}")
 | 
			
		||||
    subprocess.Popen(args.command, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
 | 
			
		||||
 | 
			
		||||
def on_window(i3, e):
 | 
			
		||||
    "callback function from i3ipc.main() loop"
 | 
			
		||||
 | 
			
		||||
    # note: I thought of adding an option to also allow a wait on the
 | 
			
		||||
    # 'name' field (ie the window title) but at the time of this
 | 
			
		||||
    # event, it has not been populated!!
 | 
			
		||||
 | 
			
		||||
    global count
 | 
			
		||||
 | 
			
		||||
    verbose(f"Got a {e.change} window event:")
 | 
			
		||||
    container = e.ipc_data['container']
 | 
			
		||||
    try:
 | 
			
		||||
        verbose(f"app_id: {container['app_id']}")
 | 
			
		||||
    except:
 | 
			
		||||
        verbose(f"Class: {container['window_properties']['class']}, instance: {container['window_properties']['instance']}")
 | 
			
		||||
 | 
			
		||||
    waitfor = args.command[0]
 | 
			
		||||
    if args.waitfor:
 | 
			
		||||
        waitfor = args.waitfor
 | 
			
		||||
 | 
			
		||||
    finished = False
 | 
			
		||||
    if args.nocheck:
 | 
			
		||||
        finished = True
 | 
			
		||||
    else:
 | 
			
		||||
        new_window = container['app_id'] or container['window_properties']['instance']
 | 
			
		||||
        if waitfor in new_window:
 | 
			
		||||
            # eg pavucontrol sometimes comes up as org.pulseaudio.pavucontrol
 | 
			
		||||
            verbose(f"a new window for '{waitfor}' appeared")
 | 
			
		||||
            count -= 1
 | 
			
		||||
            if count <= 0:
 | 
			
		||||
                finished = True
 | 
			
		||||
                args.id = container['id']
 | 
			
		||||
        else:
 | 
			
		||||
            verbose(f"a new window appeared '{new_window}' but I'm waiting for '{waitfor}'")
 | 
			
		||||
 | 
			
		||||
    if finished:
 | 
			
		||||
        i3.main_quit() # else continue to wait
 | 
			
		||||
 | 
			
		||||
if __name__ == "__main__":
 | 
			
		||||
 | 
			
		||||
    msg = "i3-msg"
 | 
			
		||||
    wm = "i3"
 | 
			
		||||
    if os.getenv("SWAYSOCK") != "":
 | 
			
		||||
        msg = "swaymsg"
 | 
			
		||||
        wm = "sway"
 | 
			
		||||
 | 
			
		||||
    parser = argparse.ArgumentParser(formatter_class=argparse.RawDescriptionHelpFormatter,
 | 
			
		||||
        description="""
 | 
			
		||||
Run 'command', wait for a window to open, then exit. If no window
 | 
			
		||||
appears in 'timeout' seconds (eg by running a non-GUI program like
 | 
			
		||||
'date') then terminate.
 | 
			
		||||
""",
 | 
			
		||||
        epilog=f"""eg.
 | 
			
		||||
 | 
			
		||||
    %(prog)s firefox # this gives time for the window to be created before:
 | 
			
		||||
    {msg} -q "floating disable; border none"
 | 
			
		||||
 | 
			
		||||
To run more complex commands use "--". eg.
 | 
			
		||||
 | 
			
		||||
    %(prog)s -- bash -c "some complex bash commands"
 | 
			
		||||
 | 
			
		||||
This may be similar to the ancient Sun OpenWindows command toolwait or
 | 
			
		||||
the X11 version at
 | 
			
		||||
http://www.ibiblio.org/pub/linux/X11/xutils/toolwait-0.9.tar.gz
 | 
			
		||||
    """)
 | 
			
		||||
    parser.add_argument('-n', '--nocheck', dest='nocheck', action='store_true',
 | 
			
		||||
                        help='don\'t check that the window that opens is for that command (default = %(default)s)')
 | 
			
		||||
    parser.add_argument('-v', '--verbose', dest='verbose', action='store_true', help='verbose operation')
 | 
			
		||||
    parser.add_argument('-m', '--mark', dest='mark', type=str, help='mark to add to window', default='')
 | 
			
		||||
    parser.add_argument('-t', '--timeout', dest='timeout', type=float, help='timeout (default = %(default)s secs)', default=30.0)
 | 
			
		||||
    parser.add_argument('-w', '--waitfor', dest='waitfor', help='app_id (wayland) or instance string (xwayland) to wait for (default is the program name)')
 | 
			
		||||
    parser.add_argument('-c', '--count', dest='count', type=int, help='number of windows to wait for (default 1)', default=1)
 | 
			
		||||
    parser.add_argument('command', nargs='+', help='command to run')
 | 
			
		||||
    args = parser.parse_args()
 | 
			
		||||
    args.id = 0
 | 
			
		||||
 | 
			
		||||
    i3 = Connection()
 | 
			
		||||
    i3.on('window::new', on_window)
 | 
			
		||||
 | 
			
		||||
    retval = 1
 | 
			
		||||
    start_time = time.time()
 | 
			
		||||
    count = args.count
 | 
			
		||||
 | 
			
		||||
    # run the command without waiting ie in background:
 | 
			
		||||
    Process(target=sleep_and_run_command, daemon=True).start()
 | 
			
		||||
    i3.main(timeout=args.timeout)
 | 
			
		||||
 | 
			
		||||
    # i3ipc gives no indication that a timeout has occured, so check the clock:
 | 
			
		||||
    elapsed_time = time.time() - start_time
 | 
			
		||||
    if elapsed_time <= args.timeout:
 | 
			
		||||
        verbose(f"'{args.command} took {elapsed_time}secs to create its first window")
 | 
			
		||||
        retval = 0
 | 
			
		||||
    else:
 | 
			
		||||
        verbose(f"timed out after {args.timeout} secs")
 | 
			
		||||
 | 
			
		||||
    if args.mark != '':
 | 
			
		||||
        mark_cmd = f'{msg} -q mark "{args.mark}"'
 | 
			
		||||
        verbose(f"Running: {mark_cmd}")
 | 
			
		||||
        subprocess.run(mark_cmd, shell=True)
 | 
			
		||||
 | 
			
		||||
    verbose(f"terminating, retval={retval}")
 | 
			
		||||
    print(args.id)
 | 
			
		||||
    sys.exit(retval)
 | 
			
		||||
 | 
			
		||||
# Local variables:
 | 
			
		||||
# mode: python
 | 
			
		||||
# time-stamp-pattern: "4/TIME_STAMP=\"%:y%02m%02d.%02H%02M%02S\""
 | 
			
		||||
# eval: (add-hook 'before-save-hook 'time-stamp)
 | 
			
		||||
# End:
 | 
			
		||||
							
								
								
									
										39
									
								
								scripts/workspaces.sh
									
										
									
									
									
										Executable file
									
								
							
							
						
						
									
										39
									
								
								scripts/workspaces.sh
									
										
									
									
									
										Executable file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,39 @@
 | 
			
		|||
#!/bin/bash
 | 
			
		||||
 | 
			
		||||
# Set workspace names/number
 | 
			
		||||
ws1=1
 | 
			
		||||
ws2=2
 | 
			
		||||
ws3=3
 | 
			
		||||
ws5=5
 | 
			
		||||
ws6=6
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#Split the binary and the options so we can optionally run w/ or w/o the option
 | 
			
		||||
# full path to the toolwait binary itself
 | 
			
		||||
TOOLWAITBIN="/home/kellya/.config/sway/scripts/i3-toolwait"
 | 
			
		||||
# Options to pass
 | 
			
		||||
TOOLWAITOPTIONS="--nocheck"
 | 
			
		||||
# binary, with options
 | 
			
		||||
TOOLWAIT="$TOOLWAITBIN $TOOLWAITOPTIONS"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
swaymsg workspace $ws6
 | 
			
		||||
$TOOLWAIT --waitfor org.mozilla.thunderbird /usr/bin/thunderbird
 | 
			
		||||
$TOOLWAIT --waitfor logseq /home/kellya/bin/logseq
 | 
			
		||||
 | 
			
		||||
# Start spotify
 | 
			
		||||
swaymsg workspace $ws5
 | 
			
		||||
$TOOLWAIT -- /usr/bin/flatpak run --branch=stable --arch=x86_64 --command=spotify --file-forwarding com.spotify.Client
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
swaymsg workspace $ws2
 | 
			
		||||
$TOOLWAITBIN --waitfor slack -- flatpak run com.slack.Slack
 | 
			
		||||
$TOOLWAIT --waitfor teams-for-linux -- /opt/teams-for-linux/teams-for-linux --optInTeamsV2 true
 | 
			
		||||
 | 
			
		||||
swaymsg workspace $ws1
 | 
			
		||||
$TOOLWAITBIN --waitfor org.mozilla.firefox firefox
 | 
			
		||||
 | 
			
		||||
# Switch to the terminal/email workspace by default
 | 
			
		||||
swaymsg workspace $ws3
 | 
			
		||||
$TOOLWAIT --waitfor kitty kitty
 | 
			
		||||
$TOOLWAIT --waitfor 1password 1password
 | 
			
		||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue