my setup: ipad as a second monitor for quick note taking
the situation
- i have an old Ipad 2 (2011 model), stuck at 9.3.5 version. its screen is kinda broken, but still usable. almost no apps can be installed. it’s slow.
- my window manager is i3.
- i also started using vimwiki for note taking. i set it up as a scratchpad* to be able to take notes quickly.
* in i3, a scratchpad it’s simply a window that does not abide to the tiling rules. ie, a floating window on top of whatever is running. here’s an example (it’s already on the correct time mark):
just imagine that in my case it opens a vim instance instead of a terminal
meh
the setup works, but i wasn’t fully satisfied.
there’s still a context switch delay when opening up the scratchpad.
i wanted the note taking to be right in front of me at all times. not only to take notes, but also to view them.
it blocked my vision of what i was taking notes of
sometimes, i wanted to take notes while sharing the main screen without anybody seeing them.
i know, in zoom you can share a specific window, but i usually share the whole screen to have a more personal connection.
for example, i hate when people are sharing a specific window, but then are interacting against a different window that’s not shared.
yes i know, i could’ve just gotten a second monitor. but it’s too bulky. i already ditched a two monitor setup in favour of a single one (yes it’s a 4k one, but point still stands).
the idea? use the ipad as a second monitor exclusively for note taking!
tldr
the final thing (don’t mind the dust):
and a demonstration of how quick the workflow is
here’s a break down of what’s happening in the video:
state | explanation |
---|---|
inital state | focused on firefox (see orange border) |
Super + u | change focus to the ipad worskpace (i3) |
i | enter insert mode (vim) |
hello world | type “hello world” (vim) |
esc | go to normal mode (vim) |
Super + u | focus back to firefox (i3) |
alright, so how is the setup done?
ipad as second monitor
first, how do i get an ipad to work as a second monitor?
if you are in the apple ecosystem, there are few solutions, including an official one. not applicable to me for obvious reasons.
as many others, i resorted to a classic solution: vnc.
the idea is simple: create another display and use the ipad to display its contents (ie, as a vnc viewer).
vnc
if you are not familiar, vnc stands for virtual network computing. in a nutshell, it allows you to control and view a remote desktop.
it’s based on the rfb (remote framebuffer) protocol, so for all effects in this post they are interchangeable.
it uses a client/server model. in a high level the server sends the framebuffer, and the (thin) client displays it.
vnc tools
i tried to run VirtScreen, which is basically a layer on top of x11vnc. but it was crashing, and the ui was buggy.
based on their api i should be able to reproduce with x11vnc and plain xrand commands. oh, yeah, i forgot to mention, this setup only works with x11 server (ie no wayland).
creating a virtual monitor
most tutorials assume you are able to create a VIRTUAL display. apparently it’s easier to do with you run an intel gpu, but in my case i run a nvidia gpu, so no luck here.
there were certain places suggesting to use a real device output, assuming you have one left (gpus usually have 2, 3 ports). in my case there are 2 non used ports: hdmi and dvi. apparently you have to trick the os to think these devices are turned on, with a jumper. liked the creativity but too hacky for my taste.
evdi kernel module
thankfully, found a stack overflow post suggesting to run displaylink’s evdi kernel module to add a virtual output. that was mouthful.
unfortunately i couldn’t install via my packet manager (dnf) neither building from source. but they ship rpm packages for fedora/centos.
the downside here is that i have to wait for them to ship new versions every time i update my os. which may be an issue.
another drawback i found is that certain applications can’t find the virtual device, which is generally not a problem.
after activating the kernel module (see the stack overflow post on how to), xrandr
shows another provider, indicating it works
|
|
adding the virtual display
to be able to use that new display, i need to add a new mode. for that, i used the gtf
tool.
the ipad has a 1024x768
resolution, so:
|
|
let’s copy that and add to xrandr
|
|
then i add that mode to one of the unnused interfaces, in my case, evdi created a DVI one:
|
|
then position that new screen. in my case, i wanted it to be below the primary one, centralized horizontally, like this:
the calculation is straightforward:
the primary monitor is 3840px
wide.
the ipad is 1024px
wide.
the center of the primary monitor is 3840/2
= 1920px
.
the center of the ipad is 1024/2
= 512px
.
so the ipad’s X axis should start at
1920 - 512 = 1408
for the height, we want to position it immediately below the primary monitor,
therefore 2160
(the primary monitor’s height).
therefore
|
|
the sanity check:
|
|
setting up vnc
as a simple test, let’s run the vnc server. i chosen x11vnc since i want the ipad to be part of my current x session.
|
|
then in the ipad, i installed realvnc client. why? because it was the only one available to download.
after setting up the vnc client, i was able to connect. so the idea works.
improving the setup
now to get it more “prod ready” i wanted few things:
- use systemd
- nice integration with i3
- vnc auth
- graceful degradation
- restrict the ipad to access the internet
systemd setup
i wanted to have a setup that’s as hands free as possible. preferably, to only be triggered when the vnc client connects.
one way to do that is using systemd socket activation. the idea is simply to start the x11vnc server when the ipad tries to connect. additionally, running setup/teardown scripts.
first, a file /etc/systemd/system/x11vncipad-proxy.socket
.
it basically sets up a socket listening on 0.0.0.0:5900
(ie all interfaces on port 5900).
|
|
when the socket activates, a service named x11vncipad-proxy
is started. this is done by convention. ie, the service with same name but with a different suffix (s/.socket/.service/
).
file /etc/systemd/system/x11vncipad-proxy.service
.
|
|
this service just starts a systemd-socket-proxy
, which is exactly what the name says: a proxy for the socket. it forwards traffic to port 15900
on localhost. i did that based on this stackoverflow post. theoretically since x11vnc supports inetd
, the proxy is not needed, but i couldn’t make it work.
notice how it Requires
another service to be running (x11vncipad
). that’s the actual x11vnc service.
file /etc/systemd/system/x11vncipad.service
.
|
|
few things happening here:
- it runs as my own user. since socket activation requires root user
- the display is exported as an environment variable, since the unit does not inherit the window’s env vars. of course, this doesn’t work if i start the x server in another tty
ExecStartPre
andExecStopPost
are responsible for setup and teardown, will break it down laterExecStartPost
, it waits for the port to be bound before signaling systemd that the service is good (since it takes few seconds for x11vnc to start)
now onto the x11vnc options:
flag | explanation |
---|---|
-nonap | don’t make it sleep, so that’s always ready to receive focus |
-repeat | allow repeating keystrokes. no idea why it’s turned off |
-clip | only tunnel the 2nd monitor area |
-auth guess | let x11vnc heuristic to authorize with x |
-rfbport 15900 | run on a different port (5900 which is already used) |
-usepw | use a password, it will ask you to generate one the first time |
so the setup happen as follows (bear in mind this is not exactly the terminology systemd uses):
teardown:
i3 integration
before we dive into the scripts, i would like to explain another requirement: graceful degration. in this case, it simply means if x11vnc is not running, still allow me to easily access the vimwiki.
the flow can be summarized as:
ok, onto the scripts now. starting with the setup:
file ~/bin/setup-ipad-vnc.sh
|
|
i added the modes (same as before). the only difference is the OR (||) with true. the idea is to never fail. this would be the default behaviour, but since i am using strict mode this is needed.
for some reason have to run the script twice. still haven’t found out why. must be a race condition. it always is.
then the i3 bit. it moves the vimwiki window to workspace 11 (arbitrary number).
then i set up that workspace to only be displayed on my ipad (DVI-I-1-1).
file ~/.config/i3/conf
|
|
also disable floating. which is turned on by scratchpad.
then the teardown:
|
|
which is pretty simple. it just turns off the monitor and move the vimwiki window to the scratchpad.
we are just missing one last piece. to have $mod+u
to always focus on vimwiki, whether x11vnc is setup or not (see flowchart above).
|
|
script should be pretty clear. the only thing is using jq
to find my virtual monitor.
if it’s active then we focus on workspace 11, otherwise, show the scratchpad.
now the initial setup, when the computer starts. in that case, let’s set up as a scratchpad. also, to open up vimwiki in a tmux session (i hope to create a different post to go over the vimwiki setup).
file ~/.config/i3/conf
|
|
also, one more neat feature is that pressing the same worskpace twice goes back to where you came from.
ie, pressing $mod + u
twice leave yous at the same place. that’s done via:
|
|
why $mod+u
? it’s close enough to hjkl
and it’s not used.
and that should be it. whew.
block ipad from external access
since the ipad should be used only locally, i added the following rule to the router (openwrt) to block external access:
|
|
btw, i left wireshark running for a while and found the ipad phones home from time to time. as expected.
things i am not 100% happy with / other comments
technically the connection is not encrypted, so somebody in the network could sniff the data. the suggestions are to run vnc over a ssh tunnel. but again, i am limited by my ipad’s ability to download apps.
since my ipad model doesn’t support ethernet, it suffers from wireless problems
we restrict vimwiki to run on the ipad, but we don’t stop other applications from running on that workspace. i wish there was something like kubernetes taints, but couldn’t find anything similar.
theoretically novnc/noVNC could be used to run the vnc client in the browser, then the tls setup should be more straightforward
use ipset instead of hardcoding the ip in iptables
parting thoughts
so far this solution has served me quite well. i strongly recommend as a way to save old tablets. it should work just fine with an android device, since all you need a vnc viewer.
links
kbumsik/VirtScreen: Make your iPad/tablet/computer into a secondary monitor on Linux.
nvidia - Unable to add a VIRTUAL display to Xorg - Unix & Linux Stack Exchange Extreme Multihead - ArchWiki
How To Make a VGA Dummy Plug | Geeks3D
i3 Config Tip: Assign Workspaces to Monitors | Destin Moulton