Subject: Clone screens for touch-enabled devices

From: Stefan Baur <[email-masked]>
Date: Tue, 06 Jan 2015 15:08:33 +0100

package: x2gothinclient
version: 1.1.0.2
priority: wishlist
Control: tag -1 patch

Hi,

when using a touch-enabled device (like a tablet computer) as a
thinclient, the cursor isn't properly aligned when you try to run a
second display (non-touch-enabled) alongside with it.

What happens is that both displays get attached to form one large
virtual screen, however, your touch-enabled surface obviously still
only covers the primary display.

The X server doesn't understand this, and tries to map your movements
on the primary display to the entire virtual screen surface, so the
further to the side and to the bottom you get, the more off your mouse
pointer will be from the actual position where you touch your primary
display.

  PRI     SEC                 VIRT
+-----+ +-----+            +----------+
|X    | |     |            |O         |
|     | |     |            |          |
|     | |     |            |          |
|     | |     |            |          |
+-----+ +-----+            +----------+

+-----+ +-----+            +----------+
|     | |     |            |          |
|     | |     |            |          |
|   \ | |   / |            |       O  |
|     | |     |            |          |
+-----+ +-----+            +----------+

\ = where you touch
/ = where X draws the cursor in reality
X = overlapping \ and /
O = where X believes the cursor is, on the virtual screen

There's no sensible way to use a touch-enabled device with a second
screen and no additional, external pointing device, so I've added this
patch/workaround that switches to clone mode instead.

Of course, if you give up on using the touchscreen and plug in a USB
mouse or other external pointing device, you could use two screens.
This patch doesn't cover that situation.

Maybe someone else has an idea on what a sensible solution could look
like that covers this as well?  Like, scan for USB HID pointing
devices ("find /dev/input -name "mouse*" | wc -l") and, if present in
addition to a touchscreen, don't clone, but do side-by-side s if no
touch device was detected at all?
Tht might have some additional caveats, though, like the detection
mis-firing if the touch component of a tablet device "cloaks" as mouse
or offers some sort of mouse emulation support.
Also, in that case, it would probably be smart to disable the touch
interface completely so as to not confuse users why their touches
don't align with the cursor.  Does anybody know of a generic way to do
this?

Again, input/suggestions welcome.

- -Stefan

- -- 
BAUR-ITCS UG (haftungsbeschränkt)
Geschäftsführer: Stefan Baur
Eichenäckerweg 10, 89081 Ulm | Registergericht Ulm, HRB 724364
Fon/Fax 0731 40 34 66-36/-35 | USt-IdNr.: DE268653243
--- /usr/sbin/x2gothinclientd.orig      2015-01-06 14:22:52.416278048 +0000
+++ /usr/sbin/x2gothinclientd   2015-01-06 14:38:58.600131472 +0000
@@ -111,16 +111,29 @@
                        # wait for X-Server to come up
                        sleep(3);

-                       # align displays next to each other in order of appearance in xrandr
+                       # Align displays next to each other in order of appearance in xrandr, unless touch
+                       # devices are detected - in that case, clone displays so that touchable area and display
+                       # stay aligned.  This fix has been introduced for a certain make of wacom touch-sensitive
+                       # displays.  If you have a touch-sensitive device that isn't affected by this, or that
+                       # is negatively affected by this fix, please let us know so we can add a better detection.
                        my $this_display;
                        my $next_display;
+                       my $touchdevicescount=`DISPLAY=:0 xsetwacom -d localhost:0.0 --list devices | wc -l`;
+
                        foreach (`DISPLAY=:0 LANG=C xrandr 2>/dev/null | grep ' connected ' | cut -d ' ' -f1`)
                        {
                                $next_display = $_;
                                $next_display =~ s/\n//;
                                if (defined($this_display))
                                {
-                                       `DISPLAY=:0 /usr/bin/xrandr --output $next_display --left-of $this_display`;
+                                       if ($touchdevicescount > 0)
+                                       {
+                                               `DISPLAY=:0 /usr/bin/xrandr --output $next_display --same-as $this_display`;
+                                       }
+                                       else
+                                       {
+                                               `DISPLAY=:0 /usr/bin/xrandr --output $next_display --left-of $this_display`;
+                                       }
                                }
                                $this_display = $next_display;
                        }

---

From: Stefan Baur <[email-masked]>
Date: Tue, 06 Jan 2015 15:49:23 +0100

Another option would be to parse /proc/cmdline, to offer the
user/administrator a way to override the detection.

If the file /proc/cmdline contains
xinerama=something, where "something" is "left-of", "right-of",
"above", "below", or "same-as", call xrandr with that parameter
instead, regardless of what was detected.

(/proc/cmdline is the list of parameters passed to the kernel while
booting.  If you have never heard of it/noticed, try cat /proc/cmdline
on your Linux system.)

- -Stefan

- --

---

From: Stefan Baur <[email-masked]>
Date: Tue, 06 Jan 2015 18:51:07 +0100

Please disregard my earlier patch and use this one instead.

I have added functionality for mouse detection and an override option
via boot parameter.

- -- 
BAUR-ITCS UG (haftungsbeschränkt)
Geschäftsführer: Stefan Baur
Eichenäckerweg 10, 89081 Ulm | Registergericht Ulm, HRB 724364
Fon/Fax 0731 40 34 66-36/-35 | USt-IdNr.: DE268653243
--- /usr/sbin/x2gothinclientd.orig      2015-01-06 18:34:27.591213413 +0000
+++ /usr/sbin/x2gothinclientd   2015-01-06 18:44:40.679505839 +0000
@@ -111,19 +111,67 @@
                        # wait for X-Server to come up
                        sleep(3);

-                       # align displays next to each other in order of appearance in xrandr
-                       my $this_display;
-                       my $next_display;
-                       foreach (`DISPLAY=:0 LANG=C xrandr 2>/dev/null | grep ' connected ' | cut -d ' ' -f1`)
+                       # Align displays next to each other in order of appearance in xrandr, unless touch
+                       # devices are detected - in that case, clone displays so that touchable area and display
+                       # stay aligned.  This fix has been introduced for a certain make of wacom touch-sensitive
+                       # displays.  If you have a touch-sensitive device that isn't affected by this, or that
+                       # is negatively affected by this fix, please let us know so we can add a better detection.
+                       # The fix is bypassed if a mouse device is detected.
+                       # Note that you can manually override the behavior by passing a kernel parameter
+                       # xinerama=above|below|same-as|left-of|right-of to override the autodetection.
+
+                       # check if a xinerama kernel parameter is set
+                       my $xrandrcmdtainted = `cat /proc/cmdline | tr ' ' '\n' | awk -F '=' '$1 == "xinerama" { print $2 }'`;
+                       my $xrandrcmd;
+                       if ($xrandrcmdtainted =~ /(^above$|^below$|^same-as$|^left-of$|^right-of$)/)
                        {
-                               $next_display = $_;
-                               $next_display =~ s/\n//;
-                               if (defined($this_display))
-                               {
-                                       `DISPLAY=:0 /usr/bin/xrandr --output $next_display --left-of $this_display`;
-                               }
-                               $this_display = $next_display;
+                               # if the parameter value matches one value of the defined set, use that
+                               $xrandrcmd = $1;
                        }
+                       else
+                       {
+                               # else default to "left-of", which was our standard behavior in previous versions
+                               $xrandrcmd = "left-of";
+                       }
+
+                       # find out how many touch devices we have
+                        my $touchdevicescount = `DISPLAY=:0 xsetwacom -d localhost:0.0 --list devices | wc -l`;
+
+                       # find out how many mouse devices we have
+                       my $micecount = `find /dev/input -maxdepth 1 -name "mouse*" | wc -l`;
+
+                       # declare two variables for the upcoming loop
+                       my $this_display;
+                       my $next_display;
+
+                       # loop through the following code block for all connected display devices
+                        foreach (`DISPLAY=:0 LANG=C xrandr 2>/dev/null | grep ' connected ' | cut -d ' ' -f1`)
+                        {
+                               # assign a value to $next_display and remove newline from it
+                                chomp ($next_display = $_);
+
+                               # $this_display won't be defined until the second time the loop is executed, which is a
+                               # neat way of running xrandr only if there are at least two connected display devices
+                                if (defined($this_display))
+                                {
+                                       if (($touchdevicescount > 0) && ($micecount < 1) && ($xrandrcmdtainted eq ""))
+                                       {
+                                               # we have a touch device and no mice, and no xinerama parameter was set,
+                                               # so switch to clone view to make the touch device usable
+                                               `DISPLAY=:0 /usr/bin/xrandr --output $next_display --same-as $this_display`;
+                                       }
+                                       else
+                                       {
+                                               # else use whatever is in $xrandrcmd (which is either our default of "left-of",
+                                               # or a valid xinerama kernel parameter value)
+                                               `DISPLAY=:0 /usr/bin/xrandr --output $next_display --$xrandrcmd $this_display`;
+                                       }
+                               }
+
+                               # now set $this_display -> every subsequent iteration of the loop will now enter the code block
+                               # above where (defined($this_display)) is the conditional
+                                $this_display = $next_display;
+                        }
                }

                # test if pulseaudio is running, if not launch it...

---

From: Stefan Baur <[email-masked]>
Date: Tue, 06 Jan 2015 19:36:57 +0100

Third time's a charm ...
Again, please disregard my earlier patch and use this one instead.

v2 had introduced formatting errors, also, two escape signs were
missing.  v3 fixes that.

- -- 
BAUR-ITCS UG (haftungsbeschränkt)
Geschäftsführer: Stefan Baur
Eichenäckerweg 10, 89081 Ulm | Registergericht Ulm, HRB 724364
Fon/Fax 0731 40 34 66-36/-35 | USt-IdNr.: DE268653243
--- /usr/sbin/x2gothinclientd   2014-02-27 13:27:09.000000000 +0000
+++ /usr/sbin/x2gothinclientd.new       2015-01-06 19:32:47.231326854 +0000
@@ -103,6 +103,7 @@
                        system("shutdown -h now");
                        system("chvt 7");
                }
+
                # test if XServer is running, if not launch it...
                if ( check_x() ==0 )
                {
@@ -111,17 +112,65 @@
                        # wait for X-Server to come up
                        sleep(3);

+                       my $xrandrcmdtainted = `cat /proc/cmdline | tr ' ' '\n' | awk -F '=' '\$1 == "xinerama" { print \$2 }'`;

---

From: Mike Gabriel <[email-masked]>
Date: Thu, 08 Jan 2015 15:16:55 +0000

Control: clone -1 -2
Control: retitle -2 use /proc/cmdline to tweak multi-head TCs
Control: tag -2 patch
Control: severity -2 wishlist

> booting.  If you have never heard of it/noticed, try cat /proc/cmdline

Cloning this one as another bug...

Mike

-- 

DAS-NETZWERKTEAM
mike gabriel, herweg 7, 24357 fleckeby
fon: +49 (1520) 1976 148

GnuPG Key ID 0x25771B31
mail: [email-masked], http://das-netzwerkteam.de

freeBusy:
https://mail.das-netzwerkteam.de/freebusy/m.gabriel%40das-netzwerkteam.de.xfb

---

From: Mike Gabriel <[email-masked]>
Date: Thu, 08 Jan 2015 15:28:18 +0000

Hi Stefan,

> Control: tag -1 patch

About sending patches: Please...

   o use unix line ending style
   o send-in patches that apply cleanly on code found in  
<x2go-component>.git, HEAD of master branch

;-)

Mike

-- 

DAS-NETZWERKTEAM

GnuPG Key ID 0x25771B31

freeBusy: