Full Code of dluksza/screenful for AI

master dd98a44b73e9 cached
7 files
10.9 KB
3.0k tokens
1 requests
Download .txt
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
	},
}
Download .txt
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.

Copied to clipboard!