diff --git a/alacritty/alacritty.yml b/alacritty/alacritty.yml
new file mode 100644
index 0000000..4cbd979
--- /dev/null
+++ b/alacritty/alacritty.yml
@@ -0,0 +1,886 @@
+# Configuration for Alacritty, the GPU enhanced terminal emulator.
+
+# Import additional configuration files
+#
+# Imports are loaded in order, skipping all missing files, with the importing
+# file being loaded last. If a field is already present in a previous import, it
+# will be replaced.
+#
+# All imports must either be absolute paths starting with `/`, or paths relative
+# to the user's home directory starting with `~/`.
+import:
+ - ~/.config/alacritty/colour-spaceship.yml
+
+# Any items in the `env` entry below will be added as
+# environment variables. Some entries may override variables
+# set by alacritty itself.
+env:
+ # TERM variable
+ #
+ # This value is used to set the `$TERM` environment variable for
+ # each instance of Alacritty. If it is not present, alacritty will
+ # check the local terminfo database and use `alacritty` if it is
+ # available, otherwise `xterm-256color` is used.
+ TERM: alacritty
+
+window:
+ # Window dimensions (changes require restart)
+ #
+ # Number of lines/columns (not pixels) in the terminal. Both lines and columns
+ # must be non-zero for this to take effect. The number of columns must be at
+ # least `2`, while using a value of `0` for columns and lines will fall back
+ # to the window manager's recommended size
+ dimensions:
+ columns: 65
+ lines: 18
+
+ # Window position (changes require restart)
+ #
+ # Specified in number of pixels.
+ # If the position is not set, the window manager will handle the placement.
+ #position:
+ # x: 0
+ # y: 0
+
+ # Window padding (changes require restart)
+ #
+ # Blank space added around the window in pixels. This padding is scaled
+ # by DPI and the specified value is always added at both opposing sides.
+ padding:
+ x: 8
+ y: 8
+
+ # Spread additional padding evenly around the terminal content.
+ #dynamic_padding: false
+
+ # Background opacity
+ #
+ # Window opacity as a floating point number from `0.0` to `1.0`.
+ # The value `0.0` is completely transparent and `1.0` is opaque.
+ opacity: 0.45
+
+ # Startup Mode (changes require restart)
+ #
+ # Values for `startup_mode`:
+ # - Windowedhttps://raw.githubusercontent.com/alacritty/alacritty/master/alacritty.yml
+ # - Maximized
+ # - Fullscreen
+ #
+ # Values for `startup_mode` (macOS only):
+ # - SimpleFullscreen
+ #startup_mode: Windowed
+
+ # Window title
+ title: Alacritty
+
+ # Allow terminal applications to change Alacritty's window title.
+ dynamic_title: true
+
+ # Window class (Linux/BSD only):
+ class:
+ # Application instance name
+ instance: Alacritty
+ # General application class
+ general: Alacritty
+
+ # Decorations theme variant
+ #
+ # Override the variant of the System theme/GTK theme/Wayland client side
+ # decorations. Commonly supported values are `Dark`, `Light`, and `None` for
+ # auto pick-up. Set this to `None` to use the default theme variant.
+ #decorations_theme_variant: None
+
+ # Resize increments
+ #
+ # Prefer resizing window by discrete steps equal to cell dimensions.
+ #resize_increments: false
+
+#scrolling:
+ # Maximum number of lines in the scrollback buffer.
+ # Specifying '0' will disable scrolling.
+ #history: 10000
+
+ # Scrolling distance multiplier.
+ #multiplier: 3
+
+# Font configuration
+font:
+ normal:
+ family: Fira Code
+
+ # The `style` can be specified to pick a specific face.
+ #style: Regular
+
+ # Bold font face
+ #bold:
+ # Font family
+ #
+ # If the bold family is not specified, it will fall back to the
+ # value specified for the normal font.
+ #family: monospace
+
+ # The `style` can be specified to pick a specific face.
+ #style: Bold
+
+ # Italic font face
+ #italic:
+ # Font family
+ #
+ # If the italic family is not specified, it will fall back to the
+ # value specified for the normal font.
+ #family: monospace
+
+ # The `style` can be specified to pick a specific face.
+ #style: Italic
+
+ # Bold italic font face
+ #bold_italic:
+ # Font family
+ #
+ # If the bold italic family is not specified, it will fall back to the
+ # value specified for the normal font.
+ #family: monospace
+
+ # The `style` can be specified to pick a specific face.
+ #style: Bold Italic
+
+ # Point size
+ size: 11
+
+ # Offset is the extra space around each character. `offset.y` can be thought
+ # of as modifying the line spacing, and `offset.x` as modifying the letter
+ # spacing.
+ #offset:
+ # x: 0
+ # y: 0
+
+ # Glyph offset determines the locations of the glyphs within their cells with
+ # the default being at the bottom. Increasing `x` moves the glyph to the
+ # right, increasing `y` moves the glyph upward.
+ #glyph_offset:
+ # x: 0
+ # y: 0
+
+ # Use built-in font for box drawing characters.
+ #
+ # If `true`, Alacritty will use a custom built-in font for box drawing
+ # characters (Unicode points 2500 - 259f).
+ #
+ #builtin_box_drawing: true
+
+# If `true`, bold text is drawn using the bright color variants.
+#draw_bold_text_with_bright_colors: false
+
+# Colors (Tomorrow Night)
+#colors:
+ # Default colors
+ #primary:
+ # background: '#1d1f21'
+ # foreground: '#c5c8c6'
+
+ # Bright and dim foreground colors
+ #
+ # The dimmed foreground color is calculated automatically if it is not
+ # present. If the bright foreground color is not set, or
+ # `draw_bold_text_with_bright_colors` is `false`, the normal foreground
+ # color will be used.
+ #dim_foreground: '#828482'
+ #bright_foreground: '#eaeaea'
+
+ # Cursor colors
+ #
+ # Colors which should be used to draw the terminal cursor.
+ #
+ # Allowed values are CellForeground/CellBackground, which reference the
+ # affected cell, or hexadecimal colors like #ff00ff.
+ #cursor:
+ # text: CellBackground
+ # cursor: CellForeground
+
+ # Vi mode cursor colors
+ #
+ # Colors for the cursor when the vi mode is active.
+ #
+ # Allowed values are CellForeground/CellBackground, which reference the
+ # affected cell, or hexadecimal colors like #ff00ff.
+ #vi_mode_cursor:
+ # text: CellBackground
+ # cursor: CellForeground
+
+ # Search colors
+ #
+ # Colors used for the search bar and match highlighting.
+ #search:
+ # Allowed values are CellForeground/CellBackground, which reference the
+ # affected cell, or hexadecimal colors like #ff00ff.
+ #matches:
+ # foreground: '#000000'
+ # background: '#ffffff'
+ #focused_match:
+ # foreground: '#ffffff'
+ # background: '#000000'
+
+ # Keyboard hints
+ #hints:
+ # First character in the hint label
+ #
+ # Allowed values are CellForeground/CellBackground, which reference the
+ # affected cell, or hexadecimal colors like #ff00ff.
+ #start:
+ # foreground: '#1d1f21'
+ # background: '#e9ff5e'
+
+ # All characters after the first one in the hint label
+ #
+ # Allowed values are CellForeground/CellBackground, which reference the
+ # affected cell, or hexadecimal colors like #ff00ff.
+ #end:
+ # foreground: '#e9ff5e'
+ # background: '#1d1f21'
+
+ # Line indicator
+ #
+ # Color used for the indicator displaying the position in history during
+ # search and vi mode.
+ #
+ # By default, these will use the opposing primary color.
+ #line_indicator:
+ # foreground: None
+ # background: None
+
+ # Footer bar
+ #
+ # Color used for the footer bar on the bottom, used by search regex input,
+ # hyperlink URI preview, etc.
+ #
+ #footer_bar:
+ # background: '#c5c8c6'
+ # foreground: '#1d1f21'
+
+ # Selection colors
+ #
+ # Colors which should be used to draw the selection area.
+ #
+ # Allowed values are CellForeground/CellBackground, which reference the
+ # affected cell, or hexadecimal colors like #ff00ff.
+ #selection:
+ # text: CellBackground
+ # background: CellForeground
+
+ # Normal colors
+ #normal:
+ # black: '#1d1f21'
+ # red: '#cc6666'
+ # green: '#b5bd68'
+ # yellow: '#f0c674'
+ # blue: '#81a2be'
+ # magenta: '#b294bb'
+ # cyan: '#8abeb7'
+ # white: '#c5c8c6'
+
+ # Bright colors
+ #bright:
+ # black: '#666666'
+ # red: '#d54e53'
+ # green: '#b9ca4a'
+ # yellow: '#e7c547'
+ # blue: '#7aa6da'
+ # magenta: '#c397d8'
+ # cyan: '#70c0b1'
+ # white: '#eaeaea'
+
+ # Dim colors
+ #
+ # If the dim colors are not set, they will be calculated automatically based
+ # on the `normal` colors.
+ #dim:
+ # black: '#131415'
+ # red: '#864343'
+ # green: '#777c44'
+ # yellow: '#9e824c'
+ # blue: '#556a7d'
+ # magenta: '#75617b'
+ # cyan: '#5b7d78'
+ # white: '#828482'
+
+ # Indexed Colors
+ #
+ # The indexed colors include all colors from 16 to 256.
+ # When these are not set, they're filled with sensible defaults.
+ #
+ # Example:
+ # `- { index: 16, color: '#ff00ff' }`
+ #
+ #indexed_colors: []
+
+ # Transparent cell backgrounds
+ #
+ # Whether or not `window.opacity` applies to all cell backgrounds or only to
+ # the default background. When set to `true` all cells will be transparent
+ # regardless of their background color.
+ #transparent_background_colors: false
+
+# Bell
+#
+# The bell is rung every time the BEL control character is received.
+#bell:
+ # Visual Bell Animation
+ #
+ # Animation effect for flashing the screen when the visual bell is rung.
+ #
+ # Values for `animation`:
+ # - Ease
+ # - EaseOut
+ # - EaseOutSine
+ # - EaseOutQuad
+ # - EaseOutCubic
+ # - EaseOutQuart
+ # - EaseOutQuint
+ # - EaseOutExpo
+ # - EaseOutCirc
+ # - Linear
+ #animation: EaseOutExpo
+
+ # Duration of the visual bell flash in milliseconds. A `duration` of `0` will
+ # disable the visual bell animation.
+ #duration: 0
+
+ # Visual bell animation color.
+ #color: '#ffffff'
+
+ # Bell Command
+ #
+ # This program is executed whenever the bell is rung.
+ #
+ # When set to `command: None`, no command will be executed.
+ #
+ # Example:
+ # command:
+ # program: notify-send
+ # args: ["Hello, World!"]
+ #
+ #command: None
+
+#selection:
+ # This string contains all characters that are used as separators for
+ # "semantic words" in Alacritty.
+ #semantic_escape_chars: ",│`|:\"' ()[]{}<>\t"
+
+ # When set to `true`, selected text will be copied to the primary clipboard.
+ #save_to_clipboard: false
+
+#cursor:
+ # Cursor style
+ #style:
+ # Cursor shape
+ #
+ # Values for `shape`:
+ # - ▇ Block
+ # - _ Underline
+ # - | Beam
+ #shape: Block
+
+ # Cursor blinking state
+ #
+ # Values for `blinking`:
+ # - Never: Prevent the cursor from ever blinking
+ # - Off: Disable blinking by default
+ # - On: Enable blinking by default
+ # - Always: Force the cursor to always blink
+ #blinking: Off
+
+ # Vi mode cursor style
+ #
+ # If the vi mode cursor style is `None` or not specified, it will fall back to
+ # the style of the active value of the normal cursor.
+ #
+ # See `cursor.style` for available options.
+ #vi_mode_style: None
+
+ # Cursor blinking interval in milliseconds.
+ #blink_interval: 750
+
+ # Time after which cursor stops blinking, in seconds.
+ #
+ # Specifying '0' will disable timeout for blinking.
+ #blink_timeout: 5
+
+ # If this is `true`, the cursor will be rendered as a hollow box when the
+ # window is not focused.
+ #unfocused_hollow: true
+
+ # Thickness of the cursor relative to the cell width as floating point number
+ # from `0.0` to `1.0`.
+ #thickness: 0.15
+
+# Live config reload (changes require restart)
+#live_config_reload: true
+
+# Shell
+#
+# You can set `shell.program` to the path of your favorite shell, e.g.
+# `/bin/fish`. Entries in `shell.args` are passed unmodified as arguments to the
+# shell.
+#
+# Default:
+# - (Linux/BSD/macOS) `$SHELL` or the user's login shell, if `$SHELL` is unset
+# - (Windows) powershell
+#shell:
+# program: /bin/bash
+# args:
+# - --login
+
+# Startup directory
+#
+# Directory the shell is started in. If this is unset, or `None`, the working
+# directory of the parent process will be used.
+#working_directory: None
+
+# Offer IPC using `alacritty msg` (unix only)
+#ipc_socket: true
+
+#mouse:
+ # Click settings
+ #
+ # The `double_click` and `triple_click` settings control the time
+ # alacritty should wait for accepting multiple clicks as one double
+ # or triple click.
+ #double_click: { threshold: 300 }
+ #triple_click: { threshold: 300 }
+
+ # If this is `true`, the cursor is temporarily hidden when typing.
+ #hide_when_typing: false
+
+# Hints
+#
+# Terminal hints can be used to find text or hyperlink in the visible part of
+# the terminal and pipe it to other applications.
+#hints:
+ # Keys used for the hint labels.
+ #alphabet: "jfkdls;ahgurieowpq"
+
+ # List with all available hints
+ #
+ # Each hint must have any of `regex` or `hyperlinks` field and either an
+ # `action` or a `command` field. The fields `mouse`, `binding` and
+ # `post_processing` are optional.
+ #
+ # The `hyperlinks` option will cause OSC 8 escape sequence hyperlinks to be
+ # highlighted.
+ #
+ # The fields `command`, `binding.key`, `binding.mods`, `binding.mode` and
+ # `mouse.mods` accept the same values as they do in the `key_bindings` section.
+ #
+ # The `mouse.enabled` field controls if the hint should be underlined while
+ # the mouse with all `mouse.mods` keys held or the vi mode cursor is above it.
+ #
+ # If the `post_processing` field is set to `true`, heuristics will be used to
+ # shorten the match if there are characters likely not to be part of the hint
+ # (e.g. a trailing `.`). This is most useful for URIs and applies only to
+ # `regex` matches.
+ #
+ # Values for `action`:
+ # - Copy
+ # Copy the hint's text to the clipboard.
+ # - Paste
+ # Paste the hint's text to the terminal or search.
+ # - Select
+ # Select the hint's text.
+ # - MoveViModeCursor
+ # Move the vi mode cursor to the beginning of the hint.
+ #enabled:
+ # - regex: "(ipfs:|ipns:|magnet:|mailto:|gemini:|gopher:|https:|http:|news:|file:|git:|ssh:|ftp:)\
+ # [^\u0000-\u001F\u007F-\u009F<>\"\\s{-}\\^⟨⟩`]+"
+ # hyperlinks: true
+ # command: xdg-open
+ # post_processing: true
+ # mouse:
+ # enabled: true
+ # mods: None
+ # binding:
+ # key: U
+ # mods: Control|Shift
+
+# Mouse bindings
+#
+# Mouse bindings are specified as a list of objects, much like the key
+# bindings further below.
+#
+# To trigger mouse bindings when an application running within Alacritty
+# captures the mouse, the `Shift` modifier is automatically added as a
+# requirement.
+#
+# Each mouse binding will specify a:
+#
+# - `mouse`:
+#
+# - Middle
+# - Left
+# - Right
+# - Numeric identifier such as `5`
+#
+# - `action` (see key bindings for actions not exclusive to mouse mode)
+#
+# - Mouse exclusive actions:
+#
+# - ExpandSelection
+# Expand the selection to the current mouse cursor location.
+#
+# And optionally:
+#
+# - `mods` (see key bindings)
+#mouse_bindings:
+# - { mouse: Right, action: ExpandSelection }
+# - { mouse: Right, mods: Control, action: ExpandSelection }
+# - { mouse: Middle, mode: ~Vi, action: PasteSelection }
+
+# Key bindings
+#
+# Key bindings are specified as a list of objects. For example, this is the
+# default paste binding:
+#
+# `- { key: V, mods: Control|Shift, action: Paste }`
+#
+# Each key binding will specify a:
+#
+# - `key`: Identifier of the key pressed
+#
+# - A-Z
+# - F1-F24
+# - Key0-Key9
+#
+# A full list with available key codes can be found here:
+# https://docs.rs/winit/*/winit/event/enum.VirtualKeyCode.html#variants
+#
+# Instead of using the name of the keys, the `key` field also supports using
+# the scancode of the desired key. Scancodes have to be specified as a
+# decimal number. This command will allow you to display the hex scancodes
+# for certain keys:
+#
+# `showkey --scancodes`.
+#
+# Then exactly one of:
+#
+# - `chars`: Send a byte sequence to the running application
+#
+# The `chars` field writes the specified string to the terminal. This makes
+# it possible to pass escape sequences. To find escape codes for bindings
+# like `PageUp` (`"\x1b[5~"`), you can run the command `showkey -a` outside
+# of tmux. Note that applications use terminfo to map escape sequences back
+# to keys. It is therefore required to update the terminfo when changing an
+# escape sequence.
+#
+# - `action`: Execute a predefined action
+#
+# - ToggleViMode
+# - SearchForward
+# Start searching toward the right of the search origin.
+# - SearchBackward
+# Start searching toward the left of the search origin.
+# - Copy
+# - Paste
+# - IncreaseFontSize
+# - DecreaseFontSize
+# - ResetFontSize
+# - ScrollPageUp
+# - ScrollPageDown
+# - ScrollHalfPageUp
+# - ScrollHalfPageDown
+# - ScrollLineUp
+# - ScrollLineDown
+# - ScrollToTop
+# - ScrollToBottom
+# - ClearHistory
+# Remove the terminal's scrollback history.
+# - Hide
+# Hide the Alacritty window.
+# - Minimize
+# Minimize the Alacritty window.
+# - Quit
+# Quit Alacritty.
+# - ToggleFullscreen
+# - ToggleMaximized
+# - SpawnNewInstance
+# Spawn a new instance of Alacritty.
+# - CreateNewWindow
+# Create a new Alacritty window from the current process.
+# - ClearLogNotice
+# Clear Alacritty's UI warning and error notice.
+# - ClearSelection
+# Remove the active selection.
+# - ReceiveChar
+# - None
+#
+# - Vi mode exclusive actions:
+#
+# - Open
+# Perform the action of the first matching hint under the vi mode cursor
+# with `mouse.enabled` set to `true`.
+# - ToggleNormalSelection
+# - ToggleLineSelection
+# - ToggleBlockSelection
+# - ToggleSemanticSelection
+# Toggle semantic selection based on `selection.semantic_escape_chars`.
+# - CenterAroundViCursor
+# Center view around vi mode cursor
+#
+# - Vi mode exclusive cursor motion actions:
+#
+# - Up
+# One line up.
+# - Down
+# One line down.
+# - Left
+# One character left.
+# - Right
+# One character right.
+# - First
+# First column, or beginning of the line when already at the first column.
+# - Last
+# Last column, or beginning of the line when already at the last column.
+# - FirstOccupied
+# First non-empty cell in this terminal row, or first non-empty cell of
+# the line when already at the first cell of the row.
+# - High
+# Top of the screen.
+# - Middle
+# Center of the screen.
+# - Low
+# Bottom of the screen.
+# - SemanticLeft
+# Start of the previous semantically separated word.
+# - SemanticRight
+# Start of the next semantically separated word.
+# - SemanticLeftEnd
+# End of the previous semantically separated word.
+# - SemanticRightEnd
+# End of the next semantically separated word.
+# - WordLeft
+# Start of the previous whitespace separated word.
+# - WordRight
+# Start of the next whitespace separated word.
+# - WordLeftEnd
+# End of the previous whitespace separated word.
+# - WordRightEnd
+# End of the next whitespace separated word.
+# - Bracket
+# Character matching the bracket at the cursor's location.
+# - SearchNext
+# Beginning of the next match.
+# - SearchPrevious
+# Beginning of the previous match.
+# - SearchStart
+# Start of the match to the left of the vi mode cursor.
+# - SearchEnd
+# End of the match to the right of the vi mode cursor.
+#
+# - Search mode exclusive actions:
+# - SearchFocusNext
+# Move the focus to the next search match.
+# - SearchFocusPrevious
+# Move the focus to the previous search match.
+# - SearchConfirm
+# - SearchCancel
+# - SearchClear
+# Reset the search regex.
+# - SearchDeleteWord
+# Delete the last word in the search regex.
+# - SearchHistoryPrevious
+# Go to the previous regex in the search history.
+# - SearchHistoryNext
+# Go to the next regex in the search history.
+#
+# - macOS exclusive actions:
+# - ToggleSimpleFullscreen
+# Enter fullscreen without occupying another space.
+#
+# - Linux/BSD exclusive actions:
+#
+# - CopySelection
+# Copy from the selection buffer.
+# - PasteSelection
+# Paste from the selection buffer.
+#
+# - `command`: Fork and execute a specified command plus arguments
+#
+# The `command` field must be a map containing a `program` string and an
+# `args` array of command line parameter strings. For example:
+# `{ program: "alacritty", args: ["-e", "vttest"] }`
+#
+# And optionally:
+#
+# - `mods`: Key modifiers to filter binding actions
+#
+# - Command
+# - Control
+# - Option
+# - Super
+# - Shift
+# - Alt
+#
+# Multiple `mods` can be combined using `|` like this:
+# `mods: Control|Shift`.
+# Whitespace and capitalization are relevant and must match the example.
+#
+# - `mode`: Indicate a binding for only specific terminal reported modes
+#
+# This is mainly used to send applications the correct escape sequences
+# when in different modes.
+#
+# - AppCursor
+# - AppKeypad
+# - Search
+# - Alt
+# - Vi
+#
+# A `~` operator can be used before a mode to apply the binding whenever
+# the mode is *not* active, e.g. `~Alt`.
+#
+# Bindings are always filled by default, but will be replaced when a new
+# binding with the same triggers is defined. To unset a default binding, it can
+# be mapped to the `ReceiveChar` action. Alternatively, you can use `None` for
+# a no-op if you do not wish to receive input characters for that binding.
+#
+# If the same trigger is assigned to multiple actions, all of them are executed
+# in the order they were defined in.
+#key_bindings:
+ #- { key: Paste, action: Paste }
+ #- { key: Copy, action: Copy }
+ #- { key: L, mods: Control, action: ClearLogNotice }
+ #- { key: L, mods: Control, mode: ~Vi|~Search, chars: "\x0c" }
+ #- { key: PageUp, mods: Shift, mode: ~Alt, action: ScrollPageUp }
+ #- { key: PageDown, mods: Shift, mode: ~Alt, action: ScrollPageDown }
+ #- { key: Home, mods: Shift, mode: ~Alt, action: ScrollToTop }
+ #- { key: End, mods: Shift, mode: ~Alt, action: ScrollToBottom }
+
+ # Vi Mode
+ #- { key: Space, mods: Shift|Control, mode: ~Search, action: ToggleViMode }
+ #- { key: Space, mods: Shift|Control, mode: Vi|~Search, action: ScrollToBottom }
+ #- { key: Escape, mode: Vi|~Search, action: ClearSelection }
+ #- { key: I, mode: Vi|~Search, action: ToggleViMode }
+ #- { key: I, mode: Vi|~Search, action: ScrollToBottom }
+ #- { key: C, mods: Control, mode: Vi|~Search, action: ToggleViMode }
+ #- { key: Y, mods: Control, mode: Vi|~Search, action: ScrollLineUp }
+ #- { key: E, mods: Control, mode: Vi|~Search, action: ScrollLineDown }
+ #- { key: G, mode: Vi|~Search, action: ScrollToTop }
+ #- { key: G, mods: Shift, mode: Vi|~Search, action: ScrollToBottom }
+ #- { key: B, mods: Control, mode: Vi|~Search, action: ScrollPageUp }
+ #- { key: F, mods: Control, mode: Vi|~Search, action: ScrollPageDown }
+ #- { key: U, mods: Control, mode: Vi|~Search, action: ScrollHalfPageUp }
+ #- { key: D, mods: Control, mode: Vi|~Search, action: ScrollHalfPageDown }
+ #- { key: Y, mode: Vi|~Search, action: Copy }
+ #- { key: Y, mode: Vi|~Search, action: ClearSelection }
+ #- { key: Copy, mode: Vi|~Search, action: ClearSelection }
+ #- { key: V, mode: Vi|~Search, action: ToggleNormalSelection }
+ #- { key: V, mods: Shift, mode: Vi|~Search, action: ToggleLineSelection }
+ #- { key: V, mods: Control, mode: Vi|~Search, action: ToggleBlockSelection }
+ #- { key: V, mods: Alt, mode: Vi|~Search, action: ToggleSemanticSelection }
+ #- { key: Return, mode: Vi|~Search, action: Open }
+ #- { key: Z, mode: Vi|~Search, action: CenterAroundViCursor }
+ #- { key: K, mode: Vi|~Search, action: Up }
+ #- { key: J, mode: Vi|~Search, action: Down }
+ #- { key: H, mode: Vi|~Search, action: Left }
+ #- { key: L, mode: Vi|~Search, action: Right }
+ #- { key: Up, mode: Vi|~Search, action: Up }
+ #- { key: Down, mode: Vi|~Search, action: Down }
+ #- { key: Left, mode: Vi|~Search, action: Left }
+ #- { key: Right, mode: Vi|~Search, action: Right }
+ #- { key: Key0, mode: Vi|~Search, action: First }
+ #- { key: Key4, mods: Shift, mode: Vi|~Search, action: Last }
+ #- { key: Key6, mods: Shift, mode: Vi|~Search, action: FirstOccupied }
+ #- { key: H, mods: Shift, mode: Vi|~Search, action: High }
+ #- { key: M, mods: Shift, mode: Vi|~Search, action: Middle }
+ #- { key: L, mods: Shift, mode: Vi|~Search, action: Low }
+ #- { key: B, mode: Vi|~Search, action: SemanticLeft }
+ #- { key: W, mode: Vi|~Search, action: SemanticRight }
+ #- { key: E, mode: Vi|~Search, action: SemanticRightEnd }
+ #- { key: B, mods: Shift, mode: Vi|~Search, action: WordLeft }
+ #- { key: W, mods: Shift, mode: Vi|~Search, action: WordRight }
+ #- { key: E, mods: Shift, mode: Vi|~Search, action: WordRightEnd }
+ #- { key: Key5, mods: Shift, mode: Vi|~Search, action: Bracket }
+ #- { key: Slash, mode: Vi|~Search, action: SearchForward }
+ #- { key: Slash, mods: Shift, mode: Vi|~Search, action: SearchBackward }
+ #- { key: N, mode: Vi|~Search, action: SearchNext }
+ #- { key: N, mods: Shift, mode: Vi|~Search, action: SearchPrevious }
+
+ # Search Mode
+ #- { key: Return, mode: Search|Vi, action: SearchConfirm }
+ #- { key: Escape, mode: Search, action: SearchCancel }
+ #- { key: C, mods: Control, mode: Search, action: SearchCancel }
+ #- { key: U, mods: Control, mode: Search, action: SearchClear }
+ #- { key: W, mods: Control, mode: Search, action: SearchDeleteWord }
+ #- { key: P, mods: Control, mode: Search, action: SearchHistoryPrevious }
+ #- { key: N, mods: Control, mode: Search, action: SearchHistoryNext }
+ #- { key: Up, mode: Search, action: SearchHistoryPrevious }
+ #- { key: Down, mode: Search, action: SearchHistoryNext }
+ #- { key: Return, mode: Search|~Vi, action: SearchFocusNext }
+ #- { key: Return, mods: Shift, mode: Search|~Vi, action: SearchFocusPrevious }
+
+ # (Windows, Linux, and BSD only)
+ #- { key: V, mods: Control|Shift, mode: ~Vi, action: Paste }
+ #- { key: C, mods: Control|Shift, action: Copy }
+ #- { key: F, mods: Control|Shift, mode: ~Search, action: SearchForward }
+ #- { key: B, mods: Control|Shift, mode: ~Search, action: SearchBackward }
+ #- { key: C, mods: Control|Shift, mode: Vi|~Search, action: ClearSelection }
+ #- { key: Insert, mods: Shift, action: PasteSelection }
+ #- { key: Key0, mods: Control, action: ResetFontSize }
+ #- { key: Equals, mods: Control, action: IncreaseFontSize }
+ #- { key: Plus, mods: Control, action: IncreaseFontSize }
+ #- { key: NumpadAdd, mods: Control, action: IncreaseFontSize }
+ #- { key: Minus, mods: Control, action: DecreaseFontSize }
+ #- { key: NumpadSubtract, mods: Control, action: DecreaseFontSize }
+
+ # (Windows only)
+ #- { key: Return, mods: Alt, action: ToggleFullscreen }
+
+ # (macOS only)
+ #- { key: K, mods: Command, mode: ~Vi|~Search, chars: "\x0c" }
+ #- { key: K, mods: Command, mode: ~Vi|~Search, action: ClearHistory }
+ #- { key: Key0, mods: Command, action: ResetFontSize }
+ #- { key: Equals, mods: Command, action: IncreaseFontSize }
+ #- { key: Plus, mods: Command, action: IncreaseFontSize }
+ #- { key: NumpadAdd, mods: Command, action: IncreaseFontSize }
+ #- { key: Minus, mods: Command, action: DecreaseFontSize }
+ #- { key: NumpadSubtract, mods: Command, action: DecreaseFontSize }
+ #- { key: V, mods: Command, action: Paste }
+ #- { key: C, mods: Command, action: Copy }
+ #- { key: C, mods: Command, mode: Vi|~Search, action: ClearSelection }
+ #- { key: H, mods: Command, action: Hide }
+ #- { key: H, mods: Command|Alt, action: HideOtherApplications }
+ #- { key: M, mods: Command, action: Minimize }
+ #- { key: Q, mods: Command, action: Quit }
+ #- { key: W, mods: Command, action: Quit }
+ #- { key: N, mods: Command, action: CreateNewWindow }
+ #- { key: F, mods: Command|Control, action: ToggleFullscreen }
+ #- { key: F, mods: Command, mode: ~Search, action: SearchForward }
+ #- { key: B, mods: Command, mode: ~Search, action: SearchBackward }
+
+#debug:
+ # Display the time it takes to redraw each frame.
+ #render_timer: false
+
+ # Keep the log file after quitting Alacritty.
+ #persistent_logging: false
+
+ # Log level
+ #
+ # Values for `log_level`:
+ # - Off
+ # - Error
+ # - Warn
+ # - Info
+ # - Debug
+ # - Trace
+ #log_level: Warn
+
+ # Renderer override.
+ # - glsl3
+ # - gles2
+ # - gles2_pure
+ #renderer: None
+
+ # Print all received window events.
+ #print_events: false
+
+ # Highlight window damage information.
+ #highlight_damage: false
diff --git a/alacritty/colour-spaceship.yml b/alacritty/colour-spaceship.yml
new file mode 100644
index 0000000..d3249f1
--- /dev/null
+++ b/alacritty/colour-spaceship.yml
@@ -0,0 +1,27 @@
+colors:
+ # Default colors
+ primary:
+ background: '0xffffff'
+ foreground: '0x233871'
+
+ # Normal colors
+ normal:
+ black: '0xe1e1e1'
+ red: '0x9e5244'
+ green: '0x687036'
+ yellow: '0xb4744d'
+ blue: '0x2d5278'
+ magenta: '0x6c3e8f'
+ cyan: '0x2d6848'
+ white: '0x5b6c99'
+
+ # Bright colors
+ bright:
+ black: '0xababab'
+ red: '0xe17461'
+ green: '0xcee161'
+ yellow: '0xe1b661'
+ blue: '0x4693e0'
+ magenta: '0xa961e1'
+ cyan: '0x61e19c'
+ white: '0x233871'
diff --git a/awesome/README.md b/awesome/README.md
new file mode 100644
index 0000000..729d6d0
--- /dev/null
+++ b/awesome/README.md
@@ -0,0 +1,9 @@
+# awesome config
+## Deps
+- picom
+- pactl (fc38 `pulseaudio-utils`)
+## Credits
+### Widgets/modules/etc I use
+- `volume_widget` comes from [streetturtle's widgets](https://github.com/streetturtle/awesome-wm-widgets) (MIT // 2017)
+### Other people's dotfiles I took from lol
+- Modularization is from [epsi-rns' awesome dotfiles](https://gitlab.com/epsi-rns/dotfiles) (MIT // 2014-2019 E. R. Nurwijayadi)
diff --git a/awesome/awesome-wm-widgets/.luacheckrc b/awesome/awesome-wm-widgets/.luacheckrc
new file mode 100644
index 0000000..e4f47fa
--- /dev/null
+++ b/awesome/awesome-wm-widgets/.luacheckrc
@@ -0,0 +1,24 @@
+self = false
+
+globals = {
+ "screen",
+ "mouse",
+ "root",
+ "client"
+}
+
+read_globals = {
+ "awesome",
+ "button",
+ "dbus",
+ "drawable",
+ "drawin",
+ "key",
+ "keygrabber",
+ "mousegrabber",
+ "selection",
+ "tag",
+ "window",
+ "table.unpack",
+ "math.atan2",
+}
\ No newline at end of file
diff --git a/awesome/awesome-wm-widgets/calendar-widget/README.md b/awesome/awesome-wm-widgets/calendar-widget/README.md
new file mode 100644
index 0000000..b663a18
--- /dev/null
+++ b/awesome/awesome-wm-widgets/calendar-widget/README.md
@@ -0,0 +1,89 @@
+# Calendar Widget
+
+Calendar widget for Awesome WM - slightly improved version of the `wibox.widget.calendar`.
+
+## Features
+
+
+### Customization
+
+| Name | Default | Description |
+|---|---|---|
+| theme | `naughty` | The theme to use |
+| placement | `top` | The position of the popup |
+| radius | 8 | The popup radius |
+| start_sunday | false | Start the week on Sunday |
+
+ - themes:
+
+ | Name | Screenshot |
+ |---|---|
+ | nord | ![nord_theme](./nord.png) |
+ | outrun | ![outrun_theme](./outrun.png) |
+ | light | ![outrun_theme](./light.png) |
+ | dark | ![outrun_theme](./dark.png) |
+ | naughty (default) | from local theme |
+
+ - setup widget placement
+
+ top center - in case you clock is centered:
+
+ ![calendar_top](./calendar_top.png)
+
+ top right - for default awesome config:
+
+ ![calendar_top_right](./calendar_top_right.png)
+
+ bottom right - in case your wibar at the bottom:
+
+ ![calendar_bottom_right](./calendar_bottom_right.png)
+
+ - setup first day of week
+
+ By setting `start_sunday` to true:
+ ![calendar_start_sunday](./calendar_start_sunday.png)
+
+ - mouse support:
+ move to the next and previous month. Using mouse buttons or scroll wheel.
+
+ You can configure this by specifying the button to move to next/previous.
+ Usually these are configured as follows. If you want to use other mouse buttons, you can find their number using `xev`.
+
+ | number | button |
+ |--------|---------------|
+ | 4 | scroll up |
+ | 5 | scroll down |
+ | 1 | left click |
+ | 2 | right click |
+ | 3 | middles click |
+
+ By default `previous_month_button` is 5, `next_month_button` is 4.
+
+
+## How to use
+
+This widget needs an 'anchor' - another widget which triggers visibility of the calendar. Default `mytextclock` is the perfect candidate!
+Just after mytextclock is instantiated, create the widget and add the mouse listener to it.
+
+```lua
+local calendar_widget = require("awesome-wm-widgets.calendar-widget.calendar")
+-- ...
+-- Create a textclock widget
+mytextclock = wibox.widget.textclock()
+-- default
+local cw = calendar_widget()
+-- or customized
+local cw = calendar_widget({
+ theme = 'outrun',
+ placement = 'bottom_right',
+ start_sunday = true,
+ radius = 8,
+-- with customized next/previous (see table above)
+ previous_month_button = 1,
+ next_month_button = 3,
+})
+mytextclock:connect_signal("button::press",
+ function(_, _, _, button)
+ if button == 1 then cw.toggle() end
+ end)
+```
diff --git a/awesome/awesome-wm-widgets/calendar-widget/calendar.lua b/awesome/awesome-wm-widgets/calendar-widget/calendar.lua
new file mode 100644
index 0000000..bc4a877
--- /dev/null
+++ b/awesome/awesome-wm-widgets/calendar-widget/calendar.lua
@@ -0,0 +1,258 @@
+-------------------------------------------------
+-- Calendar Widget for Awesome Window Manager
+-- Shows the current month and supports scroll up/down to switch month
+-- More details could be found here:
+-- https://github.com/streetturtle/awesome-wm-widgets/tree/master/calendar-widget
+
+-- @author Pavel Makhov
+-- @copyright 2019 Pavel Makhov
+-------------------------------------------------
+
+local awful = require("awful")
+local beautiful = require("beautiful")
+local wibox = require("wibox")
+local gears = require("gears")
+local naughty = require("naughty")
+
+local calendar_widget = {}
+
+local function worker(user_args)
+
+ local calendar_themes = {
+ nord = {
+ bg = '#2E3440',
+ fg = '#D8DEE9',
+ focus_date_bg = '#88C0D0',
+ focus_date_fg = '#000000',
+ weekend_day_bg = '#3B4252',
+ weekday_fg = '#88C0D0',
+ header_fg = '#E5E9F0',
+ border = '#4C566A'
+ },
+ outrun = {
+ bg = '#0d0221',
+ fg = '#D8DEE9',
+ focus_date_bg = '#650d89',
+ focus_date_fg = '#2de6e2',
+ weekend_day_bg = '#261447',
+ weekday_fg = '#2de6e2',
+ header_fg = '#f6019d',
+ border = '#261447'
+ },
+ dark = {
+ bg = '#000000',
+ fg = '#ffffff',
+ focus_date_bg = '#ffffff',
+ focus_date_fg = '#000000',
+ weekend_day_bg = '#444444',
+ weekday_fg = '#ffffff',
+ header_fg = '#ffffff',
+ border = '#333333'
+ },
+ light = {
+ bg = '#ffffff',
+ fg = '#000000',
+ focus_date_bg = '#000000',
+ focus_date_fg = '#ffffff',
+ weekend_day_bg = '#AAAAAA',
+ weekday_fg = '#000000',
+ header_fg = '#000000',
+ border = '#CCCCCC'
+ },
+ monokai = {
+ bg = '#272822',
+ fg = '#F8F8F2',
+ focus_date_bg = '#AE81FF',
+ focus_date_fg = '#ffffff',
+ weekend_day_bg = '#75715E',
+ weekday_fg = '#FD971F',
+ header_fg = '#F92672',
+ border = '#75715E'
+ },
+ naughty = {
+ bg = beautiful.notification_bg or beautiful.bg,
+ fg = beautiful.notification_fg or beautiful.fg,
+ focus_date_bg = beautiful.notification_fg or beautiful.fg,
+ focus_date_fg = beautiful.notification_bg or beautiful.bg,
+ weekend_day_bg = beautiful.bg_focus,
+ weekday_fg = beautiful.fg,
+ header_fg = beautiful.fg,
+ border = beautiful.border_normal
+ }
+
+ }
+
+ local args = user_args or {}
+
+ if args.theme ~= nil and calendar_themes[args.theme] == nil then
+ naughty.notify({
+ preset = naughty.config.presets.critical,
+ title = 'Calendar Widget',
+ text = 'Theme "' .. args.theme .. '" not found, fallback to default'})
+ args.theme = 'naughty'
+ end
+
+ local theme = args.theme or 'naughty'
+ local placement = args.placement or 'top'
+ local radius = args.radius or 8
+ local next_month_button = args.next_month_button or 4
+ local previous_month_button = args.previous_month_button or 5
+ local start_sunday = args.start_sunday or false
+
+ local styles = {}
+ local function rounded_shape(size)
+ return function(cr, width, height)
+ gears.shape.rounded_rect(cr, width, height, size)
+ end
+ end
+
+ styles.month = {
+ padding = 4,
+ bg_color = calendar_themes[theme].bg,
+ border_width = 0,
+ }
+
+ styles.normal = {
+ markup = function(t) return t end,
+ shape = rounded_shape(4)
+ }
+
+ styles.focus = {
+ fg_color = calendar_themes[theme].focus_date_fg,
+ bg_color = calendar_themes[theme].focus_date_bg,
+ markup = function(t) return '' .. t .. '' end,
+ shape = rounded_shape(4)
+ }
+
+ styles.header = {
+ fg_color = calendar_themes[theme].header_fg,
+ bg_color = calendar_themes[theme].bg,
+ markup = function(t) return '' .. t .. '' end
+ }
+
+ styles.weekday = {
+ fg_color = calendar_themes[theme].weekday_fg,
+ bg_color = calendar_themes[theme].bg,
+ markup = function(t) return '' .. t .. '' end,
+ }
+
+ local function decorate_cell(widget, flag, date)
+ if flag == 'monthheader' and not styles.monthheader then
+ flag = 'header'
+ end
+
+ -- highlight only today's day
+ if flag == 'focus' then
+ local today = os.date('*t')
+ if not (today.month == date.month and today.year == date.year) then
+ flag = 'normal'
+ end
+ end
+
+ local props = styles[flag] or {}
+ if props.markup and widget.get_text and widget.set_markup then
+ widget:set_markup(props.markup(widget:get_text()))
+ end
+ -- Change bg color for weekends
+ local d = { year = date.year, month = (date.month or 1), day = (date.day or 1) }
+ local weekday = tonumber(os.date('%w', os.time(d)))
+ local default_bg = (weekday == 0 or weekday == 6)
+ and calendar_themes[theme].weekend_day_bg
+ or calendar_themes[theme].bg
+ local ret = wibox.widget {
+ {
+ {
+ widget,
+ halign = 'center',
+ widget = wibox.container.place
+ },
+ margins = (props.padding or 2) + (props.border_width or 0),
+ widget = wibox.container.margin
+ },
+ shape = props.shape,
+ shape_border_color = props.border_color or '#000000',
+ shape_border_width = props.border_width or 0,
+ fg = props.fg_color or calendar_themes[theme].fg,
+ bg = props.bg_color or default_bg,
+ widget = wibox.container.background
+ }
+
+ return ret
+ end
+
+ local cal = wibox.widget {
+ date = os.date('*t'),
+ font = beautiful.get_font(),
+ fn_embed = decorate_cell,
+ long_weekdays = true,
+ start_sunday = start_sunday,
+ widget = wibox.widget.calendar.month
+ }
+
+ local popup = awful.popup {
+ ontop = true,
+ visible = false,
+ shape = rounded_shape(radius),
+ offset = { y = 5 },
+ border_width = 1,
+ border_color = calendar_themes[theme].border,
+ widget = cal
+ }
+
+ popup:buttons(
+ awful.util.table.join(
+ awful.button({}, next_month_button, function()
+ local a = cal:get_date()
+ a.month = a.month + 1
+ cal:set_date(nil)
+ cal:set_date(a)
+ popup:set_widget(cal)
+ end),
+ awful.button({}, previous_month_button, function()
+ local a = cal:get_date()
+ a.month = a.month - 1
+ cal:set_date(nil)
+ cal:set_date(a)
+ popup:set_widget(cal)
+ end)
+ )
+ )
+
+ function calendar_widget.toggle()
+
+ if popup.visible then
+ -- to faster render the calendar refresh it and just hide
+ cal:set_date(nil) -- the new date is not set without removing the old one
+ cal:set_date(os.date('*t'))
+ popup:set_widget(nil) -- just in case
+ popup:set_widget(cal)
+ popup.visible = not popup.visible
+ else
+ if placement == 'top' then
+ awful.placement.top(popup, { margins = { top = 30 }, parent = awful.screen.focused() })
+ elseif placement == 'top_right' then
+ awful.placement.top_right(popup, { margins = { top = 30, right = 10}, parent = awful.screen.focused() })
+ elseif placement == 'top_left' then
+ awful.placement.top_left(popup, { margins = { top = 30, left = 10}, parent = awful.screen.focused() })
+ elseif placement == 'bottom_right' then
+ awful.placement.bottom_right(popup, { margins = { bottom = 30, right = 10},
+ parent = awful.screen.focused() })
+ elseif placement == 'bottom_left' then
+ awful.placement.bottom_left(popup, { margins = { bottom = 30, left = 10},
+ parent = awful.screen.focused() })
+ else
+ awful.placement.top(popup, { margins = { top = 30 }, parent = awful.screen.focused() })
+ end
+
+ popup.visible = true
+
+ end
+ end
+
+ return calendar_widget
+
+end
+
+return setmetatable(calendar_widget, { __call = function(_, ...)
+ return worker(...)
+end })
diff --git a/awesome/awesome-wm-widgets/calendar-widget/calendar_bottom_right.png b/awesome/awesome-wm-widgets/calendar-widget/calendar_bottom_right.png
new file mode 100644
index 0000000..2bc2e82
Binary files /dev/null and b/awesome/awesome-wm-widgets/calendar-widget/calendar_bottom_right.png differ
diff --git a/awesome/awesome-wm-widgets/calendar-widget/calendar_start_sunday.png b/awesome/awesome-wm-widgets/calendar-widget/calendar_start_sunday.png
new file mode 100644
index 0000000..126a218
Binary files /dev/null and b/awesome/awesome-wm-widgets/calendar-widget/calendar_start_sunday.png differ
diff --git a/awesome/awesome-wm-widgets/calendar-widget/calendar_top.png b/awesome/awesome-wm-widgets/calendar-widget/calendar_top.png
new file mode 100644
index 0000000..3e6b66b
Binary files /dev/null and b/awesome/awesome-wm-widgets/calendar-widget/calendar_top.png differ
diff --git a/awesome/awesome-wm-widgets/calendar-widget/calendar_top_right.png b/awesome/awesome-wm-widgets/calendar-widget/calendar_top_right.png
new file mode 100644
index 0000000..4a29022
Binary files /dev/null and b/awesome/awesome-wm-widgets/calendar-widget/calendar_top_right.png differ
diff --git a/awesome/awesome-wm-widgets/calendar-widget/dark.png b/awesome/awesome-wm-widgets/calendar-widget/dark.png
new file mode 100644
index 0000000..540289f
Binary files /dev/null and b/awesome/awesome-wm-widgets/calendar-widget/dark.png differ
diff --git a/awesome/awesome-wm-widgets/calendar-widget/light.png b/awesome/awesome-wm-widgets/calendar-widget/light.png
new file mode 100644
index 0000000..ab675d1
Binary files /dev/null and b/awesome/awesome-wm-widgets/calendar-widget/light.png differ
diff --git a/awesome/awesome-wm-widgets/calendar-widget/nord.png b/awesome/awesome-wm-widgets/calendar-widget/nord.png
new file mode 100644
index 0000000..94f9f7e
Binary files /dev/null and b/awesome/awesome-wm-widgets/calendar-widget/nord.png differ
diff --git a/awesome/awesome-wm-widgets/calendar-widget/outrun.png b/awesome/awesome-wm-widgets/calendar-widget/outrun.png
new file mode 100644
index 0000000..d59c123
Binary files /dev/null and b/awesome/awesome-wm-widgets/calendar-widget/outrun.png differ
diff --git a/awesome/awesome-wm-widgets/cpu-widget/README.md b/awesome/awesome-wm-widgets/cpu-widget/README.md
new file mode 100644
index 0000000..b323f9b
--- /dev/null
+++ b/awesome/awesome-wm-widgets/cpu-widget/README.md
@@ -0,0 +1,71 @@
+# CPU widget
+
+[![GitHub issues by-label](https://img.shields.io/github/issues-raw/streetturtle/awesome-wm-widgets/cpu)](https://github.com/streetturtle/awesome-wm-widgets/labels/cpu)
+
+This widget shows the average CPU load among all cores of the machine:
+
+![screenshot](./cpu.gif)
+
+## How it works
+
+To measure the load I took Paul Colby's bash [script](http://colby.id.au/calculating-cpu-usage-from-proc-stat/) and rewrote it in Lua, which was quite simple.
+So awesome simply reads the first line of /proc/stat:
+
+```bash
+$ cat /proc/stat | grep '^cpu '
+cpu 197294 718 50102 2002182 3844 0 2724 0 0 0
+```
+
+and calculates the percentage.
+
+## Customization
+
+It is possible to customize widget by providing a table with all or some of the following config parameters:
+
+| Name | Default | Description |
+|---|---|---|
+| `width` | 50 | Width of the widget |
+| `step_width` | 2 | Width of the step |
+| `step_spacing` | 1 | Space size between steps |
+| `color` | `beautiful.fg_normal` | Color of the graph |
+| `enable_kill_button` | `false` | Show button which kills the process |
+| `process_info_max_length` | `-1` | Truncate the process information. Some processes may have a very long list of parameters which won't fit in the screen, this options allows to truncate it to the given length. |
+| `timeout` | 1 | How often in seconds the widget refreshes |
+
+### Example
+
+```lua
+cpu_widget({
+ width = 70,
+ step_width = 2,
+ step_spacing = 0,
+ color = '#434c5e'
+})
+```
+
+The config above results in the following widget:
+
+![custom](./custom.png)
+
+## Installation
+
+Clone/download repo and use widget in **rc.lua**:
+
+```lua
+local cpu_widget = require("awesome-wm-widgets.cpu-widget.cpu-widget")
+...
+s.mytasklist, -- Middle widget
+ { -- Right widgets
+ layout = wibox.layout.fixed.horizontal,
+ ...
+ -- default
+ cpu_widget(),
+ -- or custom
+ cpu_widget({
+ width = 70,
+ step_width = 2,
+ step_spacing = 0,
+ color = '#434c5e'
+ })
+ ...
+```
diff --git a/awesome/awesome-wm-widgets/cpu-widget/cpu-widget.lua b/awesome/awesome-wm-widgets/cpu-widget/cpu-widget.lua
new file mode 100644
index 0000000..11debe8
--- /dev/null
+++ b/awesome/awesome-wm-widgets/cpu-widget/cpu-widget.lua
@@ -0,0 +1,339 @@
+-------------------------------------------------
+-- CPU Widget for Awesome Window Manager
+-- Shows the current CPU utilization
+-- More details could be found here:
+-- https://github.com/streetturtle/awesome-wm-widgets/tree/master/cpu-widget
+
+-- @author Pavel Makhov
+-- @copyright 2020 Pavel Makhov
+-------------------------------------------------
+
+local awful = require("awful")
+local watch = require("awful.widget.watch")
+local wibox = require("wibox")
+local beautiful = require("beautiful")
+local gears = require("gears")
+
+local CMD = [[sh -c "grep '^cpu.' /proc/stat; ps -eo '%p|%c|%C|' -o "%mem" -o '|%a' --sort=-%cpu ]]
+ .. [[| head -11 | tail -n +2"]]
+
+-- A smaller command, less resource intensive, used when popup is not shown.
+local CMD_slim = [[grep --max-count=1 '^cpu.' /proc/stat]]
+
+local HOME_DIR = os.getenv("HOME")
+local WIDGET_DIR = HOME_DIR .. '/.config/awesome/awesome-wm-widgets/cpu-widget'
+
+local cpu_widget = {}
+local cpu_rows = {
+ spacing = 4,
+ layout = wibox.layout.fixed.vertical,
+}
+local is_update = true
+local process_rows = {
+ layout = wibox.layout.fixed.vertical,
+}
+
+-- Splits the string by separator
+-- @return table with separated substrings
+local function split(string_to_split, separator)
+ if separator == nil then separator = "%s" end
+ local t = {}
+
+ for str in string.gmatch(string_to_split, "([^".. separator .."]+)") do
+ table.insert(t, str)
+ end
+
+ return t
+end
+
+-- Checks if a string starts with a another string
+local function starts_with(str, start)
+ return str:sub(1, #start) == start
+end
+
+
+local function create_textbox(args)
+ return wibox.widget{
+ text = args.text,
+ align = args.align or 'left',
+ markup = args.markup,
+ forced_width = args.forced_width or 40,
+ widget = wibox.widget.textbox
+ }
+end
+
+local function create_process_header(params)
+ local res = wibox.widget{
+ create_textbox{markup = 'PID'},
+ create_textbox{markup = 'Name'},
+ {
+ create_textbox{markup = '%CPU'},
+ create_textbox{markup = '%MEM'},
+ params.with_action_column and create_textbox{forced_width = 20} or nil,
+ layout = wibox.layout.align.horizontal
+ },
+ layout = wibox.layout.ratio.horizontal
+ }
+ res:ajust_ratio(2, 0.2, 0.47, 0.33)
+
+ return res
+end
+
+local function create_kill_process_button()
+ return wibox.widget{
+ {
+ id = "icon",
+ image = WIDGET_DIR .. '/window-close-symbolic.svg',
+ resize = false,
+ opacity = 0.1,
+ widget = wibox.widget.imagebox
+ },
+ widget = wibox.container.background
+ }
+end
+
+local function worker(user_args)
+
+ local args = user_args or {}
+
+ local width = args.width or 50
+ local step_width = args.step_width or 2
+ local step_spacing = args.step_spacing or 1
+ local color = args.color or beautiful.fg_normal
+ local background_color = args.background_color or "#00000000"
+ local enable_kill_button = args.enable_kill_button or false
+ local process_info_max_length = args.process_info_max_length or -1
+ local timeout = args.timeout or 1
+
+ local cpugraph_widget = wibox.widget {
+ max_value = 100,
+ background_color = background_color,
+ forced_width = width,
+ step_width = step_width,
+ step_spacing = step_spacing,
+ widget = wibox.widget.graph,
+ color = "linear:0,0:0,20:0,#FF0000:0.3,#FFFF00:0.6," .. color
+ }
+
+ -- This timer periodically executes the heavy command while the popup is open.
+ -- It is stopped when the popup is closed and only the slim command is run then.
+ -- This greatly improves performance while the popup is closed at the small cost
+ -- of a slightly longer popup opening time.
+ local popup_timer = gears.timer {
+ timeout = timeout
+ }
+
+ local popup = awful.popup{
+ ontop = true,
+ visible = false,
+ shape = gears.shape.rounded_rect,
+ border_width = 1,
+ border_color = beautiful.bg_normal,
+ maximum_width = 300,
+ offset = { y = 5 },
+ widget = {}
+ }
+
+ -- Do not update process rows when mouse cursor is over the widget
+ popup:connect_signal("mouse::enter", function() is_update = false end)
+ popup:connect_signal("mouse::leave", function() is_update = true end)
+
+ cpugraph_widget:buttons(
+ awful.util.table.join(
+ awful.button({}, 1, function()
+ if popup.visible then
+ popup.visible = not popup.visible
+ -- When the popup is not visible, stop the timer
+ popup_timer:stop()
+ else
+ popup:move_next_to(mouse.current_widget_geometry)
+ -- Restart the timer, when the popup becomes visible
+ -- Emit the signal to start the timer directly and not wait the timeout first
+ popup_timer:start()
+ popup_timer:emit_signal("timeout")
+ end
+ end)
+ )
+ )
+
+ --- By default graph widget goes from left to right, so we mirror it and push up a bit
+ cpu_widget = wibox.widget {
+ {
+ cpugraph_widget,
+ reflection = {horizontal = true},
+ layout = wibox.container.mirror
+ },
+ bottom = 2,
+ color = background_color,
+ widget = wibox.container.margin
+ }
+
+ -- This part runs constantly, also when the popup is closed.
+ -- It updates the graph widget in the bar.
+ local maincpu = {}
+ watch(CMD_slim, timeout, function(widget, stdout)
+
+ local _, user, nice, system, idle, iowait, irq, softirq, steal, _, _ =
+ stdout:match('(%w+)%s+(%d+)%s(%d+)%s(%d+)%s(%d+)%s(%d+)%s(%d+)%s(%d+)%s(%d+)%s(%d+)%s(%d+)')
+
+ local total = user + nice + system + idle + iowait + irq + softirq + steal
+
+ local diff_idle = idle - tonumber(maincpu['idle_prev'] == nil and 0 or maincpu['idle_prev'])
+ local diff_total = total - tonumber(maincpu['total_prev'] == nil and 0 or maincpu['total_prev'])
+ local diff_usage = (1000 * (diff_total - diff_idle) / diff_total + 5) / 10
+
+ maincpu['total_prev'] = total
+ maincpu['idle_prev'] = idle
+
+ widget:add_value(diff_usage)
+ end,
+ cpugraph_widget
+ )
+
+ -- This part runs whenever the timer is fired.
+ -- It therefore only runs when the popup is open.
+ local cpus = {}
+ popup_timer:connect_signal('timeout', function()
+ awful.spawn.easy_async(CMD, function(stdout, _, _, _)
+ local i = 1
+ local j = 1
+ for line in stdout:gmatch("[^\r\n]+") do
+ if starts_with(line, 'cpu') then
+
+ if cpus[i] == nil then cpus[i] = {} end
+
+ local name, user, nice, system, idle, iowait, irq, softirq, steal, _, _ =
+ line:match('(%w+)%s+(%d+)%s(%d+)%s(%d+)%s(%d+)%s(%d+)%s(%d+)%s(%d+)%s(%d+)%s(%d+)%s(%d+)')
+
+ local total = user + nice + system + idle + iowait + irq + softirq + steal
+
+ local diff_idle = idle - tonumber(cpus[i]['idle_prev'] == nil and 0 or cpus[i]['idle_prev'])
+ local diff_total = total - tonumber(cpus[i]['total_prev'] == nil and 0 or cpus[i]['total_prev'])
+ local diff_usage = (1000 * (diff_total - diff_idle) / diff_total + 5) / 10
+
+ cpus[i]['total_prev'] = total
+ cpus[i]['idle_prev'] = idle
+
+ local row = wibox.widget
+ {
+ create_textbox{text = name},
+ create_textbox{text = math.floor(diff_usage) .. '%'},
+ {
+ max_value = 100,
+ value = diff_usage,
+ forced_height = 20,
+ forced_width = 150,
+ paddings = 1,
+ margins = 4,
+ border_width = 1,
+ border_color = beautiful.bg_focus,
+ background_color = beautiful.bg_normal,
+ bar_border_width = 1,
+ bar_border_color = beautiful.bg_focus,
+ color = "linear:150,0:0,0:0,#D08770:0.3,#BF616A:0.6," .. beautiful.fg_normal,
+ widget = wibox.widget.progressbar,
+
+ },
+ layout = wibox.layout.ratio.horizontal
+ }
+ row:ajust_ratio(2, 0.15, 0.15, 0.7)
+ cpu_rows[i] = row
+ i = i + 1
+ else
+ if is_update == true then
+
+ local columns = split(line, '|')
+
+ local pid = columns[1]
+ local comm = columns[2]
+ local cpu = columns[3]
+ local mem = columns[4]
+ local cmd = columns[5]
+
+ local kill_proccess_button = enable_kill_button and create_kill_process_button() or nil
+
+ local pid_name_rest = wibox.widget{
+ create_textbox{text = pid},
+ create_textbox{text = comm},
+ {
+ create_textbox{text = cpu, align = 'center'},
+ create_textbox{text = mem, align = 'center'},
+ kill_proccess_button,
+ layout = wibox.layout.fixed.horizontal
+ },
+ layout = wibox.layout.ratio.horizontal
+ }
+ pid_name_rest:ajust_ratio(2, 0.2, 0.47, 0.33)
+
+ local row = wibox.widget {
+ {
+ pid_name_rest,
+ top = 4,
+ bottom = 4,
+ widget = wibox.container.margin
+ },
+ widget = wibox.container.background
+ }
+
+ row:connect_signal("mouse::enter", function(c) c:set_bg(beautiful.bg_focus) end)
+ row:connect_signal("mouse::leave", function(c) c:set_bg(beautiful.bg_normal) end)
+
+ if enable_kill_button then
+ row:connect_signal("mouse::enter", function() kill_proccess_button.icon.opacity = 1 end)
+ row:connect_signal("mouse::leave", function() kill_proccess_button.icon.opacity = 0.1 end)
+
+ kill_proccess_button:buttons(
+ awful.util.table.join( awful.button({}, 1, function()
+ row:set_bg('#ff0000')
+ awful.spawn.with_shell('kill -9 ' .. pid)
+ end) ) )
+ end
+
+ awful.tooltip {
+ objects = { row },
+ mode = 'outside',
+ preferred_positions = {'bottom'},
+ timer_function = function()
+ local text = cmd
+ if process_info_max_length > 0 and text:len() > process_info_max_length then
+ text = text:sub(0, process_info_max_length - 3) .. '...'
+ end
+
+ return text
+ :gsub('%s%-', '\n\t-') -- put arguments on a new line
+ :gsub(':/', '\n\t\t:/') -- java classpath uses : to separate jars
+ end,
+ }
+
+ process_rows[j] = row
+
+ j = j + 1
+ end
+
+ end
+ end
+ popup:setup {
+ {
+ cpu_rows,
+ {
+ orientation = 'horizontal',
+ forced_height = 15,
+ color = beautiful.bg_focus,
+ widget = wibox.widget.separator
+ },
+ create_process_header{with_action_column = enable_kill_button},
+ process_rows,
+ layout = wibox.layout.fixed.vertical,
+ },
+ margins = 8,
+ widget = wibox.container.margin
+ }
+ end)
+ end)
+
+ return cpu_widget
+end
+
+return setmetatable(cpu_widget, { __call = function(_, ...)
+ return worker(...)
+end })
diff --git a/awesome/awesome-wm-widgets/cpu-widget/cpu.gif b/awesome/awesome-wm-widgets/cpu-widget/cpu.gif
new file mode 100644
index 0000000..cb97262
Binary files /dev/null and b/awesome/awesome-wm-widgets/cpu-widget/cpu.gif differ
diff --git a/awesome/awesome-wm-widgets/cpu-widget/cpu.png b/awesome/awesome-wm-widgets/cpu-widget/cpu.png
new file mode 100644
index 0000000..96ba29f
Binary files /dev/null and b/awesome/awesome-wm-widgets/cpu-widget/cpu.png differ
diff --git a/awesome/awesome-wm-widgets/cpu-widget/custom.png b/awesome/awesome-wm-widgets/cpu-widget/custom.png
new file mode 100644
index 0000000..be275e4
Binary files /dev/null and b/awesome/awesome-wm-widgets/cpu-widget/custom.png differ
diff --git a/awesome/awesome-wm-widgets/cpu-widget/window-close-symbolic.svg b/awesome/awesome-wm-widgets/cpu-widget/window-close-symbolic.svg
new file mode 100644
index 0000000..46ff888
--- /dev/null
+++ b/awesome/awesome-wm-widgets/cpu-widget/window-close-symbolic.svg
@@ -0,0 +1,95 @@
+
+
+
+
diff --git a/awesome/awesome-wm-widgets/email-widget/README.md b/awesome/awesome-wm-widgets/email-widget/README.md
new file mode 100644
index 0000000..510792d
--- /dev/null
+++ b/awesome/awesome-wm-widgets/email-widget/README.md
@@ -0,0 +1,36 @@
+# Email widget
+
+This widget consists of an icon with counter which shows number of unread emails: ![email icon](./em-wid-1.png)
+and a popup message which appears when mouse hovers over an icon: ![email popup](./em-wid-2.png)
+
+Note that widget uses the Arc icon theme, so it should be [installed](https://github.com/horst3180/arc-icon-theme#installation) first under **/usr/share/icons/Arc/** folder.
+
+## Installation
+
+To install it put **email.lua** and **email-widget** folder under **~/.config/awesome**. Then
+
+ - in **email.lua** change path to python scripts;
+ - in python scripts add your credentials (note that password should be encrypted using pgp for example);
+ - add widget to awesome:
+
+```lua
+local email_widget, email_icon = require("email")
+
+...
+s.mytasklist, -- Middle widget
+ { -- Right widgets
+ layout = wibox.layout.fixed.horizontal,
+ ...
+ email_icon,
+ email_widget,
+ ...
+```
+
+## How it works
+
+This widget uses the output of two python scripts, first is called every 20 seconds - it returns number of unread emails and second is called when mouse hovers over an icon and displays content of those emails. For both of them you'll need to provide your credentials and imap server. For testing, they can simply be called from console:
+
+``` bash
+python ~/.config/awesome/email/count_unread_emails.py
+python ~/.config/awesome/email/read_emails.py
+```
diff --git a/awesome/awesome-wm-widgets/email-widget/count_unread_emails.py b/awesome/awesome-wm-widgets/email-widget/count_unread_emails.py
new file mode 100644
index 0000000..a843814
--- /dev/null
+++ b/awesome/awesome-wm-widgets/email-widget/count_unread_emails.py
@@ -0,0 +1,16 @@
+#!/usr/bin/python
+
+import imaplib
+import re
+
+M=imaplib.IMAP4_SSL("mail.teenagemutantninjaturtles.com", 993)
+M.login("mickey@tmnt.com","cowabunga")
+
+status, counts = M.status("INBOX","(MESSAGES UNSEEN)")
+
+if status == "OK":
+ unread = re.search(r'UNSEEN\s(\d+)', counts[0].decode('utf-8')).group(1)
+else:
+ unread = "N/A"
+
+print(unread)
diff --git a/awesome/awesome-wm-widgets/email-widget/em-wid-1.png b/awesome/awesome-wm-widgets/email-widget/em-wid-1.png
new file mode 100644
index 0000000..5290ea8
Binary files /dev/null and b/awesome/awesome-wm-widgets/email-widget/em-wid-1.png differ
diff --git a/awesome/awesome-wm-widgets/email-widget/em-wid-2.png b/awesome/awesome-wm-widgets/email-widget/em-wid-2.png
new file mode 100644
index 0000000..0a0fd3a
Binary files /dev/null and b/awesome/awesome-wm-widgets/email-widget/em-wid-2.png differ
diff --git a/awesome/awesome-wm-widgets/email-widget/email.lua b/awesome/awesome-wm-widgets/email-widget/email.lua
new file mode 100644
index 0000000..df80678
--- /dev/null
+++ b/awesome/awesome-wm-widgets/email-widget/email.lua
@@ -0,0 +1,44 @@
+local wibox = require("wibox")
+local awful = require("awful")
+local naughty = require("naughty")
+local watch = require("awful.widget.watch")
+
+local path_to_icons = "/usr/share/icons/Arc/actions/22/"
+
+local email_widget = wibox.widget.textbox()
+email_widget:set_font('Play 9')
+
+local email_icon = wibox.widget.imagebox()
+email_icon:set_image(path_to_icons .. "/mail-mark-new.png")
+
+watch(
+ "python /home//.config/awesome/email-widget/count_unread_emails.py", 20,
+ function(_, stdout)
+ local unread_emails_num = tonumber(stdout) or 0
+ if (unread_emails_num > 0) then
+ email_icon:set_image(path_to_icons .. "/mail-mark-unread.png")
+ email_widget:set_text(stdout)
+ elseif (unread_emails_num == 0) then
+ email_icon:set_image(path_to_icons .. "/mail-message-new.png")
+ email_widget:set_text("")
+ end
+ end
+)
+
+
+local function show_emails()
+ awful.spawn.easy_async([[bash -c 'python /home//.config/awesome/email-widget/read_unread_emails.py']],
+ function(stdout)
+ naughty.notify{
+ text = stdout,
+ title = "Unread Emails",
+ timeout = 5, hover_timeout = 0.5,
+ width = 400,
+ }
+ end
+ )
+end
+
+email_icon:connect_signal("mouse::enter", function() show_emails() end)
+
+return email_widget, email_icon
diff --git a/awesome/awesome-wm-widgets/email-widget/read_unread_emails.py b/awesome/awesome-wm-widgets/email-widget/read_unread_emails.py
new file mode 100644
index 0000000..fda8188
--- /dev/null
+++ b/awesome/awesome-wm-widgets/email-widget/read_unread_emails.py
@@ -0,0 +1,44 @@
+#!/usr/bin/python
+
+import imaplib
+import email
+import datetime
+
+def process_mailbox(M):
+ rv, data = M.search(None, "(UNSEEN)")
+ if rv != 'OK':
+ print "No messages found!"
+ return
+
+ for num in data[0].split():
+ rv, data = M.fetch(num, '(BODY.PEEK[])')
+ if rv != 'OK':
+ print "ERROR getting message", num
+ return
+ msg = email.message_from_bytes(data[0][1])
+ for header in [ 'From', 'Subject', 'Date' ]:
+ hdr = email.header.make_header(email.header.decode_header(msg[header]))
+ if header == 'Date':
+ date_tuple = email.utils.parsedate_tz(str(hdr))
+ if date_tuple:
+ local_date = datetime.datetime.fromtimestamp(email.utils.mktime_tz(date_tuple))
+ print("{}: {}".format(header, local_date.strftime("%a, %d %b %Y %H:%M:%S")))
+ else:
+ print('{}: {}'.format(header, hdr))
+ # with code below you can process text of email
+ # if msg.is_multipart():
+ # for payload in msg.get_payload():
+ # if payload.get_content_maintype() == 'text':
+ # print payload.get_payload()
+ # else:
+ # print msg.get_payload()
+
+
+M=imaplib.IMAP4_SSL("mail.teenagemutantninjaturtles.com", 993)
+M.login("mickey@tmnt.com","cowabunga")
+
+rv, data = M.select("INBOX")
+if rv == 'OK':
+ process_mailbox(M)
+M.close()
+M.logout()
diff --git a/awesome/awesome-wm-widgets/fs-widget/README.md b/awesome/awesome-wm-widgets/fs-widget/README.md
new file mode 100644
index 0000000..4657e9e
--- /dev/null
+++ b/awesome/awesome-wm-widgets/fs-widget/README.md
@@ -0,0 +1,29 @@
+# Filesystem Widget
+
+This widget shows file system disk space usage which is based on the `df` output. When clicked another widget appears with more detailed information. By default, it monitors the "/" mount. It can be configured with a list of mounts to monitor though only the first will show in the wibar. To have multiple mounts displayed on the wibar simply define multiple `fs_widgets` with different mounts as arguments.
+
+![](./screenshot.png)
+
+## Customizations
+
+It is possible to customize widget by providing a table with all or some of the following config parameters:
+
+| Name | Default | Description |
+|---|---|---|
+| `mounts` | `{'/'}` | Table with mounts to monitor, check the output from a `df` command for available options (column 'Mounted on') |
+| `timeout` | 60 | How often in seconds the widget refreshes |
+
+## Installation
+
+Clone/download repo and use the widget in **rc.lua**:
+
+```lua
+ local fs_widget = require("awesome-wm-widgets.fs-widget.fs-widget")
+ ...
+ s.mywibox:setup {
+ s.mytasklist, -- Middle widget
+ { -- Right widgets
+ fs_widget(), --default
+ fs_widget({ mounts = { '/', '/mnt/music' } }), -- multiple mounts
+ ...
+```
diff --git a/awesome/awesome-wm-widgets/fs-widget/fs-widget.lua b/awesome/awesome-wm-widgets/fs-widget/fs-widget.lua
new file mode 100644
index 0000000..ca76193
--- /dev/null
+++ b/awesome/awesome-wm-widgets/fs-widget/fs-widget.lua
@@ -0,0 +1,190 @@
+local awful = require("awful")
+local watch = require("awful.widget.watch")
+local wibox = require("wibox")
+local beautiful = require("beautiful")
+local gears = require("gears")
+
+local storage_bar_widget = {}
+
+--- Table with widget configuration, consists of three sections:
+--- - general - general configuration
+--- - widget - configuration of the widget displayed on the wibar
+--- - popup - configuration of the popup
+local config = {}
+
+-- general
+config.mounts = { '/' }
+config.refresh_rate = 60
+
+-- wibar widget
+config.widget_width = 40
+config.widget_bar_color = '#aaaaaa'
+config.widget_onclick_bg = '#ff0000'
+config.widget_border_color = '#535d6c66'
+config.widget_background_color = '#22222233'
+
+-- popup
+config.popup_bg = '#22222233'
+config.popup_border_width = 1
+config.popup_border_color = '#535d6c66'
+config.popup_bar_color = '#aaaaaa'
+config.popup_bar_background_color = '#22222233'
+config.popup_bar_border_color = '#535d6c66'
+
+local function worker(user_args)
+ local args = user_args or {}
+
+ -- Setup config for the widget instance.
+ -- The `_config` table will keep the first existing value after checking
+ -- in this order: user parameter > beautiful > module default.
+ local _config = {}
+ for prop, value in pairs(config) do
+ _config[prop] = args[prop] or beautiful[prop] or value
+ end
+
+ storage_bar_widget = wibox.widget {
+ {
+ id = 'progressbar',
+ color = _config.widget_bar_color,
+ max_value = 100,
+ forced_height = 20,
+ forced_width = _config.widget_width,
+ paddings = 2,
+ margins = 4,
+ border_width = 1,
+ border_radius = 2,
+ border_color = _config.widget_border_color,
+ background_color = _config.widget_background_color,
+ widget = wibox.widget.progressbar
+ },
+ shape = function(cr, width, height)
+ gears.shape.rounded_rect(cr, width, height, 4)
+ end,
+ widget = wibox.container.background,
+ set_value = function(self, new_value)
+ self:get_children_by_id("progressbar")[1].value = new_value
+ end
+ }
+
+ local disk_rows = {
+ { widget = wibox.widget.textbox },
+ spacing = 4,
+ layout = wibox.layout.fixed.vertical,
+ }
+
+ local disk_header = wibox.widget {
+ {
+ markup = 'Mount',
+ forced_width = 150,
+ align = 'left',
+ widget = wibox.widget.textbox,
+ },
+ {
+ markup = 'Used',
+ align = 'left',
+ widget = wibox.widget.textbox,
+ },
+ layout = wibox.layout.ratio.horizontal
+ }
+ disk_header:ajust_ratio(1, 0, 0.3, 0.7)
+
+ local popup = awful.popup {
+ bg = _config.popup_bg,
+ ontop = true,
+ visible = false,
+ shape = gears.shape.rounded_rect,
+ border_width = _config.popup_border_width,
+ border_color = _config.popup_border_color,
+ maximum_width = 400,
+ offset = { y = 5 },
+ widget = {}
+ }
+
+ storage_bar_widget:buttons(
+ awful.util.table.join(
+ awful.button({}, 1, function()
+ if popup.visible then
+ popup.visible = not popup.visible
+ storage_bar_widget:set_bg('#00000000')
+ else
+ storage_bar_widget:set_bg(_config.widget_background_color)
+ popup:move_next_to(mouse.current_widget_geometry)
+ end
+ end)
+ )
+ )
+
+ local disks = {}
+ watch([[bash -c "df | tail -n +2"]], _config.refresh_rate,
+ function(widget, stdout)
+ for line in stdout:gmatch("[^\r\n$]+") do
+ local filesystem, size, used, avail, perc, mount =
+ line:match('([%p%w]+)%s+([%d%w]+)%s+([%d%w]+)%s+([%d%w]+)%s+([%d]+)%%%s+([%p%w]+)')
+
+ disks[mount] = {}
+ disks[mount].filesystem = filesystem
+ disks[mount].size = size
+ disks[mount].used = used
+ disks[mount].avail = avail
+ disks[mount].perc = perc
+ disks[mount].mount = mount
+
+ if disks[mount].mount == _config.mounts[1] then
+ widget:set_value(tonumber(disks[mount].perc))
+ end
+ end
+
+ for k, v in ipairs(_config.mounts) do
+
+ local row = wibox.widget {
+ {
+ text = disks[v].mount,
+ forced_width = 150,
+ widget = wibox.widget.textbox
+ },
+ {
+ color = _config.popup_bar_color,
+ max_value = 100,
+ value = tonumber(disks[v].perc),
+ forced_height = 20,
+ paddings = 1,
+ margins = 4,
+ border_width = 1,
+ border_color = _config.popup_bar_border_color,
+ background_color = _config.popup_bar_background_color,
+ bar_border_width = 1,
+ bar_border_color = _config.popup_bar_border_color,
+ widget = wibox.widget.progressbar,
+ },
+ {
+ text = math.floor(disks[v].used / 1024 / 1024)
+ .. '/'
+ .. math.floor(disks[v].size / 1024 / 1024) .. 'GB('
+ .. math.floor(disks[v].perc) .. '%)',
+ widget = wibox.widget.textbox
+ },
+ layout = wibox.layout.ratio.horizontal
+ }
+ row:ajust_ratio(2, 0.3, 0.3, 0.4)
+
+ disk_rows[k] = row
+ end
+ popup:setup {
+ {
+ disk_header,
+ disk_rows,
+ layout = wibox.layout.fixed.vertical,
+ },
+ margins = 8,
+ widget = wibox.container.margin
+ }
+ end,
+ storage_bar_widget
+ )
+
+ return storage_bar_widget
+end
+
+return setmetatable(storage_bar_widget, { __call = function(_, ...)
+ return worker(...)
+end })
diff --git a/awesome/awesome-wm-widgets/fs-widget/screenshot.png b/awesome/awesome-wm-widgets/fs-widget/screenshot.png
new file mode 100644
index 0000000..41e6ccc
Binary files /dev/null and b/awesome/awesome-wm-widgets/fs-widget/screenshot.png differ
diff --git a/awesome/awesome-wm-widgets/logout-menu-widget/README.md b/awesome/awesome-wm-widgets/logout-menu-widget/README.md
new file mode 100644
index 0000000..6f8ca27
--- /dev/null
+++ b/awesome/awesome-wm-widgets/logout-menu-widget/README.md
@@ -0,0 +1,45 @@
+# Logout Menu Widget
+
+This widget shows a menu with options to log out from the current session, lock, reboot, suspend and power off the computer, similar to [logout-popup-widget](https://github.com/streetturtle/awesome-wm-widgets/tree/master/logout-popup-widget):
+
+![demo](./logout-menu.gif)
+
+## Installation
+
+Clone this repo (if not cloned yet) under **./.config/awesome/**
+
+```bash
+cd ./.config/awesome/
+git clone https://github.com/streetturtle/awesome-wm-widgets
+```
+Then add the widget to the wibar:
+
+```lua
+local logout_menu_widget = require("awesome-wm-widgets.logout-menu-widget.logout-menu")
+
+s.mytasklist, -- Middle widget
+ { -- Right widgets
+ layout = wibox.layout.fixed.horizontal,
+ ...
+ -- default
+ logout_menu_widget(),
+ -- custom
+ logout_menu_widget{
+ font = 'Play 14',
+ onlock = function() awful.spawn.with_shell('i3lock-fancy') end
+ }
+ ...
+```
+
+## Customization
+
+It is possible to customize the widget by providing a table with all or some of the following config parameters:
+
+| Name | Default | Description |
+|---|---|---|
+| `font` | `beautiful.font` | Font of the menu items |
+| `onlogout` | `function() awesome.quit() end` | Function which is called when the logout item is clicked |
+| `onlock` | `function() awful.spawn.with_shell("i3lock") end` | Function which is called when the lock item is clicked |
+| `onreboot` | `function() awful.spawn.with_shell("reboot") end` | Function which is called when the reboot item is clicked |
+| `onsuspend` | `function() awful.spawn.with_shell("systemctl suspend") end` | Function which is called when the suspend item is clicked |
+| `onpoweroff` | `function() awful.spawn.with_shell("shutdown now") end` | Function which is called when the poweroff item is clicked |
diff --git a/awesome/awesome-wm-widgets/logout-menu-widget/icons/lock.svg b/awesome/awesome-wm-widgets/logout-menu-widget/icons/lock.svg
new file mode 100644
index 0000000..3cfa528
--- /dev/null
+++ b/awesome/awesome-wm-widgets/logout-menu-widget/icons/lock.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/awesome/awesome-wm-widgets/logout-menu-widget/icons/log-out.svg b/awesome/awesome-wm-widgets/logout-menu-widget/icons/log-out.svg
new file mode 100644
index 0000000..77afebb
--- /dev/null
+++ b/awesome/awesome-wm-widgets/logout-menu-widget/icons/log-out.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/awesome/awesome-wm-widgets/logout-menu-widget/icons/moon.svg b/awesome/awesome-wm-widgets/logout-menu-widget/icons/moon.svg
new file mode 100644
index 0000000..60e6ce8
--- /dev/null
+++ b/awesome/awesome-wm-widgets/logout-menu-widget/icons/moon.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/awesome/awesome-wm-widgets/logout-menu-widget/icons/power.svg b/awesome/awesome-wm-widgets/logout-menu-widget/icons/power.svg
new file mode 100644
index 0000000..68b1be8
--- /dev/null
+++ b/awesome/awesome-wm-widgets/logout-menu-widget/icons/power.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/awesome/awesome-wm-widgets/logout-menu-widget/icons/power_w.svg b/awesome/awesome-wm-widgets/logout-menu-widget/icons/power_w.svg
new file mode 100644
index 0000000..1f9c4e3
--- /dev/null
+++ b/awesome/awesome-wm-widgets/logout-menu-widget/icons/power_w.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/awesome/awesome-wm-widgets/logout-menu-widget/icons/refresh-cw.svg b/awesome/awesome-wm-widgets/logout-menu-widget/icons/refresh-cw.svg
new file mode 100644
index 0000000..39f52a5
--- /dev/null
+++ b/awesome/awesome-wm-widgets/logout-menu-widget/icons/refresh-cw.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/awesome/awesome-wm-widgets/logout-menu-widget/logout-menu.gif b/awesome/awesome-wm-widgets/logout-menu-widget/logout-menu.gif
new file mode 100644
index 0000000..9f17b51
Binary files /dev/null and b/awesome/awesome-wm-widgets/logout-menu-widget/logout-menu.gif differ
diff --git a/awesome/awesome-wm-widgets/logout-menu-widget/logout-menu.lua b/awesome/awesome-wm-widgets/logout-menu-widget/logout-menu.lua
new file mode 100644
index 0000000..9a634f1
--- /dev/null
+++ b/awesome/awesome-wm-widgets/logout-menu-widget/logout-menu.lua
@@ -0,0 +1,136 @@
+-------------------------------------------------
+-- Logout Menu Widget for Awesome Window Manager
+-- More details could be found here:
+-- https://github.com/streetturtle/awesome-wm-widgets/tree/master/logout-menu-widget
+
+-- @author Pavel Makhov
+-- @copyright 2020 Pavel Makhov
+-------------------------------------------------
+
+local awful = require("awful")
+local wibox = require("wibox")
+local gears = require("gears")
+local beautiful = require("beautiful")
+
+local HOME = os.getenv('HOME')
+local ICON_DIR = HOME .. '/.config/awesome/awesome-wm-widgets/logout-menu-widget/icons/'
+
+local logout_menu_widget = wibox.widget {
+ {
+ {
+ image = ICON_DIR .. 'power_w.svg',
+ resize = true,
+ widget = wibox.widget.imagebox,
+ },
+ margins = 4,
+ layout = wibox.container.margin
+ },
+ shape = function(cr, width, height)
+ gears.shape.rounded_rect(cr, width, height, 4)
+ end,
+ widget = wibox.container.background,
+}
+
+local popup = awful.popup {
+ ontop = true,
+ visible = false,
+ shape = function(cr, width, height)
+ gears.shape.rounded_rect(cr, width, height, 4)
+ end,
+ border_width = 1,
+ border_color = beautiful.bg_focus,
+ maximum_width = 400,
+ offset = { y = 5 },
+ widget = {}
+}
+
+local function worker(user_args)
+ local rows = { layout = wibox.layout.fixed.vertical }
+
+ local args = user_args or {}
+
+ local font = args.font or beautiful.font
+
+ local onlogout = args.onlogout or function () awesome.quit() end
+ local onlock = args.onlock or function() awful.spawn.with_shell("i3lock") end
+ local onreboot = args.onreboot or function() awful.spawn.with_shell("reboot") end
+ local onsuspend = args.onsuspend or function() awful.spawn.with_shell("systemctl suspend") end
+ local onpoweroff = args.onpoweroff or function() awful.spawn.with_shell("shutdown now") end
+
+ local menu_items = {
+ { name = 'Log out', icon_name = 'log-out.svg', command = onlogout },
+ { name = 'Lock', icon_name = 'lock.svg', command = onlock },
+ { name = 'Reboot', icon_name = 'refresh-cw.svg', command = onreboot },
+ { name = 'Suspend', icon_name = 'moon.svg', command = onsuspend },
+ { name = 'Power off', icon_name = 'power.svg', command = onpoweroff },
+ }
+
+ for _, item in ipairs(menu_items) do
+
+ local row = wibox.widget {
+ {
+ {
+ {
+ image = ICON_DIR .. item.icon_name,
+ resize = false,
+ widget = wibox.widget.imagebox
+ },
+ {
+ text = item.name,
+ font = font,
+ widget = wibox.widget.textbox
+ },
+ spacing = 12,
+ layout = wibox.layout.fixed.horizontal
+ },
+ margins = 8,
+ layout = wibox.container.margin
+ },
+ bg = beautiful.bg_normal,
+ widget = wibox.container.background
+ }
+
+ row:connect_signal("mouse::enter", function(c) c:set_bg(beautiful.bg_focus) end)
+ row:connect_signal("mouse::leave", function(c) c:set_bg(beautiful.bg_normal) end)
+
+ local old_cursor, old_wibox
+ row:connect_signal("mouse::enter", function()
+ local wb = mouse.current_wibox
+ old_cursor, old_wibox = wb.cursor, wb
+ wb.cursor = "hand1"
+ end)
+ row:connect_signal("mouse::leave", function()
+ if old_wibox then
+ old_wibox.cursor = old_cursor
+ old_wibox = nil
+ end
+ end)
+
+ row:buttons(awful.util.table.join(awful.button({}, 1, function()
+ popup.visible = not popup.visible
+ item.command()
+ end)))
+
+ table.insert(rows, row)
+ end
+ popup:setup(rows)
+
+ logout_menu_widget:buttons(
+ awful.util.table.join(
+ awful.button({}, 1, function()
+ if popup.visible then
+ popup.visible = not popup.visible
+ logout_menu_widget:set_bg('#00000000')
+ else
+ popup:move_next_to(mouse.current_widget_geometry)
+ logout_menu_widget:set_bg(beautiful.bg_focus)
+ end
+ end)
+ )
+ )
+
+ return logout_menu_widget
+
+end
+
+return worker
diff --git a/awesome/awesome-wm-widgets/logout-popup-widget/README.md b/awesome/awesome-wm-widgets/logout-popup-widget/README.md
new file mode 100644
index 0000000..d95b692
--- /dev/null
+++ b/awesome/awesome-wm-widgets/logout-popup-widget/README.md
@@ -0,0 +1,84 @@
+# Logout Popup Widget
+
+Widget which allows performing lock, reboot, log out, power off and sleep actions. It can be called either by a shortcut, or by clicking on a widget in wibar.
+
+
+
+
+
+When the widget is shown, following shortcuts can be used:
+ - Escape - hide widget
+ - s - shutdown
+ - r - reboot
+ - u - suspend
+ - k - lock
+ - l - log out
+
+# Installation
+
+Clone this (if not cloned yet) and the [awesome-buttons](https://github.com/streetturtle/awesome-buttons) repos under **./.config/awesome/**
+
+```bash
+cd ./.config/awesome/
+git clone https://github.com/streetturtle/awesome-wm-widgets
+git clone https://github.com/streetturtle/awesome-buttons
+```
+Then
+
+- to show by a shortcut - define a shortcut in `globalkeys`:
+
+ ```lua
+ local logout_popup = require("awesome-wm-widgets.logout-popup-widget.logout-popup")
+ ...
+ globalkeys = gears.table.join(
+ ...
+ awful.key({ modkey }, "l", function() logout_popup.launch() end, {description = "Show logout screen", group = "custom"}),
+ ```
+
+- to show by clicking on a widget in wibar - add widget to the wibar:
+
+ ```lua
+ local logout_popup = require("awesome-wm-widgets.logout-popup-widget.logout-popup")
+
+ s.mytasklist, -- Middle widget
+ { -- Right widgets
+ layout = wibox.layout.fixed.horizontal,
+ ...
+ logout_popup.widget{},
+ ...
+ ```
+
+# Customisation
+
+| Name | Default | Description |
+|---|---|---|
+| `icon` | `power.svg` | If used as widget - the path to the widget's icon |
+| `icon_size` | `40` | Size of the icon |
+| `icon_margin` | `16` | Margin around the icon |
+| `bg_color` | `beautiful.bg_normal` | The color the background of the |
+| `accent_color` | `beautiful.bg_focus` | The color of the buttons |
+| `text_color` | `beautiful.fg_normal` | The color of text |
+| `label_color` | `beautiful.fg_normal` | The color of the button's label |
+| `phrases` | `{'Goodbye!'}` | The table with phrase(s) to show, if more than one provided, the phrase is chosen randomly. Leave empty (`{}`) to hide the phrase |
+| `onlogout` | `function() awesome.quit() end` | Function which is called when the logout button is pressed |
+| `onlock` | `function() awful.spawn.with_shell("systemctl suspend") end` | Function which is called when the lock button is pressed |
+| `onreboot` | `function() awful.spawn.with_shell("reboot") end` | Function which is called when the reboot button is pressed |
+| `onsuspend` | `function() awful.spawn.with_shell("systemctl suspend") end` | Function which is called when the suspend button is pressed |
+| `onpoweroff` | `function() awful.spawn.with_shell("shutdown now") end` | Function which is called when the poweroff button is pressed |
+
+Some color themes for inspiration:
+
+![nord](./logout-nord.png)
+![outrun](./logout-outrun.png)
+![dark](./logout-dark.png)
+![dracula](./logout-dracula.png)
+
+```lua
+logout.launch{
+ bg_color = "#261447", accent_color = "#ff4365", text_color = '#f706cf', icon_size = 40, icon_margin = 16, -- outrun
+ -- bg_color = "#0b0c10", accent_color = "#1f2833", text_color = '#66fce1', -- dark
+ -- bg_color = "#3B4252", accent_color = "#88C0D0", text_color = '#D8DEE9', -- nord
+ -- bg_color = "#282a36", accent_color = "#ff79c6", phrases = {}, -- dracula, no phrase
+ phrases = {"exit(0)", "Don't forget to be awesome.", "Yippee ki yay!"},
+}
+```
diff --git a/awesome/awesome-wm-widgets/logout-popup-widget/logout-dark.png b/awesome/awesome-wm-widgets/logout-popup-widget/logout-dark.png
new file mode 100644
index 0000000..06e7c9c
Binary files /dev/null and b/awesome/awesome-wm-widgets/logout-popup-widget/logout-dark.png differ
diff --git a/awesome/awesome-wm-widgets/logout-popup-widget/logout-dracula.png b/awesome/awesome-wm-widgets/logout-popup-widget/logout-dracula.png
new file mode 100644
index 0000000..3c61c46
Binary files /dev/null and b/awesome/awesome-wm-widgets/logout-popup-widget/logout-dracula.png differ
diff --git a/awesome/awesome-wm-widgets/logout-popup-widget/logout-nord.png b/awesome/awesome-wm-widgets/logout-popup-widget/logout-nord.png
new file mode 100644
index 0000000..9ab4b55
Binary files /dev/null and b/awesome/awesome-wm-widgets/logout-popup-widget/logout-nord.png differ
diff --git a/awesome/awesome-wm-widgets/logout-popup-widget/logout-outrun.png b/awesome/awesome-wm-widgets/logout-popup-widget/logout-outrun.png
new file mode 100644
index 0000000..9be68b5
Binary files /dev/null and b/awesome/awesome-wm-widgets/logout-popup-widget/logout-outrun.png differ
diff --git a/awesome/awesome-wm-widgets/logout-popup-widget/logout-popup.lua b/awesome/awesome-wm-widgets/logout-popup-widget/logout-popup.lua
new file mode 100644
index 0000000..efe6882
--- /dev/null
+++ b/awesome/awesome-wm-widgets/logout-popup-widget/logout-popup.lua
@@ -0,0 +1,187 @@
+-------------------------------------------------
+-- Logout widget for Awesome Window Manager
+-- More details could be found here:
+-- https://github.com/streetturtle/awesome-wm-widgets/tree/master/logout-widget
+
+-- @author Pavel Makhov
+-- @copyright 2020 Pavel Makhov
+-------------------------------------------------
+
+local awful = require("awful")
+local capi = {keygrabber = keygrabber }
+local wibox = require("wibox")
+local gears = require("gears")
+local beautiful = require("beautiful")
+local awesomebuttons = require("awesome-buttons.awesome-buttons")
+
+
+local HOME_DIR = os.getenv("HOME")
+local WIDGET_DIR = HOME_DIR .. '/.config/awesome/awesome-wm-widgets/logout-popup-widget'
+
+
+local w = wibox {
+ bg = beautiful.fg_normal,
+ max_widget_size = 500,
+ ontop = true,
+ height = 200,
+ width = 400,
+ shape = function(cr, width, height)
+ gears.shape.rounded_rect(cr, width, height, 8)
+ end
+}
+
+local action = wibox.widget {
+ text = ' ',
+ widget = wibox.widget.textbox
+}
+
+local phrase_widget = wibox.widget{
+ align = 'center',
+ widget = wibox.widget.textbox
+}
+
+local function create_button(icon_name, action_name, accent_color, label_color, onclick, icon_size, icon_margin)
+
+ local button = awesomebuttons.with_icon {
+ type = 'basic',
+ icon = icon_name,
+ color = accent_color,
+ icon_size = icon_size,
+ icon_margin = icon_margin,
+ onclick = function()
+ onclick()
+ w.visible = false
+ capi.keygrabber.stop()
+ end
+ }
+ button:connect_signal("mouse::enter", function()
+ action:set_markup('' .. action_name .. '')
+ end)
+
+ button:connect_signal("mouse::leave", function() action:set_markup('') end)
+
+ return button
+end
+
+local function launch(args)
+ args = args or {}
+
+ local bg_color = args.bg_color or beautiful.bg_normal
+ local accent_color = args.accent_color or beautiful.bg_focus
+ local text_color = args.text_color or beautiful.fg_normal
+ local label_color = args.label_color or beautiful.fg_focus
+ local phrases = args.phrases or {'Goodbye!'}
+ local icon_size = args.icon_size or 40
+ local icon_margin = args.icon_margin or 16
+
+ local onlogout = args.onlogout or function () awesome.quit() end
+ local onlock = args.onlock or function() awful.spawn.with_shell("i3lock") end
+ local onreboot = args.onreboot or function() awful.spawn.with_shell("reboot") end
+ local onsuspend = args.onsuspend or function() awful.spawn.with_shell("systemctl suspend") end
+ local onpoweroff = args.onpoweroff or function() awful.spawn.with_shell("shutdown now") end
+
+ w:set_bg(bg_color)
+ if #phrases > 0 then
+ phrase_widget:set_markup(
+ '' .. phrases[ math.random( #phrases ) ] .. '')
+ end
+
+ w:setup {
+ {
+ phrase_widget,
+ {
+ {
+ create_button('log-out', 'Log Out (l)',
+ accent_color, label_color, onlogout, icon_size, icon_margin),
+ create_button('lock', 'Lock (k)',
+ accent_color, label_color, onlock, icon_size, icon_margin),
+ create_button('refresh-cw', 'Reboot (r)',
+ accent_color, label_color, onreboot, icon_size, icon_margin),
+ create_button('moon', 'Suspend (u)',
+ accent_color, label_color, onsuspend, icon_size, icon_margin),
+ create_button('power', 'Power Off (s)',
+ accent_color, label_color, onpoweroff, icon_size, icon_margin),
+ id = 'buttons',
+ spacing = 8,
+ layout = wibox.layout.fixed.horizontal
+ },
+ valign = 'center',
+ layout = wibox.container.place
+ },
+ {
+ action,
+ haligh = 'center',
+ layout = wibox.container.place
+ },
+ spacing = 32,
+ layout = wibox.layout.fixed.vertical
+ },
+ id = 'a',
+ shape_border_width = 1,
+ valign = 'center',
+ layout = wibox.container.place
+ }
+
+ w.screen = mouse.screen
+ w.visible = true
+
+ awful.placement.centered(w)
+ capi.keygrabber.run(function(_, key, event)
+ if event == "release" then return end
+ if key then
+ if key == 'Escape' then
+ phrase_widget:set_text('')
+ capi.keygrabber.stop()
+ w.visible = false
+ elseif key == 's' then onpoweroff()
+ elseif key == 'r' then onreboot()
+ elseif key == 'u' then onsuspend()
+ elseif key == 'k' then onlock()
+ elseif key == 'l' then onlogout()
+ end
+
+ if key == 'Escape' or string.match("srukl", key) then
+ phrase_widget:set_text('')
+ capi.keygrabber.stop()
+ w.visible = false
+ end
+ end
+ end)
+end
+
+local function widget(args)
+ local icon = args.icon or WIDGET_DIR .. '/power.svg'
+
+ local res = wibox.widget {
+ {
+ {
+ image = icon,
+ widget = wibox.widget.imagebox
+ },
+ margins = 4,
+ layout = wibox.container.margin
+ },
+ layout = wibox.layout.fixed.horizontal,
+ }
+
+ res:buttons(
+ awful.util.table.join(
+ awful.button({}, 1, function()
+ if w.visible then
+ phrase_widget:set_text('')
+ capi.keygrabber.stop()
+ w.visible = false
+ else
+ launch(args)
+ end
+ end)
+ ))
+
+ return res
+
+end
+
+return {
+ launch = launch,
+ widget = widget
+}
diff --git a/awesome/awesome-wm-widgets/logout-popup-widget/power.svg b/awesome/awesome-wm-widgets/logout-popup-widget/power.svg
new file mode 100644
index 0000000..1f9c4e3
--- /dev/null
+++ b/awesome/awesome-wm-widgets/logout-popup-widget/power.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/awesome/awesome-wm-widgets/logout-popup-widget/screenshot.gif b/awesome/awesome-wm-widgets/logout-popup-widget/screenshot.gif
new file mode 100644
index 0000000..4975c19
Binary files /dev/null and b/awesome/awesome-wm-widgets/logout-popup-widget/screenshot.gif differ
diff --git a/awesome/awesome-wm-widgets/logout-popup-widget/screenshot.png b/awesome/awesome-wm-widgets/logout-popup-widget/screenshot.png
new file mode 100644
index 0000000..74ed7f0
Binary files /dev/null and b/awesome/awesome-wm-widgets/logout-popup-widget/screenshot.png differ
diff --git a/awesome/awesome-wm-widgets/mpris-widget/README.md b/awesome/awesome-wm-widgets/mpris-widget/README.md
new file mode 100644
index 0000000..7efad78
--- /dev/null
+++ b/awesome/awesome-wm-widgets/mpris-widget/README.md
@@ -0,0 +1,26 @@
+# MPRIS Widget (In progress)
+
+Music Player Info widget cy @mgabs
+
+# Prerequisite
+
+Install `playerctl` (mpris implementation), should be available in repo, e.g for Ubuntu:
+
+```bash
+sudo apt-get install playerctl
+```
+
+## Installation
+
+To use this widget clone repo under **~/.config/awesome/** and then add it in **rc.lua**:
+
+```lua
+local mpris_widget = require("awesome-wm-widgets.mpris-widget")
+...
+s.mytasklist, -- Middle widget
+ { -- Right widgets
+ layout = wibox.layout.fixed.horizontal,
+ ...
+ mpris_widget(),
+ ...
+```
diff --git a/awesome/awesome-wm-widgets/mpris-widget/init.lua b/awesome/awesome-wm-widgets/mpris-widget/init.lua
new file mode 100644
index 0000000..5e45ffa
--- /dev/null
+++ b/awesome/awesome-wm-widgets/mpris-widget/init.lua
@@ -0,0 +1,187 @@
+-------------------------------------------------
+-- mpris based Arc Widget for Awesome Window Manager
+-- Modelled after Pavel Makhov's work
+-- @author Mohammed Gaber
+-- requires - playerctl
+-- @copyright 2020
+-------------------------------------------------
+local awful = require("awful")
+local beautiful = require("beautiful")
+local watch = require("awful.widget.watch")
+local wibox = require("wibox")
+local gears = require("gears")
+
+local GET_MPD_CMD = "playerctl -p %s -f '{{status}};{{xesam:artist}};{{xesam:title}}' metadata"
+
+local TOGGLE_MPD_CMD = "playerctl play-pause"
+local NEXT_MPD_CMD = "playerctl next"
+local PREV_MPD_CMD = "playerctl previous"
+local LIST_PLAYERS_CMD = "playerctl -l"
+
+local PATH_TO_ICONS = "/usr/share/icons/Arc"
+local PAUSE_ICON_NAME = PATH_TO_ICONS .. "/actions/24/player_pause.png"
+local PLAY_ICON_NAME = PATH_TO_ICONS .. "/actions/24/player_play.png"
+local STOP_ICON_NAME = PATH_TO_ICONS .. "/actions/24/player_stop.png"
+local LIBRARY_ICON_NAME = PATH_TO_ICONS .. "/actions/24/music-library.png"
+
+local default_player = ''
+
+local icon = wibox.widget {
+ id = "icon",
+ widget = wibox.widget.imagebox,
+ image = PLAY_ICON_NAME
+}
+
+local mpris_widget = wibox.widget{
+ {
+ id = 'artist',
+ widget = wibox.widget.textbox
+ },
+ {
+ icon,
+ max_value = 1,
+ value = 0,
+ thickness = 2,
+ start_angle = 4.71238898, -- 2pi*3/4
+ forced_height = 24,
+ forced_width = 24,
+ rounded_edge = true,
+ bg = "#ffffff11",
+ paddings = 0,
+ widget = wibox.container.arcchart
+ },
+ {
+ id = 'title',
+ widget = wibox.widget.textbox
+ },
+ layout = wibox.layout.fixed.horizontal,
+ set_text = function(self, artist, title)
+ self:get_children_by_id('artist')[1]:set_text(artist)
+ self:get_children_by_id('title')[1]:set_text(title)
+ end
+}
+
+local rows = { layout = wibox.layout.fixed.vertical }
+
+local popup = awful.popup{
+ bg = beautiful.bg_normal,
+ ontop = true,
+ visible = false,
+ shape = gears.shape.rounded_rect,
+ border_width = 1,
+ border_color = beautiful.bg_focus,
+ maximum_width = 400,
+ offset = { y = 5 },
+ widget = {}
+}
+
+local function rebuild_popup()
+ awful.spawn.easy_async(LIST_PLAYERS_CMD, function(stdout, _, _, _)
+ for i = 0, #rows do rows[i]=nil end
+ for player_name in stdout:gmatch("[^\r\n]+") do
+ if player_name ~='' and player_name ~=nil then
+
+ local checkbox = wibox.widget{
+ {
+ checked = player_name == default_player,
+ color = beautiful.bg_normal,
+ paddings = 2,
+ shape = gears.shape.circle,
+ forced_width = 20,
+ forced_height = 20,
+ check_color = beautiful.fg_urgent,
+ widget = wibox.widget.checkbox
+ },
+ valign = 'center',
+ layout = wibox.container.place,
+ }
+
+ checkbox:connect_signal("button::press", function()
+ default_player = player_name
+ rebuild_popup()
+ end)
+
+ table.insert(rows, wibox.widget {
+ {
+ {
+ checkbox,
+ {
+ {
+ text = player_name,
+ align = 'left',
+ widget = wibox.widget.textbox
+ },
+ left = 10,
+ layout = wibox.container.margin
+ },
+ spacing = 8,
+ layout = wibox.layout.align.horizontal
+ },
+ margins = 4,
+ layout = wibox.container.margin
+ },
+ bg = beautiful.bg_normal,
+ widget = wibox.container.background
+ })
+ end
+ end
+ end)
+
+ popup:setup(rows)
+end
+
+local function worker()
+
+ -- retrieve song info
+ local current_song, artist, player_status
+
+ local update_graphic = function(widget, stdout, _, _, _)
+ local words = gears.string.split(stdout, ';')
+ player_status = words[1]
+ artist = words[2]
+ current_song = words[3]
+ if current_song ~= nil then
+ if string.len(current_song) > 18 then
+ current_song = string.sub(current_song, 0, 9) .. ".."
+ end
+ end
+
+ if player_status == "Playing" then
+ icon.image = PLAY_ICON_NAME
+ widget.colors = {beautiful.widget_main_color}
+ widget:set_text(artist, current_song)
+ elseif player_status == "Paused" then
+ icon.image = PAUSE_ICON_NAME
+ widget.colors = {beautiful.widget_main_color}
+ widget:set_text(artist, current_song)
+ elseif player_status == "Stopped" then
+ icon.image = STOP_ICON_NAME
+ else -- no player is running
+ icon.image = LIBRARY_ICON_NAME
+ widget.colors = {beautiful.widget_red}
+ end
+ end
+
+ mpris_widget:buttons(
+ awful.util.table.join(
+ awful.button({}, 3, function()
+ if popup.visible then
+ popup.visible = not popup.visible
+ else
+ rebuild_popup()
+ popup:move_next_to(mouse.current_widget_geometry)
+ end
+ end),
+ awful.button({}, 4, function() awful.spawn(NEXT_MPD_CMD, false) end),
+ awful.button({}, 5, function() awful.spawn(PREV_MPD_CMD, false) end),
+ awful.button({}, 1, function() awful.spawn(TOGGLE_MPD_CMD, false) end)
+ )
+ )
+
+ watch(string.format(GET_MPD_CMD, "'" .. default_player .. "'"), 1, update_graphic, mpris_widget)
+
+ return mpris_widget
+
+end
+
+return setmetatable(mpris_widget, {__call = function(_, ...) return worker(...) end})
diff --git a/awesome/awesome-wm-widgets/net-speed-widget/README.md b/awesome/awesome-wm-widgets/net-speed-widget/README.md
new file mode 100644
index 0000000..a09893e
--- /dev/null
+++ b/awesome/awesome-wm-widgets/net-speed-widget/README.md
@@ -0,0 +1,22 @@
+# Net Speed Widget
+
+The widget and readme is in progress
+
+## Installation
+
+Please refer to the [installation](https://github.com/streetturtle/awesome-wm-widgets#installation) section of the repo.
+
+Clone repo, include widget and use it in **rc.lua**:
+
+```lua
+local net_speed_widget = require("awesome-wm-widgets.net-speed-widget.net-speed")
+...
+s.mytasklist, -- Middle widget
+ { -- Right widgets
+ layout = wibox.layout.fixed.horizontal,
+ ...
+ net_speed_widget(),
+ ...
+ }
+ ...
+```
diff --git a/awesome/awesome-wm-widgets/net-speed-widget/icons/down.svg b/awesome/awesome-wm-widgets/net-speed-widget/icons/down.svg
new file mode 100644
index 0000000..9a98f39
--- /dev/null
+++ b/awesome/awesome-wm-widgets/net-speed-widget/icons/down.svg
@@ -0,0 +1,10 @@
+
diff --git a/awesome/awesome-wm-widgets/net-speed-widget/icons/up.svg b/awesome/awesome-wm-widgets/net-speed-widget/icons/up.svg
new file mode 100644
index 0000000..e3c12a7
--- /dev/null
+++ b/awesome/awesome-wm-widgets/net-speed-widget/icons/up.svg
@@ -0,0 +1,10 @@
+
diff --git a/awesome/awesome-wm-widgets/net-speed-widget/net-speed.lua b/awesome/awesome-wm-widgets/net-speed-widget/net-speed.lua
new file mode 100644
index 0000000..6dd3b05
--- /dev/null
+++ b/awesome/awesome-wm-widgets/net-speed-widget/net-speed.lua
@@ -0,0 +1,126 @@
+-------------------------------------------------
+-- Net Speed Widget for Awesome Window Manager
+-- Shows current upload/download speed
+-- More details could be found here:
+-- https://github.com/streetturtle/awesome-wm-widgets/tree/master/net-speed-widget
+
+-- @author Pavel Makhov
+-- @copyright 2020 Pavel Makhov
+-------------------------------------------------
+
+local watch = require("awful.widget.watch")
+local wibox = require("wibox")
+
+local HOME_DIR = os.getenv("HOME")
+local WIDGET_DIR = HOME_DIR .. '/.config/awesome/awesome-wm-widgets/net-speed-widget/'
+local ICONS_DIR = WIDGET_DIR .. 'icons/'
+
+local net_speed_widget = {}
+
+local function convert_to_h(bytes)
+ local speed
+ local dim
+ local bits = bytes * 8
+ if bits < 1000 then
+ speed = bits
+ dim = 'b/s'
+ elseif bits < 1000000 then
+ speed = bits/1000
+ dim = 'kb/s'
+ elseif bits < 1000000000 then
+ speed = bits/1000000
+ dim = 'mb/s'
+ elseif bits < 1000000000000 then
+ speed = bits/1000000000
+ dim = 'gb/s'
+ else
+ speed = tonumber(bits)
+ dim = 'b/s'
+ end
+ return math.floor(speed + 0.5) .. dim
+end
+
+local function split(string_to_split, separator)
+ if separator == nil then separator = "%s" end
+ local t = {}
+
+ for str in string.gmatch(string_to_split, "([^".. separator .."]+)") do
+ table.insert(t, str)
+ end
+
+ return t
+end
+
+local function worker(user_args)
+
+ local args = user_args or {}
+
+ local interface = args.interface or '*'
+ local timeout = args.timeout or 1
+ local width = args.width or 55
+
+ net_speed_widget = wibox.widget {
+ {
+ id = 'rx_speed',
+ forced_width = width,
+ align = 'right',
+ widget = wibox.widget.textbox
+ },
+ {
+ image = ICONS_DIR .. 'down.svg',
+ widget = wibox.widget.imagebox
+ },
+ {
+ image = ICONS_DIR .. 'up.svg',
+ widget = wibox.widget.imagebox
+ },
+ {
+ id = 'tx_speed',
+ forced_width = width,
+ align = 'left',
+ widget = wibox.widget.textbox
+ },
+ layout = wibox.layout.fixed.horizontal,
+ set_rx_text = function(self, new_rx_speed)
+ self:get_children_by_id('rx_speed')[1]:set_text(tostring(new_rx_speed))
+ end,
+ set_tx_text = function(self, new_tx_speed)
+ self:get_children_by_id('tx_speed')[1]:set_text(tostring(new_tx_speed))
+ end
+ }
+
+ -- make sure these are not shared across different worker/widgets (e.g. two monitors)
+ -- otherwise the speed will be randomly split among the worker in each monitor
+ local prev_rx = 0
+ local prev_tx = 0
+
+ local update_widget = function(widget, stdout)
+
+ local cur_vals = split(stdout, '\r\n')
+
+ local cur_rx = 0
+ local cur_tx = 0
+
+ for i, v in ipairs(cur_vals) do
+ if i%2 == 1 then cur_rx = cur_rx + v end
+ if i%2 == 0 then cur_tx = cur_tx + v end
+ end
+
+ local speed_rx = (cur_rx - prev_rx) / timeout
+ local speed_tx = (cur_tx - prev_tx) / timeout
+
+ widget:set_rx_text(convert_to_h(speed_rx))
+ widget:set_tx_text(convert_to_h(speed_tx))
+
+ prev_rx = cur_rx
+ prev_tx = cur_tx
+ end
+
+ watch(string.format([[bash -c "cat /sys/class/net/%s/statistics/*_bytes"]], interface),
+ timeout, update_widget, net_speed_widget)
+
+ return net_speed_widget
+
+end
+
+return setmetatable(net_speed_widget, { __call = function(_, ...) return worker(...) end })
diff --git a/awesome/awesome-wm-widgets/pactl-widget/README.md b/awesome/awesome-wm-widgets/pactl-widget/README.md
new file mode 100644
index 0000000..ad6639b
--- /dev/null
+++ b/awesome/awesome-wm-widgets/pactl-widget/README.md
@@ -0,0 +1,55 @@
+# Pactl volume widget
+
+This is a volume widget that uses `pactl` only for controlling volume and
+selecting sinks and sources. Hence, it can be used with PulseAudio or PipeWire
+likewise, unlike the original Volume widget.
+
+Other than that it is heavily based on the original widget, including its
+customization and icon options. For screenshots, see the original widget.
+
+## Installation
+
+Clone the repo under **~/.config/awesome/** and add widget in **rc.lua**:
+
+```lua
+local volume_widget = require('awesome-wm-widgets.pactl-widget.volume')
+...
+s.mytasklist, -- Middle widget
+ { -- Right widgets
+ layout = wibox.layout.fixed.horizontal,
+ ...
+ -- default
+ volume_widget(),
+ -- customized
+ volume_widget{
+ widget_type = 'arc'
+ },
+```
+
+### Shortcuts
+
+To improve responsiveness of the widget when volume level is changed by a shortcut use corresponding methods of the widget:
+
+```lua
+awful.key({}, "XF86AudioRaiseVolume", function () volume_widget:inc(5) end),
+awful.key({}, "XF86AudioLowerVolume", function () volume_widget:dec(5) end),
+awful.key({}, "XF86AudioMute", function () volume_widget:toggle() end),
+```
+
+## Customization
+
+It is possible to customize the widget by providing a table with all or some of
+the following config parameters:
+
+### Generic parameter
+
+| Name | Default | Description |
+|---|---|---|
+| `mixer_cmd` | `pavucontrol` | command to run on middle click (e.g. a mixer program) |
+| `step` | `5` | How much the volume is raised or lowered at once (in %) |
+| `widget_type`| `icon_and_text`| Widget type, one of `horizontal_bar`, `vertical_bar`, `icon`, `icon_and_text`, `arc` |
+| `device` | `@DEFAULT_SINK@` | Select the device name to control |
+| `tooltip` | `false` | Display volume level in a tooltip when the mouse cursor hovers the widget |
+
+For more details on parameters depending on the chosen widget type, please
+refer to the original Volume widget.
diff --git a/awesome/awesome-wm-widgets/pactl-widget/pactl.lua b/awesome/awesome-wm-widgets/pactl-widget/pactl.lua
new file mode 100644
index 0000000..638dc7e
--- /dev/null
+++ b/awesome/awesome-wm-widgets/pactl-widget/pactl.lua
@@ -0,0 +1,124 @@
+local spawn = require("awful.spawn")
+local utils = require("awesome-wm-widgets.pactl-widget.utils")
+
+local pactl = {}
+
+
+function pactl.volume_increase(device, step)
+ spawn('pactl set-sink-volume ' .. device .. ' +' .. step .. '%', false)
+end
+
+function pactl.volume_decrease(device, step)
+ spawn('pactl set-sink-volume ' .. device .. ' -' .. step .. '%', false)
+end
+
+function pactl.mute_toggle(device)
+ spawn('pactl set-sink-mute ' .. device .. ' toggle', false)
+end
+
+function pactl.get_volume(device)
+ local stdout = utils.popen_and_return('pactl get-sink-volume ' .. device)
+
+ local volsum, volcnt = 0, 0
+ for vol in string.gmatch(stdout, "(%d?%d?%d)%%") do
+ vol = tonumber(vol)
+ if vol ~= nil then
+ volsum = volsum + vol
+ volcnt = volcnt + 1
+ end
+ end
+
+ if volcnt == 0 then
+ return nil
+ end
+
+ return volsum / volcnt
+end
+
+function pactl.get_mute(device)
+ local stdout = utils.popen_and_return('pactl get-sink-mute ' .. device)
+ if string.find(stdout, "yes") then
+ return true
+ else
+ return false
+ end
+end
+
+function pactl.get_sinks_and_sources()
+ local default_sink = utils.trim(utils.popen_and_return('pactl get-default-sink'))
+ local default_source = utils.trim(utils.popen_and_return('pactl get-default-source'))
+
+ local sinks = {}
+ local sources = {}
+
+ local device
+ local ports
+ local key
+ local value
+ local in_section
+
+ for line in utils.popen_and_return('pactl list'):gmatch('[^\r\n]*') do
+
+ if string.match(line, '^%a+ #') then
+ in_section = nil
+ end
+
+ local is_sink_line = string.match(line, '^Sink #')
+ local is_source_line = string.match(line, '^Source #')
+
+ if is_sink_line or is_source_line then
+ in_section = "main"
+
+ device = {
+ id = line:match('#(%d+)'),
+ is_default = false
+ }
+ if is_sink_line then
+ table.insert(sinks, device)
+ else
+ table.insert(sources, device)
+ end
+ end
+
+ -- Found a new subsection
+ if in_section ~= nil and string.match(line, '^\t%a+:$') then
+ in_section = utils.trim(line):lower()
+ in_section = string.sub(in_section, 1, #in_section-1)
+
+ if in_section == 'ports' then
+ ports = {}
+ device['ports'] = ports
+ end
+ end
+
+ -- Found a key-value pair
+ if string.match(line, "^\t*[^\t]+: ") then
+ local t = utils.split(line, ':')
+ key = utils.trim(t[1]):lower():gsub(' ', '_')
+ value = utils.trim(t[2])
+ end
+
+ -- Key value pair on 1st level
+ if in_section ~= nil and string.match(line, "^\t[^\t]+: ") then
+ device[key] = value
+
+ if key == "name" and (value == default_sink or value == default_source) then
+ device['is_default'] = true
+ end
+ end
+
+ -- Key value pair in ports section
+ if in_section == "ports" and string.match(line, "^\t\t[^\t]+: ") then
+ ports[key] = value
+ end
+ end
+
+ return sinks, sources
+end
+
+function pactl.set_default(type, name)
+ spawn('pactl set-default-' .. type .. ' "' .. name .. '"', false)
+end
+
+
+return pactl
diff --git a/awesome/awesome-wm-widgets/pactl-widget/utils.lua b/awesome/awesome-wm-widgets/pactl-widget/utils.lua
new file mode 100644
index 0000000..52e7869
--- /dev/null
+++ b/awesome/awesome-wm-widgets/pactl-widget/utils.lua
@@ -0,0 +1,28 @@
+local utils = {}
+
+
+function utils.trim(str)
+ return string.match(str, "^%s*(.-)%s*$")
+end
+
+function utils.split(string_to_split, separator)
+ if separator == nil then separator = "%s" end
+ local t = {}
+
+ for str in string.gmatch(string_to_split, "([^".. separator .."]+)") do
+ table.insert(t, str)
+ end
+
+ return t
+end
+
+function utils.popen_and_return(cmd)
+ local handle = io.popen(cmd)
+ local result = handle:read("*a")
+ handle:close()
+
+ return result
+end
+
+
+return utils
diff --git a/awesome/awesome-wm-widgets/pactl-widget/volume.lua b/awesome/awesome-wm-widgets/pactl-widget/volume.lua
new file mode 100644
index 0000000..1c3108c
--- /dev/null
+++ b/awesome/awesome-wm-widgets/pactl-widget/volume.lua
@@ -0,0 +1,243 @@
+-------------------------------------------------
+-- A purely pactl-based volume widget based on the original Volume widget
+-- More details could be found here:
+-- https://github.com/streetturtle/awesome-wm-widgets/tree/master/pactl-widget
+
+-- @author Stefan Huber
+-- @copyright 2023 Stefan Huber
+-------------------------------------------------
+
+local awful = require("awful")
+local wibox = require("wibox")
+local spawn = require("awful.spawn")
+local gears = require("gears")
+local beautiful = require("beautiful")
+
+local pactl = require("awesome-wm-widgets.pactl-widget.pactl")
+local utils = require("awesome-wm-widgets.pactl-widget.utils")
+
+
+local widget_types = {
+ icon_and_text = require("awesome-wm-widgets.volume-widget.widgets.icon-and-text-widget"),
+ icon = require("awesome-wm-widgets.volume-widget.widgets.icon-widget"),
+ arc = require("awesome-wm-widgets.volume-widget.widgets.arc-widget"),
+ horizontal_bar = require("awesome-wm-widgets.volume-widget.widgets.horizontal-bar-widget"),
+ vertical_bar = require("awesome-wm-widgets.volume-widget.widgets.vertical-bar-widget")
+}
+local volume = {}
+
+local rows = { layout = wibox.layout.fixed.vertical }
+
+local popup = awful.popup{
+ bg = beautiful.bg_normal,
+ ontop = true,
+ visible = false,
+ shape = gears.shape.rounded_rect,
+ border_width = 1,
+ border_color = beautiful.bg_focus,
+ maximum_width = 400,
+ offset = { y = 5 },
+ widget = {}
+}
+
+local function build_main_line(device)
+ if device.active_port ~= nil and device.ports[device.active_port] ~= nil then
+ return device.description .. ' · ' .. utils.split(device.ports[device.active_port], " ")[1]
+ else
+ return device.description
+ end
+end
+
+local function build_rows(devices, on_checkbox_click, device_type)
+ local device_rows = { layout = wibox.layout.fixed.vertical }
+ for _, device in pairs(devices) do
+
+ local checkbox = wibox.widget {
+ checked = device.is_default,
+ color = beautiful.bg_normal,
+ paddings = 2,
+ shape = gears.shape.circle,
+ forced_width = 20,
+ forced_height = 20,
+ check_color = beautiful.fg_urgent,
+ widget = wibox.widget.checkbox
+ }
+
+ checkbox:connect_signal("button::press", function()
+ pactl.set_default(device_type, device.name)
+ on_checkbox_click()
+ end)
+
+ local row = wibox.widget {
+ {
+ {
+ {
+ checkbox,
+ valign = 'center',
+ layout = wibox.container.place,
+ },
+ {
+ {
+ text = build_main_line(device),
+ align = 'left',
+ widget = wibox.widget.textbox
+ },
+ left = 10,
+ layout = wibox.container.margin
+ },
+ spacing = 8,
+ layout = wibox.layout.align.horizontal
+ },
+ margins = 4,
+ layout = wibox.container.margin
+ },
+ bg = beautiful.bg_normal,
+ widget = wibox.container.background
+ }
+
+ row:connect_signal("mouse::enter", function(c) c:set_bg(beautiful.bg_focus) end)
+ row:connect_signal("mouse::leave", function(c) c:set_bg(beautiful.bg_normal) end)
+
+ local old_cursor, old_wibox
+ row:connect_signal("mouse::enter", function()
+ local wb = mouse.current_wibox
+ old_cursor, old_wibox = wb.cursor, wb
+ wb.cursor = "hand1"
+ end)
+ row:connect_signal("mouse::leave", function()
+ if old_wibox then
+ old_wibox.cursor = old_cursor
+ old_wibox = nil
+ end
+ end)
+
+ row:connect_signal("button::press", function()
+ pactl.set_default(device_type, device.name)
+ on_checkbox_click()
+ end)
+
+ table.insert(device_rows, row)
+ end
+
+ return device_rows
+end
+
+local function build_header_row(text)
+ return wibox.widget{
+ {
+ markup = "" .. text .. "",
+ align = 'center',
+ widget = wibox.widget.textbox
+ },
+ bg = beautiful.bg_normal,
+ widget = wibox.container.background
+ }
+end
+
+local function rebuild_popup()
+ for i = 0, #rows do
+ rows[i]=nil
+ end
+
+ local sinks, sources = pactl.get_sinks_and_sources()
+ table.insert(rows, build_header_row("SINKS"))
+ table.insert(rows, build_rows(sinks, function() rebuild_popup() end, "sink"))
+ table.insert(rows, build_header_row("SOURCES"))
+ table.insert(rows, build_rows(sources, function() rebuild_popup() end, "source"))
+
+ popup:setup(rows)
+end
+
+local function worker(user_args)
+
+ local args = user_args or {}
+
+ local mixer_cmd = args.mixer_cmd or 'pavucontrol'
+ local widget_type = args.widget_type
+ local refresh_rate = args.refresh_rate or 1
+ local step = args.step or 5
+ local device = args.device or '@DEFAULT_SINK@'
+ local tooltip = args.tooltip or false
+
+ if widget_types[widget_type] == nil then
+ volume.widget = widget_types['icon_and_text'].get_widget(args.icon_and_text_args)
+ else
+ volume.widget = widget_types[widget_type].get_widget(args)
+ end
+
+ local function update_graphic(widget)
+ local vol = pactl.get_volume(device)
+ if vol ~= nil then
+ widget:set_volume_level(vol)
+ end
+
+ if pactl.get_mute(device) then
+ widget:mute()
+ else
+ widget:unmute()
+ end
+ end
+
+ function volume:inc(s)
+ pactl.volume_increase(device, s or step)
+ update_graphic(volume.widget)
+ end
+
+ function volume:dec(s)
+ pactl.volume_decrease(device, s or step)
+ update_graphic(volume.widget)
+ end
+
+ function volume:toggle()
+ pactl.mute_toggle(device)
+ update_graphic(volume.widget)
+ end
+
+ function volume:popup()
+ if popup.visible then
+ popup.visible = not popup.visible
+ else
+ rebuild_popup()
+ popup:move_next_to(mouse.current_widget_geometry)
+ end
+ end
+
+ function volume:mixer()
+ if mixer_cmd then
+ spawn(mixer_cmd)
+ end
+ end
+
+ volume.widget:buttons(
+ awful.util.table.join(
+ awful.button({}, 1, function() volume:toggle() end),
+ awful.button({}, 2, function() volume:mixer() end),
+ awful.button({}, 3, function() volume:popup() end),
+ awful.button({}, 4, function() volume:inc() end),
+ awful.button({}, 5, function() volume:dec() end)
+ )
+ )
+
+ gears.timer {
+ timeout = refresh_rate,
+ call_now = true,
+ autostart = true,
+ callback = function()
+ update_graphic(volume.widget)
+ end
+ }
+
+ if tooltip then
+ awful.tooltip {
+ objects = { volume.widget },
+ timer_function = function()
+ return pactl.get_volume(device) .. " %"
+ end,
+ }
+ end
+
+ return volume.widget
+end
+
+
+return setmetatable(volume, { __call = function(_, ...) return worker(...) end })
diff --git a/awesome/awesome-wm-widgets/ram-widget/README.md b/awesome/awesome-wm-widgets/ram-widget/README.md
new file mode 100644
index 0000000..568245b
--- /dev/null
+++ b/awesome/awesome-wm-widgets/ram-widget/README.md
@@ -0,0 +1,41 @@
+# Ram widget
+
+This widget shows the RAM usage. When clicked another widget appears with more detailed information:
+
+![screenshot](./out.gif)
+
+Note: this widget is compatible with Awesome v4.3+, as it is using [awful.popup](https://awesomewm.org/doc/api/classes/awful.popup.html)
+
+## Customization
+
+It is possible to customize widget by providing a table with all or some of the following config parameters:
+
+| Name | Default | Description |
+|---|---|---|
+| `color_used` | `beautiful.bg_urgent` | Color for used RAM |
+| `color_free` | `beautiful.fg_normal` | Color for free RAM |
+| `color_buf` | `beautiful.border_color_active` | Color for buffers/cache |
+| `widget_height` | `25` | Height of the widget |
+| `widget_width` | `25` | Width of the widget |
+| `widget_show_buf` | `false` | Whether to display buffers/cache separately in the tray widget. If `false`, buffers/cache are considered free RAM. |
+| `timeout` | 1 | How often (in seconds) the widget refreshes |
+
+## Installation
+
+Please refer to the [installation](https://github.com/streetturtle/awesome-wm-widgets#installation) section of the repo.
+
+Clone repo, include widget and use it in **rc.lua**:
+
+```lua
+local ram_widget = require("awesome-wm-widgets.ram-widget.ram-widget")
+...
+s.mytasklist, -- Middle widget
+ { -- Right widgets
+ layout = wibox.layout.fixed.horizontal,
+ ...
+ ram_widget(),
+ ...
+ }
+ ...
+```
+
diff --git a/awesome/awesome-wm-widgets/ram-widget/out.gif b/awesome/awesome-wm-widgets/ram-widget/out.gif
new file mode 100644
index 0000000..736f894
Binary files /dev/null and b/awesome/awesome-wm-widgets/ram-widget/out.gif differ
diff --git a/awesome/awesome-wm-widgets/ram-widget/ram-widget.lua b/awesome/awesome-wm-widgets/ram-widget/ram-widget.lua
new file mode 100644
index 0000000..867d28e
--- /dev/null
+++ b/awesome/awesome-wm-widgets/ram-widget/ram-widget.lua
@@ -0,0 +1,108 @@
+local awful = require("awful")
+local beautiful = require("beautiful")
+local gears = require("gears")
+local watch = require("awful.widget.watch")
+local wibox = require("wibox")
+
+
+local ramgraph_widget = {}
+
+
+local function worker(user_args)
+ local args = user_args or {}
+ local timeout = args.timeout or 1
+ local color_used = args.color_used or beautiful.bg_urgent
+ local color_free = args.color_free or beautiful.fg_normal
+ local color_buf = args.color_buf or beautiful.border_color_active
+ local widget_show_buf = args.widget_show_buf or false
+ local widget_height = args.widget_height or 25
+ local widget_width = args.widget_width or 25
+
+ --- Main ram widget shown on wibar
+ ramgraph_widget = wibox.widget {
+ border_width = 0,
+ colors = {
+ color_used,
+ color_free,
+ color_buf,
+ },
+ display_labels = false,
+ forced_height = widget_height,
+ forced_width = widget_width,
+ widget = wibox.widget.piechart
+ }
+
+ --- Widget which is shown when user clicks on the ram widget
+ local popup = awful.popup{
+ ontop = true,
+ visible = false,
+ widget = {
+ widget = wibox.widget.piechart,
+ forced_height = 200,
+ forced_width = 400,
+ colors = {
+ color_used,
+ color_free,
+ color_buf, -- buf_cache
+ },
+ },
+ shape = gears.shape.rounded_rect,
+ border_color = beautiful.border_color_active,
+ border_width = 1,
+ offset = { y = 5 },
+ }
+
+ --luacheck:ignore 231
+ local total, used, free, shared, buff_cache, available, total_swap, used_swap, free_swap
+
+ local function getPercentage(value)
+ return math.floor(value / (total+total_swap) * 100 + 0.5) .. '%'
+ end
+
+ watch('bash -c "LANGUAGE=en_US.UTF-8 free | grep -z Mem.*Swap.*"', timeout,
+ function(widget, stdout)
+ total, used, free, shared, buff_cache, available, total_swap, used_swap, free_swap =
+ stdout:match('(%d+)%s*(%d+)%s*(%d+)%s*(%d+)%s*(%d+)%s*(%d+)%s*Swap:%s*(%d+)%s*(%d+)%s*(%d+)')
+
+ if widget_show_buf then
+ widget.data = { used, free, buff_cache }
+ else
+ widget.data = { used, total-used }
+ end
+
+ if popup.visible then
+ popup:get_widget().data_list = {
+ {'used ' .. getPercentage(used + used_swap), used + used_swap},
+ {'free ' .. getPercentage(free + free_swap), free + free_swap},
+ {'buff_cache ' .. getPercentage(buff_cache), buff_cache}
+ }
+ end
+ end,
+ ramgraph_widget
+ )
+
+ ramgraph_widget:buttons(
+ awful.util.table.join(
+ awful.button({}, 1, function()
+ popup:get_widget().data_list = {
+ {'used ' .. getPercentage(used + used_swap), used + used_swap},
+ {'free ' .. getPercentage(free + free_swap), free + free_swap},
+ {'buff_cache ' .. getPercentage(buff_cache), buff_cache}
+ }
+
+ if popup.visible then
+ popup.visible = not popup.visible
+ else
+ popup:move_next_to(mouse.current_widget_geometry)
+ end
+ end)
+ )
+ )
+
+ return ramgraph_widget
+end
+
+
+return setmetatable(ramgraph_widget, { __call = function(_, ...)
+ return worker(...)
+end })
diff --git a/awesome/awesome-wm-widgets/todo-widget/README.md b/awesome/awesome-wm-widgets/todo-widget/README.md
new file mode 100644
index 0000000..c97d845
--- /dev/null
+++ b/awesome/awesome-wm-widgets/todo-widget/README.md
@@ -0,0 +1,28 @@
+# ToDo Widget
+
+This widget displays a list of todo items and allows marking item as done/undone, delete an item and create new ones:
+
+![screenshot](./todo.gif)
+
+# Installation
+
+Widget persists todo items as a JSON, so in order to simplify JSON serialisation/deserialisation download a **json.lua** from this repository: https://github.com/rxi/json.lua under `~/.config/awesone` folder. And don't forget to star a repo :)
+
+Then clone this repository under **~/.config/awesome/** and add the widget in **rc.lua**:
+
+```lua
+local todo_widget = require("awesome-wm-widgets.todo-widget.todo")
+...
+s.mytasklist, -- Middle widget
+ { -- Right widgets
+ layout = wibox.layout.fixed.horizontal,
+ ...
+ -- default
+ todo_widget(),
+ ...
+```
+Also note that widget uses [Arc Icons](https://github.com/horst3180/arc-icon-theme) and expects them to be installed under `/usr/share/icons/Arc/`.
+
+# Theming
+
+Widget uses your theme's colors. In case you want to have different colors, without changing your theme, please create an issue for it. I'll extract them as widget parameters.
diff --git a/awesome/awesome-wm-widgets/todo-widget/checkbox-checked-symbolic.svg b/awesome/awesome-wm-widgets/todo-widget/checkbox-checked-symbolic.svg
new file mode 100644
index 0000000..afeca62
--- /dev/null
+++ b/awesome/awesome-wm-widgets/todo-widget/checkbox-checked-symbolic.svg
@@ -0,0 +1,148 @@
+
+
+
+
diff --git a/awesome/awesome-wm-widgets/todo-widget/chevron-down.svg b/awesome/awesome-wm-widgets/todo-widget/chevron-down.svg
new file mode 100644
index 0000000..dceeb0f
--- /dev/null
+++ b/awesome/awesome-wm-widgets/todo-widget/chevron-down.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/awesome/awesome-wm-widgets/todo-widget/chevron-up.svg b/awesome/awesome-wm-widgets/todo-widget/chevron-up.svg
new file mode 100644
index 0000000..88474ce
--- /dev/null
+++ b/awesome/awesome-wm-widgets/todo-widget/chevron-up.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/awesome/awesome-wm-widgets/todo-widget/list-add-symbolic.svg b/awesome/awesome-wm-widgets/todo-widget/list-add-symbolic.svg
new file mode 100644
index 0000000..9cc2d3a
--- /dev/null
+++ b/awesome/awesome-wm-widgets/todo-widget/list-add-symbolic.svg
@@ -0,0 +1,157 @@
+
+
+
+
diff --git a/awesome/awesome-wm-widgets/todo-widget/todo.gif b/awesome/awesome-wm-widgets/todo-widget/todo.gif
new file mode 100644
index 0000000..7160e21
Binary files /dev/null and b/awesome/awesome-wm-widgets/todo-widget/todo.gif differ
diff --git a/awesome/awesome-wm-widgets/todo-widget/todo.lua b/awesome/awesome-wm-widgets/todo-widget/todo.lua
new file mode 100644
index 0000000..78ca262
--- /dev/null
+++ b/awesome/awesome-wm-widgets/todo-widget/todo.lua
@@ -0,0 +1,340 @@
+-------------------------------------------------
+-- ToDo Widget for Awesome Window Manager
+-- More details could be found here:
+-- https://github.com/streetturtle/awesome-wm-widgets/tree/master/todo-widget
+
+-- @author Pavel Makhov
+-- @copyright 2020 Pavel Makhov
+-------------------------------------------------
+
+local awful = require("awful")
+local wibox = require("wibox")
+local json = require("json")
+local spawn = require("awful.spawn")
+local gears = require("gears")
+local beautiful = require("beautiful")
+local gfs = require("gears.filesystem")
+
+local HOME_DIR = os.getenv("HOME")
+local WIDGET_DIR = HOME_DIR .. '/.config/awesome/awesome-wm-widgets/todo-widget'
+local STORAGE = HOME_DIR .. '/.cache/awmw/todo-widget/todos.json'
+
+local GET_TODO_ITEMS = 'bash -c "cat ' .. STORAGE .. '"'
+
+local rows = { layout = wibox.layout.fixed.vertical }
+local todo_widget = {}
+local update_widget
+todo_widget.widget = wibox.widget {
+ {
+ {
+ {
+ {
+ id = "icon",
+ forced_height = 16,
+ forced_width = 16,
+ widget = wibox.widget.imagebox
+ },
+ valign = 'center',
+ layout = wibox.container.place
+ },
+ {
+ id = "txt",
+ widget = wibox.widget.textbox
+ },
+ spacing = 4,
+ layout = wibox.layout.fixed.horizontal,
+ },
+ margins = 4,
+ layout = wibox.container.margin
+ },
+ shape = function(cr, width, height)
+ gears.shape.rounded_rect(cr, width, height, 4)
+ end,
+ widget = wibox.container.background,
+ set_text = function(self, new_value)
+ self:get_children_by_id("txt")[1].text = new_value
+ end,
+ set_icon = function(self, new_value)
+ self:get_children_by_id("icon")[1].image = new_value
+ end
+}
+
+function todo_widget:update_counter(todos)
+ local todo_count = 0
+ for _,p in ipairs(todos) do
+ if not p.status then
+ todo_count = todo_count + 1
+ end
+ end
+
+ todo_widget.widget:set_text(todo_count)
+end
+
+local popup = awful.popup{
+ bg = beautiful.bg_normal,
+ ontop = true,
+ visible = false,
+ shape = gears.shape.rounded_rect,
+ border_width = 1,
+ border_color = beautiful.bg_focus,
+ maximum_width = 400,
+ offset = { y = 5 },
+ widget = {}
+}
+
+local add_button = wibox.widget {
+ {
+ {
+ image = WIDGET_DIR .. '/list-add-symbolic.svg',
+ resize = false,
+ widget = wibox.widget.imagebox
+ },
+ top = 11,
+ left = 8,
+ right = 8,
+ layout = wibox.container.margin
+ },
+ shape = function(cr, width, height)
+ gears.shape.circle(cr, width, height, 12)
+ end,
+ widget = wibox.container.background
+}
+
+add_button:connect_signal("button::press", function()
+ local pr = awful.widget.prompt()
+
+ table.insert(rows, wibox.widget {
+ {
+ {
+ pr.widget,
+ spacing = 8,
+ layout = wibox.layout.align.horizontal
+ },
+ margins = 8,
+ layout = wibox.container.margin
+ },
+ bg = beautiful.bg_normal,
+ widget = wibox.container.background
+ })
+ awful.prompt.run{
+ prompt = "New item: ",
+ bg = beautiful.bg_normal,
+ bg_cursor = beautiful.fg_urgent,
+ textbox = pr.widget,
+ exe_callback = function(input_text)
+ if not input_text or #input_text == 0 then return end
+ spawn.easy_async(GET_TODO_ITEMS, function(stdout)
+ local res = json.decode(stdout)
+ table.insert(res.todo_items, {todo_item = input_text, status = false})
+ spawn.easy_async_with_shell("echo '" .. json.encode(res) .. "' > " .. STORAGE, function()
+ spawn.easy_async(GET_TODO_ITEMS, function(items) update_widget(items) end)
+ end)
+ end)
+ end
+ }
+ popup:setup(rows)
+end)
+add_button:connect_signal("mouse::enter", function(c) c:set_bg(beautiful.bg_focus) end)
+add_button:connect_signal("mouse::leave", function(c) c:set_bg(beautiful.bg_normal) end)
+
+local function worker(user_args)
+
+ local args = user_args or {}
+
+ local icon = args.icon or WIDGET_DIR .. '/checkbox-checked-symbolic.svg'
+
+ todo_widget.widget:set_icon(icon)
+
+ function update_widget(stdout)
+ local result = json.decode(stdout)
+ if result == nil or result == '' then result = {} end
+ todo_widget:update_counter(result.todo_items)
+
+ for i = 0, #rows do rows[i]=nil end
+
+ local first_row = wibox.widget {
+ {
+ {widget = wibox.widget.textbox},
+ {
+ markup = 'ToDo',
+ align = 'center',
+ forced_width = 350, -- for horizontal alignment
+ forced_height = 40,
+ widget = wibox.widget.textbox
+ },
+ add_button,
+ spacing = 8,
+ layout = wibox.layout.fixed.horizontal
+ },
+ bg = beautiful.bg_normal,
+ widget = wibox.container.background
+ }
+
+ table.insert(rows, first_row)
+
+ for i, todo_item in ipairs(result.todo_items) do
+
+ local checkbox = wibox.widget {
+ checked = todo_item.status,
+ color = beautiful.bg_normal,
+ paddings = 2,
+ shape = gears.shape.circle,
+ forced_width = 20,
+ forced_height = 20,
+ check_color = beautiful.fg_urgent,
+ widget = wibox.widget.checkbox
+ }
+
+ checkbox:connect_signal("button::press", function(c)
+ c:set_checked(not c.checked)
+ todo_item.status = not todo_item.status
+ result.todo_items[i] = todo_item
+ spawn.easy_async_with_shell("echo '" .. json.encode(result) .. "' > " .. STORAGE, function ()
+ todo_widget:update_counter(result.todo_items)
+ end)
+ end)
+
+
+ local trash_button = wibox.widget {
+ {
+ { image = WIDGET_DIR .. '/window-close-symbolic.svg',
+ resize = false,
+ widget = wibox.widget.imagebox
+ },
+ margins = 5,
+ layout = wibox.container.margin
+ },
+ border_width = 1,
+ shape = function(cr, width, height)
+ gears.shape.circle(cr, width, height, 10)
+ end,
+ widget = wibox.container.background
+ }
+
+ trash_button:connect_signal("button::press", function()
+ table.remove(result.todo_items, i)
+ spawn.easy_async_with_shell("printf '" .. json.encode(result) .. "' > " .. STORAGE, function ()
+ spawn.easy_async(GET_TODO_ITEMS, function(items) update_widget(items) end)
+ end)
+ end)
+
+
+ local move_up = wibox.widget {
+ image = WIDGET_DIR .. '/chevron-up.svg',
+ resize = false,
+ widget = wibox.widget.imagebox
+ }
+
+ move_up:connect_signal("button::press", function()
+ local temp = result.todo_items[i]
+ result.todo_items[i] = result.todo_items[i-1]
+ result.todo_items[i-1] = temp
+ spawn.easy_async_with_shell("printf '" .. json.encode(result) .. "' > " .. STORAGE, function ()
+ spawn.easy_async(GET_TODO_ITEMS, function(items) update_widget(items) end)
+ end)
+ end)
+
+ local move_down = wibox.widget {
+ image = WIDGET_DIR .. '/chevron-down.svg',
+ resize = false,
+ widget = wibox.widget.imagebox
+ }
+
+ move_down:connect_signal("button::press", function()
+ local temp = result.todo_items[i]
+ result.todo_items[i] = result.todo_items[i+1]
+ result.todo_items[i+1] = temp
+ spawn.easy_async_with_shell("printf '" .. json.encode(result) .. "' > " .. STORAGE, function ()
+ spawn.easy_async(GET_TODO_ITEMS, function(items) update_widget(items) end)
+ end)
+ end)
+
+
+ local move_buttons = {
+ layout = wibox.layout.fixed.vertical
+ }
+
+ if i == 1 and #result.todo_items > 1 then
+ table.insert(move_buttons, move_down)
+ elseif i == #result.todo_items and #result.todo_items > 1 then
+ table.insert(move_buttons, move_up)
+ elseif #result.todo_items > 1 then
+ table.insert(move_buttons, move_up)
+ table.insert(move_buttons, move_down)
+ end
+
+ local row = wibox.widget {
+ {
+ {
+ {
+ checkbox,
+ valign = 'center',
+ layout = wibox.container.place,
+ },
+ {
+ {
+ text = todo_item.todo_item,
+ align = 'left',
+ widget = wibox.widget.textbox
+ },
+ left = 10,
+ layout = wibox.container.margin
+ },
+ {
+ {
+ move_buttons,
+ valign = 'center',
+ layout = wibox.container.place,
+ },
+ {
+ trash_button,
+ valign = 'center',
+ layout = wibox.container.place,
+ },
+ spacing = 8,
+ layout = wibox.layout.align.horizontal
+ },
+ spacing = 8,
+ layout = wibox.layout.align.horizontal
+ },
+ margins = 8,
+ layout = wibox.container.margin
+ },
+ bg = beautiful.bg_normal,
+ widget = wibox.container.background
+ }
+
+ row:connect_signal("mouse::enter", function(c) c:set_bg(beautiful.bg_focus) end)
+ row:connect_signal("mouse::leave", function(c) c:set_bg(beautiful.bg_normal) end)
+
+ table.insert(rows, row)
+ end
+
+ popup:setup(rows)
+ end
+
+ todo_widget.widget:buttons(
+ gears.table.join(
+ awful.button({}, 1, function()
+ if popup.visible then
+ todo_widget.widget:set_bg('#00000000')
+ popup.visible = not popup.visible
+ else
+ todo_widget.widget:set_bg(beautiful.bg_focus)
+ popup:move_next_to(mouse.current_widget_geometry)
+ end
+ end)
+ )
+ )
+
+ spawn.easy_async(GET_TODO_ITEMS, function(stdout) update_widget(stdout) end)
+
+ return todo_widget.widget
+end
+
+if not gfs.file_readable(STORAGE) then
+ spawn.easy_async(string.format([[bash -c "dirname %s | xargs mkdir -p && echo '{\"todo_items\":{}}' > %s"]],
+ STORAGE, STORAGE))
+end
+
+return setmetatable(todo_widget, { __call = function(_, ...) return worker(...) end })
diff --git a/awesome/awesome-wm-widgets/todo-widget/window-close-symbolic.svg b/awesome/awesome-wm-widgets/todo-widget/window-close-symbolic.svg
new file mode 100644
index 0000000..46ff888
--- /dev/null
+++ b/awesome/awesome-wm-widgets/todo-widget/window-close-symbolic.svg
@@ -0,0 +1,95 @@
+
+
+
+
diff --git a/awesome/awesome-wm-widgets/volume-widget/README.md b/awesome/awesome-wm-widgets/volume-widget/README.md
new file mode 100644
index 0000000..4fc7f55
--- /dev/null
+++ b/awesome/awesome-wm-widgets/volume-widget/README.md
@@ -0,0 +1,119 @@
+# Volume widget
+
+Volume widget based on [amixer](https://linux.die.net/man/1/amixer) (is used for controlling the audio volume) and [pacmd](https://linux.die.net/man/1/pacmd) (is used for selecting a sink/source). Also, the widget provides an easy way to customize how it looks, following types are supported out-of-the-box:
+
+![types](screenshots/variations.png)
+
+From left to right: `horizontal_bar`, `vertical_bar`, `icon`, `icon_and_text`, `arc`
+
+A right-click on the widget opens a popup where you can choose a sink/source:
+![sink-sources](screenshots/volume-sink-sources.png)
+
+Left click toggles mute and middle click opens a mixer ([pavucontrol](https://freedesktop.org/software/pulseaudio/pavucontrol/) by default).
+
+### Features
+
+ - switch between sinks/sources by right click on the widget;
+ - more responsive than previous versions of volume widget, which were refreshed once a second;
+ - 5 predefined customizable looks;
+
+## Installation
+
+Clone the repo under **~/.config/awesome/** and add widget in **rc.lua**:
+
+```lua
+local volume_widget = require('awesome-wm-widgets.volume-widget.volume')
+...
+s.mytasklist, -- Middle widget
+ { -- Right widgets
+ layout = wibox.layout.fixed.horizontal,
+ ...
+ -- default
+ volume_widget(),
+ -- customized
+ volume_widget{
+ widget_type = 'arc'
+ },
+```
+
+Note that widget uses following command the get the current volume: `amixer -D pulse sget Master`, so please make sure that it works for you, otherwise you need to set parameter `device = 'default'`.
+
+### Shortcuts
+
+To improve responsiveness of the widget when volume level is changed by a shortcut use corresponding methods of the widget:
+
+```lua
+awful.key({ modkey }, "]", function() volume_widget:inc(5) end),
+awful.key({ modkey }, "[", function() volume_widget:dec(5) end),
+awful.key({ modkey }, "\\", function() volume_widget:toggle() end),
+```
+
+## Customization
+
+It is possible to customize the widget by providing a table with all or some of the following config parameters:
+
+### Generic parameter
+
+| Name | Default | Description |
+|---|---|---|
+| `mixer_cmd` | `pavucontrol` | command to run on middle click (e.g. a mixer program) |
+| `step` | `5` | How much the volume is raised or lowered at once (in %) |
+| `widget_type`| `icon_and_text`| Widget type, one of `horizontal_bar`, `vertical_bar`, `icon`, `icon_and_text`, `arc` |
+| `device` | `pulse` | Select the device name to control |
+
+Depends on the chosen widget type add parameters from the corresponding section below:
+
+#### `icon` parameters
+
+| Name | Default | Description |
+|---|---|---|
+| `icon_dir`| `./icons`| Path to the folder with icons |
+
+_Note:_ if you are changing icons, the folder should contain following .svg images:
+ - audio-volume-high-symbolic
+ - audio-volume-medium-symbolic
+ - audio-volume-low-symbolic
+ - audio-volume-muted-symbolic
+
+#### `icon_and_text` parameters
+
+| Name | Default | Description |
+|---|---|---|
+| `icon_dir`| `./icons`| Path to the folder with icons |
+| `font` | `beautiful.font` | Font name and size, like `Play 12` |
+
+#### `arc` parameters
+
+| Name | Default | Description |
+|---|---|---|
+| `thickness` | 2 | Thickness of the arc |
+| `main_color` | `beautiful.fg_color` | Color of the arc |
+| `bg_color` | `#ffffff11` | Color of the arc's background |
+| `mute_color` | `beautiful.fg_urgent` | Color of the arc when mute |
+| `size` | 18 | Size of the widget |
+
+#### `horizontal_bar` parameters
+
+| Name | Default | Description |
+|---|---|---|
+| `main_color` | `beautiful.fg_normal` | Color of the bar |
+| `mute_color` | `beautiful.fg_urgent` | Color of the bar when mute |
+| `bg_color` | `'#ffffff11'` | Color of the bar's background |
+| `width` | `50` | The bar width |
+| `margins` | `10` | Top and bottom margins (if your wibar is 22 px high, bar will be 2 px = 22 - 2*10) |
+| `shape` | `'bar'` | [gears.shape](https://awesomewm.org/doc/api/libraries/gears.shape.html), could be `octogon`, `hexagon`, `powerline`, etc |
+| `with_icon` | `true` | Show volume icon|
+
+_Note:_ I didn't figure out how does the `forced_height` property of progressbar widget work (maybe it doesn't work at all), thus there is a workaround with margins.
+
+#### `vertical_bar` parameters
+
+| Name | Default | Description |
+|---|---|---|
+| `main_color` | `beautiful.fg_normal` | Color of the bar |
+| `mute_color` | `beautiful.fg_urgent` | Color of the bar when mute |
+| `bg_color` | `'#ffffff11'` | Color of the bar's background |
+| `width` | `10` | The bar width |
+| `margins` | `20` | Top and bottom margins (if your wibar is 22 px high, bar will be 2 px = 22 - 2*10) |
+| `shape` | `'bar'` | [gears.shape](https://awesomewm.org/doc/api/libraries/gears.shape.html), could be `octogon`, `hexagon`, `powerline`, etc |
+| `with_icon` | `true` | Show volume icon|
diff --git a/awesome/awesome-wm-widgets/volume-widget/icons/audio-volume-high-symbolic.svg b/awesome/awesome-wm-widgets/volume-widget/icons/audio-volume-high-symbolic.svg
new file mode 100644
index 0000000..985c107
--- /dev/null
+++ b/awesome/awesome-wm-widgets/volume-widget/icons/audio-volume-high-symbolic.svg
@@ -0,0 +1,88 @@
+
+
diff --git a/awesome/awesome-wm-widgets/volume-widget/icons/audio-volume-low-symbolic.svg b/awesome/awesome-wm-widgets/volume-widget/icons/audio-volume-low-symbolic.svg
new file mode 100644
index 0000000..7eb4531
--- /dev/null
+++ b/awesome/awesome-wm-widgets/volume-widget/icons/audio-volume-low-symbolic.svg
@@ -0,0 +1,88 @@
+
+
diff --git a/awesome/awesome-wm-widgets/volume-widget/icons/audio-volume-medium-symbolic.svg b/awesome/awesome-wm-widgets/volume-widget/icons/audio-volume-medium-symbolic.svg
new file mode 100644
index 0000000..11e44fe
--- /dev/null
+++ b/awesome/awesome-wm-widgets/volume-widget/icons/audio-volume-medium-symbolic.svg
@@ -0,0 +1,88 @@
+
+
diff --git a/awesome/awesome-wm-widgets/volume-widget/icons/audio-volume-muted-symbolic.svg b/awesome/awesome-wm-widgets/volume-widget/icons/audio-volume-muted-symbolic.svg
new file mode 100644
index 0000000..e577d05
--- /dev/null
+++ b/awesome/awesome-wm-widgets/volume-widget/icons/audio-volume-muted-symbolic.svg
@@ -0,0 +1,88 @@
+
+
diff --git a/awesome/awesome-wm-widgets/volume-widget/screenshots/variations.png b/awesome/awesome-wm-widgets/volume-widget/screenshots/variations.png
new file mode 100644
index 0000000..21d7ead
Binary files /dev/null and b/awesome/awesome-wm-widgets/volume-widget/screenshots/variations.png differ
diff --git a/awesome/awesome-wm-widgets/volume-widget/screenshots/volume-sink-sources.png b/awesome/awesome-wm-widgets/volume-widget/screenshots/volume-sink-sources.png
new file mode 100644
index 0000000..7d010bc
Binary files /dev/null and b/awesome/awesome-wm-widgets/volume-widget/screenshots/volume-sink-sources.png differ
diff --git a/awesome/awesome-wm-widgets/volume-widget/utils.lua b/awesome/awesome-wm-widgets/volume-widget/utils.lua
new file mode 100644
index 0000000..417a666
--- /dev/null
+++ b/awesome/awesome-wm-widgets/volume-widget/utils.lua
@@ -0,0 +1,105 @@
+
+
+local utils = {}
+
+local function split(string_to_split, separator)
+ if separator == nil then separator = "%s" end
+ local t = {}
+
+ for str in string.gmatch(string_to_split, "([^".. separator .."]+)") do
+ table.insert(t, str)
+ end
+
+ return t
+end
+
+function utils.extract_sinks_and_sources(pacmd_output)
+ local sinks = {}
+ local sources = {}
+ local device
+ local properties
+ local ports
+ local in_sink = false
+ local in_source = false
+ local in_device = false
+ local in_properties = false
+ local in_ports = false
+ for line in pacmd_output:gmatch("[^\r\n]+") do
+ if string.match(line, 'source%(s%) available.') then
+ in_sink = false
+ in_source = true
+ end
+ if string.match(line, 'sink%(s%) available.') then
+ in_sink = true
+ in_source = false
+ end
+
+ if string.match(line, 'index:') then
+ in_device = true
+ in_properties = false
+ device = {
+ id = line:match(': (%d+)'),
+ is_default = string.match(line, '*') ~= nil
+ }
+ if in_sink then
+ table.insert(sinks, device)
+ elseif in_source then
+ table.insert(sources, device)
+ end
+ end
+
+ if string.match(line, '^\tproperties:') then
+ in_device = false
+ in_properties = true
+ properties = {}
+ device['properties'] = properties
+ end
+
+ if string.match(line, 'ports:') then
+ in_device = false
+ in_properties = false
+ in_ports = true
+ ports = {}
+ device['ports'] = ports
+ end
+
+ if string.match(line, 'active port:') then
+ in_device = false
+ in_properties = false
+ in_ports = false
+ device['active_port'] = line:match(': (.+)'):gsub('<',''):gsub('>','')
+ end
+
+ if in_device then
+ local t = split(line, ': ')
+ local key = t[1]:gsub('\t+', ''):lower()
+ local value = t[2]:gsub('^<', ''):gsub('>$', '')
+ device[key] = value
+ end
+
+ if in_properties then
+ local t = split(line, '=')
+ local key = t[1]:gsub('\t+', ''):gsub('%.', '_'):gsub('-', '_'):gsub(':', ''):gsub("%s+$", "")
+ local value
+ if t[2] == nil then
+ value = t[2]
+ else
+ value = t[2]:gsub('"', ''):gsub("^%s+", ""):gsub(' Analog Stereo', '')
+ end
+ properties[key] = value
+ end
+
+ if in_ports then
+ local t = split(line, ': ')
+ local key = t[1]
+ if key ~= nil then
+ key = key:gsub('\t+', '')
+ end
+ ports[key] = t[2]
+ end
+ end
+
+ return sinks, sources
+end
+
+return utils
\ No newline at end of file
diff --git a/awesome/awesome-wm-widgets/volume-widget/volume-2.svg b/awesome/awesome-wm-widgets/volume-widget/volume-2.svg
new file mode 100644
index 0000000..10f1c67
--- /dev/null
+++ b/awesome/awesome-wm-widgets/volume-widget/volume-2.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/awesome/awesome-wm-widgets/volume-widget/volume.lua b/awesome/awesome-wm-widgets/volume-widget/volume.lua
new file mode 100644
index 0000000..4c44042
--- /dev/null
+++ b/awesome/awesome-wm-widgets/volume-widget/volume.lua
@@ -0,0 +1,228 @@
+-------------------------------------------------
+-- The Ultimate Volume Widget for Awesome Window Manager
+-- More details could be found here:
+-- https://github.com/streetturtle/awesome-wm-widgets/tree/master/volume-widget
+
+-- @author Pavel Makhov
+-- @copyright 2020 Pavel Makhov
+-------------------------------------------------
+
+local awful = require("awful")
+local wibox = require("wibox")
+local spawn = require("awful.spawn")
+local gears = require("gears")
+local beautiful = require("beautiful")
+local watch = require("awful.widget.watch")
+local utils = require("awesome-wm-widgets.volume-widget.utils")
+
+
+local LIST_DEVICES_CMD = [[sh -c "pacmd list-sinks; pacmd list-sources"]]
+local function GET_VOLUME_CMD(device) return 'amixer -D ' .. device .. ' sget Master' end
+local function INC_VOLUME_CMD(device, step) return 'amixer -D ' .. device .. ' sset Master ' .. step .. '%+' end
+local function DEC_VOLUME_CMD(device, step) return 'amixer -D ' .. device .. ' sset Master ' .. step .. '%-' end
+local function TOG_VOLUME_CMD(device) return 'amixer -D ' .. device .. ' sset Master toggle' end
+
+
+local widget_types = {
+ icon_and_text = require("awesome-wm-widgets.volume-widget.widgets.icon-and-text-widget"),
+ icon = require("awesome-wm-widgets.volume-widget.widgets.icon-widget"),
+ arc = require("awesome-wm-widgets.volume-widget.widgets.arc-widget"),
+ horizontal_bar = require("awesome-wm-widgets.volume-widget.widgets.horizontal-bar-widget"),
+ vertical_bar = require("awesome-wm-widgets.volume-widget.widgets.vertical-bar-widget")
+}
+local volume = {}
+
+local rows = { layout = wibox.layout.fixed.vertical }
+
+local popup = awful.popup{
+ bg = beautiful.bg_normal,
+ ontop = true,
+ visible = false,
+ shape = gears.shape.rounded_rect,
+ border_width = 1,
+ border_color = beautiful.bg_focus,
+ maximum_width = 400,
+ offset = { y = 5 },
+ widget = {}
+}
+
+local function build_main_line(device)
+ if device.active_port ~= nil and device.ports[device.active_port] ~= nil then
+ return device.properties.device_description .. ' · ' .. device.ports[device.active_port]
+ else
+ return device.properties.device_description
+ end
+end
+
+local function build_rows(devices, on_checkbox_click, device_type)
+ local device_rows = { layout = wibox.layout.fixed.vertical }
+ for _, device in pairs(devices) do
+
+ local checkbox = wibox.widget {
+ checked = device.is_default,
+ color = beautiful.bg_normal,
+ paddings = 2,
+ shape = gears.shape.circle,
+ forced_width = 20,
+ forced_height = 20,
+ check_color = beautiful.fg_urgent,
+ widget = wibox.widget.checkbox
+ }
+
+ checkbox:connect_signal("button::press", function()
+ spawn.easy_async(string.format([[sh -c 'pacmd set-default-%s "%s"']], device_type, device.name), function()
+ on_checkbox_click()
+ end)
+ end)
+
+ local row = wibox.widget {
+ {
+ {
+ {
+ checkbox,
+ valign = 'center',
+ layout = wibox.container.place,
+ },
+ {
+ {
+ text = build_main_line(device),
+ align = 'left',
+ widget = wibox.widget.textbox
+ },
+ left = 10,
+ layout = wibox.container.margin
+ },
+ spacing = 8,
+ layout = wibox.layout.align.horizontal
+ },
+ margins = 4,
+ layout = wibox.container.margin
+ },
+ bg = beautiful.bg_normal,
+ widget = wibox.container.background
+ }
+
+ row:connect_signal("mouse::enter", function(c) c:set_bg(beautiful.bg_focus) end)
+ row:connect_signal("mouse::leave", function(c) c:set_bg(beautiful.bg_normal) end)
+
+ local old_cursor, old_wibox
+ row:connect_signal("mouse::enter", function()
+ local wb = mouse.current_wibox
+ old_cursor, old_wibox = wb.cursor, wb
+ wb.cursor = "hand1"
+ end)
+ row:connect_signal("mouse::leave", function()
+ if old_wibox then
+ old_wibox.cursor = old_cursor
+ old_wibox = nil
+ end
+ end)
+
+ row:connect_signal("button::press", function()
+ spawn.easy_async(string.format([[sh -c 'pacmd set-default-%s "%s"']], device_type, device.name), function()
+ on_checkbox_click()
+ end)
+ end)
+
+ table.insert(device_rows, row)
+ end
+
+ return device_rows
+end
+
+local function build_header_row(text)
+ return wibox.widget{
+ {
+ markup = "" .. text .. "",
+ align = 'center',
+ widget = wibox.widget.textbox
+ },
+ bg = beautiful.bg_normal,
+ widget = wibox.container.background
+ }
+end
+
+local function rebuild_popup()
+ spawn.easy_async(LIST_DEVICES_CMD, function(stdout)
+
+ local sinks, sources = utils.extract_sinks_and_sources(stdout)
+
+ for i = 0, #rows do rows[i]=nil end
+
+ table.insert(rows, build_header_row("SINKS"))
+ table.insert(rows, build_rows(sinks, function() rebuild_popup() end, "sink"))
+ table.insert(rows, build_header_row("SOURCES"))
+ table.insert(rows, build_rows(sources, function() rebuild_popup() end, "source"))
+
+ popup:setup(rows)
+ end)
+end
+
+
+local function worker(user_args)
+
+ local args = user_args or {}
+
+ local mixer_cmd = args.mixer_cmd or 'pavucontrol'
+ local widget_type = args.widget_type
+ local refresh_rate = args.refresh_rate or 1
+ local step = args.step or 5
+ local device = args.device or 'pulse'
+
+ if widget_types[widget_type] == nil then
+ volume.widget = widget_types['icon_and_text'].get_widget(args.icon_and_text_args)
+ else
+ volume.widget = widget_types[widget_type].get_widget(args)
+ end
+
+ local function update_graphic(widget, stdout)
+ local mute = string.match(stdout, "%[(o%D%D?)%]") -- \[(o\D\D?)\] - [on] or [off]
+ if mute == 'off' then widget:mute()
+ elseif mute == 'on' then widget:unmute()
+ end
+ local volume_level = string.match(stdout, "(%d?%d?%d)%%") -- (\d?\d?\d)\%)
+ volume_level = string.format("% 3d", volume_level)
+ widget:set_volume_level(volume_level)
+ end
+
+ function volume:inc(s)
+ spawn.easy_async(INC_VOLUME_CMD(device, s or step), function(stdout) update_graphic(volume.widget, stdout) end)
+ end
+
+ function volume:dec(s)
+ spawn.easy_async(DEC_VOLUME_CMD(device, s or step), function(stdout) update_graphic(volume.widget, stdout) end)
+ end
+
+ function volume:toggle()
+ spawn.easy_async(TOG_VOLUME_CMD(device), function(stdout) update_graphic(volume.widget, stdout) end)
+ end
+
+ function volume:mixer()
+ if mixer_cmd then
+ spawn.easy_async(mixer_cmd)
+ end
+ end
+
+ volume.widget:buttons(
+ awful.util.table.join(
+ awful.button({}, 3, function()
+ if popup.visible then
+ popup.visible = not popup.visible
+ else
+ rebuild_popup()
+ popup:move_next_to(mouse.current_widget_geometry)
+ end
+ end),
+ awful.button({}, 4, function() volume:inc() end),
+ awful.button({}, 5, function() volume:dec() end),
+ awful.button({}, 2, function() volume:mixer() end),
+ awful.button({}, 1, function() volume:toggle() end)
+ )
+ )
+
+ watch(GET_VOLUME_CMD(device), refresh_rate, update_graphic, volume.widget)
+
+ return volume.widget
+end
+
+return setmetatable(volume, { __call = function(_, ...) return worker(...) end })
diff --git a/awesome/awesome-wm-widgets/volume-widget/widgets/arc-widget.lua b/awesome/awesome-wm-widgets/volume-widget/widgets/arc-widget.lua
new file mode 100644
index 0000000..b512f12
--- /dev/null
+++ b/awesome/awesome-wm-widgets/volume-widget/widgets/arc-widget.lua
@@ -0,0 +1,46 @@
+local wibox = require("wibox")
+local beautiful = require('beautiful')
+
+local ICON_DIR = os.getenv("HOME") .. '/.config/awesome/awesome-wm-widgets/volume-widget/icons/'
+
+local widget = {}
+
+function widget.get_widget(widgets_args)
+ local args = widgets_args or {}
+
+ local thickness = args.thickness or 2
+ local main_color = args.main_color or beautiful.fg_color
+ local bg_color = args.bg_color or '#ffffff11'
+ local mute_color = args.mute_color or beautiful.fg_urgent
+ local size = args.size or 18
+
+ return wibox.widget {
+ {
+ id = "icon",
+ image = ICON_DIR .. 'audio-volume-high-symbolic.svg',
+ resize = true,
+ widget = wibox.widget.imagebox,
+ },
+ max_value = 100,
+ thickness = thickness,
+ start_angle = 4.71238898, -- 2pi*3/4
+ forced_height = size,
+ forced_width = size,
+ bg = bg_color,
+ paddings = 2,
+ widget = wibox.container.arcchart,
+ set_volume_level = function(self, new_value)
+ self.value = new_value
+ end,
+ mute = function(self)
+ self.colors = { mute_color }
+ end,
+ unmute = function(self)
+ self.colors = { main_color }
+ end
+ }
+
+end
+
+
+return widget
\ No newline at end of file
diff --git a/awesome/awesome-wm-widgets/volume-widget/widgets/horizontal-bar-widget.lua b/awesome/awesome-wm-widgets/volume-widget/widgets/horizontal-bar-widget.lua
new file mode 100644
index 0000000..be1f38d
--- /dev/null
+++ b/awesome/awesome-wm-widgets/volume-widget/widgets/horizontal-bar-widget.lua
@@ -0,0 +1,58 @@
+local wibox = require("wibox")
+local beautiful = require('beautiful')
+local gears = require("gears")
+
+local ICON_DIR = os.getenv("HOME") .. '/.config/awesome/awesome-wm-widgets/volume-widget/icons/'
+
+local widget = {}
+
+function widget.get_widget(widgets_args)
+ local args = widgets_args or {}
+
+ local main_color = args.main_color or beautiful.fg_normal
+ local mute_color = args.mute_color or beautiful.fg_urgent
+ local bg_color = args.bg_color or '#ffffff11'
+ local width = args.width or 50
+ local margins = args.margins or 10
+ local shape = args.shape or 'bar'
+ local with_icon = args.with_icon == true and true or false
+
+ local bar = wibox.widget {
+ {
+ {
+ id = "icon",
+ image = ICON_DIR .. 'audio-volume-high-symbolic.svg',
+ resize = false,
+ widget = wibox.widget.imagebox,
+ },
+ valign = 'center',
+ visible = with_icon,
+ layout = wibox.container.place,
+ },
+ {
+ id = 'bar',
+ max_value = 100,
+ forced_width = width,
+ color = main_color,
+ margins = { top = margins, bottom = margins },
+ background_color = bg_color,
+ shape = gears.shape[shape],
+ widget = wibox.widget.progressbar,
+ },
+ spacing = 4,
+ layout = wibox.layout.fixed.horizontal,
+ set_volume_level = function(self, new_value)
+ self:get_children_by_id('bar')[1]:set_value(tonumber(new_value))
+ end,
+ mute = function(self)
+ self:get_children_by_id('bar')[1]:set_color(mute_color)
+ end,
+ unmute = function(self)
+ self:get_children_by_id('bar')[1]:set_color(main_color)
+ end
+ }
+
+ return bar
+end
+
+return widget
diff --git a/awesome/awesome-wm-widgets/volume-widget/widgets/icon-and-text-widget.lua b/awesome/awesome-wm-widgets/volume-widget/widgets/icon-and-text-widget.lua
new file mode 100644
index 0000000..b1a2793
--- /dev/null
+++ b/awesome/awesome-wm-widgets/volume-widget/widgets/icon-and-text-widget.lua
@@ -0,0 +1,59 @@
+local wibox = require("wibox")
+local beautiful = require('beautiful')
+
+local widget = {}
+
+local ICON_DIR = os.getenv("HOME") .. '/.config/awesome/awesome-wm-widgets/volume-widget/icons/'
+
+function widget.get_widget(widgets_args)
+ local args = widgets_args or {}
+
+ local font = args.font or beautiful.font
+ local icon_dir = args.icon_dir or ICON_DIR
+
+ return wibox.widget {
+ {
+ {
+ id = "icon",
+ resize = false,
+ widget = wibox.widget.imagebox,
+ },
+ valign = 'center',
+ layout = wibox.container.place
+ },
+ {
+ id = 'txt',
+ font = font,
+ widget = wibox.widget.textbox
+ },
+ layout = wibox.layout.fixed.horizontal,
+ set_volume_level = function(self, new_value)
+ self:get_children_by_id('txt')[1]:set_text(new_value)
+ local volume_icon_name
+ if self.is_muted then
+ volume_icon_name = 'audio-volume-muted-symbolic'
+ else
+ local new_value_num = tonumber(new_value)
+ if (new_value_num >= 0 and new_value_num < 33) then
+ volume_icon_name="audio-volume-low-symbolic"
+ elseif (new_value_num < 66) then
+ volume_icon_name="audio-volume-medium-symbolic"
+ else
+ volume_icon_name="audio-volume-high-symbolic"
+ end
+ end
+ self:get_children_by_id('icon')[1]:set_image(icon_dir .. volume_icon_name .. '.svg')
+ end,
+ mute = function(self)
+ self.is_muted = true
+ self:get_children_by_id('icon')[1]:set_image(icon_dir .. 'audio-volume-muted-symbolic.svg')
+ end,
+ unmute = function(self)
+ self.is_muted = false
+ end
+ }
+
+end
+
+
+return widget
\ No newline at end of file
diff --git a/awesome/awesome-wm-widgets/volume-widget/widgets/icon-widget.lua b/awesome/awesome-wm-widgets/volume-widget/widgets/icon-widget.lua
new file mode 100644
index 0000000..cc39a3d
--- /dev/null
+++ b/awesome/awesome-wm-widgets/volume-widget/widgets/icon-widget.lua
@@ -0,0 +1,46 @@
+local wibox = require("wibox")
+
+local widget = {}
+
+local ICON_DIR = os.getenv("HOME") .. '/.config/awesome/awesome-wm-widgets/volume-widget/icons/'
+
+function widget.get_widget(widgets_args)
+ local args = widgets_args or {}
+
+ local icon_dir = args.icon_dir or ICON_DIR
+
+ return wibox.widget {
+ {
+ id = "icon",
+ resize = false,
+ widget = wibox.widget.imagebox,
+ },
+ valign = 'center',
+ layout = wibox.container.place,
+ set_volume_level = function(self, new_value)
+ local volume_icon_name
+ if self.is_muted then
+ volume_icon_name = 'audio-volume-muted-symbolic'
+ else
+ local new_value_num = tonumber(new_value)
+ if (new_value_num >= 0 and new_value_num < 33) then
+ volume_icon_name="audio-volume-low-symbolic"
+ elseif (new_value_num < 66) then
+ volume_icon_name="audio-volume-medium-symbolic"
+ else
+ volume_icon_name="audio-volume-high-symbolic"
+ end
+ end
+ self:get_children_by_id('icon')[1]:set_image(icon_dir .. volume_icon_name .. '.svg')
+ end,
+ mute = function(self)
+ self.is_muted = true
+ self:get_children_by_id('icon')[1]:set_image(icon_dir .. 'audio-volume-muted-symbolic.svg')
+ end,
+ unmute = function(self)
+ self.is_muted = false
+ end
+ }
+end
+
+return widget
\ No newline at end of file
diff --git a/awesome/awesome-wm-widgets/volume-widget/widgets/vertical-bar-widget.lua b/awesome/awesome-wm-widgets/volume-widget/widgets/vertical-bar-widget.lua
new file mode 100644
index 0000000..6f32b50
--- /dev/null
+++ b/awesome/awesome-wm-widgets/volume-widget/widgets/vertical-bar-widget.lua
@@ -0,0 +1,64 @@
+local wibox = require("wibox")
+local beautiful = require('beautiful')
+local gears = require("gears")
+
+local ICON_DIR = os.getenv("HOME") .. '/.config/awesome/awesome-wm-widgets/volume-widget/icons/'
+
+local widget = {}
+
+function widget.get_widget(widgets_args)
+ local args = widgets_args or {}
+
+ local main_color = args.main_color or beautiful.fg_normal
+ local mute_color = args.mute_color or beautiful.fg_urgent
+ local bg_color = args.bg_color or '#ffffff11'
+ local width = args.width or 10
+ local margins = args.height or 2
+ local shape = args.shape or 'bar'
+ local with_icon = args.with_icon == true and true or false
+
+ local bar = wibox.widget {
+ {
+ {
+ id = "icon",
+ image = ICON_DIR .. 'audio-volume-high-symbolic.svg',
+ resize = false,
+ widget = wibox.widget.imagebox,
+ },
+ valign = 'center',
+ visible = with_icon,
+ layout = wibox.container.place,
+ },
+ {
+ {
+ id = 'bar',
+ max_value = 100,
+ forced_width = width,
+ forced_height = 5,
+ margins = { top = margins, bottom = margins },
+ color = main_color,
+ background_color = bg_color,
+ shape = gears.shape[shape],
+ widget = wibox.widget.progressbar,
+ },
+ forced_width = width,
+ direction = 'east',
+ layout = wibox.container.rotate,
+ },
+ spacing = 4,
+ layout = wibox.layout.fixed.horizontal,
+ set_volume_level = function(self, new_value)
+ self:get_children_by_id('bar')[1]:set_value(tonumber(new_value))
+ end,
+ mute = function(self)
+ self:get_children_by_id('bar')[1]:set_color(mute_color)
+ end,
+ unmute = function(self)
+ self:get_children_by_id('bar')[1]:set_color(main_color)
+ end
+ }
+
+ return bar
+end
+
+return widget
diff --git a/awesome/awesome-wm-widgets/weather-widget/README.md b/awesome/awesome-wm-widgets/weather-widget/README.md
new file mode 100644
index 0000000..3bf6228
--- /dev/null
+++ b/awesome/awesome-wm-widgets/weather-widget/README.md
@@ -0,0 +1,144 @@
+# Weather widget
+
+