Automatically move the launcher, depending on the active screen
A possible solution is to automatically change the position of the launcher, depending on the current mouse-position:
- if it is on the left screen, move the launcher to left
- if it is on the right screen, move it to the bottom
In the test I ran, it worked surprisingly smooth, and windows adapt well to the change.
The script
#!/usr/bin/env python3
import subprocess
import time
scr_data = subprocess.check_output(["xrandr"]).decode("utf-8")
border = int([s.split("x")[0] for s in scr_data.split() if "+0+0" in s][0])
left_scr = [l.split()[0] for l in scr_data.splitlines() if "+0+0" in l][0]
key = "com.canonical.Unity.Launcher"
item = "launcher-position"
def catch_mouse():
return int(subprocess.check_output([
"xdotool", "getmouselocation"
]).decode("utf-8").split()[0].split(":")[1])
test1 = ""
while True:
time.sleep(1)
test2 = catch_mouse() <= border
if test2 != test1:
if test2 == True:
cmd = ["gsettings", "set", key, item, "Left"]
else:
cmd = ["gsettings", "set", key, item, "Bottom"]
subprocess.Popen(cmd)
test1 = test2
How to use
The script needs xdotool
:
sudo apt-get install xdotool
Copy the script into an empty file, save it as move_launcher.py
Test- run it by the command (from a terminal)
python3 /path/to/move_launcher.py
If all works fine, add to Startup Applications: Dash > Startup Applications > Add. Add tghe command:
/binh/bash -c "sleep 15 && python3 && /path/to/move_launcher.py
EDIT
...Or more advanced, only a launcher on the active screen on an arbitrary position.
...a script that will set only one launcher (on the left screen, on the left side):
...while you are working on the left screen. This will give you full size view on the right screen...
...and one launcher at the bottom of the second screen:
...If you move to the right screen, giving you the launcher you need on the desired position on the right screen.
As mentioned, in the test(s), the windows adapted smoothly without an error.
The script
#!/usr/bin/env python3
import subprocess
import time
scr_data = subprocess.check_output(["xrandr"]).decode("utf-8")
border = int([s.split("x")[0] for s in scr_data.split() if "+0+0" in s][0])
left_scr = [l.split()[0] for l in scr_data.splitlines() if "+0+0" in l][0]
right_scr = [l.split()[0] for l in scr_data.splitlines() if all([
not "+0+0" in l, l.count("+") == 2])][0]
key = "com.canonical.Unity.Launcher"
item = "launcher-position"
subprocess.call(["dconf", "write",
"/org/compiz/profiles/unity/plugins/unityshell/num-launchers", "1"])
def catch_mouse():
return int(subprocess.check_output([
"xdotool", "getmouselocation"
]).decode("utf-8").split()[0].split(":")[1])
test1 = ""
while True:
time.sleep(1)
test2 = catch_mouse() <= border
if test2 != test1:
if test2 == True:
cmd1 = ["xrandr", "--output", left_scr, "--primary"]
cmd2 = ["gsettings", "set", key, item, "Left"]
else:
cmd1 = ["xrandr", "--output", right_scr, "--primary"]
cmd2 = ["gsettings", "set", key, item, "Bottom"]
subprocess.Popen(cmd1)
subprocess.call(cmd2)
test1 = test2
To use
- This version runs exactly like the first one.
Note
These are just two examples. Many things are possible.
Two launchers, at the same time on a different position per screen, is currently impossible however, untill someone creates the option...
You can adjust the position of your screen, either using the GUI (In xubuntu, using xfce4-display-settings
, but I'm sure gnome has a equivalent) or using xrandr
.
This is something that you have to do manually, because the computer has no way of knowing the relative physical location between both monitors. They might be top aligned, one might be in the middle, etc. As long as you tell the computer where the second is, you can properly align them based on where they physically are. With a bit of experimentation, you can get something that works very well.
Using the GUI, it is as simple as dragging and dropping. As you can see on the image below, the screen on the right is aligned to the top left of the other one. You can simply click it and drag it, moving it upwards or downwards depending on your preference.
Using xrandr
, the relevant setting is --pos
.
--pos xxy
Position the output within the screen using pixel coordinates. In
case reflection or rotation is applied, the translation is applied
after the effects.
The position 0x0
is the top left corner of all the screens. For example, assuming you have two monitors, a main one, on the left, with a resolution of 1920x1080 and a second one positioned on the right, with the resolution of 1280x960. If their top pixel was physically aligned, you would want to use a command similar to this: xrandr --output SCREENNAME --auto --pos 1920x0
. This indicates that you want it shifted 1920 pixels on the x axis (horizontal) and placed at the pixel 0 on the y axis (vertical). If, instead it was bottom aligned you would instead use: xrandr --output SCREENNAME --auto --pos 1920x120
, which is 1080 minus 960.
Something to help you visualize it.
(virtual screen coordinates) The x margin is 3200 pixels
0 The y margin is 1080 pixels
0 A----------------------- A position is 0x0
| | B position is 1920x120
| |B---------------
| | |
| MAIN | SEC |
| | |
| 1920x1080 | 1280x960 |
| | |
1080 ----------------------------------------
For your setup you probably also want to use --scale
, since the pixel sizes are very different. You'll have to play with the values to get something to your liking, but it's a big trade off. You might be able to get something good looking if you maintain sane proportions.
--scale xxy
Changes the dimensions of the output picture. Values superior to 1
will lead to a compressed screen (screen dimension bigger than the
dimension of the output mode), and values below 1 leads to a zoom
in on the output. This option is actually a shortcut version of the
--transform option.
--scale-from wxh
Specifies the size in pixels of the area of the framebuffer to be
displayed on this output. This option is actually a shortcut
version of the --transform option.
With this information in mind, and knowing the other basics of using xrandr
, like the name of each screen, choosing their resolution, refresh rate, flipping, or any other special settings that you want to use in your setup, you can easily align all of your monitors, so that their physical location match their virtual one. Check man xrandr
for plenty of useful commands.
Best Answer
Create a Mouse Void
This is quite a long answer that I felt is better kept separate from my other one.
So that you understand where this solution came from, my monitor layout is as follows:
The two black area 1280x88 are off the screen but my mouse can still enter this due to an X bug. The workaround is a small program that prevents the mouse entering this void called XCreateMouseVoid.
Home Button Mouse Stopper
You can also use XCreateMouseVoid to create a small box that the mouse will stop against when pushed into the top left corner of the primary screen. This is what I have shown in green area of this image:
Installing
Open the folder in Terminal and run this command:
Test the program with values:
Add to Startup Applications so its always runs upon bootup.
Calculate Values
The values required for XCreateMouseVoid are:
x, y , w, h
For my setup to stop the mouse entering the top and bottom black 1280 x 88 areas along with stopping it travel past the Home Button, I run two instances of the program with these values:
Small Rectangle
If you have a different setup you can create the small rectangle as I mentioned earlier. The rectangle measures 60 x 25, which is the minimum width needed to properly stop the mouse.
The only value you need to change is x which is calculated by subtracting 60 from your secondary monitor's width. e.g. 1280 x 1024 monitor I subtract 60 from 1280 to get the value 1220 for XCreateMouseVoid:
Trapped Mouse Cursor
Occasionally the mouse cursor can jump into the created mouse void and become trapped. The solution is to press either the Super or Menu key so that a menu opens and frees the mouse cursor.