inital commit of clone of old repo
This commit is contained in:
parent
5529249e29
commit
77e1a1340d
28
BEAST/README
Normal file
28
BEAST/README
Normal file
@ -0,0 +1,28 @@
|
||||
BEAST - Reincarnated on a Dell Inspiron Mini Netbook, up from a old PowerEdge 2500.
|
||||
|
||||
--- Has since been replaced with BEAST2
|
||||
|
||||
Also runs Docker, so it can run different distros on the backend.
|
||||
|
||||
Screenfetch:
|
||||
|
||||
.. root@BEAST
|
||||
.PLTJ. OS: CentOS
|
||||
<><><><> Kernel: x86_64 Linux 3.2.40-grsec-dotcloud
|
||||
KKSSV' 4KKK LJ KKKL.'VSSKK Uptime: 22d 12h 45m
|
||||
KKV' 4KKKKK LJ KKKKAL 'VKK Packages: 479
|
||||
V' ' 'VKKKK LJ KKKKV' ' 'V Shell: zsh 4.3.10
|
||||
.4MA.' 'VKK LJ KKV' '.4Mb. CPU: Intel Atom CPU N455 @ 1.667GHz
|
||||
. KKKKKA.' 'V LJ V' '.4KKKKK . RAM: 944MB / 1991MB
|
||||
.4D KKKKKKKA.'' LJ ''.4KKKKKKK FA.
|
||||
<QDD ++++++++++++ ++++++++++++ GFD>
|
||||
'VD KKKKKKKK'.. LJ ..'KKKKKKKK FV
|
||||
' VKKKKK'. .4 LJ K. .'KKKKKV '
|
||||
'VK'. .4KK LJ KKA. .'KV'
|
||||
A. . .4KKKK LJ KKKKA. . .4
|
||||
KKA. 'KKKKK LJ KKKKK' .4KK
|
||||
KKSSA. VKKK LJ KKKV .4SSKK
|
||||
<><><><>
|
||||
'MKKM'
|
||||
''
|
||||
|
1
BEAST/hwinfo
Normal file
1
BEAST/hwinfo
Normal file
@ -0,0 +1 @@
|
||||
2 * Intel(R) Atom(TM) CPU N455 @ 1.66GHz, 1.9 GB mem, 2.0 GB swap
|
324
BEAST/lshw
Normal file
324
BEAST/lshw
Normal file
@ -0,0 +1,324 @@
|
||||
beast
|
||||
description: Portable Computer
|
||||
product: Inspiron 1018
|
||||
vendor: Dell Inc.
|
||||
version: A00
|
||||
width: 64 bits
|
||||
capabilities: smbios-2.5 dmi-2.5 vsyscall32
|
||||
configuration: administrator_password=disabled boot=oem-specific chassis=portable frontpanel_password=unknown keyboard_password=unknown power-on_password=disabled
|
||||
*-core
|
||||
description: Motherboard
|
||||
physical id: 0
|
||||
*-firmware
|
||||
description: BIOS
|
||||
vendor: Dell Inc.
|
||||
physical id: 1
|
||||
version: A00
|
||||
date: 06/30/2010
|
||||
size: 103KiB
|
||||
capacity: 1984KiB
|
||||
capabilities: pci pnp upgrade shadowing escd cdboot bootselect edd int5printscreen int9keyboard int14serial int17printer int10video acpi usb smartbattery biosbootspecification netboot
|
||||
*-board UNCLAIMED
|
||||
description: Motherboard
|
||||
product: 0GHG2G
|
||||
vendor: Dell Inc.
|
||||
physical id: 3
|
||||
version: A00
|
||||
serial: . .CN129611530618.
|
||||
slot: Not Applicable
|
||||
*-cpu
|
||||
description: CPU
|
||||
product: Pentium 4
|
||||
vendor: Intel Corp.
|
||||
physical id: 5
|
||||
bus info: cpu@0
|
||||
version: C1
|
||||
slot: CPU 1
|
||||
size: 1667MHz
|
||||
capacity: 1667MHz
|
||||
width: 64 bits
|
||||
clock: 667MHz
|
||||
capabilities: x86-64 fpu fpu_exception wp vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx constant_tsc arch_perfmon pebs bts rep_good nopl aperfmperf pni dtes64 monitor ds_cpl est tm2 ssse3 cx16 xtpr pdcm movbe lahf_lm dtherm cpufreq
|
||||
configuration: cores=1 enabledcores=1 threads=2
|
||||
*-cache:0
|
||||
description: L1 cache
|
||||
physical id: 6
|
||||
slot: L1 Cache
|
||||
size: 16KiB
|
||||
capacity: 16KiB
|
||||
capabilities: asynchronous internal write-back
|
||||
*-cache:1
|
||||
description: L2 cache
|
||||
physical id: 7
|
||||
slot: L2 Cache
|
||||
size: 512KiB
|
||||
capacity: 512KiB
|
||||
capabilities: burst internal write-back
|
||||
*-memory
|
||||
description: System Memory
|
||||
physical id: 12
|
||||
slot: System board or motherboard
|
||||
size: 2GiB
|
||||
*-bank
|
||||
description: SODIMM Synchronous 667 MHz (1.5 ns)
|
||||
product: CM3X2GSD1066
|
||||
vendor: AMI
|
||||
physical id: 0
|
||||
serial: 00000000
|
||||
slot: J6G1
|
||||
size: 2GiB
|
||||
width: 64 bits
|
||||
clock: 667MHz (1.5ns)
|
||||
*-pci
|
||||
description: Host bridge
|
||||
product: Atom Processor D4xx/D5xx/N4xx/N5xx DMI Bridge
|
||||
vendor: Intel Corporation
|
||||
physical id: 100
|
||||
bus info: pci@0000:00:00.0
|
||||
version: 00
|
||||
width: 32 bits
|
||||
clock: 33MHz
|
||||
configuration: driver=agpgart-intel
|
||||
resources: irq:0
|
||||
*-display:0
|
||||
description: VGA compatible controller
|
||||
product: Atom Processor D4xx/D5xx/N4xx/N5xx Integrated Graphics Controller
|
||||
vendor: Intel Corporation
|
||||
physical id: 2
|
||||
bus info: pci@0000:00:02.0
|
||||
version: 00
|
||||
width: 32 bits
|
||||
clock: 33MHz
|
||||
capabilities: msi pm vga_controller bus_master cap_list rom
|
||||
configuration: driver=i915 latency=0
|
||||
resources: irq:43 memory:f0200000-f027ffff ioport:18d0(size=8) memory:d0000000-dfffffff memory:f0000000-f00fffff
|
||||
*-display:1 UNCLAIMED
|
||||
description: Display controller
|
||||
product: Atom Processor D4xx/D5xx/N4xx/N5xx Integrated Graphics Controller
|
||||
vendor: Intel Corporation
|
||||
physical id: 2.1
|
||||
bus info: pci@0000:00:02.1
|
||||
version: 00
|
||||
width: 32 bits
|
||||
clock: 33MHz
|
||||
capabilities: pm bus_master cap_list
|
||||
configuration: latency=0
|
||||
resources: memory:f0280000-f02fffff
|
||||
*-multimedia
|
||||
description: Audio device
|
||||
product: N10/ICH 7 Family High Definition Audio Controller
|
||||
vendor: Intel Corporation
|
||||
physical id: 1b
|
||||
bus info: pci@0000:00:1b.0
|
||||
version: 02
|
||||
width: 64 bits
|
||||
clock: 33MHz
|
||||
capabilities: pm msi pciexpress bus_master cap_list
|
||||
configuration: driver=snd_hda_intel latency=0
|
||||
resources: irq:44 memory:f0300000-f0303fff
|
||||
*-pci:0
|
||||
description: PCI bridge
|
||||
product: N10/ICH 7 Family PCI Express Port 1
|
||||
vendor: Intel Corporation
|
||||
physical id: 1c
|
||||
bus info: pci@0000:00:1c.0
|
||||
version: 02
|
||||
width: 32 bits
|
||||
clock: 33MHz
|
||||
capabilities: pci pciexpress msi pm normal_decode bus_master cap_list
|
||||
configuration: driver=pcieport
|
||||
resources: irq:40 ioport:2000(size=4096) memory:80200000-805fffff ioport:f0f00000(size=1048576)
|
||||
*-network
|
||||
description: Ethernet interface
|
||||
product: RTL8101E/RTL8102E PCI Express Fast Ethernet controller
|
||||
vendor: Realtek Semiconductor Co., Ltd.
|
||||
physical id: 0
|
||||
bus info: pci@0000:05:00.0
|
||||
logical name: p1p1
|
||||
version: 05
|
||||
serial: 5c:26:0a:52:af:26
|
||||
size: 100Mbit/s
|
||||
capacity: 100Mbit/s
|
||||
width: 64 bits
|
||||
clock: 33MHz
|
||||
capabilities: pm msi pciexpress msix vpd bus_master cap_list ethernet physical tp mii 10bt 10bt-fd 100bt 100bt-fd autonegotiation
|
||||
configuration: autonegotiation=on broadcast=yes driver=r8169 driverversion=2.3LK-NAPI duplex=full firmware=N/A ip=192.168.1.3 latency=0 link=yes multicast=yes port=MII speed=100Mbit/s
|
||||
resources: irq:45 ioport:2000(size=256) memory:f0f2c000-f0f2cfff memory:f0f18000-f0f1bfff
|
||||
*-pci:1
|
||||
description: PCI bridge
|
||||
product: N10/ICH 7 Family PCI Express Port 2
|
||||
vendor: Intel Corporation
|
||||
physical id: 1c.1
|
||||
bus info: pci@0000:00:1c.1
|
||||
version: 02
|
||||
width: 32 bits
|
||||
clock: 33MHz
|
||||
capabilities: pci pciexpress msi pm normal_decode bus_master cap_list
|
||||
configuration: driver=pcieport
|
||||
resources: irq:41 ioport:3000(size=4096) memory:f0100000-f01fffff ioport:80000000(size=2097152)
|
||||
*-network UNCLAIMED
|
||||
description: Network controller
|
||||
product: RTL8188CE 802.11b/g/n WiFi Adapter
|
||||
vendor: Realtek Semiconductor Co., Ltd.
|
||||
physical id: 0
|
||||
bus info: pci@0000:07:00.0
|
||||
version: 01
|
||||
width: 64 bits
|
||||
clock: 33MHz
|
||||
capabilities: pm msi pciexpress cap_list
|
||||
configuration: latency=0
|
||||
resources: ioport:3000(size=256) memory:f0100000-f0103fff
|
||||
*-usb:0
|
||||
description: USB controller
|
||||
product: N10/ICH 7 Family USB UHCI Controller #1
|
||||
vendor: Intel Corporation
|
||||
physical id: 1d
|
||||
bus info: pci@0000:00:1d.0
|
||||
version: 02
|
||||
width: 32 bits
|
||||
clock: 33MHz
|
||||
capabilities: uhci bus_master
|
||||
configuration: driver=uhci_hcd latency=0
|
||||
resources: irq:23 ioport:1820(size=32)
|
||||
*-usb:1
|
||||
description: USB controller
|
||||
product: N10/ICH 7 Family USB UHCI Controller #2
|
||||
vendor: Intel Corporation
|
||||
physical id: 1d.1
|
||||
bus info: pci@0000:00:1d.1
|
||||
version: 02
|
||||
width: 32 bits
|
||||
clock: 33MHz
|
||||
capabilities: uhci bus_master
|
||||
configuration: driver=uhci_hcd latency=0
|
||||
resources: irq:19 ioport:1840(size=32)
|
||||
*-usb:2
|
||||
description: USB controller
|
||||
product: N10/ICH 7 Family USB UHCI Controller #3
|
||||
vendor: Intel Corporation
|
||||
physical id: 1d.2
|
||||
bus info: pci@0000:00:1d.2
|
||||
version: 02
|
||||
width: 32 bits
|
||||
clock: 33MHz
|
||||
capabilities: uhci bus_master
|
||||
configuration: driver=uhci_hcd latency=0
|
||||
resources: irq:18 ioport:1860(size=32)
|
||||
*-usb:3
|
||||
description: USB controller
|
||||
product: N10/ICH 7 Family USB UHCI Controller #4
|
||||
vendor: Intel Corporation
|
||||
physical id: 1d.3
|
||||
bus info: pci@0000:00:1d.3
|
||||
version: 02
|
||||
width: 32 bits
|
||||
clock: 33MHz
|
||||
capabilities: uhci bus_master
|
||||
configuration: driver=uhci_hcd latency=0
|
||||
resources: irq:16 ioport:1880(size=32)
|
||||
*-usb:4
|
||||
description: USB controller
|
||||
product: N10/ICH 7 Family USB2 EHCI Controller
|
||||
vendor: Intel Corporation
|
||||
physical id: 1d.7
|
||||
bus info: pci@0000:00:1d.7
|
||||
version: 02
|
||||
width: 32 bits
|
||||
clock: 33MHz
|
||||
capabilities: pm debug ehci bus_master cap_list
|
||||
configuration: driver=ehci_hcd latency=0
|
||||
resources: irq:23 memory:f0504000-f05043ff
|
||||
*-pci:2
|
||||
description: PCI bridge
|
||||
product: 82801 Mobile PCI Bridge
|
||||
vendor: Intel Corporation
|
||||
physical id: 1e
|
||||
bus info: pci@0000:00:1e.0
|
||||
version: e2
|
||||
width: 32 bits
|
||||
clock: 33MHz
|
||||
capabilities: pci subtractive_decode bus_master cap_list
|
||||
*-isa
|
||||
description: ISA bridge
|
||||
product: NM10 Family LPC Controller
|
||||
vendor: Intel Corporation
|
||||
physical id: 1f
|
||||
bus info: pci@0000:00:1f.0
|
||||
version: 02
|
||||
width: 32 bits
|
||||
clock: 33MHz
|
||||
capabilities: isa bus_master cap_list
|
||||
configuration: latency=0
|
||||
*-storage
|
||||
description: SATA controller
|
||||
product: N10/ICH7 Family SATA Controller [AHCI mode]
|
||||
vendor: Intel Corporation
|
||||
physical id: 1f.2
|
||||
bus info: pci@0000:00:1f.2
|
||||
logical name: scsi0
|
||||
version: 02
|
||||
width: 32 bits
|
||||
clock: 66MHz
|
||||
capabilities: storage msi pm ahci_1.0 bus_master cap_list emulated
|
||||
configuration: driver=ahci latency=0
|
||||
resources: irq:42 ioport:18e8(size=8) ioport:18dc(size=4) ioport:18e0(size=8) ioport:18d8(size=4) ioport:18c0(size=16) memory:f0504400-f05047ff
|
||||
*-disk
|
||||
description: ATA Disk
|
||||
product: WDC WD1600BEVS-7
|
||||
vendor: Western Digital
|
||||
physical id: 0.0.0
|
||||
bus info: scsi@0:0.0.0
|
||||
logical name: /dev/sda
|
||||
version: 04.0
|
||||
serial: WD-WXEY07K39367
|
||||
size: 149GiB (160GB)
|
||||
capabilities: partitioned partitioned:dos
|
||||
configuration: ansiversion=5 logicalsectorsize=512 sectorsize=512 signature=0009ac27
|
||||
*-volume:0
|
||||
description: Linux filesystem partition
|
||||
vendor: Linux
|
||||
physical id: 1
|
||||
bus info: scsi@0:0.0.0,1
|
||||
logical name: /dev/sda1
|
||||
logical name: /boot
|
||||
version: 1.0
|
||||
serial: 999d3b16-02f6-43f3-b79a-9e829a73393b
|
||||
size: 200MiB
|
||||
capacity: 200MiB
|
||||
capabilities: primary extended_attributes ext2 initialized
|
||||
configuration: filesystem=ext2 modified=2013-09-19 01:59:14 mount.fstype=ext2 mount.options=rw,relatime,errors=continue mounted=2013-06-16 11:28:21 state=mounted
|
||||
*-volume:1
|
||||
description: EXT4 volume
|
||||
vendor: Linux
|
||||
physical id: 2
|
||||
bus info: scsi@0:0.0.0,2
|
||||
logical name: /dev/sda2
|
||||
logical name: /
|
||||
version: 1.0
|
||||
serial: b63650b2-ef91-4183-9a67-426708cde1b2
|
||||
size: 148GiB
|
||||
capacity: 148GiB
|
||||
capabilities: primary journaled extended_attributes large_files huge_files dir_nlink recover extents ext4 ext2 initialized
|
||||
configuration: created=2013-01-12 00:42:03 filesystem=ext4 lastmountpoint=/ modified=2013-05-16 21:23:46 mount.fstype=ext4 mount.options=rw,relatime,user_xattr,barrier=1,data=ordered mounted=2013-09-19 01:59:14 state=mounted
|
||||
*-serial
|
||||
description: SMBus
|
||||
product: N10/ICH 7 Family SMBus Controller
|
||||
vendor: Intel Corporation
|
||||
physical id: 1f.3
|
||||
bus info: pci@0000:00:1f.3
|
||||
version: 02
|
||||
width: 32 bits
|
||||
clock: 33MHz
|
||||
configuration: driver=i801_smbus latency=0
|
||||
resources: irq:19 ioport:18a0(size=32)
|
||||
*-battery
|
||||
product: SmartBattery
|
||||
vendor: SDI
|
||||
physical id: 1
|
||||
slot: System Battery Bay
|
||||
capacity: 48840mWh
|
||||
configuration: voltage=11.1V
|
||||
*-remoteaccess UNCLAIMED
|
||||
vendor: Intel
|
||||
physical id: 2
|
||||
capabilities: inbound
|
BIN
DUFRESNE/Linux/home/burchettm/.config/awesome/.rc.lua.swp
Normal file
BIN
DUFRESNE/Linux/home/burchettm/.config/awesome/.rc.lua.swp
Normal file
Binary file not shown.
1
DUFRESNE/Linux/home/burchettm/.config/awesome/README
Normal file
1
DUFRESNE/Linux/home/burchettm/.config/awesome/README
Normal file
@ -0,0 +1 @@
|
||||
NOVA AwesomeWM configuration directory
|
@ -0,0 +1 @@
|
||||
Subproject commit 771f42d9bd79df39b3a8806c6cb08dbfed8a961c
|
@ -0,0 +1 @@
|
||||
Subproject commit f65180adc47792da57e5e658f30b855c4dfee29b
|
291
DUFRESNE/Linux/home/burchettm/.config/awesome/lib/archmenu.lua
Normal file
291
DUFRESNE/Linux/home/burchettm/.config/awesome/lib/archmenu.lua
Normal file
@ -0,0 +1,291 @@
|
||||
local menue0e4fc6213e8b3593495a7260c3a4c2e = {
|
||||
{"Accerciser", "/usr/bin/accerciser", "/usr/share/icons/hicolor/16x16/apps/accerciser.png" },
|
||||
{"Screen Reader", "orca --replace", "/usr/share/icons/hicolor/16x16/apps/orca.png" },
|
||||
}
|
||||
|
||||
local menu98edb85b00d9527ad5acebe451b3fae6 = {
|
||||
{"7-Zip FM", "7zFM", "/usr/share/icons/hicolor/32x32/apps/p7zip.png" },
|
||||
{"Akonaditray", "akonaditray", "/usr/share/icons/hicolor/22x22/apps/akonaditray.png" },
|
||||
{"Archive Manager", "file-roller ", "/usr/share/icons/hicolor/16x16/apps/file-roller.png" },
|
||||
{"AutoKey", "autokey-gtk -c"},
|
||||
{"AutoKey (KDE)", "autokey-qt"},
|
||||
{"Calculator", "gnome-calculator", "/usr/share/icons/gnome/16x16/apps/accessories-calculator.png" },
|
||||
{"Character Map", "gucharmap", "/usr/share/icons/gnome/16x16/apps/accessories-character-map.png" },
|
||||
{"Clocks", "gnome-clocks", "/usr/share/icons/hicolor/16x16/apps/gnome-clocks.png" },
|
||||
{"Desktop Search", "tracker-needle", "/usr/share/icons/gnome/16x16/actions/system-search.png" },
|
||||
{"Disks", "gnome-disks", "/usr/share/icons/hicolor/16x16/apps/gnome-disks.png" },
|
||||
{"Engrampa Archive Manager", "engrampa ", "/usr/share/icons/hicolor/16x16/apps/engrampa.png" },
|
||||
{"Fern Wifi Cracker", "gksu fern-wifi-cracker", "///usr/share/fern-wifi-cracker/resources/screen_splash.png" },
|
||||
{"Files", "nautilus --new-window ", "/usr/share/icons/gnome/16x16/apps/system-file-manager.png" },
|
||||
{"Font Viewer", "gnome-font-viewer ", "/usr/share/icons/gnome/16x16/apps/preferences-desktop-font.png" },
|
||||
{"Galculator", "galculator", "/usr/share/icons/hicolor/48x48/apps/galculator.png" },
|
||||
{"Growl For Linux", "/usr/bin/gol", "///usr/share/growl-for-linux/data/icon.png" },
|
||||
{"HP Device Manager", "hp-toolbox", "///usr/share/hplip/data/images/128x128/hp_logo.png" },
|
||||
{"Hwacha", "/opt/hwacha/hwacha", "///opt/hwacha/hwacha.png" },
|
||||
{"IPython Qt console", "ipython qtconsole", "/usr/share/icons/gnome/16x16/status/gnome-netstatus-idle.png" },
|
||||
{"IPython2 Qt console", "ipython2 qtconsole", "/usr/share/icons/gnome/16x16/status/gnome-netstatus-idle.png" },
|
||||
{"Johnny", "johnny", "/usr/share/pixmaps/johnny.png" },
|
||||
{"KeePassX", "keepassx ", "/usr/share/pixmaps/keepassx.xpm" },
|
||||
{"Maps", "gnome-maps", "/usr/share/icons/hicolor/16x16/apps/gnome-maps.png" },
|
||||
{"Metasploit AV Evasion", "xterm -e metasploitavevasion", "/usr/share/pixmaps/metasploitavevasion.png" },
|
||||
{"Nemo", "nemo ", "/usr/share/icons/gnome/16x16/places/folder.png" },
|
||||
{"Notes", "bijiben ", "/usr/share/icons/hicolor/16x16/apps/bijiben.png" },
|
||||
{"PCManFM File Manager", "pcmanfm-qt ", "/usr/share/icons/gnome/16x16/apps/system-file-manager.png" },
|
||||
{"PacmanXG", "ssx pacmanxg"},
|
||||
{"Passwords and Keys", "/usr/bin/seahorse", "/usr/share/icons/hicolor/16x16/apps/seahorse.png" },
|
||||
{"Pip3line", "pip3line", "///usr/share/icons/hicolor/128x128/apps/pip3line.png" },
|
||||
{"Pluma", "pluma ", "/usr/share/icons/gnome/16x16/apps/accessories-text-editor.png" },
|
||||
{"RFDump", "rfdump", "///usr/share/pixmaps/rfdump.png" },
|
||||
{"Random Wordlist Generator", "randomwordlistgenerator", "///usr/share/pixmaps/randomwordlistgenerator.png" },
|
||||
{"Recoll", "recoll", "/usr/share/icons/hicolor/48x48/apps/recoll.png" },
|
||||
{"Root Terminal", "gksu -l gnome-terminal", "/usr/share/pixmaps/gksu-root-terminal.png" },
|
||||
{"Screen Reader", "orca --replace", "/usr/share/icons/hicolor/16x16/apps/orca.png" },
|
||||
{"Screenshot", "gnome-screenshot --interactive", "/usr/share/icons/gnome/16x16/apps/applets-screenshooter.png" },
|
||||
{"Synapse", "synapse"},
|
||||
{"Tomboy Notes", "tomboy --search", "/usr/share/icons/hicolor/16x16/apps/tomboy.png" },
|
||||
{"Weather", "gapplication launch org.gnome.Weather.Application", "/usr/share/icons/hicolor/16x16/apps/org.gnome.Weather.Application.png" },
|
||||
{"Zim Desktop Wiki", "zim", "/usr/share/pixmaps/zim.png" },
|
||||
{"gedit", "gedit ", "/usr/share/icons/gnome/16x16/apps/accessories-text-editor.png" },
|
||||
{"ipython", "xterm -e ipython", "/usr/share/icons/gnome/16x16/status/gnome-netstatus-idle.png" },
|
||||
{"ipython2", "xterm -e ipython2", "/usr/share/icons/gnome/16x16/status/gnome-netstatus-idle.png" },
|
||||
{"ownCloud desktop sync client ", "owncloud", "/usr/share/icons/hicolor/22x22/apps/owncloud.png" },
|
||||
{"x3270", "/usr/bin/x3270", "///usr/share/pixmaps/x3270-icon2.xpm" },
|
||||
}
|
||||
|
||||
local menude7a22a0c94aa64ba2449e520aa20c99 = {
|
||||
{"LibreOffice Math", "libreoffice --math ", "/usr/share/icons/hicolor/16x16/apps/libreoffice-math.png" },
|
||||
}
|
||||
|
||||
local menu251bd8143891238ecedc306508e29017 = {
|
||||
{"AisleRiot Solitaire", "sol", "/usr/share/icons/hicolor/16x16/apps/gnome-aisleriot.png" },
|
||||
{"Chess", "gnome-chess", "/usr/share/icons/hicolor/16x16/apps/gnome-chess.png" },
|
||||
{"Dosbox", "dosbox", "/usr/share/pixmaps/dosbox.png" },
|
||||
{"Dwarf Fortress", "dwarffortress", "///usr/share/pixmaps/dwarffortress.png" },
|
||||
{"Feed The Beast", "feedthebeast", "/usr/share/icons/hicolor/16x16/apps/feedthebeast.png" },
|
||||
{"Firestorm Second Life viewer", "/usr/bin/firestorm", "///usr/share/pixmaps/firestorm_icon.png" },
|
||||
{"Five or More", "five-or-more", "/usr/share/icons/hicolor/16x16/apps/five-or-more.png" },
|
||||
{"Four-in-a-row", "four-in-a-row", "/usr/share/icons/hicolor/16x16/apps/four-in-a-row.png" },
|
||||
{"Game Conqueror", "gameconqueror", "/usr/share/pixmaps/GameConqueror_128x128.png" },
|
||||
{"Hitori", "hitori", "/usr/share/icons/hicolor/16x16/apps/hitori.png" },
|
||||
{"Iagno", "iagno", "/usr/share/icons/hicolor/16x16/apps/iagno.png" },
|
||||
{"Klotski", "gnome-klotski", "/usr/share/icons/hicolor/16x16/apps/gnome-klotski.png" },
|
||||
{"Lights Off", "lightsoff"},
|
||||
{"Mahjongg", "gnome-mahjongg", "/usr/share/icons/hicolor/16x16/apps/gnome-mahjongg.png" },
|
||||
{"Mari0", "mari0"},
|
||||
{"Minecraft", "minecraft", "///usr/share/pixmaps/minecraft.png" },
|
||||
{"Mines", "gnome-mines", "/usr/share/icons/hicolor/16x16/apps/gnome-mines.png" },
|
||||
{"Minetest", "minetest"},
|
||||
{"Nibbles", "gnome-nibbles", "/usr/share/icons/hicolor/16x16/apps/gnome-nibbles.png" },
|
||||
{"PlayOnLinux", "playonlinux", "///usr/share/playonlinux/etc/playonlinux.png" },
|
||||
{"Quadrapassel", "quadrapassel", "/usr/share/icons/hicolor/16x16/apps/quadrapassel.png" },
|
||||
{"Robots", "gnome-robots", "/usr/share/icons/hicolor/16x16/apps/gnome-robots.png" },
|
||||
{"RuneScape", "/opt/runescape/runescape", "///opt/runescape/share/img/runescape.png" },
|
||||
{"RuneScape OldSchool", "/opt/runescape/runescape --prmfile=oldschool.prm", "///opt/runescape/share/img/runescape.png" },
|
||||
{"Runescape Client Updater", "xterm -e /opt/runescape/rsu/rsu-query rsu.download.client", "///opt/runescape/share/img/update-runescape.png" },
|
||||
{"StarMade", "starmade", "///usr/share/pixmaps/starmade.png" },
|
||||
{"Steam", "env STEAM_FRAME_FORCE_CLOSE=1 /usr/bin/steam ", "/usr/share/icons/hicolor/16x16/apps/steam.png" },
|
||||
{"Steam", "/usr/bin/steam ", "/usr/share/icons/hicolor/16x16/apps/steam.png" },
|
||||
{"Sudoku", "gnome-sudoku", "/usr/share/icons/hicolor/16x16/apps/gnome-sudoku.png" },
|
||||
{"SuperTux 2", "supertux2", "/usr/share/pixmaps/supertux.png" },
|
||||
{"Swell Foop", "swell-foop", "/usr/share/icons/hicolor/16x16/apps/swell-foop.png" },
|
||||
{"Tali", "tali", "/usr/share/icons/hicolor/16x16/apps/tali.png" },
|
||||
{"Tetravex", "gnome-tetravex", "/usr/share/icons/hicolor/16x16/apps/gnome-tetravex.png" },
|
||||
{"Xonotic (GLX)", "/usr/bin/xonotic-glx", "/usr/share/icons/hicolor/16x16/apps/xonotic.png" },
|
||||
{"Xonotic (SDL)", "/usr/bin/xonotic-sdl", "/usr/share/icons/hicolor/16x16/apps/xonotic.png" },
|
||||
}
|
||||
|
||||
local menud334dfcea59127bedfcdbe0a3ee7f494 = {
|
||||
{"Document Viewer", "evince ", "/usr/share/icons/hicolor/16x16/apps/evince.png" },
|
||||
{"Eye of MATE Image Viewer", "eom ", "/usr/share/icons/hicolor/16x16/apps/eom.png" },
|
||||
{"FontForge", "fontforge ", "/usr/share/icons/hicolor/16x16/apps/fontforge.png" },
|
||||
{"GNU Image Manipulation Program", "gimp-2.8 ", "/usr/share/icons/hicolor/16x16/apps/gimp.png" },
|
||||
{"Image Viewer", "eog ", "/usr/share/icons/hicolor/16x16/apps/eog.png" },
|
||||
{"Image Viewer", "gpicview ", "/usr/share/icons/hicolor/48x48/apps/gpicview.png" },
|
||||
{"LibreOffice Draw", "libreoffice --draw ", "/usr/share/icons/hicolor/16x16/apps/libreoffice-draw.png" },
|
||||
{"ScreenCloud", "/opt/screencloud/screencloud.sh", "/usr/share/icons/hicolor/16x16/apps/screencloud.png" },
|
||||
{"xgps", "xgps", "///usr/share/gpsd/gpsd-logo.png" },
|
||||
{"xgpsspeed", "xgpsspeed", "///usr/share/gpsd/gpsd-logo.png" },
|
||||
}
|
||||
|
||||
local menuc8205c7636e728d448c2774e6a4a944b = {
|
||||
{"Amap", "amap"},
|
||||
{"Angry IP Scanner", "ipscan"},
|
||||
{"Avahi SSH Server Browser", "/usr/bin/bssh", "/usr/share/icons/gnome/16x16/devices/network-wired.png" },
|
||||
{"Avahi VNC Server Browser", "/usr/bin/bvnc", "/usr/share/icons/gnome/16x16/devices/network-wired.png" },
|
||||
{"Browse Mirrored Websites", "webhttrack browse", "/usr/share/icons/hicolor/16x16/apps/httrack.png" },
|
||||
{"Caja Dropbox", "caja-dropbox start -i", "/usr/share/icons/hicolor/16x16/apps/caja-dropbox.png" },
|
||||
{"Chromium", "chromium ", "/usr/share/icons/hicolor/16x16/apps/chromium.png" },
|
||||
{"Dell SonicWALL NetExtender", "/usr/bin/netExtenderGui", "///usr/share/netExtender/icons/nx48.xpm" },
|
||||
{"ELinks", "xterm -e /usr/bin/elinks ", "/usr/share/icons/gnome/16x16/mimetypes/html.png" },
|
||||
{"Empathy", "empathy", "/usr/share/icons/hicolor/16x16/apps/empathy.png" },
|
||||
{"EtherApe", "etherape", "/usr/share/pixmaps/etherape.png" },
|
||||
{"Ettercap", "ettercap-pkexec -G", "/usr/share/pixmaps/ettercap.svg" },
|
||||
{"FileZilla", "filezilla", "/usr/share/icons/hicolor/16x16/apps/filezilla.png" },
|
||||
{"Firefox", "/usr/lib/firefox/firefox ", "/usr/share/icons/hicolor/16x16/apps/firefox.png" },
|
||||
{"Firefox Developer", "firefox-developer ", "/usr/share/pixmaps/firefox-developer-icon.png" },
|
||||
{"Gajim", "gajim", "/usr/share/icons/hicolor/64x64/apps/gajim.png" },
|
||||
{"Gnome-RDP", "gnome-rdp", "/usr/share/pixmaps/gnome-rdp.png" },
|
||||
{"Google Chrome", "/usr/bin/google-chrome-stable ", "/usr/share/icons/hicolor/16x16/apps/google-chrome.png" },
|
||||
{"Google Chrome (beta)", "/usr/bin/google-chrome-beta ", "/usr/share/icons/hicolor/16x16/apps/google-chrome-beta.png" },
|
||||
{"Google Chrome (unstable)", "/usr/bin/google-chrome-unstable ", "/usr/share/icons/hicolor/16x16/apps/google-chrome-unstable.png" },
|
||||
{"KRDC", "krdc -caption KRDC "},
|
||||
{"KompoZer", "kompozer", "/usr/share/pixmaps/kompozer.png" },
|
||||
{"Midori", "midori ", "/usr/share/icons/hicolor/16x16/apps/midori.png" },
|
||||
{"Midori Private Browsing", "midori --private ", "/usr/share/icons/hicolor/16x16/apps/midori.png" },
|
||||
{"Mumble", "mumble"},
|
||||
{"Net Activity Viewer", "netactview", "/usr/share/pixmaps/netactview.png" },
|
||||
{"Netsurf", "netsurf ", "/usr/share/pixmaps/netsurf.png" },
|
||||
{"OnionShare", "/usr/bin/onionshare-gui", "///usr/share/pixmaps/onionshare80.xpm" },
|
||||
{"Opera", "opera ", "/usr/share/icons/hicolor/16x16/apps/opera.png" },
|
||||
{"Pidgin Internet Messenger", "pidgin", "/usr/share/icons/hicolor/16x16/apps/pidgin.png" },
|
||||
{"Polari", "polari", "/usr/share/icons/hicolor/16x16/apps/polari.png" },
|
||||
{"Quassel IRC (Client only)", "quasselclient", "/usr/share/icons/hicolor/16x16/apps/quassel.png" },
|
||||
{"Remmina", "remmina", "/usr/share/icons/hicolor/16x16/apps/remmina.png" },
|
||||
{"Remote Desktop Viewer", "vinagre ", "/usr/share/icons/gnome/16x16/apps/preferences-desktop-remote-desktop.png" },
|
||||
{"SeaMonkey internet suite", "seamonkey", "/usr/share/pixmaps/seamonkey.png" },
|
||||
{"Skype", "skype ", "/usr/share/icons/hicolor/16x16/apps/skype.png" },
|
||||
{"Steam", "env STEAM_FRAME_FORCE_CLOSE=1 /usr/bin/steam ", "/usr/share/icons/hicolor/16x16/apps/steam.png" },
|
||||
{"Steam", "/usr/bin/steam ", "/usr/share/icons/hicolor/16x16/apps/steam.png" },
|
||||
{"TeamSpeak 3", "teamspeak3", "/usr/share/pixmaps/teamspeak3.xpm" },
|
||||
{"TeamViewer 10", "/opt/teamviewer/tv_bin/script/teamviewer", "///opt/teamviewer/tv_bin/desktop/teamviewer.png" },
|
||||
{"Thunderbird", "thunderbird ", "/usr/share/icons/hicolor/16x16/apps/thunderbird.png" },
|
||||
{"TigerVNC Viewer", "/usr/bin/vncviewer", "/usr/share/icons/hicolor/16x16/apps/tigervnc.png" },
|
||||
{"Transmission", "transmission-gtk ", "/usr/share/icons/hicolor/16x16/apps/transmission.png" },
|
||||
{"UltraVNC Viewer", "ultravnc-viewer", "/usr/share/icons/hicolor/16x16/apps/ultravnc-viewer.png" },
|
||||
{"UltraVNC Viewer Listen mode", "ultravnc-viewer -listen", "/usr/share/icons/hicolor/16x16/apps/ultravnc-viewer.png" },
|
||||
{"Vivaldi", "/usr/bin/vivaldi-preview ", "/usr/share/icons/hicolor/16x16/apps/vivaldi.png" },
|
||||
{"Wavemon", "wavemon"},
|
||||
{"Web", "epiphany ", "/usr/share/icons/gnome/16x16/apps/web-browser.png" },
|
||||
{"WebHTTrack Website Copier", "webhttrack", "/usr/share/icons/hicolor/16x16/apps/httrack.png" },
|
||||
{"XSSer", "/usr/bin/xsser --gtk --silent", "///usr/share/xsser/gtk/images/xssericon_24x24.png" },
|
||||
{"Zenmap", "zenmap ", "///usr/share/zenmap/pixmaps/zenmap.png" },
|
||||
{"Zenmap (as root)", "/usr/share/zenmap/su-to-zenmap.sh ", "///usr/share/zenmap/pixmaps/zenmap.png" },
|
||||
{"tcpjunk", "tcpjunk -x", "/usr/share/pixmaps/tcpjunk.png" },
|
||||
{"w3af", "w3af-gui", "///usr/share/w3af/doc/sphinx/images/w3af-logo.png" },
|
||||
}
|
||||
|
||||
local menudf814135652a5a308fea15bff37ea284 = {
|
||||
{"Atril Document Viewer", "atril ", "/usr/share/icons/hicolor/16x16/apps/atril.png" },
|
||||
{"Dictionary", "gnome-dictionary", "/usr/share/icons/gnome/16x16/apps/accessories-dictionary.png" },
|
||||
{"Document Viewer", "evince ", "/usr/share/icons/hicolor/16x16/apps/evince.png" },
|
||||
{"Evolution", "evolution ", "/usr/share/icons/hicolor/16x16/apps/evolution.png" },
|
||||
{"LibreOffice", "libreoffice ", "/usr/share/icons/hicolor/16x16/apps/libreoffice-startcenter.png" },
|
||||
{"LibreOffice Base", "libreoffice --base ", "/usr/share/icons/hicolor/16x16/apps/libreoffice-base.png" },
|
||||
{"LibreOffice Calc", "libreoffice --calc ", "/usr/share/icons/hicolor/16x16/apps/libreoffice-calc.png" },
|
||||
{"LibreOffice Draw", "libreoffice --draw ", "/usr/share/icons/hicolor/16x16/apps/libreoffice-draw.png" },
|
||||
{"LibreOffice Impress", "libreoffice --impress ", "/usr/share/icons/hicolor/16x16/apps/libreoffice-impress.png" },
|
||||
{"LibreOffice Installer", "libreoffice-installer", "/usr/share/icons/gnome/16x16/actions/document-save.png" },
|
||||
{"LibreOffice Math", "libreoffice --math ", "/usr/share/icons/hicolor/16x16/apps/libreoffice-math.png" },
|
||||
{"LibreOffice Writer", "libreoffice --writer ", "/usr/share/icons/hicolor/16x16/apps/libreoffice-writer.png" },
|
||||
{"Wordview Microsoft doc Viewer", "wordview", "/usr/share/pixmaps/wordview.xpm" },
|
||||
}
|
||||
|
||||
local menu6311ae17c1ee52b36e68aaf4ad066387 = {
|
||||
{"Admsnmp", "admsnmp"},
|
||||
{"Argtable", "argtable"},
|
||||
{"Cuckoo", "/usr/bin/cuckoo"},
|
||||
{"ut2004", "/usr/local/games/ut2004//ut2004", "///usr/local/games/ut2004//ut2004.xpm" },
|
||||
}
|
||||
|
||||
local menue6f43c40ab1c07cd29e4e83e4ef6bf85 = {
|
||||
{"Accerciser", "/usr/bin/accerciser", "/usr/share/icons/hicolor/16x16/apps/accerciser.png" },
|
||||
{"Anjuta", "anjuta ", "/usr/share/icons/hicolor/16x16/apps/anjuta.png" },
|
||||
{"Arduino", "arduino ", "/usr/share/icons/hicolor/256x256/apps/arduino.png" },
|
||||
{"Brackets", "/opt/brackets/brackets ", "/usr/share/icons/hicolor/32x32/apps/brackets.png" },
|
||||
{"CMake", "cmake-gui ", "/usr/share/icons/hicolor/32x32/apps/CMakeSetup.png" },
|
||||
{"Database browser", "gda-browser-5.0", "/usr/share/pixmaps/gda-browser-5.0.png" },
|
||||
{"Devhelp", "devhelp", "/usr/share/icons/hicolor/16x16/apps/devhelp.png" },
|
||||
{"Dissy", "dissy", "/usr/share/pixmaps/dissy.svg" },
|
||||
{"Emacs", "emacs ", "/usr/share/icons/hicolor/16x16/apps/emacs.png" },
|
||||
{"Evan's Debugger", "edb"},
|
||||
{"FLUID", "fluid ", "/usr/share/icons/hicolor/16x16/apps/fluid.png" },
|
||||
{"Glade", "glade ", "/usr/share/icons/hicolor/16x16/apps/glade.png" },
|
||||
{"IPython Qt console", "ipython qtconsole", "/usr/share/icons/gnome/16x16/status/gnome-netstatus-idle.png" },
|
||||
{"IPython2 Qt console", "ipython2 qtconsole", "/usr/share/icons/gnome/16x16/status/gnome-netstatus-idle.png" },
|
||||
{"KompoZer", "kompozer", "/usr/share/pixmaps/kompozer.png" },
|
||||
{"NetBeans", "netbeans", "/usr/share/pixmaps/netbeans.png" },
|
||||
{"OpenJDK Monitoring & Management Console", "/usr/bin/jconsole", "/usr/share/icons/hicolor/16x16/apps/java.png" },
|
||||
{"OpenJDK Policy Tool", "/usr/bin/policytool", "/usr/share/icons/hicolor/16x16/apps/java.png" },
|
||||
{"Qt Assistant", "/usr/lib/qt/bin/assistant", "/usr/share/icons/hicolor/32x32/apps/assistant.png" },
|
||||
{"Qt Designer", "/usr/lib/qt/bin/designer", "/usr/share/icons/hicolor/128x128/apps/QtProject-designer.png" },
|
||||
{"Qt Linguist", "/usr/lib/qt/bin/linguist", "/usr/share/icons/hicolor/16x16/apps/linguist.png" },
|
||||
{"Qt QDbusViewer ", "/usr/lib/qt/bin/qdbusviewer", "/usr/share/icons/hicolor/32x32/apps/qdbusviewer.png" },
|
||||
{"Qt4 Assistant ", "assistant-qt4", "/usr/share/icons/hicolor/32x32/apps/assistant-qt4.png" },
|
||||
{"Qt4 Designer", "designer-qt4", "/usr/share/icons/hicolor/128x128/apps/designer-qt4.png" },
|
||||
{"Qt4 Linguist ", "linguist-qt4", "/usr/share/icons/hicolor/16x16/apps/linguist-qt4.png" },
|
||||
{"Qt4 QDbusViewer ", "qdbusviewer-qt4", "/usr/share/icons/hicolor/32x32/apps/qdbusviewer-qt4.png" },
|
||||
{"Sublime Text 3 Dev", "subl3 ", "/usr/share/icons/hicolor/16x16/apps/sublime-text.png" },
|
||||
{"VisualVM", "/usr/bin/visualvm", "///usr/share/visualvm/icon.png" },
|
||||
{"gitg", "gitg --no-wd ", "/usr/share/icons/hicolor/16x16/apps/gitg.png" },
|
||||
{"haroopad", "haroopad ", "/usr/share/icons/hicolor/16x16/apps/haroopad.png" },
|
||||
{"ipython", "xterm -e ipython", "/usr/share/icons/gnome/16x16/status/gnome-netstatus-idle.png" },
|
||||
{"ipython2", "xterm -e ipython2", "/usr/share/icons/gnome/16x16/status/gnome-netstatus-idle.png" },
|
||||
}
|
||||
|
||||
local menu52dd1c847264a75f400961bfb4d1c849 = {
|
||||
{"Audacious", "audacious ", "/usr/share/icons/hicolor/48x48/apps/audacious.png" },
|
||||
{"Brasero", "brasero ", "/usr/share/icons/hicolor/16x16/apps/brasero.png" },
|
||||
{"Cheese", "cheese", "/usr/share/icons/hicolor/16x16/apps/cheese.png" },
|
||||
{"Clementine", "clementine ", "/usr/share/icons/hicolor/64x64/apps/application-x-clementine.png" },
|
||||
{"Feed The Beast", "feedthebeast", "/usr/share/icons/hicolor/16x16/apps/feedthebeast.png" },
|
||||
{"LXMusic simple music player", "lxmusic", "/usr/share/pixmaps/lxmusic.png" },
|
||||
{"Music", "gnome-music", "/usr/share/icons/hicolor/16x16/apps/gnome-music.png" },
|
||||
{"Pithos", "pithos"},
|
||||
{"Plex Home Theater", "/usr/bin/plexhometheater.sh", "///usr/share/pixmaps/plexhometheater.png" },
|
||||
{"PulseAudio Volume Control", "pavucontrol", "/usr/share/icons/hicolor/16x16/apps/multimedia-volume-control.png" },
|
||||
{"Qt V4L2 test Utility", "qv4l2", "/usr/share/icons/hicolor/16x16/apps/qv4l2.png" },
|
||||
{"Spotify", "spotify ", "/usr/share/icons/hicolor/16x16/apps/spotify-client.png" },
|
||||
{"VLC media player", "/usr/bin/vlc --started-from-file ", "/usr/share/icons/hicolor/16x16/apps/vlc.png" },
|
||||
{"Videos", "totem ", "/usr/share/icons/hicolor/16x16/apps/totem.png" },
|
||||
{"Xnoise", "xnoise ", "/usr/share/icons/hicolor/32x32/apps/xnoise.png" },
|
||||
}
|
||||
|
||||
local menuee69799670a33f75d45c57d1d1cd0ab3 = {
|
||||
{"Avahi Zeroconf Browser", "/usr/bin/avahi-discover", "/usr/share/icons/gnome/16x16/devices/network-wired.png" },
|
||||
{"Disk Usage Analyzer", "baobab", "/usr/share/icons/hicolor/16x16/apps/baobab.png" },
|
||||
{"Disk Utility", "mate-disk"},
|
||||
{"EtherApe", "etherape", "/usr/share/pixmaps/etherape.png" },
|
||||
{"File Manager PCManFM", "pcmanfm ", "/usr/share/icons/gnome/16x16/apps/system-file-manager.png" },
|
||||
{"GParted", "/usr/bin/gparted_polkit ", "/usr/share/icons/hicolor/16x16/apps/gparted.png" },
|
||||
{"Guake Terminal", "guake", "/usr/share/icons/hicolor/16x16/apps/guake.png" },
|
||||
{"Guymager", "gksudo guymager", "/usr/share/pixmaps/guymager_128.png" },
|
||||
{"Htop", "xterm -e htop", "/usr/share/pixmaps/htop.png" },
|
||||
{"LSHW", "/usr/sbin/gtk-lshw", "///usr/share/lshw/artwork/logo.svg" },
|
||||
{"LXTerminal", "lxterminal", "/usr/share/icons/hicolor/128x128/apps/lxterminal.png" },
|
||||
{"Logs", "gnome-logs", "/usr/share/icons/hicolor/16x16/apps/gnome-logs.png" },
|
||||
{"MATE Terminal", "mate-terminal", "/usr/share/icons/gnome/16x16/apps/utilities-terminal.png" },
|
||||
{"MDB Tools", "gmdb2", "///usr/share/gmdb/glade/logo.xpm" },
|
||||
{"Manage Printing", "/usr/bin/xdg-open http://localhost:631/", "/usr/share/icons/hicolor/16x16/apps/cups.png" },
|
||||
{"Network Tools", "mate-nettool", "/usr/share/icons/hicolor/16x16/apps/mate-nettool.png" },
|
||||
{"Network Tools", "gnome-nettool", "/usr/share/icons/hicolor/16x16/apps/gnome-nettool.png" },
|
||||
{"Ophcrack", "ophcrack", "///usr/share/ophcrack/pixmaps/os.xpm" },
|
||||
{"Oracle VM VirtualBox", "VirtualBox ", "/usr/share/icons/hicolor/16x16/mimetypes/virtualbox.png" },
|
||||
{"System Log", "gnome-system-log", "/usr/share/icons/hicolor/16x16/apps/logview.png" },
|
||||
{"System Monitor", "gnome-system-monitor", "/usr/share/icons/gnome/16x16/apps/utilities-system-monitor.png" },
|
||||
{"Task Manager", "lxtask", "/usr/share/icons/gnome/16x16/apps/utilities-system-monitor.png" },
|
||||
{"Terminal", "gnome-terminal", "/usr/share/icons/gnome/16x16/apps/utilities-terminal.png" },
|
||||
{"Terminator", "terminator", "/usr/share/icons/hicolor/16x16/apps/terminator.png" },
|
||||
{"Tilda", "/usr/bin/tilda", "/usr/share/pixmaps/tilda.png" },
|
||||
{"UXTerm", "uxterm", "/usr/share/pixmaps/xterm-color_48x48.xpm" },
|
||||
{"Virtual Machine Manager", "virt-manager", "/usr/share/icons/hicolor/16x16/apps/virt-manager.png" },
|
||||
{"Wireshark", "wireshark ", "/usr/share/icons/hicolor/16x16/apps/wireshark.png" },
|
||||
{"XSSer", "/usr/bin/xsser --gtk --silent", "///usr/share/xsser/gtk/images/xssericon_24x24.png" },
|
||||
{"XTerm", "xterm", "/usr/share/pixmaps/xterm-color_48x48.xpm" },
|
||||
{"Xfce Terminal", "xfce4-terminal", "/usr/share/icons/gnome/16x16/apps/utilities-terminal.png" },
|
||||
{"dconf Editor", "dconf-editor", "/usr/share/icons/hicolor/16x16/apps/dconf-editor.png" },
|
||||
}
|
||||
|
||||
xdgmenu = {
|
||||
{"Accessibility", menue0e4fc6213e8b3593495a7260c3a4c2e},
|
||||
{"Accessories", menu98edb85b00d9527ad5acebe451b3fae6},
|
||||
{"Education", menude7a22a0c94aa64ba2449e520aa20c99},
|
||||
{"Games", menu251bd8143891238ecedc306508e29017},
|
||||
{"Graphics", menud334dfcea59127bedfcdbe0a3ee7f494},
|
||||
{"Internet", menuc8205c7636e728d448c2774e6a4a944b},
|
||||
{"Office", menudf814135652a5a308fea15bff37ea284},
|
||||
{"Other", menu6311ae17c1ee52b36e68aaf4ad066387},
|
||||
{"Programming", menue6f43c40ab1c07cd29e4e83e4ef6bf85},
|
||||
{"Sound & Video", menu52dd1c847264a75f400961bfb4d1c849},
|
||||
{"System Tools", menuee69799670a33f75d45c57d1d1cd0ab3},
|
||||
}
|
||||
|
@ -0,0 +1,46 @@
|
||||
---------------------------------------------------------------------------
|
||||
-- @author Julien Danjou <julien@danjou.info>
|
||||
-- @copyright 2009 Julien Danjou
|
||||
-- @release v3.4.10
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
local client = client
|
||||
local screen = screen
|
||||
local aclient = require("awful.client")
|
||||
local atag = require("awful.tag")
|
||||
|
||||
--- When loaded, this module makes sure that there's always a client that will have focus
|
||||
-- on event such as tag switching, client unmanaging, etc.
|
||||
module("awful.autofocus")
|
||||
|
||||
-- Give focus when clients appear/disappear.
|
||||
-- @param obj An object that should have a .screen property.
|
||||
local function check_focus(obj)
|
||||
-- When no visible client has the focus...
|
||||
if not client.focus or not client.focus:isvisible() then
|
||||
local c = aclient.focus.history.get(obj.screen, 0)
|
||||
if c then client.focus = c end
|
||||
end
|
||||
end
|
||||
|
||||
-- Give focus on tag selection change.
|
||||
-- @param obj An object that should have a .screen property.
|
||||
local function check_focus_screen(obj)
|
||||
check_focus(obj)
|
||||
if client.focus and client.focus.screen ~= obj.screen then
|
||||
local c = nil
|
||||
c = aclient.focus.history.get(obj.screen, 0)
|
||||
if c then client.focus = c end
|
||||
end
|
||||
end
|
||||
|
||||
atag.attached_add_signal(nil, "property::selected", check_focus_screen)
|
||||
client.add_signal("unmanage", check_focus)
|
||||
client.add_signal("new", function(c)
|
||||
c:add_signal("tagged", check_focus)
|
||||
c:add_signal("untagged", check_focus)
|
||||
c:add_signal("property::hidden", check_focus)
|
||||
c:add_signal("property::minimized", check_focus)
|
||||
end)
|
||||
|
||||
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80
|
@ -0,0 +1,52 @@
|
||||
---------------------------------------------------------------------------
|
||||
-- @author Julien Danjou <julien@danjou.info>
|
||||
-- @copyright 2009 Julien Danjou
|
||||
-- @release v3.4.10
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
-- Grab environment we need
|
||||
local setmetatable = setmetatable
|
||||
local ipairs = ipairs
|
||||
local capi = { button = button }
|
||||
local util = require("awful.util")
|
||||
|
||||
--- Create easily new buttons objects ignoring certain modifiers.
|
||||
module("awful.button")
|
||||
|
||||
--- Modifiers to ignore.
|
||||
-- By default this is initialized as { "Lock", "Mod2" }
|
||||
-- so the Caps Lock or Num Lock modifier are not taking into account by awesome
|
||||
-- when pressing keys.
|
||||
-- @name ignore_modifiers
|
||||
-- @class table
|
||||
ignore_modifiers = { "Lock", "Mod2" }
|
||||
|
||||
--- Create a new button to use as binding.
|
||||
-- This function is useful to create several buttons from one, because it will use
|
||||
-- the ignore_modifier variable to create more button with or without the ignored
|
||||
-- modifiers activated.
|
||||
-- For example if you want to ignore CapsLock in your buttonbinding (which is
|
||||
-- ignored by default by this function), creating button binding with this function
|
||||
-- will return 2 button objects: one with CapsLock on, and the other one with
|
||||
-- CapsLock off.
|
||||
-- @see button
|
||||
-- @return A table with one or several button objects.
|
||||
function new(mod, button, press, release)
|
||||
local ret = {}
|
||||
local subsets = util.subsets(ignore_modifiers)
|
||||
for _, set in ipairs(subsets) do
|
||||
ret[#ret + 1] = capi.button({ modifiers = util.table.join(mod, set),
|
||||
button = button })
|
||||
if press then
|
||||
ret[#ret]:add_signal("press", function(bobj, ...) press(...) end)
|
||||
end
|
||||
if release then
|
||||
ret[#ret]:add_signal("release", function (bobj, ...) release(...) end)
|
||||
end
|
||||
end
|
||||
return ret
|
||||
end
|
||||
|
||||
setmetatable(_M, { __call = function(_, ...) return new(...) end })
|
||||
|
||||
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80
|
@ -0,0 +1,876 @@
|
||||
---------------------------------------------------------------------------
|
||||
-- @author Julien Danjou <julien@danjou.info>
|
||||
-- @copyright 2008 Julien Danjou
|
||||
-- @release v3.4.10
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
-- Grab environment we need
|
||||
local util = require("awful.util")
|
||||
local tag = require("awful.tag")
|
||||
local pairs = pairs
|
||||
local type = type
|
||||
local ipairs = ipairs
|
||||
local table = table
|
||||
local math = math
|
||||
local setmetatable = setmetatable
|
||||
local capi =
|
||||
{
|
||||
client = client,
|
||||
mouse = mouse,
|
||||
screen = screen,
|
||||
}
|
||||
|
||||
--- Useful client manipulation functions.
|
||||
module("awful.client")
|
||||
|
||||
-- Private data
|
||||
data = {}
|
||||
data.focus = {}
|
||||
data.urgent = {}
|
||||
data.marked = {}
|
||||
data.properties = setmetatable({}, { __mode = 'k' })
|
||||
|
||||
-- Functions
|
||||
urgent = {}
|
||||
focus = {}
|
||||
focus.history = {}
|
||||
swap = {}
|
||||
floating = {}
|
||||
dockable = {}
|
||||
property = {}
|
||||
|
||||
--- Get the first client that got the urgent hint.
|
||||
-- @return The first urgent client.
|
||||
function urgent.get()
|
||||
if #data.urgent > 0 then
|
||||
return data.urgent[1]
|
||||
else
|
||||
-- fallback behaviour: iterate through clients and get the first urgent
|
||||
local clients = capi.client.get()
|
||||
for k, cl in pairs(clients) do
|
||||
if cl.urgent then
|
||||
return cl
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--- Jump to the client that received the urgent hint first.
|
||||
-- @param merge If true then merge tags when clients are not visible.
|
||||
function urgent.jumpto(merge)
|
||||
local c = urgent.get()
|
||||
if c then
|
||||
local s = capi.client.focus and capi.client.focus.screen or capi.mouse.screen
|
||||
-- focus the screen
|
||||
if s ~= c.screen then
|
||||
capi.mouse.screen = c.screen
|
||||
end
|
||||
|
||||
-- Try to make client visible, this also covers e.g. sticky
|
||||
local t = c:tags()[1]
|
||||
if t and not c:isvisible() then
|
||||
if merge then
|
||||
t.selected = true
|
||||
else
|
||||
tag.viewonly(t)
|
||||
end
|
||||
end
|
||||
|
||||
-- focus the client
|
||||
capi.client.focus = c
|
||||
c:raise()
|
||||
end
|
||||
end
|
||||
|
||||
--- Adds client to urgent stack.
|
||||
-- @param c The client object.
|
||||
-- @param prop The property which is updated.
|
||||
function urgent.add(c, prop)
|
||||
if type(c) == "client" and prop == "urgent" and c.urgent then
|
||||
table.insert(data.urgent, c)
|
||||
end
|
||||
end
|
||||
|
||||
--- Remove client from urgent stack.
|
||||
-- @param c The client object.
|
||||
function urgent.delete(c)
|
||||
for k, cl in ipairs(data.urgent) do
|
||||
if c == cl then
|
||||
table.remove(data.urgent, k)
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--- Remove a client from the focus history
|
||||
-- @param c The client that must be removed.
|
||||
function focus.history.delete(c)
|
||||
for k, v in ipairs(data.focus) do
|
||||
if v == c then
|
||||
table.remove(data.focus, k)
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--- Filter out window that we do not want handled by focus.
|
||||
-- This usually means that desktop, dock and splash windows are
|
||||
-- not registered and cannot get focus.
|
||||
-- @param c A client.
|
||||
-- @return The same client if it's ok, nil otherwise.
|
||||
function focus.filter(c)
|
||||
if c.type == "desktop"
|
||||
or c.type == "dock"
|
||||
or c.type == "splash"
|
||||
or not c.focusable then
|
||||
return nil
|
||||
end
|
||||
return c
|
||||
end
|
||||
|
||||
--- Update client focus history.
|
||||
-- @param c The client that has been focused.
|
||||
function focus.history.add(c)
|
||||
if focus.filter(c) then
|
||||
-- Remove the client if its in stack
|
||||
focus.history.delete(c)
|
||||
-- Record the client has latest focused
|
||||
table.insert(data.focus, 1, c)
|
||||
end
|
||||
end
|
||||
|
||||
--- Get the latest focused client for a screen in history.
|
||||
-- @param screen The screen number to look for.
|
||||
-- @param idx The index: 0 will return first candidate,
|
||||
-- 1 will return second, etc.
|
||||
-- @return A client.
|
||||
function focus.history.get(screen, idx)
|
||||
-- When this counter is equal to idx, we return the client
|
||||
local counter = 0
|
||||
local vc = visible(screen)
|
||||
for k, c in ipairs(data.focus) do
|
||||
if c.screen == screen then
|
||||
for j, vcc in ipairs(vc) do
|
||||
if vcc == c then
|
||||
if counter == idx then
|
||||
return c
|
||||
end
|
||||
-- We found one, increment the counter only.
|
||||
counter = counter + 1
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
-- Argh nobody found in history, give the first one visible if there is one
|
||||
-- that passes the filter.
|
||||
if counter == 0 then
|
||||
for k, v in ipairs(vc) do
|
||||
if focus.filter(v) then
|
||||
return v
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--- Focus the previous client in history.
|
||||
function focus.history.previous()
|
||||
local sel = capi.client.focus
|
||||
local s
|
||||
if sel then
|
||||
s = sel.screen
|
||||
else
|
||||
s = capi.mouse.screen
|
||||
end
|
||||
local c = focus.history.get(s, 1)
|
||||
if c then capi.client.focus = c end
|
||||
end
|
||||
|
||||
--- Get visible clients from a screen.
|
||||
-- @param screen The screen number, or nil for all screens.
|
||||
-- @return A table with all visible clients.
|
||||
function visible(screen)
|
||||
local cls = capi.client.get(screen)
|
||||
local vcls = {}
|
||||
for k, c in pairs(cls) do
|
||||
if c:isvisible() then
|
||||
table.insert(vcls, c)
|
||||
end
|
||||
end
|
||||
return vcls
|
||||
end
|
||||
|
||||
--- Get visible and tiled clients
|
||||
-- @param screen The screen number, or nil for all screens.
|
||||
-- @return A tabl with all visible and tiled clients.
|
||||
function tiled(screen)
|
||||
local clients = visible(screen)
|
||||
local tclients = {}
|
||||
-- Remove floating clients
|
||||
for k, c in pairs(clients) do
|
||||
if not floating.get(c) then
|
||||
table.insert(tclients, c)
|
||||
end
|
||||
end
|
||||
return tclients
|
||||
end
|
||||
|
||||
--- Get a client by its relative index to the focused window.
|
||||
-- @usage Set i to 1 to get next, -1 to get previous.
|
||||
-- @param i The index.
|
||||
-- @param c Optional client.
|
||||
-- @return A client, or nil if no client is available.
|
||||
function next(i, c)
|
||||
-- Get currently focused client
|
||||
local sel = c or capi.client.focus
|
||||
if sel then
|
||||
-- Get all visible clients
|
||||
local cls = visible(sel.screen)
|
||||
local fcls = {}
|
||||
-- Remove all non-normal clients
|
||||
for idx, c in ipairs(cls) do
|
||||
if focus.filter(c) or c == sel then
|
||||
table.insert(fcls, c)
|
||||
end
|
||||
end
|
||||
cls = fcls
|
||||
-- Loop upon each client
|
||||
for idx, c in ipairs(cls) do
|
||||
if c == sel then
|
||||
-- Cycle
|
||||
return cls[util.cycle(#cls, idx + i)]
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Return true whether client B is in the right direction
|
||||
-- compared to client A.
|
||||
-- @param dir The direction.
|
||||
-- @param cA The first client.
|
||||
-- @param cB The second client.
|
||||
-- @return True if B is in the direction of A.
|
||||
local function is_in_direction(dir, cA, cB)
|
||||
local gA = cA:geometry()
|
||||
local gB = cB:geometry()
|
||||
if dir == "up" then
|
||||
return gA.y > gB.y
|
||||
elseif dir == "down" then
|
||||
return gA.y < gB.y
|
||||
elseif dir == "left" then
|
||||
return gA.x > gB.x
|
||||
elseif dir == "right" then
|
||||
return gA.x < gB.x
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
-- Calculate distance between two points.
|
||||
-- i.e: if we want to move to the right, we will take the right border
|
||||
-- of the currently focused client and the left side of the checked client.
|
||||
-- This avoid the focus of an upper client when you move to the right in a
|
||||
-- tilebottom layout with nmaster=2 and 5 clients open, for instance.
|
||||
-- @param dir The direction.
|
||||
-- @param cA The first client.
|
||||
-- @param cB The second client.
|
||||
-- @return The distance between the clients.
|
||||
local function calculate_distance(dir, cA, cB)
|
||||
local gA = cA:geometry()
|
||||
local gB = cB:geometry()
|
||||
|
||||
if dir == "up" then
|
||||
gB.y = gB.y + gB.height
|
||||
elseif dir == "down" then
|
||||
gA.y = gA.y + gA.height
|
||||
elseif dir == "left" then
|
||||
gB.x = gB.x + gB.width
|
||||
elseif dir == "right" then
|
||||
gA.x = gA.x + gA.width
|
||||
end
|
||||
|
||||
return math.sqrt(math.pow(gB.x - gA.x, 2) + math.pow(gB.y - gA.y, 2))
|
||||
end
|
||||
|
||||
-- Get the nearest client in the given direction.
|
||||
-- @param dir The direction, can be either "up", "down", "left" or "right".
|
||||
-- @param c Optional client to get a client relative to. Else focussed is used.
|
||||
local function get_client_in_direction(dir, c)
|
||||
local sel = c or capi.client.focus
|
||||
if sel then
|
||||
local geometry = sel:geometry()
|
||||
local dist, dist_min
|
||||
local target = nil
|
||||
local cls = visible(sel.screen)
|
||||
|
||||
-- We check each client.
|
||||
for i, c in ipairs(cls) do
|
||||
-- Check geometry to see if client is located in the right direction.
|
||||
if is_in_direction(dir, sel, c) then
|
||||
|
||||
-- Calculate distance between focused client and checked client.
|
||||
dist = calculate_distance(dir, sel, c)
|
||||
|
||||
-- If distance is shorter then keep the client.
|
||||
if not target or dist < dist_min then
|
||||
target = c
|
||||
dist_min = dist
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return target
|
||||
end
|
||||
end
|
||||
|
||||
--- Focus a client by the given direction.
|
||||
-- @param dir The direction, can be either "up", "down", "left" or "right".
|
||||
-- @param c Optional client.
|
||||
function focus.bydirection(dir, c)
|
||||
local sel = c or capi.client.focus
|
||||
if sel then
|
||||
local target = get_client_in_direction(dir, sel)
|
||||
|
||||
-- If we found a client to focus, then do it.
|
||||
if target then
|
||||
capi.client.focus = target
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--- Focus a client by its relative index.
|
||||
-- @param i The index.
|
||||
-- @param c Optional client.
|
||||
function focus.byidx(i, c)
|
||||
local target = next(i, c)
|
||||
if target then
|
||||
capi.client.focus = target
|
||||
end
|
||||
end
|
||||
|
||||
--- Swap a client with another client in the given direction
|
||||
-- @param dir The direction, can be either "up", "down", "left" or "right".
|
||||
-- @param c Optional client.
|
||||
function swap.bydirection(dir, c)
|
||||
local sel = c or capi.client.focus
|
||||
if sel then
|
||||
local target = get_client_in_direction(dir, sel)
|
||||
|
||||
-- If we found a client to swap with, then go for it
|
||||
if target then
|
||||
target:swap(sel)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--- Swap a client by its relative index.
|
||||
-- @param i The index.
|
||||
-- @param c Optional client, otherwise focused one is used.
|
||||
function swap.byidx(i, c)
|
||||
local sel = c or capi.client.focus
|
||||
local target = next(i, sel)
|
||||
if target then
|
||||
target:swap(sel)
|
||||
end
|
||||
end
|
||||
|
||||
--- Cycle clients.
|
||||
-- @param clockwise True to cycle clients clockwise.
|
||||
-- @param screen Optional screen where to cycle clients.
|
||||
function cycle(clockwise, screen)
|
||||
local screen = screen or capi.mouse.screen
|
||||
local cls = visible(screen)
|
||||
-- We can't rotate without at least 2 clients, buddy.
|
||||
if #cls >= 2 then
|
||||
local c = table.remove(cls, 1)
|
||||
if clockwise then
|
||||
for i = #cls, 1, -1 do
|
||||
c:swap(cls[i])
|
||||
end
|
||||
else
|
||||
for _, rc in pairs(cls) do
|
||||
c:swap(rc)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--- Get the master window.
|
||||
-- @param screen Optional screen number, otherwise screen mouse is used.
|
||||
-- @return The master window.
|
||||
function getmaster(screen)
|
||||
local s = screen or capi.mouse.screen
|
||||
return visible(s)[1]
|
||||
end
|
||||
|
||||
--- Set the client as slave: put it at the end of other windows.
|
||||
-- @param c The window to set as slave.
|
||||
function setslave(c)
|
||||
local cls = visible(c.screen)
|
||||
for k, v in pairs(cls) do
|
||||
c:swap(v)
|
||||
end
|
||||
end
|
||||
|
||||
--- Move/resize a client relative to current coordinates.
|
||||
-- @param x The relative x coordinate.
|
||||
-- @param y The relative y coordinate.
|
||||
-- @param w The relative width.
|
||||
-- @param h The relative height.
|
||||
-- @param c The optional client, otherwise focused one is used.
|
||||
function moveresize(x, y, w, h, c)
|
||||
local sel = c or capi.client.focus
|
||||
local geometry = sel:geometry()
|
||||
geometry['x'] = geometry['x'] + x
|
||||
geometry['y'] = geometry['y'] + y
|
||||
geometry['width'] = geometry['width'] + w
|
||||
geometry['height'] = geometry['height'] + h
|
||||
sel:geometry(geometry)
|
||||
end
|
||||
|
||||
--- Move a client to a tag.
|
||||
-- @param target The tag to move the client to.
|
||||
-- @param c Optional client to move, otherwise the focused one is used.
|
||||
function movetotag(target, c)
|
||||
local sel = c or capi.client.focus
|
||||
if sel and target.screen then
|
||||
-- Set client on the same screen as the tag.
|
||||
sel.screen = target.screen
|
||||
sel:tags({ target })
|
||||
end
|
||||
end
|
||||
|
||||
--- Toggle a tag on a client.
|
||||
-- @param target The tag to toggle.
|
||||
-- @param c Optional client to toggle, otherwise the focused one is used.
|
||||
function toggletag(target, c)
|
||||
local sel = c or capi.client.focus
|
||||
-- Check that tag and client screen are identical
|
||||
if sel and sel.screen == target.screen then
|
||||
local tags = sel:tags()
|
||||
local index = nil;
|
||||
for i, v in ipairs(tags) do
|
||||
if v == target then
|
||||
index = i
|
||||
break
|
||||
end
|
||||
end
|
||||
if index then
|
||||
-- If it's the only tag for the window, stop.
|
||||
if #tags == 1 then return end
|
||||
tags[index] = nil
|
||||
else
|
||||
tags[#tags + 1] = target
|
||||
end
|
||||
sel:tags(tags)
|
||||
end
|
||||
end
|
||||
|
||||
--- Move a client to a screen. Default is next screen, cycling.
|
||||
-- @param c The client to move.
|
||||
-- @param s The screen number, default to current + 1.
|
||||
function movetoscreen(c, s)
|
||||
local sel = c or capi.client.focus
|
||||
if sel then
|
||||
local sc = capi.screen.count()
|
||||
if not s then
|
||||
s = sel.screen + 1
|
||||
end
|
||||
if s > sc then s = 1 elseif s < 1 then s = sc end
|
||||
sel.screen = s
|
||||
capi.mouse.coords(capi.screen[s].geometry)
|
||||
capi.client.focus = sel
|
||||
end
|
||||
end
|
||||
|
||||
--- Mark a client, and then call 'marked' hook.
|
||||
-- @param c The client to mark, the focused one if not specified.
|
||||
-- @return True if the client has been marked. False if the client was already marked.
|
||||
function mark(c)
|
||||
local cl = c or capi.client.focus
|
||||
if cl then
|
||||
for k, v in pairs(data.marked) do
|
||||
if cl == v then
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
table.insert(data.marked, cl)
|
||||
|
||||
-- Call callback
|
||||
cl:emit_signal("marked")
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
--- Unmark a client and then call 'unmarked' hook.
|
||||
-- @param c The client to unmark, or the focused one if not specified.
|
||||
-- @return True if the client has been unmarked. False if the client was not marked.
|
||||
function unmark(c)
|
||||
local cl = c or capi.client.focus
|
||||
|
||||
for k, v in pairs(data.marked) do
|
||||
if cl == v then
|
||||
table.remove(data.marked, k)
|
||||
cl:emit_signal("unmarked")
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
--- Check if a client is marked.
|
||||
-- @param c The client to check, or the focused one otherwise.
|
||||
function ismarked(c)
|
||||
local cl = c or capi.client.focus
|
||||
if cl then
|
||||
for k, v in pairs(data.marked) do
|
||||
if cl == v then
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
--- Toggle a client as marked.
|
||||
-- @param c The client to toggle mark.
|
||||
function togglemarked(c)
|
||||
local cl = c or capi.client.focus
|
||||
|
||||
if not mark(c) then
|
||||
unmark(c)
|
||||
end
|
||||
end
|
||||
|
||||
--- Return the marked clients and empty the marked table.
|
||||
-- @return A table with all marked clients.
|
||||
function getmarked()
|
||||
for k, v in pairs(data.marked) do
|
||||
v:emit_signal("unmarked")
|
||||
end
|
||||
|
||||
t = data.marked
|
||||
data.marked = {}
|
||||
return t
|
||||
end
|
||||
|
||||
--- Set a client floating state, overriding auto-detection.
|
||||
-- Floating client are not handled by tiling layouts.
|
||||
-- @param c A client.
|
||||
-- @param s True or false.
|
||||
function floating.set(c, s)
|
||||
local c = c or capi.client.focus
|
||||
if c and property.get(c, "floating") ~= s then
|
||||
property.set(c, "floating", s)
|
||||
local screen = c.screen
|
||||
if s == true then
|
||||
c:geometry(property.get(c, "floating_geometry"))
|
||||
end
|
||||
c.screen = screen
|
||||
end
|
||||
end
|
||||
|
||||
local function store_floating_geometry(c)
|
||||
if floating.get(c) then
|
||||
property.set(c, "floating_geometry", c:geometry())
|
||||
end
|
||||
end
|
||||
|
||||
-- Store the initial client geometry.
|
||||
capi.client.add_signal("new", function(c)
|
||||
local function store_init_geometry(c)
|
||||
property.set(c, "floating_geometry", c:geometry())
|
||||
c:remove_signal("property::geometry", store_init_geometry)
|
||||
end
|
||||
c:add_signal("property::geometry", store_init_geometry)
|
||||
end)
|
||||
|
||||
capi.client.add_signal("manage", function(c)
|
||||
c:add_signal("property::geometry", store_floating_geometry)
|
||||
end)
|
||||
|
||||
--- Return if a client has a fixe size or not.
|
||||
-- @param c The client.
|
||||
function isfixed(c)
|
||||
local c = c or capi.client.focus
|
||||
if not c then return end
|
||||
local h = c.size_hints
|
||||
if h.min_width and h.max_width
|
||||
and h.max_height and h.min_height
|
||||
and h.min_width > 0 and h.max_width > 0
|
||||
and h.max_height > 0 and h.min_height > 0
|
||||
and h.min_width == h.max_width
|
||||
and h.min_height == h.max_height then
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
--- Get a client floating state.
|
||||
-- @param c A client.
|
||||
-- @return True or false. Note that some windows might be floating even if you
|
||||
-- did not set them manually. For example, windows with a type different than
|
||||
-- normal.
|
||||
function floating.get(c)
|
||||
local c = c or capi.client.focus
|
||||
if c then
|
||||
local value = property.get(c, "floating")
|
||||
if value ~= nil then
|
||||
return value
|
||||
end
|
||||
if c.type ~= "normal"
|
||||
or c.fullscreen
|
||||
or c.maximized_vertical
|
||||
or c.maximized_horizontal
|
||||
or isfixed(c) then
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
--- Toggle the floating state of a client between 'auto' and 'true'.
|
||||
-- @param c A client.
|
||||
function floating.toggle(c)
|
||||
local c = c or capi.client.focus
|
||||
-- If it has been set to floating
|
||||
if floating.get(c) then
|
||||
floating.set(c, false)
|
||||
else
|
||||
floating.set(c, true)
|
||||
end
|
||||
end
|
||||
|
||||
--- Remove the floating information on a client.
|
||||
-- @param c The client.
|
||||
function floating.delete(c)
|
||||
floating.set(c, nil)
|
||||
end
|
||||
|
||||
--- Restore (=unminimize) a random client.
|
||||
-- @param s The screen to use.
|
||||
-- @return True if some client was restored.
|
||||
function restore(s)
|
||||
local s = s or (capi.client.focus and capi.client.focus.screen) or capi.mouse.screen
|
||||
local cls = capi.client.get(s)
|
||||
local tags = tag.selectedlist(s)
|
||||
local mcls = {}
|
||||
for k, c in pairs(cls) do
|
||||
local ctags = c:tags()
|
||||
if c.minimized then
|
||||
for k, t in ipairs(tags) do
|
||||
if util.table.hasitem(ctags, t) then
|
||||
c.minimized = false
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
-- Normalize a set of numbers to 1
|
||||
-- @param set the set of numbers to normalize
|
||||
-- @param num the number of numbers to normalize
|
||||
local function normalize(set, num)
|
||||
local num = num or #set
|
||||
local total = 0
|
||||
if num then
|
||||
for i = 1,num do
|
||||
total = total + set[i]
|
||||
end
|
||||
for i = 1,num do
|
||||
set[i] = set[i] / total
|
||||
end
|
||||
else
|
||||
for i,v in ipairs(set) do
|
||||
total = total + v
|
||||
end
|
||||
|
||||
for i,v in ipairs(set) do
|
||||
set[i] = v / total
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--- Calculate a client's column number, index in that column, and
|
||||
-- number of visible clients in this column.
|
||||
-- @param c the client
|
||||
-- @return col the column number
|
||||
-- @return idx index of the client in the column
|
||||
-- @return num the number of visible clients in the column
|
||||
function idx(c)
|
||||
local c = c or capi.client.focus
|
||||
if not c then return end
|
||||
|
||||
local clients = tiled(c.screen)
|
||||
local idx = nil
|
||||
for k, cl in ipairs(clients) do
|
||||
if cl == c then
|
||||
idx = k
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
local t = tag.selected(c.screen)
|
||||
local nmaster = tag.getnmaster(t)
|
||||
if idx <= nmaster then
|
||||
return {idx = idx, col=0, num=nmaster}
|
||||
end
|
||||
local nother = #clients - nmaster
|
||||
idx = idx - nmaster
|
||||
|
||||
-- rather than regenerate the column number we can calculate it
|
||||
-- based on the how the tiling algorithm places clients we calculate
|
||||
-- the column, we could easily use the for loop in the program but we can
|
||||
-- calculate it.
|
||||
local ncol = tag.getncol(t)
|
||||
-- minimum number of clients per column
|
||||
local percol = math.floor(nother / ncol)
|
||||
-- number of columns with an extra client
|
||||
local overcol = math.mod(nother, ncol)
|
||||
-- number of columns filled with [percol] clients
|
||||
local regcol = ncol - overcol
|
||||
|
||||
local col = math.floor( (idx - 1) / percol) + 1
|
||||
if col > regcol then
|
||||
-- col = math.floor( (idx - (percol*regcol) - 1) / (percol + 1) ) + regcol + 1
|
||||
-- simplified
|
||||
col = math.floor( (idx + regcol + percol) / (percol+1) )
|
||||
-- calculate the index in the column
|
||||
idx = idx - percol*regcol - (col - regcol - 1) * (percol+1)
|
||||
percol = percol+1
|
||||
else
|
||||
idx = idx - percol*(col-1)
|
||||
end
|
||||
|
||||
return {idx = idx, col=col, num=percol}
|
||||
end
|
||||
|
||||
|
||||
--- Set the window factor of a client
|
||||
-- @param wfact the window factor value
|
||||
-- @param c the client
|
||||
function setwfact(wfact, c)
|
||||
-- get the currently selected window
|
||||
local c = c or capi.client.focus
|
||||
if not c or not c:isvisible() then return end
|
||||
|
||||
local t = tag.selected(c.screen)
|
||||
local w = idx(c)
|
||||
|
||||
local cls = tiled(t.screen)
|
||||
local nmaster = tag.getnmaster(t)
|
||||
|
||||
-- n is the number of windows currently visible for which we have to be concerned with the properties
|
||||
local data = tag.getproperty(t, "windowfact") or {}
|
||||
local colfact = data[w.col]
|
||||
|
||||
colfact[w.idx] = wfact
|
||||
rest = 1-wfact
|
||||
|
||||
-- calculate the current denominator
|
||||
local total = 0
|
||||
for i = 1,w.num do
|
||||
if i ~= w.idx then
|
||||
total = total + colfact[i]
|
||||
end
|
||||
end
|
||||
|
||||
-- normalize the windows
|
||||
for i = 1,w.num do
|
||||
if i ~= w.idx then
|
||||
colfact[i] = (colfact[i] * rest) / total
|
||||
end
|
||||
end
|
||||
|
||||
t:emit_signal("property::windowfact")
|
||||
end
|
||||
|
||||
--- Increment a client's window factor
|
||||
-- @param add amount to increase the client's window
|
||||
-- @param c the client
|
||||
function incwfact(add, c)
|
||||
local c = c or capi.client.focus
|
||||
if not c then return end
|
||||
|
||||
local t = tag.selected(c.screen)
|
||||
|
||||
local w = idx(c)
|
||||
|
||||
local nmaster = tag.getnmaster(t)
|
||||
local data = tag.getproperty(t, "windowfact") or {}
|
||||
local colfact = data[w.col]
|
||||
curr = colfact[w.idx] or 1
|
||||
colfact[w.idx] = curr + add
|
||||
|
||||
-- keep our ratios normalized
|
||||
normalize(colfact, w.num)
|
||||
|
||||
t:emit_signal("property::windowfact")
|
||||
end
|
||||
|
||||
--- Get a client dockable state.
|
||||
-- @param c A client.
|
||||
-- @return True or false. Note that some windows might be dockable even if you
|
||||
-- did not set them manually. For example, windows with a type "utility", "toolbar"
|
||||
-- or "dock"
|
||||
function dockable.get(c)
|
||||
local value = property.get(c, "dockable")
|
||||
|
||||
-- Some sane defaults
|
||||
if value == nil then
|
||||
if (c.type == "utility" or c.type == "toolbar" or c.type == "dock") then
|
||||
value = true
|
||||
else
|
||||
value = false
|
||||
end
|
||||
end
|
||||
|
||||
return value
|
||||
end
|
||||
|
||||
--- Set a client dockable state, overriding auto-detection.
|
||||
-- With this enabled you can dock windows by moving them from the center
|
||||
-- to the edge of the workarea.
|
||||
-- @param c A client.
|
||||
-- @param value True or false.
|
||||
function dockable.set(c, value)
|
||||
property.set(c, "dockable", value)
|
||||
end
|
||||
|
||||
--- Get a client property.
|
||||
-- @param c The client.
|
||||
-- @param prop The property name.
|
||||
-- @return The property.
|
||||
function property.get(c, prop)
|
||||
if data.properties[c] then
|
||||
return data.properties[c][prop]
|
||||
end
|
||||
end
|
||||
|
||||
--- Set a client property.
|
||||
-- This properties are internal to awful. Some are used to move clients, etc.
|
||||
-- @param c The client.
|
||||
-- @param prop The property name.
|
||||
-- @param value The value.
|
||||
function property.set(c, prop, value)
|
||||
if not data.properties[c] then
|
||||
data.properties[c] = {}
|
||||
end
|
||||
data.properties[c][prop] = value
|
||||
c:emit_signal("property::" .. prop)
|
||||
end
|
||||
|
||||
-- Register standards signals
|
||||
capi.client.add_signal("focus", focus.history.add)
|
||||
capi.client.add_signal("unmanage", focus.history.delete)
|
||||
|
||||
capi.client.add_signal("manage", function(c) c:add_signal("property::urgent", urgent.add) end)
|
||||
capi.client.add_signal("focus", urgent.delete)
|
||||
capi.client.add_signal("unmanage", urgent.delete)
|
||||
|
||||
capi.client.add_signal("unmanage", floating.delete)
|
||||
|
||||
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80
|
@ -0,0 +1,191 @@
|
||||
---------------------------------------------------------------------------
|
||||
-- @author Julien Danjou <julien@danjou.info>
|
||||
-- @author Sébastien Gross <seb-awesome@chezwam.org>
|
||||
-- @copyright 2008 Julien Danjou, Sébastien Gross
|
||||
-- @release v3.4.10
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
-- Grab environment we need
|
||||
local io = io
|
||||
local os = os
|
||||
local table = table
|
||||
local math = math
|
||||
local print = print
|
||||
local util = require("awful.util")
|
||||
|
||||
--- Completion module.
|
||||
-- This module store a set of function using shell to complete commands name.
|
||||
module("awful.completion")
|
||||
|
||||
-- mapping of command/completion function
|
||||
local bashcomp_funcs = {}
|
||||
local bashcomp_src = "/etc/bash_completion"
|
||||
|
||||
--- Enable programmable bash completion in awful.completion.bash at the price of
|
||||
-- a slight overhead.
|
||||
-- @param src The bash completion source file, /etc/bash_completion by default.
|
||||
function bashcomp_load(src)
|
||||
if src then bashcomp_src = src end
|
||||
local c, err = io.popen("/usr/bin/env bash -c 'source " .. bashcomp_src .. "; complete -p'")
|
||||
if c then
|
||||
while true do
|
||||
local line = c:read("*line")
|
||||
if not line then break end
|
||||
-- if a bash function is used for completion, register it
|
||||
if line:match(".* -F .*") then
|
||||
bashcomp_funcs[line:gsub(".* (%S+)$","%1")] = line:gsub(".*-F +(%S+) .*$", "%1")
|
||||
end
|
||||
end
|
||||
c:close()
|
||||
else
|
||||
print(err)
|
||||
end
|
||||
end
|
||||
|
||||
local function bash_escape(str)
|
||||
str = str:gsub(" ", "\\ ")
|
||||
str = str:gsub("%[", "\\[")
|
||||
str = str:gsub("%]", "\\]")
|
||||
str = str:gsub("%(", "\\(")
|
||||
str = str:gsub("%)", "\\)")
|
||||
return str
|
||||
end
|
||||
|
||||
--- Use shell completion system to complete command and filename.
|
||||
-- @param command The command line.
|
||||
-- @param cur_pos The cursor position.
|
||||
-- @param ncomp The element number to complete.
|
||||
-- @param shell The shell to use for completion (bash (default) or zsh).
|
||||
-- @return The new command, the new cursor position, the table of all matches.
|
||||
function shell(command, cur_pos, ncomp, shell)
|
||||
local wstart = 1
|
||||
local wend = 1
|
||||
local words = {}
|
||||
local cword_index = 0
|
||||
local cword_start = 0
|
||||
local cword_end = 0
|
||||
local i = 1
|
||||
local comptype = "file"
|
||||
|
||||
-- do nothing if we are on a letter, i.e. not at len + 1 or on a space
|
||||
if cur_pos ~= #command + 1 and command:sub(cur_pos, cur_pos) ~= " " then
|
||||
return command, cur_pos
|
||||
elseif #command == 0 then
|
||||
return command, cur_pos
|
||||
end
|
||||
|
||||
while wend <= #command do
|
||||
wend = command:find(" ", wstart)
|
||||
if not wend then wend = #command + 1 end
|
||||
table.insert(words, command:sub(wstart, wend - 1))
|
||||
if cur_pos >= wstart and cur_pos <= wend + 1 then
|
||||
cword_start = wstart
|
||||
cword_end = wend
|
||||
cword_index = i
|
||||
end
|
||||
wstart = wend + 1
|
||||
i = i + 1
|
||||
end
|
||||
|
||||
if cword_index == 1 then
|
||||
comptype = "command"
|
||||
end
|
||||
|
||||
local shell_cmd
|
||||
if shell == "zsh" or (not shell and os.getenv("SHELL"):match("zsh$")) then
|
||||
if comptype == "file" then
|
||||
shell_cmd = "/usr/bin/env zsh -c 'local -a res; res=( " .. words[cword_index] .. "* ); print -l -- ${res[@]}'"
|
||||
else
|
||||
-- check commands, aliases, builtins, functions and reswords
|
||||
shell_cmd = "/usr/bin/env zsh -c 'local -a res; "..
|
||||
"res=( "..
|
||||
"\"${(k)commands[@]}\" \"${(k)aliases[@]}\" \"${(k)builtins[@]}\" \"${(k)functions[@]}\" \"${(k)reswords[@]}\" "..
|
||||
"); "..
|
||||
"print -l -- ${(M)res[@]:#"..words[cword_index].."*}'"
|
||||
end
|
||||
else
|
||||
if bashcomp_funcs[words[1]] then
|
||||
-- fairly complex command with inline bash script to get the possible completions
|
||||
shell_cmd = "/usr/bin/env bash -c 'source " .. bashcomp_src .. "; " ..
|
||||
"__print_completions() { for ((i=0;i<${#COMPREPLY[*]};i++)); do echo ${COMPREPLY[i]}; done }; " ..
|
||||
"COMP_WORDS=(" .. command .."); COMP_LINE=\"" .. command .. "\"; " ..
|
||||
"COMP_COUNT=" .. cur_pos .. "; COMP_CWORD=" .. cword_index-1 .. "; " ..
|
||||
bashcomp_funcs[words[1]] .. "; __print_completions'"
|
||||
else
|
||||
shell_cmd = "/usr/bin/env bash -c 'compgen -A " .. comptype .. " " .. words[cword_index] .. "'"
|
||||
end
|
||||
end
|
||||
local c, err = io.popen(shell_cmd .. " | sort -u")
|
||||
local output = {}
|
||||
i = 0
|
||||
if c then
|
||||
while true do
|
||||
local line = c:read("*line")
|
||||
if not line then break end
|
||||
if os.execute("test -d " .. line) == 0 then
|
||||
line = line .. "/"
|
||||
end
|
||||
table.insert(output, bash_escape(line))
|
||||
end
|
||||
|
||||
c:close()
|
||||
else
|
||||
print(err)
|
||||
end
|
||||
|
||||
-- no completion, return
|
||||
if #output == 0 then
|
||||
return command, cur_pos
|
||||
end
|
||||
|
||||
-- cycle
|
||||
while ncomp > #output do
|
||||
ncomp = ncomp - #output
|
||||
end
|
||||
|
||||
local str = command:sub(1, cword_start - 1) .. output[ncomp] .. command:sub(cword_end)
|
||||
cur_pos = cword_end + #output[ncomp] + 1
|
||||
|
||||
return str, cur_pos, output
|
||||
end
|
||||
|
||||
--- Run a generic completion.
|
||||
-- For this function to run properly the awful.completion.keyword table should
|
||||
-- be fed up with all keywords. The completion is run against these keywords.
|
||||
-- @param text The current text the user had typed yet.
|
||||
-- @param cur_pos The current cursor position.
|
||||
-- @param ncomp The number of yet requested completion using current text.
|
||||
-- @param keywords The keywords table uised for completion.
|
||||
-- @return The new match, the new cursor position, the table of all matches.
|
||||
function generic(text, cur_pos, ncomp, keywords)
|
||||
-- The keywords table may be empty
|
||||
if #keywords == 0 then
|
||||
return text, #text + 1
|
||||
end
|
||||
|
||||
-- if no text had been typed yet, then we could start cycling around all
|
||||
-- keywords with out filtering and move the cursor at the end of keyword
|
||||
if text == nil or #text == 0 then
|
||||
ncomp = math.mod(ncomp - 1, #keywords) + 1
|
||||
return keywords[ncomp], #keywords[ncomp] + 2
|
||||
end
|
||||
|
||||
-- Filter out only keywords starting with text
|
||||
local matches = {}
|
||||
table.foreach(keywords, function(_, x)
|
||||
if x:sub(1 , #text) == text then
|
||||
table.insert(matches, x)
|
||||
end
|
||||
end)
|
||||
|
||||
-- if there are no matches just leave out with the current text and position
|
||||
if #matches == 0 then
|
||||
return text, #text + 1, matches
|
||||
end
|
||||
|
||||
-- cycle around all matches
|
||||
ncomp = math.mod(ncomp - 1, #matches) + 1
|
||||
return matches[ncomp], #matches[ncomp] + 1, matches
|
||||
end
|
||||
|
||||
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80
|
@ -0,0 +1,19 @@
|
||||
---------------------------------------------------------------------------
|
||||
-- @author Julien Danjou <julien@danjou.info>
|
||||
-- @copyright 2009 Julien Danjou
|
||||
-- @release v3.4.10
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
-- Grab environment we need
|
||||
local dbus = dbus
|
||||
|
||||
--- D-Bus module for awful.
|
||||
-- This module simply request the org.naquadah.awesome.awful name on the D-Bus
|
||||
-- for futur usage by other awful modules.
|
||||
module("awful.dbus")
|
||||
|
||||
if dbus then
|
||||
dbus.request_name("session", "org.naquadah.awesome.awful")
|
||||
end
|
||||
|
||||
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80
|
@ -0,0 +1,160 @@
|
||||
---------------------------------------------------------------------------
|
||||
-- @author Julien Danjou <julien@danjou.info>
|
||||
-- @copyright 2008 Julien Danjou
|
||||
-- @release v3.4.10
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
-- Grab environment we need
|
||||
local pairs = pairs
|
||||
local table = table
|
||||
local ipairs = ipairs
|
||||
local type = type
|
||||
local math = math
|
||||
local capi =
|
||||
{
|
||||
hooks = hooks
|
||||
}
|
||||
local util = require("awful.util")
|
||||
|
||||
--- Hooks module for awful.
|
||||
-- This module is deprecated and should not be used anymore. You are encouraged
|
||||
-- to use signals.
|
||||
module("awful.hooks")
|
||||
|
||||
-- User hook functions
|
||||
user = {}
|
||||
|
||||
--- Create a new userhook (for external libs).
|
||||
-- @param name Hook name.
|
||||
function user.create(name)
|
||||
_M[name] = {}
|
||||
_M[name].callbacks = {}
|
||||
_M[name].register = function (f)
|
||||
table.insert(_M[name].callbacks, f)
|
||||
end
|
||||
_M[name].unregister = function (f)
|
||||
for k, h in ipairs(_M[name].callbacks) do
|
||||
if h == f then
|
||||
table.remove(_M[name].callbacks, k)
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--- Call a created userhook (for external libs).
|
||||
-- @param name Hook name.
|
||||
function user.call(name, ...)
|
||||
for name, callback in pairs(_M[name].callbacks) do
|
||||
callback(...)
|
||||
end
|
||||
end
|
||||
|
||||
-- Autodeclare awful.hooks.* functions
|
||||
-- mapped to awesome hooks.* functions
|
||||
for name, hook in pairs(capi.hooks) do
|
||||
_M[name] = {}
|
||||
if name == 'timer' then
|
||||
_M[name].register = function (time, f, runnow)
|
||||
util.deprecate("timer object")
|
||||
if type(time) ~= 'number' or type(f) ~= 'function' or time <= 0 then
|
||||
return
|
||||
end
|
||||
|
||||
if not _M[name].callbacks then
|
||||
_M[name].callbacks = {}
|
||||
end
|
||||
|
||||
for k, v in pairs(_M[name].callbacks) do
|
||||
if v.callback == f then
|
||||
_M[name].unregister(f)
|
||||
_M[name].register(time, f, runnow)
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
local new_timer
|
||||
if _M[name].timer then
|
||||
-- Take the smallest between current and new
|
||||
new_timer = math.min(time, _M[name].timer)
|
||||
else
|
||||
new_timer = time
|
||||
end
|
||||
|
||||
if _M[name].timer ~= new_timer then
|
||||
_M[name].timer = new_timer
|
||||
end
|
||||
|
||||
hook(_M[name].timer, function (...)
|
||||
for i, callback in ipairs(_M[name].callbacks) do
|
||||
callback['counter'] = callback['counter'] + _M[name].timer
|
||||
if callback['counter'] >= callback['timer'] then
|
||||
callback['callback'](...)
|
||||
callback['counter'] = 0
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
if runnow then
|
||||
table.insert(_M[name].callbacks, { callback = f, timer = time, counter = time })
|
||||
else
|
||||
table.insert(_M[name].callbacks, { callback = f, timer = time, counter = 0 })
|
||||
end
|
||||
end
|
||||
_M[name].unregister = function (f)
|
||||
if _M[name].callbacks then
|
||||
for k, h in ipairs(_M[name].callbacks) do
|
||||
if h.callback == f then
|
||||
table.remove(_M[name].callbacks, k)
|
||||
break
|
||||
end
|
||||
end
|
||||
local delays = { }
|
||||
for k, h in ipairs(_M[name].callbacks) do
|
||||
table.insert(delays, h.timer)
|
||||
end
|
||||
table.sort(delays)
|
||||
_M[name].timer = delays[1]
|
||||
if not delays[1] then delays[1] = 0 end
|
||||
hook(delays[1], function (...)
|
||||
for i, callback in ipairs(_M[name].callbacks) do
|
||||
callback['counter'] = callback['counter'] + _M[name].timer
|
||||
if callback['counter'] >= callback['timer'] then
|
||||
callback['callback'](...)
|
||||
callback['counter'] = 0
|
||||
end
|
||||
end
|
||||
end)
|
||||
end
|
||||
end
|
||||
else
|
||||
_M[name].register = function (f)
|
||||
util.deprecate("signals")
|
||||
if not _M[name].callbacks then
|
||||
_M[name].callbacks = {}
|
||||
hook(function (...)
|
||||
for i, callback in ipairs(_M[name].callbacks) do
|
||||
callback(...)
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
table.insert(_M[name].callbacks, f)
|
||||
end
|
||||
end
|
||||
|
||||
if name ~= "timer" then
|
||||
_M[name].unregister = function (f)
|
||||
if _M[name].callbacks then
|
||||
for k, h in ipairs(_M[name].callbacks) do
|
||||
if h == f then
|
||||
table.remove(_M[name].callbacks, k)
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80
|
@ -0,0 +1,30 @@
|
||||
---------------------------------------------------------------------------
|
||||
-- @author Julien Danjou <julien@danjou.info>
|
||||
-- @copyright 2008 Julien Danjou
|
||||
-- @release v3.4.10
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
require("awful.client")
|
||||
require("awful.completion")
|
||||
require("awful.hooks")
|
||||
require("awful.layout")
|
||||
require("awful.placement")
|
||||
require("awful.prompt")
|
||||
require("awful.screen")
|
||||
require("awful.tag")
|
||||
require("awful.titlebar")
|
||||
require("awful.util")
|
||||
require("awful.widget")
|
||||
require("awful.menu")
|
||||
require("awful.mouse")
|
||||
require("awful.remote")
|
||||
require("awful.key")
|
||||
require("awful.button")
|
||||
require("awful.wibox")
|
||||
require("awful.startup_notification")
|
||||
require("awful.tooltip")
|
||||
|
||||
--- AWesome Functions very UsefuL
|
||||
module("awful")
|
||||
|
||||
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80
|
@ -0,0 +1,78 @@
|
||||
---------------------------------------------------------------------------
|
||||
-- @author Julien Danjou <julien@danjou.info>
|
||||
-- @copyright 2009 Julien Danjou
|
||||
-- @release v3.4.10
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
-- Grab environment we need
|
||||
local setmetatable = setmetatable
|
||||
local ipairs = ipairs
|
||||
local capi = { key = key }
|
||||
local util = require("awful.util")
|
||||
|
||||
--- Create easily new key objects ignoring certain modifiers.
|
||||
module("awful.key")
|
||||
|
||||
--- Modifiers to ignore.
|
||||
-- By default this is initialized as { "Lock", "Mod2" }
|
||||
-- so the Caps Lock or Num Lock modifier are not taking into account by awesome
|
||||
-- when pressing keys.
|
||||
-- @name ignore_modifiers
|
||||
-- @class table
|
||||
ignore_modifiers = { "Lock", "Mod2" }
|
||||
|
||||
--- Create a new key to use as binding.
|
||||
-- This function is useful to create several keys from one, because it will use
|
||||
-- the ignore_modifier variable to create more key with or without the ignored
|
||||
-- modifiers activated.
|
||||
-- For example if you want to ignore CapsLock in your keybinding (which is
|
||||
-- ignored by default by this function), creating key binding with this function
|
||||
-- will return 2 key objects: one with CapsLock on, and the other one with
|
||||
-- CapsLock off.
|
||||
-- @see capi.key
|
||||
-- @return A table with one or several key objects.
|
||||
function new(mod, key, press, release)
|
||||
local ret = {}
|
||||
local subsets = util.subsets(ignore_modifiers)
|
||||
for _, set in ipairs(subsets) do
|
||||
ret[#ret + 1] = capi.key({ modifiers = util.table.join(mod, set),
|
||||
key = key })
|
||||
if press then
|
||||
ret[#ret]:add_signal("press", function(kobj, ...) press(...) end)
|
||||
end
|
||||
if release then
|
||||
ret[#ret]:add_signal("release", function(kobj, ...) release(...) end)
|
||||
end
|
||||
end
|
||||
return ret
|
||||
end
|
||||
|
||||
--- Compare a key object with modifiers and key.
|
||||
-- @param key The key object.
|
||||
-- @param pressed_mod The modifiers to compare with.
|
||||
-- @param pressed_key The key to compare with.
|
||||
function match(key, pressed_mod, pressed_key)
|
||||
-- First, compare key.
|
||||
if pressed_key ~= key.key then return false end
|
||||
-- Then, compare mod
|
||||
local mod = key.modifiers
|
||||
-- For each modifier of the key object, check that the modifier has been
|
||||
-- pressed.
|
||||
for _, m in ipairs(mod) do
|
||||
-- Has it been pressed?
|
||||
if not util.table.hasitem(pressed_mod, m) then
|
||||
-- No, so this is failure!
|
||||
return false
|
||||
end
|
||||
end
|
||||
-- If the number of pressed modifier is ~=, it is probably >, so this is not
|
||||
-- the same, return false.
|
||||
if #pressed_mod ~= #mod then
|
||||
return false
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
setmetatable(_M, { __call = function(_, ...) return new(...) end })
|
||||
|
||||
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80
|
@ -0,0 +1,156 @@
|
||||
---------------------------------------------------------------------------
|
||||
-- @author Julien Danjou <julien@danjou.info>
|
||||
-- @copyright 2008 Julien Danjou
|
||||
-- @release v3.4.10
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
-- Grab environment we need
|
||||
local ipairs = ipairs
|
||||
local type = type
|
||||
local capi = { screen = screen, client = client }
|
||||
local tag = require("awful.tag")
|
||||
local util = require("awful.util")
|
||||
local suit = require("awful.layout.suit")
|
||||
local ascreen = require("awful.screen")
|
||||
local capi = {
|
||||
screen = screen,
|
||||
awesome = awesome,
|
||||
client = client
|
||||
}
|
||||
local client = require("awful.client")
|
||||
|
||||
--- Layout module for awful
|
||||
module("awful.layout")
|
||||
|
||||
-- This is a special lock used by the arrange function.
|
||||
-- This avoids recurring call by emitted signals.
|
||||
local arrange_lock = false
|
||||
|
||||
--- Get the current layout.
|
||||
-- @param screen The screen number.
|
||||
-- @return The layout function.
|
||||
function get(screen)
|
||||
local t = tag.selected(screen)
|
||||
return tag.getproperty(t, "layout") or suit.floating
|
||||
end
|
||||
|
||||
--- Change the layout of the current tag.
|
||||
-- @param layouts A table of layouts.
|
||||
-- @param i Relative index.
|
||||
function inc(layouts, i)
|
||||
local t = tag.selected()
|
||||
if t then
|
||||
local curlayout = get()
|
||||
local curindex
|
||||
local rev_layouts = {}
|
||||
for k, v in ipairs(layouts) do
|
||||
if v == curlayout then
|
||||
curindex = k
|
||||
break
|
||||
end
|
||||
end
|
||||
if curindex then
|
||||
local newindex = util.cycle(#layouts, curindex + i)
|
||||
set(layouts[newindex])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--- Set the layout function of the current tag.
|
||||
-- @param layout Layout name.
|
||||
function set(layout, t)
|
||||
t = t or tag.selected()
|
||||
tag.setproperty(t, "layout", layout)
|
||||
end
|
||||
|
||||
--- Arrange a screen using its current layout.
|
||||
-- @param screen The screen to arrange.
|
||||
function arrange(screen)
|
||||
if arrange_lock then return end
|
||||
arrange_lock = true
|
||||
local p = {}
|
||||
p.workarea = capi.screen[screen].workarea
|
||||
-- Handle padding
|
||||
local padding = ascreen.padding(capi.screen[screen])
|
||||
if padding then
|
||||
p.workarea.x = p.workarea.x + (padding.left or 0)
|
||||
p.workarea.y = p.workarea.y + (padding.top or 0)
|
||||
p.workarea.width = p.workarea.width - ((padding.left or 0 ) + (padding.right or 0))
|
||||
p.workarea.height = p.workarea.height - ((padding.top or 0) + (padding.bottom or 0))
|
||||
end
|
||||
p.geometry = capi.screen[screen].geometry
|
||||
p.clients = client.tiled(screen)
|
||||
p.screen = screen
|
||||
get(screen).arrange(p)
|
||||
capi.screen[screen]:emit_signal("arrange")
|
||||
arrange_lock = false
|
||||
end
|
||||
|
||||
--- Get the current layout name.
|
||||
-- @param layout The layout.
|
||||
-- @return The layout name.
|
||||
function getname(layout)
|
||||
local layout = layout or get()
|
||||
return layout.name
|
||||
end
|
||||
|
||||
local function arrange_prop(obj) arrange(obj.screen) end
|
||||
|
||||
capi.client.add_signal("new", function(c)
|
||||
c:add_signal("property::size_hints_honor", arrange_prop)
|
||||
c:add_signal("property::struts", arrange_prop)
|
||||
c:add_signal("property::minimized", arrange_prop)
|
||||
c:add_signal("property::sticky", arrange_prop)
|
||||
c:add_signal("property::fullscreen", arrange_prop)
|
||||
c:add_signal("property::maximized_horizontal", arrange_prop)
|
||||
c:add_signal("property::maximized_vertical", arrange_prop)
|
||||
c:add_signal("property::border_width", arrange_prop)
|
||||
c:add_signal("property::hidden", arrange_prop)
|
||||
c:add_signal("property::titlebar", arrange_prop)
|
||||
c:add_signal("property::floating", arrange_prop)
|
||||
c:add_signal("property::geometry", arrange_prop)
|
||||
-- If prop is screen, we do not know what was the previous screen, so
|
||||
-- let's arrange all screens :-(
|
||||
c:add_signal("property::screen", function(c)
|
||||
for screen = 1, capi.screen.count() do arrange(screen) end end)
|
||||
end)
|
||||
|
||||
local function arrange_on_tagged(c, tag)
|
||||
if not tag.screen then return end
|
||||
arrange(tag.screen)
|
||||
if not capi.client.focus or not capi.client.focus:isvisible() then
|
||||
local c = client.focus.history.get(tag.screen, 0)
|
||||
if c then capi.client.focus = c end
|
||||
end
|
||||
end
|
||||
|
||||
for s = 1, capi.screen.count() do
|
||||
tag.attached_add_signal(s, "property::mwfact", arrange_prop)
|
||||
tag.attached_add_signal(s, "property::nmaster", arrange_prop)
|
||||
tag.attached_add_signal(s, "property::ncol", arrange_prop)
|
||||
tag.attached_add_signal(s, "property::layout", arrange_prop)
|
||||
tag.attached_add_signal(s, "property::windowfact", arrange_prop)
|
||||
tag.attached_add_signal(s, "property::selected", arrange_prop)
|
||||
tag.attached_add_signal(s, "tagged", arrange_prop)
|
||||
capi.screen[s]:add_signal("property::workarea", function(screen)
|
||||
arrange(screen.index)
|
||||
end)
|
||||
capi.screen[s]:add_signal("tag::attach", function (screen, tag)
|
||||
arrange(screen.index)
|
||||
end)
|
||||
capi.screen[s]:add_signal("tag::detach", function (screen, tag)
|
||||
arrange(screen.index)
|
||||
end)
|
||||
capi.screen[s]:add_signal("padding", function (screen)
|
||||
arrange(screen.index)
|
||||
end)
|
||||
end
|
||||
|
||||
capi.client.add_signal("focus", function(c) arrange(c.screen) end)
|
||||
capi.client.add_signal("list", function()
|
||||
for screen = 1, capi.screen.count() do
|
||||
arrange(screen)
|
||||
end
|
||||
end)
|
||||
|
||||
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80
|
@ -0,0 +1,74 @@
|
||||
---------------------------------------------------------------------------
|
||||
-- @author Julien Danjou <julien@danjou.info>
|
||||
-- @copyright 2008 Julien Danjou
|
||||
-- @release v3.4.10
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
-- Grab environment we need
|
||||
local ipairs = ipairs
|
||||
local math = math
|
||||
|
||||
--- Fair layouts module for awful
|
||||
module("awful.layout.suit.fair")
|
||||
|
||||
local function fair(p, orientation)
|
||||
local wa = p.workarea
|
||||
local cls = p.clients
|
||||
|
||||
if #cls > 0 then
|
||||
local cells = math.ceil(math.sqrt(#cls))
|
||||
local strips = math.ceil(#cls / cells)
|
||||
|
||||
local cell = 0
|
||||
local strip = 0
|
||||
for k, c in ipairs(cls) do
|
||||
local g = {}
|
||||
if ( orientation == "east" and #cls > 2 )
|
||||
or ( orientation == "south" and #cls <= 2 ) then
|
||||
if #cls < (strips * cells) and strip == strips - 1 then
|
||||
g.width = wa.width / (cells - ((strips * cells) - #cls))
|
||||
else
|
||||
g.width = wa.width / cells
|
||||
end
|
||||
g.height = wa.height / strips
|
||||
|
||||
g.x = wa.x + cell * g.width
|
||||
g.y = wa.y + strip * g.height
|
||||
|
||||
else
|
||||
if #cls < (strips * cells) and strip == strips - 1 then
|
||||
g.height = wa.height / (cells - ((strips * cells) - #cls))
|
||||
else
|
||||
g.height = wa.height / cells
|
||||
end
|
||||
g.width = wa.width / strips
|
||||
|
||||
g.x = wa.x + strip * g.width
|
||||
g.y = wa.y + cell * g.height
|
||||
end
|
||||
|
||||
c:geometry(g)
|
||||
|
||||
cell = cell + 1
|
||||
if cell == cells then
|
||||
cell = 0
|
||||
strip = strip + 1
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--- Horizontal fair layout.
|
||||
-- @param screen The screen to arrange.
|
||||
horizontal = {}
|
||||
horizontal.name = "fairh"
|
||||
function horizontal.arrange(p)
|
||||
return fair(p, "east")
|
||||
end
|
||||
|
||||
-- Vertical fair layout.
|
||||
-- @param screen The screen to arrange.
|
||||
name = "fairv"
|
||||
function arrange(p)
|
||||
return fair(p, "south")
|
||||
end
|
@ -0,0 +1,13 @@
|
||||
---------------------------------------------------------------------------
|
||||
-- @author Gregor Best
|
||||
-- @copyright 2008 Gregor Best
|
||||
-- @release v3.4.10
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
--- Dummy function for floating layout
|
||||
module("awful.layout.suit.floating")
|
||||
|
||||
function arrange()
|
||||
end
|
||||
|
||||
name = "floating"
|
@ -0,0 +1,9 @@
|
||||
require("awful.layout.suit.max")
|
||||
require("awful.layout.suit.tile")
|
||||
require("awful.layout.suit.fair")
|
||||
require("awful.layout.suit.floating")
|
||||
require("awful.layout.suit.magnifier")
|
||||
require("awful.layout.suit.spiral")
|
||||
|
||||
--- Suits for awful
|
||||
module("awful.layout.suit")
|
@ -0,0 +1,92 @@
|
||||
---------------------------------------------------------------------------
|
||||
-- @author Julien Danjou <julien@danjou.info>
|
||||
-- @copyright 2008 Julien Danjou
|
||||
-- @release v3.4.10
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
-- Grab environment we need
|
||||
local ipairs = ipairs
|
||||
local math = math
|
||||
local tag = require("awful.tag")
|
||||
local capi =
|
||||
{
|
||||
client = client,
|
||||
screen = screen
|
||||
}
|
||||
local client = require("awful.client")
|
||||
|
||||
--- Magnifier layout module for awful
|
||||
module("awful.layout.suit.magnifier")
|
||||
|
||||
function arrange(p)
|
||||
-- Fullscreen?
|
||||
local area = p.workarea
|
||||
local cls = p.clients
|
||||
local focus = capi.client.focus
|
||||
local mwfact = tag.getmwfact(tag.selected(p.screen))
|
||||
local fidx
|
||||
|
||||
-- Check that the focused window is on the right screen
|
||||
if focus and focus.screen ~= p.screen then focus = nil end
|
||||
|
||||
if not focus and #cls > 0 then
|
||||
focus = cls[1]
|
||||
fidx = 1
|
||||
end
|
||||
|
||||
-- If focused window is not tiled, take the first one which is tiled.
|
||||
if client.floating.get(focus) then
|
||||
focus = cls[1]
|
||||
fidx = 1
|
||||
end
|
||||
|
||||
-- Abort if no clients are present
|
||||
if not focus then return end
|
||||
|
||||
local geometry = {}
|
||||
if #cls > 1 then
|
||||
geometry.width = area.width * math.sqrt(mwfact)
|
||||
geometry.height = area.height * math.sqrt(mwfact)
|
||||
geometry.x = area.x + (area.width - geometry.width) / 2
|
||||
geometry.y = area.y + (area.height - geometry.height) /2
|
||||
else
|
||||
geometry.x = area.x
|
||||
geometry.y = area.y
|
||||
geometry.width = area.width
|
||||
geometry.height = area.height
|
||||
end
|
||||
focus:geometry(geometry)
|
||||
focus:raise()
|
||||
|
||||
if #cls > 1 then
|
||||
geometry.x = area.x
|
||||
geometry.y = area.y
|
||||
geometry.height = area.height / (#cls - 1)
|
||||
geometry.width = area.width
|
||||
|
||||
-- We don't know what the focus window index. Try to find it.
|
||||
if not fidx then
|
||||
for k, c in ipairs(cls) do
|
||||
if c == focus then
|
||||
fidx = k
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- First move clients that are before focused client.
|
||||
for k = fidx + 1, #cls do
|
||||
cls[k]:geometry(geometry)
|
||||
geometry.y = geometry.y + geometry.height
|
||||
end
|
||||
|
||||
-- Then move clients that are after focused client.
|
||||
-- So the next focused window will be the one at the top of the screen.
|
||||
for k = 1, fidx - 1 do
|
||||
cls[k]:geometry(geometry)
|
||||
geometry.y = geometry.y + geometry.height
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
name = "magnifier"
|
@ -0,0 +1,41 @@
|
||||
---------------------------------------------------------------------------
|
||||
-- @author Julien Danjou <julien@danjou.info>
|
||||
-- @copyright 2008 Julien Danjou
|
||||
-- @release v3.4.10
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
-- Grab environment we need
|
||||
local pairs = pairs
|
||||
local client = require("awful.client")
|
||||
|
||||
--- Maximized and fullscreen layouts module for awful
|
||||
module("awful.layout.suit.max")
|
||||
|
||||
local function fmax(p, fs)
|
||||
-- Fullscreen?
|
||||
local area
|
||||
if fs then
|
||||
area = p.geometry
|
||||
else
|
||||
area = p.workarea
|
||||
end
|
||||
|
||||
for k, c in pairs(p.clients) do
|
||||
c:geometry(area)
|
||||
end
|
||||
end
|
||||
|
||||
--- Maximized layout.
|
||||
-- @param screen The screen to arrange.
|
||||
name = "max"
|
||||
function arrange(p)
|
||||
return fmax(p, false)
|
||||
end
|
||||
|
||||
--- Fullscreen layout.
|
||||
-- @param screen The screen to arrange.
|
||||
fullscreen = {}
|
||||
fullscreen.name = "fullscreen"
|
||||
function fullscreen.arrange(p)
|
||||
return fmax(p, true)
|
||||
end
|
@ -0,0 +1,58 @@
|
||||
---------------------------------------------------------------------------
|
||||
-- @author Uli Schlachter <psychon@znc.in>
|
||||
-- @copyright 2009 Uli Schlachter
|
||||
-- @copyright 2008 Julien Danjou
|
||||
-- @release v3.4.10
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
-- Grab environment we need
|
||||
local ipairs = ipairs
|
||||
|
||||
module("awful.layout.suit.spiral")
|
||||
|
||||
local function spiral(p, spiral)
|
||||
local wa = p.workarea
|
||||
local cls = p.clients
|
||||
local n = #cls
|
||||
|
||||
for k, c in ipairs(cls) do
|
||||
if k < n then
|
||||
if k % 2 == 0 then
|
||||
wa.height = wa.height / 2
|
||||
else
|
||||
wa.width = wa.width / 2
|
||||
end
|
||||
end
|
||||
|
||||
if k % 4 == 0 and spiral then
|
||||
wa.x = wa.x - wa.width
|
||||
elseif k % 2 == 0 or
|
||||
(k % 4 == 3 and k < n and spiral) then
|
||||
wa.x = wa.x + wa.width
|
||||
end
|
||||
|
||||
if k % 4 == 1 and k ~= 1 and spiral then
|
||||
wa.y = wa.y - wa.height
|
||||
elseif k % 2 == 1 and k ~= 1 or
|
||||
(k % 4 == 0 and k < n and spiral) then
|
||||
wa.y = wa.y + wa.height
|
||||
end
|
||||
|
||||
c:geometry(wa)
|
||||
end
|
||||
end
|
||||
|
||||
--- Dwindle layout
|
||||
dwindle = {}
|
||||
dwindle.name = "dwindle"
|
||||
function dwindle.arrange(p)
|
||||
return spiral(p, false)
|
||||
end
|
||||
|
||||
--- Spiral layout
|
||||
name = "spiral"
|
||||
function arrange(p)
|
||||
return spiral(p, true)
|
||||
end
|
||||
|
||||
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80
|
@ -0,0 +1,180 @@
|
||||
---------------------------------------------------------------------------
|
||||
-- @author Donald Ephraim Curtis <dcurtis@cs.uiowa.edu>
|
||||
-- @author Julien Danjou <julien@danjou.info>
|
||||
-- @copyright 2009 Donald Ephraim Curtis
|
||||
-- @copyright 2008 Julien Danjou
|
||||
-- @release v3.4.10
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
-- Grab environment we need
|
||||
local ipairs = ipairs
|
||||
local math = math
|
||||
local tag = require("awful.tag")
|
||||
|
||||
--- Tiled layouts module for awful
|
||||
module("awful.layout.suit.tile")
|
||||
|
||||
local function tile_group(cls, wa, orientation, fact, group)
|
||||
-- get our orientation right
|
||||
local height = "height"
|
||||
local width = "width"
|
||||
local x = "x"
|
||||
local y = "y"
|
||||
if orientation == "top" or orientation == "bottom" then
|
||||
height = "width"
|
||||
width = "height"
|
||||
x = "y"
|
||||
y = "x"
|
||||
end
|
||||
|
||||
-- make this more generic (not just width)
|
||||
available = wa[width] - (group.coord - wa[x])
|
||||
|
||||
-- find our total values
|
||||
local total_fact = 0
|
||||
local min_fact = 1
|
||||
local size = group.size
|
||||
for c = group.first,group.last do
|
||||
-- determine the width/height based on the size_hint
|
||||
local i = c - group.first +1
|
||||
local size_hints = cls[c].size_hints
|
||||
local size_hint = size_hints["min_"..width] or size_hints["base_"..width] or 0
|
||||
size_hint = size_hint + cls[c].border_width*2
|
||||
size = math.max(size_hint, size)
|
||||
|
||||
-- calculate the height
|
||||
if not fact[i] then
|
||||
fact[i] = min_fact
|
||||
else
|
||||
min_fact = math.min(fact[i],min_fact)
|
||||
end
|
||||
total_fact = total_fact + fact[i]
|
||||
end
|
||||
size = math.min(size, available)
|
||||
|
||||
local coord = wa[y]
|
||||
local geom = {}
|
||||
local used_size = 0
|
||||
local unused = wa[height]
|
||||
for c = group.first,group.last do
|
||||
local i = c - group.first +1
|
||||
geom[width] = size
|
||||
geom[height] = math.floor(unused * fact[i] / total_fact)
|
||||
geom[x] = group.coord
|
||||
geom[y] = coord
|
||||
geom = cls[c]:geometry(geom)
|
||||
coord = coord + geom[height]
|
||||
unused = unused - geom[height]
|
||||
total_fact = total_fact - fact[i]
|
||||
used_size = math.max(used_size, geom[width])
|
||||
end
|
||||
|
||||
return used_size
|
||||
end
|
||||
|
||||
local function tile(param, orientation)
|
||||
local t = tag.selected(param.screen)
|
||||
orientation = orientation or "right"
|
||||
|
||||
-- this handles are different orientations
|
||||
local height = "height"
|
||||
local width = "width"
|
||||
local x = "x"
|
||||
local y = "y"
|
||||
if orientation == "top" or orientation == "bottom" then
|
||||
height = "width"
|
||||
width = "height"
|
||||
x = "y"
|
||||
y = "x"
|
||||
end
|
||||
|
||||
local cls = param.clients
|
||||
local nmaster = math.min(tag.getnmaster(t), #cls)
|
||||
local nother = math.max(#cls - nmaster,0)
|
||||
|
||||
local mwfact = tag.getmwfact(t)
|
||||
local wa = param.workarea
|
||||
local ncol = tag.getncol(t)
|
||||
|
||||
local data = tag.getdata(t).windowfact
|
||||
|
||||
if not data then
|
||||
data = {}
|
||||
tag.getdata(t).windowfact = data
|
||||
end
|
||||
|
||||
local coord = wa[x]
|
||||
local place_master = true
|
||||
if orientation == "left" or orientation == "top" then
|
||||
-- if we are on the left or top we need to render the other windows first
|
||||
place_master = false
|
||||
end
|
||||
|
||||
-- this was easier than writing functions because there is a lot of data we need
|
||||
for d = 1,2 do
|
||||
if place_master and nmaster > 0 then
|
||||
local size = wa[width]
|
||||
if nother > 0 then
|
||||
size = math.min(wa[width] * mwfact, wa[width] - (coord - wa[x]))
|
||||
end
|
||||
if not data[0] then
|
||||
data[0] = {}
|
||||
end
|
||||
coord = coord + tile_group(cls, wa, orientation, data[0], {first=1, last=nmaster, coord = coord, size = size})
|
||||
end
|
||||
|
||||
if not place_master and nother > 0 then
|
||||
local last = nmaster
|
||||
|
||||
-- we have to modify the work area size to consider left and top views
|
||||
local wasize = wa[width]
|
||||
if nmaster > 0 and (orientation == "left" or orientation == "top") then
|
||||
wasize = wa[width] - wa[width]*mwfact
|
||||
end
|
||||
for i = 1,ncol do
|
||||
-- Try to get equal width among remaining columns
|
||||
local size = math.min( (wasize - (coord - wa[x])) / (ncol - i + 1) )
|
||||
local first = last + 1
|
||||
last = last + math.floor((#cls - last)/(ncol - i + 1))
|
||||
-- tile the column and update our current x coordinate
|
||||
if not data[i] then
|
||||
data[i] = {}
|
||||
end
|
||||
coord = coord + tile_group(cls, wa, orientation, data[i], { first = first, last = last, coord = coord, size = size })
|
||||
end
|
||||
end
|
||||
place_master = not place_master
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
right = {}
|
||||
right.name = "tile"
|
||||
right.arrange = tile
|
||||
|
||||
--- The main tile algo, on left.
|
||||
-- @param screen The screen number to tile.
|
||||
left = {}
|
||||
left.name = "tileleft"
|
||||
function left.arrange(p)
|
||||
return tile(p, "left")
|
||||
end
|
||||
|
||||
--- The main tile algo, on bottom.
|
||||
-- @param screen The screen number to tile.
|
||||
bottom = {}
|
||||
bottom.name = "tilebottom"
|
||||
function bottom.arrange(p)
|
||||
return tile(p, "bottom")
|
||||
end
|
||||
|
||||
--- The main tile algo, on top.
|
||||
-- @param screen The screen number to tile.
|
||||
top = {}
|
||||
top.name = "tiletop"
|
||||
function top.arrange(p)
|
||||
return tile(p, "top")
|
||||
end
|
||||
|
||||
arrange = right.arrange
|
||||
name = right.name
|
455
DUFRESNE/Linux/home/burchettm/.config/awesome/lib/awful/menu.lua
Normal file
455
DUFRESNE/Linux/home/burchettm/.config/awesome/lib/awful/menu.lua
Normal file
@ -0,0 +1,455 @@
|
||||
---------------------------------------------------------------------------
|
||||
-- @author Damien Leone <damien.leone@gmail.com>
|
||||
-- @author Julien Danjou <julien@danjou.info>
|
||||
-- @copyright 2008 Damien Leone, Julien Danjou
|
||||
-- @release v3.4.10
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
-- Grab environment we need
|
||||
local pairs = pairs
|
||||
local table = table
|
||||
local string = string
|
||||
local type = type
|
||||
local setmetatable = setmetatable
|
||||
local wibox = wibox
|
||||
local image = image
|
||||
local widget = widget
|
||||
local button = require("awful.button")
|
||||
local capi =
|
||||
{
|
||||
screen = screen,
|
||||
mouse = mouse,
|
||||
client = client,
|
||||
keygrabber = keygrabber
|
||||
}
|
||||
local util = require("awful.util")
|
||||
local tags = require("awful.tag")
|
||||
local layout = require("awful.widget.layout")
|
||||
local awbeautiful = require("beautiful")
|
||||
local tonumber = tonumber
|
||||
|
||||
--- Creation of menus.
|
||||
module("awful.menu")
|
||||
|
||||
local cur_menu
|
||||
|
||||
--- Key bindings for menu navigation.
|
||||
-- Keys are: up, down, exec, back, close. Value are table with a list of valid
|
||||
-- keys for the action, i.e. menu_keys.up = { "j", "k" } will bind 'j' and 'k'
|
||||
-- key to up action. This is common to all created menu.
|
||||
-- @class table
|
||||
-- @name menu_keys
|
||||
menu_keys = { up = { "Up" },
|
||||
down = { "Down" },
|
||||
exec = { "Return", "Right" },
|
||||
back = { "Left" },
|
||||
close = { "Escape" } }
|
||||
|
||||
local function load_theme(custom)
|
||||
local theme = {}
|
||||
local beautiful
|
||||
|
||||
beautiful = awbeautiful.get()
|
||||
|
||||
theme.fg_focus = custom.fg_focus or beautiful.menu_fg_focus or beautiful.fg_focus
|
||||
theme.bg_focus = custom.bg_focus or beautiful.menu_bg_focus or beautiful.bg_focus
|
||||
theme.fg_normal = custom.fg_normal or beautiful.menu_fg_normal or beautiful.fg_normal
|
||||
theme.bg_normal = custom.bg_normal or beautiful.menu_bg_normal or beautiful.bg_normal
|
||||
|
||||
theme.submenu_icon = custom.submenu_icon or beautiful.menu_submenu_icon
|
||||
|
||||
theme.menu_height = custom.height or beautiful.menu_height or 16
|
||||
theme.menu_width = custom.width or beautiful.menu_width or 100
|
||||
|
||||
theme.border = custom.border_color or beautiful.menu_border_color or beautiful.border_normal
|
||||
theme.border_width = custom.border_width or beautiful.menu_border_width or beautiful.border_width
|
||||
|
||||
return theme
|
||||
end
|
||||
|
||||
local function item_leave(menu, num)
|
||||
if num > 0 then
|
||||
menu.items[num].wibox.fg = menu.theme.fg_normal
|
||||
menu.items[num].wibox.bg = menu.theme.bg_normal
|
||||
end
|
||||
end
|
||||
|
||||
--- Hide a menu popup.
|
||||
-- @param menu The menu to hide.
|
||||
function hide(menu)
|
||||
-- Remove items from screen
|
||||
for i = 1, #menu.items do
|
||||
item_leave(menu, i)
|
||||
menu.items[i].wibox.screen = nil
|
||||
end
|
||||
if menu.active_child then
|
||||
menu.active_child:hide()
|
||||
menu.active_child = nil
|
||||
end
|
||||
menu.sel = nil
|
||||
|
||||
if cur_menu == menu then
|
||||
cur_menu = cur_menu.parent
|
||||
end
|
||||
if not cur_menu and menu.keygrabber then
|
||||
capi.keygrabber.stop()
|
||||
end
|
||||
end
|
||||
|
||||
-- Get the elder parent so for example when you kill
|
||||
-- it, it will destroy the whole family.
|
||||
local function get_parents(menu)
|
||||
if menu.parent then
|
||||
return get_parents(menu.parent)
|
||||
end
|
||||
return menu
|
||||
end
|
||||
|
||||
local function exec(menu, num, mouse_event)
|
||||
local cmd = menu.items[num].cmd
|
||||
if type(cmd) == "table" then
|
||||
if #cmd == 0 then
|
||||
return
|
||||
end
|
||||
if not menu.child[num] then
|
||||
menu.child[num] = new({ items = cmd }, menu, num)
|
||||
end
|
||||
|
||||
if menu.active_child then
|
||||
menu.active_child:hide()
|
||||
menu.active_child = nil
|
||||
end
|
||||
menu.active_child = menu.child[num]
|
||||
menu.active_child:show()
|
||||
elseif type(cmd) == "string" then
|
||||
get_parents(menu):hide()
|
||||
util.spawn(cmd)
|
||||
elseif type(cmd) == "function" then
|
||||
get_parents(menu):hide()
|
||||
cmd(menu.items[num].returned_value)
|
||||
end
|
||||
end
|
||||
|
||||
local function item_enter(menu, num, mouse_event)
|
||||
if menu.sel == num then
|
||||
return
|
||||
elseif menu.sel then
|
||||
item_leave(menu, menu.sel)
|
||||
end
|
||||
|
||||
menu.items[num].wibox.fg = menu.theme.fg_focus
|
||||
menu.items[num].wibox.bg = menu.theme.bg_focus
|
||||
menu.sel = num
|
||||
cur_menu = menu
|
||||
|
||||
if menu.auto_expand and mouse_event then
|
||||
if menu.active_child then
|
||||
menu.active_child:hide()
|
||||
menu.active_child = nil
|
||||
end
|
||||
|
||||
if type(menu.items[num].cmd) == "table" then
|
||||
exec(menu, num)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function check_access_key(menu, key)
|
||||
for i, item in pairs(menu.items) do
|
||||
if item.akey == key then
|
||||
item_enter(menu, i)
|
||||
exec(menu, i)
|
||||
return
|
||||
end
|
||||
end
|
||||
if menu.parent then
|
||||
check_access_key(menu.parent, key)
|
||||
end
|
||||
end
|
||||
|
||||
local function grabber(mod, key, event)
|
||||
if event == "release" then
|
||||
return true
|
||||
end
|
||||
|
||||
local sel = cur_menu.sel or 0
|
||||
if util.table.hasitem(menu_keys.up, key) then
|
||||
local sel_new = sel-1 < 1 and #cur_menu.items or sel-1
|
||||
item_enter(cur_menu, sel_new)
|
||||
elseif util.table.hasitem(menu_keys.down, key) then
|
||||
local sel_new = sel+1 > #cur_menu.items and 1 or sel+1
|
||||
item_enter(cur_menu, sel_new)
|
||||
elseif sel > 0 and util.table.hasitem(menu_keys.exec, key) then
|
||||
exec(cur_menu, sel)
|
||||
elseif util.table.hasitem(menu_keys.back, key) then
|
||||
cur_menu:hide()
|
||||
elseif util.table.hasitem(menu_keys.close, key) then
|
||||
get_parents(cur_menu):hide()
|
||||
else
|
||||
check_access_key(cur_menu, key)
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
local function add_item(data, num, item_info)
|
||||
local item = wibox({
|
||||
fg = data.theme.fg_normal,
|
||||
bg = data.theme.bg_normal,
|
||||
border_color = data.theme.border,
|
||||
border_width = data.theme.border_width
|
||||
})
|
||||
|
||||
-- Create bindings
|
||||
local bindings = util.table.join(
|
||||
button({}, 1, function () item_enter(data, num); exec(data, num) end),
|
||||
button({}, 3, function () data:hide() end)
|
||||
)
|
||||
|
||||
-- Create the item label widget
|
||||
local label = widget({ type = "textbox" })
|
||||
local key = ''
|
||||
label.text = string.gsub(util.escape(item_info[1]), "&(%w)",
|
||||
function (l)
|
||||
key = string.lower(l)
|
||||
return "<u>"..l.."</u>"
|
||||
end, 1)
|
||||
-- Set icon if needed
|
||||
local iconbox
|
||||
if item_info[3] then
|
||||
local icon = type(item_info[3]) == "string" and image(item_info[3]) or item_info[3]
|
||||
if icon.width > data.h or icon.height > data.h then
|
||||
local width, height
|
||||
if ((data.h/icon.height) * icon.width) > data.h then
|
||||
width, height = data.h, (data.h / icon.width) * icon.height
|
||||
else
|
||||
width, height = (data.h / icon.height) * icon.width, data.h
|
||||
end
|
||||
icon = icon:crop_and_scale(0, 0, icon.width, icon.height, width, height)
|
||||
end
|
||||
iconbox = widget { type = "imagebox" }
|
||||
iconbox.image = icon
|
||||
layout.margins[label] = { left = 2 }
|
||||
else
|
||||
layout.margins[label] = { left = data.h + 2 }
|
||||
end
|
||||
|
||||
item:buttons(bindings)
|
||||
|
||||
local mouse_enter_func = function () item_enter(data, num, true) end
|
||||
item:add_signal("mouse::enter", mouse_enter_func)
|
||||
|
||||
-- Create the submenu icon widget
|
||||
local submenu
|
||||
if type(item_info[2]) == "table" then
|
||||
submenu = widget({ type = "imagebox" })
|
||||
submenu.image = data.theme.submenu_icon and image(data.theme.submenu_icon)
|
||||
submenu:buttons(bindings)
|
||||
end
|
||||
|
||||
-- Add widgets to the wibox
|
||||
if iconbox then
|
||||
item.widgets = {
|
||||
iconbox,
|
||||
label,
|
||||
{ submenu, layout = layout.horizontal.rightleft },
|
||||
layout = layout.horizontal.leftright
|
||||
}
|
||||
else
|
||||
item.widgets = {
|
||||
label,
|
||||
{ submenu, layout = layout.horizontal.rightleft },
|
||||
layout = layout.horizontal.leftright
|
||||
}
|
||||
end
|
||||
|
||||
item.height = label:extents().height + 2
|
||||
item.ontop = true
|
||||
|
||||
return { wibox = item, akey= key, cmd = item_info[2], returned_value=item_info[1] }
|
||||
end
|
||||
|
||||
--- Build a popup menu with running clients and shows it.
|
||||
-- @param menu Menu table, see new() function for more informations
|
||||
-- @param args.keygrabber A boolean enabling or not the keyboard navigation.
|
||||
-- @return The menu.
|
||||
function clients(menu, args)
|
||||
local cls = capi.client.get()
|
||||
local cls_t = {}
|
||||
for k, c in pairs(cls) do
|
||||
cls_t[#cls_t + 1] = { util.escape(c.name) or "",
|
||||
function ()
|
||||
if not c:isvisible() then
|
||||
tags.viewmore(c:tags(), c.screen)
|
||||
end
|
||||
capi.client.focus = c
|
||||
c:raise()
|
||||
end,
|
||||
c.icon }
|
||||
end
|
||||
|
||||
if not menu then
|
||||
menu = {}
|
||||
end
|
||||
|
||||
menu.items = cls_t
|
||||
|
||||
local m = new(menu)
|
||||
m:show(args)
|
||||
return m
|
||||
end
|
||||
|
||||
local function set_coords(menu, screen_idx, m_coords)
|
||||
local s_geometry = capi.screen[screen_idx].workarea
|
||||
local screen_w = s_geometry.x + s_geometry.width
|
||||
local screen_h = s_geometry.y + s_geometry.height
|
||||
|
||||
local i_h = menu.h + menu.theme.border_width
|
||||
local m_h = (i_h * #menu.items) + menu.theme.border_width
|
||||
|
||||
if menu.parent then
|
||||
menu.w = menu.parent.w
|
||||
menu.h = menu.parent.h
|
||||
|
||||
local p_w = i_h * (menu.num - 1)
|
||||
local m_w = menu.w - menu.theme.border_width
|
||||
|
||||
menu.y = menu.parent.y + p_w + m_h > screen_h and screen_h - m_h or menu.parent.y + p_w
|
||||
menu.x = menu.parent.x + m_w*2 > screen_w and menu.parent.x - m_w or menu.parent.x + m_w
|
||||
else
|
||||
local m_w = menu.w
|
||||
if m_coords == nil then
|
||||
m_coords = capi.mouse.coords()
|
||||
m_coords.x = m_coords.x + 1
|
||||
m_coords.y = m_coords.y + 1
|
||||
end
|
||||
|
||||
menu.y = m_coords.y < s_geometry.y and s_geometry.y or m_coords.y
|
||||
menu.x = m_coords.x < s_geometry.x and s_geometry.x or m_coords.x
|
||||
|
||||
menu.y = menu.y + m_h > screen_h and screen_h - m_h or menu.y
|
||||
menu.x = menu.x + m_w > screen_w and screen_w - m_w or menu.x
|
||||
end
|
||||
end
|
||||
|
||||
--- Show a menu.
|
||||
-- @param menu The menu to show.
|
||||
-- @param args.keygrabber A boolean enabling or not the keyboard navigation.
|
||||
-- @param args.coords Menu position defaulting to mouse.coords()
|
||||
function show(menu, args)
|
||||
args = args or {}
|
||||
local screen_index = capi.mouse.screen
|
||||
local keygrabber = args.keygrabber or false
|
||||
local coords = args.coords or nil
|
||||
set_coords(menu, screen_index, coords)
|
||||
for num, item in pairs(menu.items) do
|
||||
local wibox = item.wibox
|
||||
wibox.width = menu.w
|
||||
wibox.height = menu.h
|
||||
wibox.x = menu.x
|
||||
wibox.y = menu.y + (num - 1) * (menu.h + wibox.border_width)
|
||||
wibox.screen = screen_index
|
||||
end
|
||||
|
||||
if menu.parent then
|
||||
menu.keygrabber = menu.parent.keygrabber
|
||||
elseif keygrabber ~= nil then
|
||||
menu.keygrabber = keygrabber
|
||||
else
|
||||
menu.keygrabber = false
|
||||
end
|
||||
|
||||
if not cur_menu and menu.keygrabber then
|
||||
capi.keygrabber.run(grabber)
|
||||
end
|
||||
cur_menu = menu
|
||||
end
|
||||
|
||||
--- Toggle menu visibility.
|
||||
-- @param menu The menu to show if it's hidden, or to hide if it's shown.
|
||||
-- @param args.keygrabber A boolean enabling or not the keyboard navigation.
|
||||
-- @param args.coords Menu position {x,y}
|
||||
function toggle(menu, args)
|
||||
if menu.items[1] and menu.items[1].wibox.screen then
|
||||
menu:hide()
|
||||
else
|
||||
menu:show(args)
|
||||
end
|
||||
end
|
||||
|
||||
--- Open a menu popup.
|
||||
-- @param menu Table containing the menu informations.<br/>
|
||||
-- <ul>
|
||||
-- <li> Key items: Table containing the displayed items. Each element is a table containing: item name, triggered action, submenu table or function, item icon (optional). </li>
|
||||
-- <li> Keys [fg|bg]_[focus|normal], border, border_width, submenu_icon, height and width override the default display for your menu, each of them are optional. </li>
|
||||
-- <li> Key auto_expand controls the submenu auto expand behaviour by setting it to true (default) or false. </li>
|
||||
-- </ul>
|
||||
-- @param parent Specify the parent menu if we want to open a submenu, this value should never be set by the user.
|
||||
-- @param num Specify the parent's clicked item number if we want to open a submenu, this value should never be set by the user.
|
||||
-- @usage The following function builds, and shows a menu of clients that match
|
||||
-- a particular rule. Bound to a key, it can for example be used to select from
|
||||
-- dozens of terminals open on several tags. With the use of
|
||||
-- <code>match_any</code> instead of <code>match</code>, menu of clients with
|
||||
-- different classes can also be build.
|
||||
--
|
||||
-- <p><code>
|
||||
-- function terminal_menu () <br/>
|
||||
-- terms = {} <br/>
|
||||
-- for i, c in pairs(client.get()) do <br/>
|
||||
-- if awful.rules.match(c, {class = "URxvt"}) then <br/>
|
||||
-- terms[i] = <br/>
|
||||
-- {c.name, <br/>
|
||||
-- function() <br/>
|
||||
-- awful.tag.viewonly(c:tags()[1]) <br/>
|
||||
-- client.focus = c <br/>
|
||||
-- end, <br/>
|
||||
-- c.icon <br/>
|
||||
-- } <br/>
|
||||
-- end <br/>
|
||||
-- end <br/>
|
||||
-- m = awful.menu({items = terms}) <br/>
|
||||
-- m:show({keygrabber=true}) <br/>
|
||||
-- return m <br/>
|
||||
-- end <br/>
|
||||
--</code></p>
|
||||
function new(menu, parent, num)
|
||||
-- Create a table to store our menu informations
|
||||
local data = {}
|
||||
|
||||
data.items = {}
|
||||
data.num = num or 1
|
||||
data.theme = parent and parent.theme or load_theme(menu)
|
||||
data.parent = parent
|
||||
data.child = {}
|
||||
if parent then
|
||||
data.auto_expand = parent.auto_expand
|
||||
elseif menu.auto_expand ~= nil then
|
||||
data.auto_expand = menu.auto_expand
|
||||
else
|
||||
data.auto_expand = true
|
||||
end
|
||||
data.h = parent and parent.h or data.theme.menu_height
|
||||
if type(data.h) ~= 'number' then data.h = tonumber(data.h) end
|
||||
data.w = parent and parent.w or data.theme.menu_width
|
||||
if type(data.w) ~= 'number' then data.w = tonumber(data.w) end
|
||||
|
||||
-- Create items
|
||||
for k, v in pairs(menu.items) do
|
||||
table.insert(data.items, add_item(data, k, v))
|
||||
end
|
||||
|
||||
if #data.items > 0 and data.h < data.items[1].wibox.height then
|
||||
data.h = data.items[1].wibox.height
|
||||
end
|
||||
|
||||
-- Set methods
|
||||
data.hide = hide
|
||||
data.show = show
|
||||
data.toggle = toggle
|
||||
|
||||
return data
|
||||
end
|
||||
|
||||
setmetatable(_M, { __call = function(_, ...) return new(...) end })
|
||||
|
||||
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80
|
@ -0,0 +1,150 @@
|
||||
-------------------------------------------------------------------------
|
||||
-- @author Sébastien Gross <seb•ɱɩɲʋʃ•awesome•ɑƬ•chezwam•ɖɵʈ•org>
|
||||
-- @copyright 2009 Sébastien Gross
|
||||
-- @release v3.4.10
|
||||
-------------------------------------------------------------------------
|
||||
|
||||
local mouse = mouse
|
||||
local wibox = wibox
|
||||
local screen = screen
|
||||
local timer = timer
|
||||
local a_placement = require("awful.placement")
|
||||
local a_wibox = require("awful.wibox")
|
||||
local beautiful = require("beautiful")
|
||||
local setmetatable = setmetatable
|
||||
|
||||
--- Find the mouse pointer on the screen.
|
||||
-- Mouse finder highlights the mouse cursor on the screen
|
||||
-- <p>To enable this feature, a <code>awful.mouse.finder</code> object needs to
|
||||
-- be bound to a key:<br/>
|
||||
-- <code>mymousefinder = awful.mouse.finder()</code><br/>
|
||||
-- Then bind the <code>find</code> function a key binding.
|
||||
-- <p>Some configuration variable can be set in the theme:<br/>
|
||||
-- The mouse_finder display duration<br/>
|
||||
-- <code>theme.mouse_finder_timeout = 3</code><br/>
|
||||
-- The animation speed<br/>
|
||||
-- <code>theme.mouse_finder_animate_timeout = 0.05</code><br/>
|
||||
-- The mouse_finder radius<br/>
|
||||
-- <code>theme.mouse_finder_radius = 20</code><br/>
|
||||
-- The growth factor<br/>
|
||||
-- <code>theme.mouse_finder_factor = 2</code><br/>
|
||||
-- The mouse_finder color<br/>
|
||||
-- <code>theme.mouse_finder_color = "#ff0000"</code><br/>
|
||||
-- </p>
|
||||
module("awful.mouse.finder")
|
||||
|
||||
-- Mouse finder private data.
|
||||
-- @name data
|
||||
-- @field color Background color.
|
||||
-- @field hide The hide() function.
|
||||
-- @field show The show() function.
|
||||
-- @field timer Timer to hide the mouse finder.
|
||||
-- @field animate_timer Timer to animate the mouse finder.
|
||||
-- @field wibox The mouse finder wibox show on the screen.
|
||||
local data = setmetatable({}, { __mode = 'k' })
|
||||
|
||||
-- Place a mouse finder on the screen.
|
||||
-- @param self A mouse finder object.
|
||||
local function place(self)
|
||||
a_placement.under_mouse(data[self].wibox)
|
||||
a_placement.no_offscreen(data[self].wibox)
|
||||
end
|
||||
|
||||
-- Animate a mouse finder.
|
||||
-- @param self A mouse finder object.
|
||||
local function animate(self)
|
||||
local r = data[self].wibox:geometry().width
|
||||
-- Check if the object should be grown or shrinked
|
||||
-- the minimum radius is -data[self].factor because:
|
||||
-- 1. factor is alway negative when shrinking
|
||||
-- 2. geometry() does not hande negative values
|
||||
if data[self].factor > 0 and r >= data[self].radius
|
||||
or data[self].factor < 0 and r <= -data[self].factor then
|
||||
data[self].factor = -data[self].factor
|
||||
end
|
||||
data[self].wibox:geometry({width = r + data[self].factor,
|
||||
height = r + data[self].factor })
|
||||
-- need -1 to the radius to draw a full circle
|
||||
a_wibox.rounded_corners(data[self].wibox, (r + data[self].factor)/2 -1)
|
||||
-- make sure the mouse finder follows the pointer. Uh!
|
||||
place(self)
|
||||
end
|
||||
|
||||
|
||||
-- Show a mouse finder.
|
||||
-- @param self The mouse finder to show.
|
||||
local function show(self)
|
||||
-- do nothing if the mouse finder is already shown
|
||||
if data[self].wibox.visible then return end
|
||||
if not data[self].timer.started then
|
||||
-- make sure the mouse finder is on the same screen as the mouse
|
||||
data[self].wibox.screen = mouse.screen
|
||||
data[self].wibox:geometry({width = data[self].radius, height = data[self].radius })
|
||||
a_wibox.rounded_corners(data[self].wibox, data[self].radius/2 -1)
|
||||
data[self].timer:start()
|
||||
data[self].animate_timer:start()
|
||||
end
|
||||
place(self)
|
||||
data[self].wibox.visible = true
|
||||
end
|
||||
|
||||
-- Hide a mouse finder.
|
||||
-- @param self The mouse finder to hide.
|
||||
local function hide(self)
|
||||
-- do nothing if the mouse finder is already hidden
|
||||
if not data[self].wibox.visible then return end
|
||||
if data[self].timer.started then
|
||||
data[self].timer:stop()
|
||||
data[self].animate_timer:stop()
|
||||
end
|
||||
data[self].wibox.visible = false
|
||||
end
|
||||
|
||||
-- Load Default values.
|
||||
-- @param self A mouse finder object.
|
||||
local function set_defaults(self)
|
||||
data[self].wibox.border_width = 0
|
||||
data[self].wibox.opacity = beautiful.mouse_finder_opacity or 1
|
||||
data[self].wibox.bg = beautiful.mouse_finder_color or beautiful.bg_focus or "#ff0000"
|
||||
data[self].timeout = beautiful.mouse_finder_timeout or 3
|
||||
data[self].animate_timeout = beautiful.mouse_finder_animate_timeout or 0.05
|
||||
data[self].radius = beautiful.mouse_finder_radius or 20
|
||||
data[self].factor = beautiful.mouse_finder_factor or 2
|
||||
end
|
||||
|
||||
--- Find the mouse on the screen
|
||||
-- @param self A mouse finder object.
|
||||
function find(self)
|
||||
show(self)
|
||||
end
|
||||
|
||||
--- Create a new mouse finder.
|
||||
local function new()
|
||||
local self = { }
|
||||
-- private data
|
||||
data[self] = {
|
||||
wibox = wibox({ }),
|
||||
show = function() show(self) end,
|
||||
hide = function() hide(self) end,
|
||||
animate = function() animate(self) end,
|
||||
}
|
||||
|
||||
-- export functions
|
||||
self.find = find
|
||||
|
||||
set_defaults(self)
|
||||
|
||||
-- setup the timer action only if needed
|
||||
data[self].timer = timer { timeout = data[self].timeout }
|
||||
data[self].animate_timer = timer { timeout = data[self].animate_timeout }
|
||||
data[self].timer:add_signal("timeout", data[self].hide)
|
||||
data[self].animate_timer:add_signal("timeout", data[self].animate)
|
||||
data[self].wibox.ontop = true
|
||||
data[self].wibox.visible = false
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
setmetatable(_M, { __call = function(_, ...) return new(...) end })
|
||||
|
||||
-- vim: ft=lua:et:sw=4:ts=4:sts=4:enc=utf-8:tw=78
|
@ -0,0 +1,591 @@
|
||||
---------------------------------------------------------------------------
|
||||
-- @author Julien Danjou <julien@danjou.info>
|
||||
-- @copyright 2008 Julien Danjou
|
||||
-- @release v3.4.10
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
-- Grab environment we need
|
||||
local layout = require("awful.layout")
|
||||
local tag = require("awful.tag")
|
||||
local aclient = require("awful.client")
|
||||
local widget = require("awful.widget")
|
||||
local awibox = require("awful.wibox")
|
||||
local util = require("awful.util")
|
||||
local type = type
|
||||
local math = math
|
||||
local ipairs = ipairs
|
||||
local capi =
|
||||
{
|
||||
root = root,
|
||||
mouse = mouse,
|
||||
screen = screen,
|
||||
client = client,
|
||||
mousegrabber = mousegrabber,
|
||||
}
|
||||
|
||||
require("awful.mouse.finder")
|
||||
|
||||
--- Mouse module for awful
|
||||
module("awful.mouse")
|
||||
|
||||
client = {}
|
||||
wibox = {}
|
||||
|
||||
--- Get the client object under the pointer.
|
||||
-- @return The client object under the pointer, if one can be found.
|
||||
function client_under_pointer()
|
||||
local obj = capi.mouse.object_under_pointer()
|
||||
if type(obj) == "client" then
|
||||
return obj
|
||||
end
|
||||
end
|
||||
|
||||
--- Get the wibox object under the pointer.
|
||||
-- @return The wibox object under the pointer, if one can be found.
|
||||
function wibox_under_pointer()
|
||||
local obj = capi.mouse.object_under_pointer()
|
||||
if type(obj) == "wibox" then
|
||||
return obj
|
||||
end
|
||||
end
|
||||
|
||||
--- Get the widget under the pointer.
|
||||
-- @return The widget object under the pointer, if it can be found.
|
||||
function widget_under_pointer()
|
||||
local obj, obj2 = capi.mouse.object_under_pointer()
|
||||
if type(obj2) == "widget" then
|
||||
return obj2
|
||||
end
|
||||
end
|
||||
|
||||
local function snap_outside(g, sg, snap)
|
||||
if g.x < snap + sg.x + sg.width and g.x > sg.x + sg.width then
|
||||
g.x = sg.x + sg.width
|
||||
elseif g.x + g.width < sg.x and g.x + g.width > sg.x - snap then
|
||||
g.x = sg.x - g.width
|
||||
end
|
||||
if g.y < snap + sg.y + sg.height and g.y > sg.y + sg.height then
|
||||
g.y = sg.y + sg.height
|
||||
elseif g.y + g.height < sg.y and g.y + g.height > sg.y - snap then
|
||||
g.y = sg.y - g.height
|
||||
end
|
||||
return g
|
||||
end
|
||||
|
||||
local function snap_inside(g, sg, snap)
|
||||
local edgev = 'none'
|
||||
local edgeh = 'none'
|
||||
if math.abs(g.x) < snap + sg.x and g.x > sg.x then
|
||||
edgev = 'left'
|
||||
g.x = sg.x
|
||||
elseif math.abs((sg.x + sg.width) - (g.x + g.width)) < snap then
|
||||
edgev = 'right'
|
||||
g.x = sg.x + sg.width - g.width
|
||||
end
|
||||
if math.abs(g.y) < snap + sg.y and g.y > sg.y then
|
||||
edgeh = 'top'
|
||||
g.y = sg.y
|
||||
elseif math.abs((sg.y + sg.height) - (g.y + g.height)) < snap then
|
||||
edgeh = 'bottom'
|
||||
g.y = sg.y + sg.height - g.height
|
||||
end
|
||||
|
||||
-- What is the dominant dimension?
|
||||
if g.width > g.height then
|
||||
return g, edgeh
|
||||
else
|
||||
return g, edgev
|
||||
end
|
||||
end
|
||||
|
||||
--- Snap a client to the closest client or screen edge.
|
||||
-- @param c The client to snap.
|
||||
-- @param snap The pixel to snap clients.
|
||||
-- @param x The client x coordinate.
|
||||
-- @param y The client y coordinate.
|
||||
-- @param fixed_x True if the client isn't allowed to move in the x direction.
|
||||
-- @param fixed_y True if the client isn't allowed to move in the y direction.
|
||||
function client.snap(c, snap, x, y, fixed_x, fixed_y)
|
||||
local snap = snap or 8
|
||||
local c = c or client.focus
|
||||
local cur_geom = c:geometry()
|
||||
local geom = c:geometry()
|
||||
geom.width = geom.width + (2 * c.border_width)
|
||||
geom.height = geom.height + (2 * c.border_width)
|
||||
local edge = "none"
|
||||
local edge2 = "none"
|
||||
geom.x = x or geom.x
|
||||
geom.y = y or geom.y
|
||||
|
||||
geom, edge = snap_inside(geom, capi.screen[c.screen].geometry, snap)
|
||||
geom = snap_inside(geom, capi.screen[c.screen].workarea, snap)
|
||||
|
||||
-- Allow certain windows to snap to the edge of the workarea.
|
||||
-- Only allow docking to workarea for consistency/to avoid problems.
|
||||
if aclient.dockable.get(c) then
|
||||
local struts = c:struts()
|
||||
struts['left'] = 0
|
||||
struts['right'] = 0
|
||||
struts['top'] = 0
|
||||
struts['bottom'] = 0
|
||||
if edge ~= "none" and aclient.floating.get(c) then
|
||||
if edge == "left" or edge == "right" then
|
||||
struts[edge] = cur_geom.width
|
||||
elseif edge == "top" or edge == "bottom" then
|
||||
struts[edge] = cur_geom.height
|
||||
end
|
||||
end
|
||||
c:struts(struts)
|
||||
end
|
||||
|
||||
geom.x = geom.x - (2 * c.border_width)
|
||||
geom.y = geom.y - (2 * c.border_width)
|
||||
|
||||
for k, snapper in ipairs(aclient.visible(c.screen)) do
|
||||
if snapper ~= c then
|
||||
geom = snap_outside(geom, snapper:geometry(), snap)
|
||||
end
|
||||
end
|
||||
|
||||
-- It's easiest to undo changes afterwards if they're not allowed
|
||||
if fixed_x then geom.x = cur_geom.x end
|
||||
if fixed_y then geom.y = cur_geom.y end
|
||||
|
||||
geom.width = geom.width - (2 * c.border_width)
|
||||
geom.height = geom.height - (2 * c.border_width)
|
||||
geom.x = geom.x + (2 * c.border_width)
|
||||
geom.y = geom.y + (2 * c.border_width)
|
||||
|
||||
return geom
|
||||
end
|
||||
|
||||
--- Move a client.
|
||||
-- @param c The client to move, or the focused one if nil.
|
||||
-- @param snap The pixel to snap clients.
|
||||
function client.move(c, snap)
|
||||
local c = c or capi.client.focus
|
||||
|
||||
if not c
|
||||
or c.fullscreen
|
||||
or c.type == "desktop"
|
||||
or c.type == "splash"
|
||||
or c.type == "dock" then
|
||||
return
|
||||
end
|
||||
|
||||
c:raise()
|
||||
|
||||
local orig = c:geometry()
|
||||
local m_c = capi.mouse.coords()
|
||||
local dist_x = m_c.x - orig.x
|
||||
local dist_y = m_c.y - orig.y
|
||||
-- Only allow moving in the non-maximized directions
|
||||
local fixed_x = c.maximized_horizontal
|
||||
local fixed_y = c.maximized_vertical
|
||||
|
||||
capi.mousegrabber.run(function (mouse)
|
||||
for k, v in ipairs(mouse.buttons) do
|
||||
if v then
|
||||
local lay = layout.get(c.screen)
|
||||
if lay == layout.suit.floating or aclient.floating.get(c) then
|
||||
local x = mouse.x - dist_x
|
||||
local y = mouse.y - dist_y
|
||||
c:geometry(client.snap(c, snap, x, y, fixed_x, fixed_y))
|
||||
elseif lay ~= layout.suit.magnifier then
|
||||
-- Only move the client to the mouse
|
||||
-- screen if the target screen is not
|
||||
-- floating.
|
||||
-- Otherwise, we move if via geometry.
|
||||
if layout.get(capi.mouse.screen) == layout.suit.floating then
|
||||
local x = mouse.x - dist_x
|
||||
local y = mouse.y - dist_y
|
||||
c:geometry(client.snap(c, snap, x, y, fixed_x, fixed_y))
|
||||
else
|
||||
c.screen = capi.mouse.screen
|
||||
end
|
||||
if layout.get(c.screen) ~= layout.suit.floating then
|
||||
local c_u_m = client_under_pointer()
|
||||
if c_u_m and not aclient.floating.get(c_u_m) then
|
||||
if c_u_m ~= c then
|
||||
c:swap(c_u_m)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
end, "fleur")
|
||||
end
|
||||
|
||||
client.dragtotag = { }
|
||||
|
||||
--- Move a client to a tag by drag'n'dropping it over a taglist widget
|
||||
-- @param c The client to move
|
||||
function client.dragtotag.widget(c)
|
||||
capi.mousegrabber.run(function (mouse)
|
||||
local button_down = false
|
||||
for _, v in ipairs(mouse.buttons) do
|
||||
if v then button_down = true end
|
||||
end
|
||||
if not button_down then
|
||||
local w = widget_under_pointer()
|
||||
if w and widget.taglist.gettag(w) then
|
||||
local t = widget.taglist.gettag(w)
|
||||
if t.screen ~= c.screen then
|
||||
aclient.movetoscreen(c, t.screen)
|
||||
end
|
||||
aclient.movetotag(t, c)
|
||||
end
|
||||
return false
|
||||
end
|
||||
return true
|
||||
end, "fleur")
|
||||
end
|
||||
|
||||
--- Move a client to a tag by dragging it onto the left / right side of the screen
|
||||
-- @param c The client to move
|
||||
function client.dragtotag.border(c)
|
||||
capi.mousegrabber.run(function (mouse)
|
||||
local button_down = false
|
||||
for _, v in ipairs(mouse.buttons) do
|
||||
if v then button_down = true end
|
||||
end
|
||||
local wa = capi.screen[c.screen].workarea
|
||||
if mouse.x >= wa.x + wa.width then
|
||||
capi.mouse.coords({ x = wa.x + wa.width - 1 })
|
||||
elseif mouse.x <= wa.x then
|
||||
capi.mouse.coords({ x = wa.x + 1 })
|
||||
end
|
||||
if not button_down then
|
||||
local tags = capi.screen[c.screen]:tags()
|
||||
local t = tag.selected()
|
||||
local idx
|
||||
for i, v in ipairs(tags) do
|
||||
if v == t then
|
||||
idx = i
|
||||
end
|
||||
end
|
||||
if mouse.x > wa.x + wa.width - 10 then
|
||||
local newtag = tags[util.cycle(#tags, idx + 1)]
|
||||
aclient.movetotag(newtag, c)
|
||||
tag.viewnext()
|
||||
elseif mouse.x < wa.x + 10 then
|
||||
local newtag = tags[util.cycle(#tags, idx - 1)]
|
||||
aclient.movetotag(newtag, c)
|
||||
tag.viewprev()
|
||||
end
|
||||
return false
|
||||
end
|
||||
return true
|
||||
end, "fleur")
|
||||
end
|
||||
|
||||
--- Move the wibox under the cursor
|
||||
--@param w The wibox to move, or none to use that under the pointer
|
||||
function wibox.move(w)
|
||||
local w = w or wibox_under_pointer()
|
||||
if not w then return end
|
||||
|
||||
local offset = {
|
||||
x = w.x - capi.mouse.coords().x,
|
||||
y = w.y - capi.mouse.coords().y
|
||||
}
|
||||
|
||||
capi.mousegrabber.run(function (mouse)
|
||||
local button_down = false
|
||||
if awibox.get_position(w) == "floating" then
|
||||
w.x = capi.mouse.coords().x + offset.x
|
||||
w.y = capi.mouse.coords().y + offset.y
|
||||
else
|
||||
local wa = capi.screen[capi.mouse.screen].workarea
|
||||
|
||||
if capi.mouse.coords()["y"] > wa.y + wa.height - 10 then
|
||||
awibox.set_position(w, "bottom", w.screen)
|
||||
elseif capi.mouse.coords()["y"] < wa.y + 10 then
|
||||
awibox.set_position(w, "top", w.screen)
|
||||
elseif capi.mouse.coords()["x"] > wa.x + wa.width - 10 then
|
||||
awibox.set_position(w, "right", w.screen)
|
||||
elseif capi.mouse.coords()["x"] < wa.x + 10 then
|
||||
awibox.set_position(w, "left", w.screen)
|
||||
end
|
||||
w.screen = capi.mouse.screen
|
||||
end
|
||||
for k, v in ipairs(mouse.buttons) do
|
||||
if v then button_down = true end
|
||||
end
|
||||
if not button_down then
|
||||
return false
|
||||
end
|
||||
return true
|
||||
end, "fleur")
|
||||
end
|
||||
|
||||
--- Get a client corner coordinates.
|
||||
-- @param c The client to get corner from, focused one by default.
|
||||
-- @param corner The corner to use: auto, top_left, top_right, bottom_left,
|
||||
-- bottom_right. Default is auto, and auto find the nearest corner.
|
||||
-- @return Actual used corner and x and y coordinates.
|
||||
function client.corner(c, corner)
|
||||
local c = c or capi.client.focus
|
||||
if not c then return end
|
||||
|
||||
local g = c:geometry()
|
||||
|
||||
if not corner or corner == "auto" then
|
||||
local m_c = capi.mouse.coords()
|
||||
if math.abs(g.y - m_c.y) < math.abs(g.y + g.height - m_c.y) then
|
||||
if math.abs(g.x - m_c.x) < math.abs(g.x + g.width - m_c.x) then
|
||||
corner = "top_left"
|
||||
else
|
||||
corner = "top_right"
|
||||
end
|
||||
else
|
||||
if math.abs(g.x - m_c.x) < math.abs(g.x + g.width - m_c.x) then
|
||||
corner = "bottom_left"
|
||||
else
|
||||
corner = "bottom_right"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local x, y
|
||||
if corner == "top_right" then
|
||||
x = g.x + g.width
|
||||
y = g.y
|
||||
elseif corner == "top_left" then
|
||||
x = g.x
|
||||
y = g.y
|
||||
elseif corner == "bottom_left" then
|
||||
x = g.x
|
||||
y = g.y + g.height
|
||||
else
|
||||
x = g.x + g.width
|
||||
y = g.y + g.height
|
||||
end
|
||||
|
||||
return corner, x, y
|
||||
end
|
||||
|
||||
local function client_resize_magnifier(c, corner)
|
||||
local corner, x, y = client.corner(c, corner)
|
||||
capi.mouse.coords({ x = x, y = y })
|
||||
|
||||
local wa = capi.screen[c.screen].workarea
|
||||
local center_x = wa.x + wa.width / 2
|
||||
local center_y = wa.y + wa.height / 2
|
||||
local maxdist_pow = (wa.width^2 + wa.height^2) / 4
|
||||
|
||||
capi.mousegrabber.run(function (mouse)
|
||||
for k, v in ipairs(mouse.buttons) do
|
||||
if v then
|
||||
local dx = center_x - mouse.x
|
||||
local dy = center_y - mouse.y
|
||||
local dist = dx^2 + dy^2
|
||||
|
||||
-- New master width factor
|
||||
local mwfact = dist / maxdist_pow
|
||||
tag.setmwfact(math.min(math.max(0.01, mwfact), 0.99), tag.selected(c.screen))
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
end, corner .. "_corner")
|
||||
end
|
||||
|
||||
local function client_resize_tiled(c, lay)
|
||||
local wa = capi.screen[c.screen].workarea
|
||||
local mwfact = tag.getmwfact()
|
||||
local cursor
|
||||
local g = c:geometry()
|
||||
local offset = 0
|
||||
local x,y
|
||||
if lay == layout.suit.tile then
|
||||
cursor = "cross"
|
||||
if g.height+15 > wa.height then
|
||||
offset = g.height * .5
|
||||
cursor = "sb_h_double_arrow"
|
||||
elseif not (g.y+g.height+15 > wa.y+wa.height) then
|
||||
offset = g.height
|
||||
end
|
||||
capi.mouse.coords({ x = wa.x + wa.width * mwfact, y = g.y + offset })
|
||||
elseif lay == layout.suit.tile.left then
|
||||
cursor = "cross"
|
||||
if g.height+15 >= wa.height then
|
||||
offset = g.height * .5
|
||||
cursor = "sb_h_double_arrow"
|
||||
elseif not (g.y+g.height+15 > wa.y+wa.height) then
|
||||
offset = g.height
|
||||
end
|
||||
capi.mouse.coords({ x = wa.x + wa.width * (1 - mwfact), y = g.y + offset })
|
||||
elseif lay == layout.suit.tile.bottom then
|
||||
cursor = "cross"
|
||||
if g.width+15 >= wa.width then
|
||||
offset = g.width * .5
|
||||
cursor = "sb_v_double_arrow"
|
||||
elseif not (g.x+g.width+15 > wa.x+wa.width) then
|
||||
offset = g.width
|
||||
end
|
||||
capi.mouse.coords({ y = wa.y + wa.height * mwfact, x = g.x + offset})
|
||||
else
|
||||
cursor = "cross"
|
||||
if g.width+15 >= wa.width then
|
||||
offset = g.width * .5
|
||||
cursor = "sb_v_double_arrow"
|
||||
elseif not (g.x+g.width+15 > wa.x+wa.width) then
|
||||
offset = g.width
|
||||
end
|
||||
capi.mouse.coords({ y = wa.y + wa.height * (1 - mwfact), x= g.x + offset })
|
||||
end
|
||||
|
||||
capi.mousegrabber.run(function (mouse)
|
||||
for k, v in ipairs(mouse.buttons) do
|
||||
if v then
|
||||
local fact_x = (mouse.x - wa.x) / wa.width
|
||||
local fact_y = (mouse.y - wa.y) / wa.height
|
||||
local mwfact
|
||||
|
||||
local g = c:geometry()
|
||||
|
||||
|
||||
-- we have to make sure we're not on the last visible client where we have to use different settings.
|
||||
local wfact
|
||||
local wfact_x, wfact_y
|
||||
if (g.y+g.height+15) > (wa.y+wa.height) then
|
||||
wfact_y = (g.y + g.height - mouse.y) / wa.height
|
||||
else
|
||||
wfact_y = (mouse.y - g.y) / wa.height
|
||||
end
|
||||
|
||||
if (g.x+g.width+15) > (wa.x+wa.width) then
|
||||
wfact_x = (g.x + g.width - mouse.x) / wa.width
|
||||
else
|
||||
wfact_x = (mouse.x - g.x) / wa.width
|
||||
end
|
||||
|
||||
|
||||
if lay == layout.suit.tile then
|
||||
mwfact = fact_x
|
||||
wfact = wfact_y
|
||||
elseif lay == layout.suit.tile.left then
|
||||
mwfact = 1 - fact_x
|
||||
wfact = wfact_y
|
||||
elseif lay == layout.suit.tile.bottom then
|
||||
mwfact = fact_y
|
||||
wfact = wfact_x
|
||||
else
|
||||
mwfact = 1 - fact_y
|
||||
wfact = wfact_x
|
||||
end
|
||||
|
||||
tag.setmwfact(math.min(math.max(mwfact, 0.01), 0.99), tag.selected(c.screen))
|
||||
aclient.setwfact(math.min(math.max(wfact,0.01), 0.99), c)
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
end, cursor)
|
||||
end
|
||||
|
||||
local function client_resize_floating(c, corner, fixed_x, fixed_y)
|
||||
local corner, x, y = client.corner(c, corner)
|
||||
local g = c:geometry()
|
||||
|
||||
-- Warp mouse pointer
|
||||
capi.mouse.coords({ x = x, y = y })
|
||||
|
||||
capi.mousegrabber.run(function (mouse)
|
||||
for k, v in ipairs(mouse.buttons) do
|
||||
if v then
|
||||
-- Ignore screen changes
|
||||
if not aclient.floating.get(c)
|
||||
and capi.mouse.screen ~= c.screen then
|
||||
return true
|
||||
end
|
||||
|
||||
local ng
|
||||
if corner == "bottom_right" then
|
||||
ng = { width = mouse.x - g.x,
|
||||
height = mouse.y - g.y }
|
||||
elseif corner == "bottom_left" then
|
||||
ng = { x = mouse.x,
|
||||
width = (g.x + g.width) - mouse.x,
|
||||
height = mouse.y - g.y }
|
||||
elseif corner == "top_left" then
|
||||
ng = { x = mouse.x,
|
||||
width = (g.x + g.width) - mouse.x,
|
||||
y = mouse.y,
|
||||
height = (g.y + g.height) - mouse.y }
|
||||
else
|
||||
ng = { width = mouse.x - g.x,
|
||||
y = mouse.y,
|
||||
height = (g.y + g.height) - mouse.y }
|
||||
end
|
||||
if ng.width <= 0 then ng.width = nil end
|
||||
if ng.height <= 0 then ng.height = nil end
|
||||
if fixed_x then ng.width = g.width ng.x = g.x end
|
||||
if fixed_y then ng.height = g.height ng.y = g.y end
|
||||
c:geometry(ng)
|
||||
-- Get real geometry that has been applied
|
||||
-- in case we honor size hints
|
||||
-- XXX: This should be rewritten when size
|
||||
-- hints are available from Lua.
|
||||
local rg = c:geometry()
|
||||
|
||||
if corner == "bottom_right" then
|
||||
ng = {}
|
||||
elseif corner == "bottom_left" then
|
||||
ng = { x = (g.x + g.width) - rg.width }
|
||||
elseif corner == "top_left" then
|
||||
ng = { x = (g.x + g.width) - rg.width,
|
||||
y = (g.y + g.height) - rg.height }
|
||||
else
|
||||
ng = { y = (g.y + g.height) - rg.height }
|
||||
end
|
||||
c:geometry({ x = ng.x, y = ng.y })
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
end, corner .. "_corner")
|
||||
end
|
||||
|
||||
--- Resize a client.
|
||||
-- @param c The client to resize, or the focused one by default.
|
||||
-- @param corner The corner to grab on resize. Auto detected by default.
|
||||
function client.resize(c, corner)
|
||||
local c = c or capi.client.focus
|
||||
|
||||
if not c then return end
|
||||
|
||||
if c.fullscreen
|
||||
or c.type == "desktop"
|
||||
or c.type == "splash"
|
||||
or c.type == "dock" then
|
||||
return
|
||||
end
|
||||
|
||||
-- Do not allow maximized clients to be resized by mouse
|
||||
local fixed_x = c.maximized_horizontal
|
||||
local fixed_y = c.maximized_vertical
|
||||
|
||||
local lay = layout.get(c.screen)
|
||||
|
||||
if lay == layout.suit.floating or aclient.floating.get(c) then
|
||||
return client_resize_floating(c, corner, fixed_x, fixed_y)
|
||||
elseif lay == layout.suit.tile
|
||||
or lay == layout.suit.tile.left
|
||||
or lay == layout.suit.tile.top
|
||||
or lay == layout.suit.tile.bottom
|
||||
then
|
||||
return client_resize_tiled(c, lay)
|
||||
elseif lay == layout.suit.magnifier then
|
||||
return client_resize_magnifier(c, corner)
|
||||
end
|
||||
end
|
||||
|
||||
-- Set the cursor at startup
|
||||
capi.root.cursor("left_ptr")
|
||||
|
||||
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80
|
@ -0,0 +1,238 @@
|
||||
---------------------------------------------------------------------------
|
||||
-- @author Julien Danjou <julien@danjou.info>
|
||||
-- @copyright 2008 Julien Danjou
|
||||
-- @release v3.4.10
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
-- Grab environment we need
|
||||
local ipairs = ipairs
|
||||
local pairs = pairs
|
||||
local math = math
|
||||
local table = table
|
||||
local capi =
|
||||
{
|
||||
screen = screen,
|
||||
mouse = mouse,
|
||||
client = client
|
||||
}
|
||||
local client = require("awful.client")
|
||||
local layout = require("awful.layout")
|
||||
|
||||
--- Places client according to special criteria.
|
||||
module("awful.placement")
|
||||
|
||||
-- Check if an area intersect another area.
|
||||
-- @param a The area.
|
||||
-- @param b The other area.
|
||||
-- @return True if they intersect, false otherwise.
|
||||
local function area_intersect_area(a, b)
|
||||
return (b.x < a.x + a.width
|
||||
and b.x + b.width > a.x
|
||||
and b.y < a.y + a.height
|
||||
and b.y + b.height > a.y)
|
||||
end
|
||||
|
||||
-- Get the intersect area between a and b.
|
||||
-- @param a The area.
|
||||
-- @param b The other area.
|
||||
-- @return The intersect area.
|
||||
local function area_intersect_area_get(a, b)
|
||||
local g = {}
|
||||
g.x = math.max(a.x, b.x)
|
||||
g.y = math.max(a.y, b.y)
|
||||
g.width = math.min(a.x + a.width, b.x + b.width) - g.x
|
||||
g.height = math.min(a.y + a.height, b.y + b.height) - g.y
|
||||
return g
|
||||
end
|
||||
|
||||
-- Remove an area from a list, splitting the space between several area that
|
||||
-- can overlap.
|
||||
-- @param areas Table of areas.
|
||||
-- @param elem Area to remove.
|
||||
-- @return The new area list.
|
||||
local function area_remove(areas, elem)
|
||||
for i = #areas, 1, -1 do
|
||||
-- Check if the 'elem' intersect
|
||||
if area_intersect_area(areas[i], elem) then
|
||||
-- It does? remove it
|
||||
local r = table.remove(areas, i)
|
||||
local inter = area_intersect_area_get(r, elem)
|
||||
|
||||
if inter.x > r.x then
|
||||
table.insert(areas, {
|
||||
x = r.x,
|
||||
y = r.y,
|
||||
width = inter.x - r.x,
|
||||
height = r.height
|
||||
})
|
||||
end
|
||||
|
||||
if inter.y > r.y then
|
||||
table.insert(areas, {
|
||||
x = r.x,
|
||||
y = r.y,
|
||||
width = r.width,
|
||||
height = inter.y - r.y
|
||||
})
|
||||
end
|
||||
|
||||
if inter.x + inter.width < r.x + r.width then
|
||||
table.insert(areas, {
|
||||
x = inter.x + inter.width,
|
||||
y = r.y,
|
||||
width = (r.x + r.width) - (inter.x + inter.width),
|
||||
height = r.height
|
||||
})
|
||||
end
|
||||
|
||||
if inter.y + inter.height < r.y + r.height then
|
||||
table.insert(areas, {
|
||||
x = r.x,
|
||||
y = inter.y + inter.height,
|
||||
width = r.width,
|
||||
height = (r.y + r.height) - (inter.y + inter.height)
|
||||
})
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return areas
|
||||
end
|
||||
|
||||
--- Place the client so no part of it will be outside the screen.
|
||||
-- @param c The client.
|
||||
-- @return The new client geometry.
|
||||
function no_offscreen(c)
|
||||
local c = c or capi.client.focus
|
||||
local geometry = c:geometry()
|
||||
local border = c.border_width
|
||||
local screen_geometry = capi.screen[c.screen].workarea
|
||||
|
||||
if geometry.x + geometry.width + 2*border > screen_geometry.x + screen_geometry.width then
|
||||
geometry.x = screen_geometry.x + screen_geometry.width - geometry.width
|
||||
elseif geometry.x < screen_geometry.x then
|
||||
geometry.x = screen_geometry.x
|
||||
end
|
||||
|
||||
if geometry.y + geometry.height + border > screen_geometry.y + screen_geometry.height then
|
||||
geometry.y = screen_geometry.y + screen_geometry.height - geometry.height
|
||||
elseif geometry.y < screen_geometry.y then
|
||||
geometry.y = screen_geometry.y
|
||||
end
|
||||
|
||||
c:geometry(geometry)
|
||||
end
|
||||
|
||||
--- Place the client where there's place available with minimum overlap.
|
||||
-- @param c The client.
|
||||
function no_overlap(c)
|
||||
local cls = client.visible(c.screen)
|
||||
local curlay = layout.get()
|
||||
local areas = { capi.screen[c.screen].workarea }
|
||||
local geometry = c:geometry()
|
||||
for i, cl in pairs(cls) do
|
||||
if cl ~= c and cl.type ~= "desktop" and (client.floating.get(cl) or curlay == layout.suit.floating) then
|
||||
areas = area_remove(areas, cl:geometry())
|
||||
end
|
||||
end
|
||||
|
||||
-- Look for available space
|
||||
local found = false
|
||||
local new = { x = geometry.x, y = geometry.y, width = 0, height = 0 }
|
||||
for i, r in ipairs(areas) do
|
||||
if r.width >= geometry.width
|
||||
and r.height >= geometry.height
|
||||
and r.width * r.height > new.width * new.height then
|
||||
found = true
|
||||
new = r
|
||||
-- Check if the client's current position is available
|
||||
-- and prefer that one (why move it around pointlessly?)
|
||||
if geometry.x >= r.x
|
||||
and geometry.y >= r.y
|
||||
and geometry.x + geometry.width <= r.x + r.width
|
||||
and geometry.y + geometry.height <= r.y + r.height then
|
||||
new.x = geometry.x
|
||||
new.y = geometry.y
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- We did not find an area with enough space for our size:
|
||||
-- just take the biggest available one and go in
|
||||
if not found then
|
||||
for i, r in ipairs(areas) do
|
||||
if r.width * r.height > new.width * new.height then
|
||||
new = r
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Restore height and width
|
||||
new.width = geometry.width
|
||||
new.height = geometry.height
|
||||
|
||||
return c:geometry(new)
|
||||
end
|
||||
|
||||
--- Place the client under the mouse.
|
||||
-- @param c The client.
|
||||
-- @return The new client geometry.
|
||||
function under_mouse(c)
|
||||
local c = c or capi.client.focus
|
||||
local c_geometry = c:geometry()
|
||||
local m_coords = capi.mouse.coords()
|
||||
return c:geometry({ x = m_coords.x - c_geometry.width / 2,
|
||||
y = m_coords.y - c_geometry.height / 2 })
|
||||
end
|
||||
|
||||
--- Place the client centered with respect to a parent or the clients screen.
|
||||
-- @param c The client.
|
||||
-- @param p The parent (optional, nil for screen centering).
|
||||
-- @return The new client geometry.
|
||||
function centered(c, p)
|
||||
local c = c or capi.client.focus
|
||||
local c_geometry = c:geometry()
|
||||
local s_geometry
|
||||
if p then
|
||||
s_geometry = p:geometry()
|
||||
else
|
||||
s_geometry = capi.screen[c.screen].geometry
|
||||
end
|
||||
return c:geometry({ x = s_geometry.x + (s_geometry.width - c_geometry.width) / 2,
|
||||
y = s_geometry.y + (s_geometry.height - c_geometry.height) / 2 })
|
||||
end
|
||||
|
||||
--- Place the client centered on the horizontal axis with respect to a parent or the clients screen.
|
||||
-- @param c The client.
|
||||
-- @param p The parent (optional, nil for screen centering).
|
||||
-- @return The new client geometry.
|
||||
function center_horizontal(c, p)
|
||||
local c = c or capi.client.focus
|
||||
local c_geometry = c:geometry()
|
||||
local s_geometry
|
||||
if p then
|
||||
s_geometry = p:geometry()
|
||||
else
|
||||
s_geometry = capi.screen[c.screen].geometry
|
||||
end
|
||||
return c:geometry({ x = s_geometry.x + (s_geometry.width - c_geometry.width) / 2 })
|
||||
end
|
||||
|
||||
--- Place the client centered on the vertical axis with respect to a parent or the clients screen.
|
||||
-- @param c The client.
|
||||
-- @param p The parent (optional, nil for screen centering).
|
||||
-- @return The new client geometry.
|
||||
function center_vertical(c, p)
|
||||
local c = c or capi.client.focus
|
||||
local c_geometry = c:geometry()
|
||||
local s_geometry
|
||||
if p then
|
||||
s_geometry = p:geometry()
|
||||
else
|
||||
s_geometry = capi.screen[c.screen].geometry
|
||||
end
|
||||
return c:geometry({ y = s_geometry.y + (s_geometry.height - c_geometry.height) / 2 })
|
||||
end
|
||||
|
||||
|
||||
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80
|
@ -0,0 +1,381 @@
|
||||
---------------------------------------------------------------------------
|
||||
-- @author Julien Danjou <julien@danjou.info>
|
||||
-- @copyright 2008 Julien Danjou
|
||||
-- @release v3.4.10
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
-- Grab environment we need
|
||||
local assert = assert
|
||||
local io = io
|
||||
local table = table
|
||||
local math = math
|
||||
local ipairs = ipairs
|
||||
local pcall = pcall
|
||||
local capi =
|
||||
{
|
||||
keygrabber = keygrabber,
|
||||
selection = selection
|
||||
}
|
||||
local util = require("awful.util")
|
||||
local beautiful = require("beautiful")
|
||||
|
||||
--- Prompt module for awful
|
||||
module("awful.prompt")
|
||||
|
||||
--- Private data
|
||||
local data = {}
|
||||
data.history = {}
|
||||
|
||||
-- Load history file in history table
|
||||
-- @param id The data.history identifier which is the path to the filename
|
||||
-- @param max Optional parameter, the maximum number of entries in file
|
||||
local function history_check_load(id, max)
|
||||
if id and id ~= ""
|
||||
and not data.history[id] then
|
||||
data.history[id] = { max = 50, table = {} }
|
||||
|
||||
if max then
|
||||
data.history[id].max = max
|
||||
end
|
||||
|
||||
local f = io.open(id, "r")
|
||||
|
||||
-- Read history file
|
||||
if f then
|
||||
for line in f:lines() do
|
||||
table.insert(data.history[id].table, line)
|
||||
if #data.history[id].table >= data.history[id].max then
|
||||
break
|
||||
end
|
||||
end
|
||||
f:close()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Save history table in history file
|
||||
-- @param id The data.history identifier
|
||||
local function history_save(id)
|
||||
if data.history[id] then
|
||||
local f = io.open(id, "w")
|
||||
if not f then
|
||||
local i = 0
|
||||
for d in id:gmatch(".-/") do
|
||||
i = i + #d
|
||||
end
|
||||
util.mkdir(id:sub(1, i - 1))
|
||||
f = assert(io.open(id, "w"))
|
||||
end
|
||||
for i = 1, math.min(#data.history[id].table, data.history[id].max) do
|
||||
f:write(data.history[id].table[i] .. "\n")
|
||||
end
|
||||
f:close()
|
||||
end
|
||||
end
|
||||
|
||||
-- Return the number of items in history table regarding the id
|
||||
-- @param id The data.history identifier
|
||||
-- @return the number of items in history table, -1 if history is disabled
|
||||
local function history_items(id)
|
||||
if data.history[id] then
|
||||
return #data.history[id].table
|
||||
else
|
||||
return -1
|
||||
end
|
||||
end
|
||||
|
||||
-- Add an entry to the history file
|
||||
-- @param id The data.history identifier
|
||||
-- @param command The command to add
|
||||
local function history_add(id, command)
|
||||
if data.history[id] then
|
||||
if command ~= ""
|
||||
and command ~= data.history[id].table[#data.history[id].table] then
|
||||
table.insert(data.history[id].table, command)
|
||||
|
||||
-- Do not exceed our max_cmd
|
||||
if #data.history[id].table > data.history[id].max then
|
||||
table.remove(data.history[id].table, 1)
|
||||
end
|
||||
|
||||
history_save(id)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
-- Draw the prompt text with a cursor.
|
||||
-- @param args The table of arguments.
|
||||
-- @param text The text.
|
||||
-- @param font The font.
|
||||
-- @param prompt The text prefix.
|
||||
-- @param text_color The text color.
|
||||
-- @param cursor_color The cursor color.
|
||||
-- @param cursor_pos The cursor position.
|
||||
-- @param cursor_ul The cursor underline style.
|
||||
-- @param selectall If true cursor is rendered on the entire text.
|
||||
local function prompt_text_with_cursor(args)
|
||||
local char, spacer, text_start, text_end, ret
|
||||
local text = args.text or ""
|
||||
local prompt = args.prompt or ""
|
||||
local underline = args.cursor_ul or "none"
|
||||
|
||||
if args.selectall then
|
||||
if #text == 0 then char = " " else char = util.escape(text) end
|
||||
spacer = " "
|
||||
text_start = ""
|
||||
text_end = ""
|
||||
elseif #text < args.cursor_pos then
|
||||
char = " "
|
||||
spacer = ""
|
||||
text_start = util.escape(text)
|
||||
text_end = ""
|
||||
else
|
||||
char = util.escape(text:sub(args.cursor_pos, args.cursor_pos))
|
||||
spacer = " "
|
||||
text_start = util.escape(text:sub(1, args.cursor_pos - 1))
|
||||
text_end = util.escape(text:sub(args.cursor_pos + 1))
|
||||
end
|
||||
|
||||
ret = prompt .. text_start .. "<span background=\"" .. util.color_strip_alpha(args.cursor_color) .. "\" foreground=\"" .. util.color_strip_alpha(args.text_color) .. "\" underline=\"" .. underline .. "\">" .. char .. "</span>" .. text_end .. spacer
|
||||
if args.font then ret = "<span font_desc='" .. args.font .. "'>" .. ret .. "</span>" end
|
||||
return ret
|
||||
end
|
||||
|
||||
--- Run a prompt in a box.
|
||||
-- @param args A table with optional arguments: fg_cursor, bg_cursor, ul_cursor, prompt, text, selectall, font, autoexec.
|
||||
-- @param textbox The textbox to use for the prompt.
|
||||
-- @param exe_callback The callback function to call with command as argument when finished.
|
||||
-- @param completion_callback The callback function to call to get completion.
|
||||
-- @param history_path Optional parameter: file path where the history should be saved, set nil to disable history
|
||||
-- @param history_max Optional parameter: set the maximum entries in history file, 50 by default
|
||||
-- @param done_callback Optional parameter: the callback function to always call without arguments, regardless of whether the prompt was cancelled.
|
||||
function run(args, textbox, exe_callback, completion_callback, history_path, history_max, done_callback)
|
||||
local theme = beautiful.get()
|
||||
if not args then args = {} end
|
||||
local command = args.text or ""
|
||||
local command_before_comp
|
||||
local cur_pos_before_comp
|
||||
local prettyprompt = args.prompt or ""
|
||||
local inv_col = args.fg_cursor or theme.fg_focus or "black"
|
||||
local cur_col = args.bg_cursor or theme.bg_focus or "white"
|
||||
local cur_ul = args.ul_cursor
|
||||
local text = args.text or ""
|
||||
local font = args.font or theme.font
|
||||
local selectall = args.selectall
|
||||
|
||||
history_check_load(history_path, history_max)
|
||||
local history_index = history_items(history_path) + 1
|
||||
-- The cursor position
|
||||
local cur_pos = (selectall and 1) or text:wlen() + 1
|
||||
-- The completion element to use on completion request.
|
||||
local ncomp = 1
|
||||
if not textbox or not exe_callback then
|
||||
return
|
||||
end
|
||||
textbox.text = prompt_text_with_cursor{
|
||||
text = text, text_color = inv_col, cursor_color = cur_col,
|
||||
cursor_pos = cur_pos, cursor_ul = cur_ul, selectall = selectall,
|
||||
font = font, prompt = prettyprompt }
|
||||
|
||||
local exec = function()
|
||||
textbox.text = ""
|
||||
history_add(history_path, command)
|
||||
capi.keygrabber.stop()
|
||||
exe_callback(command)
|
||||
if done_callback then done_callback() end
|
||||
end
|
||||
|
||||
capi.keygrabber.run(
|
||||
function (modifiers, key, event)
|
||||
if event ~= "press" then return true end
|
||||
-- Convert index array to hash table
|
||||
local mod = {}
|
||||
for k, v in ipairs(modifiers) do mod[v] = true end
|
||||
-- Get out cases
|
||||
if (mod.Control and (key == "c" or key == "g"))
|
||||
or (not mod.Control and key == "Escape") then
|
||||
textbox.text = ""
|
||||
if done_callback then done_callback() end
|
||||
return false
|
||||
elseif (mod.Control and (key == "j" or key == "m"))
|
||||
or (not mod.Control and key == "Return")
|
||||
or (not mod.Control and key == "KP_Enter") then
|
||||
exec()
|
||||
-- We already unregistered ourselves so we don't want to return
|
||||
-- true, otherwise we may unregister someone else.
|
||||
return true
|
||||
end
|
||||
|
||||
-- Control cases
|
||||
if mod.Control then
|
||||
selectall = nil
|
||||
if key == "a" then
|
||||
cur_pos = 1
|
||||
elseif key == "b" then
|
||||
if cur_pos > 1 then
|
||||
cur_pos = cur_pos - 1
|
||||
end
|
||||
elseif key == "d" then
|
||||
if cur_pos <= #command then
|
||||
command = command:sub(1, cur_pos - 1) .. command:sub(cur_pos + 1)
|
||||
end
|
||||
elseif key == "e" then
|
||||
cur_pos = #command + 1
|
||||
elseif key == "f" then
|
||||
if cur_pos <= #command then
|
||||
cur_pos = cur_pos + 1
|
||||
end
|
||||
elseif key == "h" then
|
||||
if cur_pos > 1 then
|
||||
command = command:sub(1, cur_pos - 2) .. command:sub(cur_pos)
|
||||
cur_pos = cur_pos - 1
|
||||
end
|
||||
elseif key == "k" then
|
||||
command = command:sub(1, cur_pos - 1)
|
||||
elseif key == "u" then
|
||||
command = command:sub(cur_pos, #command)
|
||||
cur_pos = 1
|
||||
elseif key == "w" or key == "BackSpace" then
|
||||
local wstart = 1
|
||||
local wend = 1
|
||||
local cword_start = 1
|
||||
local cword_end = 1
|
||||
while wend < cur_pos do
|
||||
wend = command:find("[{[(,.:;_-+=@/ ]", wstart)
|
||||
if not wend then wend = #command + 1 end
|
||||
if cur_pos >= wstart and cur_pos <= wend + 1 then
|
||||
cword_start = wstart
|
||||
cword_end = cur_pos - 1
|
||||
break
|
||||
end
|
||||
wstart = wend + 1
|
||||
end
|
||||
command = command:sub(1, cword_start - 1) .. command:sub(cword_end + 1)
|
||||
cur_pos = cword_start
|
||||
end
|
||||
else
|
||||
if completion_callback then
|
||||
if key == "Tab" or key == "ISO_Left_Tab" then
|
||||
if key == "ISO_Left_Tab" then
|
||||
if ncomp == 1 then return true end
|
||||
if ncomp == 2 then
|
||||
command = command_before_comp
|
||||
textbox.text = prompt_text_with_cursor{
|
||||
text = command_before_comp, text_color = inv_col, cursor_color = cur_col,
|
||||
cursor_pos = cur_pos, cursor_ul = cur_ul, selectall = selectall,
|
||||
font = font, prompt = prettyprompt }
|
||||
return true
|
||||
end
|
||||
|
||||
ncomp = ncomp - 2
|
||||
elseif ncomp == 1 then
|
||||
command_before_comp = command
|
||||
cur_pos_before_comp = cur_pos
|
||||
end
|
||||
local matches
|
||||
command, cur_pos, matches = completion_callback(command_before_comp, cur_pos_before_comp, ncomp)
|
||||
ncomp = ncomp + 1
|
||||
key = ""
|
||||
-- execute if only one match found and autoexec flag set
|
||||
if matches and #matches == 1 and args.autoexec then
|
||||
exec()
|
||||
return true
|
||||
end
|
||||
else
|
||||
ncomp = 1
|
||||
end
|
||||
end
|
||||
|
||||
-- Typin cases
|
||||
if mod.Shift and key == "Insert" then
|
||||
local selection = capi.selection()
|
||||
if selection then
|
||||
-- Remove \n
|
||||
local n = selection:find("\n")
|
||||
if n then
|
||||
selection = selection:sub(1, n - 1)
|
||||
end
|
||||
command = command:sub(1, cur_pos - 1) .. selection .. command:sub(cur_pos)
|
||||
cur_pos = cur_pos + #selection
|
||||
end
|
||||
elseif key == "Home" then
|
||||
cur_pos = 1
|
||||
elseif key == "End" then
|
||||
cur_pos = #command + 1
|
||||
elseif key == "BackSpace" then
|
||||
if cur_pos > 1 then
|
||||
command = command:sub(1, cur_pos - 2) .. command:sub(cur_pos)
|
||||
cur_pos = cur_pos - 1
|
||||
end
|
||||
elseif key == "Delete" then
|
||||
command = command:sub(1, cur_pos - 1) .. command:sub(cur_pos + 1)
|
||||
elseif key == "Left" then
|
||||
cur_pos = cur_pos - 1
|
||||
elseif key == "Right" then
|
||||
cur_pos = cur_pos + 1
|
||||
elseif key == "Up" then
|
||||
if history_index > 1 then
|
||||
history_index = history_index - 1
|
||||
|
||||
command = data.history[history_path].table[history_index]
|
||||
cur_pos = #command + 2
|
||||
end
|
||||
elseif key == "Down" then
|
||||
if history_index < history_items(history_path) then
|
||||
history_index = history_index + 1
|
||||
|
||||
command = data.history[history_path].table[history_index]
|
||||
cur_pos = #command + 2
|
||||
elseif history_index == history_items(history_path) then
|
||||
history_index = history_index + 1
|
||||
|
||||
command = ""
|
||||
cur_pos = 1
|
||||
end
|
||||
else
|
||||
-- wlen() is UTF-8 aware but #key is not,
|
||||
-- so check that we have one UTF-8 char but advance the cursor of # position
|
||||
if key:wlen() == 1 then
|
||||
if selectall then command = "" end
|
||||
command = command:sub(1, cur_pos - 1) .. key .. command:sub(cur_pos)
|
||||
cur_pos = cur_pos + #key
|
||||
end
|
||||
end
|
||||
if cur_pos < 1 then
|
||||
cur_pos = 1
|
||||
elseif cur_pos > #command + 1 then
|
||||
cur_pos = #command + 1
|
||||
end
|
||||
selectall = nil
|
||||
end
|
||||
|
||||
-- Update textbox
|
||||
local function update()
|
||||
textbox.text = prompt_text_with_cursor{
|
||||
text = command, text_color = inv_col, cursor_color = cur_col,
|
||||
cursor_pos = cur_pos, cursor_ul = cur_ul, selectall = selectall,
|
||||
font = font, prompt = prettyprompt }
|
||||
end
|
||||
|
||||
local success = pcall(update)
|
||||
while not success do
|
||||
-- TODO UGLY HACK TODO
|
||||
-- Setting the text failed. Most likely reason is that the user
|
||||
-- entered a multibyte character and pressed backspace which only
|
||||
-- removed the last byte. Let's remove another byte.
|
||||
if cur_pos <= 1 then
|
||||
-- No text left?!
|
||||
break
|
||||
end
|
||||
|
||||
command = command:sub(1, cur_pos - 2) .. command:sub(cur_pos)
|
||||
cur_pos = cur_pos - 1
|
||||
success = pcall(update)
|
||||
end
|
||||
|
||||
return true
|
||||
end)
|
||||
end
|
||||
|
||||
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80
|
@ -0,0 +1,48 @@
|
||||
---------------------------------------------------------------------------
|
||||
-- @author Julien Danjou <julien@danjou.info>
|
||||
-- @copyright 2009 Julien Danjou
|
||||
-- @release v3.4.10
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
-- Grab environment we need
|
||||
require("awful.dbus")
|
||||
local loadstring = loadstring
|
||||
local tostring = tostring
|
||||
local ipairs = ipairs
|
||||
local table = table
|
||||
local dbus = dbus
|
||||
local unpack = unpack
|
||||
local type = type
|
||||
|
||||
--- Remote control module allowing usage of awesome-client.
|
||||
module("awful.remote")
|
||||
|
||||
if dbus then
|
||||
dbus.add_signal("org.naquadah.awesome.awful.Remote", function(data, code)
|
||||
if data.member == "Eval" then
|
||||
local f, e = loadstring(code)
|
||||
if f then
|
||||
results = { f() }
|
||||
retvals = {}
|
||||
for _, v in ipairs(results) do
|
||||
local t = type(v)
|
||||
if t == "boolean" then
|
||||
table.insert(retvals, "b")
|
||||
table.insert(retvals, v)
|
||||
elseif t == "number" then
|
||||
table.insert(retvals, "d")
|
||||
table.insert(retvals, v)
|
||||
else
|
||||
table.insert(retvals, "s")
|
||||
table.insert(retvals, tostring(v))
|
||||
end
|
||||
end
|
||||
return unpack(retvals)
|
||||
elseif e then
|
||||
return "s", e
|
||||
end
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80
|
@ -0,0 +1,203 @@
|
||||
---------------------------------------------------------------------------
|
||||
-- @author Julien Danjou <julien@danjou.info>
|
||||
-- @copyright 2009 Julien Danjou
|
||||
-- @release v3.4.10
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
-- Grab environment we need
|
||||
local client = client
|
||||
local table = table
|
||||
local type = type
|
||||
local ipairs = ipairs
|
||||
local pairs = pairs
|
||||
local aclient = require("awful.client")
|
||||
local atag = require("awful.tag")
|
||||
|
||||
--- Apply rules to clients at startup.
|
||||
module("awful.rules")
|
||||
|
||||
--- This is the global rules table.
|
||||
-- <p>You should fill this table with your rule and properties to apply.
|
||||
-- For example, if you want to set xterm maximized at startup, you can add:
|
||||
-- <br/>
|
||||
-- <code>
|
||||
-- { rule = { class = "xterm" },
|
||||
-- properties = { maximized_vertical = true, maximized_horizontal = true } }
|
||||
-- </code>
|
||||
-- </p>
|
||||
-- <p>If you want to set mplayer floating at startup, you can add:
|
||||
-- <br/>
|
||||
-- <code>
|
||||
-- { rule = { name = "MPlayer" },
|
||||
-- properties = { floating = true } }
|
||||
-- </code>
|
||||
-- </p>
|
||||
-- <p>If you want to put Firefox on a specific tag at startup, you
|
||||
-- can add:
|
||||
-- <br/>
|
||||
-- <code>
|
||||
-- { rule = { instance = "firefox" },
|
||||
-- properties = { tag = mytagobject } }
|
||||
-- </code>
|
||||
-- </p>
|
||||
-- <p>If you want to put Emacs on a specific tag at startup, and
|
||||
-- immediately switch to that tag you can add:
|
||||
-- <br/>
|
||||
-- <code>
|
||||
-- { rule = { class = "Emacs" },
|
||||
-- properties = { tag = mytagobject, switchtotag = true } }
|
||||
-- </code>
|
||||
-- </p>
|
||||
-- <p>If you want to apply a custom callback to execute when a rule matched, you
|
||||
-- can add:
|
||||
-- <br/>
|
||||
-- <code>
|
||||
-- { rule = { class = "dosbox" },
|
||||
-- callback = awful.placement.centered }
|
||||
-- </code>
|
||||
-- </p>
|
||||
-- <p>Note that all "rule" entries need to match. If any of the entry does not
|
||||
-- match, the rule won't be applied.</p>
|
||||
-- <p>If a client matches multiple rules, their applied in the order they are
|
||||
-- put in this global rules table. If the value of a rule is a string, then the
|
||||
-- match function is used to determine if the client matches the rule.</p>
|
||||
--
|
||||
-- <p> To match multiple clients to a rule one need to use slightly different
|
||||
-- syntax:
|
||||
-- <br/>
|
||||
-- <code>
|
||||
-- { rule_any = { class = { "MPlayer", "Nitrogen" }, instance = { "xterm" } },
|
||||
-- properties = { floating = true } }
|
||||
-- </code>
|
||||
-- </p>
|
||||
--
|
||||
-- <p> To match multiple clients with an exception one can couple 'except' or
|
||||
-- 'except_any' with the rules:
|
||||
-- <br/>
|
||||
-- <code>
|
||||
-- { rule = { class = "Firefox" },
|
||||
-- except = { instance = "Navigator" },
|
||||
-- properties = {floating = true},
|
||||
-- },
|
||||
-- </code>
|
||||
-- <br/>
|
||||
-- <code>
|
||||
-- { rule_any = { class = { "Pidgin", "Xchat" } },
|
||||
-- except_any = { role = { "conversation" } },
|
||||
-- properties = { tag = tags[1][1] }
|
||||
-- }
|
||||
-- <br/>
|
||||
-- <code>
|
||||
-- { rule = {},
|
||||
-- except_any = { class = { "Firefox", "Vim" } },
|
||||
-- properties = { floating = true }
|
||||
-- }
|
||||
-- </code>
|
||||
-- </p>
|
||||
--
|
||||
-- @class table
|
||||
-- @name rules
|
||||
rules = {}
|
||||
|
||||
--- Check if a client match a rule.
|
||||
-- @param c The client.
|
||||
-- @param rule The rule to check.
|
||||
-- @return True if it matches, false otherwise.
|
||||
function match(c, rule)
|
||||
if not rule then return false end
|
||||
for field, value in pairs(rule) do
|
||||
if c[field] then
|
||||
if type(c[field]) == "string" then
|
||||
if not c[field]:match(value) and c[field] ~= value then
|
||||
return false
|
||||
end
|
||||
elseif c[field] ~= value then
|
||||
return false
|
||||
end
|
||||
else
|
||||
return false
|
||||
end
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
--- Check if a client match a rule. Multiple clients can be matched
|
||||
-- @param c The client.
|
||||
-- @param rules The rule to check.
|
||||
-- @return True if at least one rule is matched, false otherwise.
|
||||
function match_any(c, rule)
|
||||
if not rule then return false end
|
||||
for field, values in pairs(rule) do
|
||||
if c[field] then
|
||||
for _, value in ipairs(values) do
|
||||
if c[field] == value then
|
||||
return true
|
||||
elseif type(c[field]) == "string" and c[field]:match(value) then
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
--- Apply rules to a client.
|
||||
-- @param c The client.
|
||||
function apply(c)
|
||||
local props = {}
|
||||
local callbacks = {}
|
||||
for _, entry in ipairs(rules) do
|
||||
if (match(c, entry.rule) or match_any(c, entry.rule_any)) and
|
||||
(not match(c, entry.except) and not match_any(c, entry.except_any)) then
|
||||
if entry.properties then
|
||||
for property, value in pairs(entry.properties) do
|
||||
props[property] = value
|
||||
end
|
||||
end
|
||||
if entry.callback then
|
||||
table.insert(callbacks, entry.callback)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
for property, value in pairs(props) do
|
||||
if property == "floating" then
|
||||
aclient.floating.set(c, value)
|
||||
elseif property == "tag" then
|
||||
c:tags({ value })
|
||||
c.screen = value.screen
|
||||
elseif property == "switchtotag" and value and props.tag then
|
||||
atag.viewonly(props.tag)
|
||||
elseif property == "height" or property == "width" or
|
||||
property == "x" or property == "y" then
|
||||
local geo = c:geometry();
|
||||
geo[property] = value
|
||||
c:geometry(geo);
|
||||
elseif type(c[property]) == "function" then
|
||||
c[property](c, value)
|
||||
else
|
||||
c[property] = value
|
||||
end
|
||||
end
|
||||
|
||||
-- If untagged, stick the client on the current one.
|
||||
if #c:tags() == 0 then
|
||||
atag.withcurrent(c)
|
||||
end
|
||||
|
||||
-- Apply all callbacks from matched rules.
|
||||
for i, callback in pairs(callbacks) do
|
||||
callback(c)
|
||||
end
|
||||
|
||||
-- Do this at last so we do not erase things done by the focus
|
||||
-- signal.
|
||||
if props.focus then
|
||||
client.focus = c
|
||||
end
|
||||
end
|
||||
|
||||
client.add_signal("manage", apply)
|
||||
client.remove_signal("manage", atag.withcurrent)
|
||||
|
||||
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80
|
@ -0,0 +1,53 @@
|
||||
---------------------------------------------------------------------------
|
||||
-- @author Julien Danjou <julien@danjou.info>
|
||||
-- @copyright 2008 Julien Danjou
|
||||
-- @release v3.4.10
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
-- Grab environment we need
|
||||
local capi =
|
||||
{
|
||||
mouse = mouse,
|
||||
screen = screen,
|
||||
client = client
|
||||
}
|
||||
local util = require("awful.util")
|
||||
local client = require("awful.client")
|
||||
|
||||
--- Screen module for awful
|
||||
module("awful.screen")
|
||||
|
||||
local data = {}
|
||||
data.padding = {}
|
||||
|
||||
--- Give the focus to a screen, and move pointer.
|
||||
-- @param screen Screen number.
|
||||
function focus(screen)
|
||||
if screen > capi.screen.count() then screen = capi.mouse.screen end
|
||||
local c = client.focus.history.get(screen, 0)
|
||||
if c then capi.client.focus = c end
|
||||
-- Move the mouse on the screen
|
||||
capi.mouse.screen = screen
|
||||
end
|
||||
|
||||
--- Give the focus to a screen, and move pointer, but relative to the current
|
||||
-- focused screen.
|
||||
-- @param i Value to add to the current focused screen index. 1 will focus next
|
||||
-- screen, -1 would focus the previous one.
|
||||
function focus_relative(i)
|
||||
return focus(util.cycle(capi.screen.count(), capi.mouse.screen + i))
|
||||
end
|
||||
|
||||
--- Get or set the screen padding.
|
||||
-- @param screen The screen object to change the padding on
|
||||
-- @param padding The padding, an table with 'top', 'left', 'right' and/or
|
||||
-- 'bottom'. Can be nil if you only want to retrieve padding
|
||||
function padding(screen, padding)
|
||||
if padding then
|
||||
data.padding[screen] = padding
|
||||
screen:emit_signal("padding")
|
||||
end
|
||||
return data.padding[screen]
|
||||
end
|
||||
|
||||
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80
|
@ -0,0 +1,54 @@
|
||||
---------------------------------------------------------------------------
|
||||
-- @author Julien Danjou <julien@danjou.info>
|
||||
-- @copyright 2009 Julien Danjou
|
||||
-- @release v3.4.10
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
-- Grab environment we need
|
||||
local ipairs = ipairs
|
||||
local table = table
|
||||
local capi =
|
||||
{
|
||||
awesome = awesome,
|
||||
root = root
|
||||
}
|
||||
|
||||
--- Startup notification module for awful
|
||||
module("awful.startup_notification")
|
||||
|
||||
local app_starting = {}
|
||||
|
||||
cursor_waiting = "watch"
|
||||
|
||||
local function update_cursor()
|
||||
if #app_starting > 0 then
|
||||
capi.root.cursor(cursor_waiting)
|
||||
else
|
||||
capi.root.cursor("left_ptr")
|
||||
end
|
||||
end
|
||||
|
||||
local function unregister_event(event_id)
|
||||
for k, v in ipairs(app_starting) do
|
||||
if v == event_id then
|
||||
table.remove(app_starting, k)
|
||||
update_cursor()
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function register_event(event_id)
|
||||
table.insert(app_starting, event_id)
|
||||
update_cursor()
|
||||
end
|
||||
|
||||
local function unregister_hook(event) unregister_event(event.id) end
|
||||
local function register_hook(event) register_event(event.id) end
|
||||
|
||||
capi.awesome.add_signal("spawn::initiated", register_hook)
|
||||
capi.awesome.add_signal("spawn::canceled", unregister_hook)
|
||||
capi.awesome.add_signal("spawn::completed", unregister_hook)
|
||||
capi.awesome.add_signal("spawn::timeout", unregister_hook)
|
||||
|
||||
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80
|
527
DUFRESNE/Linux/home/burchettm/.config/awesome/lib/awful/tag.lua
Normal file
527
DUFRESNE/Linux/home/burchettm/.config/awesome/lib/awful/tag.lua
Normal file
@ -0,0 +1,527 @@
|
||||
---------------------------------------------------------------------------
|
||||
-- @author Julien Danjou <julien@danjou.info>
|
||||
-- @copyright 2008 Julien Danjou
|
||||
-- @release v3.4.10
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
-- Grab environment we need
|
||||
local util = require("awful.util")
|
||||
local tostring = tostring
|
||||
local pairs = pairs
|
||||
local ipairs = ipairs
|
||||
local table = table
|
||||
local setmetatable = setmetatable
|
||||
local capi =
|
||||
{
|
||||
tag = tag,
|
||||
screen = screen,
|
||||
mouse = mouse,
|
||||
client = client
|
||||
}
|
||||
|
||||
--- Useful functions for tag manipulation.
|
||||
module("awful.tag")
|
||||
|
||||
-- Private data
|
||||
local data = {}
|
||||
data.history = {}
|
||||
data.tags = setmetatable({}, { __mode = 'k' })
|
||||
|
||||
-- History functions
|
||||
history = {}
|
||||
history.limit = 20
|
||||
|
||||
--- Move a tag to an absolute position in the screen[]:tags() table.
|
||||
-- @param new_index Integer absolute position in the table to insert.
|
||||
function move(new_index, target_tag)
|
||||
local target_tag = target_tag or selected()
|
||||
local scr = target_tag.screen
|
||||
local tmp_tags = capi.screen[scr]:tags()
|
||||
|
||||
if (not new_index) or (new_index < 1) or (new_index > #tmp_tags) then
|
||||
return
|
||||
end
|
||||
|
||||
for i, t in ipairs(tmp_tags) do
|
||||
if t == target_tag then
|
||||
table.remove(tmp_tags, i)
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
table.insert(tmp_tags, new_index, target_tag)
|
||||
capi.screen[scr]:tags(tmp_tags)
|
||||
end
|
||||
|
||||
--- Add a tag.
|
||||
-- @param name The tag name, a string
|
||||
-- @param props The tags properties, a table
|
||||
-- @return The created tag
|
||||
function add(name, props)
|
||||
local properties = props or {}
|
||||
local newtag = capi.tag{name = name}
|
||||
newtag.screen = properties.screen or capi.mouse.screen
|
||||
|
||||
for k, v in pairs(properties) do
|
||||
setproperty(newtag, k, v)
|
||||
end
|
||||
|
||||
return newtag
|
||||
end
|
||||
|
||||
--- Create a set of tags and attach it to a screen.
|
||||
-- @param names The tag name, in a table
|
||||
-- @param screen The tag screen, or 1 if not set.
|
||||
-- @param layout The layout or layout table to set for this tags by default.
|
||||
-- @return A table with all created tags.
|
||||
function new(names, screen, layout)
|
||||
local screen = screen or 1
|
||||
local tags = {}
|
||||
for id, name in ipairs(names) do
|
||||
table.insert(tags, id, add(name, {screen = screen,
|
||||
layout = (layout and layout[id]) or
|
||||
layout}))
|
||||
-- Select the first tag.
|
||||
if id == 1 then
|
||||
tags[id].selected = true
|
||||
end
|
||||
end
|
||||
|
||||
return tags
|
||||
end
|
||||
|
||||
--- Find a suitable fallback tag.
|
||||
-- @param screen The screen number to look for a tag on. [mouse.screen]
|
||||
-- @param target A table of tags we consider unacceptable. [selectedlist(scr)]
|
||||
function find_fallback(screen, invalids)
|
||||
local scr = screen or capi.mouse.screen
|
||||
local t = invalids or selectedlist(scr)
|
||||
|
||||
for _, v in pairs(capi.screen[scr]:tags()) do
|
||||
if not util.table.hasitem(t, v) then return v end
|
||||
end
|
||||
end
|
||||
|
||||
--- Delete a tag.
|
||||
-- @param target_tag Optional tag object to delete. [selected()]
|
||||
-- @param fallback_tag Tag to assign stickied tags to. [~selected()]
|
||||
-- @return Returns true if the tag is successfully deleted, nil otherwise.
|
||||
-- If there are no clients exclusively on this tag then delete it. Any
|
||||
-- stickied clients are assigned to the optional 'fallback_tag'.
|
||||
-- If after deleting the tag there is no selected tag, try and restore from
|
||||
-- history or select the first tag on the screen.
|
||||
function delete(target_tag, fallback_tag)
|
||||
-- abort if no tag is passed or currently selected
|
||||
local target_tag = target_tag or selected()
|
||||
if target_tag == nil then return end
|
||||
|
||||
local ntags = #capi.screen[target_tag.screen]:tags()
|
||||
local target_scr = target_tag.screen
|
||||
|
||||
-- We can't use the target tag as a fallback.
|
||||
local fallback_tag = fallback_tag
|
||||
if fallback_tag == target_tag then return end
|
||||
|
||||
-- No fallback_tag provided, try and get one.
|
||||
if fallback_tag == nil then
|
||||
fallback_tag = find_fallback(target_scr, {target_tag})
|
||||
end
|
||||
|
||||
-- Abort if we would have un-tagged clients.
|
||||
local clients = target_tag:clients()
|
||||
if ( #clients > 0 and ntags <= 1 ) or fallback_tag == nil then return end
|
||||
|
||||
-- Move the clients we can off of this tag.
|
||||
for _, c in pairs(clients) do
|
||||
|
||||
-- If a client has only this tag, or stickied clients with
|
||||
-- nowhere to go, abort.
|
||||
if (not c.sticky and #c:tags() == 1) or
|
||||
(c.sticky and fallback_tag == nil) then
|
||||
return
|
||||
else
|
||||
c:tags({fallback_tag})
|
||||
end
|
||||
end
|
||||
|
||||
-- delete the tag
|
||||
target_tag.screen = nil
|
||||
|
||||
-- If no tags are visible, try and view one.
|
||||
if selected(target_scr) == nil and ntags > 0 then
|
||||
history.restore()
|
||||
if selected(target_scr) == nil then
|
||||
capi.screen[target_scr]:tags()[1].selected = true
|
||||
end
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
--- Update the tag history.
|
||||
-- @param obj Screen object.
|
||||
function history.update(obj)
|
||||
local s = obj.index
|
||||
local curtags = selectedlist(s)
|
||||
-- create history table
|
||||
if not data.history[s] then
|
||||
data.history[s] = {}
|
||||
else
|
||||
if data.history[s].current then
|
||||
-- Check that the list is not identical
|
||||
local identical = true
|
||||
for idx, tag in ipairs(data.history[s].current) do
|
||||
if curtags[idx] ~= tag then
|
||||
identical = false
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
-- Do not update history the table are identical
|
||||
if identical then return end
|
||||
end
|
||||
|
||||
-- Limit history
|
||||
if #data.history[s] >= history.limit then
|
||||
for i = history.limit, #data.history[s] do
|
||||
data.history[s][i] = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- store previously selected tags in the history table
|
||||
table.insert(data.history[s], 1, data.history[s].current)
|
||||
data.history[s].previous = data.history[s][1]
|
||||
-- store currently selected tags
|
||||
data.history[s].current = setmetatable(curtags, { __mode = 'v' })
|
||||
end
|
||||
|
||||
--- Revert tag history.
|
||||
-- @param screen The screen number.
|
||||
-- @param idx Index in history. Defaults to "previous" which is a special index
|
||||
-- toggling between last two selected sets of tags. Number (eg 1) will go back
|
||||
-- to the given index in history.
|
||||
function history.restore(screen, idx)
|
||||
local s = screen or capi.mouse.screen
|
||||
local i = idx or "previous"
|
||||
local sel = selectedlist(s)
|
||||
-- do nothing if history empty
|
||||
if not data.history[s] or not data.history[s][i] then return end
|
||||
-- if all tags been deleted, try next entry
|
||||
if #data.history[s][i] == 0 then
|
||||
if i == "previous" then i = 0 end
|
||||
history.restore(s, i + 1)
|
||||
return
|
||||
end
|
||||
-- deselect all tags
|
||||
viewnone(s)
|
||||
-- select tags from the history entry
|
||||
for _, t in ipairs(data.history[s][i]) do
|
||||
t.selected = true
|
||||
end
|
||||
-- update currently selected tags table
|
||||
data.history[s].current = data.history[s][i]
|
||||
-- store previously selected tags
|
||||
data.history[s].previous = setmetatable(sel, { __mode = 'v' })
|
||||
-- remove the reverted history entry
|
||||
if i ~= "previous" then table.remove(data.history[s], i) end
|
||||
end
|
||||
|
||||
--- Return a table with all visible tags
|
||||
-- @param s Screen number.
|
||||
-- @return A table with all selected tags.
|
||||
function selectedlist(s)
|
||||
local screen = s or capi.mouse.screen
|
||||
local tags = capi.screen[screen]:tags()
|
||||
local vtags = {}
|
||||
for i, t in pairs(tags) do
|
||||
if t.selected then
|
||||
vtags[#vtags + 1] = t
|
||||
end
|
||||
end
|
||||
return vtags
|
||||
end
|
||||
|
||||
--- Return only the first visible tag.
|
||||
-- @param s Screen number.
|
||||
function selected(s)
|
||||
return selectedlist(s)[1]
|
||||
end
|
||||
|
||||
--- Set master width factor.
|
||||
-- @param mwfact Master width factor.
|
||||
function setmwfact(mwfact, t)
|
||||
local t = t or selected()
|
||||
if mwfact >= 0 and mwfact <= 1 then
|
||||
setproperty(t, "mwfact", mwfact)
|
||||
end
|
||||
end
|
||||
|
||||
--- Increase master width factor.
|
||||
-- @param add Value to add to master width factor.
|
||||
function incmwfact(add, t)
|
||||
setmwfact(getmwfact(t) + add)
|
||||
end
|
||||
|
||||
--- Get master width factor.
|
||||
-- @param t Optional tag.
|
||||
function getmwfact(t)
|
||||
local t = t or selected()
|
||||
return getproperty(t, "mwfact") or 0.5
|
||||
end
|
||||
|
||||
--- Set the number of master windows.
|
||||
-- @param nmaster The number of master windows.
|
||||
-- @param t Optional tag.
|
||||
function setnmaster(nmaster, t)
|
||||
local t = t or selected()
|
||||
if nmaster >= 0 then
|
||||
setproperty(t, "nmaster", nmaster)
|
||||
end
|
||||
end
|
||||
|
||||
--- Get the number of master windows.
|
||||
-- @param t Optional tag.
|
||||
function getnmaster(t)
|
||||
local t = t or selected()
|
||||
return getproperty(t, "nmaster") or 1
|
||||
end
|
||||
|
||||
--- Increase the number of master windows.
|
||||
-- @param add Value to add to number of master windows.
|
||||
function incnmaster(add, t)
|
||||
setnmaster(getnmaster(t) + add)
|
||||
end
|
||||
|
||||
|
||||
--- Set the tag icon
|
||||
-- @param icon the icon to set, either path or image object
|
||||
-- @param tag the tag
|
||||
function seticon(icon, tag)
|
||||
local tag = tag or selected()
|
||||
setproperty(tag, "icon", icon)
|
||||
end
|
||||
|
||||
--- Get the tag icon
|
||||
-- @param t the tag
|
||||
function geticon(tag)
|
||||
local tag = tag or selected()
|
||||
return getproperty(tag, "icon")
|
||||
end
|
||||
|
||||
--- Set number of column windows.
|
||||
-- @param ncol The number of column.
|
||||
function setncol(ncol, t)
|
||||
local t = t or selected()
|
||||
if ncol >= 1 then
|
||||
setproperty(t, "ncol", ncol)
|
||||
end
|
||||
end
|
||||
|
||||
--- Get number of column windows.
|
||||
-- @param t Optional tag.
|
||||
function getncol(t)
|
||||
local t = t or selected()
|
||||
return getproperty(t, "ncol") or 1
|
||||
end
|
||||
|
||||
--- Increase number of column windows.
|
||||
-- @param add Value to add to number of column windows.
|
||||
function incncol(add, t)
|
||||
setncol(getncol(t) + add)
|
||||
end
|
||||
|
||||
--- View no tag.
|
||||
-- @param Optional screen number.
|
||||
function viewnone(screen)
|
||||
local tags = capi.screen[screen or capi.mouse.screen]:tags()
|
||||
for i, t in pairs(tags) do
|
||||
t.selected = false
|
||||
end
|
||||
end
|
||||
|
||||
--- View a tag by its taglist index.
|
||||
-- @param i The relative index to see.
|
||||
-- @param screen Optional screen number.
|
||||
function viewidx(i, screen)
|
||||
local screen = screen and screen.index or capi.mouse.screen
|
||||
local tags = capi.screen[screen]:tags()
|
||||
local showntags = {}
|
||||
for k, t in ipairs(tags) do
|
||||
if not getproperty(t, "hide") then
|
||||
table.insert(showntags, t)
|
||||
end
|
||||
end
|
||||
local sel = selected(screen)
|
||||
viewnone(screen)
|
||||
for k, t in ipairs(showntags) do
|
||||
if t == sel then
|
||||
showntags[util.cycle(#showntags, k + i)].selected = true
|
||||
end
|
||||
end
|
||||
capi.screen[screen]:emit_signal("tag::history::update")
|
||||
end
|
||||
|
||||
--- Get a tag's index in the screen[]:tags() table.
|
||||
-- @param query_tag The tag object to find. [selected()]
|
||||
-- @return The index of the tag, nil if the tag is not found.
|
||||
function getidx(query_tag)
|
||||
local query_tag = query_tag or selected()
|
||||
if query_tag == nil then return end
|
||||
|
||||
for i, t in ipairs(capi.screen[query_tag.screen]:tags()) do
|
||||
if t == query_tag then
|
||||
return i
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--- View next tag. This is the same as tag.viewidx(1).
|
||||
-- @param screen The screen number.
|
||||
function viewnext(screen)
|
||||
return viewidx(1, screen)
|
||||
end
|
||||
|
||||
--- View previous tag. This is the same a tag.viewidx(-1).
|
||||
-- @param screen The screen number.
|
||||
function viewprev(screen)
|
||||
return viewidx(-1, screen)
|
||||
end
|
||||
|
||||
--- View only a tag.
|
||||
-- @param t The tag object.
|
||||
function viewonly(t)
|
||||
local tags = capi.screen[t.screen]:tags()
|
||||
-- First, untag everyone except the viewed tag.
|
||||
for _, tag in pairs(tags) do
|
||||
if tag ~= t then
|
||||
tag.selected = false
|
||||
end
|
||||
end
|
||||
-- Then, set this one to selected.
|
||||
-- We need to do that in 2 operations so we avoid flickering and several tag
|
||||
-- selected at the same time.
|
||||
t.selected = true
|
||||
capi.screen[t.screen]:emit_signal("tag::history::update")
|
||||
end
|
||||
|
||||
--- View only a set of tags.
|
||||
-- @param tags A table with tags to view only.
|
||||
-- @param screen Optional screen number of the tags.
|
||||
function viewmore(tags, screen)
|
||||
local screen_tags = capi.screen[screen or capi.mouse.screen]:tags()
|
||||
for _, tag in ipairs(screen_tags) do
|
||||
if not util.table.hasitem(tags, tag) then
|
||||
tag.selected = false
|
||||
end
|
||||
end
|
||||
for _, tag in ipairs(tags) do
|
||||
tag.selected = true
|
||||
end
|
||||
capi.screen[screen]:emit_signal("tag::history::update")
|
||||
end
|
||||
|
||||
--- Toggle selection of a tag
|
||||
-- @param tag Tag to be toggled
|
||||
function viewtoggle(t)
|
||||
t.selected = not t.selected
|
||||
capi.screen[t.screen]:emit_signal("tag::history::update")
|
||||
end
|
||||
|
||||
--- Get tag data table.
|
||||
-- @param tag The Tag.
|
||||
-- @return The data table.
|
||||
function getdata(tag)
|
||||
return data.tags[tag]
|
||||
end
|
||||
|
||||
--- Get a tag property.
|
||||
-- @param tag The tag.
|
||||
-- @param prop The property name.
|
||||
-- @return The property.
|
||||
function getproperty(tag, prop)
|
||||
if data.tags[tag] then
|
||||
return data.tags[tag][prop]
|
||||
end
|
||||
end
|
||||
|
||||
--- Set a tag property.
|
||||
-- This properties are internal to awful. Some are used to draw taglist, or to
|
||||
-- handle layout, etc.
|
||||
-- @param tag The tag.
|
||||
-- @param prop The property name.
|
||||
-- @param value The value.
|
||||
function setproperty(tag, prop, value)
|
||||
if not data.tags[tag] then
|
||||
data.tags[tag] = {}
|
||||
end
|
||||
data.tags[tag][prop] = value
|
||||
tag:emit_signal("property::" .. prop)
|
||||
end
|
||||
|
||||
--- Tag a client with the set of current tags.
|
||||
-- @param c The client to tag.
|
||||
-- @param startup Optional: don't do anything if true.
|
||||
function withcurrent(c, startup)
|
||||
if startup ~= true and c.sticky == false then
|
||||
if #c:tags() == 0 then
|
||||
c:tags(selectedlist(c.screen))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function attached_add_signal_screen(screen, sig, func)
|
||||
capi.screen[screen]:add_signal("tag::attach", function (s, tag)
|
||||
tag:add_signal(sig, func)
|
||||
end)
|
||||
capi.screen[screen]:add_signal("tag::detach", function (s, tag)
|
||||
tag:remove_signal(sig, func)
|
||||
end)
|
||||
for _, tag in ipairs(capi.screen[screen]:tags()) do
|
||||
tag:add_signal(sig, func)
|
||||
end
|
||||
end
|
||||
|
||||
--- Add a signal to all attached tag and all tag that will be attached in the
|
||||
-- future. When a tag is detach from the screen, its signal is removed.
|
||||
-- @param screen The screen concerned, or all if nil.
|
||||
function attached_add_signal(screen, ...)
|
||||
if screen then
|
||||
attached_add_signal_screen(screen, ...)
|
||||
else
|
||||
for screen = 1, capi.screen.count() do
|
||||
attached_add_signal_screen(screen, ...)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Register standards signals
|
||||
capi.client.add_signal("manage", function(c, startup)
|
||||
-- If we are not managing this application at startup,
|
||||
-- move it to the screen where the mouse is.
|
||||
-- We only do it for "normal" windows (i.e. no dock, etc).
|
||||
if not startup
|
||||
and c.type ~= "desktop"
|
||||
and c.type ~= "dock"
|
||||
and c.type ~= "splash" then
|
||||
if c.transient_for then
|
||||
c.screen = c.transient_for.screen
|
||||
if not c.sticky then
|
||||
c:tags(c.transient_for:tags())
|
||||
end
|
||||
else
|
||||
c.screen = capi.mouse.screen
|
||||
end
|
||||
end
|
||||
c:add_signal("property::screen", withcurrent)
|
||||
end)
|
||||
|
||||
capi.client.add_signal("manage", withcurrent)
|
||||
|
||||
for s = 1, capi.screen.count() do
|
||||
capi.screen[s]:add_signal("tag::history::update", history.update)
|
||||
end
|
||||
|
||||
setmetatable(_M, { __call = function (_, ...) return new(...) end })
|
||||
|
||||
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80
|
@ -0,0 +1,421 @@
|
||||
---------------------------------------------------------------------------
|
||||
-- @author Julien Danjou <julien@danjou.info>
|
||||
-- @copyright 2008 Julien Danjou
|
||||
-- @release v3.4.10
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
-- Grab environment we need
|
||||
local math = math
|
||||
local image = image
|
||||
local pairs = pairs
|
||||
local type = type
|
||||
local setmetatable = setmetatable
|
||||
local type = type
|
||||
local capi =
|
||||
{
|
||||
awesome = awesome,
|
||||
wibox = wibox,
|
||||
widget = widget,
|
||||
client = client,
|
||||
}
|
||||
local abutton = require("awful.button")
|
||||
local beautiful = require("beautiful")
|
||||
local util = require("awful.util")
|
||||
local widget = require("awful.widget")
|
||||
local mouse = require("awful.mouse")
|
||||
local client = require("awful.client")
|
||||
local layout = require("awful.widget.layout")
|
||||
|
||||
--- Titlebar module for awful
|
||||
module("awful.titlebar")
|
||||
|
||||
-- Privata data
|
||||
local data = setmetatable({}, { __mode = 'k' })
|
||||
|
||||
-- Predeclaration for buttons
|
||||
local button_groups
|
||||
|
||||
local function button_callback_focus_raise_move(w, t)
|
||||
capi.client.focus = t.client
|
||||
t.client:raise()
|
||||
mouse.client.move(t.client)
|
||||
end
|
||||
|
||||
local function button_callback_move(w, t)
|
||||
return mouse.client.move(t.client)
|
||||
end
|
||||
|
||||
local function button_callback_resize(w, t)
|
||||
return mouse.client.resize(t.client)
|
||||
end
|
||||
|
||||
--- Create a standard titlebar.
|
||||
-- @param c The client.
|
||||
-- @param args Arguments.
|
||||
-- modkey: the modkey used for the bindings.
|
||||
-- fg: the foreground color.
|
||||
-- bg: the background color.
|
||||
-- fg_focus: the foreground color for focused window.
|
||||
-- fg_focus: the background color for focused window.
|
||||
-- width: the titlebar width
|
||||
function add(c, args)
|
||||
if not c or (c.type ~= "normal" and c.type ~= "dialog") then return end
|
||||
if not args then args = {} end
|
||||
if not args.height then args.height = capi.awesome.font_height * 1.5 end
|
||||
local theme = beautiful.get()
|
||||
if not args.widget then customwidget = {} else customwidget = args.widget end
|
||||
-- Store colors
|
||||
data[c] = {}
|
||||
data[c].fg = args.fg or theme.titlebar_fg_normal or theme.fg_normal
|
||||
data[c].bg = args.bg or theme.titlebar_bg_normal or theme.bg_normal
|
||||
data[c].fg_focus = args.fg_focus or theme.titlebar_fg_focus or theme.fg_focus
|
||||
data[c].bg_focus = args.bg_focus or theme.titlebar_bg_focus or theme.bg_focus
|
||||
data[c].width = args.width
|
||||
data[c].font = args.font or theme.titlebar_font or theme.font
|
||||
|
||||
local tb = capi.wibox(args)
|
||||
|
||||
local title = capi.widget({ type = "textbox" })
|
||||
if c.name then
|
||||
title.text = "<span font_desc='" .. data[c].font .. "'> " ..
|
||||
util.escape(c.name) .. " </span>"
|
||||
end
|
||||
|
||||
-- Redirect relevant events to the client the titlebar belongs to
|
||||
local bts = util.table.join(
|
||||
abutton({ }, 1, button_callback_focus_raise_move),
|
||||
abutton({ args.modkey }, 1, button_callback_move),
|
||||
abutton({ args.modkey }, 3, button_callback_resize))
|
||||
title:buttons(bts)
|
||||
|
||||
local appicon = capi.widget({ type = "imagebox" })
|
||||
appicon.image = c.icon
|
||||
|
||||
-- for each button group, call create for the client.
|
||||
-- if a button set is created add the set to the
|
||||
-- data[c].button_sets for late updates and add the
|
||||
-- individual buttons to the array part of the widget
|
||||
-- list
|
||||
local widget_list = {
|
||||
layout = layout.horizontal.rightleft
|
||||
}
|
||||
local iw = 1
|
||||
local is = 1
|
||||
data[c].button_sets = {}
|
||||
for i = 1, #button_groups do
|
||||
local set = button_groups[i].create(c, args.modkey, theme)
|
||||
if (set) then
|
||||
data[c].button_sets[is] = set
|
||||
is = is + 1
|
||||
for n,b in pairs(set) do
|
||||
widget_list[iw] = b
|
||||
iw = iw + 1
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
tb.widgets = {
|
||||
widget_list,
|
||||
customwidget,
|
||||
{
|
||||
appicon = appicon,
|
||||
title = title,
|
||||
layout = layout.horizontal.flex
|
||||
},
|
||||
layout = layout.horizontal.rightleft
|
||||
}
|
||||
|
||||
c.titlebar = tb
|
||||
|
||||
c:add_signal("property::icon", update)
|
||||
c:add_signal("property::name", update)
|
||||
c:add_signal("property::sticky", update)
|
||||
c:add_signal("property::floating", update)
|
||||
c:add_signal("property::ontop", update)
|
||||
c:add_signal("property::maximized_vertical", update)
|
||||
c:add_signal("property::maximized_horizontal", update)
|
||||
update(c)
|
||||
end
|
||||
|
||||
--- Update a titlebar. This should be called in some hooks.
|
||||
-- @param c The client to update.
|
||||
-- @param prop The property name which has changed.
|
||||
function update(c)
|
||||
if c.titlebar and data[c] then
|
||||
local widgets = c.titlebar.widgets
|
||||
if widgets[3].title then
|
||||
widgets[3].title.text = "<span font_desc='" .. data[c].font ..
|
||||
"'> ".. util.escape(c.name or "<unknown>") .. " </span>"
|
||||
end
|
||||
if widgets[3].appicon then
|
||||
widgets[3].appicon.image = c.icon
|
||||
end
|
||||
if capi.client.focus == c then
|
||||
c.titlebar.fg = data[c].fg_focus
|
||||
c.titlebar.bg = data[c].bg_focus
|
||||
else
|
||||
c.titlebar.fg = data[c].fg
|
||||
c.titlebar.bg = data[c].bg
|
||||
end
|
||||
|
||||
-- iterated of all registered button_sets and update
|
||||
local sets = data[c].button_sets
|
||||
for i = 1, #sets do
|
||||
sets[i].update(c,prop)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--- Remove a titlebar from a client.
|
||||
-- @param c The client.
|
||||
function remove(c)
|
||||
c.titlebar = nil
|
||||
data[c] = nil
|
||||
end
|
||||
|
||||
-- Create a new button for the toolbar
|
||||
-- @param c The client of the titlebar
|
||||
-- @param name The base name of the button (i.e. close)
|
||||
-- @param modkey ... you know that one, don't you?
|
||||
-- @param theme The theme from beautifull. Used to get the image paths
|
||||
-- @param state The state the button is associated to. Containse path the action and info about the image
|
||||
local function button_new(c, name, modkey, theme, state)
|
||||
local bts = abutton({ }, 1, nil, state.action)
|
||||
|
||||
-- get the image path from the theme. Only return a button if we find an image
|
||||
local img
|
||||
img = "titlebar_" .. name .. "_button_" .. state.img
|
||||
img = theme[img]
|
||||
if not img then return end
|
||||
img = image(img)
|
||||
if not img then return end
|
||||
|
||||
-- now create the button
|
||||
local bname = name .. "_" .. state.idx
|
||||
local button = widget.button({ image = img })
|
||||
if not button then return end
|
||||
local rbts = button:buttons()
|
||||
|
||||
for k, v in pairs(rbts) do
|
||||
bts[#bts + 1] = v
|
||||
end
|
||||
|
||||
button:buttons(bts)
|
||||
button.visible = false
|
||||
return button
|
||||
end
|
||||
|
||||
-- Update the buttons in a button group
|
||||
-- @param s The button group to update
|
||||
-- @param c The client of the titlebar
|
||||
-- @param p The property that has changed
|
||||
local function button_group_update(s,c,p)
|
||||
-- hide the currently active button, get the new state and show the new button
|
||||
local n = s.select_state(c,p)
|
||||
if n == nil then return end
|
||||
if (s.active ~= nil) then s.active.visible = false end
|
||||
s.active = s.buttons[n]
|
||||
s.active.visible = true
|
||||
end
|
||||
|
||||
-- Create all buttons in a group
|
||||
-- @param c The client of the titlebar
|
||||
-- @param group The button group to create the buttons for
|
||||
-- @param modkey ...
|
||||
-- @param theme Theme for the image paths
|
||||
local function button_group_create(c, group, modkey, theme )
|
||||
local s = {}
|
||||
s.name = group.name
|
||||
s.select_state = group.select_state
|
||||
s.buttons = {
|
||||
layout = layout.horizontal.rightleft
|
||||
}
|
||||
for n,state in pairs(group.states) do
|
||||
s.buttons[n] = button_new(c, s.name, modkey, theme, state)
|
||||
if (s.buttons[n] == nil) then return end
|
||||
for a,v in pairs(group.attributes) do
|
||||
s.buttons[n][a] = v
|
||||
end
|
||||
end
|
||||
function s.update(c,p) button_group_update(s,c,p) end
|
||||
return s
|
||||
end
|
||||
|
||||
-- Builds a new button group
|
||||
-- @param name The base name for the buttons in the group (i.e. "close")
|
||||
-- @param attrs Common attributes for the buttons (i.e. {align = "right")
|
||||
-- @param sfn State select function.
|
||||
-- @param args The states of the button
|
||||
local function button_group(name, attrs, sfn, ...)
|
||||
local s = {}
|
||||
s.name = name
|
||||
s.select_state = sfn
|
||||
s.attributes = attrs
|
||||
s.states = {}
|
||||
|
||||
for i, state in pairs({...}) do
|
||||
s.states[state.idx] = state
|
||||
end
|
||||
|
||||
function s.create(c,modkey, theme) return button_group_create(c,s,modkey, theme) end
|
||||
return s
|
||||
end
|
||||
|
||||
-- Select a state for a client based on an attribute of the client and whether it has focus
|
||||
-- @param c The client of the titlebar
|
||||
-- @param p The property that has changed
|
||||
-- @param a The property to check
|
||||
local function select_state(c,p,a)
|
||||
if (c == nil) then return "n/i" end
|
||||
if capi.client.focus == c then
|
||||
if c[a] then
|
||||
return "f/a"
|
||||
else
|
||||
return "f/i"
|
||||
end
|
||||
else
|
||||
if c[a] then
|
||||
return "n/a"
|
||||
else
|
||||
return "n/i"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Select a state for a client based on whether it's floating or not
|
||||
-- @param c The client of the titlebar
|
||||
-- @param p The property that has changed
|
||||
local function select_state_floating(c,p)
|
||||
if not c then return end
|
||||
if capi.client.focus == c then
|
||||
if client.floating.get(c) then
|
||||
return "f/a"
|
||||
end
|
||||
return "f/i"
|
||||
end
|
||||
if client.floating.get(c) then
|
||||
return "n/a"
|
||||
end
|
||||
return "n/i"
|
||||
end
|
||||
|
||||
-- Select a state for a client based on whether it's maximized or not
|
||||
-- @param c The client of the titlebar
|
||||
-- @param p The property that has changed
|
||||
local function select_state_maximized(c,p)
|
||||
if (c == nil) then return "n/i" end
|
||||
if capi.client.focus == c then
|
||||
if c.maximized_horizontal or c.maximized_vertical then
|
||||
return "f/a"
|
||||
else
|
||||
return "f/i"
|
||||
end
|
||||
else
|
||||
if c.maximized_horizontal or c.maximized_vertical then
|
||||
return "n/a"
|
||||
else
|
||||
return "n/i"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Select a state for a client based on whether it has focus or not
|
||||
-- @param c The client of the titlebar
|
||||
-- @param p The property that has changed
|
||||
local function select_state_focus(c,p)
|
||||
if c and capi.client.focus == c then
|
||||
return "f"
|
||||
end
|
||||
return "n"
|
||||
end
|
||||
|
||||
-- These are the predefined button groups
|
||||
-- A short explanation using 'close_buttons' as an example:
|
||||
-- "close" : name of the button, the images for this button are taken from the
|
||||
-- theme variables titlebar_close_button_...
|
||||
-- { align ... : attributes of all the buttons
|
||||
-- select_state_focus : This function returns a short string used to describe
|
||||
-- the state. In this case either "n" or "f" depending on
|
||||
-- the focus state of the client. These strings can be
|
||||
-- choosen freely but the< must match one of the idx fuekds
|
||||
-- of the states below
|
||||
-- { idx = "n" ... : This is the state of the button for the 'unfocussed'
|
||||
-- (normal) state. The idx = "n" parameter connects this
|
||||
-- button to the return value of the 'select_state_focus'
|
||||
-- function. The img = "normal" parameter is used to
|
||||
-- determine its image. In this case the iamge is taken from
|
||||
-- the theme variable "titlebar_close_button_normal".
|
||||
-- Finally the last parameter is the action for mouse
|
||||
-- button 1
|
||||
|
||||
local ontop_buttons = button_group("ontop",
|
||||
{ align = "right" },
|
||||
function(c,p) return select_state(c, p, "ontop") end,
|
||||
{ idx = "n/i", img = "normal_inactive",
|
||||
action = function(w, t) t.client.ontop = true end },
|
||||
{ idx = "f/i", img = "focus_inactive",
|
||||
action = function(w, t) t.client.ontop = true end },
|
||||
{ idx = "n/a", img = "normal_active",
|
||||
action = function(w, t) t.client.ontop = false end },
|
||||
{ idx = "f/a", img = "focus_active",
|
||||
action = function(w, t) t.client.ontop = false end })
|
||||
|
||||
local sticky_buttons = button_group("sticky",
|
||||
{ align = "right" },
|
||||
function(c,p) return select_state(c,p,"sticky") end,
|
||||
{ idx = "n/i", img = "normal_inactive",
|
||||
action = function(w, t) t.client.sticky = true end },
|
||||
{ idx = "f/i", img = "focus_inactive",
|
||||
action = function(w, t) t.client.sticky = true end },
|
||||
{ idx = "n/a", img = "normal_active",
|
||||
action = function(w, t) t.client.sticky = false end },
|
||||
{ idx = "f/a", img = "focus_active",
|
||||
action = function(w, t) t.client.sticky = false end })
|
||||
|
||||
local maximized_buttons = button_group("maximized",
|
||||
{ align = "right" },
|
||||
select_state_maximized,
|
||||
{ idx = "n/i", img = "normal_inactive",
|
||||
action = function(w, t) t.client.maximized_horizontal = true
|
||||
t.client.maximized_vertical = true end },
|
||||
{ idx = "f/i", img = "focus_inactive",
|
||||
action = function(w, t) t.client.maximized_horizontal = true
|
||||
t.client.maximized_vertical = true end },
|
||||
{ idx = "n/a", img = "normal_active",
|
||||
action = function(w, t) t.client.maximized_horizontal = false
|
||||
t.client.maximized_vertical = false end },
|
||||
{ idx = "f/a", img = "focus_active",
|
||||
action = function(w, t) t.client.maximized_horizontal = false
|
||||
t.client.maximized_vertical = false end })
|
||||
|
||||
local close_buttons = button_group("close",
|
||||
{ align = "left" },
|
||||
select_state_focus,
|
||||
{ idx = "n", img = "normal",
|
||||
action = function (w, t) t.client:kill() end },
|
||||
{ idx = "f", img = "focus",
|
||||
action = function (w, t) t.client:kill() end })
|
||||
|
||||
local function floating_update(w, t)
|
||||
client.floating.toggle(t.client)
|
||||
end
|
||||
|
||||
local floating_buttons = button_group("floating",
|
||||
{ align = "right"},
|
||||
select_state_floating,
|
||||
{ idx = "n/i", img = "normal_inactive", action = floating_update },
|
||||
{ idx = "f/i", img = "focus_inactive", action = floating_update },
|
||||
{ idx = "n/a", img = "normal_active", action = floating_update },
|
||||
{ idx = "f/a", img = "focus_active", action = floating_update })
|
||||
|
||||
button_groups = { close_buttons,
|
||||
ontop_buttons,
|
||||
sticky_buttons,
|
||||
maximized_buttons,
|
||||
floating_buttons }
|
||||
|
||||
-- Register standards hooks
|
||||
capi.client.add_signal("focus", update)
|
||||
capi.client.add_signal("unfocus", update)
|
||||
|
||||
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80
|
@ -0,0 +1,233 @@
|
||||
-------------------------------------------------------------------------
|
||||
-- @author Sébastien Gross <seb•ɱɩɲʋʃ•awesome•ɑƬ•chezwam•ɖɵʈ•org>
|
||||
-- @copyright 2009 Sébastien Gross
|
||||
-- @release v3.4.10
|
||||
-------------------------------------------------------------------------
|
||||
|
||||
local mouse = mouse
|
||||
local widget = widget
|
||||
local wibox = wibox
|
||||
local screen = screen
|
||||
local timer = timer
|
||||
local a_placement = require("awful.placement")
|
||||
local beautiful = require("beautiful")
|
||||
local setmetatable = setmetatable
|
||||
local ipairs = ipairs
|
||||
|
||||
--- Tooltip module for awesome objects.
|
||||
-- A tooltip is a small hint displayed when the mouse cursor
|
||||
-- hovers a specific item.
|
||||
-- In awesome, a tooltip can be linked with almost any
|
||||
-- object having a <code>add_signal()</code> method and receiving
|
||||
-- <code>mouse::enter</code> and <code>mouse::leave</code> signals.
|
||||
-- <p>How to create a tooltip?<br/>
|
||||
-- <code>
|
||||
-- myclock = awful.widget.textclock({}, "%T", 1)<br/>
|
||||
-- myclock_t = awful.tooltip({<br/>
|
||||
-- objects = { K },<br/>
|
||||
-- timer_function = function()<br/>
|
||||
-- return os.date("Today is %A %B %d %Y\nThe time is %T")<br/>
|
||||
-- end,<br/>
|
||||
-- })<br/>
|
||||
-- </code>
|
||||
-- </p>
|
||||
-- <p>How to add the same tooltip to several objects?<br/>
|
||||
-- <code>
|
||||
-- myclock_t:add_to_object(obj1)<br/>
|
||||
-- myclock_t:add_to_object(obj2)<br/>
|
||||
-- </code>
|
||||
-- Now the same tooltip is attached to <code>K</code>, <code>obj1</code>,
|
||||
-- <code>obj2</code>.<br/>
|
||||
-- </p>
|
||||
-- <p>How to remove tooltip from many objects?<br/>
|
||||
-- <code>
|
||||
-- myclock_t:remove_from_object(obj1)<br/>
|
||||
-- myclock_t:remove_from_object(obj2)<br/>
|
||||
-- </code>
|
||||
-- Now the same tooltip is only attached to <code>K</code>.<br/>
|
||||
-- </p>
|
||||
module("awful.tooltip")
|
||||
|
||||
local data = setmetatable({}, { __mode = 'k' })
|
||||
|
||||
--- Tooltip object definition.
|
||||
-- @name tooltip
|
||||
-- @field wibox The wibox displaying the tooltip.
|
||||
-- @field visible True if tooltip is visible.
|
||||
-- @class table
|
||||
|
||||
-- Tooltip private data.
|
||||
-- @name awful.tooltip.data
|
||||
-- @field fg tooltip foreground color.
|
||||
-- @field font Tooltip font.
|
||||
-- @field hide The hide() function.
|
||||
-- @field show The show() function.
|
||||
-- @field timer The text update timer.
|
||||
-- @field timer_function The text update timer function.
|
||||
|
||||
-- Place to tooltip on th screen.
|
||||
-- @param self A tooltip object.
|
||||
local function place(self)
|
||||
a_placement.under_mouse(self.wibox)
|
||||
a_placement.no_offscreen(self.wibox)
|
||||
end
|
||||
|
||||
-- Place the tooltip under the mouse.
|
||||
-- @param self A tooltip object.
|
||||
local function set_geometry(self)
|
||||
local my_geo = self.wibox:geometry()
|
||||
-- calculate width / height
|
||||
n_s = self.wibox.widgets[1]:extents()
|
||||
if my_geo.width ~= n_s.width or my_geo.height ~= n_s.height then
|
||||
self.wibox:geometry(n_s)
|
||||
place(self)
|
||||
end
|
||||
if not self.wibox.visible then
|
||||
place(self)
|
||||
end
|
||||
end
|
||||
|
||||
-- Show a tooltip.
|
||||
-- @param self The tooltip to show.
|
||||
local function show(self)
|
||||
-- do nothing if the tooltip is already shown
|
||||
if self.visible then return end
|
||||
-- make sure the tooltip is on the same screen as the mouse
|
||||
self.wibox.screen = mouse.screen
|
||||
if data[self].timer then
|
||||
if not data[self].timer.started then
|
||||
data[self].timer_function()
|
||||
data[self].timer:start()
|
||||
end
|
||||
end
|
||||
set_geometry(self)
|
||||
self.wibox.visible = true
|
||||
self.visible = true
|
||||
end
|
||||
|
||||
-- Hide a tooltip.
|
||||
-- @param self The tooltip to hide.
|
||||
local function hide(self)
|
||||
-- do nothing if the tooltip is already hidden
|
||||
if not self.visible then return end
|
||||
if data[self].timer then
|
||||
if data[self].timer.started then
|
||||
data[self].timer:stop()
|
||||
end
|
||||
end
|
||||
self.visible = false
|
||||
self.wibox.visible = false
|
||||
end
|
||||
|
||||
--- Change displayed text.
|
||||
-- @param self The tooltip object.
|
||||
-- @param text New tooltip text.
|
||||
local function set_text(self, text)
|
||||
self.wibox.widgets[1].text = '<span color="' .. data[self].fg
|
||||
.. '" font_desc="' .. data[self].font .. '">' .. text .. "</span>"
|
||||
end
|
||||
|
||||
--- Change the tooltip's update interval.
|
||||
-- @param self A tooltip object.
|
||||
-- @param timeout The timeout value.
|
||||
local function set_timeout(self, timeout)
|
||||
if data[self].timer then
|
||||
data[self].timer.timeout = timeout
|
||||
end
|
||||
end
|
||||
|
||||
-- Load Default values.
|
||||
-- @param self A tooltip object.
|
||||
local function set_defaults(self)
|
||||
self.wibox.border_width = beautiful.tooltip_border_width or beautiful.border_width or 1
|
||||
self.wibox.border_color = beautiful.tooltip_border_color or beautiful.border_normal or "#ffcb60"
|
||||
self.wibox.opacity = beautiful.tooltip_opacity or 1
|
||||
self.wibox.bg = beautiful.tooltip_bg_color or beautiful.bg_focus or "#ffcb60"
|
||||
data[self].fg = beautiful.tooltip_fg_color or beautiful.fg_focus or "#000000"
|
||||
data[self].font = beautiful.tooltip_font or beautiful.font or "terminus 6"
|
||||
end
|
||||
|
||||
--- Add tooltip to an object.
|
||||
-- @param self The tooltip.
|
||||
-- @param object An object.
|
||||
local function add_to_object(self, object)
|
||||
object:add_signal("mouse::enter", data[self].show)
|
||||
object:add_signal("mouse::leave", data[self].hide)
|
||||
end
|
||||
|
||||
--- Remove tooltip from an object.
|
||||
-- @param self The tooltip.
|
||||
-- @param object An object.
|
||||
local function remove_from_object(self, object)
|
||||
object:remove_signal("mouse::enter", data[self].show)
|
||||
object:remove_signal("mouse::leave", data[self].hide)
|
||||
end
|
||||
|
||||
|
||||
--- Create a new tooltip and link it to a widget.
|
||||
-- @param args Arguments for tooltip creation may containt:<br/>
|
||||
-- <code>timeout</code>: The timeout value for update_func.<br/>
|
||||
-- <code>timer_function</code>: A function to dynamicaly change the tooltip
|
||||
-- text.<br/>
|
||||
-- <code>objects</code>: A list of objects linked to the tooltip.<br/>
|
||||
-- @return The created tooltip.
|
||||
-- @see add_to_object
|
||||
-- @see set_timeout
|
||||
-- @see set_text
|
||||
local function new(args)
|
||||
local self = {
|
||||
wibox = wibox({ }),
|
||||
visible = false,
|
||||
}
|
||||
|
||||
local my_textbox = widget({
|
||||
type = "textbox",
|
||||
name = "tooltip_textbox",
|
||||
align="right"})
|
||||
|
||||
-- private data
|
||||
data[self] = {
|
||||
show = function() show(self) end,
|
||||
hide = function() hide(self) end
|
||||
}
|
||||
|
||||
-- export functions
|
||||
self.set_text = set_text
|
||||
self.set_timeout = set_timeout
|
||||
self.add_to_object = add_to_object
|
||||
self.remove_from_object = remove_from_object
|
||||
|
||||
set_defaults(self)
|
||||
|
||||
-- setup the timer action only if needed
|
||||
if args.timer_function then
|
||||
data[self].timer = timer { timeout = args.timeout and args.timeout or 1 }
|
||||
data[self].timer_function = function()
|
||||
self:set_text(args.timer_function())
|
||||
set_geometry(self)
|
||||
end
|
||||
data[self].timer:add_signal("timeout", data[self].timer_function)
|
||||
end
|
||||
|
||||
-- set tooltip properties
|
||||
self.wibox.visible = false
|
||||
-- Who want a non ontop tooltip ?
|
||||
self.wibox.ontop = true
|
||||
self.wibox.widgets = { my_textbox }
|
||||
|
||||
-- add some signals on both the tooltip and widget
|
||||
self.wibox:add_signal("mouse::enter", data[self].hide)
|
||||
|
||||
-- Add tooltip to objects
|
||||
if args.objects then
|
||||
for _, object in ipairs(args.objects) do
|
||||
self:add_to_object(object)
|
||||
end
|
||||
end
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
setmetatable(_M, { __call = function(_, ...) return new(...) end })
|
||||
|
||||
-- vim: ft=lua:et:sw=4:ts=4:sts=4:enc=utf-8:tw=78
|
347
DUFRESNE/Linux/home/burchettm/.config/awesome/lib/awful/util.lua
Normal file
347
DUFRESNE/Linux/home/burchettm/.config/awesome/lib/awful/util.lua
Normal file
@ -0,0 +1,347 @@
|
||||
---------------------------------------------------------------------------
|
||||
-- @author Julien Danjou <julien@danjou.info>
|
||||
-- @copyright 2008 Julien Danjou
|
||||
-- @release v3.4.10
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
-- Grab environment we need
|
||||
local os = os
|
||||
local io = io
|
||||
local assert = assert
|
||||
local loadstring = loadstring
|
||||
local loadfile = loadfile
|
||||
local debug = debug
|
||||
local pairs = pairs
|
||||
local ipairs = ipairs
|
||||
local type = type
|
||||
local rtable = table
|
||||
local pairs = pairs
|
||||
local string = string
|
||||
local capi =
|
||||
{
|
||||
awesome = awesome,
|
||||
mouse = mouse
|
||||
}
|
||||
|
||||
--- Utility module for awful
|
||||
module("awful.util")
|
||||
|
||||
table = {}
|
||||
|
||||
shell = os.getenv("SHELL") or "/bin/sh"
|
||||
|
||||
function deprecate(see)
|
||||
io.stderr:write("W: awful: function is deprecated")
|
||||
if see then
|
||||
io.stderr:write(", see " .. see)
|
||||
end
|
||||
io.stderr:write("\n")
|
||||
io.stderr:write(debug.traceback())
|
||||
end
|
||||
|
||||
--- Strip alpha part of color.
|
||||
-- @param color The color.
|
||||
-- @return The color without alpha channel.
|
||||
function color_strip_alpha(color)
|
||||
if color:len() == 9 then
|
||||
color = color:sub(1, 7)
|
||||
end
|
||||
return color
|
||||
end
|
||||
|
||||
--- Make i cycle.
|
||||
-- @param t A length.
|
||||
-- @param i An absolute index to fit into #t.
|
||||
-- @return The object at new index.
|
||||
function cycle(t, i)
|
||||
while i > t do i = i - t end
|
||||
while i < 1 do i = i + t end
|
||||
return i
|
||||
end
|
||||
|
||||
--- Create a directory
|
||||
-- @param dir The directory.
|
||||
-- @return mkdir return code
|
||||
function mkdir(dir)
|
||||
return os.execute("mkdir -p " .. dir)
|
||||
end
|
||||
|
||||
--- Spawn a program.
|
||||
-- @param cmd The command.
|
||||
-- @param sn Enable startup-notification.
|
||||
-- @param screen The screen where to spawn window.
|
||||
-- @return The awesome.spawn return value.
|
||||
function spawn(cmd, sn, screen)
|
||||
if cmd and cmd ~= "" then
|
||||
if sn == nil then sn = true end
|
||||
return capi.awesome.spawn(cmd, sn, screen or capi.mouse.screen)
|
||||
end
|
||||
end
|
||||
|
||||
--- Spawn a program using the shell.
|
||||
-- @param cmd The command.
|
||||
-- @param screen The screen where to run the command.
|
||||
function spawn_with_shell(cmd, screen)
|
||||
if cmd and cmd ~= "" then
|
||||
cmd = shell .. " -c \"" .. cmd .. "\""
|
||||
return capi.awesome.spawn(cmd, false, screen or capi.mouse.screen)
|
||||
end
|
||||
end
|
||||
|
||||
--- Read a program output and returns its output as a string.
|
||||
-- @param cmd The command to run.
|
||||
-- @return A string with the program output, or the error if one occured.
|
||||
function pread(cmd)
|
||||
if cmd and cmd ~= "" then
|
||||
local f, err = io.popen(cmd, 'r')
|
||||
if f then
|
||||
local s = f:read("*all")
|
||||
f:close()
|
||||
return s
|
||||
else
|
||||
return err
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--- Eval Lua code.
|
||||
-- @return The return value of Lua code.
|
||||
function eval(s)
|
||||
return assert(loadstring(s))()
|
||||
end
|
||||
|
||||
local xml_entity_names = { ["'"] = "'", ["\""] = """, ["<"] = "<", [">"] = ">", ["&"] = "&" };
|
||||
--- Escape a string from XML char.
|
||||
-- Useful to set raw text in textbox.
|
||||
-- @param text Text to escape.
|
||||
-- @return Escape text.
|
||||
function escape(text)
|
||||
return text and text:gsub("['&<>\"]", xml_entity_names) or nil
|
||||
end
|
||||
|
||||
local xml_entity_chars = { lt = "<", gt = ">", nbsp = " ", quot = "\"", apos = "'", ndash = "-", mdash = "-", amp = "&" };
|
||||
--- Unescape a string from entities.
|
||||
-- @param text Text to unescape.
|
||||
-- @return Unescaped text.
|
||||
function unescape(text)
|
||||
return text and text:gsub("&(%a+);", xml_entity_chars) or nil
|
||||
end
|
||||
|
||||
--- Check if a file is a Lua valid file.
|
||||
-- This is done by loading the content and compiling it with loadfile().
|
||||
-- @param path The file path.
|
||||
-- @return A function if everything is alright, a string with the error
|
||||
-- otherwise.
|
||||
function checkfile(path)
|
||||
local f, e = loadfile(path)
|
||||
-- Return function if function, otherwise return error.
|
||||
if f then return f end
|
||||
return e
|
||||
end
|
||||
|
||||
--- Try to restart awesome.
|
||||
-- It checks if the configuration file is valid, and then restart if it's ok.
|
||||
-- If it's not ok, the error will be returned.
|
||||
-- @return Never return if awesome restart, or return a string error.
|
||||
function restart()
|
||||
local c = checkfile(capi.awesome.conffile)
|
||||
|
||||
if type(c) ~= "function" then
|
||||
return c
|
||||
end
|
||||
|
||||
capi.awesome.restart()
|
||||
end
|
||||
|
||||
--- Get the user's config or cache dir.
|
||||
-- It first checks XDG_CONFIG_HOME / XDG_CACHE_HOME, but then goes with the
|
||||
-- default paths.
|
||||
-- @param d The directory to get (either "config" or "cache").
|
||||
-- @return A string containing the requested path.
|
||||
function getdir(d)
|
||||
if d == "config" then
|
||||
local dir = os.getenv("XDG_CONFIG_HOME")
|
||||
if dir then
|
||||
return dir .. "/awesome"
|
||||
end
|
||||
return os.getenv("HOME") .. "/.config/awesome"
|
||||
elseif d == "cache" then
|
||||
local dir = os.getenv("XDG_CACHE_HOME")
|
||||
if dir then
|
||||
return dir .. "/awesome"
|
||||
end
|
||||
return os.getenv("HOME").."/.cache/awesome"
|
||||
end
|
||||
end
|
||||
|
||||
--- Check if file exists and is readable.
|
||||
-- @param filename The file path
|
||||
-- @return True if file exists and readable.
|
||||
function file_readable(filename)
|
||||
local file = io.open(filename)
|
||||
if file then
|
||||
io.close(file)
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
local function subset_mask_apply(mask, set)
|
||||
local ret = {}
|
||||
for i = 1, #set do
|
||||
if mask[i] then
|
||||
rtable.insert(ret, set[i])
|
||||
end
|
||||
end
|
||||
return ret
|
||||
end
|
||||
|
||||
local function subset_next(mask)
|
||||
local i = 1
|
||||
while i <= #mask and mask[i] do
|
||||
mask[i] = false
|
||||
i = i + 1
|
||||
end
|
||||
|
||||
if i <= #mask then
|
||||
mask[i] = 1
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
--- Return all subsets of a specific set.
|
||||
-- This function, giving a set, will return all subset it.
|
||||
-- For example, if we consider a set with value { 10, 15, 34 },
|
||||
-- it will return a table containing 2^n set:
|
||||
-- { }, { 10 }, { 15 }, { 34 }, { 10, 15 }, { 10, 34 }, etc.
|
||||
-- @param set A set.
|
||||
-- @return A table with all subset.
|
||||
function subsets(set)
|
||||
local mask = {}
|
||||
local ret = {}
|
||||
for i = 1, #set do mask[i] = false end
|
||||
|
||||
-- Insert the empty one
|
||||
rtable.insert(ret, {})
|
||||
|
||||
while subset_next(mask) do
|
||||
rtable.insert(ret, subset_mask_apply(mask, set))
|
||||
end
|
||||
return ret
|
||||
end
|
||||
|
||||
--- Join all tables given as parameters.
|
||||
-- This will iterate all tables and insert all their keys into a new table.
|
||||
-- @param args A list of tables to join
|
||||
-- @return A new table containing all keys from the arguments.
|
||||
function table.join(...)
|
||||
local ret = {}
|
||||
for i, t in ipairs({...}) do
|
||||
if t then
|
||||
for k, v in pairs(t) do
|
||||
if type(k) == "number" then
|
||||
rtable.insert(ret, v)
|
||||
else
|
||||
ret[k] = v
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
return ret
|
||||
end
|
||||
|
||||
--- Check if a table has an item and return its key.
|
||||
-- @param t The table.
|
||||
-- @param item The item to look for in values of the table.
|
||||
-- @return The key were the item is found, or nil if not found.
|
||||
function table.hasitem(t, item)
|
||||
for k, v in pairs(t) do
|
||||
if v == item then
|
||||
return k
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--- Split a string into multiple lines
|
||||
-- @param text String to wrap.
|
||||
-- @param width Maximum length of each line. Default: 72.
|
||||
-- @param indent Number of spaces added before each wrapped line. Default: 0.
|
||||
-- @return The string with lines wrapped to width.
|
||||
function linewrap(text, width, indent)
|
||||
local text = text or ""
|
||||
local width = width or 72
|
||||
local indent = indent or 0
|
||||
|
||||
local pos = 1
|
||||
return text:gsub("(%s+)()(%S+)()",
|
||||
function(sp, st, word, fi)
|
||||
if fi - pos > width then
|
||||
pos = st
|
||||
return "\n" .. string.rep(" ", indent) .. word
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
--- Get a sorted table with all integer keys from a table
|
||||
-- @param t the table for which the keys to get
|
||||
-- @return A table with keys
|
||||
function table.keys(t)
|
||||
local keys = { }
|
||||
for k, _ in pairs(t) do
|
||||
rtable.insert(keys, k)
|
||||
end
|
||||
rtable.sort(keys, function (a, b)
|
||||
return type(a) == type(b) and a < b or false
|
||||
end)
|
||||
return keys
|
||||
end
|
||||
|
||||
--- Filter a tables keys for certain content types
|
||||
-- @param t The table to retrieve the keys for
|
||||
-- @param ... the types to look for
|
||||
-- @return A filtered table with keys
|
||||
function table.keys_filter(t, ...)
|
||||
local keys = table.keys(t)
|
||||
local keys_filtered = { }
|
||||
for _, k in pairs(keys) do
|
||||
for _, et in pairs({...}) do
|
||||
if type(t[k]) == et then
|
||||
rtable.insert(keys_filtered, k)
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
return keys_filtered
|
||||
end
|
||||
|
||||
--- Reverse a table
|
||||
-- @param t the table to reverse
|
||||
-- @return the reversed table
|
||||
function table.reverse(t)
|
||||
local tr = { }
|
||||
-- reverse all elements with integer keys
|
||||
for _, v in ipairs(t) do
|
||||
rtable.insert(tr, 1, v)
|
||||
end
|
||||
-- add the remaining elements
|
||||
for k, v in pairs(t) do
|
||||
if type(k) ~= "number" then
|
||||
tr[k] = v
|
||||
end
|
||||
end
|
||||
return tr
|
||||
end
|
||||
|
||||
--- Clone a table
|
||||
-- @param t the table to clone
|
||||
-- @return a clone of t
|
||||
function table.clone(t)
|
||||
local c = { }
|
||||
for k, v in pairs(t) do
|
||||
c[k] = v
|
||||
end
|
||||
return c
|
||||
end
|
||||
|
||||
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80
|
@ -0,0 +1,345 @@
|
||||
---------------------------------------------------------------------------
|
||||
-- @author Julien Danjou <julien@danjou.info>
|
||||
-- @copyright 2009 Julien Danjou
|
||||
-- @release v3.4.10
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
-- Grab environment we need
|
||||
local capi =
|
||||
{
|
||||
awesome = awesome,
|
||||
screen = screen,
|
||||
wibox = wibox,
|
||||
client = client
|
||||
}
|
||||
local setmetatable = setmetatable
|
||||
local tostring = tostring
|
||||
local ipairs = ipairs
|
||||
local table = table
|
||||
local type = type
|
||||
local image = image
|
||||
local error = error
|
||||
|
||||
--- Wibox module for awful.
|
||||
-- This module allows you to easily create wibox and attach them to the edge of
|
||||
-- a screen.
|
||||
module("awful.wibox")
|
||||
|
||||
-- Array of table with wiboxes inside.
|
||||
-- It's an array so it is ordered.
|
||||
local wiboxes = {}
|
||||
|
||||
--- Get a wibox position if it has been set, or return top.
|
||||
-- @param wibox The wibox
|
||||
-- @return The wibox position.
|
||||
function get_position(wibox)
|
||||
for _, wprop in ipairs(wiboxes) do
|
||||
if wprop.wibox == wibox then
|
||||
return wprop.position
|
||||
end
|
||||
end
|
||||
return "top"
|
||||
end
|
||||
|
||||
--- Put a wibox on a screen at this position.
|
||||
-- @param wibox The wibox to attach.
|
||||
-- @param position The position: top, bottom left or right.
|
||||
-- @param screen If the wibox it not attached to a screen, specified on which
|
||||
-- screen the position should be set.
|
||||
function set_position(wibox, position, screen)
|
||||
local screen = screen or wibox.screen or 1
|
||||
local area = capi.screen[screen].geometry
|
||||
|
||||
-- The "length" of a wibox is always chosen to be the optimal size
|
||||
-- (non-floating).
|
||||
-- The "width" of a wibox is kept if it exists.
|
||||
if position == "right" then
|
||||
wibox.x = area.x + area.width - (wibox.width + 2 * wibox.border_width)
|
||||
elseif position == "left" then
|
||||
wibox.x = area.x
|
||||
elseif position == "bottom" then
|
||||
wibox.y = (area.y + area.height) - (wibox.height + 2 * wibox.border_width)
|
||||
elseif position == "top" then
|
||||
wibox.y = area.y
|
||||
end
|
||||
|
||||
for _, wprop in ipairs(wiboxes) do
|
||||
if wprop.wibox == wibox then
|
||||
wprop.position = position
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Reset all wiboxes positions.
|
||||
local function update_all_wiboxes_position()
|
||||
for _, wprop in ipairs(wiboxes) do
|
||||
set_position(wprop.wibox, wprop.position)
|
||||
end
|
||||
end
|
||||
|
||||
local function call_wibox_position_hook_on_prop_update(w)
|
||||
update_all_wiboxes_position()
|
||||
end
|
||||
|
||||
local function wibox_update_strut(wibox)
|
||||
for _, wprop in ipairs(wiboxes) do
|
||||
if wprop.wibox == wibox then
|
||||
if not wibox.visible then
|
||||
wibox:struts { left = 0, right = 0, bottom = 0, top = 0 }
|
||||
elseif wprop.position == "top" then
|
||||
wibox:struts { left = 0, right = 0, bottom = 0, top = wibox.height + 2 * wibox.border_width }
|
||||
elseif wprop.position == "bottom" then
|
||||
wibox:struts { left = 0, right = 0, bottom = wibox.height + 2 * wibox.border_width, top = 0 }
|
||||
elseif wprop.position == "left" then
|
||||
wibox:struts { left = wibox.width + 2 * wibox.border_width, right = 0, bottom = 0, top = 0 }
|
||||
elseif wprop.position == "right" then
|
||||
wibox:struts { left = 0, right = wibox.width + 2 * wibox.border_width, bottom = 0, top = 0 }
|
||||
end
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--- Attach a wibox to a screen.
|
||||
-- If a wibox is attached, it will be automatically be moved when other wiboxes
|
||||
-- will be attached.
|
||||
-- @param wibox The wibox to attach.
|
||||
-- @param position The position of the wibox: top, bottom, left or right.
|
||||
function attach(wibox, position)
|
||||
-- Store wibox as attached in a weak-valued table
|
||||
local wibox_prop_table
|
||||
-- Start from end since we sometimes remove items
|
||||
for i = #wiboxes, 1, -1 do
|
||||
-- Since wiboxes are stored as weak value, they can disappear.
|
||||
-- If they did, remove their entries
|
||||
if wiboxes[i].wibox == nil then
|
||||
table.remove(wiboxes, i)
|
||||
elseif wiboxes[i].wibox == wibox then
|
||||
wibox_prop_table = wiboxes[i]
|
||||
-- We could break here, but well, let's check if there is no other
|
||||
-- table with their wiboxes been garbage collected.
|
||||
end
|
||||
end
|
||||
|
||||
if not wibox_prop_table then
|
||||
table.insert(wiboxes, setmetatable({ wibox = wibox, position = position }, { __mode = 'v' }))
|
||||
else
|
||||
wibox_prop_table.position = position
|
||||
end
|
||||
|
||||
wibox:add_signal("property::width", wibox_update_strut)
|
||||
wibox:add_signal("property::height", wibox_update_strut)
|
||||
wibox:add_signal("property::visible", wibox_update_strut)
|
||||
|
||||
wibox:add_signal("property::screen", call_wibox_position_hook_on_prop_update)
|
||||
wibox:add_signal("property::width", call_wibox_position_hook_on_prop_update)
|
||||
wibox:add_signal("property::height", call_wibox_position_hook_on_prop_update)
|
||||
wibox:add_signal("property::visible", call_wibox_position_hook_on_prop_update)
|
||||
wibox:add_signal("property::border_width", call_wibox_position_hook_on_prop_update)
|
||||
end
|
||||
|
||||
--- Align a wibox.
|
||||
-- @param wibox The wibox.
|
||||
-- @param align The alignment: left, right or center.
|
||||
-- @param screen If the wibox is not attached to any screen, you can specify the
|
||||
-- screen where to align. Otherwise 1 is assumed.
|
||||
function align(wibox, align, screen)
|
||||
local position = get_position(wibox)
|
||||
local screen = screen or wibox.screen or 1
|
||||
local area = capi.screen[screen].workarea
|
||||
|
||||
if position == "right" then
|
||||
if align == "right" then
|
||||
wibox.y = area.y
|
||||
elseif align == "left" then
|
||||
wibox.y = area.y + area.height - (wibox.height + 2 * wibox.border_width)
|
||||
elseif align == "center" then
|
||||
wibox.y = area.y + (area.height - wibox.height) / 2
|
||||
end
|
||||
elseif position == "left" then
|
||||
if align == "right" then
|
||||
wibox.y = (area.y + area.height) - (wibox.height + 2 * wibox.border_width)
|
||||
elseif align == "left" then
|
||||
wibox.y = area.y
|
||||
elseif align == "center" then
|
||||
wibox.y = area.y + (area.height - wibox.height) / 2
|
||||
end
|
||||
elseif position == "bottom" then
|
||||
if align == "right" then
|
||||
wibox.x = area.x + area.width - (wibox.width + 2 * wibox.border_width)
|
||||
elseif align == "left" then
|
||||
wibox.x = area.x
|
||||
elseif align == "center" then
|
||||
wibox.x = area.x + (area.width - wibox.width) / 2
|
||||
end
|
||||
elseif position == "top" then
|
||||
if align == "right" then
|
||||
wibox.x = area.x + area.width - (wibox.width + 2 * wibox.border_width)
|
||||
elseif align == "left" then
|
||||
wibox.x = area.x
|
||||
elseif align == "center" then
|
||||
wibox.x = area.x + (area.width - wibox.width) / 2
|
||||
end
|
||||
end
|
||||
|
||||
-- Update struts regardless of changes
|
||||
wibox_update_strut(wibox)
|
||||
end
|
||||
|
||||
--- Stretch a wibox so it takes all screen width or height.
|
||||
-- @param wibox The wibox.
|
||||
-- @param screen The screen to stretch on, or the wibox screen.
|
||||
function stretch(wibox, screen)
|
||||
local screen = screen or wibox.screen
|
||||
if screen then
|
||||
local position = get_position(wibox)
|
||||
local area = capi.screen[screen].workarea
|
||||
if position == "right" or position == "left" then
|
||||
wibox.height = area.height - (2 * wibox.border_width)
|
||||
wibox.y = area.y
|
||||
else
|
||||
wibox.width = area.width - (2 * wibox.border_width)
|
||||
wibox.x = area.x
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--- Create a new wibox and attach it to a screen edge.
|
||||
-- @see capi.wibox
|
||||
-- @param args A table with standard arguments to wibox() creator.
|
||||
-- You can add also position key with value top, bottom, left or right.
|
||||
-- You can also use width or height in % and set align to center, right or left.
|
||||
-- You can also set the screen key with a screen number to attach the wibox.
|
||||
-- If not specified, 1 is assumed.
|
||||
-- @return The wibox created.
|
||||
function new(arg)
|
||||
local arg = arg or {}
|
||||
local position = arg.position or "top"
|
||||
local has_to_stretch = true
|
||||
-- Empty position and align in arg so we are passing deprecation warning
|
||||
arg.position = nil
|
||||
|
||||
if position ~= "top" and position ~="bottom"
|
||||
and position ~= "left" and position ~= "right" then
|
||||
error("Invalid position in awful.wibox(), you may only use"
|
||||
.. " 'top', 'bottom', 'left' and 'right'")
|
||||
end
|
||||
|
||||
-- Set default size
|
||||
if position == "left" or position == "right" then
|
||||
arg.width = arg.width or capi.awesome.font_height * 1.5
|
||||
if arg.height then
|
||||
has_to_stretch = false
|
||||
if arg.screen then
|
||||
local hp = tostring(arg.height):match("(%d+)%%")
|
||||
if hp then
|
||||
arg.height = capi.screen[arg.screen].geometry.height * hp / 100
|
||||
end
|
||||
end
|
||||
end
|
||||
else
|
||||
arg.height = arg.height or capi.awesome.font_height * 1.5
|
||||
if arg.width then
|
||||
has_to_stretch = false
|
||||
if arg.screen then
|
||||
local wp = tostring(arg.width):match("(%d+)%%")
|
||||
if wp then
|
||||
arg.width = capi.screen[arg.screen].geometry.width * wp / 100
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local w = capi.wibox(arg)
|
||||
|
||||
if position == "left" then
|
||||
w.orientation = "north"
|
||||
elseif position == "right" then
|
||||
w.orientation = "south"
|
||||
end
|
||||
|
||||
w.screen = arg.screen or 1
|
||||
|
||||
attach(w, position)
|
||||
if has_to_stretch then
|
||||
stretch(w)
|
||||
else
|
||||
align(w, arg.align)
|
||||
end
|
||||
|
||||
set_position(w, position)
|
||||
|
||||
return w
|
||||
end
|
||||
|
||||
local function do_rounded_corners(width, height, corner)
|
||||
local img = image.argb32(width, height, nil)
|
||||
|
||||
-- The image starts completely black which is fully opaque for our use
|
||||
|
||||
local function transp_rect(x, y)
|
||||
img:draw_rectangle(x, y, corner, corner, true, "#ffffff")
|
||||
end
|
||||
local function opaque_circle(x, y)
|
||||
-- x, y are the center of the circle
|
||||
img:draw_circle(x, y, corner, corner, true, "#000000")
|
||||
end
|
||||
|
||||
-- Upper left corner
|
||||
-- First make a 'corner times corner' rectangle transparent
|
||||
transp_rect(0, 0)
|
||||
-- Then add the rounded corner
|
||||
opaque_circle(corner, corner)
|
||||
|
||||
-- Upper right corner
|
||||
transp_rect(width - corner, 0)
|
||||
opaque_circle(width - corner - 1, corner)
|
||||
|
||||
-- Bottom left corner
|
||||
transp_rect(0, height - corner)
|
||||
opaque_circle(corner, height - corner - 1)
|
||||
|
||||
-- Bottom right corner
|
||||
transp_rect(width - corner, height - corner)
|
||||
opaque_circle(width - corner - 1, height - corner - 1)
|
||||
|
||||
return img
|
||||
end
|
||||
|
||||
--- Add rounded corners to a wibox
|
||||
-- @param wibox The wibox.
|
||||
-- @param corner_size The size in pixel of the rounded corners.
|
||||
function rounded_corners(wibox, corner_size)
|
||||
local border = wibox.border_width
|
||||
|
||||
-- Corners can't be larger than half the wibox' space
|
||||
if wibox.width / 2 < corner_size then
|
||||
corner_size = wibox.width / 2
|
||||
end
|
||||
if wibox.height / 2 < corner_size then
|
||||
corner_size = wibox.height / 2
|
||||
end
|
||||
|
||||
wibox.shape_clip = do_rounded_corners(wibox.width, wibox.height, corner_size)
|
||||
wibox.shape_bounding = do_rounded_corners(wibox.width + border * 2, wibox.height + border * 2, corner_size + border)
|
||||
end
|
||||
|
||||
local function update_wiboxes_on_struts(c)
|
||||
local struts = c:struts()
|
||||
if struts.left ~= 0 or struts.right ~= 0
|
||||
or struts.top ~= 0 or struts.bottom ~= 0 then
|
||||
update_all_wiboxes_position()
|
||||
end
|
||||
end
|
||||
|
||||
-- Hook registered to reset all wiboxes position.
|
||||
capi.client.add_signal("manage", function(c)
|
||||
update_wiboxes_on_struts(c)
|
||||
c:add_signal("property::struts", update_wiboxes_on_struts)
|
||||
end)
|
||||
capi.client.add_signal("unmanage", update_wiboxes_on_struts)
|
||||
|
||||
setmetatable(_M, { __call = function(_, ...) return new(...) end })
|
||||
|
||||
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80
|
@ -0,0 +1,45 @@
|
||||
---------------------------------------------------------------------------
|
||||
-- @author Julien Danjou <julien@danjou.info>
|
||||
-- @copyright 2008-2009 Julien Danjou
|
||||
-- @release v3.4.10
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
local setmetatable = setmetatable
|
||||
local type = type
|
||||
local button = require("awful.button")
|
||||
local capi = { image = image,
|
||||
widget = widget,
|
||||
mouse = mouse }
|
||||
|
||||
module("awful.widget.button")
|
||||
|
||||
--- Create a button widget. When clicked, the image is deplaced to make it like
|
||||
-- a real button.
|
||||
-- @param args Standard widget table arguments, plus image for the image path or
|
||||
-- the image object.
|
||||
-- @return A textbox widget configured as a button.
|
||||
function new(args)
|
||||
if not args or not args.image then return end
|
||||
local img_release
|
||||
if type(args.image) == "string" then
|
||||
img_release = capi.image(args.image)
|
||||
elseif type(args.image) == "image" then
|
||||
img_release = args.image
|
||||
else
|
||||
return
|
||||
end
|
||||
local img_press = img_release:crop(-2, -2, img_release.width, img_release.height)
|
||||
args.type = "imagebox"
|
||||
local w = capi.widget(args)
|
||||
w.image = img_release
|
||||
w:buttons(button({}, 1, function () w.image = img_press end, function () w.image = img_release end))
|
||||
w:add_signal("mouse::leave", function () w.image = img_release end)
|
||||
w:add_signal("mouse::enter", function ()
|
||||
if capi.mouse.coords().buttons[1] then w.image = img_press end
|
||||
end)
|
||||
return w
|
||||
end
|
||||
|
||||
setmetatable(_M, { __call = function(_, ...) return new(...) end })
|
||||
|
||||
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80
|
@ -0,0 +1,98 @@
|
||||
---------------------------------------------------------------------------
|
||||
-- @author Julien Danjou <julien@danjou.info>
|
||||
-- @copyright 2008-2009 Julien Danjou
|
||||
-- @release v3.4.10
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
-- Grab environment we need
|
||||
local math = math
|
||||
local type = type
|
||||
local pcall = pcall
|
||||
local ipairs = ipairs
|
||||
local setmetatable = setmetatable
|
||||
local capi = { widget = widget, button = button }
|
||||
|
||||
--- Common widget code
|
||||
module("awful.widget.common")
|
||||
|
||||
-- Private structures
|
||||
tagwidgets = setmetatable({}, { __mode = 'k' })
|
||||
|
||||
function list_update(w, buttons, label, data, widgets, objects)
|
||||
-- Hack: if it has been registered as a widget in a wibox,
|
||||
-- it's w.len since __len meta does not work on table until Lua 5.2.
|
||||
-- Otherwise it's standard #w.
|
||||
local len = (w.len or #w) / 2
|
||||
-- Add more widgets
|
||||
if len < #objects then
|
||||
for i = len * 2 + 1, #objects * 2, 2 do
|
||||
local ib = capi.widget({ type = "imagebox", align = widgets.imagebox.align })
|
||||
local tb = capi.widget({ type = "textbox", align = widgets.textbox.align })
|
||||
|
||||
w[i] = ib
|
||||
w[i + 1] = tb
|
||||
w[i + 1]:margin({ left = widgets.textbox.margin.left, right = widgets.textbox.margin.right })
|
||||
w[i + 1].bg_resize = widgets.textbox.bg_resize or false
|
||||
w[i + 1].bg_align = widgets.textbox.bg_align or ""
|
||||
|
||||
if type(objects[math.floor(i / 2) + 1]) == "tag" then
|
||||
tagwidgets[ib] = objects[math.floor(i / 2) + 1]
|
||||
tagwidgets[tb] = objects[math.floor(i / 2) + 1]
|
||||
end
|
||||
end
|
||||
-- Remove widgets
|
||||
elseif len > #objects then
|
||||
for i = #objects * 2 + 1, len * 2, 2 do
|
||||
w[i] = nil
|
||||
w[i + 1] = nil
|
||||
end
|
||||
end
|
||||
|
||||
-- update widgets text
|
||||
for k = 1, #objects * 2, 2 do
|
||||
local o = objects[(k + 1) / 2]
|
||||
if buttons then
|
||||
-- Use a local variable so that the garbage collector doesn't strike
|
||||
-- between now and the :buttons() call.
|
||||
local btns = data[o]
|
||||
if not btns then
|
||||
btns = {}
|
||||
data[o] = btns
|
||||
for kb, b in ipairs(buttons) do
|
||||
-- Create a proxy button object: it will receive the real
|
||||
-- press and release events, and will propagate them the the
|
||||
-- button object the user provided, but with the object as
|
||||
-- argument.
|
||||
local btn = capi.button { modifiers = b.modifiers, button = b.button }
|
||||
btn:add_signal("press", function () b:emit_signal("press", o) end)
|
||||
btn:add_signal("release", function () b:emit_signal("release", o) end)
|
||||
btns[#btns + 1] = btn
|
||||
end
|
||||
end
|
||||
w[k]:buttons(btns)
|
||||
w[k + 1]:buttons(btns)
|
||||
end
|
||||
|
||||
local text, bg, bg_image, icon = label(o)
|
||||
|
||||
-- Check if we got a valid text here, it might contain e.g. broken utf8.
|
||||
if not pcall(function() w[k + 1].text = text end) then
|
||||
w[k + 1].text = "<i>Invalid</i>"
|
||||
end
|
||||
|
||||
w[k + 1].bg, w[k + 1].bg_image = bg, bg_image
|
||||
w[k].bg, w[k].image = bg, icon
|
||||
if not w[k + 1].text then
|
||||
w[k+1].visible = false
|
||||
else
|
||||
w[k+1].visible = true
|
||||
end
|
||||
if not w[k].image then
|
||||
w[k].visible = false
|
||||
else
|
||||
w[k].visible = true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80
|
@ -0,0 +1,301 @@
|
||||
---------------------------------------------------------------------------
|
||||
-- @author Julien Danjou <julien@danjou.info>
|
||||
-- @copyright 2009 Julien Danjou
|
||||
-- @release v3.4.10
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
local setmetatable = setmetatable
|
||||
local ipairs = ipairs
|
||||
local math = math
|
||||
local table = table
|
||||
local type = type
|
||||
local capi = { image = image,
|
||||
widget = widget }
|
||||
local layout = require("awful.widget.layout")
|
||||
|
||||
--- A graph widget.
|
||||
module("awful.widget.graph")
|
||||
|
||||
local data = setmetatable({}, { __mode = "k" })
|
||||
|
||||
--- Set the graph border color.
|
||||
-- If the value is nil, no border will be drawn.
|
||||
-- @name set_border_color
|
||||
-- @class function
|
||||
-- @param graph The graph.
|
||||
-- @param color The border color to set.
|
||||
|
||||
--- Set the graph foreground color as a gradient.
|
||||
-- @name set_gradient_colors
|
||||
-- @class function
|
||||
-- @param graph The graph.
|
||||
-- @param gradient_colors A table with gradients colors. The distance between each color
|
||||
-- can also be specified. Example: { "red", "blue" } or { "red", "green",
|
||||
-- "blue", blue = 10 } to specify blue distance from other colors.
|
||||
|
||||
--- Set the graph foreground colors gradient angle. Default is 270 degrees
|
||||
-- (horizontal).
|
||||
-- @name set_gradient_angle
|
||||
-- @class function
|
||||
-- @param graph The graph.
|
||||
-- @param gradient_angle Angle of gradient in degrees.
|
||||
|
||||
--- Set the graph foreground color.
|
||||
-- @name set_color
|
||||
-- @class function
|
||||
-- @param graph The graph.
|
||||
-- @param color The graph color.
|
||||
|
||||
--- Set the graph background color.
|
||||
-- @name set_background_color
|
||||
-- @class function
|
||||
-- @param graph The graph.
|
||||
-- @param color The graph background color.
|
||||
|
||||
--- Set the maximum value the graph should handle.
|
||||
-- If "scale" is also set, the graph never scales up below this value, but it
|
||||
-- automatically scales down to make all data fit.
|
||||
-- @name set_max_value
|
||||
-- @class function
|
||||
-- @param graph The graph.
|
||||
-- @param value The value.
|
||||
|
||||
--- Set the graph to automatically scale its values. Default is false.
|
||||
-- @name set_scale
|
||||
-- @class function
|
||||
-- @param graph The graph.
|
||||
-- @param scale A boolean value
|
||||
|
||||
--- Set the graph to draw stacks. Default is false.
|
||||
-- @name set_stack
|
||||
-- @class function
|
||||
-- @param graph The graph.
|
||||
-- @param stack A boolean value.
|
||||
|
||||
--- Set the graph stacking colors. Order matters.
|
||||
-- @name set_stack_colors
|
||||
-- @class function
|
||||
-- @param graph The graph.
|
||||
-- @param stack_colors A table with stacking colors.
|
||||
|
||||
local properties = { "width", "height", "border_color", "stack",
|
||||
"stack_colors", "gradient_colors", "gradient_angle",
|
||||
"color", "background_color", "max_value", "scale" }
|
||||
|
||||
local function update(graph)
|
||||
-- Create new empty image
|
||||
local img = capi.image.argb32(data[graph].width, data[graph].height, nil)
|
||||
local max_value = data[graph].max_value
|
||||
local values = data[graph].values
|
||||
|
||||
local border_width = 0
|
||||
if data[graph].border_color then
|
||||
border_width = 1
|
||||
end
|
||||
|
||||
-- Draw a stacked graph
|
||||
if data[graph].stack then
|
||||
|
||||
if data[graph].scale then
|
||||
for _, v in ipairs(values) do
|
||||
for __, sv in ipairs(v) do
|
||||
if sv > max_value then
|
||||
max_value = sv
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Draw the background first
|
||||
img:draw_rectangle(border_width, border_width,
|
||||
data[graph].width - (2 * border_width),
|
||||
data[graph].height,
|
||||
true, data[graph].background_color or "#000000aa")
|
||||
|
||||
for i = 0, data[graph].width - (2 * border_width) do
|
||||
local rel_i = 0
|
||||
local rel_x = data[graph].width - border_width - i - 1
|
||||
|
||||
if data[graph].stack_colors then
|
||||
for idx, color in ipairs(data[graph].stack_colors) do
|
||||
local stack_values = values[idx]
|
||||
if stack_values and i < #stack_values then
|
||||
local value = stack_values[#stack_values - i] + rel_i
|
||||
|
||||
img:draw_line(rel_x, border_width - 1 +
|
||||
math.ceil((data[graph].height - 2 * border_width) * (1 - (rel_i / max_value))),
|
||||
rel_x, border_width - 1 +
|
||||
math.ceil((data[graph].height - 2 * border_width) * (1 - (value / max_value))),
|
||||
color or "red")
|
||||
rel_i = value
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
else
|
||||
|
||||
if data[graph].scale then
|
||||
for _, v in ipairs(values) do
|
||||
if v > max_value then
|
||||
max_value = v
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Draw full gradient
|
||||
if data[graph].gradient_colors then
|
||||
img:draw_rectangle_gradient(border_width, border_width,
|
||||
data[graph].width - (2 * border_width),
|
||||
data[graph].height - (2 * border_width),
|
||||
data[graph].gradient_colors,
|
||||
data[graph].gradient_angle or 270)
|
||||
else
|
||||
img:draw_rectangle(border_width, border_width,
|
||||
data[graph].width - (2 * border_width),
|
||||
data[graph].height - (2 * border_width),
|
||||
true, data[graph].color or "red")
|
||||
end
|
||||
|
||||
-- Draw the background on no value
|
||||
if #values ~= 0 then
|
||||
-- Draw reverse
|
||||
for i = 0, #values - 1 do
|
||||
local value = values[#values - i]
|
||||
if value >= 0 then
|
||||
value = value / max_value
|
||||
img:draw_line(data[graph].width - border_width - i - 1,
|
||||
border_width - 1 +
|
||||
math.ceil((data[graph].height - 2 * border_width) * (1 - value)),
|
||||
data[graph].width - border_width - i - 1,
|
||||
border_width - 1,
|
||||
data[graph].background_color or "#000000aa")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- If we didn't draw values in full length, draw a square
|
||||
-- over the last, left, part to reset everything to 0
|
||||
if #values < data[graph].width - (2 * border_width) then
|
||||
img:draw_rectangle(border_width, border_width,
|
||||
data[graph].width - (2 * border_width) - #values,
|
||||
data[graph].height - (2 * border_width),
|
||||
true, data[graph].background_color or "#000000aa")
|
||||
end
|
||||
end
|
||||
|
||||
-- Draw the border last so that it overlaps already drawn values
|
||||
if data[graph].border_color then
|
||||
-- Draw the border
|
||||
img:draw_rectangle(0, 0, data[graph].width, data[graph].height,
|
||||
false, data[graph].border_color or "white")
|
||||
end
|
||||
|
||||
-- Update the image
|
||||
graph.widget.image = img
|
||||
end
|
||||
|
||||
--- Add a value to the graph
|
||||
-- @param graph The graph.
|
||||
-- @param value The value between 0 and 1.
|
||||
-- @param group The stack color group index.
|
||||
local function add_value(graph, value, group)
|
||||
if not graph then return end
|
||||
|
||||
local value = value or 0
|
||||
local values = data[graph].values
|
||||
local max_value = data[graph].max_value
|
||||
value = math.max(0, value)
|
||||
if not data[graph].scale then
|
||||
value = math.min(max_value, value)
|
||||
end
|
||||
|
||||
if data[graph].stack and group then
|
||||
if not data[graph].values[group]
|
||||
or type(data[graph].values[group]) ~= "table"
|
||||
then
|
||||
data[graph].values[group] = {}
|
||||
end
|
||||
values = data[graph].values[group]
|
||||
end
|
||||
table.insert(values, value)
|
||||
|
||||
local border_width = 0
|
||||
if data[graph].border then border_width = 2 end
|
||||
|
||||
-- Ensure we never have more data than we can draw
|
||||
while #values > data[graph].width - border_width do
|
||||
table.remove(values, 1)
|
||||
end
|
||||
|
||||
update(graph)
|
||||
return graph
|
||||
end
|
||||
|
||||
|
||||
--- Set the graph height.
|
||||
-- @param graph The graph.
|
||||
-- @param height The height to set.
|
||||
function set_height(graph, height)
|
||||
if height >= 5 then
|
||||
data[graph].height = height
|
||||
update(graph)
|
||||
end
|
||||
return graph
|
||||
end
|
||||
|
||||
--- Set the graph width.
|
||||
-- @param graph The graph.
|
||||
-- @param width The width to set.
|
||||
function set_width(graph, width)
|
||||
if width >= 5 then
|
||||
data[graph].width = width
|
||||
update(graph)
|
||||
end
|
||||
return graph
|
||||
end
|
||||
|
||||
-- Build properties function
|
||||
for _, prop in ipairs(properties) do
|
||||
if not _M["set_" .. prop] then
|
||||
_M["set_" .. prop] = function(graph, value)
|
||||
data[graph][prop] = value
|
||||
update(graph)
|
||||
return graph
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--- Create a graph widget.
|
||||
-- @param args Standard widget() arguments. You should add width and height
|
||||
-- key to set graph geometry.
|
||||
-- @return A graph widget.
|
||||
function new(args)
|
||||
local args = args or {}
|
||||
args.type = "imagebox"
|
||||
|
||||
local width = args.width or 100
|
||||
local height = args.height or 20
|
||||
|
||||
if width < 5 or height < 5 then return end
|
||||
|
||||
local graph = {}
|
||||
graph.widget = capi.widget(args)
|
||||
graph.widget.resize = false
|
||||
|
||||
data[graph] = { width = width, height = height, values = {}, max_value = 1 }
|
||||
|
||||
-- Set methods
|
||||
graph.add_value = add_value
|
||||
|
||||
for _, prop in ipairs(properties) do
|
||||
graph["set_" .. prop] = _M["set_" .. prop]
|
||||
end
|
||||
|
||||
graph.layout = args.layout or layout.horizontal.leftright
|
||||
|
||||
return graph
|
||||
end
|
||||
|
||||
setmetatable(_M, { __call = function(_, ...) return new(...) end })
|
||||
|
||||
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80
|
@ -0,0 +1,21 @@
|
||||
---------------------------------------------------------------------------
|
||||
-- @author Julien Danjou <julien@danjou.info>
|
||||
-- @copyright 2008-2009 Julien Danjou
|
||||
-- @release v3.4.10
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
require("awful.widget.taglist")
|
||||
require("awful.widget.tasklist")
|
||||
require("awful.widget.button")
|
||||
require("awful.widget.launcher")
|
||||
require("awful.widget.prompt")
|
||||
require("awful.widget.progressbar")
|
||||
require("awful.widget.graph")
|
||||
require("awful.widget.layoutbox")
|
||||
require("awful.widget.textclock")
|
||||
require("awful.widget.layout")
|
||||
|
||||
--- Widget module for awful
|
||||
module("awful.widget")
|
||||
|
||||
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80
|
@ -0,0 +1,35 @@
|
||||
---------------------------------------------------------------------------
|
||||
-- @author Julien Danjou <julien@danjou.info>
|
||||
-- @copyright 2008-2009 Julien Danjou
|
||||
-- @release v3.4.10
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
local setmetatable = setmetatable
|
||||
local util = require("awful.util")
|
||||
local wbutton = require("awful.widget.button")
|
||||
local button = require("awful.button")
|
||||
|
||||
module("awful.widget.launcher")
|
||||
|
||||
--- Create a button widget which will launch a command.
|
||||
-- @param args Standard widget table arguments, plus image for the image path
|
||||
-- and command for the command to run on click, or either menu to create menu.
|
||||
-- @return A launcher widget.
|
||||
function new(args)
|
||||
if not args.command and not args.menu then return end
|
||||
local w = wbutton(args)
|
||||
if not w then return end
|
||||
|
||||
if args.command then
|
||||
b = util.table.join(w:buttons(), button({}, 1, nil, function () util.spawn(args.command) end))
|
||||
elseif args.menu then
|
||||
b = util.table.join(w:buttons(), button({}, 1, nil, function () args.menu:toggle() end))
|
||||
end
|
||||
|
||||
w:buttons(b)
|
||||
return w
|
||||
end
|
||||
|
||||
setmetatable(_M, { __call = function (_, ...) return new(...) end })
|
||||
|
||||
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80
|
@ -0,0 +1,58 @@
|
||||
-------------------------------------------------
|
||||
-- @author Gregor Best <farhaven@googlemail.com>
|
||||
-- @copyright 2009 Gregor Best
|
||||
-- @release v3.4.10
|
||||
-------------------------------------------------
|
||||
|
||||
-- Grab environment
|
||||
local ipairs = ipairs
|
||||
local type = type
|
||||
local table = table
|
||||
local math = math
|
||||
local setmetatable = setmetatable
|
||||
local util = require("awful.util")
|
||||
|
||||
--- Simple default layout, emulating the fallback C layout
|
||||
module("awful.widget.layout.default")
|
||||
|
||||
local function default(bounds, widgets, screen)
|
||||
local geometries = {
|
||||
free = { x = 0, y = 0, width = 0, height = bounds.height }
|
||||
}
|
||||
|
||||
local width = 0
|
||||
|
||||
local keys = util.table.keys_filter(widgets, "table", "widget")
|
||||
|
||||
for _, k in ipairs(keys) do
|
||||
local v = widgets[k]
|
||||
if type(v) == "table" then
|
||||
local layout = v.layout or default
|
||||
local nbounds = util.table.clone(bounds)
|
||||
local g = layout(nbounds, v, screen)
|
||||
for _, w in ipairs(g) do
|
||||
table.insert(geometries, w)
|
||||
end
|
||||
else
|
||||
if v.visible then
|
||||
local e = v:extents(screen)
|
||||
e.x = 0
|
||||
e.y = 0
|
||||
e.width = math.min(e.width, bounds.width)
|
||||
e.height = bounds.height
|
||||
width = math.max(e.width, width)
|
||||
|
||||
table.insert(geometries, e)
|
||||
else
|
||||
table.insert(geometries, { x = 0, y = 0, width = 0, height = 0 })
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
geometries.free.width = bounds.width - width
|
||||
geometries.free.x = width
|
||||
|
||||
return geometries
|
||||
end
|
||||
|
||||
setmetatable(_M, { __call = function(_, ...) return default(...) end })
|
@ -0,0 +1,188 @@
|
||||
-------------------------------------------------
|
||||
-- @author Gregor Best <farhaven@googlemail.com>
|
||||
-- @copyright 2009 Gregor Best
|
||||
-- @release v3.4.10
|
||||
-------------------------------------------------
|
||||
|
||||
-- Grab environment
|
||||
local ipairs = ipairs
|
||||
local type = type
|
||||
local table = table
|
||||
local math = math
|
||||
local util = require("awful.util")
|
||||
local default = require("awful.widget.layout.default")
|
||||
local margins = awful.widget.layout.margins
|
||||
|
||||
--- Horizontal widget layout
|
||||
module("awful.widget.layout.horizontal")
|
||||
|
||||
local function horizontal(direction, bounds, widgets, screen)
|
||||
local geometries = { }
|
||||
local x = 0
|
||||
|
||||
-- we are only interested in tables and widgets
|
||||
local keys = util.table.keys_filter(widgets, "table", "widget")
|
||||
|
||||
for _, k in ipairs(keys) do
|
||||
local v = widgets[k]
|
||||
if type(v) == "table" then
|
||||
local layout = v.layout or default
|
||||
if margins[v] then
|
||||
bounds.width = bounds.width - (margins[v].left or 0) - (margins[v].right or 0)
|
||||
bounds.height = bounds.height - (margins[v].top or 0) - (margins[v].bottom or 0)
|
||||
end
|
||||
local g = layout(bounds, v, screen)
|
||||
if margins[v] then
|
||||
x = x + (margins[v].left or 0)
|
||||
end
|
||||
for _, v in ipairs(g) do
|
||||
v.x = v.x + x
|
||||
v.y = v.y + (margins[v] and (margins[v].top and margins[v].top or 0) or 0)
|
||||
table.insert(geometries, v)
|
||||
end
|
||||
bounds = g.free
|
||||
if margins[v] then
|
||||
x = x + g.free.x + (margins[v].right or 0)
|
||||
bounds.width = bounds.width - (margins[v].right or 0) - (margins[v].left or 0)
|
||||
else
|
||||
x = x + g.free.x
|
||||
end
|
||||
elseif type(v) == "widget" then
|
||||
local g
|
||||
if v.visible then
|
||||
g = v:extents(screen)
|
||||
if margins[v] then
|
||||
g.width = g.width + (margins[v].left or 0) + (margins[v].right or 0)
|
||||
g.height = g.height + (margins[v].top or 0) + (margins[v].bottom or 0)
|
||||
end
|
||||
else
|
||||
g = {
|
||||
width = 0,
|
||||
height = 0,
|
||||
}
|
||||
end
|
||||
|
||||
if v.resize and g.width > 0 and g.height > 0 then
|
||||
local ratio = g.width / g.height
|
||||
g.width = math.floor(bounds.height * ratio)
|
||||
g.height = bounds.height
|
||||
end
|
||||
|
||||
if g.width > bounds.width then
|
||||
g.width = bounds.width
|
||||
end
|
||||
g.height = bounds.height
|
||||
|
||||
if margins[v] then
|
||||
g.y = (margins[v].top or 0)
|
||||
else
|
||||
g.y = 0
|
||||
end
|
||||
|
||||
if direction == "leftright" then
|
||||
if margins[v] then
|
||||
g.x = x + (margins[v].left or 0)
|
||||
else
|
||||
g.x = x
|
||||
end
|
||||
x = x + g.width
|
||||
else
|
||||
if margins[v] then
|
||||
g.x = x + bounds.width - g.width + (margins[v].left or 0)
|
||||
else
|
||||
g.x = x + bounds.width - g.width
|
||||
end
|
||||
end
|
||||
bounds.width = bounds.width - g.width
|
||||
|
||||
table.insert(geometries, g)
|
||||
end
|
||||
end
|
||||
|
||||
geometries.free = util.table.clone(bounds)
|
||||
geometries.free.x = x
|
||||
geometries.free.y = 0
|
||||
|
||||
return geometries
|
||||
end
|
||||
|
||||
function flex(bounds, widgets, screen)
|
||||
local geometries = {
|
||||
free = util.table.clone(bounds)
|
||||
}
|
||||
-- the flex layout always uses the complete available place, thus we return
|
||||
-- no usable free area
|
||||
geometries.free.width = 0
|
||||
|
||||
-- we are only interested in tables and widgets
|
||||
local keys = util.table.keys_filter(widgets, "table", "widget")
|
||||
local nelements = 0
|
||||
|
||||
for _, k in ipairs(keys) do
|
||||
local v = widgets[k]
|
||||
if type(v) == "table" then
|
||||
nelements = nelements + 1
|
||||
elseif type(v) == "widget" then
|
||||
local g = v:extents()
|
||||
if v.resize and g.width > 0 and g.height > 0 then
|
||||
bounds.width = bounds.width - bounds.height
|
||||
elseif g.width > 0 and g.height > 0 then
|
||||
nelements = nelements + 1
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
nelements = (nelements == 0) and 1 or nelements
|
||||
|
||||
local x = 0
|
||||
local width = bounds.width / nelements
|
||||
|
||||
for _, k in ipairs(util.table.keys(widgets)) do
|
||||
local v = widgets[k]
|
||||
if type(v) == "table" then
|
||||
local layout = v.layout or default
|
||||
local g = layout(bounds, v, screen)
|
||||
for _, v in ipairs(g) do
|
||||
v.x = v.x + x
|
||||
table.insert(geometries, v)
|
||||
end
|
||||
bounds = g.free
|
||||
elseif type(v) == "widget" then
|
||||
local g = v:extents(screen)
|
||||
g.resize = v.resize
|
||||
|
||||
if v.resize and g.width > 0 and g.height > 0 then
|
||||
g.width = bounds.height
|
||||
g.height = bounds.height
|
||||
g.x = x
|
||||
g.y = bounds.y
|
||||
x = x + g.width
|
||||
elseif g.width > 0 and g.height > 0 then
|
||||
g.x = x
|
||||
g.y = bounds.y
|
||||
g.width = math.floor(width + 0.5)
|
||||
g.height = bounds.height
|
||||
x = x + width
|
||||
else
|
||||
g.x = 0
|
||||
g.y = 0
|
||||
g.width = 0
|
||||
g.height = 0
|
||||
end
|
||||
|
||||
table.insert(geometries, g)
|
||||
end
|
||||
end
|
||||
|
||||
return geometries
|
||||
end
|
||||
|
||||
function leftright(...)
|
||||
return horizontal("leftright", ...)
|
||||
end
|
||||
|
||||
function rightleft(...)
|
||||
return horizontal("rightleft", ...)
|
||||
end
|
||||
|
||||
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80
|
@ -0,0 +1,23 @@
|
||||
local setmetatable = setmetatable
|
||||
local require = require
|
||||
|
||||
-- Widget layouts
|
||||
module("awful.widget.layout")
|
||||
|
||||
--- Widgets margins.
|
||||
-- <p>In this table you can set the margin you want the layout to use when
|
||||
-- positionning your widgets.
|
||||
-- For example, if you want to put 10 pixel free on left on a widget, add this:
|
||||
-- <code>
|
||||
-- awful.widget.layout.margins[mywidget] = { left = 10 }
|
||||
-- </code>
|
||||
-- </p>
|
||||
-- @name margins
|
||||
-- @class table
|
||||
margins = setmetatable({}, { __mode = 'k' })
|
||||
|
||||
require("awful.widget.layout.horizontal")
|
||||
require("awful.widget.layout.vertical")
|
||||
require("awful.widget.layout.default")
|
||||
|
||||
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80
|
@ -0,0 +1,101 @@
|
||||
-------------------------------------------------
|
||||
-- @author Gregor Best <farhaven@googlemail.com>
|
||||
-- @copyright 2009 Gregor Best
|
||||
-- @release v3.4.10
|
||||
-------------------------------------------------
|
||||
|
||||
-- Grab environment
|
||||
local ipairs = ipairs
|
||||
local type = type
|
||||
local table = table
|
||||
local math = math
|
||||
local util = require("awful.util")
|
||||
local default = require("awful.widget.layout.default")
|
||||
|
||||
--- Vertical widget layout
|
||||
module("awful.widget.layout.vertical")
|
||||
|
||||
function flex(bounds, widgets, screen)
|
||||
local geometries = {
|
||||
free = util.table.clone(bounds)
|
||||
}
|
||||
|
||||
local y = 0
|
||||
|
||||
-- we are only interested in tables and widgets
|
||||
local keys = util.table.keys_filter(widgets, "table", "widget")
|
||||
local nelements = 0
|
||||
for _, k in ipairs(keys) do
|
||||
local v = widgets[k]
|
||||
if type(v) == "table" then
|
||||
nelements = nelements + 1
|
||||
else
|
||||
local e = v:extents()
|
||||
if v.visible and e.width > 0 and e.height > 0 then
|
||||
nelements = nelements + 1
|
||||
end
|
||||
end
|
||||
end
|
||||
if nelements == 0 then return geometries end
|
||||
local height = math.floor(bounds.height / nelements)
|
||||
|
||||
for _, k in ipairs(keys) do
|
||||
local v = widgets[k]
|
||||
if type(v) == "table" then
|
||||
local layout = v.layout or default
|
||||
-- we need to modify the height a bit because vertical layouts always span the
|
||||
-- whole height
|
||||
nbounds = util.table.clone(bounds)
|
||||
nbounds.height = height
|
||||
local g = layout(nbounds, v, screen)
|
||||
for _, w in ipairs(g) do
|
||||
w.y = w.y + y
|
||||
table.insert(geometries, w)
|
||||
end
|
||||
y = y + height
|
||||
elseif type(v) == "widget" then
|
||||
local g
|
||||
if v.visible then
|
||||
g = v:extents(screen)
|
||||
else
|
||||
g = {
|
||||
["width"] = 0,
|
||||
["height"] = 0
|
||||
}
|
||||
end
|
||||
|
||||
g.ratio = 1
|
||||
if g.height > 0 and g.width > 0 then
|
||||
g.ratio = g.width / g.height
|
||||
end
|
||||
g.height = height
|
||||
if v.resize then
|
||||
g.width = g.height * g.ratio
|
||||
end
|
||||
g.width = math.min(g.width, bounds.width)
|
||||
geometries.free.x = math.max(geometries.free.x, g.width)
|
||||
|
||||
g.x = 0
|
||||
g.y = y
|
||||
y = y + g.height
|
||||
bounds.height = bounds.height - g.height
|
||||
|
||||
table.insert(geometries, g)
|
||||
end
|
||||
end
|
||||
|
||||
local maxw = 0
|
||||
local maxx = 0
|
||||
for _, v in ipairs(geometries) do
|
||||
if v.width > maxw then maxw = v.width end
|
||||
if v.x > maxx then maxx = v.x end
|
||||
end
|
||||
|
||||
geometries.free.width = geometries.free.width - maxw
|
||||
geometries.free.x = geometries.free.x + maxw
|
||||
|
||||
geometries.free.height = nelements * height
|
||||
geometries.free.y = 0
|
||||
|
||||
return geometries
|
||||
end
|
@ -0,0 +1,53 @@
|
||||
---------------------------------------------------------------------------
|
||||
-- @author Julien Danjou <julien@danjou.info>
|
||||
-- @copyright 2009 Julien Danjou
|
||||
-- @release v3.4.10
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
local setmetatable = setmetatable
|
||||
local ipairs = ipairs
|
||||
local button = require("awful.button")
|
||||
local layout = require("awful.layout")
|
||||
local tag = require("awful.tag")
|
||||
local beautiful = require("beautiful")
|
||||
local capi = { image = image,
|
||||
screen = screen,
|
||||
widget = widget }
|
||||
|
||||
--- Layoutbox widget.
|
||||
module("awful.widget.layoutbox")
|
||||
|
||||
local function update(w, screen)
|
||||
local layout = layout.getname(layout.get(screen))
|
||||
if layout and beautiful["layout_" ..layout] then
|
||||
w.image = capi.image(beautiful["layout_" ..layout])
|
||||
else
|
||||
w.image = nil
|
||||
end
|
||||
end
|
||||
|
||||
--- Create a layoutbox widget. It draws a picture with the current layout
|
||||
-- symbol of the current tag.
|
||||
-- @param screen The screen number that the layout will be represented for.
|
||||
-- @param args Standard arguments for an imagebox widget.
|
||||
-- @return An imagebox widget configured as a layoutbox.
|
||||
function new(screen, args)
|
||||
local screen = screen or 1
|
||||
local args = args or {}
|
||||
args.type = "imagebox"
|
||||
local w = capi.widget(args)
|
||||
update(w, screen)
|
||||
|
||||
local function update_on_tag_selection(tag)
|
||||
return update(w, tag.screen)
|
||||
end
|
||||
|
||||
tag.attached_add_signal(screen, "property::selected", update_on_tag_selection)
|
||||
tag.attached_add_signal(screen, "property::layout", update_on_tag_selection)
|
||||
|
||||
return w
|
||||
end
|
||||
|
||||
setmetatable(_M, { __call = function(_, ...) return new(...) end })
|
||||
|
||||
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80
|
@ -0,0 +1,243 @@
|
||||
---------------------------------------------------------------------------
|
||||
-- @author Julien Danjou <julien@danjou.info>
|
||||
-- @copyright 2009 Julien Danjou
|
||||
-- @release v3.4.10
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
local setmetatable = setmetatable
|
||||
local ipairs = ipairs
|
||||
local math = math
|
||||
local capi = { image = image,
|
||||
widget = widget }
|
||||
local layout = require("awful.widget.layout")
|
||||
|
||||
--- A progressbar widget.
|
||||
module("awful.widget.progressbar")
|
||||
|
||||
local data = setmetatable({}, { __mode = "k" })
|
||||
|
||||
--- Set the progressbar border color.
|
||||
-- If the value is nil, no border will be drawn.
|
||||
-- @name set_border_color
|
||||
-- @class function
|
||||
-- @param progressbar The progressbar.
|
||||
-- @param color The border color to set.
|
||||
|
||||
--- Set the progressbar foreground color as a gradient.
|
||||
-- @name set_gradient_colors
|
||||
-- @class function
|
||||
-- @param progressbar The progressbar.
|
||||
-- @param gradient_colors A table with gradients colors. The distance between each color
|
||||
-- can also be specified. Example: { "red", "blue" } or { "red", "green",
|
||||
-- "blue", blue = 10 } to specify blue distance from other colors.
|
||||
|
||||
--- Set the progressbar foreground color.
|
||||
-- @name set_color
|
||||
-- @class function
|
||||
-- @param progressbar The progressbar.
|
||||
-- @param color The progressbar color.
|
||||
|
||||
--- Set the progressbar background color.
|
||||
-- @name set_background_color
|
||||
-- @class function
|
||||
-- @param progressbar The progressbar.
|
||||
-- @param color The progressbar background color.
|
||||
|
||||
--- Set the progressbar to draw vertically. Default is false.
|
||||
-- @name set_vertical
|
||||
-- @class function
|
||||
-- @param progressbar The progressbar.
|
||||
-- @param vertical A boolean value.
|
||||
|
||||
--- Set the progressbar to draw ticks. Default is false.
|
||||
-- @name set_ticks
|
||||
-- @class function
|
||||
-- @param progressbar The progressbar.
|
||||
-- @param ticks A boolean value.
|
||||
|
||||
--- Set the progressbar ticks gap.
|
||||
-- @name set_ticks_gap
|
||||
-- @class function
|
||||
-- @param progressbar The progressbar.
|
||||
-- @param value The value.
|
||||
|
||||
--- Set the progressbar ticks size.
|
||||
-- @name set_ticks_size
|
||||
-- @class function
|
||||
-- @param progressbar The progressbar.
|
||||
-- @param value The value.
|
||||
|
||||
--- Set the maximum value the progressbar should handle.
|
||||
-- @name set_max_value
|
||||
-- @class function
|
||||
-- @param progressbar The progressbar.
|
||||
-- @param value The value.
|
||||
|
||||
local properties = { "width", "height", "border_color",
|
||||
"gradient_colors", "color", "background_color",
|
||||
"vertical", "value", "max_value",
|
||||
"ticks", "ticks_gap", "ticks_size" }
|
||||
|
||||
local function update(pbar)
|
||||
local width = data[pbar].width or 100
|
||||
local height = data[pbar].height or 20
|
||||
local ticks_gap = data[pbar].ticks_gap or 1
|
||||
local ticks_size = data[pbar].ticks_size or 4
|
||||
|
||||
-- Create new empty image
|
||||
local img = capi.image.argb32(width, height, nil)
|
||||
|
||||
local value = data[pbar].value
|
||||
local max_value = data[pbar].max_value
|
||||
if value >= 0 then
|
||||
value = value / max_value
|
||||
end
|
||||
|
||||
local over_drawn_width = width
|
||||
local over_drawn_height = height
|
||||
local border_width = 0
|
||||
if data[pbar].border_color then
|
||||
-- Draw border
|
||||
img:draw_rectangle(0, 0, width, height, false, data[pbar].border_color)
|
||||
over_drawn_width = width - 2 -- remove 2 for borders
|
||||
over_drawn_height = height - 2 -- remove 2 for borders
|
||||
border_width = 1
|
||||
end
|
||||
|
||||
local angle = 270
|
||||
if data[pbar].vertical then
|
||||
angle = 180
|
||||
end
|
||||
|
||||
-- Draw full gradient
|
||||
if data[pbar].gradient_colors then
|
||||
img:draw_rectangle_gradient(border_width, border_width,
|
||||
over_drawn_width, over_drawn_height,
|
||||
data[pbar].gradient_colors, angle)
|
||||
else
|
||||
img:draw_rectangle(border_width, border_width,
|
||||
over_drawn_width, over_drawn_height,
|
||||
true, data[pbar].color or "red")
|
||||
end
|
||||
|
||||
-- Cover the part that is not set with a rectangle
|
||||
if data[pbar].vertical then
|
||||
local rel_height = math.floor(over_drawn_height * (1 - value))
|
||||
img:draw_rectangle(border_width,
|
||||
border_width,
|
||||
over_drawn_width,
|
||||
rel_height,
|
||||
true, data[pbar].background_color or "#000000aa")
|
||||
|
||||
-- Place smaller pieces over the gradient if ticks are enabled
|
||||
if data[pbar].ticks then
|
||||
for i=0, height / (ticks_size+ticks_gap)-border_width do
|
||||
local rel_offset = over_drawn_height / 1 - (ticks_size+ticks_gap) * i
|
||||
|
||||
if rel_offset >= rel_height then
|
||||
img:draw_rectangle(border_width,
|
||||
rel_offset,
|
||||
over_drawn_width,
|
||||
ticks_gap,
|
||||
true, data[pbar].background_color or "#000000aa")
|
||||
end
|
||||
end
|
||||
end
|
||||
else
|
||||
local rel_x = math.ceil(over_drawn_width * value)
|
||||
img:draw_rectangle(border_width + rel_x,
|
||||
border_width,
|
||||
over_drawn_width - rel_x,
|
||||
over_drawn_height,
|
||||
true, data[pbar].background_color or "#000000aa")
|
||||
|
||||
if data[pbar].ticks then
|
||||
for i=0, width / (ticks_size+ticks_gap)-border_width do
|
||||
local rel_offset = over_drawn_width / 1 - (ticks_size+ticks_gap) * i
|
||||
|
||||
if rel_offset <= rel_x then
|
||||
img:draw_rectangle(rel_offset,
|
||||
border_width,
|
||||
ticks_gap,
|
||||
over_drawn_height,
|
||||
true, data[pbar].background_color or "#000000aa")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Update the image
|
||||
pbar.widget.image = img
|
||||
end
|
||||
|
||||
--- Set the progressbar value.
|
||||
-- @param pbar The progress bar.
|
||||
-- @param value The progress bar value between 0 and 1.
|
||||
function set_value(pbar, value)
|
||||
local value = value or 0
|
||||
local max_value = data[pbar].max_value
|
||||
data[pbar].value = math.min(max_value, math.max(0, value))
|
||||
update(pbar)
|
||||
return pbar
|
||||
end
|
||||
|
||||
--- Set the progressbar height.
|
||||
-- @param progressbar The progressbar.
|
||||
-- @param height The height to set.
|
||||
function set_height(progressbar, height)
|
||||
data[progressbar].height = height
|
||||
update(progressbar)
|
||||
return progressbar
|
||||
end
|
||||
|
||||
--- Set the progressbar width.
|
||||
-- @param progressbar The progressbar.
|
||||
-- @param width The width to set.
|
||||
function set_width(progressbar, width)
|
||||
data[progressbar].width = width
|
||||
update(progressbar)
|
||||
return progressbar
|
||||
end
|
||||
|
||||
-- Build properties function
|
||||
for _, prop in ipairs(properties) do
|
||||
if not _M["set_" .. prop] then
|
||||
_M["set_" .. prop] = function(pbar, value)
|
||||
data[pbar][prop] = value
|
||||
update(pbar)
|
||||
return pbar
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--- Create a progressbar widget.
|
||||
-- @param args Standard widget() arguments. You should add width and height
|
||||
-- key to set progressbar geometry.
|
||||
-- @return A progressbar widget.
|
||||
function new(args)
|
||||
local args = args or {}
|
||||
local width = args.width or 100
|
||||
local height = args.height or 20
|
||||
|
||||
args.type = "imagebox"
|
||||
|
||||
local pbar = {}
|
||||
|
||||
pbar.widget = capi.widget(args)
|
||||
pbar.widget.resize = false
|
||||
|
||||
data[pbar] = { width = width, height = height, value = 0, max_value = 1 }
|
||||
|
||||
-- Set methods
|
||||
for _, prop in ipairs(properties) do
|
||||
pbar["set_" .. prop] = _M["set_" .. prop]
|
||||
end
|
||||
|
||||
pbar.layout = args.layout or layout.horizontal.leftright
|
||||
|
||||
return pbar
|
||||
end
|
||||
|
||||
setmetatable(_M, { __call = function(_, ...) return new(...) end })
|
||||
|
||||
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80
|
@ -0,0 +1,51 @@
|
||||
---------------------------------------------------------------------------
|
||||
-- @author Julien Danjou <julien@danjou.info>
|
||||
-- @copyright 2009 Julien Danjou
|
||||
-- @release v3.4.10
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
local setmetatable = setmetatable
|
||||
|
||||
local capi = { widget = widget }
|
||||
local completion = require("awful.completion")
|
||||
local util = require("awful.util")
|
||||
local prompt = require("awful.prompt")
|
||||
local layout = require("awful.widget.layout")
|
||||
local type = type
|
||||
|
||||
module("awful.widget.prompt")
|
||||
|
||||
--- Run method for promptbox.
|
||||
-- @param promptbox The promptbox to run.
|
||||
local function run(promptbox)
|
||||
return prompt.run({ prompt = promptbox.prompt },
|
||||
promptbox.widget,
|
||||
function (...)
|
||||
local result = util.spawn(...)
|
||||
if type(result) == "string" then
|
||||
promptbox.widget.text = result
|
||||
end
|
||||
end,
|
||||
completion.shell,
|
||||
util.getdir("cache") .. "/history")
|
||||
end
|
||||
|
||||
--- Create a prompt widget which will launch a command.
|
||||
-- @param args Standard widget table arguments, with prompt to change the
|
||||
-- default prompt.
|
||||
-- @return A launcher widget.
|
||||
function new(args)
|
||||
local args = args or {}
|
||||
local promptbox = {}
|
||||
args.type = "textbox"
|
||||
promptbox.widget = capi.widget(args)
|
||||
promptbox.widget.ellipsize = "start"
|
||||
promptbox.run = run
|
||||
promptbox.prompt = args.prompt or "Run: "
|
||||
promptbox.layout = args.layout or layout.horizontal.leftright
|
||||
return promptbox
|
||||
end
|
||||
|
||||
setmetatable(_M, { __call = function (_, ...) return new(...) end })
|
||||
|
||||
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80
|
@ -0,0 +1,196 @@
|
||||
---------------------------------------------------------------------------
|
||||
-- @author Julien Danjou <julien@danjou.info>
|
||||
-- @copyright 2008-2009 Julien Danjou
|
||||
-- @release v3.4.10
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
-- Grab environment we need
|
||||
local capi = { widget = widget,
|
||||
screen = screen,
|
||||
image = image,
|
||||
client = client }
|
||||
local type = type
|
||||
local setmetatable = setmetatable
|
||||
local pairs = pairs
|
||||
local ipairs = ipairs
|
||||
local table = table
|
||||
local common = require("awful.widget.common")
|
||||
local util = require("awful.util")
|
||||
local tag = require("awful.tag")
|
||||
local beautiful = require("beautiful")
|
||||
local layout = require("awful.widget.layout")
|
||||
|
||||
--- Taglist widget module for awful
|
||||
module("awful.widget.taglist")
|
||||
|
||||
label = {}
|
||||
|
||||
local function taglist_update (screen, w, label, buttons, data, widgets)
|
||||
local tags = capi.screen[screen]:tags()
|
||||
local showntags = {}
|
||||
for k, t in ipairs(tags) do
|
||||
if not tag.getproperty(t, "hide") then
|
||||
table.insert(showntags, t)
|
||||
end
|
||||
end
|
||||
common.list_update(w, buttons, label, data, widgets, showntags)
|
||||
end
|
||||
|
||||
--- Get the tag object the given widget appears on.
|
||||
-- @param widget The widget the look for.
|
||||
-- @return The tag object.
|
||||
function gettag(widget)
|
||||
return common.tagwidgets[widget]
|
||||
end
|
||||
|
||||
--- Create a new taglist widget.
|
||||
-- @param screen The screen to draw tag list for.
|
||||
-- @param label Label function to use.
|
||||
-- @param buttons A table with buttons binding to set.
|
||||
function new(screen, label, buttons)
|
||||
local w = {
|
||||
layout = layout.horizontal.leftright
|
||||
}
|
||||
local widgets = { }
|
||||
widgets.imagebox = { }
|
||||
widgets.textbox = { ["margin"] = { ["left"] = 0,
|
||||
["right"] = 0},
|
||||
["bg_resize"] = true
|
||||
}
|
||||
local data = setmetatable({}, { __mode = 'kv' })
|
||||
local u = function (s)
|
||||
if s == screen then
|
||||
taglist_update(s, w, label, buttons, data, widgets)
|
||||
end
|
||||
end
|
||||
local uc = function (c) return u(c.screen) end
|
||||
capi.client.add_signal("focus", uc)
|
||||
capi.client.add_signal("unfocus", uc)
|
||||
tag.attached_add_signal(screen, "property::selected", uc)
|
||||
tag.attached_add_signal(screen, "property::icon", uc)
|
||||
tag.attached_add_signal(screen, "property::hide", uc)
|
||||
tag.attached_add_signal(screen, "property::name", uc)
|
||||
capi.screen[screen]:add_signal("tag::attach", function(screen, tag)
|
||||
u(screen.index)
|
||||
end)
|
||||
capi.screen[screen]:add_signal("tag::detach", function(screen, tag)
|
||||
u(screen.index)
|
||||
end)
|
||||
capi.client.add_signal("new", function(c)
|
||||
c:add_signal("property::urgent", uc)
|
||||
c:add_signal("property::screen", function(c)
|
||||
-- If client change screen, refresh it anyway since we don't from
|
||||
-- which screen it was coming :-)
|
||||
u(screen)
|
||||
end)
|
||||
c:add_signal("tagged", uc)
|
||||
c:add_signal("untagged", uc)
|
||||
end)
|
||||
capi.client.add_signal("unmanage", uc)
|
||||
u(screen)
|
||||
return w
|
||||
end
|
||||
|
||||
--- Return labels for a taglist widget with all tag from screen.
|
||||
-- It returns the tag name and set a special
|
||||
-- foreground and background color for selected tags.
|
||||
-- @param t The tag.
|
||||
-- @param args The arguments table.
|
||||
-- bg_focus The background color for selected tag.
|
||||
-- fg_focus The foreground color for selected tag.
|
||||
-- bg_urgent The background color for urgent tags.
|
||||
-- fg_urgent The foreground color for urgent tags.
|
||||
-- squares_sel Optional: a user provided image for selected squares.
|
||||
-- squares_unsel Optional: a user provided image for unselected squares.
|
||||
-- squares_resize Optional: true or false to resize squares.
|
||||
-- @return A string to print, a background color, a background image and a
|
||||
-- background resize value.
|
||||
function label.all(t, args)
|
||||
if not args then args = {} end
|
||||
local theme = beautiful.get()
|
||||
local fg_focus = args.fg_focus or theme.taglist_fg_focus or theme.fg_focus
|
||||
local bg_focus = args.bg_focus or theme.taglist_bg_focus or theme.bg_focus
|
||||
local fg_urgent = args.fg_urgent or theme.taglist_fg_urgent or theme.fg_urgent
|
||||
local bg_urgent = args.bg_urgent or theme.taglist_bg_urgent or theme.bg_urgent
|
||||
local taglist_squares_sel = args.squares_sel or theme.taglist_squares_sel
|
||||
local taglist_squares_unsel = args.squares_unsel or theme.taglist_squares_unsel
|
||||
local taglist_squares_resize = theme.taglist_squares_resize or args.squares_resize or "true"
|
||||
local font = args.font or theme.taglist_font or theme.font or ""
|
||||
local text = "<span font_desc='"..font.."'>"
|
||||
local sel = capi.client.focus
|
||||
local bg_color = nil
|
||||
local fg_color = nil
|
||||
local bg_image
|
||||
local icon
|
||||
local bg_resize = false
|
||||
local is_selected = false
|
||||
if t.selected then
|
||||
bg_color = bg_focus
|
||||
fg_color = fg_focus
|
||||
end
|
||||
if sel then
|
||||
if taglist_squares_sel then
|
||||
-- Check that the selected clients is tagged with 't'.
|
||||
local seltags = sel:tags()
|
||||
for _, v in ipairs(seltags) do
|
||||
if v == t then
|
||||
bg_image = capi.image(taglist_squares_sel)
|
||||
bg_resize = taglist_squares_resize == "true"
|
||||
is_selected = true
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
if not is_selected then
|
||||
local cls = t:clients()
|
||||
if #cls > 0 and taglist_squares_unsel then
|
||||
bg_image = capi.image(taglist_squares_unsel)
|
||||
bg_resize = taglist_squares_resize == "true"
|
||||
end
|
||||
for k, c in pairs(cls) do
|
||||
if c.urgent then
|
||||
if bg_urgent then bg_color = bg_urgent end
|
||||
if fg_urgent then fg_color = fg_urgent end
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
if not tag.getproperty(t, "icon_only") then
|
||||
if fg_color then
|
||||
text = text .. "<span color='"..util.color_strip_alpha(fg_color).."'>"
|
||||
text = " " .. text.. (util.escape(t.name) or "") .." </span>"
|
||||
else
|
||||
text = text .. " " .. (util.escape(t.name) or "") .. " "
|
||||
end
|
||||
end
|
||||
text = text .. "</span>"
|
||||
if tag.geticon(t) and type(tag.geticon(t)) == "image" then
|
||||
icon = tag.geticon(t)
|
||||
elseif tag.geticon(t) then
|
||||
icon = capi.image(tag.geticon(t))
|
||||
end
|
||||
|
||||
return text, bg_color, bg_image, icon
|
||||
end
|
||||
|
||||
--- Return labels for a taglist widget with all *non empty* tags from screen.
|
||||
-- It returns the tag name and set a special
|
||||
-- foreground and background color for selected tags.
|
||||
-- @param t The tag.
|
||||
-- @param args The arguments table.
|
||||
-- bg_focus The background color for selected tag.
|
||||
-- fg_focus The foreground color for selected tag.
|
||||
-- bg_urgent The background color for urgent tags.
|
||||
-- fg_urgent The foreground color for urgent tags.
|
||||
-- @return A string to print, a background color, a background image and a
|
||||
-- background resize value.
|
||||
function label.noempty(t, args)
|
||||
if #t:clients() > 0 or t.selected then
|
||||
return label.all(t, args)
|
||||
end
|
||||
end
|
||||
|
||||
setmetatable(_M, { __call = function(_, ...) return new(...) end })
|
||||
|
||||
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80
|
@ -0,0 +1,213 @@
|
||||
---------------------------------------------------------------------------
|
||||
-- @author Julien Danjou <julien@danjou.info>
|
||||
-- @copyright 2008-2009 Julien Danjou
|
||||
-- @release v3.4.10
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
-- Grab environment we need
|
||||
local capi = { screen = screen,
|
||||
image = image,
|
||||
client = client }
|
||||
local ipairs = ipairs
|
||||
local type = type
|
||||
local setmetatable = setmetatable
|
||||
local table = table
|
||||
local common = require("awful.widget.common")
|
||||
local beautiful = require("beautiful")
|
||||
local client = require("awful.client")
|
||||
local util = require("awful.util")
|
||||
local tag = require("awful.tag")
|
||||
local layout = require("awful.widget.layout")
|
||||
|
||||
--- Tasklist widget module for awful
|
||||
module("awful.widget.tasklist")
|
||||
|
||||
-- Public structures
|
||||
label = {}
|
||||
|
||||
local function tasklist_update(w, buttons, label, data, widgets)
|
||||
local clients = capi.client.get()
|
||||
local shownclients = {}
|
||||
for k, c in ipairs(clients) do
|
||||
if not (c.skip_taskbar or c.hidden
|
||||
or c.type == "splash" or c.type == "dock" or c.type == "desktop") then
|
||||
table.insert(shownclients, c)
|
||||
end
|
||||
end
|
||||
clients = shownclients
|
||||
|
||||
common.list_update(w, buttons, label, data, widgets, clients)
|
||||
end
|
||||
|
||||
--- Create a new tasklist widget.
|
||||
-- @param label Label function to use.
|
||||
-- @param buttons A table with buttons binding to set.
|
||||
function new(label, buttons)
|
||||
local w = {
|
||||
layout = layout.horizontal.flex
|
||||
}
|
||||
local widgets = { }
|
||||
widgets.imagebox = { }
|
||||
widgets.textbox = { margin = { left = 2,
|
||||
right = 2 },
|
||||
bg_resize = true,
|
||||
bg_align = "right"
|
||||
}
|
||||
local data = setmetatable({}, { __mode = 'kv' })
|
||||
local u = function () tasklist_update(w, buttons, label, data, widgets) end
|
||||
for s = 1, capi.screen.count() do
|
||||
tag.attached_add_signal(s, "property::selected", u)
|
||||
capi.screen[s]:add_signal("tag::attach", u)
|
||||
capi.screen[s]:add_signal("tag::detach", u)
|
||||
end
|
||||
capi.client.add_signal("new", function (c)
|
||||
c:add_signal("property::urgent", u)
|
||||
c:add_signal("property::floating", u)
|
||||
c:add_signal("property::maximized_horizontal", u)
|
||||
c:add_signal("property::maximized_vertical", u)
|
||||
c:add_signal("property::minimized", u)
|
||||
c:add_signal("property::name", u)
|
||||
c:add_signal("property::icon_name", u)
|
||||
c:add_signal("property::icon", u)
|
||||
c:add_signal("property::skip_taskbar", u)
|
||||
c:add_signal("property::hidden", u)
|
||||
c:add_signal("tagged", u)
|
||||
c:add_signal("untagged", u)
|
||||
end)
|
||||
capi.client.add_signal("unmanage", u)
|
||||
capi.client.add_signal("list", u)
|
||||
capi.client.add_signal("focus", u)
|
||||
capi.client.add_signal("unfocus", u)
|
||||
u()
|
||||
return w
|
||||
end
|
||||
|
||||
local function widget_tasklist_label_common(c, args)
|
||||
if not args then args = {} end
|
||||
local theme = beautiful.get()
|
||||
local fg_focus = args.fg_focus or theme.tasklist_fg_focus or theme.fg_focus
|
||||
local bg_focus = args.bg_focus or theme.tasklist_bg_focus or theme.bg_focus
|
||||
local fg_urgent = args.fg_urgent or theme.tasklist_fg_urgent or theme.fg_urgent
|
||||
local bg_urgent = args.bg_urgent or theme.tasklist_bg_urgent or theme.bg_urgent
|
||||
local fg_minimize = args.fg_minimize or theme.tasklist_fg_minimize or theme.fg_minimize
|
||||
local bg_minimize = args.bg_minimize or theme.tasklist_bg_minimize or theme.bg_minimize
|
||||
local floating_icon = args.floating_icon or theme.tasklist_floating_icon
|
||||
local font = args.font or theme.tasklist_font or theme.font or ""
|
||||
local bg = nil
|
||||
local text = "<span font_desc='"..font.."'>"
|
||||
local name
|
||||
local status_image
|
||||
if client.floating.get(c) and floating_icon then
|
||||
status_image = capi.image(floating_icon)
|
||||
end
|
||||
if c.minimized then
|
||||
name = util.escape(c.icon_name) or util.escape(c.name) or util.escape("<untitled>")
|
||||
else
|
||||
name = util.escape(c.name) or util.escape("<untitled>")
|
||||
end
|
||||
if capi.client.focus == c then
|
||||
bg = bg_focus
|
||||
if fg_focus then
|
||||
text = text .. "<span color='"..util.color_strip_alpha(fg_focus).."'>"..name.."</span>"
|
||||
else
|
||||
text = text .. name
|
||||
end
|
||||
elseif c.urgent and fg_urgent then
|
||||
bg = bg_urgent
|
||||
text = text .. "<span color='"..util.color_strip_alpha(fg_urgent).."'>"..name.."</span>"
|
||||
elseif c.minimized and fg_minimize and bg_minimize then
|
||||
bg = bg_minimize
|
||||
text = text .. "<span color='"..util.color_strip_alpha(fg_minimize).."'>"..name.."</span>"
|
||||
else
|
||||
text = text .. name
|
||||
end
|
||||
text = text .. "</span>"
|
||||
-- return text, bg, status_image, c.icon
|
||||
return text, bg, status_image, nil
|
||||
end
|
||||
|
||||
--- Return labels for a tasklist widget with clients from all tags and screen.
|
||||
-- It returns the client name and set a special
|
||||
-- foreground and background color for focused client.
|
||||
-- It also puts a special icon for floating windows.
|
||||
-- @param c The client.
|
||||
-- @param screen The screen we are drawing on.
|
||||
-- @param args The arguments table.
|
||||
-- bg_focus The background color for focused client.
|
||||
-- fg_focus The foreground color for focused client.
|
||||
-- bg_urgent The background color for urgent clients.
|
||||
-- fg_urgent The foreground color for urgent clients.
|
||||
-- @return A string to print, a background color and a status image.
|
||||
function label.allscreen(c, screen, args)
|
||||
return widget_tasklist_label_common(c, args)
|
||||
end
|
||||
|
||||
--- Return labels for a tasklist widget with clients from all tags.
|
||||
-- It returns the client name and set a special
|
||||
-- foreground and background color for focused client.
|
||||
-- It also puts a special icon for floating windows.
|
||||
-- @param c The client.
|
||||
-- @param screen The screen we are drawing on.
|
||||
-- @param args The arguments table.
|
||||
-- bg_focus The background color for focused client.
|
||||
-- fg_focus The foreground color for focused client.
|
||||
-- bg_urgent The background color for urgent clients.
|
||||
-- fg_urgent The foreground color for urgent clients.
|
||||
-- @return A string to print, a background color and a status image.
|
||||
function label.alltags(c, screen, args)
|
||||
-- Only print client on the same screen as this widget
|
||||
if c.screen ~= screen then return end
|
||||
return widget_tasklist_label_common(c, args)
|
||||
end
|
||||
|
||||
--- Return labels for a tasklist widget with clients from currently selected tags.
|
||||
-- It returns the client name and set a special
|
||||
-- foreground and background color for focused client.
|
||||
-- It also puts a special icon for floating windows.
|
||||
-- @param c The client.
|
||||
-- @param screen The screen we are drawing on.
|
||||
-- @param args The arguments table.
|
||||
-- bg_focus The background color for focused client.
|
||||
-- fg_focus The foreground color for focused client.
|
||||
-- bg_urgent The background color for urgent clients.
|
||||
-- fg_urgent The foreground color for urgent clients.
|
||||
-- @return A string to print, a background color and a status image.
|
||||
function label.currenttags(c, screen, args)
|
||||
-- Only print client on the same screen as this widget
|
||||
if c.screen ~= screen then return end
|
||||
-- Include sticky client too
|
||||
if c.sticky then return widget_tasklist_label_common(c, args) end
|
||||
for k, t in ipairs(capi.screen[screen]:tags()) do
|
||||
if t.selected then
|
||||
local ctags = c:tags()
|
||||
for _, v in ipairs(ctags) do
|
||||
if v == t then
|
||||
return widget_tasklist_label_common(c, args)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--- Return label for only the currently focused client.
|
||||
-- It returns the client name and set a special
|
||||
-- foreground and background color for focused client.
|
||||
-- It also puts a special icon for floating windows.
|
||||
-- @param c The client.
|
||||
-- @param screen The screen we are drawing on.
|
||||
-- @param args The arguments table.
|
||||
-- bg_focus The background color for focused client.
|
||||
-- fg_focus The foreground color for focused client.
|
||||
-- bg_urgent The background color for urgent clients.
|
||||
-- fg_urgent The foreground color for urgent clients.
|
||||
-- @return A string to print, a background color and a status image.
|
||||
function label.focused(c, screen, args)
|
||||
-- Only print client on the same screen as this widget
|
||||
if c.screen == screen and capi.client.focus == c then
|
||||
return widget_tasklist_label_common(c, args)
|
||||
end
|
||||
end
|
||||
|
||||
setmetatable(_M, { __call = function(_, ...) return new(...) end })
|
||||
|
||||
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80
|
@ -0,0 +1,35 @@
|
||||
---------------------------------------------------------------------------
|
||||
-- @author Julien Danjou <julien@danjou.info>
|
||||
-- @copyright 2009 Julien Danjou
|
||||
-- @release v3.4.10
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
local setmetatable = setmetatable
|
||||
local os = os
|
||||
local capi = { widget = widget,
|
||||
timer = timer }
|
||||
|
||||
--- Text clock widget.
|
||||
module("awful.widget.textclock")
|
||||
|
||||
--- Create a textclock widget. It draws the time it is in a textbox.
|
||||
-- @param args Standard arguments for textbox widget.
|
||||
-- @param format The time format. Default is " %a %b %d, %H:%M ".
|
||||
-- @param timeout How often update the time. Default is 60.
|
||||
-- @return A textbox widget.
|
||||
function new(args, format, timeout)
|
||||
local args = args or {}
|
||||
local format = format or " %a %b %d, %H:%M "
|
||||
local timeout = timeout or 60
|
||||
args.type = "textbox"
|
||||
local w = capi.widget(args)
|
||||
local timer = capi.timer { timeout = timeout }
|
||||
w.text = os.date(format)
|
||||
timer:add_signal("timeout", function() w.text = os.date(format) end)
|
||||
timer:start()
|
||||
return w
|
||||
end
|
||||
|
||||
setmetatable(_M, { __call = function(_, ...) return new(...) end })
|
||||
|
||||
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80
|
@ -0,0 +1,76 @@
|
||||
----------------------------------------------------------------------------
|
||||
-- @author Damien Leone <damien.leone@gmail.com>
|
||||
-- @author Julien Danjou <julien@danjou.info>
|
||||
-- @copyright 2008-2009 Damien Leone, Julien Danjou
|
||||
-- @release v3.4.9
|
||||
----------------------------------------------------------------------------
|
||||
|
||||
-- Grab environment
|
||||
local io = io
|
||||
local os = os
|
||||
local print = print
|
||||
local pcall = pcall
|
||||
local pairs = pairs
|
||||
local type = type
|
||||
local dofile = dofile
|
||||
local setmetatable = setmetatable
|
||||
local util = require("awful.util")
|
||||
local package = package
|
||||
local capi =
|
||||
{
|
||||
screen = screen,
|
||||
awesome = awesome,
|
||||
image = image
|
||||
}
|
||||
|
||||
--- Theme library.
|
||||
module("beautiful")
|
||||
|
||||
-- Local data
|
||||
local theme
|
||||
|
||||
--- Init function, should be runned at the beginning of configuration file.
|
||||
-- @param path The theme file path.
|
||||
function init(path)
|
||||
if path then
|
||||
local success
|
||||
success, theme = pcall(function() return dofile(path) end)
|
||||
|
||||
if not success then
|
||||
return print("E: beautiful: error loading theme file " .. theme)
|
||||
elseif theme then
|
||||
-- try and grab user's $HOME directory
|
||||
local homedir = os.getenv("HOME")
|
||||
-- expand '~'
|
||||
if homedir then
|
||||
for k, v in pairs(theme) do
|
||||
if type(v) == "string" then theme[k] = v:gsub("~", homedir) end
|
||||
end
|
||||
end
|
||||
|
||||
-- setup wallpaper
|
||||
if theme.wallpaper_cmd then
|
||||
for s = 1, capi.screen.count() do
|
||||
util.spawn(theme.wallpaper_cmd[util.cycle(#theme.wallpaper_cmd, s)], false, s)
|
||||
end
|
||||
end
|
||||
if theme.font then capi.awesome.font = theme.font end
|
||||
if theme.fg_normal then capi.awesome.fg = theme.fg_normal end
|
||||
if theme.bg_normal then capi.awesome.bg = theme.bg_normal end
|
||||
else
|
||||
return print("E: beautiful: error loading theme file " .. path)
|
||||
end
|
||||
else
|
||||
return print("E: beautiful: error loading theme: no path specified")
|
||||
end
|
||||
end
|
||||
|
||||
--- Get the current theme.
|
||||
-- @return The current theme table.
|
||||
function get()
|
||||
return theme
|
||||
end
|
||||
|
||||
setmetatable(_M, { __index = function(t, k) return theme[k] end })
|
||||
|
||||
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80
|
121
DUFRESNE/Linux/home/burchettm/.config/awesome/lib/cal.lua
Normal file
121
DUFRESNE/Linux/home/burchettm/.config/awesome/lib/cal.lua
Normal file
@ -0,0 +1,121 @@
|
||||
-- original code made by Bzed and published on http://awesome.naquadah.org/wiki/Calendar_widget
|
||||
-- modified by Marc Dequènes (Duck) <Duck@DuckCorp.org> (2009-12-29), under the same licence,
|
||||
-- and with the following changes:
|
||||
-- + transformed to module
|
||||
-- + the current day formating is customizable
|
||||
-- modified by Jörg Thalheim (Mic92) <jthalheim@gmail.com> (2011), under the same licence,
|
||||
-- and with the following changes:
|
||||
-- + use tooltip instead of naughty.notify
|
||||
-- + rename it to cal
|
||||
--
|
||||
-- # How to Install #
|
||||
-- 1. Download the code and move it into your config directory
|
||||
-- wget --no-check-certificate https://github.com/Mic92/awesome-dotfiles/raw/master/cal.lua -O $XDG_CONFIG_HOME/awesome/cal.lua
|
||||
-- 2. require it in your rc.lua
|
||||
-- require("cal")
|
||||
-- 3. attach the calendar to a widget of your choice (ex mytextclock)
|
||||
-- cal.register(mytextclock)
|
||||
-- If you don't like the default current day formating you can change it as following
|
||||
-- cal.register(mytextclock, "<b>%s</b>") -- now the current day is bold instead of underlined
|
||||
--
|
||||
-- # How to Use #
|
||||
-- Just hover with your mouse over the widget, you register and the calendar popup.
|
||||
-- On clicking or by using the mouse wheel the displayed month changes.
|
||||
-- Pressing Shift + Mouse click change the year.
|
||||
|
||||
local string = {format = string.format}
|
||||
local os = {date = os.date, time = os.time}
|
||||
local awful = require("awful")
|
||||
|
||||
module("cal")
|
||||
|
||||
local tooltip
|
||||
local state = {}
|
||||
local current_day_format = "<u>%s</u>"
|
||||
|
||||
function displayMonth(month,year,weekStart)
|
||||
local t,wkSt=os.time{year=year, month=month+1, day=0},weekStart or 1
|
||||
local d=os.date("*t",t)
|
||||
local mthDays,stDay=d.day,(d.wday-d.day-wkSt+1)%7
|
||||
|
||||
local lines = " "
|
||||
|
||||
for x=0,6 do
|
||||
lines = lines .. os.date("%a ",os.time{year=2006,month=1,day=x+wkSt})
|
||||
end
|
||||
|
||||
lines = lines .. "\n" .. os.date(" %V",os.time{year=year,month=month,day=1})
|
||||
|
||||
local writeLine = 1
|
||||
while writeLine < (stDay + 1) do
|
||||
lines = lines .. " "
|
||||
writeLine = writeLine + 1
|
||||
end
|
||||
|
||||
for d=1,mthDays do
|
||||
local x = d
|
||||
local t = os.time{year=year,month=month,day=d}
|
||||
if writeLine == 8 then
|
||||
writeLine = 1
|
||||
lines = lines .. "\n" .. os.date(" %V",t)
|
||||
end
|
||||
if os.date("%Y-%m-%d") == os.date("%Y-%m-%d", t) then
|
||||
x = string.format(current_day_format, d)
|
||||
end
|
||||
if d < 10 then
|
||||
x = " " .. x
|
||||
end
|
||||
lines = lines .. " " .. x
|
||||
writeLine = writeLine + 1
|
||||
end
|
||||
local header = os.date("%B %Y\n",os.time{year=year,month=month,day=1})
|
||||
|
||||
return header .. "\n" .. lines
|
||||
end
|
||||
|
||||
function register(mywidget, custom_current_day_format)
|
||||
if custom_current_day_format then current_day_format = custom_current_day_format end
|
||||
|
||||
if not tooltip then
|
||||
tooltip = awful.tooltip({})
|
||||
end
|
||||
tooltip:add_to_object(mywidget)
|
||||
|
||||
mywidget:add_signal("mouse::enter", function()
|
||||
local month, year = os.date('%m'), os.date('%Y')
|
||||
state = {month, year}
|
||||
tooltip:set_text(string.format('<span font_desc="monospace">%s</span>', displayMonth(month, year, 2)))
|
||||
end)
|
||||
|
||||
mywidget:buttons(awful.util.table.join(
|
||||
awful.button({ }, 1, function()
|
||||
switchMonth(-1)
|
||||
end),
|
||||
awful.button({ }, 3, function()
|
||||
switchMonth(1)
|
||||
end),
|
||||
awful.button({ }, 4, function()
|
||||
switchMonth(-1)
|
||||
end),
|
||||
awful.button({ }, 5, function()
|
||||
switchMonth(1)
|
||||
end),
|
||||
awful.button({ 'Shift' }, 1, function()
|
||||
switchMonth(-12)
|
||||
end),
|
||||
awful.button({ 'Shift' }, 3, function()
|
||||
switchMonth(12)
|
||||
end),
|
||||
awful.button({ 'Shift' }, 4, function()
|
||||
switchMonth(-12)
|
||||
end),
|
||||
awful.button({ 'Shift' }, 5, function()
|
||||
switchMonth(12)
|
||||
end)))
|
||||
end
|
||||
|
||||
function switchMonth(delta)
|
||||
state[1] = state[1] + (delta or 1)
|
||||
local text = string.format('<span font_desc="monospace">%s</span>', displayMonth(state[1], state[2], 2))
|
||||
tooltip:set_text(text)
|
||||
end
|
594
DUFRESNE/Linux/home/burchettm/.config/awesome/lib/naughty.lua
Normal file
594
DUFRESNE/Linux/home/burchettm/.config/awesome/lib/naughty.lua
Normal file
@ -0,0 +1,594 @@
|
||||
----------------------------------------------------------------------------
|
||||
-- @author koniu <gkusnierz@gmail.com>
|
||||
-- @copyright 2008 koniu
|
||||
-- @release v3.4.9
|
||||
----------------------------------------------------------------------------
|
||||
|
||||
-- Package environment
|
||||
local pairs = pairs
|
||||
local table = table
|
||||
local type = type
|
||||
local string = string
|
||||
local pcall = pcall
|
||||
local capi = { screen = screen,
|
||||
awesome = awesome,
|
||||
dbus = dbus,
|
||||
widget = widget,
|
||||
wibox = wibox,
|
||||
image = image,
|
||||
timer = timer }
|
||||
local button = require("awful.button")
|
||||
local util = require("awful.util")
|
||||
local bt = require("beautiful")
|
||||
local layout = require("awful.widget.layout")
|
||||
|
||||
--- Notification library
|
||||
module("naughty")
|
||||
|
||||
--- Naughty configuration - a table containing common popup settings.
|
||||
-- @name config
|
||||
-- @field padding Space between popups and edge of the workarea. Default: 4
|
||||
-- @field spacing Spacing between popups. Default: 1
|
||||
-- @field icon_dirs List of directories that will be checked by getIcon()
|
||||
-- Default: { "/usr/share/pixmaps/", }
|
||||
-- @field icon_formats List of formats that will be checked by getIcon()
|
||||
-- Default: { "png", "gif" }
|
||||
-- @field default_preset Preset to be used by default.
|
||||
-- Default: config.presets.normal
|
||||
-- @class table
|
||||
|
||||
config = {}
|
||||
config.padding = 4
|
||||
config.spacing = 1
|
||||
config.icon_dirs = { "/usr/share/pixmaps/", }
|
||||
config.icon_formats = { "png", "gif" }
|
||||
|
||||
|
||||
--- Notification Presets - a table containing presets for different purposes
|
||||
-- Preset is a table of any parameters available to notify()
|
||||
-- You have to pass a reference of a preset in your notify() call to use the preset
|
||||
-- At least the default preset named "normal" has to be defined
|
||||
-- The presets "low", "normal" and "critical" are used for notifications over DBUS
|
||||
-- @name config.presets
|
||||
-- @field low The preset for notifications with low urgency level
|
||||
-- @field normal The default preset for every notification without a preset that will also be used for normal urgency level
|
||||
-- @field critical The preset for notifications with a critical urgency level
|
||||
-- @class table
|
||||
|
||||
config.presets = {
|
||||
normal = {},
|
||||
low = {
|
||||
timeout = 5
|
||||
},
|
||||
critical = {
|
||||
bg = "#ff0000",
|
||||
fg = "#ffffff",
|
||||
timeout = 0,
|
||||
}
|
||||
}
|
||||
|
||||
config.default_preset = config.presets.normal
|
||||
|
||||
-- DBUS Notification constants
|
||||
urgency = {
|
||||
low = "\0",
|
||||
normal = "\1",
|
||||
critical = "\2"
|
||||
}
|
||||
|
||||
--- DBUS notification to preset mapping
|
||||
-- @name config.mapping
|
||||
-- The first element is an object containing the filter
|
||||
-- If the rules in the filter matches the associated preset will be applied
|
||||
-- The rules object can contain: urgency, category, appname
|
||||
-- The second element is the preset
|
||||
|
||||
config.mapping = {
|
||||
{{urgency = urgency.low}, config.presets.low},
|
||||
{{urgency = urgency.normal}, config.presets.normal},
|
||||
{{urgency = urgency.critical}, config.presets.critical}
|
||||
}
|
||||
|
||||
-- Counter for the notifications
|
||||
-- Required for later access via DBUS
|
||||
local counter = 1
|
||||
|
||||
-- True if notifying is suspended
|
||||
local suspended = false
|
||||
|
||||
--- Index of notifications. See config table for valid 'position' values.
|
||||
-- Each element is a table consisting of:
|
||||
-- @field box Wibox object containing the popup
|
||||
-- @field height Popup height
|
||||
-- @field width Popup width
|
||||
-- @field die Function to be executed on timeout
|
||||
-- @field id Unique notification id based on a counter
|
||||
-- @name notifications[screen][position]
|
||||
-- @class table
|
||||
|
||||
notifications = { suspended = { } }
|
||||
for s = 1, capi.screen.count() do
|
||||
notifications[s] = {
|
||||
top_left = {},
|
||||
top_right = {},
|
||||
bottom_left = {},
|
||||
bottom_right = {},
|
||||
}
|
||||
end
|
||||
|
||||
--- Suspend notifications
|
||||
function suspend()
|
||||
suspended = true
|
||||
end
|
||||
|
||||
--- Resume notifications
|
||||
function resume()
|
||||
suspended = false
|
||||
for i, v in pairs(notifications.suspended) do
|
||||
v.box.visible = true
|
||||
if v.timer then v.timer:start() end
|
||||
end
|
||||
notifications.suspended = { }
|
||||
end
|
||||
|
||||
-- Evaluate desired position of the notification by index - internal
|
||||
-- @param idx Index of the notification
|
||||
-- @param position top_right | top_left | bottom_right | bottom_left
|
||||
-- @param height Popup height
|
||||
-- @param width Popup width (optional)
|
||||
-- @return Absolute position and index in { x = X, y = Y, idx = I } table
|
||||
local function get_offset(screen, position, idx, width, height)
|
||||
local ws = capi.screen[screen].workarea
|
||||
local v = {}
|
||||
local idx = idx or #notifications[screen][position] + 1
|
||||
local width = width or notifications[screen][position][idx].width
|
||||
|
||||
-- calculate x
|
||||
if position:match("left") then
|
||||
v.x = ws.x + config.padding
|
||||
else
|
||||
v.x = ws.x + ws.width - (width + config.padding)
|
||||
end
|
||||
|
||||
-- calculate existing popups' height
|
||||
local existing = 0
|
||||
for i = 1, idx-1, 1 do
|
||||
existing = existing + notifications[screen][position][i].height + config.spacing
|
||||
end
|
||||
|
||||
-- calculate y
|
||||
if position:match("top") then
|
||||
v.y = ws.y + config.padding + existing
|
||||
else
|
||||
v.y = ws.y + ws.height - (config.padding + height + existing)
|
||||
end
|
||||
|
||||
-- if positioned outside workarea, destroy oldest popup and recalculate
|
||||
if v.y + height > ws.y + ws.height or v.y < ws.y then
|
||||
idx = idx - 1
|
||||
destroy(notifications[screen][position][1])
|
||||
v = get_offset(screen, position, idx, width, height)
|
||||
end
|
||||
if not v.idx then v.idx = idx end
|
||||
|
||||
return v
|
||||
end
|
||||
|
||||
-- Re-arrange notifications according to their position and index - internal
|
||||
-- @return None
|
||||
local function arrange(screen)
|
||||
for p,pos in pairs(notifications[screen]) do
|
||||
for i,notification in pairs(notifications[screen][p]) do
|
||||
local offset = get_offset(screen, p, i, notification.width, notification.height)
|
||||
notification.box:geometry({ x = offset.x, y = offset.y })
|
||||
notification.idx = offset.idx
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--- Destroy notification by notification object
|
||||
-- @param notification Notification object to be destroyed
|
||||
-- @return True if the popup was successfully destroyed, nil otherwise
|
||||
function destroy(notification)
|
||||
if notification and notification.box.screen then
|
||||
if suspended then
|
||||
for k, v in pairs(notifications.suspended) do
|
||||
if v.box == notification.box then
|
||||
table.remove(notifications.suspended, k)
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
local scr = notification.box.screen
|
||||
table.remove(notifications[notification.box.screen][notification.position], notification.idx)
|
||||
if notification.timer then
|
||||
notification.timer:stop()
|
||||
end
|
||||
notification.box.screen = nil
|
||||
arrange(scr)
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
-- Get notification by ID
|
||||
-- @param id ID of the notification
|
||||
-- @return notification object if it was found, nil otherwise
|
||||
local function getById(id)
|
||||
-- iterate the notifications to get the notfications with the correct ID
|
||||
for s = 1, capi.screen.count() do
|
||||
for p,pos in pairs(notifications[s]) do
|
||||
for i,notification in pairs(notifications[s][p]) do
|
||||
if notification.id == id then
|
||||
return notification
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Search for an icon in specified directories with a specified format
|
||||
-- @param icon Name of the icon
|
||||
-- @return full path of the icon, or nil of no icon was found
|
||||
local function getIcon(name)
|
||||
for d, dir in pairs(config.icon_dirs) do
|
||||
for f, format in pairs(config.icon_formats) do
|
||||
local icon = dir .. name .. "." .. format
|
||||
if util.file_readable(icon) then
|
||||
return icon
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--- Create notification. args is a dictionary of (optional) arguments.
|
||||
-- @param text Text of the notification. Default: ''
|
||||
-- @param title Title of the notification. Default: nil
|
||||
-- @param timeout Time in seconds after which popup expires.
|
||||
-- Set 0 for no timeout. Default: 5
|
||||
-- @param hover_timeout Delay in seconds after which hovered popup disappears.
|
||||
-- Default: nil
|
||||
-- @param screen Target screen for the notification. Default: 1
|
||||
-- @param position Corner of the workarea displaying the popups.
|
||||
-- Values: "top_right" (default), "top_left", "bottom_left", "bottom_right".
|
||||
-- @param ontop Boolean forcing popups to display on top. Default: true
|
||||
-- @param height Popup height. Default: nil (auto)
|
||||
-- @param width Popup width. Default: nil (auto)
|
||||
-- @param font Notification font. Default: beautiful.font or awesome.font
|
||||
-- @param icon Path to icon. Default: nil
|
||||
-- @param icon_size Desired icon size in px. Default: nil
|
||||
-- @param fg Foreground color. Default: beautiful.fg_focus or '#ffffff'
|
||||
-- @param bg Background color. Default: beautiful.bg_focus or '#535d6c'
|
||||
-- @param border_width Border width. Default: 1
|
||||
-- @param border_color Border color.
|
||||
-- Default: beautiful.border_focus or '#535d6c'
|
||||
-- @param run Function to run on left click. Default: nil
|
||||
-- @param preset Table with any of the above parameters. Note: Any parameters
|
||||
-- specified directly in args will override ones defined in the preset.
|
||||
-- @param replaces_id Replace the notification with the given ID
|
||||
-- @param callback function that will be called with all arguments
|
||||
-- the notification will only be displayed if the function returns true
|
||||
-- note: this function is only relevant to notifications sent via dbus
|
||||
-- @usage naughty.notify({ title = "Achtung!", text = "You're idling", timeout = 0 })
|
||||
-- @return The notification object
|
||||
function notify(args)
|
||||
-- gather variables together
|
||||
local preset = args.preset or config.default_preset or {}
|
||||
local timeout = args.timeout or preset.timeout or 5
|
||||
local icon = args.icon or preset.icon
|
||||
local icon_size = args.icon_size or preset.icon_size
|
||||
local text = args.text or preset.text or ""
|
||||
local title = args.title or preset.title
|
||||
local screen = args.screen or preset.screen or 1
|
||||
local ontop = args.ontop or preset.ontop or true
|
||||
local width = args.width or preset.width
|
||||
local height = args.height or preset.height
|
||||
local hover_timeout = args.hover_timeout or preset.hover_timeout
|
||||
local opacity = args.opacity or preset.opacity
|
||||
local margin = args.margin or preset.margin or "5"
|
||||
local border_width = args.border_width or preset.border_width or "1"
|
||||
local position = args.position or preset.position or "top_right"
|
||||
|
||||
-- beautiful
|
||||
local beautiful = bt.get()
|
||||
local font = args.font or preset.font or beautiful.font or capi.awesome.font
|
||||
local fg = args.fg or preset.fg or beautiful.fg_normal or '#ffffff'
|
||||
local bg = args.bg or preset.bg or beautiful.bg_normal or '#535d6c'
|
||||
local border_color = args.border_color or preset.border_color or beautiful.bg_focus or '#535d6c'
|
||||
local notification = {}
|
||||
|
||||
-- replace notification if needed
|
||||
if args.replaces_id then
|
||||
local obj = getById(args.replaces_id)
|
||||
if obj then
|
||||
-- destroy this and ...
|
||||
destroy(obj)
|
||||
end
|
||||
-- ... may use its ID
|
||||
if args.replaces_id < counter then
|
||||
notification.id = args.replaces_id
|
||||
else
|
||||
counter = counter + 1
|
||||
notification.id = counter
|
||||
end
|
||||
else
|
||||
-- get a brand new ID
|
||||
counter = counter + 1
|
||||
notification.id = counter
|
||||
end
|
||||
|
||||
notification.position = position
|
||||
|
||||
if title then title = title .. "\n" else title = "" end
|
||||
|
||||
-- hook destroy
|
||||
local die = function () destroy(notification) end
|
||||
if timeout > 0 then
|
||||
local timer_die = capi.timer { timeout = timeout }
|
||||
timer_die:add_signal("timeout", die)
|
||||
if not suspended then
|
||||
timer_die:start()
|
||||
end
|
||||
notification.timer = timer_die
|
||||
end
|
||||
notification.die = die
|
||||
|
||||
local run = function ()
|
||||
if args.run then
|
||||
args.run(notification)
|
||||
else
|
||||
die()
|
||||
end
|
||||
end
|
||||
|
||||
local hover_destroy = function ()
|
||||
if hover_timeout == 0 then
|
||||
die()
|
||||
else
|
||||
if notification.timer then notification.timer:stop() end
|
||||
notification.timer = capi.timer { timeout = hover_timeout }
|
||||
notification.timer:add_signal("timeout", die)
|
||||
notification.timer:start()
|
||||
end
|
||||
end
|
||||
|
||||
-- create textbox
|
||||
local textbox = capi.widget({ type = "textbox", align = "flex" })
|
||||
textbox:buttons(util.table.join(button({ }, 1, run), button({ }, 3, die)))
|
||||
layout.margins[textbox] = { right = margin, left = margin, bottom = margin, top = margin }
|
||||
textbox.valign = "middle"
|
||||
|
||||
local function setText(pattern, replacements)
|
||||
textbox.text = string.format('<span font_desc="%s"><b>%s</b>%s</span>', font, title, text:gsub(pattern, replacements))
|
||||
end
|
||||
|
||||
-- First try to set the text while only interpreting <br>.
|
||||
-- (Setting a textbox' .text to an invalid pattern throws a lua error)
|
||||
if not pcall(setText, "<br.->", "\n") then
|
||||
-- That failed, escape everything which might cause an error from pango
|
||||
if not pcall(setText, "[<>&]", { ['<'] = "<", ['>'] = ">", ['&'] = "&" }) then
|
||||
textbox.text = "<i><Invalid markup, cannot display message></i>"
|
||||
end
|
||||
end
|
||||
|
||||
-- create iconbox
|
||||
local iconbox = nil
|
||||
if icon then
|
||||
-- try to guess icon if the provided one is non-existent/readable
|
||||
if type(icon) == "string" and not util.file_readable(icon) then
|
||||
icon = getIcon(icon)
|
||||
end
|
||||
|
||||
-- if we have an icon, use it
|
||||
if icon then
|
||||
iconbox = capi.widget({ type = "imagebox", align = "left" })
|
||||
layout.margins[iconbox] = { right = margin, left = margin, bottom = margin, top = margin }
|
||||
iconbox:buttons(util.table.join(button({ }, 1, run), button({ }, 3, die)))
|
||||
local img
|
||||
if type(icon) == "string" then
|
||||
img = capi.image(icon)
|
||||
else
|
||||
img = icon
|
||||
end
|
||||
if icon_size then
|
||||
img = img:crop_and_scale(0,0,img.height,img.width,icon_size,icon_size)
|
||||
end
|
||||
iconbox.resize = false
|
||||
iconbox.image = img
|
||||
end
|
||||
end
|
||||
|
||||
-- create container wibox
|
||||
notification.box = capi.wibox({ fg = fg,
|
||||
bg = bg,
|
||||
border_color = border_color,
|
||||
border_width = border_width })
|
||||
|
||||
if hover_timeout then notification.box:add_signal("mouse::enter", hover_destroy) end
|
||||
|
||||
-- calculate the height
|
||||
if not height then
|
||||
if iconbox and iconbox:extents().height + 2 * margin > textbox:extents().height + 2 * margin then
|
||||
height = iconbox:extents().height + 2 * margin
|
||||
else
|
||||
height = textbox:extents().height + 2 * margin
|
||||
end
|
||||
end
|
||||
|
||||
-- calculate the width
|
||||
if not width then
|
||||
width = textbox:extents().width + (iconbox and iconbox:extents().width + 2 * margin or 0) + 2 * margin
|
||||
end
|
||||
|
||||
-- crop to workarea size if too big
|
||||
local workarea = capi.screen[screen].workarea
|
||||
if width > workarea.width - 2 * (border_width or 0) - 2 * (config.padding or 0) then
|
||||
width = workarea.width - 2 * (border_width or 0) - 2 * (config.padding or 0)
|
||||
end
|
||||
if height > workarea.height - 2 * (border_width or 0) - 2 * (config.padding or 0) then
|
||||
height = workarea.height - 2 * (border_width or 0) - 2 * (config.padding or 0)
|
||||
end
|
||||
|
||||
-- set size in notification object
|
||||
notification.height = height + 2 * (border_width or 0)
|
||||
notification.width = width + 2 * (border_width or 0)
|
||||
|
||||
-- position the wibox
|
||||
local offset = get_offset(screen, notification.position, nil, notification.width, notification.height)
|
||||
notification.box.ontop = ontop
|
||||
notification.box:geometry({ width = width,
|
||||
height = height,
|
||||
x = offset.x,
|
||||
y = offset.y })
|
||||
notification.box.opacity = opacity
|
||||
notification.box.screen = screen
|
||||
notification.idx = offset.idx
|
||||
|
||||
-- populate widgets
|
||||
notification.box.widgets = { iconbox, textbox, ["layout"] = layout.horizontal.leftright }
|
||||
|
||||
-- insert the notification to the table
|
||||
table.insert(notifications[screen][notification.position], notification)
|
||||
|
||||
if suspended then
|
||||
notification.box.visible = false
|
||||
table.insert(notifications.suspended, notification)
|
||||
end
|
||||
|
||||
-- return the notification
|
||||
return notification
|
||||
end
|
||||
|
||||
-- DBUS/Notification support
|
||||
-- Notify
|
||||
if capi.dbus then
|
||||
capi.dbus.add_signal("org.freedesktop.Notifications", function (data, appname, replaces_id, icon, title, text, actions, hints, expire)
|
||||
args = { preset = { } }
|
||||
if data.member == "Notify" then
|
||||
if text ~= "" then
|
||||
args.text = text
|
||||
if title ~= "" then
|
||||
args.title = title
|
||||
end
|
||||
else
|
||||
if title ~= "" then
|
||||
args.text = title
|
||||
else
|
||||
return
|
||||
end
|
||||
end
|
||||
local score = 0
|
||||
for i, obj in pairs(config.mapping) do
|
||||
local filter, preset, s = obj[1], obj[2], 0
|
||||
if (not filter.urgency or filter.urgency == hints.urgency) and
|
||||
(not filter.category or filter.category == hints.category) and
|
||||
(not filter.appname or filter.appname == appname) then
|
||||
for j, el in pairs(filter) do s = s + 1 end
|
||||
if s > score then
|
||||
score = s
|
||||
args.preset = preset
|
||||
end
|
||||
end
|
||||
end
|
||||
if not args.preset.callback or (type(args.preset.callback) == "function" and
|
||||
args.preset.callback(data, appname, replaces_id, icon, title, text, actions, hints, expire)) then
|
||||
if icon ~= "" then
|
||||
args.icon = icon
|
||||
elseif hints.icon_data or hints.image_data then
|
||||
if hints.icon_data == nil then hints.icon_data = hints.image_data end
|
||||
-- icon_data is an array:
|
||||
-- 1 -> width, 2 -> height, 3 -> rowstride, 4 -> has alpha
|
||||
-- 5 -> bits per sample, 6 -> channels, 7 -> data
|
||||
|
||||
local imgdata
|
||||
-- If has alpha (ARGB32)
|
||||
if hints.icon_data[6] == 4 then
|
||||
imgdata = hints.icon_data[7]
|
||||
-- If has not alpha (RGB24)
|
||||
elseif hints.icon_data[6] == 3 then
|
||||
imgdata = ""
|
||||
for i = 1, #hints.icon_data[7], 3 do
|
||||
imgdata = imgdata .. hints.icon_data[7]:sub(i , i + 2):reverse()
|
||||
imgdata = imgdata .. string.format("%c", 255) -- alpha is 255
|
||||
end
|
||||
end
|
||||
if imgdata then
|
||||
args.icon = capi.image.argb32(hints.icon_data[1], hints.icon_data[2], imgdata)
|
||||
end
|
||||
end
|
||||
if replaces_id and replaces_id ~= "" and replaces_id ~= 0 then
|
||||
args.replaces_id = replaces_id
|
||||
end
|
||||
if expire and expire > -1 then
|
||||
args.timeout = expire / 1000
|
||||
end
|
||||
local id = notify(args).id
|
||||
return "u", id
|
||||
end
|
||||
return "u", "0"
|
||||
elseif data.member == "CloseNotification" then
|
||||
local obj = getById(appname)
|
||||
if obj then
|
||||
destroy(obj)
|
||||
end
|
||||
elseif data.member == "GetServerInfo" or data.member == "GetServerInformation" then
|
||||
-- name of notification app, name of vender, version
|
||||
return "s", "naughty", "s", "awesome", "s", capi.awesome.version:match("%d.%d"), "s", "1.0"
|
||||
elseif data.member == "GetCapabilities" then
|
||||
-- We actually do display the body of the message, we support <b>, <i>
|
||||
-- and <u> in the body and we handle static (non-animated) icons.
|
||||
return "as", { "s", "body", "s", "body-markup", "s", "icon-static" }
|
||||
end
|
||||
end)
|
||||
|
||||
capi.dbus.add_signal("org.freedesktop.DBus.Introspectable",
|
||||
function (data, text)
|
||||
if data.member == "Introspect" then
|
||||
local xml = [=[<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object
|
||||
Introspection 1.0//EN"
|
||||
"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
|
||||
<node>
|
||||
<interface name="org.freedesktop.DBus.Introspectable">
|
||||
<method name="Introspect">
|
||||
<arg name="data" direction="out" type="s"/>
|
||||
</method>
|
||||
</interface>
|
||||
<interface name="org.freedesktop.Notifications">
|
||||
<method name="GetCapabilities">
|
||||
<arg name="caps" type="as" direction="out"/>
|
||||
</method>
|
||||
<method name="CloseNotification">
|
||||
<arg name="id" type="u" direction="in"/>
|
||||
</method>
|
||||
<method name="Notify">
|
||||
<arg name="app_name" type="s" direction="in"/>
|
||||
<arg name="id" type="u" direction="in"/>
|
||||
<arg name="icon" type="s" direction="in"/>
|
||||
<arg name="summary" type="s" direction="in"/>
|
||||
<arg name="body" type="s" direction="in"/>
|
||||
<arg name="actions" type="as" direction="in"/>
|
||||
<arg name="hints" type="a{sv}" direction="in"/>
|
||||
<arg name="timeout" type="i" direction="in"/>
|
||||
<arg name="return_id" type="u" direction="out"/>
|
||||
</method>
|
||||
<method name="GetServerInformation">
|
||||
<arg name="return_name" type="s" direction="out"/>
|
||||
<arg name="return_vendor" type="s" direction="out"/>
|
||||
<arg name="return_version" type="s" direction="out"/>
|
||||
<arg name="return_spec_version" type="s" direction="out"/>
|
||||
</method>
|
||||
<method name="GetServerInfo">
|
||||
<arg name="return_name" type="s" direction="out"/>
|
||||
<arg name="return_vendor" type="s" direction="out"/>
|
||||
<arg name="return_version" type="s" direction="out"/>
|
||||
</method>
|
||||
</interface>
|
||||
</node>]=]
|
||||
return "s", xml
|
||||
end
|
||||
end)
|
||||
|
||||
-- listen for dbus notification requests
|
||||
capi.dbus.request_name("session", "org.freedesktop.Notifications")
|
||||
end
|
||||
|
||||
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80
|
@ -0,0 +1,129 @@
|
||||
-------------------------------------------------------------------
|
||||
-- Drop-down applications manager for the awesome window manager
|
||||
-------------------------------------------------------------------
|
||||
-- Coded by: * Lucas de Vries <lucas@glacicle.com>
|
||||
-- Hacked by: * Adrian C. (anrxc) <anrxc@sysphere.org>
|
||||
-- Licensed under the WTFPL version 2
|
||||
-- * http://sam.zoy.org/wtfpl/COPYING
|
||||
-------------------------------------------------------------------
|
||||
-- To use this module add:
|
||||
-- require("scratch")
|
||||
-- to the top of your rc.lua, and call it from a keybinding:
|
||||
-- scratch.drop(prog, vert, horiz, width, height, sticky, screen)
|
||||
--
|
||||
-- Parameters:
|
||||
-- prog - Program to run; "urxvt", "gmrun", "thunderbird"
|
||||
-- vert - Vertical; "bottom", "center" or "top" (default)
|
||||
-- horiz - Horizontal; "left", "right" or "center" (default)
|
||||
-- width - Width in absolute pixels, or width percentage
|
||||
-- when <= 1 (1 (100% of the screen) by default)
|
||||
-- height - Height in absolute pixels, or height percentage
|
||||
-- when <= 1 (0.25 (25% of the screen) by default)
|
||||
-- sticky - Visible on all tags, false by default
|
||||
-- screen - Screen (optional), mouse.screen by default
|
||||
-------------------------------------------------------------------
|
||||
|
||||
-- Grab environment
|
||||
local pairs = pairs
|
||||
local awful = require("awful")
|
||||
local setmetatable = setmetatable
|
||||
local capi = {
|
||||
mouse = mouse,
|
||||
client = client,
|
||||
screen = screen
|
||||
}
|
||||
|
||||
-- Scratchdrop: drop-down applications manager for the awesome window manager
|
||||
module("scratch.drop")
|
||||
|
||||
local dropdown = {}
|
||||
|
||||
-- Create a new window for the drop-down application when it doesn't
|
||||
-- exist, or toggle between hidden and visible states when it does
|
||||
function toggle(prog, vert, horiz, width, height, sticky, screen)
|
||||
vert = vert or "top"
|
||||
horiz = horiz or "center"
|
||||
width = width or 1
|
||||
height = height or 0.25
|
||||
sticky = sticky or false
|
||||
screen = screen or capi.mouse.screen
|
||||
|
||||
if not dropdown[prog] then
|
||||
dropdown[prog] = {}
|
||||
|
||||
-- Add unmanage signal for scratchdrop programs
|
||||
capi.client.add_signal("unmanage", function (c)
|
||||
for scr, cl in pairs(dropdown[prog]) do
|
||||
if cl == c then
|
||||
dropdown[prog][scr] = nil
|
||||
end
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
if not dropdown[prog][screen] then
|
||||
spawnw = function (c)
|
||||
dropdown[prog][screen] = c
|
||||
|
||||
-- Scratchdrop clients are floaters
|
||||
awful.client.floating.set(c, true)
|
||||
|
||||
-- Client geometry and placement
|
||||
local screengeom = capi.screen[screen].workarea
|
||||
|
||||
if width <= 1 then width = screengeom.width * width end
|
||||
if height <= 1 then height = screengeom.height * height end
|
||||
|
||||
if horiz == "left" then x = screengeom.x
|
||||
elseif horiz == "right" then x = screengeom.width - width
|
||||
else x = screengeom.x+(screengeom.width-width)/2 end
|
||||
|
||||
if vert == "bottom" then y = screengeom.height + screengeom.y - height
|
||||
elseif vert == "center" then y = screengeom.y+(screengeom.height-height)/2
|
||||
else y = screengeom.y - screengeom.y end
|
||||
|
||||
-- Client properties
|
||||
c:geometry({ x = x, y = y, width = width, height = height })
|
||||
c.ontop = true
|
||||
c.above = true
|
||||
c.skip_taskbar = true
|
||||
if sticky then c.sticky = true end
|
||||
if c.titlebar then awful.titlebar.remove(c) end
|
||||
|
||||
c:raise()
|
||||
capi.client.focus = c
|
||||
capi.client.remove_signal("manage", spawnw)
|
||||
end
|
||||
|
||||
-- Add manage signal and spawn the program
|
||||
capi.client.add_signal("manage", spawnw)
|
||||
awful.util.spawn(prog, false)
|
||||
else
|
||||
-- Get a running client
|
||||
c = dropdown[prog][screen]
|
||||
|
||||
-- Switch the client to the current workspace
|
||||
if c:isvisible() == false then c.hidden = true
|
||||
awful.client.movetotag(awful.tag.selected(screen), c)
|
||||
end
|
||||
|
||||
-- Focus and raise if hidden
|
||||
if c.hidden then
|
||||
-- Make sure it is centered
|
||||
if vert == "center" then awful.placement.center_vertical(c) end
|
||||
if horiz == "center" then awful.placement.center_horizontal(c) end
|
||||
c.hidden = false
|
||||
c:raise()
|
||||
capi.client.focus = c
|
||||
else -- Hide and detach tags if not
|
||||
c.hidden = true
|
||||
local ctags = c:tags()
|
||||
for i, t in pairs(ctags) do
|
||||
ctags[i] = nil
|
||||
end
|
||||
c:tags(ctags)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
setmetatable(_M, { __call = function(_, ...) return toggle(...) end })
|
@ -0,0 +1,12 @@
|
||||
---------------------------------------------------------------
|
||||
-- Drop-down applications and scratchpad manager for awesome wm
|
||||
---------------------------------------------------------------
|
||||
-- Coded by: * Adrian C. (anrxc) <anrxc@sysphere.org>
|
||||
-- Licensed under the WTFPL version 2
|
||||
-- * http://sam.zoy.org/wtfpl/COPYING
|
||||
---------------------------------------------------------------
|
||||
|
||||
require("scratch.pad")
|
||||
require("scratch.drop")
|
||||
|
||||
module("scratch")
|
@ -0,0 +1,130 @@
|
||||
---------------------------------------------------------------
|
||||
-- Basic scratchpad manager for the awesome window manager
|
||||
---------------------------------------------------------------
|
||||
-- Coded by: * Adrian C. (anrxc) <anrxc@sysphere.org>
|
||||
-- Licensed under the WTFPL version 2
|
||||
-- * http://sam.zoy.org/wtfpl/COPYING
|
||||
---------------------------------------------------------------
|
||||
-- To use this module add:
|
||||
-- require("scratch")
|
||||
-- to the top of your rc.lua, and call:
|
||||
-- scratch.pad.set(c, width, height, sticky, screen)
|
||||
-- from a clientkeys binding, and:
|
||||
-- scratch.pad.toggle(screen)
|
||||
-- from a globalkeys binding.
|
||||
--
|
||||
-- Parameters:
|
||||
-- c - Client to scratch or un-scratch
|
||||
-- width - Width in absolute pixels, or width percentage
|
||||
-- when <= 1 (0.50 (50% of the screen) by default)
|
||||
-- height - Height in absolute pixels, or height percentage
|
||||
-- when <= 1 (0.50 (50% of the screen) by default)
|
||||
-- sticky - Visible on all tags, false by default
|
||||
-- screen - Screen (optional), mouse.screen by default
|
||||
---------------------------------------------------------------
|
||||
|
||||
-- Grab environment
|
||||
local pairs = pairs
|
||||
local awful = require("awful")
|
||||
local capi = {
|
||||
mouse = mouse,
|
||||
client = client,
|
||||
screen = screen
|
||||
}
|
||||
|
||||
-- Scratchpad: basic scratchpad manager for the awesome window manager
|
||||
module("scratch.pad")
|
||||
|
||||
local scratchpad = {}
|
||||
|
||||
-- Toggle a set of properties on a client.
|
||||
local function toggleprop(c, prop)
|
||||
c.ontop = prop.ontop or false
|
||||
c.above = prop.above or false
|
||||
c.hidden = prop.hidden or false
|
||||
c.sticky = prop.stick or false
|
||||
c.skip_taskbar = prop.task or false
|
||||
end
|
||||
|
||||
-- Scratch the focused client, or un-scratch and tile it. If another
|
||||
-- client is already scratched, replace it with the focused client.
|
||||
function set(c, width, height, sticky, screen)
|
||||
width = width or 0.50
|
||||
height = height or 0.50
|
||||
sticky = sticky or false
|
||||
screen = screen or capi.mouse.screen
|
||||
|
||||
local function setscratch(c)
|
||||
-- Scratchpad is floating and has no titlebar
|
||||
awful.client.floating.set(c, true); awful.titlebar.remove(c)
|
||||
|
||||
-- Scratchpad client properties
|
||||
toggleprop(c, {ontop=true, above=true, task=true, stick=sticky})
|
||||
|
||||
-- Scratchpad geometry and placement
|
||||
local screengeom = capi.screen[screen].workarea
|
||||
if width <= 1 then width = screengeom.width * width end
|
||||
if height <= 1 then height = screengeom.height * height end
|
||||
|
||||
c:geometry({ -- Scratchpad is always centered on screen
|
||||
x = screengeom.x + (screengeom.width - width) / 2,
|
||||
y = screengeom.y + (screengeom.height - height) / 2,
|
||||
width = width, height = height
|
||||
})
|
||||
|
||||
-- Scratchpad should not loose focus
|
||||
c:raise(); capi.client.focus = c
|
||||
end
|
||||
|
||||
-- Prepare a table for storing clients,
|
||||
if not scratchpad.pad then scratchpad.pad = {}
|
||||
-- add unmanage signal for scratchpad clients
|
||||
capi.client.add_signal("unmanage", function (c)
|
||||
for scr, cl in pairs(scratchpad.pad) do
|
||||
if cl == c then scratchpad.pad[scr] = nil end
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
-- If the scratcphad is emtpy, store the client,
|
||||
if not scratchpad.pad[screen] then
|
||||
scratchpad.pad[screen] = c
|
||||
-- then apply geometry and properties
|
||||
setscratch(c)
|
||||
else -- If a client is already scratched,
|
||||
local oc = scratchpad.pad[screen]
|
||||
-- unscratch, and compare it with the focused client
|
||||
awful.client.floating.toggle(oc); toggleprop(oc, {})
|
||||
-- If it matches clear the table, if not replace it
|
||||
if oc == c then scratchpad.pad[screen] = nil
|
||||
else scratchpad.pad[screen] = c; setscratch(c) end
|
||||
end
|
||||
end
|
||||
|
||||
-- Move the scratchpad to the current workspace, focus and raise it
|
||||
-- when it's hidden, or hide it when it's visible.
|
||||
function toggle(screen)
|
||||
screen = screen or capi.mouse.screen
|
||||
|
||||
-- Check if we have a client on storage,
|
||||
if scratchpad.pad and
|
||||
scratchpad.pad[screen] ~= nil
|
||||
then -- and get it out, to play
|
||||
local c = scratchpad.pad[screen]
|
||||
|
||||
-- If it's visible on another tag hide it,
|
||||
if c:isvisible() == false then c.hidden = true
|
||||
-- and move it to the current worskpace
|
||||
awful.client.movetotag(awful.tag.selected(screen), c)
|
||||
end
|
||||
|
||||
-- Focus and raise if it's hidden,
|
||||
if c.hidden then
|
||||
awful.placement.centered(c)
|
||||
c.hidden = false
|
||||
c:raise(); capi.client.focus = c
|
||||
else -- hide it if it's not
|
||||
c.hidden = true
|
||||
end
|
||||
end
|
||||
end
|
@ -0,0 +1,51 @@
|
||||
---------------------------------------------------
|
||||
-- Licensed under the GNU General Public License v2
|
||||
-- * (c) 2010, Adrian C. <anrxc@sysphere.org>
|
||||
---------------------------------------------------
|
||||
|
||||
-- {{{ Grab environment
|
||||
local tonumber = tonumber
|
||||
local io = { popen = io.popen }
|
||||
local setmetatable = setmetatable
|
||||
local table = { insert = table.insert }
|
||||
local string = { match = string.match }
|
||||
-- }}}
|
||||
|
||||
|
||||
-- Batacpi: provides state, charge, and remaining time for all batteries using acpitool
|
||||
module("vicious.contrib.batacpi")
|
||||
|
||||
|
||||
-- {{{ Battery widget type
|
||||
local function worker(format)
|
||||
local battery_info = {}
|
||||
local battery_state = {
|
||||
["full"] = "↯",
|
||||
["unknown"] = "⌁",
|
||||
["charged"] = "↯",
|
||||
["charging"] = "+",
|
||||
["discharging"] = "-"
|
||||
}
|
||||
|
||||
-- Get data from acpitool
|
||||
local f = io.popen("acpitool -b")
|
||||
|
||||
for line in f:lines() do
|
||||
-- Check if the battery is present
|
||||
if string.match(line, "^[%s]+Battery.*") then
|
||||
-- Store state and charge information
|
||||
table.insert(battery_info, (battery_state[string.match(line, "([%a]*),") or "unknown"]))
|
||||
table.insert(battery_info, (tonumber(string.match(line, "([%d]?[%d]?[%d])%.")) or 0))
|
||||
-- Store remaining time information
|
||||
table.insert(battery_info, (string.match(line, "%%,%s(.*)") or "N/A"))
|
||||
else
|
||||
return {battery_state["unknown"], 0, "N/A"}
|
||||
end
|
||||
end
|
||||
f:close()
|
||||
|
||||
return battery_info
|
||||
end
|
||||
-- }}}
|
||||
|
||||
setmetatable(_M, { __call = function(_, ...) return worker(...) end })
|
@ -0,0 +1,78 @@
|
||||
---------------------------------------------------
|
||||
-- Licensed under the GNU General Public License v2
|
||||
-- * (c) 2010, Adrian C. <anrxc@sysphere.org>
|
||||
---------------------------------------------------
|
||||
|
||||
-- {{{ Grab environment
|
||||
local tonumber = tonumber
|
||||
local io = { open = io.open }
|
||||
local setmetatable = setmetatable
|
||||
local math = {
|
||||
min = math.min,
|
||||
floor = math.floor
|
||||
}
|
||||
local string = {
|
||||
find = string.find,
|
||||
match = string.match,
|
||||
format = string.format
|
||||
}
|
||||
-- }}}
|
||||
|
||||
|
||||
-- Batpmu: provides state, charge and remaining time for a requested battery using PMU
|
||||
module("vicious.contrib.batpmu")
|
||||
|
||||
|
||||
-- {{{ Battery widget type
|
||||
local function worker(format, batid)
|
||||
local battery_state = {
|
||||
["full"] = "↯",
|
||||
["unknown"] = "⌁",
|
||||
["00000013"] = "+",
|
||||
["00000011"] = "-"
|
||||
}
|
||||
|
||||
-- Get /proc/pmu/battery* state
|
||||
local f = io.open("/proc/pmu/" .. batid)
|
||||
-- Handler for incompetent users
|
||||
if not f then return {battery_state["unknown"], 0, "N/A"} end
|
||||
local statefile = f:read("*all")
|
||||
f:close()
|
||||
|
||||
-- Get /proc/pmu/info data
|
||||
local f = io.open("/proc/pmu/info")
|
||||
local infofile = f:read("*all")
|
||||
f:close()
|
||||
|
||||
-- Check if the battery is present
|
||||
if infofile == nil or string.find(infofile, "Battery count[%s]+:[%s]0") then
|
||||
return {battery_state["unknown"], 0, "N/A"}
|
||||
end
|
||||
|
||||
|
||||
-- Get capacity and charge information
|
||||
local capacity = string.match(statefile, "max_charge[%s]+:[%s]([%d]+).*")
|
||||
local remaining = string.match(statefile, "charge[%s]+:[%s]([%d]+).*")
|
||||
|
||||
-- Calculate percentage
|
||||
local percent = math.min(math.floor(remaining / capacity * 100), 100)
|
||||
|
||||
|
||||
-- Get timer information
|
||||
local timer = string.match(statefile, "time rem%.[%s]+:[%s]([%d]+).*")
|
||||
if timer == "0" then return {battery_state["full"], percent, "N/A"} end
|
||||
|
||||
-- Get state information
|
||||
local state = string.match(statefile, "flags[%s]+:[%s]([%d]+).*")
|
||||
local state = battery_state[state] or battery_state["unknown"]
|
||||
|
||||
-- Calculate remaining (charging or discharging) time
|
||||
local hoursleft = math.floor(tonumber(timer) / 3600)
|
||||
local minutesleft = math.floor((tonumber(timer) / 60) % 60)
|
||||
local time = string.format("%02d:%02d", hoursleft, minutesleft)
|
||||
|
||||
return {state, percent, time}
|
||||
end
|
||||
-- }}}
|
||||
|
||||
setmetatable(_M, { __call = function(_, ...) return worker(...) end })
|
@ -0,0 +1,85 @@
|
||||
---------------------------------------------------
|
||||
-- Licensed under the GNU General Public License v2
|
||||
-- * (c) 2010, Adrian C. <anrxc@sysphere.org>
|
||||
---------------------------------------------------
|
||||
|
||||
-- {{{ Grab environment
|
||||
local tonumber = tonumber
|
||||
local io = { open = io.open }
|
||||
local setmetatable = setmetatable
|
||||
local math = {
|
||||
min = math.min,
|
||||
floor = math.floor
|
||||
}
|
||||
local string = {
|
||||
find = string.find,
|
||||
match = string.match,
|
||||
format = string.format
|
||||
}
|
||||
-- }}}
|
||||
|
||||
|
||||
-- Batproc: provides state, charge, and remaining time for a requested battery using procfs
|
||||
module("vicious.contrib.batproc")
|
||||
|
||||
|
||||
-- {{{ Battery widget type
|
||||
local function worker(format, batid)
|
||||
local battery_state = {
|
||||
["full"] = "↯",
|
||||
["unknown"] = "⌁",
|
||||
["charged"] = "↯",
|
||||
["charging"] = "+",
|
||||
["discharging"] = "-"
|
||||
}
|
||||
|
||||
-- Get /proc/acpi/battery info
|
||||
local f = io.open("/proc/acpi/battery/"..batid.."/info")
|
||||
-- Handler for incompetent users
|
||||
if not f then return {battery_state["unknown"], 0, "N/A"} end
|
||||
local infofile = f:read("*all")
|
||||
f:close()
|
||||
|
||||
-- Check if the battery is present
|
||||
if infofile == nil or string.find(infofile, "present:[%s]+no") then
|
||||
return {battery_state["unknown"], 0, "N/A"}
|
||||
end
|
||||
|
||||
-- Get capacity information
|
||||
local capacity = string.match(infofile, "last full capacity:[%s]+([%d]+).*")
|
||||
|
||||
|
||||
-- Get /proc/acpi/battery state
|
||||
local f = io.open("/proc/acpi/battery/"..batid.."/state")
|
||||
local statefile = f:read("*all")
|
||||
f:close()
|
||||
|
||||
-- Get state information
|
||||
local state = string.match(statefile, "charging state:[%s]+([%a]+).*")
|
||||
local state = battery_state[state] or battery_state["unknown"]
|
||||
|
||||
-- Get charge information
|
||||
local rate = string.match(statefile, "present rate:[%s]+([%d]+).*")
|
||||
local remaining = string.match(statefile, "remaining capacity:[%s]+([%d]+).*")
|
||||
|
||||
|
||||
-- Calculate percentage (but work around broken BAT/ACPI implementations)
|
||||
local percent = math.min(math.floor(remaining / capacity * 100), 100)
|
||||
|
||||
-- Calculate remaining (charging or discharging) time
|
||||
if state == "+" then
|
||||
timeleft = (tonumber(capacity) - tonumber(remaining)) / tonumber(rate)
|
||||
elseif state == "-" then
|
||||
timeleft = tonumber(remaining) / tonumber(rate)
|
||||
else
|
||||
return {state, percent, "N/A"}
|
||||
end
|
||||
local hoursleft = math.floor(timeleft)
|
||||
local minutesleft = math.floor((timeleft - hoursleft) * 60 )
|
||||
local time = string.format("%02d:%02d", hoursleft, minutesleft)
|
||||
|
||||
return {state, percent, time}
|
||||
end
|
||||
-- }}}
|
||||
|
||||
setmetatable(_M, { __call = function(_, ...) return worker(...) end })
|
@ -0,0 +1,72 @@
|
||||
---------------------------------------------------
|
||||
-- Licensed under the GNU General Public License v2
|
||||
-- * (c) 2010, Adrian C. <anrxc@sysphere.org>
|
||||
---------------------------------------------------
|
||||
|
||||
-- {{{ Grab environment
|
||||
local ipairs = ipairs
|
||||
local setmetatable = setmetatable
|
||||
local table = { insert = table.insert }
|
||||
local string = { gmatch = string.gmatch }
|
||||
local helpers = require("vicious.helpers")
|
||||
-- }}}
|
||||
|
||||
|
||||
-- Disk I/O: provides I/O statistics for requested storage devices
|
||||
module("vicious.contrib.dio")
|
||||
|
||||
|
||||
-- Initialize function tables
|
||||
local disk_usage = {}
|
||||
local disk_total = {}
|
||||
-- Variable definitions
|
||||
local unit = { ["s"] = 1, ["kb"] = 2, ["mb"] = 2048 }
|
||||
|
||||
-- {{{ Disk I/O widget type
|
||||
local function worker(format, disk)
|
||||
if not disk then return end
|
||||
|
||||
local disk_lines = { [disk] = {} }
|
||||
local disk_stats = helpers.pathtotable("/sys/block/" .. disk)
|
||||
|
||||
if disk_stats.stat then
|
||||
local match = string.gmatch(disk_stats.stat, "[%s]+([%d]+)")
|
||||
for i = 1, 11 do -- Store disk stats
|
||||
table.insert(disk_lines[disk], match())
|
||||
end
|
||||
end
|
||||
|
||||
-- Ensure tables are initialized correctly
|
||||
local diff_total = { [disk] = {} }
|
||||
if not disk_total[disk] then
|
||||
disk_usage[disk] = {}
|
||||
disk_total[disk] = {}
|
||||
|
||||
while #disk_total[disk] < #disk_lines[disk] do
|
||||
table.insert(disk_total[disk], 0)
|
||||
end
|
||||
end
|
||||
|
||||
for i, v in ipairs(disk_lines[disk]) do
|
||||
-- Diskstats are absolute, substract our last reading
|
||||
diff_total[disk][i] = v - disk_total[disk][i]
|
||||
|
||||
-- Store totals
|
||||
disk_total[disk][i] = v
|
||||
end
|
||||
|
||||
-- Calculate and store I/O
|
||||
helpers.uformat(disk_usage[disk], "read", diff_total[disk][3], unit)
|
||||
helpers.uformat(disk_usage[disk], "write", diff_total[disk][7], unit)
|
||||
helpers.uformat(disk_usage[disk], "total", diff_total[disk][7] + diff_total[disk][3], unit)
|
||||
|
||||
-- Store I/O scheduler
|
||||
if disk_stats.queue and disk_stats.queue.scheduler then
|
||||
disk_usage[disk]["{sched}"] = string.gmatch(disk_stats.queue.scheduler, "%[([%a]+)%]")
|
||||
end
|
||||
|
||||
return disk_usage[disk]
|
||||
end
|
||||
-- }}}
|
||||
|
||||
setmetatable(_M, { __call = function(_, ...) return worker(...) end })
|
@ -0,0 +1,17 @@
|
||||
---------------------------------------------------
|
||||
-- Vicious widgets for the awesome window manager
|
||||
---------------------------------------------------
|
||||
-- Licensed under the GNU General Public License v2
|
||||
-- * (c) 2010, Adrian C. <anrxc@sysphere.org>
|
||||
---------------------------------------------------
|
||||
|
||||
-- {{{ Setup environment
|
||||
local setmetatable = setmetatable
|
||||
local wrequire = require("vicious.helpers").wrequire
|
||||
|
||||
-- Vicious: widgets for the awesome window manager
|
||||
module("vicious.contrib")
|
||||
-- }}}
|
||||
|
||||
-- Load modules at runtime as needed
|
||||
setmetatable(_M, { __index = wrequire })
|
@ -0,0 +1,47 @@
|
||||
---------------------------------------------------
|
||||
-- Licensed under the GNU General Public License v2
|
||||
-- * (c) 2010, Adrian C. <anrxc@sysphere.org>
|
||||
-- * (c) 2009, Lucas de Vries <lucas@glacicle.com>
|
||||
---------------------------------------------------
|
||||
|
||||
-- {{{ Grab environment
|
||||
local type = type
|
||||
local io = { popen = io.popen }
|
||||
local setmetatable = setmetatable
|
||||
local string = { find = string.find }
|
||||
local helpers = require("vicious.helpers")
|
||||
-- }}}
|
||||
|
||||
|
||||
-- Mpc: provides the currently playing song in MPD
|
||||
module("vicious.contrib.mpc")
|
||||
|
||||
|
||||
-- {{{ MPC widget type
|
||||
local function worker(format, warg)
|
||||
-- Get data from mpd
|
||||
local f = io.popen("mpc")
|
||||
local np = f:read("*line")
|
||||
f:close()
|
||||
|
||||
-- Not installed,
|
||||
if np == nil or -- off or stoppped.
|
||||
(string.find(np, "MPD_HOST") or string.find(np, "volume:"))
|
||||
then
|
||||
return {"Stopped"}
|
||||
end
|
||||
|
||||
-- Check if we should scroll, or maybe truncate
|
||||
if warg then
|
||||
if type(warg) == "table" then
|
||||
np = helpers.scroll(np, warg[1], warg[2])
|
||||
else
|
||||
np = helpers.truncate(np, warg)
|
||||
end
|
||||
end
|
||||
|
||||
return {helpers.escape(np)}
|
||||
end
|
||||
-- }}}
|
||||
|
||||
setmetatable(_M, { __call = function(_, ...) return worker(...) end })
|
@ -0,0 +1,138 @@
|
||||
---------------------------------------------------
|
||||
-- Licensed under the GNU General Public License v2
|
||||
-- * (c) 2010, Adrian C. <anrxc@sysphere.org>
|
||||
-- * (c) 2009, Henning Glawe <glaweh@debian.org>
|
||||
-- * (c) 2009, Lucas de Vries <lucas@glacicle.com>
|
||||
---------------------------------------------------
|
||||
|
||||
-- {{{ Grab environment
|
||||
local pairs = pairs
|
||||
local tonumber = tonumber
|
||||
local os = { time = os.time }
|
||||
local io = { lines = io.lines }
|
||||
local setmetatable = setmetatable
|
||||
local string = { match = string.match }
|
||||
local helpers = require("vicious.helpers")
|
||||
-- }}}
|
||||
|
||||
|
||||
-- Net: provides usage statistics for all network interfaces
|
||||
module("vicious.contrib.net")
|
||||
|
||||
|
||||
-- Initialise function tables
|
||||
local nets = {}
|
||||
-- Variable definitions
|
||||
local unit = { ["b"] = 1, ["kb"] = 1024,
|
||||
["mb"] = 1024^2, ["gb"] = 1024^3
|
||||
}
|
||||
|
||||
-- {{{ Net widget type
|
||||
local function worker(format, tignorelist)
|
||||
local args = {}
|
||||
local tignore = {}
|
||||
local total_rx = 0
|
||||
local total_tx = 0
|
||||
local any_up = 0
|
||||
|
||||
if not tignorelist then
|
||||
tignorelist = {"lo", "wmaster0"}
|
||||
end
|
||||
for k, i in pairs(tignorelist) do
|
||||
tignore[i] = true
|
||||
end
|
||||
|
||||
-- Get NET stats
|
||||
for line in io.lines("/proc/net/dev") do
|
||||
-- Match wmaster0 as well as rt0 (multiple leading spaces)
|
||||
local name = string.match(line, "^[%s]?[%s]?[%s]?[%s]?([%w]+):")
|
||||
if name ~= nil then
|
||||
-- Received bytes, first value after the name
|
||||
local recv = tonumber(string.match(line, ":[%s]*([%d]+)"))
|
||||
-- Transmited bytes, 7 fields from end of the line
|
||||
local send = tonumber(string.match(line,
|
||||
"([%d]+)%s+%d+%s+%d+%s+%d+%s+%d+%s+%d+%s+%d+%s+%d$"))
|
||||
|
||||
if not tignore[name] then
|
||||
total_rx = total_rx + recv
|
||||
total_tx = total_tx + send
|
||||
end
|
||||
|
||||
helpers.uformat(args, name .. " rx", recv, unit)
|
||||
helpers.uformat(args, name .. " tx", send, unit)
|
||||
|
||||
if nets[name] == nil then
|
||||
-- Default values on the first run
|
||||
nets[name] = {}
|
||||
|
||||
helpers.uformat(args, name .. " down", 0, unit)
|
||||
helpers.uformat(args, name .. " up", 0, unit)
|
||||
args["{"..name.." carrier}"] = 0
|
||||
|
||||
nets[name].time = os.time()
|
||||
else -- Net stats are absolute, substract our last reading
|
||||
local interval = os.time() - nets[name].time > 0 and
|
||||
os.time() - nets[name].time or 1
|
||||
nets[name].time = os.time()
|
||||
|
||||
local down = (recv - nets[name][1]) / interval
|
||||
local up = (send - nets[name][2]) / interval
|
||||
|
||||
helpers.uformat(args, name .. " down", down, unit)
|
||||
helpers.uformat(args, name .. " up", up, unit)
|
||||
|
||||
-- Carrier detection
|
||||
sysnet = helpers.pathtotable("/sys/class/net/" .. name)
|
||||
|
||||
if sysnet.carrier then
|
||||
ccarrier = tonumber(sysnet.carrier)
|
||||
|
||||
args["{"..name.." carrier}"] = ccarrier
|
||||
if ccarrier ~= 0 and not tignore[name] then
|
||||
any_up = 1
|
||||
end
|
||||
else
|
||||
args["{"..name.." carrier}"] = 0
|
||||
end
|
||||
end
|
||||
|
||||
-- Store totals
|
||||
nets[name][1] = recv
|
||||
nets[name][2] = send
|
||||
end
|
||||
end
|
||||
|
||||
helpers.uformat(args, "total rx", total_rx, unit)
|
||||
helpers.uformat(args, "total tx", total_tx, unit)
|
||||
|
||||
if nets["total"] == nil then
|
||||
-- Default values on the first run
|
||||
nets["total"] = {}
|
||||
|
||||
helpers.uformat(args, "total down", 0, unit)
|
||||
helpers.uformat(args, "total up", 0, unit)
|
||||
args["{total carrier}"] = 0
|
||||
|
||||
nets["total"].time = os.time()
|
||||
else -- Net stats are absolute, substract our last reading
|
||||
local interval = os.time() - nets["total"].time > 0 and
|
||||
os.time() - nets["total"].time or 1
|
||||
nets["total"].time = os.time()
|
||||
|
||||
local down = (total_rx - nets["total"][1]) / interval
|
||||
local up = (total_tx - nets["total"][2]) / interval
|
||||
|
||||
helpers.uformat(args, "total down", down, unit)
|
||||
helpers.uformat(args, "total up", up, unit)
|
||||
args["{total carrier}"] = any_up
|
||||
end
|
||||
|
||||
-- Store totals
|
||||
nets["total"][1] = total_rx
|
||||
nets["total"][2] = total_tx
|
||||
|
||||
return args
|
||||
end
|
||||
-- }}}
|
||||
|
||||
setmetatable(_M, { __call = function(_, ...) return worker(...) end })
|
@ -0,0 +1,34 @@
|
||||
---------------------------------------------------
|
||||
-- Licensed under the GNU General Public License v2
|
||||
-- * (c) 2010, Radu A. <admiral0@tuxfamily.org>
|
||||
---------------------------------------------------
|
||||
|
||||
-- {{{ Grab environment
|
||||
local io = { popen = io.popen }
|
||||
local setmetatable = setmetatable
|
||||
local table = { insert = table.insert }
|
||||
-- }}}
|
||||
|
||||
|
||||
-- Netcfg: provides active netcfg network profiles
|
||||
module("vicious.contrib.netcfg")
|
||||
|
||||
|
||||
-- {{{ Netcfg widget type
|
||||
local function worker(format)
|
||||
-- Initialize counters
|
||||
local profiles = {}
|
||||
|
||||
local f = io.popen("ls -1 /var/run/network/profiles")
|
||||
for line in f:lines() do
|
||||
if line ~= nil then
|
||||
table.insert(profiles, line)
|
||||
end
|
||||
end
|
||||
f:close()
|
||||
|
||||
return profiles
|
||||
end
|
||||
-- }}}
|
||||
|
||||
setmetatable(_M, { __call = function(_, ...) return worker(...) end })
|
@ -0,0 +1,53 @@
|
||||
---------------------------------------------------
|
||||
-- Licensed under the GNU General Public License v2
|
||||
-- * (c) 2010, Adrian C. <anrxc@sysphere.org>
|
||||
---------------------------------------------------
|
||||
|
||||
-- {{{ Grab environment
|
||||
local tonumber = tonumber
|
||||
local io = { popen = io.popen }
|
||||
local setmetatable = setmetatable
|
||||
local string = { match = string.match }
|
||||
-- }}}
|
||||
|
||||
|
||||
-- Ossvol: provides volume levels of requested OSS mixers
|
||||
module("vicious.contrib.ossvol")
|
||||
|
||||
|
||||
-- {{{ Volume widget type
|
||||
local function worker(format, warg)
|
||||
if not warg then return end
|
||||
|
||||
local mixer_state = {
|
||||
["on"] = "♫", -- "",
|
||||
["off"] = "♩" -- "M"
|
||||
}
|
||||
|
||||
-- Get mixer control contents
|
||||
local f = io.popen("ossmix -c")
|
||||
local mixer = f:read("*all")
|
||||
f:close()
|
||||
|
||||
-- Capture mixer control state
|
||||
local volu = tonumber(string.match(mixer, warg .. "[%s]([%d%.]+)"))/0.25
|
||||
local mute = string.match(mixer, "vol%.mute[%s]([%a]+)")
|
||||
-- Handle mixers without data
|
||||
if volu == nil then
|
||||
return {0, mixer_state["off"]}
|
||||
end
|
||||
|
||||
-- Handle mixers without mute
|
||||
if mute == "OFF" and volu == "0"
|
||||
-- Handle mixers that are muted
|
||||
or mute == "ON" then
|
||||
mute = mixer_state["off"]
|
||||
else
|
||||
mute = mixer_state["on"]
|
||||
end
|
||||
|
||||
return {volu, mute}
|
||||
end
|
||||
-- }}}
|
||||
|
||||
setmetatable(_M, { __call = function(_, ...) return worker(...) end })
|
@ -0,0 +1,54 @@
|
||||
---------------------------------------------------
|
||||
-- Licensed under the GNU General Public License v2
|
||||
-- * (c) 2010, Boris Bolgradov <>
|
||||
--
|
||||
-- This widget type depends on luasocket.
|
||||
--
|
||||
-- Widget arguments are host, port, username and
|
||||
-- password, i.e.:
|
||||
-- {"mail.myhost.com", 110, "John", "132435"}
|
||||
---------------------------------------------------
|
||||
|
||||
-- {{{ Grab environment
|
||||
local tonumber = tonumber
|
||||
local setmetatable = setmetatable
|
||||
local sock_avail, socket = pcall(function()
|
||||
return require("socket")
|
||||
end)
|
||||
-- }}}
|
||||
|
||||
|
||||
-- POP: provides the count of new messages in a POP3 mailbox
|
||||
module("vicious.contrib.pop")
|
||||
|
||||
|
||||
-- {{{ POP3 count widget type
|
||||
local function worker(format, warg)
|
||||
if not sock_avail or (not warg or #warg ~= 4) then
|
||||
return {"N/A"}
|
||||
end
|
||||
|
||||
local host, port = warg[1], tonumber(warg[2])
|
||||
local user, pass = warg[3], warg[4]
|
||||
|
||||
local client = socket.tcp()
|
||||
client:settimeout(3)
|
||||
client:connect(host, port)
|
||||
client:receive("*l")
|
||||
client:send("USER " .. user .. "\r\n")
|
||||
client:receive("*l")
|
||||
client:send("PASS " .. pass .. "\r\n")
|
||||
client:receive("*l")
|
||||
client:send("STAT" .. "\r\n")
|
||||
local response = client:receive("*l")
|
||||
client:close()
|
||||
|
||||
if response:find("%+OK") then
|
||||
response = response:match("%+OK (%d+)")
|
||||
end
|
||||
|
||||
return {response}
|
||||
end
|
||||
-- }}}
|
||||
|
||||
setmetatable(_M, { __call = function(_, ...) return worker(...) end })
|
@ -0,0 +1,111 @@
|
||||
---------------------------------------------------
|
||||
-- Licensed under the GNU General Public License v2
|
||||
-- * (c) 2010, MrMagne <mr.magne@yahoo.fr>
|
||||
-- * (c) 2010, Mic92 <jthalheim@gmail.com>
|
||||
---------------------------------------------------
|
||||
|
||||
-- {{{ Grab environment
|
||||
local type = type
|
||||
local tonumber = tonumber
|
||||
local io = { popen = io.popen }
|
||||
local setmetatable = setmetatable
|
||||
local os = { execute = os.execute }
|
||||
local table = { insert = table.insert }
|
||||
local string = {
|
||||
find = string.find,
|
||||
match = string.match,
|
||||
format = string.format,
|
||||
gmatch = string.gmatch
|
||||
}
|
||||
-- }}}
|
||||
|
||||
|
||||
-- Pulse: provides volume levels of requested pulseaudio sinks and methods to change them
|
||||
module("vicious.contrib.pulse")
|
||||
|
||||
-- {{{ Helper function
|
||||
local function pacmd(args)
|
||||
local f = io.popen("pacmd "..args)
|
||||
local line = f:read("*all")
|
||||
f:close()
|
||||
return line
|
||||
end
|
||||
|
||||
local function escape(text)
|
||||
local special_chars = { ["."] = "%.", ["-"] = "%-" }
|
||||
return text:gsub("[%.%-]", special_chars)
|
||||
end
|
||||
|
||||
local cached_sinks = {}
|
||||
local function get_sink_name(sink)
|
||||
if type(sink) == "string" then return sink end
|
||||
-- avoid nil keys
|
||||
local key = sink or 1
|
||||
-- Cache requests
|
||||
if not cached_sinks[key] then
|
||||
local line = pacmd("list-sinks")
|
||||
for s in string.gmatch(line, "name: <(.-)>") do
|
||||
table.insert(cached_sinks, s)
|
||||
end
|
||||
end
|
||||
|
||||
return cached_sinks[key]
|
||||
end
|
||||
|
||||
|
||||
-- }}}
|
||||
|
||||
-- {{{ Pulseaudio widget type
|
||||
local function worker(format, sink)
|
||||
sink = get_sink_name(sink)
|
||||
if sink == nil then return {0, "unknown"} end
|
||||
|
||||
-- Get sink data
|
||||
local data = pacmd("dump")
|
||||
|
||||
-- If mute return 0 (not "Mute") so we don't break progressbars
|
||||
if string.find(data,"set%-sink%-mute "..escape(sink).." yes") then
|
||||
return {0, "off"}
|
||||
end
|
||||
|
||||
local vol = tonumber(string.match(data, "set%-sink%-volume "..escape(sink).." (0x[%x]+)"))
|
||||
if vol == nil then vol = 0 end
|
||||
|
||||
return { vol/0x10000*100, "on"}
|
||||
end
|
||||
-- }}}
|
||||
|
||||
-- {{{ Volume control helper
|
||||
function add(percent, sink)
|
||||
sink = get_sink_name(sink)
|
||||
if sink == nil then return end
|
||||
|
||||
local data = pacmd("dump")
|
||||
|
||||
local pattern = "set%-sink%-volume "..escape(sink).." (0x[%x]+)"
|
||||
local initial_vol = tonumber(string.match(data, pattern))
|
||||
|
||||
local vol = initial_vol + percent/100*0x10000
|
||||
if vol > 0x10000 then vol = 0x10000 end
|
||||
if vol < 0 then vol = 0 end
|
||||
|
||||
local cmd = string.format("pacmd set-sink-volume %s 0x%x >/dev/null", sink, vol)
|
||||
return os.execute(cmd)
|
||||
end
|
||||
|
||||
function toggle(sink)
|
||||
sink = get_sink_name(sink)
|
||||
if sink == nil then return end
|
||||
|
||||
local data = pacmd("dump")
|
||||
local pattern = "set%-sink%-mute "..escape(sink).." (%a%a%a?)"
|
||||
local mute = string.match(data, pattern)
|
||||
|
||||
-- 0 to enable a sink or 1 to mute it.
|
||||
local state = { yes = 0, no = 1}
|
||||
local cmd = string.format("pacmd set-sink-mute %s %d", sink, state[mute])
|
||||
return os.execute(cmd)
|
||||
end
|
||||
-- }}}
|
||||
|
||||
setmetatable(_M, { __call = function(_, ...) return worker(...) end })
|
@ -0,0 +1,67 @@
|
||||
---------------------------------------------------
|
||||
-- Licensed under the GNU General Public License v2
|
||||
-- * (c) 2009, olcc
|
||||
--
|
||||
-- This is now a standalone RSS reader for awesome:
|
||||
-- * http://github.com/olcc/aware
|
||||
---------------------------------------------------
|
||||
|
||||
-- {{{ Grab environment
|
||||
local pairs = pairs
|
||||
local io = { popen = io.popen }
|
||||
local setmetatable = setmetatable
|
||||
-- }}}
|
||||
|
||||
|
||||
-- RSS: provides latest world news
|
||||
module("vicious.contrib.rss")
|
||||
|
||||
|
||||
-- {{{ RSS widget type
|
||||
local function worker(format, input)
|
||||
-- input: * feed - feed url
|
||||
-- * object - entity to look for (typically: 'item')
|
||||
-- * fields - fields to read (example: 'link', 'title', 'description')
|
||||
-- output: * count - number of entities found
|
||||
-- * one table for each field, containing wanted values
|
||||
local feed = input.feed
|
||||
local object = input.object
|
||||
local fields = input.fields
|
||||
|
||||
-- Initialise tables
|
||||
local out = {}
|
||||
|
||||
for _, v in pairs(fields) do
|
||||
out[v] = {}
|
||||
end
|
||||
|
||||
-- Initialise variables
|
||||
local ob = nil
|
||||
local i,j,k = 1, 1, 0
|
||||
local curl = "curl -A 'Mozilla/4.0' -fsm 5 --connect-timeout 3 "
|
||||
|
||||
-- Get the feed
|
||||
local f = io.popen(curl .. '"' .. feed .. '"')
|
||||
local feed = f:read("*all")
|
||||
f:close()
|
||||
|
||||
while true do
|
||||
i, j, ob = feed.find(feed, "<" .. object .. ">(.-)</" .. object .. ">", i)
|
||||
if not ob then break end
|
||||
|
||||
for _, v in pairs(fields) do
|
||||
out[v][k] = ob:match("<" .. v .. ">(.*)</" .. v .. ">")
|
||||
end
|
||||
|
||||
k = k+1
|
||||
i = j+1
|
||||
end
|
||||
|
||||
-- Update the entity count
|
||||
out.count = k
|
||||
|
||||
return out
|
||||
end
|
||||
-- }}}
|
||||
|
||||
setmetatable(_M, { __call = function(_, ...) return worker(...) end })
|
@ -0,0 +1,68 @@
|
||||
---------------------------------------------------
|
||||
-- Licensed under the GNU General Public License v2
|
||||
-- * (c) 2010, Greg D. <jabbas@jabbas.pl>
|
||||
---------------------------------------------------
|
||||
|
||||
-- {{{ Grab environment
|
||||
local tonumber = tonumber
|
||||
local io = { popen = io.popen }
|
||||
local setmetatable = setmetatable
|
||||
local table = { insert = table.insert }
|
||||
local string = {
|
||||
gsub = string.gsub,
|
||||
match = string.match
|
||||
}
|
||||
-- }}}
|
||||
|
||||
|
||||
-- Sensors: provides access to lm_sensors data
|
||||
module("vicious.contrib.sensors")
|
||||
|
||||
|
||||
-- {{{ Split helper function
|
||||
local function datasplit(str)
|
||||
-- Splitting strings into associative array
|
||||
-- with some magic to get the values right.
|
||||
str = string.gsub(str, "\n", ":")
|
||||
|
||||
local tbl = {}
|
||||
string.gsub(str, "([^:]*)", function (v)
|
||||
if string.match(v, ".") then
|
||||
table.insert(tbl, v)
|
||||
end
|
||||
end)
|
||||
|
||||
local assoc = {}
|
||||
for c = 1, #tbl, 2 do
|
||||
local k = string.gsub(tbl[c], ".*_", "")
|
||||
local v = tonumber(string.match(tbl[c+1], "[%d]+"))
|
||||
assoc[k] = v
|
||||
end
|
||||
|
||||
return assoc
|
||||
end
|
||||
-- }}}
|
||||
|
||||
-- {{{ Sensors widget type
|
||||
local function worker(format, warg)
|
||||
-- Get data from all sensors
|
||||
local f = io.popen("LANG=C sensors -uA")
|
||||
local lm_sensors = f:read("*all")
|
||||
f:close()
|
||||
|
||||
local sensor_data = string.gsub(
|
||||
string.match(lm_sensors, warg..":\n(%s%s.-)\n[^ ]"), " ", "")
|
||||
|
||||
-- One of: crit, max
|
||||
local divisor = "crit"
|
||||
local s_data = datasplit(sensor_data)
|
||||
|
||||
if s_data[divisor] and s_data[divisor] > 0 then
|
||||
s_data.percent = s_data.input / s_data[divisor] * 100
|
||||
end
|
||||
|
||||
return {s_data.input, tonumber(s_data.percent)}
|
||||
end
|
||||
-- }}}
|
||||
|
||||
setmetatable(_M, { __call = function(_, ...) return worker(...) end })
|
@ -0,0 +1,149 @@
|
||||
---------------------------------------------------
|
||||
-- Licensed under the GNU General Public License v2
|
||||
-- * (c) 2010, Adrian C. <anrxc@sysphere.org>
|
||||
-- * (c) 2009, Rémy C. <shikamaru@mandriva.org>
|
||||
-- * (c) 2009, Benedikt Sauer <filmor@gmail.com>
|
||||
-- * (c) 2009, Henning Glawe <glaweh@debian.org>
|
||||
-- * (c) 2009, Lucas de Vries <lucas@glacicle.com>
|
||||
---------------------------------------------------
|
||||
|
||||
-- {{{ Grab environment
|
||||
local pairs = pairs
|
||||
local rawget = rawget
|
||||
local require = require
|
||||
local tonumber = tonumber
|
||||
local io = { open = io.open }
|
||||
local setmetatable = setmetatable
|
||||
local getmetatable = getmetatable
|
||||
local string = {
|
||||
upper = string.upper,
|
||||
format = string.format
|
||||
}
|
||||
-- }}}
|
||||
|
||||
|
||||
-- Helpers: provides helper functions for vicious widgets
|
||||
module("vicious.helpers")
|
||||
|
||||
|
||||
-- {{{ Variable definitions
|
||||
local scroller = {}
|
||||
-- }}}
|
||||
|
||||
-- {{{ Helper functions
|
||||
-- {{{ Loader of vicious modules
|
||||
function wrequire(table, key)
|
||||
local module = rawget(table, key)
|
||||
return module or require(table._NAME .. "." .. key)
|
||||
end
|
||||
-- }}}
|
||||
|
||||
-- {{{ Expose path as a Lua table
|
||||
function pathtotable(dir)
|
||||
return setmetatable({ _path = dir },
|
||||
{ __index = function(table, index)
|
||||
local path = table._path .. '/' .. index
|
||||
local f = io.open(path)
|
||||
if f then
|
||||
local s = f:read("*all")
|
||||
f:close()
|
||||
if s then
|
||||
return s
|
||||
else
|
||||
local o = { _path = path }
|
||||
setmetatable(o, getmetatable(table))
|
||||
return o
|
||||
end
|
||||
end
|
||||
end
|
||||
})
|
||||
end
|
||||
-- }}}
|
||||
|
||||
-- {{{ Format a string with args
|
||||
function format(format, args)
|
||||
for var, val in pairs(args) do
|
||||
format = format:gsub("$" .. (tonumber(var) and var or
|
||||
var:gsub("[-+?*]", function(i) return "%"..i end)),
|
||||
val)
|
||||
end
|
||||
|
||||
return format
|
||||
end
|
||||
-- }}}
|
||||
|
||||
-- {{{ Format units to one decimal point
|
||||
function uformat(array, key, value, unit)
|
||||
for u, v in pairs(unit) do
|
||||
array["{"..key.."_"..u.."}"] = string.format("%.1f", value/v)
|
||||
end
|
||||
|
||||
return array
|
||||
end
|
||||
-- }}}
|
||||
|
||||
-- {{{ Escape a string
|
||||
function escape(text)
|
||||
local xml_entities = {
|
||||
["\""] = """,
|
||||
["&"] = "&",
|
||||
["'"] = "'",
|
||||
["<"] = "<",
|
||||
[">"] = ">"
|
||||
}
|
||||
|
||||
return text and text:gsub("[\"&'<>]", xml_entities)
|
||||
end
|
||||
-- }}}
|
||||
|
||||
-- {{{ Capitalize a string
|
||||
function capitalize(text)
|
||||
return text and text:gsub("([%w])([%w]*)", function(c, s)
|
||||
return string.upper(c) .. s
|
||||
end)
|
||||
end
|
||||
-- }}}
|
||||
|
||||
-- {{{ Truncate a string
|
||||
function truncate(text, maxlen)
|
||||
local txtlen = text:len()
|
||||
|
||||
if txtlen > maxlen then
|
||||
text = text:sub(1, maxlen - 3) .. "..."
|
||||
end
|
||||
|
||||
return text
|
||||
end
|
||||
-- }}}
|
||||
|
||||
-- {{{ Scroll through a string
|
||||
function scroll(text, maxlen, widget)
|
||||
if not scroller[widget] then
|
||||
scroller[widget] = { i = 1, d = true }
|
||||
end
|
||||
|
||||
local txtlen = text:len()
|
||||
local state = scroller[widget]
|
||||
|
||||
if txtlen > maxlen then
|
||||
if state.d then
|
||||
text = text:sub(state.i, state.i + maxlen) .. "..."
|
||||
state.i = state.i + 3
|
||||
|
||||
if maxlen + state.i >= txtlen then
|
||||
state.d = false
|
||||
end
|
||||
else
|
||||
text = "..." .. text:sub(state.i, state.i + maxlen)
|
||||
state.i = state.i - 3
|
||||
|
||||
if state.i <= 1 then
|
||||
state.d = true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return text
|
||||
end
|
||||
-- }}}
|
||||
-- }}}
|
@ -0,0 +1,249 @@
|
||||
---------------------------------------------------
|
||||
-- Vicious widgets for the awesome window manager
|
||||
---------------------------------------------------
|
||||
-- Licensed under the GNU General Public License v2
|
||||
-- * (c) 2010, Adrian C. <anrxc@sysphere.org>
|
||||
-- * (c) 2009, Lucas de Vries <lucas@glacicle.com>
|
||||
---------------------------------------------------
|
||||
|
||||
-- {{{ Setup environment
|
||||
local type = type
|
||||
local pairs = pairs
|
||||
local tonumber = tonumber
|
||||
local capi = { timer = timer }
|
||||
local os = { time = os.time }
|
||||
local table = {
|
||||
insert = table.insert,
|
||||
remove = table.remove
|
||||
}
|
||||
require("vicious.helpers")
|
||||
require("vicious.widgets")
|
||||
--require("vicious.contrib")
|
||||
|
||||
-- Vicious: widgets for the awesome window manager
|
||||
module("vicious")
|
||||
|
||||
|
||||
-- Initialize tables
|
||||
local timers = {}
|
||||
local registered = {}
|
||||
local widget_cache = {}
|
||||
-- }}}
|
||||
|
||||
|
||||
-- {{{ Local functions
|
||||
-- {{{ Update a widget
|
||||
local function update(widget, reg, disablecache)
|
||||
-- Check if there are any equal widgets
|
||||
if reg == nil then
|
||||
for w, i in pairs(registered) do
|
||||
if w == widget then
|
||||
for _, r in pairs(i) do
|
||||
update(w, r, disablecache)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return
|
||||
end
|
||||
|
||||
local t = os.time()
|
||||
local data = {}
|
||||
|
||||
-- Check for chached output newer than the last update
|
||||
if widget_cache[reg.wtype] ~= nil then
|
||||
local c = widget_cache[reg.wtype]
|
||||
|
||||
if (c.time == nil or c.time <= t-reg.timer) or disablecache then
|
||||
c.time, c.data = t, reg.wtype(reg.format, reg.warg)
|
||||
end
|
||||
|
||||
data = c.data
|
||||
else
|
||||
data = reg.wtype and reg.wtype(reg.format, reg.warg)
|
||||
end
|
||||
|
||||
if type(data) == "table" then
|
||||
if type(reg.format) == "string" then
|
||||
data = helpers.format(reg.format, data)
|
||||
elseif type(reg.format) == "function" then
|
||||
data = reg.format(widget, data)
|
||||
end
|
||||
end
|
||||
|
||||
if widget.add_value ~= nil then
|
||||
widget:add_value(tonumber(data) and tonumber(data)/100)
|
||||
elseif widget.set_value ~= nil then
|
||||
widget:set_value(tonumber(data) and tonumber(data)/100)
|
||||
elseif widget.set_markup ~= nil then
|
||||
widget:set_markup(data)
|
||||
else
|
||||
widget.text = data
|
||||
end
|
||||
|
||||
return data
|
||||
end
|
||||
-- }}}
|
||||
|
||||
-- {{{ Register from reg object
|
||||
local function regregister(reg)
|
||||
if not reg.running then
|
||||
if registered[reg.widget] == nil then
|
||||
registered[reg.widget] = {}
|
||||
table.insert(registered[reg.widget], reg)
|
||||
else
|
||||
local already = false
|
||||
|
||||
for w, i in pairs(registered) do
|
||||
if w == reg.widget then
|
||||
for _, v in pairs(i) do
|
||||
if v == reg then
|
||||
already = true
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
if already then
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if not already then
|
||||
table.insert(registered[reg.widget], reg)
|
||||
end
|
||||
end
|
||||
|
||||
-- Start the timer
|
||||
if reg.timer > 0 then
|
||||
timers[reg.update] = {
|
||||
timer = capi.timer({ timeout = reg.timer })
|
||||
}
|
||||
|
||||
local tm = timers[reg.update].timer
|
||||
if tm.connect_signal then
|
||||
tm:connect_signal("timeout", reg.update)
|
||||
else
|
||||
tm:add_signal("timeout", reg.update)
|
||||
end
|
||||
tm:start()
|
||||
|
||||
-- Initial update
|
||||
tm:emit_signal("timeout")
|
||||
end
|
||||
reg.running = true
|
||||
end
|
||||
end
|
||||
-- }}}
|
||||
-- }}}
|
||||
|
||||
|
||||
-- {{{ Global functions
|
||||
-- {{{ Register a widget
|
||||
function register(widget, wtype, format, timer, warg)
|
||||
local reg = {}
|
||||
local widget = widget
|
||||
|
||||
-- Set properties
|
||||
reg.wtype = wtype
|
||||
reg.format = format
|
||||
reg.timer = timer
|
||||
reg.warg = warg
|
||||
reg.widget = widget
|
||||
|
||||
-- Update function
|
||||
reg.update = function ()
|
||||
update(widget, reg)
|
||||
end
|
||||
|
||||
-- Default to 2s timer
|
||||
if reg.timer == nil then
|
||||
reg.timer = 2
|
||||
end
|
||||
|
||||
-- Register a reg object
|
||||
regregister(reg)
|
||||
|
||||
-- Return a reg object for reuse
|
||||
return reg
|
||||
end
|
||||
-- }}}
|
||||
|
||||
-- {{{ Unregister a widget
|
||||
function unregister(widget, keep, reg)
|
||||
if reg == nil then
|
||||
for w, i in pairs(registered) do
|
||||
if w == widget then
|
||||
for _, v in pairs(i) do
|
||||
reg = unregister(w, keep, v)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return reg
|
||||
end
|
||||
|
||||
if not keep then
|
||||
for w, i in pairs(registered) do
|
||||
if w == widget then
|
||||
for k, v in pairs(i) do
|
||||
if v == reg then
|
||||
table.remove(registered[w], k)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Stop the timer
|
||||
if timers[reg.update].timer.started then
|
||||
timers[reg.update].timer:stop()
|
||||
end
|
||||
reg.running = false
|
||||
|
||||
return reg
|
||||
end
|
||||
-- }}}
|
||||
|
||||
-- {{{ Enable caching of a widget type
|
||||
function cache(wtype)
|
||||
if wtype ~= nil then
|
||||
if widget_cache[wtype] == nil then
|
||||
widget_cache[wtype] = {}
|
||||
end
|
||||
end
|
||||
end
|
||||
-- }}}
|
||||
|
||||
-- {{{ Force update of widgets
|
||||
function force(wtable)
|
||||
if type(wtable) == "table" then
|
||||
for _, w in pairs(wtable) do
|
||||
update(w, nil, true)
|
||||
end
|
||||
end
|
||||
end
|
||||
-- }}}
|
||||
|
||||
-- {{{ Suspend all widgets
|
||||
function suspend()
|
||||
for w, i in pairs(registered) do
|
||||
for _, v in pairs(i) do
|
||||
unregister(w, true, v)
|
||||
end
|
||||
end
|
||||
end
|
||||
-- }}}
|
||||
|
||||
-- {{{ Activate a widget
|
||||
function activate(widget)
|
||||
for w, i in pairs(registered) do
|
||||
if widget == nil or w == widget then
|
||||
for _, v in pairs(i) do
|
||||
regregister(v)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
-- }}}
|
||||
-- }}}
|
@ -0,0 +1,85 @@
|
||||
---------------------------------------------------
|
||||
-- Licensed under the GNU General Public License v2
|
||||
-- * (c) 2010, Adrian C. <anrxc@sysphere.org>
|
||||
---------------------------------------------------
|
||||
|
||||
-- {{{ Grab environment
|
||||
local tonumber = tonumber
|
||||
local setmetatable = setmetatable
|
||||
local string = { format = string.format }
|
||||
local helpers = require("vicious.helpers")
|
||||
local math = {
|
||||
min = math.min,
|
||||
floor = math.floor
|
||||
}
|
||||
-- }}}
|
||||
|
||||
|
||||
-- Bat: provides state, charge, and remaining time for a requested battery
|
||||
module("vicious.widgets.bat")
|
||||
|
||||
|
||||
-- {{{ Battery widget type
|
||||
local function worker(format, warg)
|
||||
if not warg then return end
|
||||
|
||||
local battery = helpers.pathtotable("/sys/class/power_supply/"..warg)
|
||||
local battery_state = {
|
||||
["Full\n"] = "↯",
|
||||
["Unknown\n"] = "⌁",
|
||||
["Charged\n"] = "↯",
|
||||
["Charging\n"] = "+",
|
||||
["Discharging\n"] = "-"
|
||||
}
|
||||
|
||||
-- Check if the battery is present
|
||||
if battery.present ~= "1\n" then
|
||||
return {battery_state["Unknown\n"], 0, "N/A"}
|
||||
end
|
||||
|
||||
|
||||
-- Get state information
|
||||
local state = battery_state[battery.status] or battery_state["Unknown\n"]
|
||||
|
||||
-- Get capacity information
|
||||
if battery.charge_now then
|
||||
remaining, capacity = battery.charge_now, battery.charge_full
|
||||
elseif battery.energy_now then
|
||||
remaining, capacity = battery.energy_now, battery.energy_full
|
||||
else
|
||||
return {battery_state["Unknown\n"], 0, "N/A"}
|
||||
end
|
||||
|
||||
-- Calculate percentage (but work around broken BAT/ACPI implementations)
|
||||
local percent = math.min(math.floor(remaining / capacity * 100), 100)
|
||||
|
||||
|
||||
-- Get charge information
|
||||
if battery.current_now then
|
||||
rate = battery.current_now
|
||||
elseif battery.power_now then
|
||||
rate = battery.power_now
|
||||
else
|
||||
return {state, percent, "N/A"}
|
||||
end
|
||||
|
||||
-- Calculate remaining (charging or discharging) time
|
||||
local time = "N/A"
|
||||
if rate ~= nil then
|
||||
if state == "+" then
|
||||
timeleft = (tonumber(capacity) - tonumber(remaining)) / tonumber(rate)
|
||||
elseif state == "-" then
|
||||
timeleft = tonumber(remaining) / tonumber(rate)
|
||||
else
|
||||
return {state, percent, time}
|
||||
end
|
||||
local hoursleft = math.floor(timeleft)
|
||||
local minutesleft = math.floor((timeleft - hoursleft) * 60 )
|
||||
time = string.format("%02d:%02d", hoursleft, minutesleft)
|
||||
end
|
||||
|
||||
return {state, percent, time}
|
||||
end
|
||||
-- }}}
|
||||
|
||||
setmetatable(_M, { __call = function(_, ...) return worker(...) end })
|
@ -0,0 +1,75 @@
|
||||
---------------------------------------------------
|
||||
-- Licensed under the GNU General Public License v2
|
||||
-- * (c) 2011, Adrian C. <anrxc@sysphere.org>
|
||||
-- * (c) 2009, Lucas de Vries <lucas@glacicle.com>
|
||||
-- * (c) 2011, Jörg Thalheim <jthalheim@gmail.com>
|
||||
---------------------------------------------------
|
||||
|
||||
-- {{{ Grab environment
|
||||
local ipairs = ipairs
|
||||
local io = { lines = io.lines }
|
||||
local setmetatable = setmetatable
|
||||
local math = { floor = math.floor }
|
||||
local table = { insert = table.insert }
|
||||
local string = {
|
||||
sub = string.sub,
|
||||
gmatch = string.gmatch
|
||||
}
|
||||
-- }}}
|
||||
|
||||
|
||||
-- Cpu: provides CPU usage for all available CPUs/cores
|
||||
module("vicious.widgets.cpu")
|
||||
|
||||
|
||||
-- Initialize function tables
|
||||
local cpu_usage = {}
|
||||
local cpu_total = {}
|
||||
local cpu_active = {}
|
||||
|
||||
-- {{{ CPU widget type
|
||||
local function worker(format)
|
||||
local cpu_lines = {}
|
||||
|
||||
-- Get CPU stats
|
||||
for line in io.lines("/proc/stat") do
|
||||
if string.sub(line, 1, 3) ~= "cpu" then break end
|
||||
|
||||
cpu_lines[#cpu_lines+1] = {}
|
||||
|
||||
for i in string.gmatch(line, "[%s]+([^%s]+)") do
|
||||
table.insert(cpu_lines[#cpu_lines], i)
|
||||
end
|
||||
end
|
||||
|
||||
-- Ensure tables are initialized correctly
|
||||
for i = #cpu_total + 1, #cpu_lines do
|
||||
cpu_total[i] = 0
|
||||
cpu_usage[i] = 0
|
||||
cpu_active[i] = 0
|
||||
end
|
||||
|
||||
|
||||
for i, v in ipairs(cpu_lines) do
|
||||
-- Calculate totals
|
||||
local total_new = 0
|
||||
for j = 1, #v do
|
||||
total_new = total_new + v[j]
|
||||
end
|
||||
local active_new = total_new - (v[4] + v[5])
|
||||
|
||||
-- Calculate percentage
|
||||
local diff_total = total_new - cpu_total[i]
|
||||
local diff_active = active_new - cpu_active[i]
|
||||
cpu_usage[i] = math.floor((diff_active / diff_total) * 100)
|
||||
|
||||
-- Store totals
|
||||
cpu_total[i] = total_new
|
||||
cpu_active[i] = active_new
|
||||
end
|
||||
|
||||
return cpu_usage
|
||||
end
|
||||
-- }}}
|
||||
|
||||
setmetatable(_M, { __call = function(_, ...) return worker(...) end })
|
@ -0,0 +1,56 @@
|
||||
---------------------------------------------------
|
||||
-- Licensed under the GNU General Public License v2
|
||||
-- * (c) 2010, Adrian C. <anrxc@sysphere.org>
|
||||
---------------------------------------------------
|
||||
|
||||
-- {{{ Grab environment
|
||||
local tonumber = tonumber
|
||||
local setmetatable = setmetatable
|
||||
local string = { match = string.match }
|
||||
local helpers = require("vicious.helpers")
|
||||
-- }}}
|
||||
|
||||
|
||||
-- Cpufreq: provides freq, voltage and governor info for a requested CPU
|
||||
module("vicious.widgets.cpufreq")
|
||||
|
||||
|
||||
-- {{{ CPU frequency widget type
|
||||
local function worker(format, warg)
|
||||
if not warg then return end
|
||||
|
||||
local cpufreq = helpers.pathtotable("/sys/devices/system/cpu/"..warg.."/cpufreq")
|
||||
local governor_state = {
|
||||
["ondemand\n"] = "↯",
|
||||
["powersave\n"] = "⌁",
|
||||
["userspace\n"] = "¤",
|
||||
["performance\n"] = "⚡",
|
||||
["conservative\n"] = "↯"
|
||||
}
|
||||
-- Default voltage values
|
||||
local voltage = { v = "N/A", mv = "N/A" }
|
||||
|
||||
|
||||
-- Get the current frequency
|
||||
local freq = tonumber(cpufreq.scaling_cur_freq)
|
||||
-- Calculate MHz and GHz
|
||||
local freqmhz = freq / 1000
|
||||
local freqghz = freqmhz / 1000
|
||||
|
||||
-- Get the current voltage
|
||||
if cpufreq.scaling_voltages then
|
||||
voltage.mv = tonumber(string.match(cpufreq.scaling_voltages, freq.."[%s]([%d]+)"))
|
||||
-- Calculate voltage from mV
|
||||
voltage.v = voltage.mv / 1000
|
||||
end
|
||||
|
||||
-- Get the current governor
|
||||
local governor = cpufreq.scaling_governor
|
||||
-- Represent the governor as a symbol
|
||||
governor = governor_state[governor] or governor
|
||||
|
||||
return {freqmhz, freqghz, voltage.mv, voltage.v, governor}
|
||||
end
|
||||
-- }}}
|
||||
|
||||
setmetatable(_M, { __call = function(_, ...) return worker(...) end })
|
@ -0,0 +1,43 @@
|
||||
---------------------------------------------------
|
||||
-- Licensed under the GNU General Public License v2
|
||||
-- * (c) 2010, Adrian C. <anrxc@sysphere.org>
|
||||
---------------------------------------------------
|
||||
|
||||
-- {{{ Grab environment
|
||||
local tonumber = tonumber
|
||||
local io = { lines = io.lines }
|
||||
local setmetatable = setmetatable
|
||||
local string = { gmatch = string.gmatch }
|
||||
-- }}}
|
||||
|
||||
|
||||
-- Cpuinf: provides speed and cache information for all available CPUs/cores
|
||||
module("vicious.widgets.cpuinf")
|
||||
|
||||
|
||||
-- {{{ CPU Information widget type
|
||||
local function worker(format)
|
||||
local id = nil
|
||||
|
||||
local cpu_info = {} -- Get CPU info
|
||||
for line in io.lines("/proc/cpuinfo") do
|
||||
for k, v in string.gmatch(line, "([%a%s]+)[%s]+:[%s]([%d]+).-$") do
|
||||
if k == "processor" then
|
||||
id = v
|
||||
elseif k == "cpu MHz\t" or k == "cpu MHz" then
|
||||
local speed = tonumber(v)
|
||||
cpu_info["{cpu"..id.." mhz}"] = speed
|
||||
cpu_info["{cpu"..id.." ghz}"] = speed / 1000
|
||||
elseif k == "cache size" then
|
||||
local cache = tonumber(v)
|
||||
cpu_info["{cpu"..id.." kb}"] = cache
|
||||
cpu_info["{cpu"..id.." mb}"] = cache / 1024
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return cpu_info
|
||||
end
|
||||
-- }}}
|
||||
|
||||
setmetatable(_M, { __call = function(_, ...) return worker(...) end })
|
@ -0,0 +1,26 @@
|
||||
---------------------------------------------------
|
||||
-- Licensed under the GNU General Public License v2
|
||||
-- * (c) 2010, Adrian C. <anrxc@sysphere.org>
|
||||
-- * (c) 2009, Lucas de Vries <lucas@glacicle.com>
|
||||
---------------------------------------------------
|
||||
|
||||
-- {{{ Grab environment
|
||||
local setmetatable = setmetatable
|
||||
local os = {
|
||||
date = os.date,
|
||||
time = os.time
|
||||
}
|
||||
-- }}}
|
||||
|
||||
|
||||
-- Date: provides access to os.date with optional time formatting
|
||||
module("vicious.widgets.date")
|
||||
|
||||
|
||||
-- {{{ Date widget type
|
||||
local function worker(format, warg)
|
||||
return os.date(format or nil, warg and os.time()+warg or nil)
|
||||
end
|
||||
-- }}}
|
||||
|
||||
setmetatable(_M, { __call = function(_, ...) return worker(...) end })
|
@ -0,0 +1,72 @@
|
||||
---------------------------------------------------
|
||||
-- Licensed under the GNU General Public License v2
|
||||
-- * (c) 2011, Jörg T. <jthalheim@gmail.com>
|
||||
---------------------------------------------------
|
||||
|
||||
-- {{{ Grab environment
|
||||
local pairs = pairs
|
||||
local io = { lines = io.lines }
|
||||
local setmetatable = setmetatable
|
||||
local string = { match = string.match }
|
||||
local helpers = require("vicious.helpers")
|
||||
local os = {
|
||||
time = os.time,
|
||||
difftime = os.difftime
|
||||
}
|
||||
-- }}}
|
||||
|
||||
|
||||
-- Disk I/O: provides I/O statistics for requested storage devices
|
||||
module("vicious.widgets.dio")
|
||||
|
||||
|
||||
-- Initialize function tables
|
||||
local disk_usage = {}
|
||||
local disk_stats = {}
|
||||
local disk_time = 0
|
||||
-- Constant definitions
|
||||
local unit = { ["s"] = 1, ["kb"] = 2, ["mb"] = 2048 }
|
||||
|
||||
-- {{{ Disk I/O widget type
|
||||
local function worker(format)
|
||||
local disk_lines = {}
|
||||
|
||||
for line in io.lines("/proc/diskstats") do
|
||||
local device, read, write =
|
||||
-- Linux kernel documentation: Documentation/iostats.txt
|
||||
string.match(line, "([^%s]+) %d+ %d+ (%d+) %d+ %d+ %d+ (%d+)")
|
||||
disk_lines[device] = { read, write }
|
||||
end
|
||||
|
||||
local time = os.time()
|
||||
local interval = os.difftime(time, disk_time)
|
||||
if interval == 0 then interval = 1 end
|
||||
|
||||
for device, stats in pairs(disk_lines) do
|
||||
-- Avoid insane values on startup
|
||||
local last_stats = disk_stats[device] or stats
|
||||
|
||||
-- Check for overflows and counter resets (> 2^32)
|
||||
if stats[1] < last_stats[1] or stats[2] < last_stats[2] then
|
||||
last_stats[1], last_stats[2] = stats[1], stats[2]
|
||||
end
|
||||
|
||||
-- Diskstats are absolute, substract our last reading
|
||||
-- * divide by timediff because we don't know the timer value
|
||||
local read = (stats[1] - last_stats[1]) / interval
|
||||
local write = (stats[2] - last_stats[2]) / interval
|
||||
|
||||
-- Calculate and store I/O
|
||||
helpers.uformat(disk_usage, device.." read", read, unit)
|
||||
helpers.uformat(disk_usage, device.." write", write, unit)
|
||||
helpers.uformat(disk_usage, device.." total", read + write, unit)
|
||||
end
|
||||
|
||||
disk_time = time
|
||||
disk_stats = disk_lines
|
||||
|
||||
return disk_usage
|
||||
end
|
||||
-- }}}
|
||||
|
||||
setmetatable(_M, { __call = function(_, ...) return worker(...) end })
|
@ -0,0 +1,51 @@
|
||||
---------------------------------------------------
|
||||
-- Licensed under the GNU General Public License v2
|
||||
-- * (c) 2010, Adrian C. <anrxc@sysphere.org>
|
||||
-- * (c) 2009, Lucas de Vries <lucas@glacicle.com>
|
||||
---------------------------------------------------
|
||||
|
||||
-- {{{ Grab environment
|
||||
local tonumber = tonumber
|
||||
local io = { popen = io.popen }
|
||||
local setmetatable = setmetatable
|
||||
local string = { match = string.match }
|
||||
local helpers = require("vicious.helpers")
|
||||
-- }}}
|
||||
|
||||
|
||||
-- FS: provides file system disk space usage
|
||||
module("vicious.widgets.fs")
|
||||
|
||||
|
||||
-- Variable definitions
|
||||
local unit = { ["mb"] = 1024, ["gb"] = 1024^2 }
|
||||
|
||||
-- {{{ Filesystem widget type
|
||||
local function worker(format, warg)
|
||||
-- Fallback to listing local filesystems
|
||||
if warg then warg = "" else warg = "-l" end
|
||||
|
||||
local fs_info = {} -- Get data from df
|
||||
local f = io.popen("LC_ALL=C df -kP " .. warg)
|
||||
|
||||
for line in f:lines() do -- Match: (size) (used)(avail)(use%) (mount)
|
||||
local s = string.match(line, "^.-[%s]([%d]+)")
|
||||
local u,a,p = string.match(line, "([%d]+)[%D]+([%d]+)[%D]+([%d]+)%%")
|
||||
local m = string.match(line, "%%[%s]([%p%w]+)")
|
||||
|
||||
if u and m then -- Handle 1st line and broken regexp
|
||||
helpers.uformat(fs_info, m .. " size", s, unit)
|
||||
helpers.uformat(fs_info, m .. " used", u, unit)
|
||||
helpers.uformat(fs_info, m .. " avail", a, unit)
|
||||
|
||||
fs_info["{" .. m .. " used_p}"] = tonumber(p)
|
||||
fs_info["{" .. m .. " avail_p}"] = 100 - tonumber(p)
|
||||
end
|
||||
end
|
||||
f:close()
|
||||
|
||||
return fs_info
|
||||
end
|
||||
-- }}}
|
||||
|
||||
setmetatable(_M, { __call = function(_, ...) return worker(...) end })
|
@ -0,0 +1,82 @@
|
||||
---------------------------------------------------
|
||||
-- Licensed under the GNU General Public License v2
|
||||
-- * (c) 2010, Adrian C. <anrxc@sysphere.org>
|
||||
---------------------------------------------------
|
||||
|
||||
-- {{{ Grab environment
|
||||
local type = type
|
||||
local tonumber = tonumber
|
||||
local io = { popen = io.popen }
|
||||
local setmetatable = setmetatable
|
||||
local helpers = require("vicious.helpers")
|
||||
local string = {
|
||||
find = string.find,
|
||||
match = string.match
|
||||
}
|
||||
-- }}}
|
||||
|
||||
|
||||
-- Gmail: provides count of new and subject of last e-mail on Gmail
|
||||
module("vicious.widgets.gmail")
|
||||
|
||||
|
||||
-- {{{ Variable definitions
|
||||
local rss = {
|
||||
inbox = {
|
||||
"https://mail.google.com/mail/feed/atom",
|
||||
"Gmail %- Inbox"
|
||||
},
|
||||
unread = {
|
||||
"https://mail.google.com/mail/feed/atom/unread",
|
||||
"Gmail %- Label"
|
||||
},
|
||||
--labelname = {
|
||||
-- "https://mail.google.com/mail/feed/atom/labelname",
|
||||
-- "Gmail %- Label"
|
||||
--},
|
||||
}
|
||||
|
||||
-- Default is just Inbox
|
||||
local feed = rss.inbox
|
||||
local mail = {
|
||||
["{count}"] = 0,
|
||||
["{subject}"] = "N/A"
|
||||
}
|
||||
-- }}}
|
||||
|
||||
|
||||
-- {{{ Gmail widget type
|
||||
local function worker(format, warg)
|
||||
-- Get info from the Gmail atom feed
|
||||
local f = io.popen("curl --connect-timeout 1 -m 3 -fsn " .. feed[1])
|
||||
|
||||
-- Could be huge don't read it all at once, info we are after is at the top
|
||||
for line in f:lines() do
|
||||
mail["{count}"] = -- Count comes before messages and matches at least 0
|
||||
tonumber(string.match(line, "<fullcount>([%d]+)</fullcount>")) or mail["{count}"]
|
||||
|
||||
-- Find subject tags
|
||||
local title = string.match(line, "<title>(.*)</title>")
|
||||
-- If the subject changed then break out of the loop
|
||||
if title ~= nil and not string.find(title, feed[2]) then
|
||||
-- Check if we should scroll, or maybe truncate
|
||||
if warg then
|
||||
if type(warg) == "table" then
|
||||
title = helpers.scroll(title, warg[1], warg[2])
|
||||
else
|
||||
title = helpers.truncate(title, warg)
|
||||
end
|
||||
end
|
||||
|
||||
-- Spam sanitize the subject and store
|
||||
mail["{subject}"] = helpers.escape(title)
|
||||
break
|
||||
end
|
||||
end
|
||||
f:close()
|
||||
|
||||
return mail
|
||||
end
|
||||
-- }}}
|
||||
|
||||
setmetatable(_M, { __call = function(_, ...) return worker(...) end })
|
@ -0,0 +1,37 @@
|
||||
---------------------------------------------------
|
||||
-- Licensed under the GNU General Public License v2
|
||||
-- * (c) 2010, Adrian C. <anrxc@sysphere.org>
|
||||
---------------------------------------------------
|
||||
|
||||
-- {{{ Grab environment
|
||||
local tonumber = tonumber
|
||||
local io = { popen = io.popen }
|
||||
local setmetatable = setmetatable
|
||||
local string = { gmatch = string.gmatch }
|
||||
-- }}}
|
||||
|
||||
|
||||
-- Hddtemp: provides hard drive temperatures using the hddtemp daemon
|
||||
module("vicious.widgets.hddtemp")
|
||||
|
||||
|
||||
-- {{{ HDD Temperature widget type
|
||||
local function worker(format, warg)
|
||||
-- Fallback to default hddtemp port
|
||||
if warg == nil then warg = 7634 end
|
||||
|
||||
local hdd_temp = {} -- Get info from the hddtemp daemon
|
||||
local f = io.popen("curl --connect-timeout 1 -fsm 3 telnet://127.0.0.1:"..warg)
|
||||
|
||||
for line in f:lines() do
|
||||
for d, t in string.gmatch(line, "|([%/%a%d]+)|.-|([%d]+)|[CF]+|") do
|
||||
hdd_temp["{"..d.."}"] = tonumber(t)
|
||||
end
|
||||
end
|
||||
f:close()
|
||||
|
||||
return hdd_temp
|
||||
end
|
||||
-- }}}
|
||||
|
||||
setmetatable(_M, { __call = function(_, ...) return worker(...) end })
|
@ -0,0 +1,17 @@
|
||||
---------------------------------------------------
|
||||
-- Vicious widgets for the awesome window manager
|
||||
---------------------------------------------------
|
||||
-- Licensed under the GNU General Public License v2
|
||||
-- * (c) 2010, Adrian C. <anrxc@sysphere.org>
|
||||
---------------------------------------------------
|
||||
|
||||
-- {{{ Setup environment
|
||||
local setmetatable = setmetatable
|
||||
local wrequire = require("vicious.helpers").wrequire
|
||||
|
||||
-- Vicious: widgets for the awesome window manager
|
||||
module("vicious.widgets")
|
||||
-- }}}
|
||||
|
||||
-- Load modules at runtime as needed
|
||||
setmetatable(_M, { __index = wrequire })
|
@ -0,0 +1,52 @@
|
||||
---------------------------------------------------
|
||||
-- Licensed under the GNU General Public License v2
|
||||
-- * (c) 2010, Adrian C. <anrxc@sysphere.org>
|
||||
---------------------------------------------------
|
||||
|
||||
-- {{{ Grab environment
|
||||
local type = type
|
||||
local io = { open = io.open }
|
||||
local setmetatable = setmetatable
|
||||
local string = { gfind = string.gfind }
|
||||
local helpers = require("vicious.helpers")
|
||||
-- }}}
|
||||
|
||||
|
||||
-- Mbox: provides the subject of last e-mail in a mbox file
|
||||
module("vicious.widgets.mbox")
|
||||
|
||||
|
||||
-- Initialize variables
|
||||
local subject = "N/A"
|
||||
|
||||
-- {{{ Mailbox widget type
|
||||
local function worker(format, warg)
|
||||
if not warg then return end
|
||||
|
||||
-- mbox could be huge, get a 30kb chunk from EOF
|
||||
if type(warg) ~= "table" then mbox = warg end
|
||||
-- * attachment could be much bigger than 30kb
|
||||
local f = io.open(mbox or warg[1])
|
||||
f:seek("end", -30720)
|
||||
local txt = f:read("*all")
|
||||
f:close()
|
||||
|
||||
-- Find all Subject lines
|
||||
for i in string.gfind(txt, "Subject: ([^\n]*)") do
|
||||
subject = i
|
||||
end
|
||||
|
||||
-- Check if we should scroll, or maybe truncate
|
||||
if type(warg) == "table" then
|
||||
if warg[3] ~= nil then
|
||||
subject = helpers.scroll(subject, warg[2], warg[3])
|
||||
else
|
||||
subject = helpers.truncate(subject, warg[2])
|
||||
end
|
||||
end
|
||||
|
||||
return {helpers.escape(subject)}
|
||||
end
|
||||
-- }}}
|
||||
|
||||
setmetatable(_M, { __call = function(_, ...) return worker(...) end })
|
@ -0,0 +1,57 @@
|
||||
---------------------------------------------------
|
||||
-- Licensed under the GNU General Public License v2
|
||||
-- * (c) 2010, Adrian C. <anrxc@sysphere.org>
|
||||
---------------------------------------------------
|
||||
|
||||
-- {{{ Grab environment
|
||||
local io = { open = io.open }
|
||||
local setmetatable = setmetatable
|
||||
local string = { find = string.find }
|
||||
-- }}}
|
||||
|
||||
|
||||
-- Mboxc: provides the count of total, old and new messages in mbox files
|
||||
module("vicious.widgets.mboxc")
|
||||
|
||||
|
||||
-- {{{ Mbox count widget type
|
||||
local function worker(format, warg)
|
||||
if not warg then return end
|
||||
|
||||
-- Initialize counters
|
||||
local count = { old = 0, total = 0, new = 0 }
|
||||
|
||||
-- Get data from mbox files
|
||||
for i=1, #warg do
|
||||
local f = io.open(warg[i])
|
||||
|
||||
while true do
|
||||
-- Read the mbox line by line, if we are going to read
|
||||
-- some *HUGE* folders then switch to reading chunks
|
||||
local lines = f:read("*line")
|
||||
if not lines then break end
|
||||
|
||||
-- Find all messages
|
||||
-- * http://www.jwz.org/doc/content-length.html
|
||||
local _, from = string.find(lines, "^From[%s]")
|
||||
if from ~= nil then count.total = count.total + 1 end
|
||||
|
||||
-- Read messages have the Status header
|
||||
local _, status = string.find(lines, "^Status:[%s]RO$")
|
||||
if status ~= nil then count.old = count.old + 1 end
|
||||
|
||||
-- Skip the folder internal data
|
||||
local _, int = string.find(lines, "^Subject:[%s].*FOLDER[%s]INTERNAL[%s]DATA")
|
||||
if int ~= nil then count.total = count.total - 1 end
|
||||
end
|
||||
f:close()
|
||||
end
|
||||
|
||||
-- Substract total from old to get the new count
|
||||
count.new = count.total - count.old
|
||||
|
||||
return {count.total, count.old, count.new}
|
||||
end
|
||||
-- }}}
|
||||
|
||||
setmetatable(_M, { __call = function(_, ...) return worker(...) end })
|
@ -0,0 +1,40 @@
|
||||
---------------------------------------------------
|
||||
-- Licensed under the GNU General Public License v2
|
||||
-- * (c) 2010, Adrian C. <anrxc@sysphere.org>
|
||||
-- * (c) Maildir Biff Widget, Fredrik Ax
|
||||
---------------------------------------------------
|
||||
|
||||
-- {{{ Grab environment
|
||||
local io = { popen = io.popen }
|
||||
local setmetatable = setmetatable
|
||||
-- }}}
|
||||
|
||||
|
||||
-- Mdir: provides the number of new and unread messages in Maildir structures/dirs
|
||||
module("vicious.widgets.mdir")
|
||||
|
||||
|
||||
-- {{{ Maildir widget type
|
||||
local function worker(format, warg)
|
||||
if not warg then return end
|
||||
|
||||
-- Initialize counters
|
||||
local count = { new = 0, cur = 0 }
|
||||
|
||||
for i=1, #warg do
|
||||
-- Recursively find new messages
|
||||
local f = io.popen("find "..warg[i].." -type f -wholename '*/new/*'")
|
||||
for line in f:lines() do count.new = count.new + 1 end
|
||||
f:close()
|
||||
|
||||
-- Recursively find "old" messages lacking the Seen flag
|
||||
local f = io.popen("find "..warg[i].." -type f -regex '.*/cur/.*2,[^S]*$'")
|
||||
for line in f:lines() do count.cur = count.cur + 1 end
|
||||
f:close()
|
||||
end
|
||||
|
||||
return {count.new, count.cur}
|
||||
end
|
||||
-- }}}
|
||||
|
||||
setmetatable(_M, { __call = function(_, ...) return worker(...) end })
|
@ -0,0 +1,49 @@
|
||||
---------------------------------------------------
|
||||
-- Licensed under the GNU General Public License v2
|
||||
-- * (c) 2010, Adrian C. <anrxc@sysphere.org>
|
||||
-- * (c) 2009, Lucas de Vries <lucas@glacicle.com>
|
||||
---------------------------------------------------
|
||||
|
||||
-- {{{ Grab environment
|
||||
local io = { lines = io.lines }
|
||||
local setmetatable = setmetatable
|
||||
local math = { floor = math.floor }
|
||||
local string = { gmatch = string.gmatch }
|
||||
-- }}}
|
||||
|
||||
|
||||
-- Mem: provides RAM and Swap usage statistics
|
||||
module("vicious.widgets.mem")
|
||||
|
||||
|
||||
-- {{{ Memory widget type
|
||||
local function worker(format)
|
||||
local mem = { buf = {}, swp = {} }
|
||||
|
||||
-- Get MEM info
|
||||
for line in io.lines("/proc/meminfo") do
|
||||
for k, v in string.gmatch(line, "([%a]+):[%s]+([%d]+).+") do
|
||||
if k == "MemTotal" then mem.total = math.floor(v/1024)
|
||||
elseif k == "MemFree" then mem.buf.f = math.floor(v/1024)
|
||||
elseif k == "Buffers" then mem.buf.b = math.floor(v/1024)
|
||||
elseif k == "Cached" then mem.buf.c = math.floor(v/1024)
|
||||
elseif k == "SwapTotal" then mem.swp.t = math.floor(v/1024)
|
||||
elseif k == "SwapFree" then mem.swp.f = math.floor(v/1024)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Calculate memory percentage
|
||||
mem.free = mem.buf.f + mem.buf.b + mem.buf.c
|
||||
mem.inuse = mem.total - mem.free
|
||||
mem.usep = math.floor(mem.inuse / mem.total * 100)
|
||||
-- Calculate swap percentage
|
||||
mem.swp.inuse = mem.swp.t - mem.swp.f
|
||||
mem.swp.usep = math.floor(mem.swp.inuse / mem.swp.t * 100)
|
||||
|
||||
return {mem.usep, mem.inuse, mem.total, mem.free,
|
||||
mem.swp.usep, mem.swp.inuse, mem.swp.t, mem.swp.f}
|
||||
end
|
||||
-- }}}
|
||||
|
||||
setmetatable(_M, { __call = function(_, ...) return worker(...) end })
|
@ -0,0 +1,63 @@
|
||||
---------------------------------------------------
|
||||
-- Licensed under the GNU General Public License v2
|
||||
-- * (c) 2010, Adrian C. <anrxc@sysphere.org>
|
||||
---------------------------------------------------
|
||||
|
||||
-- {{{ Grab environment
|
||||
local tonumber = tonumber
|
||||
local io = { popen = io.popen }
|
||||
local setmetatable = setmetatable
|
||||
local string = { gmatch = string.gmatch }
|
||||
local helpers = require("vicious.helpers")
|
||||
-- }}}
|
||||
|
||||
|
||||
-- Mpd: provides Music Player Daemon information
|
||||
module("vicious.widgets.mpd")
|
||||
|
||||
|
||||
-- {{{ MPD widget type
|
||||
local function worker(format, warg)
|
||||
local mpd_state = {
|
||||
["{volume}"] = 0,
|
||||
["{state}"] = "N/A",
|
||||
["{Artist}"] = "N/A",
|
||||
["{Title}"] = "N/A",
|
||||
["{Album}"] = "N/A",
|
||||
["{Genre}"] = "N/A",
|
||||
--["{Name}"] = "N/A",
|
||||
--["{file}"] = "N/A",
|
||||
}
|
||||
|
||||
-- Fallback to MPD defaults
|
||||
local pass = warg and (warg.password or warg[1]) or "\"\""
|
||||
local host = warg and (warg.host or warg[2]) or "127.0.0.1"
|
||||
local port = warg and (warg.port or warg[3]) or "6600"
|
||||
|
||||
-- Construct MPD client options
|
||||
local mpdh = "telnet://"..host..":"..port
|
||||
local echo = "echo 'password "..pass.."\nstatus\ncurrentsong\nclose'"
|
||||
|
||||
-- Get data from MPD server
|
||||
local f = io.popen(echo.." | curl --connect-timeout 1 -fsm 3 "..mpdh)
|
||||
|
||||
for line in f:lines() do
|
||||
for k, v in string.gmatch(line, "([%w]+):[%s](.*)$") do
|
||||
if k == "volume" then mpd_state["{"..k.."}"] = v and tonumber(v)
|
||||
elseif k == "state" then mpd_state["{"..k.."}"] = helpers.capitalize(v)
|
||||
elseif k == "Artist" then mpd_state["{"..k.."}"] = helpers.escape(v)
|
||||
elseif k == "Title" then mpd_state["{"..k.."}"] = helpers.escape(v)
|
||||
elseif k == "Album" then mpd_state["{"..k.."}"] = helpers.escape(v)
|
||||
elseif k == "Genre" then mpd_state["{"..k.."}"] = helpers.escape(v)
|
||||
--elseif k == "Name" then mpd_state["{"..k.."}"] = helpers.escape(v)
|
||||
--elseif k == "file" then mpd_state["{"..k.."}"] = helpers.escape(v)
|
||||
end
|
||||
end
|
||||
end
|
||||
f:close()
|
||||
|
||||
return mpd_state
|
||||
end
|
||||
-- }}}
|
||||
|
||||
setmetatable(_M, { __call = function(_, ...) return worker(...) end })
|
@ -0,0 +1,79 @@
|
||||
---------------------------------------------------
|
||||
-- Licensed under the GNU General Public License v2
|
||||
-- * (c) 2010, Adrian C. <anrxc@sysphere.org>
|
||||
-- * (c) 2009, Lucas de Vries <lucas@glacicle.com>
|
||||
---------------------------------------------------
|
||||
|
||||
-- {{{ Grab environment
|
||||
local tonumber = tonumber
|
||||
local os = { time = os.time }
|
||||
local io = { lines = io.lines }
|
||||
local setmetatable = setmetatable
|
||||
local string = { match = string.match }
|
||||
local helpers = require("vicious.helpers")
|
||||
-- }}}
|
||||
|
||||
|
||||
-- Net: provides state and usage statistics of all network interfaces
|
||||
module("vicious.widgets.net")
|
||||
|
||||
|
||||
-- Initialize function tables
|
||||
local nets = {}
|
||||
-- Variable definitions
|
||||
local unit = { ["b"] = 1, ["kb"] = 1024,
|
||||
["mb"] = 1024^2, ["gb"] = 1024^3
|
||||
}
|
||||
|
||||
-- {{{ Net widget type
|
||||
local function worker(format)
|
||||
local args = {}
|
||||
|
||||
-- Get NET stats
|
||||
for line in io.lines("/proc/net/dev") do
|
||||
-- Match wmaster0 as well as rt0 (multiple leading spaces)
|
||||
local name = string.match(line, "^[%s]?[%s]?[%s]?[%s]?([%w]+):")
|
||||
if name ~= nil then
|
||||
-- Received bytes, first value after the name
|
||||
local recv = tonumber(string.match(line, ":[%s]*([%d]+)"))
|
||||
-- Transmited bytes, 7 fields from end of the line
|
||||
local send = tonumber(string.match(line,
|
||||
"([%d]+)%s+%d+%s+%d+%s+%d+%s+%d+%s+%d+%s+%d+%s+%d$"))
|
||||
|
||||
helpers.uformat(args, name .. " rx", recv, unit)
|
||||
helpers.uformat(args, name .. " tx", send, unit)
|
||||
|
||||
-- Operational state and carrier detection
|
||||
local sysnet = helpers.pathtotable("/sys/class/net/" .. name)
|
||||
args["{"..name.." carrier}"] = tonumber(sysnet.carrier) or 0
|
||||
|
||||
if nets[name] == nil then
|
||||
-- Default values on the first run
|
||||
nets[name] = {}
|
||||
helpers.uformat(args, name .. " down", 0, unit)
|
||||
helpers.uformat(args, name .. " up", 0, unit)
|
||||
|
||||
nets[name].time = os.time()
|
||||
else -- Net stats are absolute, substract our last reading
|
||||
local interval = os.time() - nets[name].time > 0 and
|
||||
os.time() - nets[name].time or 1
|
||||
nets[name].time = os.time()
|
||||
|
||||
local down = (recv - nets[name][1]) / interval
|
||||
local up = (send - nets[name][2]) / interval
|
||||
|
||||
helpers.uformat(args, name .. " down", down, unit)
|
||||
helpers.uformat(args, name .. " up", up, unit)
|
||||
end
|
||||
|
||||
-- Store totals
|
||||
nets[name][1] = recv
|
||||
nets[name][2] = send
|
||||
end
|
||||
end
|
||||
|
||||
return args
|
||||
end
|
||||
-- }}}
|
||||
|
||||
setmetatable(_M, { __call = function(_, ...) return worker(...) end })
|
@ -0,0 +1,61 @@
|
||||
---------------------------------------------------
|
||||
-- Licensed under the GNU General Public License v2
|
||||
-- * (c) 2010, Adrian C. <anrxc@sysphere.org>
|
||||
-- * (c) org-awesome, Damien Leone
|
||||
---------------------------------------------------
|
||||
|
||||
-- {{{ Grab environment
|
||||
local io = { lines = io.lines }
|
||||
local setmetatable = setmetatable
|
||||
local string = { find = string.find }
|
||||
local os = {
|
||||
time = os.time,
|
||||
date = os.date
|
||||
}
|
||||
-- }}}
|
||||
|
||||
|
||||
-- Org: provides agenda statistics for Emacs org-mode
|
||||
module("vicious.widgets.org")
|
||||
|
||||
|
||||
-- {{{ OrgMode widget type
|
||||
local function worker(format, warg)
|
||||
if not warg then return end
|
||||
|
||||
-- Compute delays
|
||||
local today = os.time{ year=os.date("%Y"), month=os.date("%m"), day=os.date("%d") }
|
||||
local soon = today + 24 * 3600 * 3 -- 3 days ahead is close
|
||||
local future = today + 24 * 3600 * 7 -- 7 days ahead is maximum
|
||||
|
||||
-- Initialize counters
|
||||
local count = { past = 0, today = 0, soon = 0, future = 0 }
|
||||
|
||||
-- Get data from agenda files
|
||||
for i=1, #warg do
|
||||
for line in io.lines(warg[i]) do
|
||||
local scheduled = string.find(line, "SCHEDULED:")
|
||||
local closed = string.find(line, "CLOSED:")
|
||||
local deadline = string.find(line, "DEADLINE:")
|
||||
|
||||
if (scheduled and not closed) or (deadline and not closed) then
|
||||
local b, e, y, m, d = string.find(line, "(%d%d%d%d)-(%d%d)-(%d%d)")
|
||||
|
||||
if b then
|
||||
local t = os.time{ year = y, month = m, day = d }
|
||||
|
||||
if t < today then count.past = count.past + 1
|
||||
elseif t == today then count.today = count.today + 1
|
||||
elseif t <= soon then count.soon = count.soon + 1
|
||||
elseif t <= future then count.future = count.future + 1
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return {count.past, count.today, count.soon, count.future}
|
||||
end
|
||||
-- }}}
|
||||
|
||||
setmetatable(_M, { __call = function(_, ...) return worker(...) end })
|
@ -0,0 +1,72 @@
|
||||
---------------------------------------------------
|
||||
-- Licensed under the GNU General Public License v2
|
||||
-- * (c) 2010, Adrian C. <anrxc@sysphere.org>
|
||||
---------------------------------------------------
|
||||
|
||||
-- {{{ Grab environment
|
||||
local pairs = pairs
|
||||
local tonumber = tonumber
|
||||
local io = { popen = io.popen }
|
||||
local os = { getenv = os.getenv }
|
||||
local math = { ceil = math.ceil }
|
||||
local setmetatable = setmetatable
|
||||
local helpers = require("vicious.helpers")
|
||||
local string = {
|
||||
gsub = string.gsub,
|
||||
match = string.match
|
||||
}
|
||||
-- }}}
|
||||
|
||||
|
||||
-- OS: provides operating system information
|
||||
module("vicious.widgets.os")
|
||||
|
||||
|
||||
-- {{{ Operating system widget type
|
||||
local function worker(format)
|
||||
local system = {
|
||||
["ostype"] = "N/A",
|
||||
["hostname"] = "N/A",
|
||||
["osrelease"] = "N/A",
|
||||
["username"] = "N/A",
|
||||
["entropy"] = "N/A",
|
||||
["entropy_p"] = "N/A"
|
||||
}
|
||||
|
||||
-- Linux manual page: uname(2)
|
||||
local kernel = helpers.pathtotable("/proc/sys/kernel")
|
||||
for k, v in pairs(system) do
|
||||
if kernel[k] then
|
||||
system[k] = string.gsub(kernel[k], "[%s]*$", "")
|
||||
end
|
||||
end
|
||||
|
||||
-- BSD manual page: uname(1)
|
||||
if system["ostype"] == "N/A" then
|
||||
local f = io.popen("uname -snr")
|
||||
local uname = f:read("*line")
|
||||
f:close()
|
||||
|
||||
system["ostype"], system["hostname"], system["osrelease"] =
|
||||
string.match(uname, "([%w]+)[%s]([%w%p]+)[%s]([%w%p]+)")
|
||||
end
|
||||
|
||||
-- Linux manual page: random(4)
|
||||
if kernel.random then
|
||||
-- Linux 2.6 default entropy pool is 4096-bits
|
||||
local poolsize = tonumber(kernel.random.poolsize)
|
||||
|
||||
-- Get available entropy and calculate percentage
|
||||
system["entropy"] = tonumber(kernel.random.entropy_avail)
|
||||
system["entropy_p"] = math.ceil(system["entropy"] * 100 / poolsize)
|
||||
end
|
||||
|
||||
-- Get user from the environment
|
||||
system["username"] = os.getenv("USER")
|
||||
|
||||
return {system["ostype"], system["osrelease"], system["username"],
|
||||
system["hostname"], system["entropy"], system["entropy_p"]}
|
||||
end
|
||||
-- }}}
|
||||
|
||||
setmetatable(_M, { __call = function(_, ...) return worker(...) end })
|
@ -0,0 +1,46 @@
|
||||
---------------------------------------------------
|
||||
-- Licensed under the GNU General Public License v2
|
||||
-- * (c) 2010, Adrian C. <anrxc@sysphere.org>
|
||||
---------------------------------------------------
|
||||
|
||||
-- {{{ Grab environment
|
||||
local io = { popen = io.popen }
|
||||
local math = { max = math.max }
|
||||
local setmetatable = setmetatable
|
||||
-- }}}
|
||||
|
||||
|
||||
-- Pkg: provides number of pending updates on UNIX systems
|
||||
module("vicious.widgets.pkg")
|
||||
|
||||
|
||||
-- {{{ Packages widget type
|
||||
local function worker(format, warg)
|
||||
if not warg then return end
|
||||
|
||||
-- Initialize counters
|
||||
local updates = 0
|
||||
local manager = {
|
||||
["Arch"] = { cmd = "pacman -Qu" },
|
||||
["Arch S"] = { cmd = "yes | pacman -Sup", sub = 2 },
|
||||
["Debian"] = { cmd = "apt-show-versions -u -b" },
|
||||
["Ubuntu"] = { cmd = "aptitude search '~U'" },
|
||||
["Fedora"] = { cmd = "yum list updates", sub = 3 },
|
||||
["FreeBSD"] ={ cmd = "pkg_version -I -l '<'" },
|
||||
["Mandriva"]={ cmd = "urpmq --auto-select" }
|
||||
}
|
||||
|
||||
-- Check if updates are available
|
||||
local pkg = manager[warg]
|
||||
local f = io.popen(pkg.cmd)
|
||||
|
||||
for line in f:lines() do
|
||||
updates = updates + 1
|
||||
end
|
||||
f:close()
|
||||
|
||||
return {pkg.sub and math.max(updates-pkg.sub, 0) or updates}
|
||||
end
|
||||
-- }}}
|
||||
|
||||
setmetatable(_M, { __call = function(_, ...) return worker(...) end })
|
@ -0,0 +1,57 @@
|
||||
-----------------------------------------------------
|
||||
-- Licensed under the GNU General Public License v2
|
||||
-- * (c) 2010, Hagen Schink <troja84@googlemail.com>
|
||||
-----------------------------------------------------
|
||||
|
||||
-- {{{ Grab environment
|
||||
local io = { lines = io.lines }
|
||||
local setmetatable = setmetatable
|
||||
local string = {
|
||||
len = string.len,
|
||||
sub = string.sub,
|
||||
match = string.match,
|
||||
gmatch = string.gmatch
|
||||
}
|
||||
-- }}}
|
||||
|
||||
|
||||
-- Raid: provides state information for a requested RAID array
|
||||
module("vicious.widgets.raid")
|
||||
|
||||
|
||||
-- Initialize function tables
|
||||
local mddev = {}
|
||||
|
||||
-- {{{ RAID widget type
|
||||
local function worker(format, warg)
|
||||
if not warg then return end
|
||||
mddev[warg] = {
|
||||
["found"] = false,
|
||||
["active"] = 0,
|
||||
["assigned"] = 0
|
||||
}
|
||||
|
||||
-- Linux manual page: md(4)
|
||||
for line in io.lines("/proc/mdstat") do
|
||||
if mddev[warg]["found"] then
|
||||
local updev = string.match(line, "%[[_U]+%]")
|
||||
|
||||
for i in string.gmatch(updev, "U") do
|
||||
mddev[warg]["active"] = mddev[warg]["active"] + 1
|
||||
end
|
||||
|
||||
break
|
||||
elseif string.sub(line, 1, string.len(warg)) == warg then
|
||||
mddev[warg]["found"] = true
|
||||
|
||||
for i in string.gmatch(line, "%[[%d]%]") do
|
||||
mddev[warg]["assigned"] = mddev[warg]["assigned"] + 1
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return {mddev[warg]["assigned"], mddev[warg]["active"]}
|
||||
end
|
||||
-- }}}
|
||||
|
||||
setmetatable(_M, { __call = function(_, ...) return worker(...) end })
|
@ -0,0 +1,45 @@
|
||||
---------------------------------------------------
|
||||
-- Licensed under the GNU General Public License v2
|
||||
-- * (c) 2010, Adrian C. <anrxc@sysphere.org>
|
||||
---------------------------------------------------
|
||||
|
||||
-- {{{ Grab environment
|
||||
local type = type
|
||||
local tonumber = tonumber
|
||||
local setmetatable = setmetatable
|
||||
local string = { match = string.match }
|
||||
local helpers = require("vicious.helpers")
|
||||
-- }}}
|
||||
|
||||
|
||||
-- Thermal: provides temperature levels of ACPI and coretemp thermal zones
|
||||
module("vicious.widgets.thermal")
|
||||
|
||||
|
||||
-- {{{ Thermal widget type
|
||||
local function worker(format, warg)
|
||||
if not warg then return end
|
||||
|
||||
local zone = { -- Known temperature data sources
|
||||
["sys"] = {"/sys/class/thermal/", file = "temp", div = 1000},
|
||||
["core"] = {"/sys/devices/platform/", file = "temp1_input",div = 1000},
|
||||
["proc"] = {"/proc/acpi/thermal_zone/",file = "temperature"}
|
||||
} -- Default to /sys/class/thermal
|
||||
warg = type(warg) == "table" and warg or { warg, "sys" }
|
||||
|
||||
-- Get temperature from thermal zone
|
||||
local thermal = helpers.pathtotable(zone[warg[2]][1] .. warg[1])
|
||||
|
||||
if thermal[zone[warg[2]].file] then
|
||||
if zone[warg[2]].div then
|
||||
return {thermal[zone[warg[2]].file] / zone[warg[2]].div}
|
||||
else -- /proc/acpi "temperature: N C"
|
||||
return {tonumber(string.match(thermal[zone[warg[2]].file], "[%d]+"))}
|
||||
end
|
||||
end
|
||||
|
||||
return {0}
|
||||
end
|
||||
-- }}}
|
||||
|
||||
setmetatable(_M, { __call = function(_, ...) return worker(...) end })
|
@ -0,0 +1,35 @@
|
||||
---------------------------------------------------
|
||||
-- Licensed under the GNU General Public License v2
|
||||
-- * (c) 2010, Adrian C. <anrxc@sysphere.org>
|
||||
-- * (c) 2009, Lucas de Vries <lucas@glacicle.com>
|
||||
---------------------------------------------------
|
||||
|
||||
-- {{{ Grab environment
|
||||
local setmetatable = setmetatable
|
||||
local math = { floor = math.floor }
|
||||
local string = { match = string.match }
|
||||
local helpers = require("vicious.helpers")
|
||||
-- }}}
|
||||
|
||||
|
||||
-- Uptime: provides system uptime and load information
|
||||
module("vicious.widgets.uptime")
|
||||
|
||||
|
||||
-- {{{ Uptime widget type
|
||||
local function worker(format)
|
||||
local proc = helpers.pathtotable("/proc")
|
||||
|
||||
-- Get system uptime
|
||||
local up_t = math.floor(string.match(proc.uptime, "[%d]+"))
|
||||
local up_d = math.floor(up_t / (3600 * 24))
|
||||
local up_h = math.floor((up_t % (3600 * 24)) / 3600)
|
||||
local up_m = math.floor(((up_t % (3600 * 24)) % 3600) / 60)
|
||||
|
||||
local l1, l5, l15 = -- Get load averages for past 1, 5 and 15 minutes
|
||||
string.match(proc.loadavg, "([%d%.]+)[%s]([%d%.]+)[%s]([%d%.]+)")
|
||||
return {up_d, up_h, up_m, l1, l5, l15}
|
||||
end
|
||||
-- }}}
|
||||
|
||||
setmetatable(_M, { __call = function(_, ...) return worker(...) end })
|
@ -0,0 +1,52 @@
|
||||
---------------------------------------------------
|
||||
-- Licensed under the GNU General Public License v2
|
||||
-- * (c) 2010, Adrian C. <anrxc@sysphere.org>
|
||||
---------------------------------------------------
|
||||
|
||||
-- {{{ Grab environment
|
||||
local tonumber = tonumber
|
||||
local io = { popen = io.popen }
|
||||
local setmetatable = setmetatable
|
||||
local string = { match = string.match }
|
||||
-- }}}
|
||||
|
||||
|
||||
-- Volume: provides volume levels and state of requested ALSA mixers
|
||||
module("vicious.widgets.volume")
|
||||
|
||||
|
||||
-- {{{ Volume widget type
|
||||
local function worker(format, warg)
|
||||
if not warg then return end
|
||||
|
||||
local mixer_state = {
|
||||
["on"] = "♫", -- "",
|
||||
["off"] = "♩" -- "M"
|
||||
}
|
||||
|
||||
-- Get mixer control contents
|
||||
local f = io.popen("amixer get " .. warg)
|
||||
local mixer = f:read("*all")
|
||||
f:close()
|
||||
|
||||
-- Capture mixer control state: [5%] ... ... [on]
|
||||
local volu, mute = string.match(mixer, "([%d]+)%%.*%[([%l]*)")
|
||||
-- Handle mixers without data
|
||||
if volu == nil then
|
||||
return {0, mixer_state["off"]}
|
||||
end
|
||||
|
||||
-- Handle mixers without mute
|
||||
if mute == "" and volu == "0"
|
||||
-- Handle mixers that are muted
|
||||
or mute == "off" then
|
||||
mute = mixer_state["off"]
|
||||
else
|
||||
mute = mixer_state["on"]
|
||||
end
|
||||
|
||||
return {tonumber(volu), mute}
|
||||
end
|
||||
-- }}}
|
||||
|
||||
setmetatable(_M, { __call = function(_, ...) return worker(...) end })
|
@ -0,0 +1,85 @@
|
||||
---------------------------------------------------
|
||||
-- Licensed under the GNU General Public License v2
|
||||
-- * (c) 2010, Adrian C. <anrxc@sysphere.org>
|
||||
---------------------------------------------------
|
||||
|
||||
-- {{{ Grab environment
|
||||
local tonumber = tonumber
|
||||
local io = { popen = io.popen }
|
||||
local setmetatable = setmetatable
|
||||
local math = { ceil = math.ceil }
|
||||
local string = { match = string.match }
|
||||
local helpers = require("vicious.helpers")
|
||||
-- }}}
|
||||
|
||||
|
||||
-- Weather: provides weather information for a requested station
|
||||
module("vicious.widgets.weather")
|
||||
|
||||
|
||||
-- Initialize function tables
|
||||
local weather = {
|
||||
["{city}"] = "N/A",
|
||||
["{wind}"] = "N/A",
|
||||
["{windmph}"] = "N/A",
|
||||
["{windkmh}"] = "N/A",
|
||||
["{sky}"] = "N/A",
|
||||
["{weather}"] = "N/A",
|
||||
["{tempf}"] = "N/A",
|
||||
["{tempc}"] = "N/A",
|
||||
["{humid}"] = "N/A",
|
||||
["{press}"] = "N/A"
|
||||
}
|
||||
|
||||
-- {{{ Weather widget type
|
||||
local function worker(format, warg)
|
||||
if not warg then return end
|
||||
|
||||
-- Get weather forceast by the station ICAO code, from:
|
||||
-- * US National Oceanic and Atmospheric Administration
|
||||
local noaa = "http://weather.noaa.gov/pub/data/observations/metar/decoded/"
|
||||
local f = io.popen("curl --connect-timeout 1 -fsm 3 "..noaa..warg..".TXT")
|
||||
local ws = f:read("*all")
|
||||
f:close()
|
||||
|
||||
-- Check if there was a timeout or a problem with the station
|
||||
if ws == nil then return weather end
|
||||
|
||||
weather["{city}"] = -- City and/or area
|
||||
string.match(ws, "^(.+)%,.*%([%u]+%)") or weather["{city}"]
|
||||
weather["{wind}"] = -- Wind direction and degrees if available
|
||||
string.match(ws, "Wind:[%s][%a]+[%s][%a]+[%s](.+)[%s]at.+$") or weather["{wind}"]
|
||||
weather["{windmph}"] = -- Wind speed in MPH if available
|
||||
string.match(ws, "Wind:[%s].+[%s]at[%s]([%d]+)[%s]MPH") or weather["{windmph}"]
|
||||
weather["{sky}"] = -- Sky conditions if available
|
||||
string.match(ws, "Sky[%s]conditions:[%s](.-)[%c]") or weather["{sky}"]
|
||||
weather["{weather}"] = -- Weather conditions if available
|
||||
string.match(ws, "Weather:[%s](.-)[%c]") or weather["{weather}"]
|
||||
weather["{tempf}"] = -- Temperature in fahrenheit
|
||||
string.match(ws, "Temperature:[%s]([%-]?[%d%.]+).*[%c]") or weather["{tempf}"]
|
||||
weather["{humid}"] = -- Relative humidity in percent
|
||||
string.match(ws, "Relative[%s]Humidity:[%s]([%d]+)%%") or weather["{humid}"]
|
||||
weather["{press}"] = -- Pressure in hPa
|
||||
string.match(ws, "Pressure[%s].+%((.+)[%s]hPa%)") or weather["{press}"]
|
||||
|
||||
-- Wind speed in km/h if MPH was available
|
||||
if weather["{windmph}"] ~= "N/A" then
|
||||
weather["{windmph}"] = tonumber(weather["{windmph}"])
|
||||
weather["{windkmh}"] = math.ceil(weather["{windmph}"] * 1.6)
|
||||
end -- Temperature in °C if °F was available
|
||||
if weather["{tempf}"] ~= "N/A" then
|
||||
weather["{tempf}"] = tonumber(weather["{tempf}"])
|
||||
weather["{tempc}"] = math.ceil((weather["{tempf}"] - 32) * 5/9)
|
||||
end -- Capitalize some stats so they don't look so out of place
|
||||
if weather["{sky}"] ~= "N/A" then
|
||||
weather["{sky}"] = helpers.capitalize(weather["{sky}"])
|
||||
end
|
||||
if weather["{weather}"] ~= "N/A" then
|
||||
weather["{weather}"] = helpers.capitalize(weather["{weather}"])
|
||||
end
|
||||
|
||||
return weather
|
||||
end
|
||||
-- }}}
|
||||
|
||||
setmetatable(_M, { __call = function(_, ...) return worker(...) end })
|
@ -0,0 +1,80 @@
|
||||
---------------------------------------------------
|
||||
-- Licensed under the GNU General Public License v2
|
||||
-- * (c) 2010, Adrian C. <anrxc@sysphere.org>
|
||||
---------------------------------------------------
|
||||
|
||||
-- {{{ Grab environment
|
||||
local tonumber = tonumber
|
||||
local math = { ceil = math.ceil }
|
||||
local setmetatable = setmetatable
|
||||
local helpers = require("vicious.helpers")
|
||||
local io = {
|
||||
open = io.open,
|
||||
popen = io.popen
|
||||
}
|
||||
local string = {
|
||||
find = string.find,
|
||||
match = string.match
|
||||
}
|
||||
-- }}}
|
||||
|
||||
|
||||
-- Wifi: provides wireless information for a requested interface
|
||||
module("vicious.widgets.wifi")
|
||||
|
||||
|
||||
-- {{{ Wireless widget type
|
||||
local function worker(format, warg)
|
||||
if not warg then return end
|
||||
|
||||
-- Default values
|
||||
local winfo = {
|
||||
["{ssid}"] = "N/A",
|
||||
["{mode}"] = "N/A",
|
||||
["{chan}"] = 0,
|
||||
["{rate}"] = 0,
|
||||
["{link}"] = 0,
|
||||
["{linp}"] = 0,
|
||||
["{sign}"] = 0
|
||||
}
|
||||
|
||||
-- Get data from iwconfig where available
|
||||
local iwconfig = "/sbin/iwconfig"
|
||||
local f = io.open(iwconfig, "rb")
|
||||
if not f then
|
||||
iwconfig = "/usr/sbin/iwconfig"
|
||||
else
|
||||
f:close()
|
||||
end
|
||||
local f = io.popen(iwconfig .." ".. warg .. " 2>&1")
|
||||
local iw = f:read("*all")
|
||||
f:close()
|
||||
|
||||
-- iwconfig wasn't found, isn't executable, or non-wireless interface
|
||||
if iw == nil or string.find(iw, "No such device") then
|
||||
return winfo
|
||||
end
|
||||
|
||||
-- Output differs from system to system, some stats can be
|
||||
-- separated by =, and not all drivers report all stats
|
||||
winfo["{ssid}"] = -- SSID can have almost anything in it
|
||||
helpers.escape(string.match(iw, 'ESSID[=:]"(.-)"') or winfo["{ssid}"])
|
||||
winfo["{mode}"] = -- Modes are simple, but also match the "-" in Ad-Hoc
|
||||
string.match(iw, "Mode[=:]([%w%-]*)") or winfo["{mode}"]
|
||||
winfo["{chan}"] = -- Channels are plain digits
|
||||
tonumber(string.match(iw, "Channel[=:]([%d]+)") or winfo["{chan}"])
|
||||
winfo["{rate}"] = -- Bitrate can start with a space, we don't want to display Mb/s
|
||||
tonumber(string.match(iw, "Bit Rate[=:]([%s]?[%d%.]*)") or winfo["{rate}"])
|
||||
winfo["{link}"] = -- Link quality can contain a slash (32/70), match only the first number
|
||||
tonumber(string.match(iw, "Link Quality[=:]([%d]+)") or winfo["{link}"])
|
||||
winfo["{sign}"] = -- Signal level can be a negative value, don't display decibel notation
|
||||
tonumber(string.match(iw, "Signal level[=:]([%-]?[%d]+)") or winfo["{sign}"])
|
||||
|
||||
-- Link quality percentage if quality was available
|
||||
if winfo["{link}"] ~= 0 then winfo["{linp}"] = math.ceil(winfo["{link}"] / 0.7) end
|
||||
|
||||
return winfo
|
||||
end
|
||||
-- }}}
|
||||
|
||||
setmetatable(_M, { __call = function(_, ...) return worker(...) end })
|
154
DUFRESNE/Linux/home/burchettm/.config/awesome/menu
Normal file
154
DUFRESNE/Linux/home/burchettm/.config/awesome/menu
Normal file
@ -0,0 +1,154 @@
|
||||
menu98edb85b00d9527ad5acebe451b3fae6 = { {"7-Zip FM", "7zFM"},
|
||||
{"Android Notifier Desktop", "/usr/share/android-notifier-desktop/run.sh"},
|
||||
{"Archive Manager", "file-roller "},
|
||||
{"AutoKey (GTK)", "autokey-gtk"},
|
||||
{"Avant Window Navigator", "avant-window-navigator"},
|
||||
{"ClamTk", "clamtk "},
|
||||
{"Disk Utility", "palimpsest"},
|
||||
{"File Manager", "pcmanfm "},
|
||||
{"HP Device Manager", "hp-toolbox"},
|
||||
{"Image Viewer", "gpicview "},
|
||||
{"KeePassX", "keepassx "},
|
||||
{"LXTerminal", "lxterminal"},
|
||||
{"Leafpad", "leafpad "},
|
||||
{"NFO Viewer", "nfoview "},
|
||||
{"Root Terminal", "gksu -l gnome-terminal"},
|
||||
{"Terminator", "terminator"},
|
||||
{"Vi IMproved", "gvim -f "},
|
||||
}
|
||||
|
||||
menu78059f1898ed518c6ccd6a6392fa82c1 = { {"AUR", "xdg-open https://aur.archlinux.org"},
|
||||
{"Bugs", "xdg-open https://bugs.archlinux.org"},
|
||||
{"Developers", "xdg-open http://www.archlinux.org/developers/"},
|
||||
{"Documentation", "xdg-open https://wiki.archlinux.org/index.php/Official_Arch_Linux_Install_Guide"},
|
||||
{"Donate", "xdg-open http://www.archlinux.org/donate/"},
|
||||
{"Forum", "xdg-open https://bbs.archlinux.org"},
|
||||
{"Homepage", "xdg-open http://www.archlinux.org"},
|
||||
{"SVN", "xdg-open http://projects.archlinux.org/svntogit/"},
|
||||
{"Schwag", "xdg-open http://www.zazzle.com/archlinux/"},
|
||||
{"Wiki", "xdg-open https://wiki.archlinux.org"},
|
||||
}
|
||||
|
||||
menu251bd8143891238ecedc306508e29017 = { {"Imprudence Second Life viewer", "/usr/bin/imprudence-secondlife"},
|
||||
{"Lincity-NG", "lincity-ng"},
|
||||
{"Minecraft", "minecraft"},
|
||||
{"PlayOnLinux", "playonlinux"},
|
||||
{"Savage 2", "/usr/bin/savage2"},
|
||||
{"Savage 2 Map Editor", "/usr/bin/savage2 \"PushMod editor; Set host_autoExec StartClient\""},
|
||||
{"Savage 2 Model Viewer", "/usr/bin/savage2 \"PushMod modelviewer; Set host_autoExec StartClient\""},
|
||||
{"Supertuxkart", "/usr/bin/supertuxkart --log=file"},
|
||||
{"The Lord of the Rings Online", "pylotro"},
|
||||
{"World of Padman", "worldofpadman"},
|
||||
{"fretsonfire", "fretsonfire"},
|
||||
}
|
||||
|
||||
menud334dfcea59127bedfcdbe0a3ee7f494 = { {"E-book Viewer", "ebook-viewer "},
|
||||
{"GNU Image Manipulation Program", "gimp-2.7 "},
|
||||
{"Image Viewer", "gpicview "},
|
||||
{"LRF Viewer", "lrfviewer "},
|
||||
{"XSane - Scanning", "xsane"},
|
||||
}
|
||||
|
||||
menuc8205c7636e728d448c2774e6a4a944b = { {"Avahi SSH Server Browser", "/usr/bin/bssh"},
|
||||
{"Avahi VNC Server Browser", "/usr/bin/bvnc"},
|
||||
{"Chromium", "chromium "},
|
||||
{"Dropbox", "/opt/dropbox/dropboxd"},
|
||||
{"FileZilla", "filezilla"},
|
||||
{"Firefox", "firefox "},
|
||||
{"Links", "xlinks -g"},
|
||||
{"Mangler", "mangler"},
|
||||
{"Midori", "midori "},
|
||||
{"Opera", "/usr/bin/opera "},
|
||||
{"Pidgin Internet Messenger", "pidgin"},
|
||||
{"QuickSynergy", "quicksynergy"},
|
||||
{"SeaMonkey internet suite", "seamonkey "},
|
||||
{"Skype", "skype"},
|
||||
{"TeamSpeak 3", "/usr/bin/teamspeak3"},
|
||||
{"TeamViewer", "/opt/teamviewer/teamviewer/6/bin/teamviewer"},
|
||||
{"Thunderbird", "thunderbird "},
|
||||
{"Turpial", "turpial"},
|
||||
{"Wicd", "/usr/bin/wicd-client"},
|
||||
{"X11VNC Server", "x11vnc -gui tray=setpass -rfbport PROMPT -bg -o %HOME/.x11vnc.log.%VNCDISPLAY"},
|
||||
}
|
||||
|
||||
menudf814135652a5a308fea15bff37ea284 = { {"Calibre", "calibre"},
|
||||
{"LibreOffice ", "libreoffice "},
|
||||
{"ePDFViewer", "epdfview "},
|
||||
}
|
||||
|
||||
menu6311ae17c1ee52b36e68aaf4ad066387 = { {"ROX Filer", "rox"},
|
||||
{"dosbox Emulator", "dosbox"},
|
||||
}
|
||||
|
||||
menue6f43c40ab1c07cd29e4e83e4ef6bf85 = { {"Android SDK", "android"},
|
||||
{"BlueJ", "/usr/bin/bluej"},
|
||||
{"Bluefish Editor", "bluefish "},
|
||||
{"Eclipse", "eclipse"},
|
||||
{"Google Gadget Designer", "/usr/bin/ggl-gtk -sa -nd -gp /usr/share/google-gadgets/designer.gg"},
|
||||
{"Java Monitoring and Management Console", "jconsole"},
|
||||
{"Java VisualVM", "jvisualvm"},
|
||||
{"MonoDevelop", "monodevelop "},
|
||||
{"NetBeans IDE", "/usr/share/netbeans/bin/netbeans"},
|
||||
{"Qt Assistant", "/usr/bin/assistant"},
|
||||
{"Qt Designer", "/usr/bin/designer"},
|
||||
{"Qt Linguist", "/usr/bin/linguist"},
|
||||
}
|
||||
|
||||
menu52dd1c847264a75f400961bfb4d1c849 = { {"AcetoneISO", "acetoneiso "},
|
||||
{"Audacious", "audacious "},
|
||||
{"Audacity", "audacity"},
|
||||
{"EasyTAG", "easytag "},
|
||||
{"Ex Falso", "exfalso"},
|
||||
{"GNOME MPlayer", "gnome-mplayer "},
|
||||
{"Gnome Music Player Client", "gmpc"},
|
||||
{"HandBrake", "ghb"},
|
||||
{"Last.fm", "lastfm"},
|
||||
{"Nero Linux", "nero "},
|
||||
{"Nero Linux Express", "neroexpress "},
|
||||
{"Pithos", "pithos"},
|
||||
{"QT V4L2 test Utility", "qv4l2"},
|
||||
{"Quod Libet", "quodlibet"},
|
||||
{"Sonata", "sonata"},
|
||||
{"Sound Converter", "soundconverter "},
|
||||
{"VLC media player", "vlc "},
|
||||
{"VolWheel", "volwheel"},
|
||||
{"Webcam Application", "wxcam"},
|
||||
{"XBMC Media Center", "xbmc"},
|
||||
{"dvd::rip", "/usr/bin/vendor_perl/dvdrip"},
|
||||
{"gtk-recordMyDesktop", "gtk-recordMyDesktop"},
|
||||
}
|
||||
|
||||
menuee69799670a33f75d45c57d1d1cd0ab3 = { {"Avahi Zeroconf Browser", "/usr/bin/avahi-discover"},
|
||||
{"Bulk Rename", "/usr/lib/Thunar/ThunarBulkRename "},
|
||||
{"Cairo Composite Manager", "cairo-compmgr"},
|
||||
{"Cairo-Dock (no OpenGL)", "cairo-dock -c"},
|
||||
{"Compiz Fusion Icon", "fusion-icon"},
|
||||
{"GLX-Dock (Cairo-Dock with OpenGL)", "cairo-dock -o"},
|
||||
{"GParted", "gksu /usr/sbin/gparted "},
|
||||
{"Htop", "xterm -e htop"},
|
||||
{"Manage Printing", "/usr/bin/xdg-open http://localhost:631/"},
|
||||
{"Oracle VM VirtualBox", "VirtualBox "},
|
||||
{"PkgBrowser", "pkgbrowser"},
|
||||
{"Sakura", "sakura"},
|
||||
{"Terminal", "Terminal"},
|
||||
{"Thunar File Manager", "Thunar "},
|
||||
{"UNetbootin", "/usr/bin/unetbootin"},
|
||||
{"VMware Player", "/usr/bin/vmplayer"},
|
||||
{"VMware Workstation", "/usr/bin/vmware"},
|
||||
{"Virtual Network Editor", "/usr/bin/vmware-netcfg"},
|
||||
{"Wireshark", "wireshark"},
|
||||
{"rxvt-unicode", "urxvt"},
|
||||
}
|
||||
|
||||
xdgmenu = { {"Accessories", menu98edb85b00d9527ad5acebe451b3fae6},
|
||||
{"Archlinux", menu78059f1898ed518c6ccd6a6392fa82c1},
|
||||
{"Games", menu251bd8143891238ecedc306508e29017},
|
||||
{"Graphics", menud334dfcea59127bedfcdbe0a3ee7f494},
|
||||
{"Internet", menuc8205c7636e728d448c2774e6a4a944b},
|
||||
{"Office", menudf814135652a5a308fea15bff37ea284},
|
||||
{"Other", menu6311ae17c1ee52b36e68aaf4ad066387},
|
||||
{"Programming", menue6f43c40ab1c07cd29e4e83e4ef6bf85},
|
||||
{"Sound & Video", menu52dd1c847264a75f400961bfb4d1c849},
|
||||
{"System Tools", menuee69799670a33f75d45c57d1d1cd0ab3},
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user