I run a
Matlab script in the
workspace 1. This generates several plots. In the mean time I switch to
workspace 2 and working there. My problem is that the plots are popping up in
workspace 2. Is it possible to lock on software into a workspace.
Matlab generates the plots in
workspace 1, I can work in
workspace 2 without the disruption of the poping up plots?
Ubuntu – How to lock an application (and all its new windows) into a specific workspace
I run a
I don't think that there's such a function for the standard window manager.
But Devil's Pie can do what you want.
Quote from Devil's Pie website: "Devil's Pie can be configured to detect windows as they are created, and match the window to a set of rules. If the window matches the rules, it can perform a series of actions on that window. For example, I can make all windows created by X-Chat appear on all workspaces, and the main Gkrellm1 window does not appear in the pager or task list."
I hope this helped you,
It can be done very well, but you need some understanding on Unity/viewports. I hope the story below is understandable, if not, please leave a comment.
The script below can be used to open a window of any application on any of your viewports, on any position, if you run it with the right arguments. The script is an edited version of this one, but now prepared to place windows on the spanning virtual desktop.
1. Understanding viewports and window coordinates
Workspaces in Unity
In Unity, unlike other window managers, you actually only have one spanning workspace, which is divided into viewports. In your case, your workspace is divided into eight viewports.
How the position of the windows is defined
The window position, as the output of the command:
wmctrl -lG (you need to have wmctrl installed to run the command)
is described as the position, relative to the upper left corner of the current viewport:
So if you are on viewport
a window on viewport 2 to could be positioned on e.g. 1700 (x-wise) x 500 (y-wise)
(my screen is 1680x1050)
However, if you are on viewport 6:
the same window would be positioned on 20 (x), -550 (y)
Using these coordinates correctly is important to run the script with the right arguments, as described below:
2. How to use the script
The script below can be used to place a new window of an application on your virtual (spanning) workspace.
sudo apt-get install wmctrl
Copy the script below into an empty file, save it as
setwindow(no extension) in
~/bin. Create the directory if it doesn't exist yet. Make the script executable.
- If you just created
~/bin, either run the command
source ~/.profileor log out/in to make the directory available in
Test run the command:
setwindow <application> <x_position> <y_position> <horizontal_size> <vertical_size>
setwindow gedit 100 100 200 200
A gedit window should show up on the current viewport.
- Keep in mind that not all applications allow window sizes below a certain width or height. The minimum width of a
geditwindow on my system is e.g. appr. 470 px.
- The script only works fine if the whole window fits on the targeted viewport, choose your coordinates/sizes accordingly. Also mind that the Unity Launcher and the panel use some space (!) which can influence the position of the window.
- Use negative
<x_position>to place windows on the left of the current viewport(s)
- Use negative
<y_position>to place windows above the current viewport(s)
To open new windows on different viewports at once, you can simply chain commands. Looking at the viewport setup in the "Long story" example, If I am on viewport 1, I can open gedit windows on viewport 1, 2, 3 and 4 with the command:
setwindow gedit 100 100 200 200&&setwindow gedit 1780 100 200 200&&setwindow gedit 3460 100 200 200&&setwindow gedit 5140 100 200 200
#!/usr/bin/env python3 import subprocess import time import sys app = sys.argv get = lambda x: subprocess.check_output(["/bin/bash", "-c", x]).decode("utf-8") ws1 = get("wmctrl -lp"); t = 0 subprocess.Popen(["/bin/bash", "-c", app]) # fix exception for Chrome (command = google-chrome-stable, but processname = chrome) app = "chrome" if "chrome" in app else app while t < 30: ws2 = [w.split()[0:3] for w in get("wmctrl -lp").splitlines() if not w in ws1] procs = [[(p, w) for p in get("ps -e ww").splitlines() \ if app in p and w in p] for w in ws2] if len(procs) > 0: w_id = procs cmd1 = "wmctrl -ir "+w_id+" -b remove,maximized_horz" cmd2 = "wmctrl -ir "+w_id+" -b remove,maximized_vert" cmd3 = "wmctrl -ir "+procs+" -e 0,"+sys.argv+","+sys.argv+","+sys.argv+","+sys.argv for cmd in [cmd1, cmd2, cmd3]: subprocess.call(["/bin/bash", "-c", cmd]) break time.sleep(0.5) t = t+1
EDIT: the lazy version
In case you'd prefer to just enter coordinates and size, simply as if you would open a window on the current viewport, and give the targeted viewport as an argument (without having to calculate anything), then use the version below...
If you set it up like the first version of the script, you can run it with the command:
setwindow <application> <x_position> <y_position> <horizontal_size> <vertical_size> <targeted_viewport>
An example: to open a
Google-Chrome window positioned on
20, 20, size
300x300, on viewport
setwindow google-chrome 20 20 300 300 5
The setup is pretty much the same as the first version of the script.
Note that also this script only works correctly if the defined window (position/size) fits completely within the targeted viewport.
#!/usr/bin/env python3 import subprocess import time import sys app = sys.argv target_vp = int(sys.argv) def get_res(): # get resolution xr = subprocess.check_output(["xrandr"]).decode("utf-8").split() pos = xr.index("current") return [int(xr[pos+1]), int(xr[pos+3].replace(",", "") )] res = get_res() def current(set_vp): # get the current viewport vp_data = subprocess.check_output( ["wmctrl", "-d"] ).decode("utf-8").split() dt = [int(n) for n in vp_data.split("x")] cols = int(dt/res) rows = int(dt/res) curr_vpdata = [int(n) for n in vp_data.split(",")] curr_col = int(curr_vpdata/res) curr_row = int(curr_vpdata/res) curr_vp = curr_col+curr_row*cols+1 # calculate the vector to the origin from the current viewport (in resolution units) vec_curr = vector(curr_vp, cols) # calculate the vector to the origin from the targeted viewport vec_set = vector(set_vp, cols) # calculate the vector between current and targeted viewport vec_relative = [vec_set - vec_curr, vec_set - vec_curr] # calculate needed correction (absolute) relative = [vec_relative*res, vec_relative*res] return relative def vector(vp, cols): rem = vp%cols vec_x = rem-1 if rem != 0 else cols-1 vec_y = int((vp-1)/cols) return [vec_x, vec_y] res = get_res() # nieuw get = lambda x: subprocess.check_output(["/bin/bash", "-c", x]).decode("utf-8") ws1 = get("wmctrl -lp"); t = 0 # check for additional arguments to run the application try: subprocess.Popen(["/bin/bash", "-c", app+" "+sys.argv]) except IndexError: subprocess.Popen(["/bin/bash", "-c", app]) # fix exception for Chrome (command = google-chrome-stable, but processname = chrome) app = "chrome" if "chrome" in app else app while t < 30: ws2 = [w.split()[0:3] for w in get("wmctrl -lp").splitlines() if not w in ws1] procs = [[(p, w) for p in get("ps -e ww").splitlines() \ if app in p and w in p] for w in ws2] if len(procs) > 0: w_id = procs cmd1 = "wmctrl -ir "+w_id+" -b remove,maximized_horz" cmd2 = "wmctrl -ir "+w_id+" -b remove,maximized_vert" # calculate the correction, related to the current workspace, marge for launcher and panel pos_x = int(sys.argv); pos_y = int(sys.argv); x_marge = 65; y_marge = 35 pos_x = pos_x if pos_x > x_marge else x_marge; pos_y = pos_y if pos_y > y_marge else y_marge x_relative = pos_x+current(target_vp) y_relative = pos_y+current(target_vp) # correct possible inaccurately set width / height x_size = res; y_size = res set_width = int(sys.argv); set_height = int(sys.argv) width = set_width if set_width+x_marge+pos_x < x_size else x_size - pos_x - x_marge height = set_height if set_height+y_marge+pos_y < y_size else y_size - pos_y - y_marge cmd3 = "wmctrl -ir "+w_id+" -e 0,"+str(x_relative)+","+str(y_relative)+","+str(width)+","+str(height) for cmd in [cmd1, cmd2, cmd3]: subprocess.call(["/bin/bash", "-c", cmd]) break time.sleep(0.5) t = t+1
Opening application windows with arguments
To finish the job, answering your question completely:
If you run the script as e.g.:
setwindow google-chrome 20 20 300 300 5
it will open a default window on the targeted desktop(s).
With the latest version of the script however, you can add an additional argument to open the application window, for example a
setwindow <application> <x_position> <y_position> <horizontal_size> <vertical_size> <targeted_viewport> <(optional)_argument>
setwindow google-chrome 0 0 600 600 3 "--new-window http://askubuntu.com"
If the (extra) argument contains spaces, use quotes. The above example will open a
google-chrome window on viewport 3, opening the
You can chain commands to open multiple windows/urls on different workspaces in one command, e.g.:
setwindow google-chrome 0 0 600 600 8 "--new-window http://askubuntu.com"&&setwindow google-chrome 0 0 600 600 7 "--new-window www.google.com"
Below a rewritten version of the script from the first answer (below). The differences:
WM_CLASSand the targeted workspace are now arguments to run the script. Only use either the first or the second (identifying) part of the
WM_CLASS(see further below: how to use)
When the script starts, it shows a notification (example
How to use
The script needs both
Copy the script above into an empty file, save it as
Of your specific application, find out the
WM_CLASS: open your application, run in a terminal:
The output will look like (in your case):
Either use the first or the second part in the command to run the script.
The command to run the script then is:
In the command, the last section;
2,2is the workspace where you want to lock the application to (without spaces: (!) column, row), in "human" format; the first column/row is
(second) TEST VERSION
The script below locks a specific application to its initial workspace. If the script is started, it determines on which workspace the application resides. All additional windows the application produces will be moved to the same workspace in a split second.
The focus issue is solved by automatically re- focussing on the window that was focussed before the additional window was produced.
How to use
The script needs both
Copy the script into an empty file, save it as
determine your application's `WM_CLASS' by opening the application, then open a terminal and run the command:
Then click on your application's window. Copy the output, looking like
"sun-awt-X11-XFramePeer", "MATLAB R2015a - academic use"in your case, and place it between single quotes in the head section of the script, as indicated.
Run the script with the command:
If it works as you like, I'll add a toggle function. Although it works already for a few hours on my system, bu it might need some tweaking first however.
Although you should not notice it, the script does add some processor load to the system. On my elderly system I noticed an increase of 3-10%. If you like how it works, I will probably further tweak it to reduce the load.
The script, as it is, assumes the secundary windows are of the same class as the main window, like you indicated in a comment. With a (very) simple change, the secondary windows can be of another class however.
Although probably not very interesting for an average reader, the script works by calculating in vectors. On startup, the script calculates:
From then on, the script looks for new windows of the same application, with the output of
xprop WM_CLASS, looks up their position in the same way as above and moves them to the "original" workspace.
Since the newly created window "stole" the focus from the last used window the user was working on, the focus is subsequently set to the window that had focus before.