Open application window on the same screen as where It was launched

Unity uses Compiz as composing manager, and that has all sorts of plugins for this sort of stuff. To make it easy and long story short without messing in command line , install Compiz Config Settings Manager ( with sudo apt-get install compizconfig-settings-manager or via Software Center ) , and look for Place Windows , ensure it's checked

enter image description here

Under that plugin there will be several options for Multi Output Mode . What you want is Use output device of focused window . Thus it will place open file window wherever your file manager is enter image description here


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).

<image>

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):

    1. To change the main command of the launcher:

      • find the line:

        Exec=/usr/bin/google-chrome-stable %U
        
      • change it to

        Exec=/bin/bash -c "open_oncurrent /usr/bin/google-chrome-stable"
        
    2. 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)