You can actually do this without a third party script. Openbox supports an extensive range of per-application settings.
Creating an app-specific rule
Application rules are matched against different properties like the window name, class, role or title. Most of these properties can be obtained for a specific window by running
obxprop | grep "^_OB_APP"
and clicking on the window in question.
Seeing how you are planning to specify the rule for a Chrome extension window you might want to supply as many matching properties as possible so as to make the rule as specific as possible. You don't want it to apply to all Chrome windows. Try out different matching properties and see what works best for you.
Having defined the matching window you can set different properties that will exclusively apply to the window/application in question. Here's an excerpt of the default rc.xml
which describes all available properties:
# each rule element can be left out or set to 'default' to specify to not
# change that attribute of the window
<decor>yes</decor>
# enable or disable window decorations
<shade>no</shade>
# make the window shaded when it appears, or not
<position force="no">
# the position is only used if both an x and y coordinate are provided
# (and not set to 'default')
# when force is "yes", then the window will be placed here even if it
# says you want it placed elsewhere. this is to override buggy
# applications who refuse to behave
<x>center</x>
# a number like 50, or 'center' to center on screen. use a negative number
# to start from the right (or bottom for <y>), ie -50 is 50 pixels from
# the right edge (or bottom). use 'default' to specify using value
# provided by the application, or chosen by openbox, instead.
<y>200</y>
<monitor>1</monitor>
# specifies the monitor in a xinerama setup.
# 1 is the first head, or 'mouse' for wherever the mouse is
</position>
<size>
# the size to make the window.
<width>20</width>
# a number like 20, or 'default' to use the size given by the application.
# you can use fractions such as 1/2 or percentages such as 75% in which
# case the value is relative to the size of the monitor that the window
# appears on.
<height>30%</height>
</size>
<focus>yes</focus>
# if the window should try be given focus when it appears. if this is set
# to yes it doesn't guarantee the window will be given focus. some
# restrictions may apply, but Openbox will try to
<desktop>1</desktop>
# 1 is the first desktop, 'all' for all desktops
<layer>normal</layer>
# 'above', 'normal', or 'below'
<iconic>no</iconic>
# make the window iconified when it appears, or not
<skip_pager>no</skip_pager>
# asks to not be shown in pagers
<skip_taskbar>no</skip_taskbar>
# asks to not be shown in taskbars. window cycling actions will also
# skip past such windows
<fullscreen>yes</fullscreen>
# make the window in fullscreen mode when it appears
<maximized>true</maximized>
# 'Horizontal', 'Vertical' or boolean (yes/no)
In your specific case you will be interested in specifying the layer
and desktop
of the application. Here's an example of a rule that would designate all windows of a specific application to be always on top and omnipresent on all available desktops:
<application name="miniplayer" class="miniplayer" type="normal">
<layer>above</layer>
<desktop>all</desktop>
</application>
I chose an arbitrary application name and class for this example. As stated before you will have to make sure to find the correct values for your specific application.
Edit: I looked into your specific application and came up with a rule that works on my system:
<application name="crx_npngaakpdgeaajbnidkkginekmnaejbi" class="Google-chrome" type="normal" role="pop-up">
<layer>above</layer>
<desktop>all</desktop>
</application>
I hope this works for you as well.
Modifiying your openbox configuration to add an app specific rule
To add an application rule open your openbox rc.xml
(found under ~/.config/openbox/rc.xml
for stock openbox or ~/.config/openbox/lxde-rc.xml
for LXDE) and navigate to the <applications>
section at the very end of the file.
Insert your application specific rules between the <applications>..</applications>
tags. Then save the file and proceed to reload the configuration by executing:
openbox --reconfigure
The application specific rules should be in effect after this and will automatically get applied to newly spawned windows.
1. Script to swap all windows from screen 1 --> screen 2 and vice versa
The script assumes the screens are of the same vertical resolution, and the left screen is the primary one. The horizontal resolutions of both screens is searched by the script.
How to set up
The script needs wmctrl
to be installed:
sudo apt-get install wmctrl
- Copy the script below into an empty file, save it as
swap_windows
(no extension) in ~/.bin
. Create the directory if it doesn't exist already, and make the script executable.
- If you just created the directory
~/bin
(it didn't exist yet), either log out/in or run in a terminal: source ~/.profile
.
test run the script with the command:
swap_windows
If all works as expected, add shortut key; choose: System Settings > "Keyboard" > "Shortcuts" > "Custom Shortcuts". Click the "+" and add the command
The script
#!/usr/bin/env python3
import subprocess
import sys
def get(cmd):
return subprocess.check_output(["/bin/bash", "-c", cmd]).decode("utf-8")
def get_shiftright(xr_output):
lines = [l for l in xr_output.splitlines() if "+0+0" in l][0].split()
return int([it for it in lines if "x" in it][0].split("x")[0])
def get_shiftleft(xr_output):
lines = [l for l in xr_output.splitlines() if "+0" in l and not "+0+0" in l][0].split()
return -int([it for it in lines if "x" in it][0].split("x")[0])
def swap_windows():
xr_output = get("xrandr")
shift_r = get_shiftright(xr_output)
shift_l = get_shiftleft(xr_output)
w_data = [l.split() for l in get("wmctrl -lG").splitlines()]
for w in w_data:
props = get("xprop -id "+w[0])
if any(["_TYPE_NORMAL" in props, "TYPE_DIALOG" in props]):
if 0 < int(w[2]) < shift_r:
shift = shift_r
elif shift_r-shift_l > int(w[2]) >= shift_r:
shift = -shift_r
else:
shift = 0
command = "wmctrl -ir "+w[0]+" -e 0,"+(",").join([str(int(w[2])+shift), str(int(w[3])-28), w[4], w[5]])
subprocess.Popen(["/bin/bash", "-c", command])
swap_windows()
2. Script to move (all) windows from one monitor to the other
The script below moves windows in a dual monitor setup from one screen to another, either:
Depending on the argument you run it with (left
or right
)
The script (again) assumes the screens are of the same vertical resolution, and the left screen is the primary one. The horizontal resolutions of both screens is searched by the script.
How to set up
The script needs wmctrl
to be installed:
sudo apt-get install wmctrl
- Copy the script below into an empty file, save it as
shift_windows
(no extension) in ~/.bin
. Create the directory if it doesn't exist already, and make the script executable.
- If you just created the directory
~/bin
(it didn't exist yet), either log out/in or run in a terminal: source ~/.profile
.
test run the script with the commands
shift_windows right
and:
shift_windows left
In the first case, windows on your left screen should move to the right screen and in the second case vice versa.
- If all works as expected, add the script to two shortcut combinations: choose: System Settings > "Keyboard" > "Shortcuts" > "Custom Shortcuts". Click the "+" and add the commands as explained above.
The script
#!/usr/bin/env python3
import subprocess
import sys
vec = sys.argv[1]
def get(cmd):
return subprocess.check_output(["/bin/bash", "-c", cmd]).decode("utf-8")
def get_shiftright(xr_output):
lines = [l for l in xr_output.splitlines() if "+0+0" in l][0].split()
return int([it for it in lines if "x" in it][0].split("x")[0])
def get_shiftleft(xr_output):
lines = [l for l in xr_output.splitlines() if "+0" in l and not "+0+0" in l][0].split()
return -int([it for it in lines if "x" in it][0].split("x")[0])
def shift_windows():
xr_output = get("xrandr")
shift_r = get_shiftright(xr_output)
shift_l = get_shiftleft(xr_output)
w_data = [l.split() for l in get("wmctrl -lG").splitlines()]
for w in w_data:
props = get("xprop -id "+w[0])
if vec == "right":
check = (0 < int(w[2]) < shift_r, "_TYPE_NORMAL" in props, "TYPE_DIALOG" in props).count(True)
shift = shift_r
if vec == "left":
check = (shift_r-shift_l > int(w[2]) >= shift_r , "_TYPE_NORMAL" in props, "TYPE_DIALOG" in props).count(True)
shift = -shift_r
if check == 2:
command = "wmctrl -ir "+w[0]+" -e 0,"+(",").join([str(int(w[2])+shift), str(int(w[3])-28), w[4], w[5]])
subprocess.Popen(["/bin/bash", "-c", command])
shift_windows()
3. Move a single window from one screen to another
Although not literally your question, with just a few lines more, you can either move all windows from one screen to the other, but also a single one (the frontmost) with a key combination.
With the script below, you can move all windows with the command:
shift_windows right
or move a single window with the command:
shift_windows right s
The setup is pretty much the same as the script above (don't forget to install wmctrl
)
The script
#!/usr/bin/env python3
import subprocess
import sys
vec = sys.argv[1]
try:
n = sys.argv[2]
except IndexError:
n = "a"
def get(cmd):
return subprocess.check_output(["/bin/bash", "-c", cmd]).decode("utf-8")
def get_shiftright(xr_output):
lines = [l for l in xr_output.splitlines() if "+0+0" in l][0].split()
return int([it for it in lines if "x" in it][0].split("x")[0])
def get_shiftleft(xr_output):
lines = [l for l in xr_output.splitlines() if "+0" in l and not "+0+0" in l][0].split()
return -int([it for it in lines if "x" in it][0].split("x")[0])
def shift_windows():
xr_output = get("xrandr")
shift_r = get_shiftright(xr_output)
shift_l = get_shiftleft(xr_output)
w_data = [l.split() for l in get("wmctrl -lG").splitlines()]
if n == "s":
frontmost = [l for l in get("xprop -root").splitlines() if "_NET_ACTIVE_WINDOW(WINDOW)" in l][0].split()[-1]
frontmost = frontmost[:2]+"0"+frontmost[2:]
w_data = [l for l in w_data if frontmost in l]
for w in w_data:
props = get("xprop -id "+w[0])
if vec == "right":
check = (0 < int(w[2]) < shift_r, "_TYPE_NORMAL" in props, "TYPE_DIALOG" in props).count(True)
shift = shift_r
if vec == "left":
check = (shift_r-shift_l > int(w[2]) >= shift_r , "_TYPE_NORMAL" in props, "TYPE_DIALOG" in props).count(True)
shift = -shift_r
if check == 2:
command = "wmctrl -ir "+w[0]+" -e 0,"+(",").join([str(int(w[2])+shift), str(int(w[3])-28), w[4], w[5]])
subprocess.Popen(["/bin/bash", "-c", command])
shift_windows()
Best Answer
Moving all windows of a specific window class to a specific screen by (screen-) name
The script below will send windows, belonging to a specific
WM_CLASS
(application), to a specific screen, by the screen's name. How that is done is explained in the script and also further below.The script assumes the screens are arranged horizontally, and more or less top- aligned (with a difference < 100 PX).
The script
How to use
The script needs both
wmctrl
andxdotool
:Copy the script below into an empty file, save it as
move_wclass.py
Run it by the command:
for example:
For the
WM_CLASS
, you may use part of theWM_CLASS
, like in the example. The screen's name needs to be the exact and complete name.How it is done (the concept)
The explanation is mostly on the concept, not so much on the coding.
In the output of xrandr, for every connected screen, there is a string/line, looking like:
This line gives us information on the screen's position and its name, as explained here.
The script lists the information for all screens. When the script is run with the screen and the window class as arguments, it looks up the (x-) position of the screen, looks up all windows (-id's) of a certain class (with the help of
wmctrl -l
and the output ofxprop -id <window_id>
.Subsequently, the script moves all windows, one by one, to a position on the targeted screen (using
wmctrl -ir <window_id> -e 0,<x>,<y>,<width>,<height>
) and maximizes it (withxdotool windowsize 100% 100%
).Note
The script worked fine on the tests I ran it with. Using
wmctrl
, and evenxdotool
, on Unity can have some stubborn peculiarities however that sometimes need to be solved by experiment rather than reasoning. If you might run into exceptions, please mention.