Using Multiple Screens
People often ask how to configure X to use multiple monitors on awesome IRC channel. So here is a brief document that covers a few different drivers and methods of achieving that on GNU/Linux.
If you are interested in how to utilize multiple monitors after you have set them up then you can take a look at awesome 3 key bindings (look for ones that deal with screens, you can also do man awesome from a terminal) and if you want to control widgets (such as the system tray) for each screen then you may want to look at the Widgets in awesome page, especially the controlling widgets section
Contents |
Basics
The easiest way is by using XRandR (X Resize and Rotate) extension which allows dynamic control over our outputs, resolutions, orientation... and adding new displays on-the-fly without reseting the X server. But not all drivers support it yet. Ones that do are: intel, ati (OpenSource driver), radeonhd (OpenSource driver), nv (nvidia 2D driver) and nouveau (OpenSource nvidia driver). I will also cover the nvidia driver, as that is probably the most common driver people use, using both TwinView and Xinerama (which can be used with other drivers too, i.e. fglrx).
Besides the fact that awesome has: Real multihead support (XRandR, Xinerama or Zaphod mode) with per screen desktops (tags); Awesome is distributed with a sample configuration file (/etc/xdg/awesome/rc.lua with v3.0 and above) which is already setup for multiple displays; regarding wiboxes, taskbars and widgets but also has keybindings which allow you to move clients between multiple screens and switch focus between them.
XRandR
First I will show you a few examples of using xrandr for dynamic and on-the-fly setup and (re)configuration.
With the first command we will query our hardware:
$ xrandr -q
After checking the output, let's suppose that you have a laptop which panel is LVDS and an external VGA port which we will regard as VGA, we execute:
$ xrandr --output VGA --mode 1280x1024 --right-of LVDS
The above command is straightforward, your VGA monitor is initialised using 1280x1024 resolution and it's placement is Right Of your LVDS screen (let's say that LVDS is 1280x800). The important thing to remember is that you will then have one big screen which size will then be 2560x1024. If the above command failed then you probably didn't take this into account when setting up your xorg.conf (you need to configure your Virtual size), more about this a few lines below.
It happens quite frequently that xrandr can not find the 'best' resolution for your external monitor. Let alone the correct refresh rate. When this happens, you need to create a modeline (gtf), then add it to the appropriate output. Here are a couple simple commands that would create a new 1280x800 at 68Hz refresh and attach it to the VGA output:
$ xrandr --newmode $(gtf 1280 800 68 | grep Modeline | sed s/Modeline\ // | tr -d '"') $ xrandr --addmode VGA 1280x800_68.00
For other uses of xrandr read the manual page. I will show just one other example, disabling your external display:
$ xrandr --output VGA --off
Here is a simple script that somewhat simplifies the task of picking the correct refresh rate and then setting up your screens stupid.sh
Cycling through possible configurations
It is possible to cycle through different configurations with some key (for example XF86Display). Here is a snippet of code which uses notification to display the proposed configuration. Each time the key is pressed, another configuration is proposed depending on the active outputs. Once we have proposed all possible configurations, we propose to not change anything. To accept a configuration, the user should not switch to another configuration:
- Only LVDS1
- Only VGA1
- LVDS1 + VGA1
- VGA1 + LVDS1
- No change
- Only LVDS1
- ...
-- Get active outputs
local function outputs()
local outputs = {}
local xrandr = io.popen("xrandr -q")
if xrandr then
for line in xrandr:lines() do
output = line:match("^([%w-]+) connected ")
if output then
outputs[#outputs + 1] = output
end
end
xrandr:close()
end
return outputs
end
local function arrange(out)
-- We need to enumerate all the way to combinate output. We assume
-- we want only an horizontal layout.
local choices = {}
local previous = { {} }
for i = 1, #out do
-- Find all permutation of length `i`: we take the permutation
-- of length `i-1` and for each of them, we create new
-- permutations by adding each output at the end of it if it is
-- not already present.
local new = {}
for _, p in pairs(previous) do
for _, o in pairs(out) do
if not awful.util.table.hasitem(p, o) then
new[#new + 1] = awful.util.table.join(p, {o})
end
end
end
choices = awful.util.table.join(choices, new)
previous = new
end
return choices
end
-- Build available choices
local function menu()
local menu = {}
local out = outputs()
local choices = arrange(out)
for _, choice in pairs(choices) do
local cmd = "xrandr"
-- Enabled outputs
for i, o in pairs(choice) do
cmd = cmd .. " --output " .. o .. " --auto"
if i > 1 then
cmd = cmd .. " --right-of " .. choice[i-1]
end
end
-- Disabled outputs
for _, o in pairs(out) do
if not awful.util.table.hasitem(choice, o) then
cmd = cmd .. " --output " .. o .. " --off"
end
end
local label = ""
if #choice == 1 then
label = 'Only <span weight="bold">' .. choice[1] .. '</span>'
else
for i, o in pairs(choice) do
if i > 1 then label = label .. " + " end
label = label .. '<span weight="bold">' .. o .. '</span>'
end
end
menu[#menu + 1] = { label,
cmd,
"/usr/share/icons/Tango/32x32/devices/display.png"}
end
return menu
end
-- Display xrandr notifications from choices
local state = { iterator = nil,
timer = nil,
cid = nil }
local function xrandr()
-- Stop any previous timer
if state.timer then
state.timer:stop()
state.timer = nil
end
-- Build the list of choices
if not state.iterator then
state.iterator = awful.util.table.iterate(menu(),
function() return true end)
end
-- Select one and display the appropriate notification
local next = state.iterator()
local label, action, icon
if not next then
label, icon = "Keep the current configuration", "/usr/share/icons/Tango/32x32/devices/display.png"
state.iterator = nil
else
label, action, icon = unpack(next)
end
state.cid = naughty.notify({ text = label,
icon = icon,
timeout = 4,
screen = mouse.screen, -- Important, not all screens may be visible
font = "Free Sans 18",
replaces_id = state.cid }).id
-- Setup the timer
state.timer = timer { timeout = 4 }
state.timer:connect_signal("timeout",
function()
state.timer:stop()
state.timer = nil
state.iterator = nil
if action then
awful.util.spawn(action, false)
end
end)
state.timer:start()
end
config.keys.global = awful.util.table.join(
config.keys.global,
awful.key({}, "XF86Display", xrandr))
Static configuration
If you want to do a static setup for your displays then you could follow the next example. You already have one Section "Monitor" for your first display (and for this example let's say that it's identifier is LCD-Monitor and our VGA will be CRT-Monitor), the first step is to add another one, with settings for your second display (we continue with the VGA example):
# This is for a static setup of the external display
#
Section "Monitor"
Identifier "CRT-Monitor"
VendorName "FUS"
ModelName "19P4"
HorizSync 30-96
VertRefresh 50-160
Option "DPMS"
Option "PreferredMode" "1280x1024"
Option "RightOf" "LVDS"
##Option "Position" "1280 0"
EndSection
Then in your Section "Device" you do the actual setup:
# Graphics configuration
#
Section "Device"
Identifier "intel"
Driver "intel"
VendorName "Intel Corporation"
BoardName "Mobile GM965/GL960 Integrated Graphics Controller"
# VGA display options
Option "monitor-VGA" "CRT-Monitor"
##Option "MonitorLayout" "CRT,LFP"
##Option "MonitorLayout" "NONE,CRT+LFP"
EndSection
These are the most basic settings, some other that are worth mentioning are: CheckLid, DevicePresence and Clone. You can find all options with explanations listed in the manual page of the intel driver (to read it you can execute: man intel or replace intel with the name of the driver you use).
The last step involves setting up your Virtual size as I mentioned earlier. In your Section "Screen" subsection "Display" you need to configure the virtual size of your desktop (usually placed below the Modes line). So, following our earlier examples this is how Section "Screen" would look like:
# Screen configuration
#
Section "Screen"
Identifier "LCD Screen"
Device "intel"
Monitor "LCD-Monitor"
DefaultDepth 24
Subsection "Display"
Depth 24
Modes "1280x800" "1280x768" "1280x720" "1024x768" "800x600" "640x480"
ViewPort 0 0
Virtual 2560 1024
EndSubsection
EndSection
nvidia
So, nvidia does not support XRandR yet. What they did up to this point is use their own technology called TwinView which in it's simplest configuration is not so great for us in the classic sense, as awesome will see the screen as one big desktop (thus you will not be able to move clients between screens etc. as there is "no" other screen to move them to). But, I suppose there might be some use cases where this would be the desired behaviour, so I will cover that too. Then with a little tweaking we could get the same behaviour as usually expected. Our last example will be using Xinerama which will also have the same effect as our earlier examples.
TwinView
With TwinView you will only have one Section "Monitor", for the first display. Complete setup of the second display is done in Section "Device". The easiest way to do this is with nvidia-settings, and if that doesn't seem to work you can edit your Xorg.conf manually. So let's see how one such could look like (in this example I am using two identical CRT monitors):
Section "Device"
Identifier "Card0"
Driver "nvidia"
VendorName "nVidia Corporation"
BoardName "NV34 [GeForce FX 5500]"
#
Option "ConnectedMonitor" "CRT-0, CRT-1"
##Option "IgnoreDisplayDevices" "TV-0"
#
# This is the important part
Option "TwinView" "true"
# Possible options are: Right-Of, Left-Of, Above, Below, Clone
Option "TwinViewOrientation" "Right-Of"
#
Option "SecondMonitorHorizSync" "30-96"
Option "SecondMonitorVertRefresh" "50-160"
#
# Metamodes tell us when:
# monitor A is using resolution X then monitor B will use resolution Y; second lower A reolution, second lower B resolution...
Option "MetaModes" "1280x1024, 1280x1024; 1024x768, 1024x768; 800x600, 800x600; 640x480, 640x480"
# Example when monitor B is using a lower resolution
#Option "MetaModes" "1280x1024, 1024x768@1280x1024; 1024x768, 1024x768; 800x600, 800x600"
EndSection
Now let's see a different example contributed by another user, where he got two displays to behave independantly under awesome using TwinView. Here we will shuffle the options a bit, delegate them to other sections, but don't let it confuse you. In this example we will be using two identical LCD monitors (referenced as DFP-0 and DFP-1):
Section "Monitor"
Identifier "Monitor0"
HorizSync 30-100
VertRefresh 60
ModeLine "1680x1050" 147.1 1680 1784 1968 2256 1050 1051 1054 1087 +Hsync -Vsync
EndSection
Section "Monitor"
Identifier "Monitor1"
HorizSync 30-100
VertRefresh 60
ModeLine "1680x1050" 147.1 1680 1784 1968 2256 1050 1051 1054 1087 +Hsync -Vsync
EndSection
Section "Device"
Identifier "Card0"
Driver "nvidia"
VendorName "nVidia"
BoardName "NVIDIA GeForce 7800GS"
Option "AllowDDCCI" "true"
Option "FlatPanelProperties" "Scaling = aspect-scaled"
Option "RandRRotation" "true"
Option "TripleBuffer" "true"
# Multiple display configuration
##Option "ConnectedMonitor" "DFP-0, DFP-1"
Option "PrimaryMonitor" "DFP-0"
Option "UseDisplayDevice" "DFP-0, DFP-1"
# According to their docs, this is what makes the difference
# http://us.download.nvidia.com/XFree86/Linux-x86/180.29/README/chapter-13.html
Option "TwinViewOrientation" "DFP-0 LeftOf DFP-1"
Option "TwinViewXineramaInfoOrder" "DFP-0, DFP-1"
EndSection
Section "Screen"
Identifier "Screen0"
Device "Card0"
Monitor "Monitor0"
DefaultDepth 24
Subsection "Display"
Modes "1680x1050"
EndSubsection
Option "MetaModes" "DFP-0: 1680x1050 +0+0, DFP-1: 1680x1050 +1680+0;"
Option "HorizSync" "DFP-0: 30-100; DFP-1: 30-100"
Option "VertRefresh" "DFP-0: 60; DFP-1: 60"
Option "TwinView" "true"
EndSection
Section "ServerLayout"
Identifier "TwinView Screen"
Screen 0 "Screen0" 0 0
Option "Xinerama" "false"
EndSection
For more information about TwinView (naming the devices (CRT, DFP, TV...), which pipes can be used at the same time and for everything else) refer to the latest nvidia README file which is distributed with their drivers but can also be read online: http://www.nvidia.com/object/unix.html
Xinerama
Xinerama is an X extension which enables multi-headed X applications and window managers to use two or more physical displays as one large virtual display. Note that you can use Xinerama in the same way with other drivers too (fglrx for example). When using Xinerama we will need to have a section for each Monitor, two Device sections, two Screen sections (each using it's own Device and Monitor) and we will setup orientation of our screens in the main ServerLayout section (where we will also enable Xinerama). This is the most basic example showing what I'm talking about (using two identical LCD displays):
# Out Monitor sections
#
Section "Monitor"
Identifier "Monitor0"
VendorName "Monitor Vendor"
ModelName "Monitor Model"
EndSection
Section "Monitor"
Identifier "Monitor1"
VendorName "Monitor Vendor"
ModelName "Monitor Model"
EndSection
# Our Device sections
#
Section "Device"
Identifier "Card0"
Driver "nvidia"
VendorName "nVidia Corporation"
BoardName "G70 [GeForce 7800 GS]"
Screen 0
EndSection
Section "Device"
Identifier "Card1"
Driver "nvidia"
VendorName "nVidia Corporation"
BoardName "G70 [GeForce 7800 GS]"
Screen 1
EndSection
# Our Screen sections
#
Section "Screen"
Identifier "Screen0"
Device "Card0"
Monitor "Monitor0"
DefaultDepth 24
SubSection "Display"
Viewport 0 0
Depth 24
Modes "1680x1050"
EndSubSection
EndSection
Section "Screen"
Identifier "Screen1"
Device "Card1"
Monitor "Monitor1"
DefaultDepth 24
SubSection "Display"
Viewport 0 0
Depth 24
Modes "1680x1050"
EndSubSection
EndSection
# Finally our ServerLayout that does the work
#
Section "ServerLayout"
Identifier "Xinerama Screen"
Screen 0 "Screen0" 0 0
Screen 1 "Screen1" RightOf "Screen0"
Option "Xinerama" "true"
EndSection
You will also have your Keyboard and Mouse configuration in this file, and reference them in your server layout etc. (if you are not already using HAL enabled X.org). You should already know all that. I'm only writing about displays. Speaking of which there are even more ways of using multiple displays, such as running two independant X sessions each on it's own monitor, there are also Zaphod and MergedFB, last to mention is that ATi, like nVidia, has it's own thing called BigDesktop (fglrx driver). Researching into those is up to you, reader. With that said I am wraping up this document, I hope it was clear enough and you have your huge desktop operational (and awesome controling it :).
Disper
A simplified utility: allowing command line switching of monitor configurations is http://willem.engen.nl/projects/disper/
This also helps work around the issue of the nvidia-settings confirmation dialog being hidden by awesome's restart when nvidia-settings changes the monitor mode.