Procrastinating by tweaking my desktop with devilspie2

2018-04-30 5-minute read

Tweaking my desktop seems to be my preferred form of procrastination. So, a blog like this is a sure sign I have too much work on my plate.

I have a laptop. I carry it to work and plug it into a large monitor - where I like to keep all my instant or near-instant communications displayed at all times while I switch between workspaces on my smaller laptop screen as I move from email (workspace one), to shell (workspace two), to web (workspace three), etc.

When I’m not at the office, I only have my laptop screen - which has to accomdate everything.

I soon got tired of dragging things around everytime I plugged or unplugged the monitor and starting accumulating a mess of bash scripts running wmctrl and even calling my own python-wnck script. (At first I couldn’t get wmctrl to pin a window but I lived with it. But when gajim switched to gtk3 and my openbox window decorations disappeared, then I couldn’t even pin my window manually. NOTE: This behavior has changed - I now have my openbox decorations back on my gajim windows.)

Now I have the following simpler setup.

Manage hot plugging of my monitor.

Symlink to my monitor status device:

0 jamie@turkey:~$ ls -l ~/.config/turkey/monitor.status 
lrwxrwxrwx 1 jamie jamie 64 Jan 15 15:26 /home/jamie/.config/turkey/monitor.status -> /sys/devices/pci0000:00/0000:00:02.0/drm/card0/card0-DP-1/status
0 jamie@turkey:~$ 

Create a udev rule to handle things when the monitor is unplugged (for some reason, automating the detection of the monitor being plugged in was too unreliable).

0 jamie@turkey:~$ cat /etc/udev/rules.d/90-vga.rules 
# When a monitor is plugged in, adjust my display to take advantage of it
ACTION=="change", SUBSYSTEM=="drm", ENV{HOTPLUG}=="1", RUN+="/etc/udev/scripts/vga-adjust"
0 jamie@turkey:~$ 

And here is the udev script:

0 jamie@turkey:~$ cat /etc/udev/scripts/vga-adjust 
#!/bin/bash

logger -t "jamie-udev" "Monitor event detected, waiting 1 second for \
system to detect change."
sleep 1 

# This process seems to be unreliable when alerting the X11 system, so I'm
# only configuring it to tell the X windows system when the monitor is unplugged.
#
# The X11 system adjusts for a monitor being plugged in via the systemd service
# devilspie2 (~/.config/systemd/user/devilspie2.service) which executes a-vga-auto
# via a PreExec command.
#
# We don't know whether the VGA monitor is being plugged in or unplugged so we
# have to autodetect first. And,it takes a few seconds to assess whether the
# monitor is there or not, so sleep for 1 second.
monitor_status="/home/jamie/.config/turkey/monitor.status"
status=$(cat "$monitor_status")  

export XAUTHORITY=/home/jamie/.Xauthority
export DISPLAY=:0
if [ "$status" = "disconnected" ]; then
  # The monitor is not plugged in	
  logger -t "jamie-udev" "Monitor is being unplugged"
  /usr/bin/xrandr --output DP-1 --off
fi
0 jamie@turkey:~$

Move windows into place.

So far, this handles ensuring the monitor is activated and placed in the right position. But, nothing has changed in my workspace.

Here’s where the devilspie2 configuration comes in:

==> /home/jamie/.config/devilspie2/00-globals.lua <==
-- Collect some global varibles to be used throughout.
name = get_window_name();
app = get_application_name();
instance = get_class_instance_name();

-- See if the monitor is plugged in or not. If monitor is true, it is
-- plugged in, if it is false, it is not plugged in.
monitor = false;
device = "/home/jamie/.config/turkey/monitor.status"
f = io.open(device, "rb")
if f then
  -- Read the contents, remove the trailing line break.
  content = string.gsub(f:read "*all", "\n", "");
  if content == "connected" then
    monitor = true;
  end
end


==> /home/jamie/.config/devilspie2/gajim.lua <==
-- Look for my gajim message window. Pin it if we have the monitor.
if string.find(name, "Gajim: conversations.im") then
  if monitor then
    set_window_geometry(1931,31,590,1025);
    pin_window();
  else
    set_window_workspace(4);
    set_window_geometry(676,31,676,725);
    unpin_window();
  end
end

==> /home/jamie/.config/devilspie2/grunt.lua <==
-- grunt is the window I use to connect via irc. I typically connect to
-- grunt via a terminal called spade, which is opened using a-terminal-yoohoo
-- so that bell actions cause a notification. The window is called spade if I
-- just opened it but usually changes names to grunt after I connect via autossh
-- to grunt. 
--
-- If no monitor, put spade in workspace 2, if monitor, then pin it to all
-- workspaces and maximize it vertically.

if instance == "urxvt" then
  -- When we launch, the terminal is called spade, after we connect it
  -- seems to get changed to jamie@grunt or something like that.
  if name == "spade" or string.find(name, "grunt:") then
    if monitor then
      set_window_geometry(1365,10,570,1025);
      set_window_workspace(3);
      -- maximize_vertically();
      pin_window();
    else
      set_window_geometry(677,10,676,375);
      set_window_workspace(2);
      unpin_window();
    end
  end
end

==> /home/jamie/.config/devilspie2/terminals.lua <==
-- Note - these will typically only work after I start the terminals
-- for the first time because their names seem to change.
if instance == "urxvt" then
  if name == "heart" then
    set_window_geometry(0,10,676,375);
  elseif name == "spade" then
    set_window_geometry(677,10,676,375);
  elseif name == "diamond" then
    set_window_geometry(0,376,676,375);
  elseif name == "clover" then
    set_window_geometry(677,376,676,375);
  end
end

==> /home/jamie/.config/devilspie2/zimbra.lua <==
-- Look for my zimbra firefox window. Shows support queue.
if string.find(name, "Zimbra") then
  if monitor then
    unmaximize();
    set_window_geometry(2520,10,760,1022);
    pin_window();
  else
    set_window_workspace(5);
    set_window_geometry(0,10,676,375);
    -- Zimbra can take up the whole window on this workspace.
    maximize();
    unpin_window();
  end
end

It is started (and restartd) with:

0 jamie@turkey:~$ cat ~/.config/systemd/user/devilspie2.service 
[Unit]
Description=Start devilspie2, program to place windows in the right locations.

[Service]
ExecStart=/usr/bin/devilspie2
ExecStartPre=/home/jamie/bin/a-vga-auto

[Install]
WantedBy=multi-user.target
0 jamie@turkey:~$ 

Which I have configured via a key combination that I hit everytime I plug in or unplug my monitor.

And lastly, the ExecStartPre:

#!/bin/bash

# If the monitor is plugged in, we have to tell the X window system about it
# so we can see our desktop. If it's unplugged, we have tell the X window system
# to re-adjust. This scripts checks whether the monitor is plugged in and
# whether the x window system realizes it. It auto adjusts the X window setting.
#
# This script is invoked by the devilspie2 systemd service 
# (~/.config/systemd/user/devilspie2.service). The devilspie2 systemd server
# is invoked with W-d as configured in ~/.config/openbox/rc.xml.

monitor_status_path="/home/jamie/.config/turkey/monitor.status"
monitor_status=$(cat "$monitor_status_path")

xrandr_status="disconnected"

if /usr/bin/xrandr | grep "DP-1 connected 1920x1080+1366+0" >/dev/null; then
  xrandr_status="connected"
fi

if [ "$monitor_status" = "disconnected" -a "$xrandr_status" = "connected" ]; then
  /usr/bin/xrandr --output DP-1 --off
elif [ "$monitor_status" = "connected" -a "$xrandr_status" = "disconnected" ]; then
  /usr/bin/xrandr --output DP-1 --right-of eDP-1 --auto
fi