loading...
Cover image for How I open and resize all my applications with just a keyboard shortcut

How I open and resize all my applications with just a keyboard shortcut

ricardo93borges profile image Ricardo Borges Updated on ・4 min read

Every morning I have to open, resize and and reposition all applications I need to work, so I thought: What if I only had to press a keyboard shortcut that could do that for me...

To make this happen I would need to write a script that will be executed by that shortcut, this script would have to do three tasks: Open applications, wait for it to start and resize and reposition it.

Before continuing, this was developed and tested on Pop!_OS 20.04 LTS, a Ubuntu-based Linux distro. The source code is here. I could just use suspend mode, but I use dual boot, so that doesn't always works for me, and exploring other tools to find a solution is way more fun.

This script was written in Python 3.8, I called it desktop-bootstrap.py, to open the applications I used the subprocess module. And to resize and reposition I used the command line tool wmctrl. The script accepts arguments, so you can open one application at a time, but it also support a configuration file to open a set of applications, I'll cover in this article the latter approach.

In each line of the configuration file you write the application you want to open, the command to open it, size an position, like this:

<command> <Application name> <X Axios> <Y Axios> <Window width> <Window height>

An example of configuration file would be:

insomnia insomnia 960 0 960 1080
google-chrome google 0 0 960 1080 https://dev.to/ricardo93borges https://github.com/ricardo93borges

Note that most browsers accepts as arguments the websites to open when it starts, each website open in a different tab, so we'll take advantage of that. You can name the configuration file as config-sample.txt.

Now we need a shell script that will be executed when we use the keyboard shortcut, this shell script will call the python script passing as argument the location of the configuration file. I want to open a terminal too, so I also included the command to do so in the shell script:

# desktop-bootstrap.sh

#!/bin/sh
gnome-terminal --geometry 170x25+1920+890 --working-directory=/home
/usr/bin/python3.8 /path/to/desktop-bootstrap.py --file /path/to/config-sample.txt

Here is the python script with comments to explain some pieces of the code:

# desktop-bootstrap.py

import subprocess
import time
import sys

"""
I limited the retries, so the script don't run 
forever waiting for a application to start 
"""
max_retries = 20

"""
This method get an application ID looking for its name 
in a list obtained by a wmctrl command, 
that ID is used in the resize command
"""
def get_id_by_name(applications_running, name):
    for app in applications_running:
        if app.lower().find(name) > -1:
            return app.split(' ')[0]

"""
This method receives a list of applications and 
for each one check if is running. If is running resize and 
reposition it, if not check again in the next iteration
"""
def resize(applications):
    retry = 0
    while len(applications) > 0:
# Get a list of running applications
        applications_running = subprocess.check_output(["wmctrl", "-lp"]).decode("utf-8").split("\n")
        for index, app in enumerate(applications):
            application_id = get_id_by_name(applications_running, app['name'])
            if application_id:
# Resize and reposition
                dimensions = "-e " f"0,{app['x']},{app['y']},{app['width']},{app['height']}"
                command = ["wmctrl", "-i", "-r", application_id, dimensions]
                subprocess.run(command)
                applications.pop(index)

        retry += 1
        if retry > max_retries:
            break

        time.sleep(5)

"""
This method open the application and send it to 
resize() method to resize and reposition it 
accordingly to the arguments passed
"""
def handle_args():
    command = [sys.argv[1]]

"""
If the application is a browser it may have more 
arguments (the websites to open when it starts)
"""
    for i in range(len(sys.argv) - 7):
        command.append(sys.argv[7 + i])

    output = subprocess.Popen(command)

    applications = [{
        'name': sys.argv[2],
        'pid': output.pid,
        'x': sys.argv[3],
        'y': sys.argv[4],
        'width': sys.argv[5],
        'height': sys.argv[6]
        }]

    resize(applications)

"""
This method handle the configuration file, open 
the applications and send it to resize() method 
to resize and reposition it.
"""
def handle_file(file):
    applications = []
    with open(file) as f:
        for index, line in enumerate(f):
            props = line.split(' ')
            command = [props[0]]

"""
If the application is a browser it may have 
more arguments (the websites to open when it starts)
"""
            for i in range(len(props) - 6):
                command.append(props[6+i])

            output = subprocess.Popen(command)
            applications.append({
                'name': props[1],
                'pid': output.pid,
                'x': props[2],
                'y': props[3],
                'width': props[4],
                'height': props[5]
            })
    resize(applications)

"""
Main method, check the arguments and call the 
appropriated method to process the applications.
"""
def run():
    if len(sys.argv) > 2:
        if sys.argv[1] == "--file":
            handle_file(sys.argv[2])
        else:
            handle_args()
    else:
        print("\nInvalid number of arguments")
        print("\nUse the following arguments: ")
        print("\n<command> <Application name> <X Axios> <Y Axios> <Window width> <Window height>")
        print("\nOr: ")
        print("\n--file <path/to/configuration/file>")

    sys.exit(0)


run()

Finally, we'll create the keyboard shortcut, this may differ from one Linux distribution to another, in Pop_OS! 20.04 you open settings menu go to keyboard shortcuts, then scroll to down to the bottom of the list of shortcuts and click on the + button. In the window that launched you set a name for the shortcut, in the command input you type the path to that shell script (desktop-bootstrap.sh), for example: /home/ricardo/workspace/desktop-bootstrap/desktop-bootstrap.sh. In shortcut you choose the combinations of keys that will execute the shell script.

And that's it, you can find more details on this repository.

Discussion

pic
Editor guide
Collapse
thiagoa profile image
Thiago Araújo Silva

Cool script! On my end, I use devilspie2 to monitor new windows and do whatever I want with them. That along with Gnome's automatic shortcuts for favorite applications (Win+1, Win+2, ..., until Win+9) makes the process lazy for me because I just trigger the shortcut to open the app and its window appears exactly where I want. Here is my configuration file in Lua.

I imagine your script might have a few edge cases to deal with. For instance, I think you should match by WM_CLASS instead of window title. If there's an unrelated window with "google" in its title and it appears before Google Chrome, your script will probably resize the wrong window. For that, you should probably use wmctrl -xl, which will also print out the application's WM_CLASS, and then parse the output.

I even use this trick in my Lua config file to figure out how many Chrome windows are open and only act on the window if it's the first one.

Collapse
twright profile image
Thomas Wright

On the one hand I can see many uses of such a script. On the other hand, I cannot help seeing a shorter alternative article:
"Every morning I have to open, resize and and reposition all applications I need to work, so I thought: What if I used suspend/hibernate?"

This alternative aside, I believe KDE and some other desktop environments have "restore previous session" options although, last time I checked this did not extend to restoring window positions. Perhaps this could make a useful gnome shell extension?

Collapse
ricardo93borges profile image
Ricardo Borges Author

I use dual boot, so suspend mode is not a option for me. I could use hibernate but I have learn more writing my own solution.

Collapse
twright profile image
Thomas Wright

Fair enough; I do see the value of such a tool even if I would not necessarily use it. This is one of the reasons I very rarely boot into windows these days, alongside the hour of Windows updates I incur every time I do so. I also keep too much other state in RAM such as my browser tabs, my tmux session, and my open jupyter notebooks to want to reboot frequently. My applications also tend to be spread over ~8 virtual desktops, which would be interesting to try and restore programmatically.

Collapse
pgronkievitz profile image
Patryk Gronkiewicz

Wouldn't it be easier to use tiling window manager rather than regular desktop environment? Most of them support floating windows, so I don't think it's the problem

Collapse
sakshatshinde profile image
Sakshat

Exactly what I was thinking. There are some easy to configure tiling window managers like awesome or i3 with a good amount of tutorials for beginners.

Collapse
kvanrooyen profile image
Keagan Van Rooyen

Anything like that for Mac?

Collapse
pgronkievitz profile image
Collapse
beernutz profile image
beernutz

Here are a couple options for doing this in Windows.
Free: winsize2.sourceforge.net
Paid: $29, but MUCH more full-featured: displayfusion.com

Both of them are super easy to set up, and don't require coding or text file editing if you would rather spend your mental cycles on other things.

Collapse
gwutama profile image
Galuh Utama

Not bad!

I’m too lazy though, so I just put my laptop and pc to sleep so I can get everything ready just as I left them.

Collapse
johannesjo profile image
Johannes Millan

Another a little bit more flexible alternative for doing this (sorry for the shameless self promotion):
github.com/johannesjo/linux-window...

Collapse
ricardo93borges profile image
Ricardo Borges Author

It's okay, I wrote these posts to share knowledge and I'm glad to see comments like yours. I'll take look at it later.

Collapse
jamesbright profile image
James Ononiwu

this is lovely and intuitive