Repository: dluksza/screenful
Branch: master
Commit: dd98a44b73e9
Files: 7
Total size: 10.9 KB
Directory structure:
gitextract_xrrk0h17/
├── .gitignore
├── 98-screen-detect.rules
├── LICENSE
├── README.md
├── notify-awesome
├── screenful.lua
└── screens_db.lua
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitignore
================================================
*.swp
================================================
FILE: 98-screen-detect.rules
================================================
# change /devices/pci0000:00/0000:00:02.0/drm/card0 (drm)
ACTION=="change", SUBSYSTEM=="drm", RUN+="notify-awesome %k"
================================================
FILE: LICENSE
================================================
MIT License
Copyright (c) 2012 Dariusz Łuksza
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
================================================
FILE: README.md
================================================
screenful
=========
screenful is an extension library for [Awesome WM](http://awesome.naquadah.org/) that enables it to automatically setup screen organization. It leverage from udev notification about drm change events and device specific EDID information.
When drm change event occurs, screenful is informed via awesome-client command. Then it discovers with output was connected and reads screen EDID. Next it reads lua configuration script and looks for configuration for this device. If it isn't available yet, it will add commented out template and run default configuration, otherwise it will execute specific configuration.
Since configuration file is also lua script you can do many things when screens are connected or disconnected. For example you can change default mplayer audio output when you are connecting HD TV set using HDMI; theoretically you can also reorganize yours windows/tags etc. When one of configuration options is missing ('connected' or 'disconnected') then default action will be launched.
Install
=======
* 98-screen-detect.rules - copy to /etc/udev/rules.d/ and execute with root privileges `udevadm control --reload-rules`
* notify-awesome - copy to /lib/udev and add execution bit
* screenful.lua - copy to ~/.config/awesome
* screens_db.lua - copy to ~/.config/awesome
Add to your rc.lua file the following require statements:
```
require("awful.remote")
require("screenful")
```
* Restart Awesome WM
Now you can connect an additional screen. HDMI outputs are detected almost instantly, but in the case of VGA outputs you need to wait a couple of seconds for detection. Default configuration will clone LVDS1 output. Then you can edit ~/.config/awesome/screens_db.lua config file. At the end you will find commented out configuration template with screen EDID value. Both functions ('connected' and 'disconnected') should return xrandr options eg:
```lua
screens = {
['default'] = {
['connected'] = function (xrandrOutput)
return '--output ' .. xrandrOutput .. ' --auto --same-as LVDS1'
end,
['disconnected'] = function (xrandrOutput)
return '--output ' .. xrandrOutput .. ' --off --output LVDS1 --auto'
end
}
['99999999999'] = {
['connected'] = function (xrandrOutput)
return '--output ' .. xrandrOutput .. ' --auto --above LVDS1'
end,
}
}
```
In this example, when screen with ID 99999999999 is connected to VGA1 output then screenful will execute command:
```
$ xrandr --output VGA1 --auto --above LVDS1
```
When it is disconnected, because 'disconnected' is not defined for this output, default disconnect action will be executed:
```
$ xrandr --output VGA1 --off --output LVDS1 --auto
```
Known BUGS
=========
* when device is disconnected always default disconnect action is called
TODO
====
* setup proper screen organization on awesome boot
* support more then one card
* support conditional configuration based on connected devices/outputs and id's
================================================
FILE: notify-awesome
================================================
#!/bin/sh
_PID=$(pgrep -x awesome)
_UID=$(ps -o uid= -p $_PID)
USER=$(id -nu $_UID)
DBUS_ADDRESS_VAR=$(cat /proc/$_PID/environ | grep -z "^DBUS_SESSION_BUS_ADDRESS=")
notify() {
su - $USER -c "/bin/bash \
-c ' \
export DISPLAY=:0; \
export XAUTHORITY='/home/$USER/.Xauthority'; \
export $DBUS_ADDRESS_VAR; \
dbus-send --dest=org.awesomewm.awful --type=method_call \
/ org.awesomewm.awful.Remote.Eval string:"updateScreens\\\(\\\"$1\\\"\\\)" \
' \
"
}
notify $1 &
================================================
FILE: screenful.lua
================================================
----------------------------------------------------------------------------
---- @author dluksza <dariusz@luksza.org>
---- @copyright 2012 dluksza
------------------------------------------------------------------------------
-- Package envronment
local naughty = require('naughty')
local awful = require("awful")
local screen = require("awful.screen")
local io = require("io")
local os = require("os")
local awesome = awesome
require('screens_db')
local card = 'card0'
local dev = '/sys/class/drm/'
local configPath = awful.util.getdir("config") .. "/screens_db.lua"
local function log(text)
naughty.notify({
title = 'screenful debug',
text = text,
ontop = true,
preset = naughty.config.presets.critical
})
local log = io.open('/tmp/awesomewm-widget-screenful.error.log', 'a+')
log:write(text .. "\n")
log:flush()
log:close()
end
local function isOutputConnected(path)
local status = io.open(path .. '/status', 'r')
local value = status:read('*all')
return 'connected\n' == value
end
local function connectedOutputs(path, card)
local result = {}
local outputs = io.popen('ls -1 -d ' .. path .. '/' .. card .. '-*')
while true do
local output = outputs:read('*line')
if not output then break end
if isOutputConnected(output) then
result[output] = true
end
end
return result
end
local function emptyStr(str)
return str == nil or str == ''
end
local function getScreenId(output)
local screenId = nil
if isOutputConnected(output) then
screenId = ''
os.execute("udevadm settle")
local edid = io.open(output .. '/edid', 'rb')
local id = edid:read('*all')
io.close(edid)
if emptyStr(id) then
log('cannot read EDID from ' .. output .. '/edid')
return false
end
for i = 12, 17 do
code = id:byte(i)
if code then
screenId = screenId .. code
end
end
end
return screenId
end
local function getXrandrOutput(outputPath, outCard)
local regex = dev .. outCard .. '/' .. outCard .. '[-]'
local drmName = string.gsub(outputPath, regex, '')
if outputMapping[drmName] then
return outputMapping[drmName]
end
return drmName
end
local function mergeTables(table1, table2)
local result = {}
for k,v in pairs(table1) do
result[k] = v
end
for k,v in pairs(table2) do
result[k] = v
end
return result
end
local function hasConfigurationFor(screenId)
local file = io.open(configPath, 'r')
local conf = file:read('*all')
file:close()
return string.find(conf, "['\"]" .. screenId .. "['\"]")
end
local function appendConfiguration(screenId, xrandrOut)
local file = io.open(configPath, 'a')
file:write("--\t['" .. screenId .. "'] = { -- " .. xrandrOut .. "\n")
file:write("--\t\t['connected'] = function (xrandrOutput)\n")
file:write("--\t\t\tif xrandrOutput ~= defaultOutput then\n")
file:write("--\t\t\t\treturn '--output ' .. xrandrOutput .. ' --auto --same-as ' .. defaultOutput\n")
file:write("--\t\t\tend\n")
file:write("--\t\t\treturn nil\n")
file:write("--\t\tend,\n")
file:write("--\t\t['disconnected'] = function (xrandrOutput)\n")
file:write("--\t\t\tif xrandrOutput ~= defaultOutput then\n")
file:write("--\t\t\treturn '--output ' .. xrandrOutput .. ' --off --output ' .. defaultOutput .. ' --auto'\n")
file:write("--\t\t\tend\n")
file:write("--\t\t\treturn nil\n")
file:write("--\t\tend\n")
file:write("--\t}\n")
file:flush()
file:close()
end
local function setupScreen(xrandrParams)
os.execute('xrandr ' .. xrandrParams)
end
local function performConfiguredAction(screenId, action, xrandrOut)
local xrandrOpts = ''
if screenId then
local configuration = screens[screenId]
if configuration then
if configuration[action] then -- get xrandr options
xrandrOpts = configuration[action](xrandrOut)
end
else -- configuration not found, append configuration template
if tostring(screenId):len() ~= 0 and not hasConfigurationFor(screenId) then
naughty.notify({text = 'Append new configuration for screen id: ' .. screenId})
appendConfiguration(screenId, xrandrOut)
end
end
end
if xrandrOpts:len() == 0 then -- use default configuration if specific was not found
xrandrOpts = screens['default'][action](xrandrOut)
end
if xrandrOpts then
setupScreen(xrandrOpts)
end
end
local function disableOutput(out, changedCard)
local xrandrOut = getXrandrOutput(out, changedCard)
local screenId = getScreenId(out)
performConfiguredAction(screenId, 'disconnected', xrandrOut)
naughty.notify({ text='Output ' .. xrandrOut .. ' disconnected' })
end
local function enableOutput(out, changedCard)
local xrandrOut = getXrandrOutput(out, changedCard)
local screenId = getScreenId(out)
performConfiguredAction(screenId, 'connected', xrandrOut)
end
local cardDev = dev .. card
local outputs = connectedOutputs(cardDev, card)
function updateScreens(changedCard)
local newCardDev = dev .. changedCard
local newOutputs = connectedOutputs(newCardDev, changedCard)
local mergedOutputs = mergeTables(outputs, newOutputs)
for out in pairs(mergedOutputs) do
if not outputs[out] then -- connected
enableOutput(out, changedCard)
elseif not newOutputs[out] then -- disconnected
disableOutput(out, changedCard)
end
end
outputs = newOutputs
-- reinit awesome
awesome.restart()
end
================================================
FILE: screens_db.lua
================================================
local naughty = require("naughty")
local defaultOutput = 'eDP1'
outputMapping = {
['DP-1'] = 'DP1',
['DP-2'] = 'DP2',
['DP-3'] = 'DP3',
['VGA-1'] = 'VGA1',
['LVDS-1'] = 'LVDS1',
['HDMI-A-1'] = 'HDMI1',
['HDMI-A-2'] = 'HDMI2',
['eDP-1'] = 'eDP1',
['eDP-2'] = 'eDP2',
}
screens = {
['default'] = {
['connected'] = function (xrandrOutput)
if xrandrOutput ~= defaultOutput then
return '--output ' .. xrandrOutput .. ' --auto --same-as ' .. defaultOutput
end
return nil
end,
['disconnected'] = function (xrandrOutput)
if xrandrOutput ~= defaultOutput then
return '--output ' .. xrandrOutput .. ' --off --output ' .. defaultOutput .. ' --auto'
end
return nil
end
},
}
gitextract_xrrk0h17/ ├── .gitignore ├── 98-screen-detect.rules ├── LICENSE ├── README.md ├── notify-awesome ├── screenful.lua └── screens_db.lua
Condensed preview — 7 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (12K chars).
[
{
"path": ".gitignore",
"chars": 6,
"preview": "*.swp\n"
},
{
"path": "98-screen-detect.rules",
"chars": 122,
"preview": "# change /devices/pci0000:00/0000:00:02.0/drm/card0 (drm)\nACTION==\"change\", SUBSYSTEM==\"drm\", RUN+=\"notify-awesome %k"
},
{
"path": "LICENSE",
"chars": 1071,
"preview": "MIT License\n\nCopyright (c) 2012 Dariusz Łuksza\n\nPermission is hereby granted, free of charge, to any person obtaining a "
},
{
"path": "README.md",
"chars": 3012,
"preview": "screenful\n=========\n\nscreenful is an extension library for [Awesome WM](http://awesome.naquadah.org/) that enables it to"
},
{
"path": "notify-awesome",
"chars": 651,
"preview": "#!/bin/sh\n\n_PID=$(pgrep -x awesome)\n_UID=$(ps -o uid= -p $_PID)\nUSER=$(id -nu $_UID)\nDBUS_ADDRESS_VAR=$(cat /proc/$_PID/"
},
{
"path": "screenful.lua",
"chars": 5449,
"preview": "----------------------------------------------------------------------------\n---- @author dluksza <dariusz@luksza.org"
},
{
"path": "screens_db.lua",
"chars": 815,
"preview": "local naughty = require(\"naughty\")\n\nlocal defaultOutput = 'eDP1'\n\noutputMapping = {\n ['DP-1'] = 'DP1',\n ['DP-2'] ="
}
]
About this extraction
This page contains the full source code of the dluksza/screenful GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 7 files (10.9 KB), approximately 3.0k tokens. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.