Can I set Hot Corners to run custom commands in Unity?

Solution 1:

CCSM

  1. Install CompizConfig Settings Manager (CCSM). Run in terminal:

    sudo apt-get install compizconfig-settings-manager
    
  2. Open CCSM.

  3. Go to "Commands"
  4. Enter your desired command in one of the slots. E.g:

    CCSM screenshot - command

  5. Go to "Edge Bindings" tab

  6. Click "None" and set your desired hot corner (or edge), which corresponds to the command you just set

    CCSM screenshot - hot corners

  7. Move your mouse to the corner

  8. Now your command is run!

    CCSM screenshot - command running

Confirmed working on 14.04.

Solution 2:

Custom commands

If you are using Unity and have ccsm installed, wjandrea's answer is your answer of course. If not, or to use on other distros, a light weight alternative might be useful.

With the script below, you can set any command, specific to each of your hotcorners.

As an example, I made the following setup:

  • Top Left No action
  • Top Right Run Gedit
  • Bottom Left No action
  • Bottom RightRun Gnome-terminal

Of course you can also make the commands run external scripts.

Furthermore, you can set the size of the hot corner in the line:

cornersize = 10

Simply change the value (pixels). The script sets (square) areas to trigger your commands:

enter image description here

The script

#!/usr/bin/env python3
import subprocess
import time

cornersize = 20

commands = [
    None,
    "gedit",
    None,
    "gnome-terminal",
    ]

def get(cmd):
    return subprocess.check_output(cmd).decode("utf-8").strip()

def get_pos():
    return [int(s.split(":")[1]) for s in get(["xdotool", "getmouselocation"]).split()[:2]]

scrdata = get("xrandr").split(); resindex = scrdata.index("connected")+2
res = [int(n) for n in scrdata[resindex].split("+")[0].split("x")]

match1 = None

while True:
    time.sleep(1)
    xy = get_pos()
    x = xy[0]; y = xy[1]
    test = [
        [x < cornersize, y < cornersize],
        [x > res[0]-cornersize, y < cornersize],
        [x < cornersize, y > res[1]-cornersize],
        [x > res[0]-cornersize, y > res[1]-cornersize],
        ]
    match2 = [i for i, p in enumerate(test) if all(p)]
    if match2 != match1:
        if match2:
            cmd = commands[match2[0]]
            if cmd:
                subprocess.Popen(["/bin/bash", "-c", cmd])
    match1 = match2

Set up

  1. The script needs xdotool

    sudo apt install xdotool
    
  2. Copy the script into an empty file, save i as hotcorners2.py
  3. In the head of the script, set your commands (mind the quotes)

    commands = [
        None,
        "gedit",
        None,
        "gnome-terminal",
    ]
    

    (subsequently top left/righ, bottom left/right)

  4. Test- run the script:

    python3 /path/to/hotcorners2.py
    
  5. If all works fine, add to Startup Applications: Dash > Startup Applications > Add. Add the command:

    /bin/bash -c "sleep 5 && python3 /path/to/hotcorners2.py"
    

Notes

  • The script currently runs on on (the first) screen. It can be easily edited to take care of multiple screens, even do different things in different screens, please mention.
  • If a few people like it, we can add a gui and a ppa for convenient usage and easy installation.

EDIT

If we use a bit more advanced computing, we can use a radius instead of a square area to trigger the commands (thanks to good old @pythagoras):

enter image description here

Small difference, but just for fun:

The script

#!/usr/bin/env python3
import subprocess
import math
import time

# set distance (hotcorner sensitivity)
radius = 20

# top-left, top-right, bottom-left, bottom-right
commands = [
    None,
    "gedit",
    None,
    "gnome-terminal",
    ]

def get(cmd):
    return subprocess.check_output(cmd).decode("utf-8").strip()

def get_pos():
    return [int(s.split(":")[1]) for s in get(["xdotool", "getmouselocation"]).split()[:2]]

# get the resolution
scrdata = get("xrandr").split(); resindex = scrdata.index("connected")+2
res = [int(n) for n in scrdata[resindex].split("+")[0].split("x")]
# list the corners, could be more elegant no doubt
corners = [[0, 0], [res[0], 0], [0, res[1]], [res[0], res[1]]]

match1 = None

while True:
    time.sleep(1)
    pos = get_pos()
    # get the current difference from the mousepointer to each of the corner (radius)
    diff = [int(math.sqrt(sum([(c[i]-pos[i])**2 for i, n in enumerate(res)])))\
            for c in corners]
    # see if any of the corners is "approached" within the radius
    match2 = [diff.index(n) for n in diff if n < radius]
    # if so, and the corresponding command is not set to None, run it.
    if all([match2 != match1, match2]):
        cmd = commands[match2[0]]
        if cmd:
            subprocess.Popen(["/bin/bash", "-c", cmd])
    match1 = match2

Usage

Is pretty much the same. Set your commands, and the radius to trigger, in the head section of the script.

Solution 3:

NOTE:

wjandrea's answer is the most suitable answer for someone who uses default Ubuntu or Ubuntu Kylin ( or has compiz as their display manager ), thus it gets my upvote and respect. The answer provided below, can be used on Unity as well, but probably would be slightly redundant. However, on desktop environments that don't have compiz, one can use the indicator presented below. I've tested it briefly in Lubuntu 16.04 VM , so I know it works there, and made it compatible with Kylin 14.04 as well. For GNOME and MATE desktops, you will need have support for AppIndicators enabled first in order to use any indicator.

Introduction

I've implemented indicator-edger which allows triggering user-defined commands based on mouse position anywhere along the 4 edges of the screen. Original version was done within one day, in approximately 7 hours, thus it is fairly minimalistic but does the job.

enter image description here

The indicator is controlled via ~/.edger-commands.json file , obviously in json format. It can be written manually by the user, or set via indicator's DEFINE COMMANDS option. The enable/disable triggering option is remembered and written automatically to file for user's convenience. Sample configuration file would be like so:

{
    "right": "gnome-terminal",
    "top": "firefox",
    "left": "",
    "bottom": "gnome-screenshot",
    "enabled": true
}

Note the "left" entry in the file. That edge is unset, but due to json syntax it requires having an empty string there, i.e. quotes "".

Once the indicator detects that user has placed the mouse along any of the edges (with ~3 pixel margin), the indicator will send a bubble notification and run the appropriate command (if defined). Activation of the trigger won't repeat unless the user moves the mouse away from the edge.

enter image description here

As you can see from the screenshot above, the indicator also has debugging output in the command-line. If you find any bugs, feel free to run it from the terminal, find out what error occurs, and submit appropriate bug report on issues page of the project's GitHub.

Currently there is no support for corners (only edges) and it was built for one-monitor setup (obviously, one cannot cover all the bases within 7 hours of creation), but those features might be available eventually in the future.

Installation and source code

The source code is available at the projects GitHub page or via Launchpad. Installation is performed via the following commands in terminal:

sudo add-apt-repository ppa:1047481448-2/sergkolo
sudo apt-get update
sudo apt-get install indicator-edger