Redirecting the command to run an application
Most applications open their window on the screen they were initiated from (either from Dash or the launcher). Some applications however do not, but they can be forced to, by redirecting the command to run the application through the script below. To do that, you will need to edit the corresponding .desktop
file (launcher).
The setup seems a bit complicated, but if the procedure is followed ("How to use"), it should not be too difficult at all.
How it works
- The script reads the mouse position at the moment you click the launcher or choose the application from Dash, and determines on which screen that is (left/right).
- Subsquently, it waits for the new window to appear, owned by the application (pid) you started.
- Once the window appears, it checks if the window (screen-) position matches the mouse (screen-) initial position.
- If not, it moves the window to the screen you started the application from. In most cases, the action will be in a (very) early stage of the window's existance, so you even won't notice it.
Issue / solution
There is one downside: if you replace the .desktop
file's main command by the command to call this script, the right-click "open with " will not work properly. In the case of a webbrowser like Google Chrome, that will not be too big a problem. With other applications, a simple solution would be to add the option to open a new window on the current screen as a shortcut (see further below).
How to use:
The script uses both wmctrl
and xautomation
:
sudo apt-get install xautomation
sudo apt-get install wmctrl
Create a directory ~/bin
if it does not exist yet.
Copy the script into an empty file, save it as open_oncurrent
(no extension) in ~/bin
- Make it executable(!)
Copy the corresponding .desktop
file from /usr/share/applications
to ~/.local/share/applications
:
cp /usr/share/applications/google-chrome.desktop ~/.local/share/applications/google-chrome.desktop
Open the local copy in ~/.local/share/applications
:
gedit ~/.local/share/applications/google-chrome.desktop
Edit the file (two options):
To change the main command of the launcher:
To add the option as a shortcut (like in the image above):
find the line:
X-Ayatana-Desktop-Shortcuts=NewWindow;NewIncognito;
replace it by:
X-Ayatana-Desktop-Shortcuts=NewWindow;NewIncognito;New window on this screen;
Then add the following section to the very end of the file:
[New window on this screen Shortcut Group]
Name=New window on this screen
Exec=/bin/bash -c "open_oncurrent /usr/bin/google-chrome-stable"
TargetEnvironment=Unity
How to use with other applications:
Similarly, you can apply the solution to other applications. The syntax of the command to use in the .desktop
fileis like the example:
Exec=/bin/bash -c "open_oncurrent <command>"
A small additional explanation on how to deal with exceptions is in the script.
The script
#!/usr/bin/env python3
import subprocess
import sys
import time
import getpass
t = 0; user = getpass.getuser(); application = sys.argv[1]
"""
In most cases, the command to run an application is the same as the process
name. There are however exceptions, to be listed below, if you use these appli-
cations i.c.w. this script. Just add an item to the list in the format:
["<command>", "<process_name>"],
"""
exceptions = [
["/usr/bin/google-chrome-stable", "chrome"],
]
try:
procname = [app[1] for app in exceptions if app[0] == application][0]
except IndexError:
procname = application
get = lambda cmd: subprocess.check_output(["/bin/bash", "-c", cmd]).decode("utf-8")
# initial position of the mouse (click position)
start_pos = int(get("xmousepos").strip().split()[0])
# x- position of right side of the screen
x_res = [int(s.split("x")[0]) for s in get("xrandr").split() if s.endswith("+0+0")][0]
# current windows
start_windows = get("wmctrl -l")
# open application
subprocess.call(["/bin/bash", "-c", application+"&"])
while t < 30:
procs = get("ps -u "+user).splitlines()
new = [w for w in get("wmctrl -lpG").splitlines() if not w.split()[0] in start_windows]
match = sum([[line for line in procs if w.split()[2] in line and procname[:15] in line] for w in new], [])
if len(match) == 1:
data = new[0].split(); curr_pos = int(data[3]); compare = (start_pos > x_res, curr_pos > x_res)
if compare[0] == compare[1]:
pass
else:
if compare[0] == True:
data[3] = str(int(data[3])+x_res)
else:
data[3] = str(int(data[3])-x_res)
cmd1 = "wmctrl -r "+data[0]+" -b remove,maximized_vert,maximized_horz"
cmd2 = "wmctrl -ir "+data[0]+" -e 0,"+(",").join(data[3:7])
for cmd in [cmd1, cmd2]:
subprocess.Popen(["/bin/bash", "-c", cmd])
break
t = t + 1
time.sleep(0.5)