Revert "Update"

This reverts commit 777960ac7b.
This commit is contained in:
Derek Taylor
2025-12-03 11:20:33 -06:00
parent 777960ac7b
commit a91301075a
758 changed files with 37421 additions and 6 deletions

311
.config/amfora/config.toml Normal file
View File

@@ -0,0 +1,311 @@
# This is the default config file.
# It also shows all the default values, if you don't create the file.
[a-general]
home = "gemini://distro.tube"
color = true
ansi = true
bullets = true
show_link = false
# Follow up to 5 Gemini redirects without prompting.
# A prompt is always shown after the 5th redirect and for redirects to protocols other than Gemini.
# If set to false, a prompt will be shown before following redirects.
auto_redirect = false
# What command to run to open a HTTP(S) URL.
# The best to define a command is using a string array.
# Examples:
# http = ['firefox']
# http = ['custom-browser', '--flag', '--option=2']
# http = ['/path/with spaces/in it/firefox']
#
# Note the use of single quotes, so that backslashes will not be escaped.
# Using just a string will also work, but it is deprecated, and will degrade if
# you use paths with spaces.
http = 'brave'
# Any URL that will accept a query string can be put here
search = "gemini://gus.guru/search"
# A number from 0 to 1, indicating what percentage of the terminal width the left margin should take up.
left_margin = 0.10
# The max number of columns to wrap a page's text to. Preformatted blocks are not wrapped.
max_width = 140
# 'downloads' is the path to a downloads folder.
# An empty value means the code will find the default downloads folder for your system.
# If the path does not exist it will be created.
# Note the use of single quotes, so that backslashes will not be escaped.
downloads = ''
# Max size for displayable content in bytes - after that size a download window pops up
page_max_size = 2097152 # 2 MiB
# Max time it takes to load a page in seconds - after that a download window pops up
page_max_time = 10
# Whether to replace tab numbers with emoji favicons, which are cached.
emoji_favicons = true
[auth]
# Authentication settings
# Note the use of single quotes for values, so that backslashes will not be escaped.
[auth.certs]
# Client certificates
# Set domain name equal to path to client cert
# "example.com" = 'mycert.crt'
[auth.keys]
# Client certificate keys
# Set domain name equal to path to key for the client cert above
# "example.com" = 'mycert.key'
[keybindings]
bind_bottom = ":"
bind_quit = "q"
bind_reload = "R"
bind_back = "H"
bind_forward = "L"
bind_next_tab = "J"
bind_prev_tab = "K"
bind_edit = "o"
bind_new_tab = "O"
bind_save = "S"
bind_home = "h"
bind_bookmarks = "b"
bind_add_bookmark = "B"
# If you have a non-US keyboard, use bind_tab1 through bind_tab0 to
# setup the shift-number bindings: Eg, for US keyboards (the default):
# bind_tab1 = "!"
# bind_tab2 = "@"
# bind_tab3 = "#"
# bind_tab4 = "$"
# bind_tab5 = "%"
# bind_tab6 = "^"
# bind_tab7 = "&"
# bind_tab8 = "*"
# bind_tab9 = "("
# bind_tab0 = ")"
# The bind_link[1-90] options are for the commands to go to the first 10 links on a page,
# typically these are bound to the number keys:
# bind_link1 = "1"
# bind_link2 = "2"
# bind_link3 = "3"
# bind_link4 = "4"
# bind_link5 = "5"
# bind_link6 = "6"
# bind_link7 = "7"
# bind_link8 = "8"
# bind_link9 = "9"
# bind_link0 = "0"
[url-handlers]
# Allows setting the commands to run for various URL schemes.
# E.g. to open FTP URLs with FileZilla set the following key:
# ftp = 'filezilla'
# You can set any scheme to "off" or "" to disable handling it, or
# just leave the key unset.
#
# DO NOT use this for setting the HTTP command.
# Use the http setting in the "a-general" section above.
#
# NOTE: These settings are overrided by the ones in the proxies section.
# Note the use of single quotes, so that backslashes will not be escaped.
# This is a special key that defines the handler for all URL schemes for which
# no handler is defined.
other = 'off'
# [[mediatype-handlers]] section
# ---------------------------------
#
# Specify what applications will open certain media types.
# By default your default application will be used to open the file when you select "Open".
# You only need to configure this section if you want to override your default application,
# or do special things like streaming.
#
# Note the use of single quotes for commands, so that backslashes will not be escaped.
#
#
# To open jpeg files with the feh command:
#
# [[mediatype-handlers]]
# cmd = ['feh']
# types = ["image/jpeg"]
#
# Each command that you specify must come under its own [[mediatype-handlers]]. You may
# specify as many [[mediatype-handlers]] as you want to setup multiple commands.
#
# If the subtype is omitted then the specified command will be used for the
# entire type:
#
# [[mediatype-handlers]]
# command = ['vlc', '--flag']
# types = ["audio", "video"]
#
# A catch-all handler can by specified with "*".
# Note that there are already catch-all handlers in place for all OSes,
# that open the file using your default application. This is only if you
# want to override that.
#
# [[mediatype-handlers]]
# cmd = ['some-command']
# types = [
# "application/pdf",
# "*",
# ]
#
# You can also choose to stream the data instead of downloading it all before
# opening it. This is especially useful for large video or audio files, as
# well as radio streams, which will never complete. You can do this like so:
#
# [[mediatype-handlers]]
# cmd = ['vlc', '-']
# types = ["audio", "video"]
# stream = true
#
# This uses vlc to stream all video and audio content.
# By default stream is set to off for all handlers
#
#
# If you want to always open a type in its viewer without the download or open
# prompt appearing, you can add no_prompt = true
#
# [[mediatype-handlers]]
# cmd = ['feh']
# types = ["image"]
# no_prompt = true
#
# Note: Multiple handlers cannot be defined for the same full media type, but
# still there needs to be an order for which handlers are used. The following
# order applies regardless of the order written in the config:
#
# 1. Full media type: "image/jpeg"
# 2. Just type: "image"
# 3. Catch-all: "*"
[cache]
# Options for page cache - which is only for text pages
# Increase the cache size to speed up browsing at the expense of memory
# Zero values mean there is no limit
max_size = 0 # Size in bytes
max_pages = 30 # The maximum number of pages the cache will store
# How long a page will stay in cache, in seconds.
timeout = 1800 # 30 mins
[proxies]
# Allows setting a Gemini proxy for different schemes.
# The settings are similar to the url-handlers section above.
# E.g. to open a gopher page by connecting to a Gemini proxy server:
# gopher = "example.com:123"
#
# Port 1965 is assumed if no port is specified.
#
# NOTE: These settings override any external handlers specified in
# the url-handlers section.
#
# Note that HTTP and HTTPS are treated as separate protocols here.
[subscriptions]
# For tracking feeds and pages
# Whether a pop-up appears when viewing a potential feed
popup = true
# How often to check for updates to subscriptions in the background, in seconds.
# Set it to 0 to disable this feature. You can still update individual feeds
# manually, or restart the browser.
#
# Note Amfora will check for updates on browser start no matter what this setting is.
update_interval = 1800 # 30 mins
# How many subscriptions can be checked at the same time when updating.
# If you have many subscriptions you may want to increase this for faster
# update times. Any value below 1 will be corrected to 1.
workers = 3
# The number of subscription updates displayed per page.
entries_per_page = 20
[theme]
# This section is for changing the COLORS used in Amfora.
# These colors only apply if 'color' is enabled above.
# Colors can be set using a W3C color name, or a hex value such as "#ffffff".
# Note that not all colors will work on terminals that do not have truecolor support.
# If you want to stick to the standard 16 or 256 colors, you can get
# a list of those here: https://jonasjacek.github.io/colors/
# DO NOT use the names from that site, just the hex codes.
# Definitions:
# bg = background
# fg = foreground
# dl = download
# btn = button
# hdg = heading
# bkmk = bookmark
# modal = a popup window/box in the middle of the screen
# EXAMPLES:
# hdg_1 = "green"
# hdg_2 = "#5f0000"
# Available keys to set:
bg = "#282c34"
tab_num = "#3071db"
tab_divider = "#5699af"
bottombar_label = "#98be65"
bottombar_text = "#7d7d7d"
bottombar_bg = "#202328"
hdg_1 = "#ff6c6b"
hdg_2 = "#51afef"
hdg_3 = "#4669ff"
amfora_link = "#c678dd"
foreign_link = "#98be65"
link_number = "#7d7d7d"
regular_text = "#ffffff"
quote_text = "#a9a1e1"
preformatted_text = "#ecbe7b"
list_text = "#bbc2cf"
# btn_bg: The bg color for all modal buttons
# btn_text: The text color for all modal buttons
# dl_choice_modal_bg
# dl_choice_modal_text
# dl_modal_bg
# dl_modal_text
# info_modal_bg
# info_modal_text
# error_modal_bg
# error_modal_text
# yesno_modal_bg
# yesno_modal_text
# tofu_modal_bg
# tofu_modal_text
# subscription_modal_bg
# subscription_modal_text
# input_modal_bg
# input_modal_text
# input_modal_field_bg: The bg of the input field, where you type the text
# input_modal_field_text: The color of the text you type
# bkmk_modal_bg
# bkmk_modal_text
# bkmk_modal_label
# bkmk_modal_field_bg
# bkmk_modal_field_text

View File

@@ -0,0 +1,9 @@
# Awesome4Laptop
Installation:
git clone https://github.com/msjche/Awesome4Laptop.git ~/.config/awesome
cd ~/.config/awesome && cp -r Awesome4Laptop/* .
rm -r Awesome4Laptop
![Alt text](screenshot.png?raw=true "Title")

17
.config/awesome/autostart.sh Executable file
View File

@@ -0,0 +1,17 @@
#!/usr/bin/env bash
function run {
if ! pgrep $1 ;
then
$@&
fi
}
#run "megasync"
run "xscreensaver -no-splash"
#run "/usr/bin/dropbox"
#run "insync start"
run "picom"
#run "/usr/bin/redshift"
run "mpd"
run "nm-applet"

View File

@@ -0,0 +1,131 @@
-----------------------------------------------------------------------------
-- conkyrc_seamod
-- Date : 04/23/2016
-- Author : SeaJey and Maxiwell
-- Conky : >= 1.10
-- License : Distributed under the terms of GNU GPL version 2 or later
-----------------------------------------------------------------------------
conky.config = {
background = true,
update_interval = 1,
time_in_seconds = true,
cpu_avg_samples = 2,
net_avg_samples = 2,
temperature_unit = 'farenheight',
double_buffer = true,
no_buffers = true,
text_buffer_size = 2048,
gap_x = 0,
gap_y = 150,
minimum_width = 100, minimum_height = 900,
maximum_width = 115,
own_window = true,
own_window_type = 'desktop',
own_window_transparent = true,
own_window_argb_visual = true,
own_window_class = 'conky-semi',
own_window_hints = 'undecorated,below,sticky,skip_taskbar,skip_pager',
border_inner_margin = 0,
border_outer_margin = 0,
alignment = 'top_left',
draw_shades = false,
draw_outline = false,
draw_borders = false,
draw_graph_borders = false,
override_utf8_locale = true,
use_xft = true,
font = 'caviar dreams:size=11',
xftalpha = 0.5,
uppercase = false,
-- Defining colors
default_color = '#FFFFFF',
-- Shades of Gray
color1 = '#DDDDDD',
color2 = '#AAAAAA',
color3 = '#888888',
-- Gentoo Purple
color4 = '#7A5ADA',
-- Green
color5 = '#8FEB8F',
-- Red
color6 = '#F45F45',
-- Loading lua script for drawning rings
lua_load = '~/.config/awesome/conky/seamod_rings.lua',
lua_draw_hook_pre = 'main',
};
--${offset 15}${font Droid Sans:size=11:style=normal}${color1}${pre_exec lsb_release -d | cut -f 2} - $sysname $kernel
conky.text = [[
${font Droid Sans:size=8:style=normal}${color1}$kernel
${font Droid Sans:size=8:style=normal}${color1}Temp ${color3}$alignr${exec 10 sensors | grep Core\ 3 | awk '{print $3}'}
${font Droid Sans:size=9:style=normal}${color1}NVidia Optimus: ${color3}$alignr${execi 10 cat /proc/acpi/bbswitch | awk '{print $2}'}
${font Droid Sans:size=9:style=normal}${color1}Uptime: $alignr${color3}${color3}$uptime
#${voffset 40}
#${offset 65}${font Droid Sans:size=16:style=bold}${color5}BAT
#
#${voffset -35}
${font Droid Sans:size=8:style=normal}${color1}Status ${color3}$alignr${battery BAT1}
${font Droid Sans:size=8:style=normal}${color1}Time Left ${font Droid Sans:size=8:bold:style=normal}${color4}$alignr${format_time $battery_time "\hh\mm"}${battery_time BAT1}
# Showing CPU Graph
${voffset 40}
${offset 65}${font Droid Sans:size=19:style=bold}${color5}CPU
${voffset 10}
${cpugraph cpu1 20,118 666666 666666}
${voffset -40}
${font Droid Sans:size=9:style=normal}${color1}CPU Freq: ${font Droid Sans:size=9:bold:style=normal}${alignr}${color4}${freq} ${color2}MHz
# Showing TOP 5 CPU-consumers
${font Droid Sans:bold:size=8:style=normal}${color4}${top name 1}${alignr}${top cpu 1}%
${font Droid Sans:size=8:style=normal}${color1}${top name 2}${alignr}${top cpu 2}%
${font Droid Sans:size=8:style=normal}${color2}${top name 3}${alignr}${top cpu 3}%
${font Droid Sans:size=8:style=normal}${color3}${top name 4}${alignr}${top cpu 4}%
${font Droid Sans:size=8:style=normal}${color3}${top name 5}${alignr}${top cpu 5}%
#Showing memory part with TOP 5
${voffset 30}
${offset 65}${font Droid Sans:size=14:style=bold}${color5}MEM
${voffset 1}
${font Droid Sans:bold:size=8:style=normal}${color4}${top_mem name 1}${alignr}${top_mem mem_res 1}
${font Droid Sans:size=8:style=normal}${color1}${top_mem name 2}${alignr}${top_mem mem_res 2}
${font Droid Sans:size=8:style=normal}${color2}${top_mem name 3}${alignr}${top_mem mem_res 3}
${font Droid Sans:size=8:style=normal}${color3}${top_mem name 4}${alignr}${top_mem mem_res 4}
${font Droid Sans:size=8:style=normal}${color3}${top_mem name 4}${alignr}${top_mem mem_res 5}
# Showing disk partitions: boot, root, home
${voffset 47}
${offset 70}${font Droid Sans:size=12:style=bold}${color5}DISKS
${voffset 20}
${diskiograph 20,118 666666 666666}${voffset -30}
${voffset 10}
${font Droid Sans:size=8:}${color1}Boot Free: ${alignr}$color3${font Droid Sans:size=8:style=normal}${fs_free /boot}
${font Droid Sans:size=8:}${color1}Root Free: ${alignr}$color3${font Droid Sans:size=8:style=normal}${fs_free /}
${font Droid Sans:size=8:}${color1}Home Free: ${alignr}$color3${font Droid Sans:size=8:style=normal}${fs_free /home}
# Network
${voffset 49}
${offset 70}${font Droid Sans:size=14:style=bold}${color5}WiFi
${voffset 10}
${font Droid Sans:size=10:style=bold}${color1}${color2}VPN: ${font Droid Sans:size=10:style=bold}${color5}${if_up tun0}UP${else}${color6}Down$endif$font$color
${font Droid Sans:size=8:style=bold}${color1}Lan IP: ${alignr}$color3${addr wlp6s0}
${font Droid Sans:size=8:style=bold}${color1}Ext IP: ${alignr}${color3}NOPE#${alignr}$color3${execi 600 wget -q -O /dev/stdout http://checkip.dyndns.org/ | cut -d : -f 2- | cut -d \< -f -1}
#${font Droid Sans:size=8:style=bold}${alignr}$color3${execi 600 wget -q -O /dev/stdout https://www.dnsleaktest.com/ | grep from | grep -o '<p>.*<img' | grep -o '>.*<' | grep -oEi '[a-zA-Z0-9 ,]+'}
${voffset 10}
${color1}${font Droid Sans:size=8:style=bold}Up: ${alignr}${font Droid Sans:size=8:style=normal}$color2${upspeed wlp6s0} / ${totalup wlp6s0}
${upspeedgraph wlp6s0 40,118 4B1B0C FF5C2B 1280KiB -l}
${color1}${font Droid Sans:size=8:style=bold}Down: ${alignr}${font Droid Sans:size=8:style=normal}$color2${downspeed wlp6s0} / ${totaldown wlp6s0}
${downspeedgraph wlp6s0 40,118 324D23 77B753 1280KiB -l}
]];

View File

@@ -0,0 +1,478 @@
--==============================================================================
-- seamod_rings.lua
--
-- Date : 05/02/2012
-- Author : SeaJey
-- Version : v0.1
-- License : Distributed under the terms of GNU GPL version 2 or later
--
-- This version is a modification of lunatico_rings.lua wich is modification of conky_orange.lua
--
-- conky_orange.lua: http://gnome-look.org/content/show.php?content=137503&forumpage=0
-- lunatico_rings.lua: http://gnome-look.org/content/show.php?content=142884
--==============================================================================
require 'cairo'
gauge = {
{
name='cpu', arg='cpu1', max_value=100,
x=60, y=175,
graph_radius=54,
graph_thickness=5,
graph_start_angle=180,
graph_unit_angle=2.7, graph_unit_thickness=2.7,
graph_bg_colour=0xffffff, graph_bg_alpha=0.1,
graph_fg_colour=0xFFFFFF, graph_fg_alpha=0.3,
hand_fg_colour=0x7A5ADA, hand_fg_alpha=1.0,
txt_radius=0,
txt_weight=0, txt_size=10.0,
txt_fg_colour=0x7A5ADA, txt_fg_alpha=1.0,
graduation_radius=28,
graduation_thickness=0, graduation_mark_thickness=1,
graduation_unit_angle=27,
graduation_fg_colour=0xFFFFFF, graduation_fg_alpha=0.3,
caption='',
caption_weight=1, caption_size=9.0,
caption_fg_colour=0xFFFFFF, caption_fg_alpha=0.3,
},
{
name='cpu', arg='cpu2', max_value=100,
x=60, y=175,
graph_radius=48,
graph_thickness=5,
graph_start_angle=180,
graph_unit_angle=2.7, graph_unit_thickness=2.7,
graph_bg_colour=0xffffff, graph_bg_alpha=0.1,
graph_fg_colour=0xFFFFFF, graph_fg_alpha=0.3,
hand_fg_colour=0x7A5ADA, hand_fg_alpha=1.0,
txt_radius=0,
txt_weight=0, txt_size=10.0,
txt_fg_colour=0x7A5ADA, txt_fg_alpha=1.0,
graduation_radius=28,
graduation_thickness=0, graduation_mark_thickness=1,
graduation_unit_angle=27,
graduation_fg_colour=0xFFFFFF, graduation_fg_alpha=0.3,
caption='',
caption_weight=1, caption_size=9.0,
caption_fg_colour=0xFFFFFF, caption_fg_alpha=0.3,
},
{
name='cpu', arg='cpu3', max_value=100,
x=60, y=175,
graph_radius=42,
graph_thickness=5,
graph_start_angle=180,
graph_unit_angle=2.7, graph_unit_thickness=2.7,
graph_bg_colour=0xffffff, graph_bg_alpha=0.1,
graph_fg_colour=0xFFFFFF, graph_fg_alpha=0.3,
hand_fg_colour=0x7A5ADA, hand_fg_alpha=1.0,
txt_radius=0,
txt_weight=0, txt_size=10.0,
txt_fg_colour=0x7A5ADA, txt_fg_alpha=1.0,
graduation_radius=28,
graduation_thickness=0, graduation_mark_thickness=1,
graduation_unit_angle=27,
graduation_fg_colour=0xFFFFFF, graduation_fg_alpha=0.3,
caption='',
caption_weight=1, caption_size=9.0,
caption_fg_colour=0xFFFFFF, caption_fg_alpha=0.3,
},
{
name='cpu', arg='cpu4', max_value=100,
x=60, y=175,
graph_radius=36,
graph_thickness=5,
graph_start_angle=180,
graph_unit_angle=2.7, graph_unit_thickness=2.7,
graph_bg_colour=0xffffff, graph_bg_alpha=0.1,
graph_fg_colour=0xFFFFFF, graph_fg_alpha=0.3,
hand_fg_colour=0x7A5ADA, hand_fg_alpha=1.0,
txt_radius=0,
txt_weight=0, txt_size=10.0,
txt_fg_colour=0x7A5ADA, txt_fg_alpha=1.0,
graduation_radius=28,
graduation_thickness=0, graduation_mark_thickness=1,
graduation_unit_angle=27,
graduation_fg_colour=0xFFFFFF, graduation_fg_alpha=0.3,
caption='',
caption_weight=1, caption_size=9.0,
caption_fg_colour=0xFFFFFF, caption_fg_alpha=0.3,
},
{
name='cpu', arg='cpu5', max_value=100,
x=60, y=175,
graph_radius=30,
graph_thickness=5,
graph_start_angle=180,
graph_unit_angle=2.7, graph_unit_thickness=2.7,
graph_bg_colour=0xffffff, graph_bg_alpha=0.1,
graph_fg_colour=0xFFFFFF, graph_fg_alpha=0.3,
hand_fg_colour=0x7A5ADA, hand_fg_alpha=1.0,
txt_radius=0,
txt_weight=0, txt_size=10.0,
txt_fg_colour=0x7A5ADA, txt_fg_alpha=1.0,
graduation_radius=28,
graduation_thickness=0, graduation_mark_thickness=1,
graduation_unit_angle=27,
graduation_fg_colour=0xFFFFFF, graduation_fg_alpha=0.3,
caption='',
caption_weight=1, caption_size=9.0,
caption_fg_colour=0xFFFFFF, caption_fg_alpha=0.3,
},
{
name='cpu', arg='cpu6', max_value=100,
x=60, y=175,
graph_radius=24,
graph_thickness=5,
graph_start_angle=180,
graph_unit_angle=2.7, graph_unit_thickness=2.7,
graph_bg_colour=0xffffff, graph_bg_alpha=0.1,
graph_fg_colour=0xFFFFFF, graph_fg_alpha=0.3,
hand_fg_colour=0x7A5ADA, hand_fg_alpha=1.0,
txt_radius=0,
txt_weight=0, txt_size=10.0,
txt_fg_colour=0x7A5ADA, txt_fg_alpha=1.0,
graduation_radius=28,
graduation_thickness=0, graduation_mark_thickness=1,
graduation_unit_angle=27,
graduation_fg_colour=0xFFFFFF, graduation_fg_alpha=0.3,
caption='',
caption_weight=1, caption_size=9.0,
caption_fg_colour=0xFFFFFF, caption_fg_alpha=0.3,
},
{
name='cpu', arg='cpu7', max_value=100,
x=60, y=175,
graph_radius=18,
graph_thickness=5,
graph_start_angle=180,
graph_unit_angle=2.7, graph_unit_thickness=2.7,
graph_bg_colour=0xffffff, graph_bg_alpha=0.1,
graph_fg_colour=0xFFFFFF, graph_fg_alpha=0.3,
hand_fg_colour=0x7A5ADA, hand_fg_alpha=1.0,
txt_radius=0,
txt_weight=0, txt_size=10.0,
txt_fg_colour=0x7A5ADA, txt_fg_alpha=1.0,
graduation_radius=28,
graduation_thickness=0, graduation_mark_thickness=1,
graduation_unit_angle=27,
graduation_fg_colour=0xFFFFFF, graduation_fg_alpha=0.3,
caption='',
caption_weight=1, caption_size=9.0,
caption_fg_colour=0xFFFFFF, caption_fg_alpha=0.3,
},
{
name='cpu', arg='cpu8', max_value=100,
x=60, y=175,
graph_radius=12,
graph_thickness=5,
graph_start_angle=180,
graph_unit_angle=2.7, graph_unit_thickness=2.7,
graph_bg_colour=0xffffff, graph_bg_alpha=0.1,
graph_fg_colour=0xFFFFFF, graph_fg_alpha=0.3,
hand_fg_colour=0x7A5ADA, hand_fg_alpha=1.0,
txt_radius=0,
txt_weight=0, txt_size=10.0,
txt_fg_colour=0x7A5ADA, txt_fg_alpha=1.0,
graduation_radius=28,
graduation_thickness=0, graduation_mark_thickness=1,
graduation_unit_angle=27,
graduation_fg_colour=0xFFFFFF, graduation_fg_alpha=0.3,
caption='',
caption_weight=1, caption_size=9.0,
caption_fg_colour=0xFFFFFF, caption_fg_alpha=0.3,
},
--{
-- name='battery_percent', arg='BAT1', max_value=100,
-- x=60, y=133,
-- graph_radius=35,
-- graph_thickness=20,
-- graph_start_angle=180,
-- graph_unit_angle=2.7, graph_unit_thickness=2.7,
-- graph_bg_colour=0xffffff, graph_bg_alpha=0.1,
-- graph_fg_colour=0xFFFFFF, graph_fg_alpha=0.3,
-- hand_fg_colour=0x7A5ADA, hand_fg_alpha=1.0,
-- txt_radius=13,
-- txt_weight=1, txt_size=10.0,
-- txt_fg_colour=0x7A5ADA, txt_fg_alpha=1.0,
-- graduation_radius=23,
-- graduation_thickness=0, graduation_mark_thickness=2,
-- graduation_unit_angle=27,
-- graduation_fg_colour=0xFFFFFF, graduation_fg_alpha=0.5,
-- caption='',
-- caption_weight=1, caption_size=10.0,
-- caption_fg_colour=0xFFFFFF, caption_fg_alpha=0.3,
--},
{
name='memperc', arg='', max_value=100,
x=60, y=428,
graph_radius=35,
graph_thickness=20,
graph_start_angle=180,
graph_unit_angle=2.7, graph_unit_thickness=2.7,
graph_bg_colour=0xffffff, graph_bg_alpha=0.1,
graph_fg_colour=0xFFFFFF, graph_fg_alpha=0.3,
hand_fg_colour=0x7A5ADA, hand_fg_alpha=1.0,
txt_radius=18,
txt_weight=0, txt_size=10.0,
txt_fg_colour=0x7A5ADA, txt_fg_alpha=1.0,
graduation_radius=23,
graduation_thickness=0, graduation_mark_thickness=2,
graduation_unit_angle=27,
graduation_fg_colour=0xFFFFFF, graduation_fg_alpha=0.5,
caption='',
caption_weight=1, caption_size=10.0,
caption_fg_colour=0xFFFFFF, caption_fg_alpha=0.3,
},
{
name='fs_used_perc', arg='/home', max_value=100,
x=60, y=620,
graph_radius=52,
graph_thickness=7,
graph_start_angle=180,
graph_unit_angle=2.7, graph_unit_thickness=2.7,
graph_bg_colour=0xffffff, graph_bg_alpha=0.1,
graph_fg_colour=0xFFFFFF, graph_fg_alpha=0.3,
hand_fg_colour=0x7A5ADA, hand_fg_alpha=1.0,
txt_radius=65,
txt_weight=0, txt_size=10.0,
txt_fg_colour=0x7A5ADA, txt_fg_alpha=1.0,
graduation_radius=23,
graduation_thickness=0, graduation_mark_thickness=2,
graduation_unit_angle=27,
graduation_fg_colour=0xFFFFFF, graduation_fg_alpha=0.3,
caption='/home',
caption_weight=1, caption_size=12.0,
caption_fg_colour=0xFFFFFF, caption_fg_alpha=0.5,
},
{
name='fs_used_perc', arg='/', max_value=100,
x=60, y=620,
graph_radius=40,
graph_thickness=7,
graph_start_angle=180,
graph_unit_angle=2.7, graph_unit_thickness=2.7,
graph_bg_colour=0xffffff, graph_bg_alpha=0.1,
graph_fg_colour=0xFFFFFF, graph_fg_alpha=0.3,
hand_fg_colour=0x7A5ADA, hand_fg_alpha=1.0,
txt_radius=27,
txt_weight=0, txt_size=10.0,
txt_fg_colour=0x7A5ADA, txt_fg_alpha=1.0,
graduation_radius=23,
graduation_thickness=0, graduation_mark_thickness=2,
graduation_unit_angle=27,
graduation_fg_colour=0xFFFFFF, graduation_fg_alpha=0.3,
caption='/',
caption_weight=1, caption_size=12.0,
caption_fg_colour=0xFFFFFF, caption_fg_alpha=0.5,
},
{
name='fs_used_perc', arg='/boot', max_value=100,
x=60, y=620,
graph_radius=28,
graph_thickness=7,
graph_start_angle=180,
graph_unit_angle=2.7, graph_unit_thickness=2.7,
graph_bg_colour=0xffffff, graph_bg_alpha=0.1,
graph_fg_colour=0xFFFFFF, graph_fg_alpha=0.3,
hand_fg_colour=0x7A5ADA, hand_fg_alpha=1.0,
txt_radius=16,
txt_weight=0, txt_size=10.0,
txt_fg_colour=0x7A5ADA, txt_fg_alpha=1.0,
graduation_radius=23,
graduation_thickness=0, graduation_mark_thickness=2,
graduation_unit_angle=27,
graduation_fg_colour=0xFFFFFF, graduation_fg_alpha=0.3,
caption='/boot',
caption_weight=1, caption_size=12.0,
caption_fg_colour=0xFFFFFF, caption_fg_alpha=0.5,
},
{
name='downspeedf', arg='wlp6s0', max_value=100,
x=60, y=835,
graph_radius=42,
graph_thickness=7,
graph_start_angle=180,
graph_unit_angle=2.7, graph_unit_thickness=2.7,
graph_bg_colour=0xffffff, graph_bg_alpha=0.1,
graph_fg_colour=0xFFFFFF, graph_fg_alpha=0.3,
hand_fg_colour=0x7A5ADA, hand_fg_alpha=0,
txt_radius=60,
txt_weight=0, txt_size=10.0,
txt_fg_colour=0x7A5ADA, txt_fg_alpha=1.0,
graduation_radius=28,
graduation_thickness=0, graduation_mark_thickness=1,
graduation_unit_angle=27,
graduation_fg_colour=0xFFFFFF, graduation_fg_alpha=0.3,
caption='Down',
caption_weight=1, caption_size=12.0,
caption_fg_colour=0xFFFFFF, caption_fg_alpha=0.5,
},
{
name='upspeedf', arg='wlp6s0', max_value=100,
x=60, y=835,
graph_radius=30,
graph_thickness=7,
graph_start_angle=180,
graph_unit_angle=2.7, graph_unit_thickness=2.7,
graph_bg_colour=0xffffff, graph_bg_alpha=0.1,
graph_fg_colour=0xFFFFFF, graph_fg_alpha=0.3,
hand_fg_colour=0x7A5ADA, hand_fg_alpha=0,
txt_radius=20,
txt_weight=0, txt_size=10.0,
txt_fg_colour=0x7A5ADA, txt_fg_alpha=1.0,
graduation_radius=28,
graduation_thickness=0, graduation_mark_thickness=1,
graduation_unit_angle=27,
graduation_fg_colour=0xFFFFFF, graduation_fg_alpha=0.3,
caption='Up',
caption_weight=1, caption_size=12.0,
caption_fg_colour=0xFFFFFF, caption_fg_alpha=0.5,
},
}
-- converts color in hexa to decimal
function rgb_to_r_g_b(colour, alpha)
return ((colour / 0x10000) % 0x100) / 255., ((colour / 0x100) % 0x100) / 255., (colour % 0x100) / 255., alpha
end
-- convert degree to rad and rotate (0 degree is top/north)
function angle_to_position(start_angle, current_angle)
local pos = current_angle + start_angle
return ( ( pos * (2 * math.pi / 360) ) - (math.pi / 2) )
end
-- displays gauges
function draw_gauge_ring(display, data, value)
local max_value = data['max_value']
local x, y = data['x'], data['y']
local graph_radius = data['graph_radius']
local graph_thickness, graph_unit_thickness = data['graph_thickness'], data['graph_unit_thickness']
local graph_start_angle = data['graph_start_angle']
local graph_unit_angle = data['graph_unit_angle']
local graph_bg_colour, graph_bg_alpha = data['graph_bg_colour'], data['graph_bg_alpha']
local graph_fg_colour, graph_fg_alpha = data['graph_fg_colour'], data['graph_fg_alpha']
local hand_fg_colour, hand_fg_alpha = data['hand_fg_colour'], data['hand_fg_alpha']
local graph_end_angle = (max_value * graph_unit_angle) % 360
-- background ring
cairo_arc(display, x, y, graph_radius, angle_to_position(graph_start_angle, 0), angle_to_position(graph_start_angle, graph_end_angle))
cairo_set_source_rgba(display, rgb_to_r_g_b(graph_bg_colour, graph_bg_alpha))
cairo_set_line_width(display, graph_thickness)
cairo_stroke(display)
-- arc of value
local val = value % (max_value + 1)
local start_arc = 0
local stop_arc = 0
local i = 1
while i <= val do
start_arc = (graph_unit_angle * i) - graph_unit_thickness
stop_arc = (graph_unit_angle * i)
cairo_arc(display, x, y, graph_radius, angle_to_position(graph_start_angle, start_arc), angle_to_position(graph_start_angle, stop_arc))
cairo_set_source_rgba(display, rgb_to_r_g_b(graph_fg_colour, graph_fg_alpha))
cairo_stroke(display)
i = i + 1
end
local angle = start_arc
-- hand
start_arc = (graph_unit_angle * val) - (graph_unit_thickness * 2)
stop_arc = (graph_unit_angle * val)
cairo_arc(display, x, y, graph_radius, angle_to_position(graph_start_angle, start_arc), angle_to_position(graph_start_angle, stop_arc))
cairo_set_source_rgba(display, rgb_to_r_g_b(hand_fg_colour, hand_fg_alpha))
cairo_stroke(display)
-- graduations marks
local graduation_radius = data['graduation_radius']
local graduation_thickness, graduation_mark_thickness = data['graduation_thickness'], data['graduation_mark_thickness']
local graduation_unit_angle = data['graduation_unit_angle']
local graduation_fg_colour, graduation_fg_alpha = data['graduation_fg_colour'], data['graduation_fg_alpha']
if graduation_radius > 0 and graduation_thickness > 0 and graduation_unit_angle > 0 then
local nb_graduation = graph_end_angle / graduation_unit_angle
local i = 0
while i < nb_graduation do
cairo_set_line_width(display, graduation_thickness)
start_arc = (graduation_unit_angle * i) - (graduation_mark_thickness / 2)
stop_arc = (graduation_unit_angle * i) + (graduation_mark_thickness / 2)
cairo_arc(display, x, y, graduation_radius, angle_to_position(graph_start_angle, start_arc), angle_to_position(graph_start_angle, stop_arc))
cairo_set_source_rgba(display,rgb_to_r_g_b(graduation_fg_colour,graduation_fg_alpha))
cairo_stroke(display)
cairo_set_line_width(display, graph_thickness)
i = i + 1
end
end
-- text
local txt_radius = data['txt_radius']
local txt_weight, txt_size = data['txt_weight'], data['txt_size']
local txt_fg_colour, txt_fg_alpha = data['txt_fg_colour'], data['txt_fg_alpha']
local movex = txt_radius * math.cos(angle_to_position(graph_start_angle, angle))
local movey = txt_radius * math.sin(angle_to_position(graph_start_angle, angle))
cairo_select_font_face (display, "ubuntu", CAIRO_FONT_SLANT_NORMAL, txt_weight)
cairo_set_font_size (display, txt_size)
cairo_set_source_rgba (display, rgb_to_r_g_b(txt_fg_colour, txt_fg_alpha))
if txt_radius > 0 then
cairo_move_to (display, x + movex - (txt_size / 2), y + movey + 3)
cairo_show_text (display, value)
cairo_stroke (display)
end
-- caption
local caption = data['caption']
local caption_weight, caption_size = data['caption_weight'], data['caption_size']
local caption_fg_colour, caption_fg_alpha = data['caption_fg_colour'], data['caption_fg_alpha']
local tox = graph_radius * (math.cos((graph_start_angle * 2 * math.pi / 360)-(math.pi/2)))
local toy = graph_radius * (math.sin((graph_start_angle * 2 * math.pi / 360)-(math.pi/2)))
cairo_select_font_face (display, "ubuntu", CAIRO_FONT_SLANT_NORMAL, caption_weight);
cairo_set_font_size (display, caption_size)
cairo_set_source_rgba (display, rgb_to_r_g_b(caption_fg_colour, caption_fg_alpha))
cairo_move_to (display, x + tox + 5, y + toy + 5)
-- bad hack but not enough time !
if graph_start_angle < 105 then
cairo_move_to (display, x + tox - 30, y + toy + 1)
end
cairo_show_text (display, caption)
cairo_stroke (display)
end
-- loads data and displays gauges
function go_gauge_rings(display)
local function load_gauge_rings(display, data)
local str, value = '', 0
str = string.format('${%s %s}',data['name'], data['arg'])
str = conky_parse(str)
value = tonumber(str)
draw_gauge_ring(display, data, value)
end
for i in pairs(gauge) do
load_gauge_rings(display, gauge[i])
end
end
-------------------------------------------------------------------------------
-- MAIN
function conky_main()
if conky_window == nil then
return
end
local cs = cairo_xlib_surface_create(conky_window.display, conky_window.drawable, conky_window.visual, conky_window.width, conky_window.height)
local display = cairo_create(cs)
local updates = conky_parse('${updates}')
update_num = tonumber(updates)
if update_num > 5 then
go_gauge_rings(display)
end
cairo_surface_destroy(cs)
cairo_destroy(display)
end

View File

@@ -0,0 +1,339 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc., <http://fsf.org/>
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Lesser General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
{description}
Copyright (C) {year} {fullname}
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
{signature of Ty Coon}, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License.

View File

@@ -0,0 +1,52 @@
Awesome-Freedesktop
===================
-------------------------------------------------------------------
Freedesktop.org menu and desktop icons support for Awesome WM 4.x
-------------------------------------------------------------------
:Original author: Antonio Terceiro
:Maintainer: Luke Bonham
:Version: git
:License: GNU-GPL2_
:Source: https://github.com/copycat-killer/awesome-freedesktop
Description
-----------
This is a port of awesome-freedesktop_ to Awesome_ 4.x.
See branches_ for previous versions.
Since the introduction of Menubar_ as core library for providing Freedesktop.org menu functionalities in Awesome,
we can now avoid all the dirty work by just exploiting ``menubar.utils`` functions.
At the initial status of this port, the menu is pretty much complete, while the desktop icons are very basic,
so the long term objective will be to complete functionalities on this part too.
More specifically, the todo list is:
- A better way to handle desktop icons path
- Ability to drag and line up icons
- Event-based signals, in particular:
- Updating trash icon according to its status
- Dynamic update (no need to restart Awesome to see changes on desktop)
Screenshot
----------
.. image:: screenshot.png
:align: center
:alt: Showcase of Freedesktop support in Awesome, using Adwaita icons
Installation and usage
----------------------
Read the wiki_.
.. _GNU-GPL2: http://www.gnu.org/licenses/gpl-2.0.html
.. _awesome-freedesktop: https://github.com/terceiro/awesome-freedesktop
.. _Awesome: https://github.com/awesomeWM/awesome
.. _branches: https://github.com/copycat-killer/awesome-freedesktop/branches
.. _Menubar: https://github.com/awesomeWM/awesome/tree/master/lib/menubar
.. _wiki: https://github.com/copycat-killer/awesome-freedesktop/wiki

View File

@@ -0,0 +1,20 @@
package = "awesome-freedesktop"
version = "git"
source = {
url = "https://github.com/copycat-killer/awesome-freedesktop",
tag = "git"
}
description = {
summary = "Freedesktop.org menu and desktop icons support for Awesome WM",
homepage = "https://github.com/copycat-killer/awesome-freedesktop",
license = "GPL v2"
}
dependencies = {
"lua >= 5.3",
"awesome >= 4.0"
}
supported_platforms = { "linux" }
build = {
type = "builtin",
modules = { freedesktop = "init.lua" }
}

View File

@@ -0,0 +1,255 @@
--[[
Awesome-Freedesktop
Freedesktop.org compliant desktop entries and menu
Desktop section
Licensed under GNU General Public License v2
* (c) 2016, Luke Bonham
* (c) 2009-2015, Antonio Terceiro
--]]
local awful = require("awful")
local theme = require("beautiful")
local utils = require("menubar.utils")
local wibox = require("wibox")
local capi = { screen = screen }
local io = io
local ipairs = ipairs
local mouse = mouse
local os = os
local string = { format = string.format }
local table = table
-- Desktop icons
-- freedesktop.desktop
local desktop = {
-- Default desktop basic icons
baseicons = {
[1] = {
label = "This PC",
icon = "computer",
onclick = "computer://"
},
[2] = {
label = "Home",
icon = "user-home",
onclick = os.getenv("HOME")
},
[3] = {
label = "Trash",
icon = "user-trash",
onclick = "trash://"
}
},
-- Default parameters
iconsize = { width = 48, height = 48 },
labelsize = { width = 140, height = 20 },
margin = { x = 20, y = 20 },
}
-- MIME types list
local mime_types = {}
-- Icons positioning
local desktop_current_pos = {}
-- @return iterator on input pipe
local function pipelines(...)
local f = assert(io.popen(...))
return function ()
local data = f:read()
if data == nil then f:close() end
return data
end
end
-- Adds an icon to desktop
-- @param args settings from desktop.add_icons
-- @param label icon string label
-- @param icon icon string file path
-- @param onclick function to execute on click
function desktop.add_single_icon(args, label, icon, onclick)
local s = args.screen
-- define icon dimensions and position
if not desktop_current_pos[s] then
desktop_current_pos[s] = { x = (capi.screen[s].geometry.x + args.iconsize.width + args.margin.x), y = 40 }
end
local totheight = (icon and args.iconsize.height or 0) + (label and args.labelsize.height or 0)
if totheight == 0 then return end
if desktop_current_pos[s].y + totheight > capi.screen[s].geometry.height - 40 then
desktop_current_pos[s].x = desktop_current_pos[s].x + args.labelsize.width + args.iconsize.width + args.margin.x
desktop_current_pos[s].y = 40
end
local common = { screen = s, bg = "#00000000", visible = true, type = "desktop" }
-- create icon container
if icon then
common.width = args.iconsize.width
common.height = args.iconsize.height
common.x = desktop_current_pos[s].x
common.y = desktop_current_pos[s].y
icon = wibox.widget {
image = icon,
resize = false,
widget = wibox.widget.imagebox
}
icon:buttons(awful.button({ }, 1, nil, onclick))
icon_container = wibox(common)
icon_container:set_widget(icon)
desktop_current_pos[s].y = desktop_current_pos[s].y + args.iconsize.height + 5
end
-- create label container
if label then
common.width = args.labelsize.width
common.height = args.labelsize.height
common.x = desktop_current_pos[s].x - (args.labelsize.width/2) + args.iconsize.width/2
common.y = desktop_current_pos[s].y
caption = wibox.widget {
text = label,
align = "center",
forced_width = common.width,
forced_height = common.height,
ellipsize = "middle",
widget = wibox.widget.textbox
}
caption:buttons(awful.button({ }, 1, onclick))
caption_container = wibox(common)
caption_container:set_widget(caption)
end
desktop_current_pos[s].y = desktop_current_pos[s].y + args.labelsize.height + args.margin.y
end
-- Adds base icons (This PC, Trash, etc) to desktop
-- @param args settings from desktop.add_icons
function desktop.add_base_icons(args)
for _,base in ipairs(args.baseicons) do
desktop.add_single_icon(args, base.label, utils.lookup_icon(base.icon), function()
awful.spawn(string.format("%s '%s'", args.open_width, base.onclick))
end)
end
end
-- Looks up a suitable icon for filename
-- @param filename string file name
-- @return icon file path (string)
function desktop.lookup_file_icon(filename)
-- load system MIME types
if #mime_types == 0 then
for line in io.lines("/etc/mime.types") do
if not line:find("^#") then
local parsed = {}
for w in line:gmatch("[^%s]+") do
table.insert(parsed, w)
end
if #parsed > 1 then
for i = 2, #parsed do
mime_types[parsed[i]] = parsed[1]:gsub("/", "-")
end
end
end
end
end
-- try to search a possible icon among standards
local extension = filename:match("%a+$")
local mime = mime_types[extension] or ""
local mime_family = mime:match("^%a+") or ""
local possible_filenames = {
mime, "gnome-mime-" .. mime,
mime_family, "gnome-mime-" .. mime_family,
extension
}
for i, filename in ipairs(possible_filenames) do
local icon = utils.lookup_icon(filename)
if icon then return icon end
end
-- if we don"t find ad icon, then pretend is a plain text file
return utils.lookup_icon("text-x-generic")
end
-- Parse subdirectories and files list from input directory
-- @input dir directory to parse (string)
-- @return files table with found entries
function desktop.parse_dirs_and_files(dir)
local files = {}
local paths = pipelines('find '..dir..' -maxdepth 1 -type d | tail -1')
for path in paths do
if path:match("[^/]+$") then
local file = {}
file.filename = path:match("[^/]+$")
file.path = path
file.show = true
file.icon = utils.lookup_icon("folder")
table.insert(files, file)
end
end
local paths = pipelines('find '..dir..' -maxdepth 1 -type f')
for path in paths do
if not path:find("%.desktop$") then
local file = {}
file.filename = path:match("[^/]+$")
file.path = path
file.show = true
file.icon = desktop.lookup_file_icon(file.filename)
table.insert(files, file)
end
end
return files
end
-- Adds subdirectories and files icons from args.dir
-- @param args settings from desktop.add_icons
function desktop.add_dirs_and_files_icons(args)
for _, file in ipairs(desktop.parse_dirs_and_files(args.dir)) do
if file.show then
local label = args.showlabels and file.filename or nil
local onclick = function () awful.spawn(string.format("%s '%s'", args.open_with, file.path)) end
desktop.add_single_icon(args, label, file.icon, onclick)
end
end
end
-- Main function, adds base, directory and files icons
-- @param args user defined settings, with fallback on defaults
function desktop.add_icons(args)
args = args or {}
args.screen = args.screen or mouse.screen
args.dir = args.dir or os.getenv("HOME") .. "/Desktop"
args.showlabels = args.showlabel or true
args.open_with = args.open_with or "xdg_open"
args.baseicons = args.baseicons or desktop.baseicons
args.iconsize = args.iconsize or desktop.iconsize
args.labelsize = args.labelsize or desktop.labelsize
args.margin = args.margin or desktop.margin
-- trying to fallback on Adwaita if theme.icon_theme is not defined
-- if Adwaita is missing too, no icons will be shown
if not theme.icon_theme then
theme.icon_theme = args.icon_theme or "Adwaita"
end
desktop.add_base_icons(args)
desktop.add_dirs_and_files_icons(args)
end
return desktop

View File

@@ -0,0 +1,16 @@
--[[
Awesome-Freedesktop
Freedesktop.org compliant desktop entries and menu
Licensed under GNU General Public License v2
* (c) 2016, Luke Bonham
* (c) 2009-2015, Antonio Terceiro
--]]
return {
desktop = require("freedesktop.desktop"),
menu = require("freedesktop.menu")
}

View File

@@ -0,0 +1,123 @@
--[[
Awesome-Freedesktop
Freedesktop.org compliant desktop entries and menu
Menu section
Licensed under GNU General Public License v2
* (c) 2016, Luke Bonham
* (c) 2014, Harvey Mittens
--]]
local awful_menu = require("awful.menu")
local menu_gen = require("menubar.menu_gen")
local menu_utils = require("menubar.utils")
local icon_theme = require("menubar.icon_theme")
local os = { execute = os.execute,
getenv = os.getenv }
local pairs = pairs
local string = { byte = string.byte,
format = string.format }
local table = { insert = table.insert,
remove = table.remove,
sort = table.sort }
-- Add support for NixOS systems too
table.insert(menu_gen.all_menu_dirs, string.format("%s/.nix-profile/share/applications", os.getenv("HOME")))
-- Remove non existent paths in order to avoid issues
local existent_paths = {}
for k,v in pairs(menu_gen.all_menu_dirs) do
if os.execute(string.format("ls %s &> /dev/null", v)) then
table.insert(existent_paths, v)
end
end
menu_gen.all_menu_dirs = existent_paths
-- Expecting a wm_name of awesome omits too many applications and tools
menu_utils.wm_name = ""
-- Menu
-- freedesktop.menu
local menu = {}
-- Determines whether an table includes a certain element
-- @param tab a given table
-- @param val the element to search for
-- @return true if the given string is found within the search table; otherwise, false if not
local function has_value (tab, val)
for index, value in ipairs(tab) do
if val:find(value) then
return true
end
end
return false
end
-- Use MenuBar parsing utils to build a menu for Awesome
-- @return awful.menu
function menu.build(args)
local args = args or {}
local icon_size = args.icon_size
local before = args.before or {}
local after = args.after or {}
local skip_items = args.skip_items or {}
local result = {}
local _menu = awful_menu({ items = before })
menu_gen.generate(function(entries)
-- Add category icons
for k, v in pairs(menu_gen.all_categories) do
table.insert(result, { k, {}, v.icon })
end
-- Get items table
for k, v in pairs(entries) do
for _, cat in pairs(result) do
if cat[1] == v.category then
if not has_value(skip_items, v.name) then
table.insert(cat[2], { v.name, v.cmdline, v.icon })
end
break
end
end
end
-- Cleanup things a bit
for i = #result, 1, -1 do
local v = result[i]
if #v[2] == 0 then
-- Remove unused categories
table.remove(result, i)
else
--Sort entries alphabetically (by name)
table.sort(v[2], function (a, b) return string.byte(a[1]) < string.byte(b[1]) end)
-- Replace category name with nice name
v[1] = menu_gen.all_categories[v[1]].name
end
end
-- Sort categories alphabetically also
table.sort(result, function(a, b) return string.byte(a[1]) < string.byte(b[1]) end)
-- Add items to menu
for _, v in pairs(result) do _menu:add(v) end
for _, v in pairs(after) do _menu:add(v) end
end)
-- Set icon size
if icon_size then
for _,v in pairs(menu_gen.all_categories) do
v.icon = icon_theme():find_icon_path(v.icon_name, icon_size)
end
end
return _menu
end
return menu

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

View File

@@ -0,0 +1,21 @@
# If you have a question
Take the following steps:
1. [Google it](https://encrypted.google.com)
2. Search [Awesome doc](https://awesomewm.org/doc)
3. Ask [community](https://awesomewm.org/community)
and, if you still don't have an answer, you can ask here.
**Please be warned:** if your question is __unrelated__ to this repository, a reply is only an act of kindness.
# If you have an issue
**Please read the [wiki](https://github.com/copycat-killer/lain/wiki) and search the [Issues section](https://github.com/copycat-killer/lain/issues) first.**
If you can't find a solution there, then go ahead and provide:
* output of `awesome -v` and `lua -v`
* expected behavior and actual behavior
* steps to reproduce the problem

View File

@@ -0,0 +1,339 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc., <http://fsf.org/>
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Lesser General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
{description}
Copyright (C) {year} {fullname}
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
{signature of Ty Coon}, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License.

View File

@@ -0,0 +1,39 @@
Lain
====
-------------------------------------------------
Layouts, widgets and utilities for Awesome WM 4.x
-------------------------------------------------
:Author: Luke Bonham <dada [at] archlinux [dot] info>
:Version: git
:License: GNU-GPL2_
:Source: https://github.com/copycat-killer/lain
Description
-----------
Successor of awesome-vain_, this module provides alternative layouts, asynchronous widgets and utility functions for Awesome_ WM. Read the wiki_ for all the info.
Contributions
-------------
Constructive criticism and suggestions are welcome.
If you want to create a pull request, make sure that:
- Your code fits with the general style of the module. In particular, you should use the same indentation pattern that the code uses, and also avoid adding space at the ends of lines.
- Your code its easy to understand, maintainable, and modularized. You should also avoid code duplication wherever possible by adding functions to or using lain.helpers_. If something is unclear, or you can't write it in such a way that it will be clear, explain it with a comment.
- You test your changes before submitting to make sure that you code works and does not break other parts of the module.
- You eventually update ``wiki`` submodule with a thorough section.
Contributed widgets have to be put in ``widget/contrib``.
.. _GNU-GPL2: http://www.gnu.org/licenses/gpl-2.0.html
.. _awesome-vain: https://github.com/vain/awesome-vain
.. _Awesome: https://github.com/awesomeWM/awesome
.. _wiki: https://github.com/copycat-killer/lain/wiki
.. _lain.helpers: https://github.com/copycat-killer/lain/blob/master/helpers.lua

View File

@@ -0,0 +1,167 @@
--[[
Licensed under GNU General Public License v2
* (c) 2013, Luke Bonham
--]]
local easy_async = require("awful.spawn").easy_async
local timer = require("gears.timer")
local debug = require("debug")
local io = { lines = io.lines,
open = io.open }
local rawget = rawget
local table = { sort = table.sort }
-- Lain helper functions for internal use
-- lain.helpers
local helpers = {}
helpers.lain_dir = debug.getinfo(1, 'S').source:match[[^@(.*/).*$]]
helpers.icons_dir = helpers.lain_dir .. 'icons/'
helpers.scripts_dir = helpers.lain_dir .. 'scripts/'
-- {{{ Modules loader
function helpers.wrequire(table, key)
local module = rawget(table, key)
return module or require(table._NAME .. '.' .. key)
end
-- }}}
-- {{{ File operations
-- see if the file exists and is readable
function helpers.file_exists(file)
local f = io.open(file)
if f then
local s = f:read()
f:close()
f = s
end
return f ~= nil
end
-- get all lines from a file, returns an empty
-- list/table if the file does not exist
function helpers.lines_from(file)
if not helpers.file_exists(file) then return {} end
local lines = {}
for line in io.lines(file) do
lines[#lines + 1] = line
end
return lines
end
-- match all lines from a file, returns an empty
-- list/table if the file or match does not exist
function helpers.lines_match(regexp, file)
local lines = {}
for index,line in pairs(helpers.lines_from(file)) do
if string.match(line, regexp) then
lines[index] = line
end
end
return lines
end
-- get first line of a file, return nil if
-- the file does not exist
function helpers.first_line(file)
return helpers.lines_from(file)[1]
end
-- get first non empty line from a file,
-- returns nil otherwise
function helpers.first_nonempty_line(file)
for k,v in pairs(helpers.lines_from(file)) do
if #v then return v end
end
return nil
end
-- }}}
-- {{{ Timer maker
helpers.timer_table = {}
function helpers.newtimer(name, timeout, fun, nostart, stoppable)
if not name or #name == 0 then return end
name = (stoppable and name) or timeout
if not helpers.timer_table[name] then
helpers.timer_table[name] = timer({ timeout = timeout })
helpers.timer_table[name]:start()
end
helpers.timer_table[name]:connect_signal("timeout", fun)
if not nostart then
helpers.timer_table[name]:emit_signal("timeout")
end
return stoppable and helpers.timer_table[name]
end
-- }}}
-- {{{ Pipe operations
-- run a command and execute a function on its output (asynchronous pipe)
-- @param cmd the input command
-- @param callback function to execute on cmd output
-- @return cmd PID
function helpers.async(cmd, callback)
return easy_async(cmd,
function (stdout, stderr, reason, exit_code)
callback(stdout)
end)
end
-- }}}
-- {{{ A map utility
helpers.map_table = {}
function helpers.set_map(element, value)
helpers.map_table[element] = value
end
function helpers.get_map(element)
return helpers.map_table[element]
end
-- }}}
-- {{{ Misc
-- check if an element exist on a table
function helpers.element_in_table(element, tbl)
for _, i in pairs(tbl) do
if i == element then
return true
end
end
return false
end
-- iterate over table of records sorted by keys
function helpers.spairs(t)
-- collect the keys
local keys = {}
for k in pairs(t) do keys[#keys+1] = k end
table.sort(keys)
-- return the iterator function
local i = 0
return function()
i = i + 1
if keys[i] then
return keys[i], t[keys[i]]
end
end
end
-- }}}
return helpers

Binary file not shown.

After

Width:  |  Height:  |  Size: 714 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1000 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 233 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 230 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 230 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 233 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 169 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 169 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 204 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 199 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 200 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 195 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 191 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 191 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 225 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 227 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 361 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 185 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 204 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 237 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 526 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

View File

@@ -0,0 +1,3 @@
[Plain Weather Icons](http://merlinthered.deviantart.com/art/plain-weather-icons-157162192), created by [MerlinTheRed](http://merlinthered.deviantart.com/).
<a href="http://creativecommons.org/licenses/by-nc-sa/2.5/"><img src="http://i.creativecommons.org/l/by-nc-sa/2.5/80x15.png" align="right"></a>

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 636 B

View File

@@ -0,0 +1,15 @@
--[[
Lain
Layouts, widgets and utilities for Awesome WM
Licensed under GNU General Public License v2
* (c) 2013, Luke Bonham
--]]
return {
layout = require("lain.layout"),
util = require("lain.util"),
widget = require("lain.widget")
}

View File

@@ -0,0 +1,26 @@
package = "lain"
version = "git"
source = {
url = "https://github.com/copycat-killer/lain",
tag = "git"
}
description = {
summary = "Layout, widgets and utilities for Awesome WM",
detailed = [[
Successor of awesome-vain, this module provides alternative layouts, asynchronous widgets and utility functions for Awesome WM.
Optional dependency: curl (for IMAP, MPD and weather widgets).
]],
homepage = "https://github.com/copycat-killer/lain",
license = "GPL v2"
}
dependencies = {
"lua >= 5.1",
"awesome >= 4.0",
"curl"
}
supported_platforms = { "linux" }
build = {
type = "builtin",
modules = { lain = "init.lua" }
}

View File

@@ -0,0 +1,172 @@
--[[
Licensed under GNU General Public License v2
* (c) 2014, projektile
* (c) 2013, Luke Bonham
* (c) 2010-2012, Peter Hofmann
--]]
local floor = math.floor
local screen = screen
local cascade = {
name = "cascade",
nmaster = 0,
offset_x = 32,
offset_y = 8,
tile = {
name = "cascadetile",
nmaster = 0,
ncol = 0,
mwfact = 0,
offset_x = 5,
offset_y = 32,
extra_padding = 0
}
}
local function do_cascade(p, tiling)
local t = p.tag or screen[p.screen].selected_tag
local wa = p.workarea
local cls = p.clients
if #cls == 0 then return end
if not tiling then
-- Cascade windows.
local num_c
if cascade.nmaster > 0 then
num_c = cascade.nmaster
else
num_c = t.master_count
end
-- Opening a new window will usually force all existing windows to
-- get resized. This wastes a lot of CPU time. So let's set a lower
-- bound to "how_many": This wastes a little screen space but you'll
-- get a much better user experience.
local how_many = (#cls >= num_c and #cls) or num_c
local current_offset_x = cascade.offset_x * (how_many - 1)
local current_offset_y = cascade.offset_y * (how_many - 1)
-- Iterate.
for i = 1,#cls,1 do
local c = cls[i]
local g = {}
g.x = wa.x + (how_many - i) * cascade.offset_x
g.y = wa.y + (i - 1) * cascade.offset_y
g.width = wa.width - current_offset_x
g.height = wa.height - current_offset_y
if g.width < 1 then g.width = 1 end
if g.height < 1 then g.height = 1 end
p.geometries[c] = g
end
else
-- Layout with one fixed column meant for a master window. Its
-- width is calculated according to mwfact. Other clients are
-- cascaded or "tabbed" in a slave column on the right.
-- (1) (2) (3) (4)
-- +----------+---+ +----------+---+ +----------+---+ +----------+---+
-- | | | | | 3 | | | 4 | | +---+|
-- | | | -> | | | -> | +---++ -> | +---+|+
-- | 1 | 2 | | 1 +---++ | 1 | 3 || | 1 +---+|+|
-- | | | | | 2 || | +---++| | +---+|+ |
-- | | | | | || | | 2 | | | | 2 |+ |
-- +----------+---+ +---------+---++ +--------+---+-+ +------+---+---+
local mwfact
if cascade.tile.mwfact > 0 then
mwfact = cascade.tile.mwfact
else
mwfact = t.master_width_factor
end
-- Make slave windows overlap main window? Do this if ncol is 1.
local overlap_main
if cascade.tile.ncol > 0 then
overlap_main = cascade.tile.ncol
else
overlap_main = t.column_count
end
-- Minimum space for slave windows? See cascade.tile.lua.
local num_c
if cascade.tile.nmaster > 0 then
num_c = cascade.tile.nmaster
else
num_c = t.master_count
end
local how_many = (#cls - 1 >= num_c and (#cls - 1)) or num_c
local current_offset_x = cascade.tile.offset_x * (how_many - 1)
local current_offset_y = cascade.tile.offset_y * (how_many - 1)
if #cls <= 0 then return end
-- Main column, fixed width and height.
local c = cls[1]
local g = {}
-- Rounding is necessary to prevent the rendered size of slavewid
-- from being 1 pixel off when the result is not an integer.
local mainwid = floor(wa.width * mwfact)
local slavewid = wa.width - mainwid
if overlap_main == 1 then
g.width = wa.width
-- The size of the main window may be reduced a little bit.
-- This allows you to see if there are any windows below the
-- main window.
-- This only makes sense, though, if the main window is
-- overlapping everything else.
g.width = g.width - cascade.tile.extra_padding
else
g.width = mainwid
end
g.height = wa.height
g.x = wa.x
g.y = wa.y
if g.width < 1 then g.width = 1 end
if g.height < 1 then g.height = 1 end
p.geometries[c] = g
-- Remaining clients stacked in slave column, new ones on top.
if #cls <= 1 then return end
for i = 2,#cls do
c = cls[i]
g = {}
g.width = slavewid - current_offset_x
g.height = wa.height - current_offset_y
g.x = wa.x + mainwid + (how_many - (i - 1)) * cascade.tile.offset_x
g.y = wa.y + (i - 2) * cascade.tile.offset_y
if g.width < 1 then g.width = 1 end
if g.height < 1 then g.height = 1 end
p.geometries[c] = g
end
end
end
function cascade.tile.arrange(p)
return do_cascade(p, true)
end
function cascade.arrange(p)
return do_cascade(p, false)
end
return cascade

View File

@@ -0,0 +1,153 @@
--[[
Licensed under GNU General Public License v2
* (c) 2016, Henrik Antonsson
* (c) 2015, Joerg Jaspert
* (c) 2014, projektile
* (c) 2013, Luke Bonham
* (c) 2010-2012, Peter Hofmann
--]]
local floor = math.floor
local screen = screen
local centerwork = {
name = "centerwork",
horizontal = { name = "centerworkh" }
}
local function do_centerwork(p, orientation)
local t = p.tag or screen[p.screen].selected_tag
local wa = p.workarea
local cls = p.clients
if #cls == 0 then return end
local c = cls[1]
local g = {}
-- Main column, fixed width and height.
local mwfact = t.master_width_factor
local mainhei = floor(wa.height * mwfact)
local mainwid = floor(wa.width * mwfact)
local slavewid = wa.width - mainwid
local slaveLwid = floor(slavewid / 2)
local slaveRwid = slavewid - slaveLwid
local slavehei = wa.height - mainhei
local slaveThei = floor(slavehei / 2)
local slaveBhei = slavehei - slaveThei
local nbrFirstSlaves = floor(#cls / 2)
local nbrSecondSlaves = floor((#cls - 1) / 2)
local slaveFirstDim, slaveSecondDim = 0, 0
if orientation == "vertical" then
if nbrFirstSlaves > 0 then slaveFirstDim = floor(wa.height / nbrFirstSlaves) end
if nbrSecondSlaves > 0 then slaveSecondDim = floor(wa.height / nbrSecondSlaves) end
g.height = wa.height
g.width = mainwid
g.x = wa.x + slaveLwid
g.y = wa.y
else
if nbrFirstSlaves > 0 then slaveFirstDim = floor(wa.width / nbrFirstSlaves) end
if nbrSecondSlaves > 0 then slaveSecondDim = floor(wa.width / nbrSecondSlaves) end
g.height = mainhei
g.width = wa.width
g.x = wa.x
g.y = wa.y + slaveThei
end
if g.width < 1 then g.width = 1 end
if g.height < 1 then g.height = 1 end
p.geometries[c] = g
-- Auxiliary windows.
if #cls <= 1 then return end
for i = 2,#cls do
local c = cls[i]
local g = {}
local rowIndex = floor(i/2)
if orientation == "vertical" then
if i % 2 == 0 then
-- left slave
g.x = wa.x
g.y = wa.y + (rowIndex-1)*slaveFirstDim
g.width = slaveLwid
-- if last slave in left row use remaining space for that slave
if rowIndex == nbrFirstSlaves then
g.height = wa.y + wa.height - g.y
else
g.height = slaveFirstDim
end
else
-- right slave
g.x = wa.x + slaveLwid + mainwid
g.y = wa.y + (rowIndex-1)*slaveSecondDim
g.width = slaveRwid
-- if last slave in right row use remaining space for that slave
if rowIndex == nbrSecondSlaves then
g.height = wa.y + wa.height - g.y
else
g.height = slaveSecondDim
end
end
else
if i % 2 == 0 then
-- top slave
g.x = wa.x + (rowIndex-1)*slaveFirstDim
g.y = wa.y
g.height = slaveThei
-- if last slave in top row use remaining space for that slave
if rowIndex == nbrFirstSlaves then
g.width = wa.x + wa.width - g.x
else
g.width = slaveFirstDim
end
else
-- bottom slave
g.x = wa.x + (rowIndex-1)*slaveSecondDim
g.y = wa.y + slaveThei + mainhei
g.height = slaveBhei
-- if last slave in bottom row use remaining space for that slave
if rowIndex == nbrSecondSlaves then
g.width = wa.x + wa.width - g.x
else
g.width = slaveSecondDim
end
end
end
if g.width < 1 then g.width = 1 end
if g.height < 1 then g.height = 1 end
p.geometries[c] = g
end
end
function centerwork.horizontal.arrange(p)
return do_centerwork(p, "horizontal")
end
function centerwork.arrange(p)
return do_centerwork(p, "vertical")
end
return centerwork

View File

@@ -0,0 +1,19 @@
--[[
Lain
Layouts, widgets and utilities for Awesome WM
Layouts section
Licensed under GNU General Public License v2
* (c) 2013, Luke Bonham
* (c) 2010-2012, Peter Hofmann
--]]
local wrequire = require("lain.helpers").wrequire
local setmetatable = setmetatable
local layout = { _NAME = "lain.layout" }
return setmetatable(layout, { __index = wrequire })

View File

@@ -0,0 +1,239 @@
--[[
Licensed under GNU General Public License v2
* (c) 2014, projektile
* (c) 2013, Luke Bonham
* (c) 2010, Nicolas Estibals
* (c) 2010-2012, Peter Hofmann
--]]
local math = { ceil = math.ceil,
floor = math.floor,
max = math.max }
local screen = screen
local tonumber = tonumber
local termfair = { name = "termfair" }
termfair.center = { name = "centerfair" }
local function do_fair(p, orientation)
local t = p.tag or screen[p.screen].selected_tag
local wa = p.workarea
local cls = p.clients
if #cls == 0 then return end
if orientation == "west" then
-- Layout with fixed number of vertical columns (read from nmaster).
-- New windows align from left to right. When a row is full, a now
-- one above it is created. Like this:
-- (1) (2) (3)
-- +---+---+---+ +---+---+---+ +---+---+---+
-- | | | | | | | | | | | |
-- | 1 | | | -> | 2 | 1 | | -> | 3 | 2 | 1 | ->
-- | | | | | | | | | | | |
-- +---+---+---+ +---+---+---+ +---+---+---+
-- (4) (5) (6)
-- +---+---+---+ +---+---+---+ +---+---+---+
-- | 4 | | | | 5 | 4 | | | 6 | 5 | 4 |
-- +---+---+---+ -> +---+---+---+ -> +---+---+---+
-- | 3 | 2 | 1 | | 3 | 2 | 1 | | 3 | 2 | 1 |
-- +---+---+---+ +---+---+---+ +---+---+---+
-- How many vertical columns? Read from nmaster on the tag.
local num_x = tonumber(termfair.nmaster) or t.master_count
local ncol = tonumber(termfair.ncol) or t.column_count
if num_x <= 2 then num_x = 2 end
if ncol <= 1 then ncol = 1 end
local width = math.floor(wa.width/num_x)
local num_y = math.max(math.ceil(#cls / num_x), ncol)
local height = math.floor(wa.height/num_y)
local cur_num_x = num_x
local at_x = 0
local at_y = 0
local remaining_clients = #cls
-- We start the first row. Left-align by limiting the number of
-- available slots.
if remaining_clients < num_x then
cur_num_x = remaining_clients
end
-- Iterate in reversed order.
for i = #cls,1,-1 do
-- Get x and y position.
local c = cls[i]
local this_x = cur_num_x - at_x - 1
local this_y = num_y - at_y - 1
-- Calculate geometry.
local g = {}
if this_x == (num_x - 1) then
g.width = wa.width - (num_x - 1)*width
else
g.width = width
end
if this_y == (num_y - 1) then
g.height = wa.height - (num_y - 1)*height
else
g.height = height
end
g.x = wa.x + this_x*width
g.y = wa.y + this_y*height
if g.width < 1 then g.width = 1 end
if g.height < 1 then g.height = 1 end
p.geometries[c] = g
remaining_clients = remaining_clients - 1
-- Next grid position.
at_x = at_x + 1
if at_x == num_x then
-- Row full, create a new one above it.
at_x = 0
at_y = at_y + 1
-- We start a new row. Left-align.
if remaining_clients < num_x then
cur_num_x = remaining_clients
end
end
end
elseif orientation == "center" then
-- Layout with fixed number of vertical columns (read from nmaster).
-- Cols are centerded until there is nmaster columns, then windows
-- are stacked in the slave columns, with at most ncol clients per
-- column if possible.
-- with nmaster=3 and ncol=1 you'll have
-- (1) (2) (3)
-- +---+---+---+ +-+---+---+-+ +---+---+---+
-- | | | | | | | | | | | | |
-- | | 1 | | -> | | 1 | 2 | | -> | 1 | 2 | 3 | ->
-- | | | | | | | | | | | | |
-- +---+---+---+ +-+---+---+-+ +---+---+---+
-- (4) (5)
-- +---+---+---+ +---+---+---+
-- | | | 3 | | | 2 | 4 |
-- + 1 + 2 +---+ -> + 1 +---+---+
-- | | | 4 | | | 3 | 5 |
-- +---+---+---+ +---+---+---+
-- How many vertical columns? Read from nmaster on the tag.
local num_x = tonumber(termfair.center.nmaster) or t.master_count
local ncol = tonumber(termfair.center.ncol) or t.column_count
if num_x <= 2 then num_x = 2 end
if ncol <= 1 then ncol = 1 end
local width = math.floor(wa.width / num_x)
if #cls < num_x then
-- Less clients than the number of columns, let's center it!
local offset_x = wa.x + (wa.width - #cls*width) / 2
for i = 1, #cls do
local g = { y = wa.y }
g.width = width
g.height = wa.height
if g.width < 1 then g.width = 1 end
if g.height < 1 then g.height = 1 end
g.x = offset_x + (i - 1) * width
p.geometries[cls[i]] = g
end
else
-- More clients than the number of columns, let's arrange it!
-- Master client deserves a special treatement
local g = {}
g.width = wa.width - (num_x - 1)*width
g.height = wa.height
if g.width < 1 then g.width = 1 end
if g.height < 1 then g.height = 1 end
g.x = wa.x
g.y = wa.y
p.geometries[cls[1]] = g
-- Treat the other clients
-- Compute distribution of clients among columns
local num_y = {}
local remaining_clients = #cls-1
local ncol_min = math.ceil(remaining_clients/(num_x-1))
if ncol >= ncol_min then
for i = (num_x-1), 1, -1 do
if (remaining_clients-i+1) < ncol then
num_y[i] = remaining_clients-i + 1
else
num_y[i] = ncol
end
remaining_clients = remaining_clients - num_y[i]
end
else
local rem = remaining_clients % (num_x-1)
if rem == 0 then
for i = 1, num_x-1 do
num_y[i] = ncol_min
end
else
for i = 1, num_x-1 do
num_y[i] = ncol_min - 1
end
for i = 0, rem-1 do
num_y[num_x-1-i] = num_y[num_x-1-i] + 1
end
end
end
-- Compute geometry of the other clients
local nclient = 2 -- we start with the 2nd client
local wx = g.x + g.width
for i = 1, (num_x-1) do
local height = math.floor(wa.height / num_y[i])
local wy = wa.y
for j = 0, (num_y[i]-2) do
local g = {}
g.x = wx
g.y = wy
g.height = height
g.width = width
if g.width < 1 then g.width = 1 end
if g.height < 1 then g.height = 1 end
p.geometries[cls[nclient]] = g
nclient = nclient + 1
wy = wy + height
end
local g = {}
g.x = wx
g.y = wy
g.height = wa.height - (num_y[i] - 1)*height
g.width = width
if g.width < 1 then g.width = 1 end
if g.height < 1 then g.height = 1 end
p.geometries[cls[nclient]] = g
nclient = nclient + 1
wx = wx + width
end
end
end
end
function termfair.center.arrange(p)
return do_fair(p, "center")
end
function termfair.arrange(p)
return do_fair(p, "west")
end
return termfair

397
.config/awesome/lain/scripts/dfs Executable file
View File

@@ -0,0 +1,397 @@
#!/usr/bin/env bash
#
# Adapted from Eridan's "fs" (cleanup, enhancements and switch to bash/Linux)
# JM, 10/12/2004
#
# Integrated into Lain in september 2013
# https://github.com/copycat-killer/lain
# Requires gawk
# -------------------------------------------------------------------------
# Decoding options
# -------------------------------------------------------------------------
USAGE="Usage: $0 [-h(elp)] | [-n(arrow mode)] | [-w(eb output) | --type=<fstype> | --exclude-type=<fstype>]"
NARROW_MODE=0
WEB_OUTPUT=0
DF_OPTIONS=""
while [ $# -gt 0 ]; do
case "$1" in
"-h" )
echo $USAGE
exit
;;
"-d" )
DEBUG=1
;;
"-n" )
NARROW_MODE=1
;;
"-w" )
WEB_OUTPUT=1
;;
--type=*)
DF_OPTIONS+=" $1"
;;
--exclude-type=*)
DF_OPTIONS+=" $1"
;;
* )
echo $USAGE
exit
;;
esac
shift
done
# -------------------------------------------------------------------------
# Preparations
# -------------------------------------------------------------------------
SYSTEM=`uname -s`
PATTERN="/"
case "$SYSTEM" in
"Linux" )
DF_COMMAND="/usr/bin/env df -k"
SORT_COMMAND="/usr/bin/env sort -k6"
AWK_COMMAND="/usr/bin/env awk"
;;
* )
DF_COMMAND="/bin/df -k"
SORT_COMMAND="/usr/bin/sort -k6"
AWK_COMMAND="/usr/bin/env gawk"
;;
esac
# Add additional df options
DF_COMMAND+=$DF_OPTIONS
# -------------------------------------------------------------------------
# Grabbing "df" result
# -------------------------------------------------------------------------
DF_RESULT=`$DF_COMMAND`
if [ ! -z $DEBUG ]; then
echo "--> DF_RESULT:"
echo "$DF_RESULT"
echo ""
fi
# -------------------------------------------------------------------------
# Preprocessing "df" result, to join split logical lines
# -------------------------------------------------------------------------
PREPROCESSING_RESULT=` \
echo "$DF_RESULT" | $AWK_COMMAND -v PATTERN=$PATTERN \
'
NF == 1 {
printf ("%s", $0)
}
NF == 5 {
printf ("%s\n", $0)
}
NF > 6 {
}
NF == 6 {
printf ("%s\n", $0)
}'
`
if [ ! -z $DEBUG ]; then
echo "--> PREPROCESSING_RESULT:"
echo "$PREPROCESSING_RESULT"
echo ""
fi
SORTED_FILE_SYSTEMS_INFO=`echo "$PREPROCESSING_RESULT" | $SORT_COMMAND`
if [ ! -z $DEBUG ]; then
echo "--> SORTED_FILE_SYSTEMS_INFO:"
echo "$SORTED_FILE_SYSTEMS_INFO"
echo ""
fi
# -------------------------------------------------------------------------
# Computing mount point max length
# -------------------------------------------------------------------------
MOUNT_POINT_MAX_LENGTH=` \
echo "$SORTED_FILE_SYSTEMS_INFO" | $AWK_COMMAND -v PATTERN=$PATTERN \
'
BEGIN {
mount_point_length_max = 15;
}
END {
printf ("%d", mount_point_length_max);
}
$0 ~ PATTERN {
# printf ("$6 = %s\n", $6);
mount_point = $6;
# printf ("mount_point = %s\n", mount_point);
mount_point_length = length (mount_point);
# printf ("mount_point_length = %d\n", mount_point_length);
if (mount_point_length > mount_point_length_max)
mount_point_length_max = mount_point_length;
}'
`
if [ ! -z $DEBUG ]; then
echo "MOUNT_POINT_MAX_LENGTH: $MOUNT_POINT_MAX_LENGTH"
fi
# -------------------------------------------------------------------------
# Computing mount point data max size
# -------------------------------------------------------------------------
MOUNT_POINT_MAX_SIZE=` \
echo "$SORTED_FILE_SYSTEMS_INFO" | $AWK_COMMAND -v PATTERN=$PATTERN \
'
BEGIN {
mount_point_size_max = 0;
}
END {
printf ("%d", mount_point_size_max);
}
$0 ~ PATTERN {
# df -k shows k_bytes!
# printf ("$2 = %s\n", $2);
mount_point_size = $2 * 1024;
# printf ("mount_point_size = %d\n", mount_point_size);
if (mount_point_size > mount_point_size_max)
mount_point_size_max = mount_point_size;
}'
`
if [ ! -z $DEBUG ]; then
echo "MOUNT_POINT_MAX_SIZE: $MOUNT_POINT_MAX_SIZE"
fi
# -------------------------------------------------------------------------
# Let's go!
# -------------------------------------------------------------------------
echo "$SORTED_FILE_SYSTEMS_INFO" | $AWK_COMMAND -v DEBUG=$DEBUG -v PATTERN=$PATTERN -v NARROW_MODE=$NARROW_MODE -v LEFT_COLUMN=$MOUNT_POINT_MAX_LENGTH -v MAX_SIZE=$MOUNT_POINT_MAX_SIZE -v SCALE=$SCALE -v WEB_OUTPUT=$WEB_OUTPUT \
'
# {printf ("$0 = %s\n", $0);}
# {printf ("$1 = %s\n", $1);}
# {printf ("PATTERN = %s\n", PATTERN);}
# {printf ("LEFT_COLUMN = %s\n", LEFT_COLUMN);}
BEGIN {
k_bytes = 1024.0;
m_bytes = 1024.0 * k_bytes;
g_bytes = 1024.0 * m_bytes;
t_bytes = 1024.0 * g_bytes;
if (WEB_OUTPUT)
{
all_stars = "**************************************************";
current_date = strftime ("%d-%m-%Y @ %H:%M:%S", localtime (systime ()));
free_threshold = 10; # %
printf ("<!-- DEBUT CONTENU -->\n");
printf ( \
"<A NAME=\"top\"></A>\n" \
"<P ALIGN=CENTER><SPAN CLASS=\"titleblue\">%s</SPAN><SPAN CLASS=\"textbold\"> -- STATUS OF <SPAN CLASS=\"titlered\">ALCOR</SPAN> FILE SYSTEMS</SPAN></P><BR>\n",
current_date )
printf ("<TABLE WIDTH=\"100%%\" BORDER=1>\n");
printf ( \
"<TR>\n" \
"<TD ALIGN=LEFT><STRONG>Mount point</STRONG></TD>\n" \
"<TD ALIGN=CENTER><STRONG>%% Usato&nbsp;(<SPAN CLASS=\"titleblue\">*</SPAN>)" \
"&nbsp;-&nbsp;%% Free&nbsp;(<SPAN CLASS=\"titlegreen\">*</SPAN>)</STRONG></TD>\n" \
"<TD ALIGN=CENTER><STRONG>%% Used</STRONG></TD>\n" \
"<TD ALIGN=CENTER><STRONG>Free</STRONG></TD>\n" \
"<TD ALIGN=CENTER><STRONG>Total</STRONG></TD>\n" \
"</TR>\n" );
}
else
{
narrow_margin = " ";
# printf ("%-*s", LEFT_COLUMN + 2, "Mount point");
if (NARROW_MODE)
printf ("\n%s", narrow_margin);
else
printf ("%-*s", LEFT_COLUMN + 2, "");
print " Used Free Total ";
if (! NARROW_MODE)
print " ";
}
}
END {
if (WEB_OUTPUT)
{
printf ("</TABLE>\n");
printf ("<!-- FIN CONTENU -->\n");
}
else
{
if (NARROW_MODE)
printf ("%s", narrow_margin);
else
printf ("%-*s", LEFT_COLUMN + 2, "");
print "|----|----|----|----|----|----|----|----|----|----|"
if (NARROW_MODE)
printf ("\n%s", narrow_margin);
else
printf ("%-*s", LEFT_COLUMN + 2, "");
print "0 10 20 30 40 50 60 70 80 90 100";
print "";
}
}
$0 ~ PATTERN {
if (index ($0, "members") == 0 && index ($0, "Download") == 0 && index ($0, "admin") == 0)
{
# df -k shows k_bytes!
total_size = $2 * k_bytes;
free_size = $4 * k_bytes;
percentage_occupied = substr($5, 0, 3);
mount_point = $6;
percentage_free = int (100 - percentage_occupied);
# reduction_factor: 2
stars_number = int (percentage_occupied / 2);
if (WEB_OUTPUT)
{
posGroup = index (mount_point, "scratch");
if (posGroup == 0)
posGroup = index (mount_point, "u1");
if (posGroup == 0)
posGroup = index (mount_point, "u2");
if (posGroup == 0)
posGroup = index (mount_point, "u4");
if (posGroup == 0)
posGroup = index (mount_point, "u5");
printf ("<TR>\n");
if (posGroup > 0 || percentage_free < free_threshold)
{
if (percentage_free < free_threshold)
{
class = "titlered";
if (posGroup == 0)
posGroup = 1; # to display the whole mount_point in this color anyway
}
else if ((index (mount_point, "scratch") != 0) || (index (mount_point, "u1") != 0) || (index (mount_point, "u2") != 0))
{
class = "titleorange";
posGroup = 1; # to display the whole mount_point in this color
}
else if ((index (mount_point, "u4") != 0) || (index (mount_point, "u5") != 0))
{
class = "titlebrown";
posGroup = 1; # to display the whole mount_point in this color
}
printf ( \
"<TD ALIGN=LEFT>%s<SPAN CLASS=\"%s\">%s</SPAN></TD>\n",
substr (mount_point, 1, posGroup - 1),
class,
substr (mount_point, posGroup) );
}
else
{
printf ("<TD ALIGN=LEFT>%s</TD>\n", mount_point);
}
printf ( \
"<TD ALIGN=CENTER><SPAN CLASS=\"titleblue\">%s</SPAN><SPAN CLASS=\"titlegreen\">%s</SPAN></TD>\n",
substr (all_stars, 1, stars_number), substr (all_stars, stars_number + 1, 49) );
if (percentage_free < free_threshold)
{
color_beginning = "<SPAN CLASS=\"titlered\">";
color_end = "</SPAN>"
}
else
{
color_beginning = "";
color_end = ""
}
if (total_size > 1 * t_bytes)
printf ( \
"<TD ALIGN=RIGHT>%s%3d%%%s</TD><TD ALIGN=RIGHT>%5.1f Tb</TD><TD ALIGN=RIGHT>%5.1f Tb</TD>\n", \
color_beginning, percentage_occupied, color_end, free_size / t_bytes, total_size / t_bytes \
);
else if (total_size > 1 * g_bytes)
printf ( \
"<TD ALIGN=RIGHT>%s%3d%%%s</TD><TD ALIGN=RIGHT>%5.1f Gb</TD><TD ALIGN=RIGHT>%5.1f Gb</TD>\n", \
color_beginning, percentage_occupied, color_end, free_size / g_bytes, total_size / g_bytes \
);
else if (total_size > 1 * m_byptes)
printf ( \
"<TD ALIGN=RIGHT>%s%3d%%%s</TD><TD ALIGN=RIGHT>%5.1f Mb</TD><TD ALIGN=RIGHT>%5.1f Mb</TD>\n", \
color_beginning, percentage_occupied, color_end, free_size / m_bytes, total_size / m_bytes \
);
else
printf ( \
"<TD ALIGN=RIGHT>%s%3d%%%s</TD><TD ALIGN=RIGHT>%5.1f Kb</TD><TD ALIGN=RIGHT>%5.1f Kb</TD>\n", \
color_beginning, percentage_occupied, color_end, free_size / k_bytes, total_size / k_bytes \
);
printf ("</TR>\n");
}
else
{
# printf ("percentage_occupied = %d\n", percentage_occupied);
# printf ("percentage_free = %d\n", percentage_free);
printf ("%-*s", LEFT_COLUMN + 2, mount_point);
if (NARROW_MODE)
printf ("\n%s", narrow_margin);
# printf ("stars_number = %d\n", stars_number);
printf ("|");
for (i = 1; i <= stars_number && i <= 49; i++)
{
printf ("%s", "*");
}
for (i = stars_number + 1; i <= 49; i++)
{
printf ("%s", "-");
}
if (total_size > 1 * t_bytes)
printf ( \
"| %3d%% %6.1f %6.1f Tb\n", \
percentage_occupied, free_size / t_bytes, total_size / t_bytes \
);
else if (total_size > 1 * g_bytes)
printf ( \
"| %3d%% %6.1f %6.1f Gb\n", \
percentage_occupied, free_size / g_bytes, total_size / g_bytes \
);
else if (total_size > 1 * m_byptes)
printf ( \
"| %3d%% %6.1f %6.1f Mb\n", \
percentage_occupied, free_size / m_bytes, total_size / m_bytes \
);
else
printf ( \
"| %3d%% %6.1f %6.1f Kb\n", \
percentage_occupied, free_size / k_bytes, total_size / k_bytes \
);
}
} # if
}'

View File

@@ -0,0 +1,713 @@
-- Module options:
local always_try_using_lpeg = true
local register_global_module_table = false
local global_module_name = 'json'
--[==[
David Kolf's JSON module for Lua 5.1/5.2
Version 2.5
For the documentation see the corresponding readme.txt or visit
<http://dkolf.de/src/dkjson-lua.fsl/>.
You can contact the author by sending an e-mail to 'david' at the
domain 'dkolf.de'.
Copyright (C) 2010-2013 David Heiko Kolf
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.
--]==]
-- global dependencies:
local pairs, type, tostring, tonumber, getmetatable, setmetatable, rawset =
pairs, type, tostring, tonumber, getmetatable, setmetatable, rawset
local error, require, pcall, select = error, require, pcall, select
local floor, huge = math.floor, math.huge
local strrep, gsub, strsub, strbyte, strchar, strfind, strlen, strformat =
string.rep, string.gsub, string.sub, string.byte, string.char,
string.find, string.len, string.format
local strmatch = string.match
local concat = table.concat
local json = { version = "dkjson 2.5" }
if register_global_module_table then
_G[global_module_name] = json
end
local _ENV = nil -- blocking globals in Lua 5.2
pcall (function()
-- Enable access to blocked metatables.
-- Don't worry, this module doesn't change anything in them.
local debmeta = require "debug".getmetatable
if debmeta then getmetatable = debmeta end
end)
json.null = setmetatable ({}, {
__tojson = function () return "null" end
})
local function isarray (tbl)
local max, n, arraylen = 0, 0, 0
for k,v in pairs (tbl) do
if k == 'n' and type(v) == 'number' then
arraylen = v
if v > max then
max = v
end
else
if type(k) ~= 'number' or k < 1 or floor(k) ~= k then
return false
end
if k > max then
max = k
end
n = n + 1
end
end
if max > 10 and max > arraylen and max > n * 2 then
return false -- don't create an array with too many holes
end
return true, max
end
local escapecodes = {
["\""] = "\\\"", ["\\"] = "\\\\", ["\b"] = "\\b", ["\f"] = "\\f",
["\n"] = "\\n", ["\r"] = "\\r", ["\t"] = "\\t"
}
local function escapeutf8 (uchar)
local value = escapecodes[uchar]
if value then
return value
end
local a, b, c, d = strbyte (uchar, 1, 4)
a, b, c, d = a or 0, b or 0, c or 0, d or 0
if a <= 0x7f then
value = a
elseif 0xc0 <= a and a <= 0xdf and b >= 0x80 then
value = (a - 0xc0) * 0x40 + b - 0x80
elseif 0xe0 <= a and a <= 0xef and b >= 0x80 and c >= 0x80 then
value = ((a - 0xe0) * 0x40 + b - 0x80) * 0x40 + c - 0x80
elseif 0xf0 <= a and a <= 0xf7 and b >= 0x80 and c >= 0x80 and d >= 0x80 then
value = (((a - 0xf0) * 0x40 + b - 0x80) * 0x40 + c - 0x80) * 0x40 + d - 0x80
else
return ""
end
if value <= 0xffff then
return strformat ("\\u%.4x", value)
elseif value <= 0x10ffff then
-- encode as UTF-16 surrogate pair
value = value - 0x10000
local highsur, lowsur = 0xD800 + floor (value/0x400), 0xDC00 + (value % 0x400)
return strformat ("\\u%.4x\\u%.4x", highsur, lowsur)
else
return ""
end
end
local function fsub (str, pattern, repl)
-- gsub always builds a new string in a buffer, even when no match
-- exists. First using find should be more efficient when most strings
-- don't contain the pattern.
if strfind (str, pattern) then
return gsub (str, pattern, repl)
else
return str
end
end
local function quotestring (value)
-- based on the regexp "escapable" in https://github.com/douglascrockford/JSON-js
value = fsub (value, "[%z\1-\31\"\\\127]", escapeutf8)
if strfind (value, "[\194\216\220\225\226\239]") then
value = fsub (value, "\194[\128-\159\173]", escapeutf8)
value = fsub (value, "\216[\128-\132]", escapeutf8)
value = fsub (value, "\220\143", escapeutf8)
value = fsub (value, "\225\158[\180\181]", escapeutf8)
value = fsub (value, "\226\128[\140-\143\168-\175]", escapeutf8)
value = fsub (value, "\226\129[\160-\175]", escapeutf8)
value = fsub (value, "\239\187\191", escapeutf8)
value = fsub (value, "\239\191[\176-\191]", escapeutf8)
end
return "\"" .. value .. "\""
end
json.quotestring = quotestring
local function replace(str, o, n)
local i, j = strfind (str, o, 1, true)
if i then
return strsub(str, 1, i-1) .. n .. strsub(str, j+1, -1)
else
return str
end
end
-- locale independent num2str and str2num functions
local decpoint, numfilter
local function updatedecpoint ()
decpoint = strmatch(tostring(0.5), "([^05+])")
-- build a filter that can be used to remove group separators
numfilter = "[^0-9%-%+eE" .. gsub(decpoint, "[%^%$%(%)%%%.%[%]%*%+%-%?]", "%%%0") .. "]+"
end
updatedecpoint()
local function num2str (num)
return replace(fsub(tostring(num), numfilter, ""), decpoint, ".")
end
local function str2num (str)
local num = tonumber(replace(str, ".", decpoint))
if not num then
updatedecpoint()
num = tonumber(replace(str, ".", decpoint))
end
return num
end
local function addnewline2 (level, buffer, buflen)
buffer[buflen+1] = "\n"
buffer[buflen+2] = strrep (" ", level)
buflen = buflen + 2
return buflen
end
function json.addnewline (state)
if state.indent then
state.bufferlen = addnewline2 (state.level or 0,
state.buffer, state.bufferlen or #(state.buffer))
end
end
local encode2 -- forward declaration
local function addpair (key, value, prev, indent, level, buffer, buflen, tables, globalorder, state)
local kt = type (key)
if kt ~= 'string' and kt ~= 'number' then
return nil, "type '" .. kt .. "' is not supported as a key by JSON."
end
if prev then
buflen = buflen + 1
buffer[buflen] = ","
end
if indent then
buflen = addnewline2 (level, buffer, buflen)
end
buffer[buflen+1] = quotestring (key)
buffer[buflen+2] = ":"
return encode2 (value, indent, level, buffer, buflen + 2, tables, globalorder, state)
end
local function appendcustom(res, buffer, state)
local buflen = state.bufferlen
if type (res) == 'string' then
buflen = buflen + 1
buffer[buflen] = res
end
return buflen
end
local function exception(reason, value, state, buffer, buflen, defaultmessage)
defaultmessage = defaultmessage or reason
local handler = state.exception
if not handler then
return nil, defaultmessage
else
state.bufferlen = buflen
local ret, msg = handler (reason, value, state, defaultmessage)
if not ret then return nil, msg or defaultmessage end
return appendcustom(ret, buffer, state)
end
end
function json.encodeexception(reason, value, state, defaultmessage)
return quotestring("<" .. defaultmessage .. ">")
end
encode2 = function (value, indent, level, buffer, buflen, tables, globalorder, state)
local valtype = type (value)
local valmeta = getmetatable (value)
valmeta = type (valmeta) == 'table' and valmeta -- only tables
local valtojson = valmeta and valmeta.__tojson
if valtojson then
if tables[value] then
return exception('reference cycle', value, state, buffer, buflen)
end
tables[value] = true
state.bufferlen = buflen
local ret, msg = valtojson (value, state)
if not ret then return exception('custom encoder failed', value, state, buffer, buflen, msg) end
tables[value] = nil
buflen = appendcustom(ret, buffer, state)
elseif value == nil then
buflen = buflen + 1
buffer[buflen] = "null"
elseif valtype == 'number' then
local s
if value ~= value or value >= huge or -value >= huge then
-- This is the behaviour of the original JSON implementation.
s = "null"
else
s = num2str (value)
end
buflen = buflen + 1
buffer[buflen] = s
elseif valtype == 'boolean' then
buflen = buflen + 1
buffer[buflen] = value and "true" or "false"
elseif valtype == 'string' then
buflen = buflen + 1
buffer[buflen] = quotestring (value)
elseif valtype == 'table' then
if tables[value] then
return exception('reference cycle', value, state, buffer, buflen)
end
tables[value] = true
level = level + 1
local isa, n = isarray (value)
if n == 0 and valmeta and valmeta.__jsontype == 'object' then
isa = false
end
local msg
if isa then -- JSON array
buflen = buflen + 1
buffer[buflen] = "["
for i = 1, n do
buflen, msg = encode2 (value[i], indent, level, buffer, buflen, tables, globalorder, state)
if not buflen then return nil, msg end
if i < n then
buflen = buflen + 1
buffer[buflen] = ","
end
end
buflen = buflen + 1
buffer[buflen] = "]"
else -- JSON object
local prev = false
buflen = buflen + 1
buffer[buflen] = "{"
local order = valmeta and valmeta.__jsonorder or globalorder
if order then
local used = {}
n = #order
for i = 1, n do
local k = order[i]
local v = value[k]
if v then
used[k] = true
buflen, msg = addpair (k, v, prev, indent, level, buffer, buflen, tables, globalorder, state)
prev = true -- add a seperator before the next element
end
end
for k,v in pairs (value) do
if not used[k] then
buflen, msg = addpair (k, v, prev, indent, level, buffer, buflen, tables, globalorder, state)
if not buflen then return nil, msg end
prev = true -- add a seperator before the next element
end
end
else -- unordered
for k,v in pairs (value) do
buflen, msg = addpair (k, v, prev, indent, level, buffer, buflen, tables, globalorder, state)
if not buflen then return nil, msg end
prev = true -- add a seperator before the next element
end
end
if indent then
buflen = addnewline2 (level - 1, buffer, buflen)
end
buflen = buflen + 1
buffer[buflen] = "}"
end
tables[value] = nil
else
return exception ('unsupported type', value, state, buffer, buflen,
"type '" .. valtype .. "' is not supported by JSON.")
end
return buflen
end
function json.encode (value, state)
state = state or {}
local oldbuffer = state.buffer
local buffer = oldbuffer or {}
state.buffer = buffer
updatedecpoint()
local ret, msg = encode2 (value, state.indent, state.level or 0,
buffer, state.bufferlen or 0, state.tables or {}, state.keyorder, state)
if not ret then
error (msg, 2)
elseif oldbuffer == buffer then
state.bufferlen = ret
return true
else
state.bufferlen = nil
state.buffer = nil
return concat (buffer)
end
end
local function loc (str, where)
local line, pos, linepos = 1, 1, 0
while true do
pos = strfind (str, "\n", pos, true)
if pos and pos < where then
line = line + 1
linepos = pos
pos = pos + 1
else
break
end
end
return "line " .. line .. ", column " .. (where - linepos)
end
local function unterminated (str, what, where)
return nil, strlen (str) + 1, "unterminated " .. what .. " at " .. loc (str, where)
end
local function scanwhite (str, pos)
while true do
pos = strfind (str, "%S", pos)
if not pos then return nil end
local sub2 = strsub (str, pos, pos + 1)
if sub2 == "\239\187" and strsub (str, pos + 2, pos + 2) == "\191" then
-- UTF-8 Byte Order Mark
pos = pos + 3
elseif sub2 == "//" then
pos = strfind (str, "[\n\r]", pos + 2)
if not pos then return nil end
elseif sub2 == "/*" then
pos = strfind (str, "*/", pos + 2)
if not pos then return nil end
pos = pos + 2
else
return pos
end
end
end
local escapechars = {
["\""] = "\"", ["\\"] = "\\", ["/"] = "/", ["b"] = "\b", ["f"] = "\f",
["n"] = "\n", ["r"] = "\r", ["t"] = "\t"
}
local function unichar (value)
if value < 0 then
return nil
elseif value <= 0x007f then
return strchar (value)
elseif value <= 0x07ff then
return strchar (0xc0 + floor(value/0x40),
0x80 + (floor(value) % 0x40))
elseif value <= 0xffff then
return strchar (0xe0 + floor(value/0x1000),
0x80 + (floor(value/0x40) % 0x40),
0x80 + (floor(value) % 0x40))
elseif value <= 0x10ffff then
return strchar (0xf0 + floor(value/0x40000),
0x80 + (floor(value/0x1000) % 0x40),
0x80 + (floor(value/0x40) % 0x40),
0x80 + (floor(value) % 0x40))
else
return nil
end
end
local function scanstring (str, pos)
local lastpos = pos + 1
local buffer, n = {}, 0
while true do
local nextpos = strfind (str, "[\"\\]", lastpos)
if not nextpos then
return unterminated (str, "string", pos)
end
if nextpos > lastpos then
n = n + 1
buffer[n] = strsub (str, lastpos, nextpos - 1)
end
if strsub (str, nextpos, nextpos) == "\"" then
lastpos = nextpos + 1
break
else
local escchar = strsub (str, nextpos + 1, nextpos + 1)
local value
if escchar == "u" then
value = tonumber (strsub (str, nextpos + 2, nextpos + 5), 16)
if value then
local value2
if 0xD800 <= value and value <= 0xDBff then
-- we have the high surrogate of UTF-16. Check if there is a
-- low surrogate escaped nearby to combine them.
if strsub (str, nextpos + 6, nextpos + 7) == "\\u" then
value2 = tonumber (strsub (str, nextpos + 8, nextpos + 11), 16)
if value2 and 0xDC00 <= value2 and value2 <= 0xDFFF then
value = (value - 0xD800) * 0x400 + (value2 - 0xDC00) + 0x10000
else
value2 = nil -- in case it was out of range for a low surrogate
end
end
end
value = value and unichar (value)
if value then
if value2 then
lastpos = nextpos + 12
else
lastpos = nextpos + 6
end
end
end
end
if not value then
value = escapechars[escchar] or escchar
lastpos = nextpos + 2
end
n = n + 1
buffer[n] = value
end
end
if n == 1 then
return buffer[1], lastpos
elseif n > 1 then
return concat (buffer), lastpos
else
return "", lastpos
end
end
local scanvalue -- forward declaration
local function scantable (what, closechar, str, startpos, nullval, objectmeta, arraymeta)
local len = strlen (str)
local tbl, n = {}, 0
local pos = startpos + 1
if what == 'object' then
setmetatable (tbl, objectmeta)
else
setmetatable (tbl, arraymeta)
end
while true do
pos = scanwhite (str, pos)
if not pos then return unterminated (str, what, startpos) end
local char = strsub (str, pos, pos)
if char == closechar then
return tbl, pos + 1
end
local val1, err
val1, pos, err = scanvalue (str, pos, nullval, objectmeta, arraymeta)
if err then return nil, pos, err end
pos = scanwhite (str, pos)
if not pos then return unterminated (str, what, startpos) end
char = strsub (str, pos, pos)
if char == ":" then
if val1 == nil then
return nil, pos, "cannot use nil as table index (at " .. loc (str, pos) .. ")"
end
pos = scanwhite (str, pos + 1)
if not pos then return unterminated (str, what, startpos) end
local val2
val2, pos, err = scanvalue (str, pos, nullval, objectmeta, arraymeta)
if err then return nil, pos, err end
tbl[val1] = val2
pos = scanwhite (str, pos)
if not pos then return unterminated (str, what, startpos) end
char = strsub (str, pos, pos)
else
n = n + 1
tbl[n] = val1
end
if char == "," then
pos = pos + 1
end
end
end
scanvalue = function (str, pos, nullval, objectmeta, arraymeta)
pos = pos or 1
pos = scanwhite (str, pos)
if not pos then
return nil, strlen (str) + 1, "no valid JSON value (reached the end)"
end
local char = strsub (str, pos, pos)
if char == "{" then
return scantable ('object', "}", str, pos, nullval, objectmeta, arraymeta)
elseif char == "[" then
return scantable ('array', "]", str, pos, nullval, objectmeta, arraymeta)
elseif char == "\"" then
return scanstring (str, pos)
else
local pstart, pend = strfind (str, "^%-?[%d%.]+[eE]?[%+%-]?%d*", pos)
if pstart then
local number = str2num (strsub (str, pstart, pend))
if number then
return number, pend + 1
end
end
pstart, pend = strfind (str, "^%a%w*", pos)
if pstart then
local name = strsub (str, pstart, pend)
if name == "true" then
return true, pend + 1
elseif name == "false" then
return false, pend + 1
elseif name == "null" then
return nullval, pend + 1
end
end
return nil, pos, "no valid JSON value at " .. loc (str, pos)
end
end
local function optionalmetatables(...)
if select("#", ...) > 0 then
return ...
else
return {__jsontype = 'object'}, {__jsontype = 'array'}
end
end
function json.decode (str, pos, nullval, ...)
local objectmeta, arraymeta = optionalmetatables(...)
return scanvalue (str, pos, nullval, objectmeta, arraymeta)
end
function json.use_lpeg ()
local g = require ("lpeg")
if g.version() == "0.11" then
error "due to a bug in LPeg 0.11, it cannot be used for JSON matching"
end
local pegmatch = g.match
local P, S, R = g.P, g.S, g.R
local function ErrorCall (str, pos, msg, state)
if not state.msg then
state.msg = msg .. " at " .. loc (str, pos)
state.pos = pos
end
return false
end
local function Err (msg)
return g.Cmt (g.Cc (msg) * g.Carg (2), ErrorCall)
end
local SingleLineComment = P"//" * (1 - S"\n\r")^0
local MultiLineComment = P"/*" * (1 - P"*/")^0 * P"*/"
local Space = (S" \n\r\t" + P"\239\187\191" + SingleLineComment + MultiLineComment)^0
local PlainChar = 1 - S"\"\\\n\r"
local EscapeSequence = (P"\\" * g.C (S"\"\\/bfnrt" + Err "unsupported escape sequence")) / escapechars
local HexDigit = R("09", "af", "AF")
local function UTF16Surrogate (match, pos, high, low)
high, low = tonumber (high, 16), tonumber (low, 16)
if 0xD800 <= high and high <= 0xDBff and 0xDC00 <= low and low <= 0xDFFF then
return true, unichar ((high - 0xD800) * 0x400 + (low - 0xDC00) + 0x10000)
else
return false
end
end
local function UTF16BMP (hex)
return unichar (tonumber (hex, 16))
end
local U16Sequence = (P"\\u" * g.C (HexDigit * HexDigit * HexDigit * HexDigit))
local UnicodeEscape = g.Cmt (U16Sequence * U16Sequence, UTF16Surrogate) + U16Sequence/UTF16BMP
local Char = UnicodeEscape + EscapeSequence + PlainChar
local String = P"\"" * g.Cs (Char ^ 0) * (P"\"" + Err "unterminated string")
local Integer = P"-"^(-1) * (P"0" + (R"19" * R"09"^0))
local Fractal = P"." * R"09"^0
local Exponent = (S"eE") * (S"+-")^(-1) * R"09"^1
local Number = (Integer * Fractal^(-1) * Exponent^(-1))/str2num
local Constant = P"true" * g.Cc (true) + P"false" * g.Cc (false) + P"null" * g.Carg (1)
local SimpleValue = Number + String + Constant
local ArrayContent, ObjectContent
-- The functions parsearray and parseobject parse only a single value/pair
-- at a time and store them directly to avoid hitting the LPeg limits.
local function parsearray (str, pos, nullval, state)
local obj, cont
local npos
local t, nt = {}, 0
repeat
obj, cont, npos = pegmatch (ArrayContent, str, pos, nullval, state)
if not npos then break end
pos = npos
nt = nt + 1
t[nt] = obj
until cont == 'last'
return pos, setmetatable (t, state.arraymeta)
end
local function parseobject (str, pos, nullval, state)
local obj, key, cont
local npos
local t = {}
repeat
key, obj, cont, npos = pegmatch (ObjectContent, str, pos, nullval, state)
if not npos then break end
pos = npos
t[key] = obj
until cont == 'last'
return pos, setmetatable (t, state.objectmeta)
end
local Array = P"[" * g.Cmt (g.Carg(1) * g.Carg(2), parsearray) * Space * (P"]" + Err "']' expected")
local Object = P"{" * g.Cmt (g.Carg(1) * g.Carg(2), parseobject) * Space * (P"}" + Err "'}' expected")
local Value = Space * (Array + Object + SimpleValue)
local ExpectedValue = Value + Space * Err "value expected"
ArrayContent = Value * Space * (P"," * g.Cc'cont' + g.Cc'last') * g.Cp()
local Pair = g.Cg (Space * String * Space * (P":" + Err "colon expected") * ExpectedValue)
ObjectContent = Pair * Space * (P"," * g.Cc'cont' + g.Cc'last') * g.Cp()
local DecodeValue = ExpectedValue * g.Cp ()
function json.decode (str, pos, nullval, ...)
local state = {}
state.objectmeta, state.arraymeta = optionalmetatables(...)
local obj, retpos = pegmatch (DecodeValue, str, pos, nullval, state)
if state.msg then
return nil, state.pos, state.msg
else
return obj, retpos
end
end
-- use this function only once:
json.use_lpeg = function () return json end
json.using_lpeg = true
return json -- so you can get the module using json = require "dkjson".use_lpeg()
end
if always_try_using_lpeg then
pcall (json.use_lpeg)
end
return json

View File

@@ -0,0 +1,167 @@
--[[
Lain
Layouts, widgets and utilities for Awesome WM
Utilities section
Licensed under GNU General Public License v2
* (c) 2013, Luke Bonham
* (c) 2010-2012, Peter Hofmann
--]]
local awful = require("awful")
local sqrt = math.sqrt
local pairs = pairs
local client = client
local tonumber = tonumber
local wrequire = require("lain.helpers").wrequire
local setmetatable = setmetatable
-- Lain utilities submodule
-- lain.util
local util = { _NAME = "lain.util" }
-- Like awful.menu.clients, but only show clients of currently selected tags
function util.menu_clients_current_tags(menu, args)
-- List of currently selected tags.
local cls_tags = awful.screen.focused().selected_tags
if cls_tags == nil then return nil end
-- Final list of menu items.
local cls_t = {}
-- For each selected tag get all clients of that tag and add them to
-- the menu. A click on a menu item will raise that client.
for i = 1,#cls_tags do
local t = cls_tags[i]
local cls = t:clients()
for k, c in pairs(cls) do
cls_t[#cls_t + 1] = { awful.util.escape(c.name) or "",
function ()
c.minimized = false
client.focus = c
c:raise()
end,
c.icon }
end
end
-- No clients? Then quit.
if #cls_t <= 0 then return nil end
-- menu may contain some predefined values, otherwise start with a
-- fresh menu.
if not menu then menu = {} end
-- Set the list of items and show the menu.
menu.items = cls_t
local m = awful.menu(menu)
m:show(args)
return m
end
-- Magnify a client: set it to "float" and resize it.
function util.magnify_client(c, width_f, height_f)
if c and not c.floating then
util.magnified_client = c
util.mc(c, width_f, height_f)
else
util.magnified_client = nil
c.floating = false
end
end
-- https://github.com/copycat-killer/lain/issues/195
function util.mc(c, width_f, height_f)
c = c or util.magnified_client
if not c then return end
c.floating = true
local s = awful.screen.focused()
local mg = s.workarea
local g = {}
local mwfact = width_f or s.selected_tag.master_width_factor or 0.5
g.width = sqrt(mwfact) * mg.width
g.height = sqrt(height_f or mwfact) * mg.height
g.x = mg.x + (mg.width - g.width) / 2
g.y = mg.y + (mg.height - g.height) / 2
if c then c:geometry(g) end -- if c is still a valid object
end
-- Non-empty tag browsing
-- direction in {-1, 1} <-> {previous, next} non-empty tag
function util.tag_view_nonempty(direction, sc)
local s = sc or awful.screen.focused()
for i = 1, #s.tags do
awful.tag.viewidx(direction, s)
if #s.clients > 0 then
return
end
end
end
-- {{{ Dynamic tagging
-- Add a new tag
function util.add_tag(layout)
awful.prompt.run {
prompt = "New tag name: ",
textbox = awful.screen.focused().mypromptbox.widget,
exe_callback = function(name)
if not name or #name == 0 then return end
awful.tag.add(name, { screen = awful.screen.focused(), layout = layout or awful.layout.suit.tile }):view_only()
end
}
end
-- Rename current tag
function util.rename_tag()
awful.prompt.run {
prompt = "Rename tag: ",
textbox = awful.screen.focused().mypromptbox.widget,
exe_callback = function(new_name)
if not new_name or #new_name == 0 then return end
local t = awful.screen.focused().selected_tag
if t then
t.name = new_name
end
end
}
end
-- Move current tag
-- pos in {-1, 1} <-> {previous, next} tag position
function util.move_tag(pos)
local tag = awful.screen.focused().selected_tag
if tonumber(pos) <= -1 then
awful.tag.move(tag.index - 1, tag)
else
awful.tag.move(tag.index + 1, tag)
end
end
-- Delete current tag
-- Any rule set on the tag shall be broken
function util.delete_tag()
local t = awful.screen.focused().selected_tag
if not t then return end
t:delete()
end
-- }}}
-- On the fly useless gaps change
function util.useless_gaps_resize(thatmuch)
local scr = awful.screen.focused()
scr.selected_tag.gap = scr.selected_tag.gap + tonumber(thatmuch)
awful.layout.arrange(scr)
end
return setmetatable(util, { __index = wrequire })

View File

@@ -0,0 +1,66 @@
--[[
Licensed under MIT License
* (c) 2013, Luke Bonham
* (c) 2009, Uli Schlachter
* (c) 2009, Majic
--]]
local string = { format = string.format }
local setmetatable = setmetatable
-- Lain markup util submodule
-- lain.util.markup
local markup = { fg = {}, bg = {} }
-- Convenience tags.
function markup.bold(text) return '<b>' .. text .. '</b>' end
function markup.italic(text) return '<i>' .. text .. '</i>' end
function markup.strike(text) return '<s>' .. text .. '</s>' end
function markup.underline(text) return '<u>' .. text .. '</u>' end
function markup.monospace(text) return '<tt>' .. text .. '</tt>' end
function markup.big(text) return '<big>' .. text .. '</big>' end
function markup.small(text) return '<small>' .. text .. '</small>' end
-- Set the font.
function markup.font(font, text)
return '<span font="' .. font .. '">' .. text ..'</span>'
end
-- Set the foreground.
function markup.fg.color(color, text)
return '<span foreground="' .. color .. '">' .. text .. '</span>'
end
-- Set the background.
function markup.bg.color(color, text)
return '<span background="' .. color .. '">' .. text .. '</span>'
end
-- Set foreground and background.
function markup.color(fg, bg, text)
return string.format('<span foreground="%s" background="%s">%s</span>', fg, bg, text)
end
-- Set font and foreground.
function markup.fontfg(font, fg, text)
return string.format('<span font="%s" foreground="%s">%s</span>', font, fg, text)
end
-- Set font and background.
function markup.fontbg(font, bg, text)
return string.format('<span font="%s" background="%s">%s</span>', font, bg, text)
end
-- Set font, foreground and background.
function markup.fontcolor(font, fg, bg, text)
return string.format('<span font="%s" foreground="%s" background="%s">%s</span>', font, fg, bg, text)
end
-- link markup.{fg,bg}(...) calls to markup.{fg,bg}.color(...)
setmetatable(markup.fg, { __call = function(_, ...) return markup.fg.color(...) end })
setmetatable(markup.bg, { __call = function(_, ...) return markup.bg.color(...) end })
-- link markup(...) calls to markup.fg.color(...)
return setmetatable(markup, { __call = function(_, ...) return markup.fg.color(...) end })

View File

@@ -0,0 +1,168 @@
--[[
Licensed under GNU General Public License v2
* (c) 2016, Luke Bonham
* (c) 2015, unknown
--]]
local awful = require("awful")
local capi = { client = client }
local math = { floor = math.floor }
local string = { format = string.format }
local pairs = pairs
local screen = screen
local setmetatable = setmetatable
-- Quake-like Dropdown application spawn
local quake = {}
-- If you have a rule like "awful.client.setslave" for your terminals,
-- ensure you use an exception for QuakeDD. Otherwise, you may
-- run into problems with focus.
function quake:display()
if self.followtag then self.screen = awful.screen.focused() end
-- First, we locate the client
local client = nil
local i = 0
for c in awful.client.iterate(function (c)
-- c.name may be changed!
return c.instance == self.name
end)
do
i = i + 1
if i == 1 then
client = c
else
-- Additional matching clients, let's remove the sticky bit
-- which may persist between awesome restarts. We don't close
-- them as they may be valuable. They will just turn into
-- normal clients.
c.sticky = false
c.ontop = false
c.above = false
end
end
if not client and not self.visible then return end
if not client then
-- The client does not exist, we spawn it
cmd = string.format("%s %s %s", self.app,
string.format(self.argname, self.name), self.extra)
awful.spawn(cmd, { tag = self.screen.selected_tag })
return
end
-- Set geometry
client.floating = true
client.border_width = self.border
client.size_hints_honor = false
client:geometry(self.geometry[self.screen] or self:compute_size())
-- Set not sticky and on top
client.sticky = false
client.ontop = true
client.above = true
client.skip_taskbar = true
-- Additional user settings
if self.settings then self.settings(client) end
-- Toggle display
if self.visible then
client.hidden = false
client:raise()
self.last_tag = self.screen.selected_tag
client:tags({self.screen.selected_tag})
capi.client.focus = client
else
client.hidden = true
local ctags = client:tags()
for i, t in pairs(ctags) do
ctags[i] = nil
end
client:tags(ctags)
end
return client
end
function quake:compute_size()
-- skip if we already have a geometry for this screen
if not self.geometry[self.screen] then
local geom
if not self.overlap then
geom = screen[self.screen].workarea
else
geom = screen[self.screen].geometry
end
local width, height = self.width, self.height
if width <= 1 then width = math.floor(geom.width * width) - 2 * self.border end
if height <= 1 then height = math.floor(geom.height * height) end
local x, y
if self.horiz == "left" then x = geom.x
elseif self.horiz == "right" then x = geom.width + geom.x - width
else x = geom.x + (geom.width - width)/2 end
if self.vert == "top" then y = geom.y
elseif self.vert == "bottom" then y = geom.height + geom.y - height
else y = geom.y + (geom.height - height)/2 end
self.geometry[self.screen] = { x = x, y = y, width = width, height = height }
end
return self.geometry[self.screen]
end
function quake:new(config)
local conf = config or {}
conf.app = conf.app or "xterm" -- application to spawn
conf.name = conf.name or "QuakeDD" -- window name
conf.argname = conf.argname or "-name %s" -- how to specify window name
conf.extra = conf.extra or "" -- extra arguments
conf.border = conf.border or 1 -- client border width
conf.visible = conf.visible or false -- initially not visible
conf.followtag = conf.followtag or false -- spawn on currently focused screen
conf.overlap = conf.overlap or false -- overlap wibox
conf.screen = conf.screen or awful.screen.focused()
conf.settings = conf.settings
-- If width or height <= 1 this is a proportion of the workspace
conf.height = conf.height or 0.25 -- height
conf.width = conf.width or 1 -- width
conf.vert = conf.vert or "top" -- top, bottom or center
conf.horiz = conf.horiz or "left" -- left, right or center
conf.geometry = {} -- internal use
local dropdown = setmetatable(conf, { __index = quake })
capi.client.connect_signal("manage", function(c)
if c.instance == dropdown.name and c.screen == dropdown.screen then
dropdown:display()
end
end)
capi.client.connect_signal("unmanage", function(c)
if c.instance == dropdown.name and c.screen == dropdown.screen then
dropdown.visible = false
end
end)
return dropdown
end
function quake:toggle()
if self.followtag then self.screen = awful.screen.focused() end
local current_tag = self.screen.selected_tag
if current_tag and self.last_tag ~= current_tag and self.visible then
self:display():move_to_tag(current_tag)
else
self.visible = not self.visible
self:display()
end
end
return setmetatable(quake, { __call = function(_, ...) return quake:new(...) end })

View File

@@ -0,0 +1,101 @@
--[[
Licensed under GNU General Public License v2
* (c) 2015, Luke Bonham
* (c) 2015, plotnikovanton
--]]
local wibox = require("wibox")
local gears = require("gears")
-- Lain Cairo separators util submodule
-- lain.util.separators
local separators = { height = 0, width = 9 }
-- [[ Arrow
-- Right
function separators.arrow_right(col1, col2)
local widget = wibox.widget.base.make_widget()
widget.fit = function(m, w, h)
return separators.width, separators.height
end
widget.draw = function(mycross, wibox, cr, width, height)
if col2 ~= "alpha" then
cr:set_source_rgb(gears.color.parse_color(col2))
cr:new_path()
cr:move_to(0, 0)
cr:line_to(width, height/2)
cr:line_to(width, 0)
cr:close_path()
cr:fill()
cr:new_path()
cr:move_to(0, height)
cr:line_to(width, height/2)
cr:line_to(width, height)
cr:close_path()
cr:fill()
end
if col1 ~= "alpha" then
cr:set_source_rgb(gears.color.parse_color(col1))
cr:new_path()
cr:move_to(0, 0)
cr:line_to(width, height/2)
cr:line_to(0, height)
cr:close_path()
cr:fill()
end
end
return widget
end
-- Left
function separators.arrow_left(col1, col2)
local widget = wibox.widget.base.make_widget()
widget.fit = function(m, w, h)
return separators.width, separators.height
end
widget.draw = function(mycross, wibox, cr, width, height)
if col1 ~= "alpha" then
cr:set_source_rgb(gears.color.parse_color(col1))
cr:new_path()
cr:move_to(width, 0)
cr:line_to(0, height/2)
cr:line_to(0, 0)
cr:close_path()
cr:fill()
cr:new_path()
cr:move_to(width, height)
cr:line_to(0, height/2)
cr:line_to(0, height)
cr:close_path()
cr:fill()
end
if col2 ~= "alpha" then
cr:new_path()
cr:move_to(width, 0)
cr:line_to(0, height/2)
cr:line_to(width, height)
cr:close_path()
cr:set_source_rgb(gears.color.parse_color(col2))
cr:fill()
end
end
return widget
end
-- ]]
return separators

View File

@@ -0,0 +1,54 @@
--[[
Licensed under GNU General Public License v2
* (c) 2013, Luke Bonham
* (c) 2010, Adrian C. <anrxc@sysphere.org>
--]]
local helpers = require("lain.helpers")
local shell = require("awful.util").shell
local wibox = require("wibox")
local string = { match = string.match,
format = string.format }
-- ALSA volume
-- lain.widget.alsa
local function factory(args)
local alsa = { widget = wibox.widget.textbox() }
local args = args or {}
local timeout = args.timeout or 5
local settings = args.settings or function() end
alsa.cmd = args.cmd or "amixer"
alsa.channel = args.channel or "Master"
alsa.togglechannel = args.togglechannel
local format_cmd = string.format("%s get %s", alsa.cmd, alsa.channel)
if alsa.togglechannel then
format_cmd = { shell, "-c", string.format("%s get %s; %s get %s",
alsa.cmd, alsa.channel, alsa.cmd, alsa.togglechannel) }
end
alsa.last = {}
function alsa.update()
helpers.async(format_cmd, function(mixer)
local l,s = string.match(mixer, "([%d]+)%%.*%[([%l]*)")
if alsa.last.level ~= l or alsa.last.status ~= s then
volume_now = { level = l, status = s }
widget = alsa.widget
settings()
alsa.last = volume_now
end
end)
end
helpers.newtimer(string.format("alsa-%s-%s", alsa.cmd, alsa.channel), timeout, alsa.update)
return alsa
end
return factory

View File

@@ -0,0 +1,138 @@
--[[
Licensed under GNU General Public License v2
* (c) 2013, Luke Bonham
* (c) 2013, Rman
--]]
local helpers = require("lain.helpers")
local awful = require("awful")
local naughty = require("naughty")
local wibox = require("wibox")
local math = { modf = math.modf }
local string = { format = string.format,
match = string.match,
rep = string.rep }
local type, tonumber = type, tonumber
-- ALSA volume bar
-- lain.widget.alsabar
local function factory(args)
local alsabar = {
colors = {
background = "#000000",
mute = "#EB8F8F",
unmute = "#A4CE8A"
},
_current_level = 0,
_playback = "off"
}
local args = args or {}
local timeout = args.timeout or 5
local settings = args.settings or function() end
local width = args.width or 63
local height = args.height or 1
local ticks = args.ticks or false
local ticks_size = args.ticks_size or 7
alsabar.cmd = args.cmd or "amixer"
alsabar.channel = args.channel or "Master"
alsabar.togglechannel = args.togglechannel
alsabar.colors = args.colors or alsabar.colors
alsabar.followtag = args.followtag or false
alsabar.notification_preset = args.notification_preset
if not alsabar.notification_preset then
alsabar.notification_preset = {}
alsabar.notification_preset.font = "Monospace 10"
end
local format_cmd = string.format("%s get %s", alsabar.cmd, alsabar.channel)
if alsabar.togglechannel then
format_cmd = { awful.util.shell, "-c", string.format("%s get %s; %s get %s",
alsabar.cmd, alsabar.channel, alsabar.cmd, alsabar.togglechannel) }
end
alsabar.bar = wibox.widget {
forced_height = height,
forced_width = width,
color = alsabar.colors.unmute,
background_color = alsabar.colors.background,
margins = 1,
paddings = 1,
ticks = ticks,
ticks_size = ticks_size,
widget = wibox.widget.progressbar
}
alsabar.tooltip = awful.tooltip({ objects = { alsabar.bar } })
function alsabar.update(callback)
helpers.async(format_cmd, function(mixer)
local vol, playback = string.match(mixer, "([%d]+)%%.*%[([%l]*)")
if not vol or not playback then return end
if vol ~= alsabar._current_level or playback ~= alsabar._playback then
alsabar._current_level = tonumber(vol)
alsabar.bar:set_value(alsabar._current_level / 100)
if alsabar._current_level == 0 or playback == "off" then
alsabar._playback = playback
alsabar.tooltip:set_text("[Muted]")
alsabar.bar.color = alsabar.colors.mute
else
alsabar._playback = "on"
alsabar.tooltip:set_text(string.format("%s: %s", alsabar.channel, vol))
alsabar.bar.color = alsabar.colors.unmute
end
volume_now = {
level = alsabar._current_level,
status = alsabar._playback
}
settings()
if type(callback) == "function" then callback() end
end
end)
end
function alsabar.notify()
alsabar.update(function()
local preset = alsabar.notification_preset
preset.title = string.format("%s - %s%%", alsabar.channel, alsabar._current_level)
if alsabar._playback == "off" then
preset.title = preset.title .. " Muted"
end
int = math.modf((alsabar._current_level / 100) * awful.screen.focused().mywibox.height)
preset.text = string.format("[%s%s]", string.rep("|", int),
string.rep(" ", awful.screen.focused().mywibox.height - int))
if alsabar.followtag then preset.screen = awful.screen.focused() end
if not alsabar.notification then
alsabar.notification = naughty.notify {
preset = preset,
destroy = function() alsabar.notification = nil end
}
else
naughty.replace_text(alsabar.notification, preset.title, preset.text)
end
end)
end
helpers.newtimer(string.format("alsabar-%s-%s", alsabar.cmd, alsabar.channel), timeout, alsabar.update)
return alsabar
end
return factory

View File

@@ -0,0 +1,180 @@
--[[
Licensed under GNU General Public License v2
* (c) 2013, Luke Bonham
* (c) 2010-2012, Peter Hofmann
--]]
local first_line = require("lain.helpers").first_line
local newtimer = require("lain.helpers").newtimer
local naughty = require("naughty")
local wibox = require("wibox")
local math = { abs = math.abs,
floor = math.floor,
log10 = math.log10,
min = math.min }
local string = { format = string.format }
local ipairs = ipairs
local tonumber = tonumber
-- Battery infos
-- lain.widget.bat
local function factory(args)
local bat = { widget = wibox.widget.textbox() }
local args = args or {}
local timeout = args.timeout or 30
local batteries = args.batteries or (args.battery and {args.battery}) or {"BAT1"}
local ac = args.ac or "AC0"
local notify = args.notify or "on"
local n_perc = args.n_perc or { 5, 15 }
local settings = args.settings or function() end
bat_notification_critical_preset = {
title = "Battery exhausted",
text = "Shutdown imminent",
timeout = 15,
fg = "#000000",
bg = "#FFFFFF"
}
bat_notification_low_preset = {
title = "Battery low",
text = "Plug the cable!",
timeout = 15,
fg = "#202020",
bg = "#CDCDCD"
}
bat_now = {
status = "N/A",
ac_status = "N/A",
perc = "N/A",
time = "N/A",
watt = "N/A"
}
bat_now.n_status = {}
bat_now.n_perc = {}
for i = 1, #batteries do
bat_now.n_status[i] = "N/A"
bat_now.n_perc[i] = 0
end
function bat.update()
local sum_rate_current = 0
local sum_rate_voltage = 0
local sum_rate_power = 0
local sum_rate_energy = 0
local sum_energy_now = 0
local sum_energy_full = 0
local pspath = "/sys/class/power_supply/"
for i, battery in ipairs(batteries) do
local bstr = pspath .. battery
local present = first_line(bstr .. "/present")
if tonumber(present) == 1 then
-- current_now(I)[uA], voltage_now(U)[uV], power_now(P)[uW]
local rate_current = tonumber(first_line(bstr .. "/current_now"))
local rate_voltage = tonumber(first_line(bstr .. "/voltage_now"))
local rate_power = tonumber(first_line(bstr .. "/power_now"))
-- energy_now(P)[uWh], charge_now(I)[uAh]
local energy_now = tonumber(first_line(bstr .. "/energy_now") or
first_line(bstr .. "/charge_now"))
-- energy_full(P)[uWh], charge_full(I)[uAh]
local energy_full = tonumber(first_line(bstr .. "/energy_full") or
first_line(bstr .. "/charge_full"))
local energy_percentage = tonumber(first_line(bstr .. "/capacity")) or
math.floor((energy_now / energy_full) * 100)
bat_now.n_status[i] = first_line(bstr .. "/status") or "N/A"
bat_now.n_perc[i] = energy_percentage or bat_now.n_perc[i]
sum_rate_current = sum_rate_current + (rate_current or 0)
sum_rate_voltage = sum_rate_voltage + (rate_voltage or 0)
sum_rate_power = sum_rate_power + (rate_power or 0)
sum_rate_energy = sum_rate_energy + (rate_power or (((rate_voltage or 0) * (rate_current or 0)) / 1e6))
sum_energy_now = sum_energy_now + (energy_now or 0)
sum_energy_full = sum_energy_full + (energy_full or 0)
end
end
-- When one of the battery is charging, others' status are either
-- "Full", "Unknown" or "Charging". When the laptop is not plugged in,
-- one or more of the batteries may be full, but only one battery
-- discharging suffices to set global status to "Discharging".
bat_now.status = bat_now.n_status[1]
for _,status in ipairs(bat_now.n_status) do
if status == "Discharging" or status == "Charging" then
bat_now.status = status
end
end
bat_now.ac_status = tonumber(first_line(string.format("%s%s/online", pspath, ac))) or "N/A"
if bat_now.status ~= "N/A" then
if bat_now.status ~= "Full" and sum_rate_power == 0 and bat_now.ac_status == 1 then
bat_now.perc = math.floor(math.min(100, (sum_energy_now / sum_energy_full) * 100))
bat_now.time = "00:00"
bat_now.watt = 0
-- update {perc,time,watt} iff battery not full and rate > 0
elseif bat_now.status ~= "Full" then
local rate_time = 0
-- Calculate time and watt if rates are greater then 0
if (sum_rate_power > 0 or sum_rate_current > 0) then
local div = (sum_rate_power > 0 and sum_rate_power) or sum_rate_current
if bat_now.status == "Charging" then
rate_time = (sum_energy_full - sum_energy_now) / div
else -- Discharging
rate_time = sum_energy_now / div
end
if 0 < rate_time and rate_time < 0.01 then -- check for magnitude discrepancies (#199)
rate_time_magnitude = math.abs(math.floor(math.log10(rate_time)))
rate_time = rate_time * 10^(rate_time_magnitude - 2)
end
end
local hours = math.floor(rate_time)
local minutes = math.floor((rate_time - hours) * 60)
bat_now.perc = math.floor(math.min(100, (sum_energy_now / sum_energy_full) * 100))
bat_now.time = string.format("%02d:%02d", hours, minutes)
bat_now.watt = tonumber(string.format("%.2f", sum_rate_energy / 1e6))
elseif bat_now.status == "Full" then
bat_now.perc = 100
bat_now.time = "00:00"
bat_now.watt = 0
end
end
widget = bat.widget
settings()
-- notifications for critical and low levels
if notify == "on" and bat_now.status == "Discharging" then
if tonumber(bat_now.perc) <= n_perc[1] then
bat.id = naughty.notify({
preset = bat_notification_critical_preset,
replaces_id = bat.id
}).id
elseif tonumber(bat_now.perc) <= n_perc[2] then
bat.id = naughty.notify({
preset = bat_notification_low_preset,
replaces_id = bat.id
}).id
end
end
end
newtimer("batteries", timeout, bat.update)
return bat
end
return factory

View File

@@ -0,0 +1,127 @@
--[[
Licensed under GNU General Public License v2
* (c) 2013, Luke Bonham
--]]
local helpers = require("lain.helpers")
local markup = require("lain.util.markup")
local awful = require("awful")
local naughty = require("naughty")
local mouse = mouse
local os = { date = os.date }
local string = { format = string.format,
gsub = string.gsub }
local ipairs = ipairs
local tonumber = tonumber
local setmetatable = setmetatable
-- Calendar notification
-- lain.widget.calendar
local calendar = { offset = 0 }
function calendar.hide()
if not calendar.notification then return end
naughty.destroy(calendar.notification)
calendar.notification = nil
end
function calendar.show(t_out, inc_offset, scr)
local f, offs = nil, inc_offset or 0
calendar.notification_preset.screen = scr or (calendar.followtag and awful.screen.focused()) or 1
calendar.offset = calendar.offset + offs
local current_month = (offs == 0 or calendar.offset == 0)
if current_month then -- today highlighted
calendar.offset = 0
calendar.icon = calendar.icons:len() > 0 and string.format("%s%s.png", calendar.icons, tonumber(os.date("%d")))
f = calendar.cal
else -- no current month showing, no day to highlight
local month = tonumber(os.date("%m"))
local year = tonumber(os.date("%Y"))
month = month + calendar.offset
while month > 12 do
month = month - 12
year = year + 1
end
while month < 1 do
month = month + 12
year = year - 1
end
calendar.icon = nil
f = string.format("%s %s %s", calendar.cal, month, year)
end
helpers.async(f, function(ws)
local fg, bg = calendar.notification_preset.fg, calendar.notification_preset.bg
calendar.notification_preset.text = ws:gsub("%c%[%d+[m]?%s?%d+%c%[%d+[m]?",
markup.bold(markup.color(bg, fg, os.date("%e")))):gsub("\n*$", "")
local widget_focused = true
if t_out == 0 and mouse.current_widgets then
widget_focused = false
for i, widget in ipairs(calendar.attach_to) do
for _,v in ipairs(mouse.current_widgets) do
if widget == v then
widget_focused = true
break
end
end
end
end
if widget_focused then
calendar.hide()
calendar.notification = naughty.notify({
preset = calendar.notification_preset,
icon = calendar.icon,
timeout = t_out or calendar.notification_preset.timeout or 5
})
end
end)
end
function calendar.hover_on() calendar.show(0) end
function calendar.hover_off() calendar.hide() end
function calendar.prev() calendar.show(0, -1) end
function calendar.next() calendar.show(0, 1) end
function calendar.attach(widget)
widget:connect_signal("mouse::enter", calendar.hover_on)
widget:connect_signal("mouse::leave", calendar.hover_off)
widget:buttons(awful.util.table.join(
awful.button({}, 1, calendar.prev),
awful.button({}, 3, calendar.next),
awful.button({}, 2, calendar.hover_on),
awful.button({}, 4, calendar.prev),
awful.button({}, 5, calendar.next)))
end
local function factory(args)
local args = args or {}
calendar.cal = args.cal or "/usr/bin/cal"
calendar.attach_to = args.attach_to or {}
calendar.followtag = args.followtag or false
calendar.icons = args.icons or helpers.icons_dir .. "cal/white/"
calendar.notification_preset = args.notification_preset
if not calendar.notification_preset then
calendar.notification_preset = {
font = "Monospace 10",
fg = "#FFFFFF",
bg = "#000000"
}
end
for i, widget in ipairs(calendar.attach_to) do calendar.attach(widget) end
end
return setmetatable(calendar, { __call = function(_, ...) return factory(...) end })

View File

@@ -0,0 +1,18 @@
--[[
Lain
Layouts, widgets and utilities for Awesome WM
Users contributed widgets section
Licensed under GNU General Public License v2
* (c) 2013, Luke Bonham
--]]
local wrequire = require("lain.helpers").wrequire
local setmetatable = setmetatable
local widget = { _NAME = "lain.widget.contrib" }
return setmetatable(widget, { __index = wrequire })

View File

@@ -0,0 +1,77 @@
--[[
Licensed under GNU General Public License v2
* (c) 2015, Dario Gjorgjevski
--]]
local helpers = require("lain.helpers")
local awful = require("awful")
local wibox = require("wibox")
local string = { format = string.format,
match = string.match }
local execute = os.execute
local setmetatable = setmetatable
-- Keyboard layout switcher
-- lain.widget.contrib.kblayout
local function factory(args)
local kbdlayout = { widget = wibox.widget.textbox() }
local args = args or {}
local layouts = args.layouts or {}
local settings = args.settings or function () end
local add_us_secondary = true
local timeout = args.timeout or 5
local idx = 1
if args.add_us_secondary == false then add_us_secondary = false end
local function kbd_run_settings(layout, variant)
kbdlayout_now = {
layout = string.match(layout, "[^,]+"), -- Make sure to match the primary layout only.
variant = variant
}
widget = kbdlayout.widget
settings()
end
function kbdlayout.update()
helpers.async("setxkbmap -query", function(status)
kbd_run_settings(string.match(status, "layout:%s*([^\n]*)"),
string.match(status, "variant:%s*([^\n]*)"))
end)
end
function kbdlayout.set(i)
if #layouts == 0 then return end
idx = ((i - 1) % #layouts) + 1 -- Make sure to wrap around as needed.
local to_execute = "setxkbmap " .. layouts[idx].layout
if add_us_secondary and not string.match(layouts[idx].layout, ",?us,?") then
to_execute = to_execute .. ",us"
end
if layouts[idx].variant then
to_execute = to_execute .. " " .. layouts[idx].variant
end
if execute(to_execute) then
kbd_run_settings(layouts[idx].layout, layouts[idx].variant)
end
end
function kbdlayout.next() kbdlayout.set(idx + 1) end
function kbdlayout.prev() kbdlayout.set(idx - 1) end
-- Mouse bindings
kbdlayout.widget:buttons(awful.util.table.join(
awful.button({ }, 1, function () kbdlayout.next() end),
awful.button({ }, 3, function () kbdlayout.prev() end)))
helpers.newtimer("kbdlayout", timeout, kbdlayout.update)
return kbdlayout
end
return factory

Some files were not shown because too many files have changed in this diff Show More