Scale application differently on different monitors - Ubuntu 16.04

I have found a lot of very solid articles/answers about this topic:

  • https://askubuntu.com/a/555812/574648
  • https://unix.stackexchange.com/a/213984
  • https://askubuntu.com/a/662567/574648

And of course:

  • https://wiki.archlinux.org/index.php/Xrandr
  • https://wiki.archlinux.org/index.php/HiDPI#Multiple_displays

However, I'm still struggling. My laptop is Dell XPS15. Its display is 3840x2160. I have tried different external monitors, but at the moment the one I use is also Dell with resolution 1920x1080.

When I connect external monitor, some of the panels immediately become very small on 3840x2160 screen. When I try to scale up build-in display, chrome scales, my IDE scales, but displays window along with other windows like NVIDIA X Server settings stay very small. I have tried to play with Scale all window contents to match in Display but to no avail. It's either too big on the external screen or to small on the build-in. I have also tried xrandr with scale param but it gives me:

xrandr --output HDMI-1 --scale 2x2
X Error of failed request:  BadValue (integer parameter out of range for operation)
  Major opcode of failed request:  140 (RANDR)
  Minor opcode of failed request:  26 (RRSetCrtcTransform)
  Value in failed request:  0x40
  Serial number of failed request:  38
  Current serial number in output stream:  39

Ideally, I want several windows of the same application(let's say Chrome or Intellij Idea to be open on different displays and scale independently on them).

EDIT

I am not looking for Scale for menus and title bar, I like the way the bars are. I want windows contents scaled independently. Displays UI forces me to either scale all windows to match Built-id display or the external display. As a result:

  1. Scale all window contents to match Build-In Display:

    Build-In Display - everything looks perfect; External Display - everything is huge.

  2. Scale all window contents to match External Display:

    Build-In Display - very small; External Display - everything looks perfect.


I have nvidia driver 340.98 with GT218M [NVS 3100M], Xubuntu 16.04, any results below are from this environment if I don't mention otherwise. Here is my testing environment info, the output of:

sudo apt-get install pastebinit; \
sudo sh -c "lsb_release -sd; \
 dmidecode -s system-product-name; echo ==; \
 lshw -c display; echo ==; \
 xrandr --verbose; echo ==; \
 cat /etx/X11/xorg.conf" \
 | tee ~/Desktop/ubuntu-graphic-info.txt \
 | pastebinit

Weird and complex stack to debug specially using proprietary drivers. Most of the time, I get unexpected behaviors, may be due to lack of knowledge about the current Linux graphics stack setup.

  • I wrote this answer before, that may introduce some debugging tools like xtrace
  • Avoid running multiple/sequential xrandr commands, only after X server reset. Same command may have different result depending on previous commands. I have noticed that with --scale (see test case from my answer, linked above) --transform & --fb. Still don't know an easy way only by logout/login. So always logout/login before making another trial.
  • Screenshots take only pixel size image from FB, so I will add camera photos to show the real results.

Method 1: xrandr --output .. --scale HCoefxVCoef or --scale-from WxH

Note, works fine for me. --scale is a shortcut for --transform, see method3

(VGA-0 below DP-3)

xrandr \
--output DP-3 --mode 1280x800 --scale 1x1 --pos 0x0 --fb 2880x2600 \
--output VGA-0 --mode 1440x900 --scale 2x2 --pos 0x800

or:

xrandr \
--output DP-3 --mode 1280x800 --pos 0x0 --fb 2880x2600 \
--output VGA-0 --mode 1440x900 --scale-from 2880x1800 --pos 0x800

FrameBuffer size calculation:

width = max(1280,1440*2) = 2880
height = 800+900*2 = 2600

Results:

  • nvidia xrandr scale screenshot

    nvidia xrandr scale screenshot

  • nvidia xrandr scale photo

    nvidia xrandr scale photo

Method 2: nvidia-settings View Port In/Out

Note, doesn't work well. nvidia-settings does not change frame-buffer to the required size as in xrandr command. It seems a bug (kind of, nvidia has its own FB), need more research.

Tried to replicate xrandr setup directly using nvidia-settings (I used xrandr from method1, marked down nvidia setting, reset settings, then used nvidia-settings directly):

  1. gksu nvidia-settings → X Server Display Configuration
  2. Select external monitor → advanced...
  3. Make ViewPortIn & Panning double of ViewPortOut (which is the same as original resolution)
  4. Leave internal monitor unchanged then Apply

Example:

  • Internal monitor nvidia settings

    Position:    +0+0
    ViewPortIn:  1280x800
    ViewPortOut: 1280x800+0+0
    Panning:     1280x800
    
  • External monitor nvidia settings

    Position:    +1280+0 (rightof) or +0+800 (below)
    ViewPortIn:  2880x1800
    ViewPortOut: 1440x900+0+0
    Panning:     2880x1800
    

Results: Notice the mouse pointer, it can reach all edges of the 2nd monitor even it only draws the top left quarter.

  • nvidia-settings viewportin screenshot

    nvidia-settings viewportin screenshot

  • nvidia-settings viewportin photo

    nvidia-settings viewportin photo

Update: Well, I could finally get a workaround trick. Add 1px to the width or height of panning (Panning)

    Panning:     2881x1800 or 2880x1801

New Results: I can't explain this, just the background is corrupted if i use below, otherwise every thing seems ok.

  • nvidia-settings viewportin with panning trick screenshot

    nvidia-settings viewportin with panning trick screenshot - below lowered the color quality of above picture to make less then 2MB imgur limitnvidia-settings viewportin with panning trick screenshot - right of

  • nvidia -settings viewportin with panning trick photo

    nvidia-settings viewportin with panning trick photo - below nvidia-settings viewportin with panning trick photo - right of

Method 3: xrandr --output .. --transform "H,0,0,0,V,0,0,0,1"

Note, works fine for me, same as method1

(VGA-0 right of DP-3)

xrandr \
--output DP-3  -primary --mode 1280x800 --pos 0x0 --transform "1,0,0,0,1,0,0,0,1" --fb 4160x1800 \
--output VGA-0 --mode 1440x900 --transform "2,0,0,0,2,0,0,0,1" --right-of DP-3

FrameBuffer size calculation:

width = 1280+1440*2 = 4160
height = max(800,900*2) = 1800

Results:

  • nvidia xrandr transform screenshot

    nvidia xrandr transform screenshot

  • nvidia xrandr transform photo

    nvidia xrandr transform photo