From 0877ecc694445a7219ded84a560cd3411eb3e9b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yi=C4=9Fit=20=C3=87olako=C4=9Flu?= Date: Mon, 15 Feb 2021 19:31:32 +0300 Subject: [PATCH] Initial Commit --- arch-setup.sh | 0 gtk/gtk-3.0/bookmarks | 7 + gtk/gtk-3.0/settings.ini | 16 + gtk/gtk-4.0/settings.ini | 2 + install.sh | 35 + misc/dunst/dunstrc | 323 ++ misc/dunst/not.svg | 9 + misc/dunst/notif.png | Bin 0 -> 21416 bytes misc/rofi/config.rasi | 149 + misc/rofi/music_menu | 10 + misc/rofi/sidebar-mod.rasi | 109 + misc/rofi/themes/denvit.rasi | 149 + misc/rofi/themes/dmenu.rasi | 44 + misc/zathura/a | 4 + misc/zathura/zathurarc | 64 + scripts/autotrim | 163 + scripts/bluetooth_battery.py | 89 + scripts/convertToHtmlMultipart | 239 ++ scripts/dmenu-killall | 80 + scripts/dmenu-logout | 61 + scripts/dunst_toggle.sh | 23 + scripts/gen_tracking_url | 26 + scripts/mail_tag.sh | 15 + scripts/mails.sh | 8 + scripts/newmail.sh | 4 + scripts/nm_sendmail.sh | 28 + scripts/status-bar/arch | 12 + scripts/status-bar/arch-block | 17 + scripts/status-bar/battery | 37 + scripts/status-bar/battery-blocks | 49 + scripts/status-bar/capslock | 14 + scripts/status-bar/clima | 12 + scripts/status-bar/clima-icon | 27 + scripts/status-bar/cpu-temp | 6 + scripts/status-bar/fecha | 9 + scripts/status-bar/fecha-block | 11 + scripts/status-bar/listener | 10 + scripts/status-bar/red | 9 + scripts/status-bar/red-texto | 14 + scripts/status-bar/sep1 | 3 + scripts/status-bar/spotify-bar | 14 + scripts/status-bar/spotify-block | 17 + scripts/status-bar/spotify_status.py | 122 + scripts/status-bar/volume | 24 + scripts/status-bar/volume-block | 29 + scripts/toggle_monitor.sh | 6 + scripts/toggle_touchpad.sh | 9 + scripts/update_events.sh | 3 + scripts/welcome.sh | 28 + suckless/dwm/, | 245 ++ suckless/dwm/LICENSE | 37 + suckless/dwm/Makefile | 51 + suckless/dwm/Makefile.bak | 50 + suckless/dwm/README.es.org | 32 + suckless/dwm/README.org | 35 + suckless/dwm/config.h | 262 ++ suckless/dwm/config.mk | 38 + suckless/dwm/drw.c | 438 +++ suckless/dwm/drw.h | 57 + .../dwm/dwm-systray-20200914-61bb8b2.diff | 727 +++++ suckless/dwm/dwm.1 | 185 ++ suckless/dwm/dwm.c | 2768 ++++++++++++++++ suckless/dwm/dwm.png | Bin 0 -> 373 bytes suckless/dwm/dwm_config_pulseaudio.h | 28 + suckless/dwm/fibonacci.c | 66 + suckless/dwm/layouts.c | 27 + suckless/dwm/movestack.c | 49 + suckless/dwm/patches/dwm-6.0-winview.diff | 65 + ...dwm-actualfullscreen-20191112-cb3f58a.diff | 53 + ...-alttagsdecoration-2020010304-cb3f58a.diff | 67 + .../dwm-alwayscenter-20200625-f04cac6.diff | 12 + .../dwm-barpadding-20200720-bb2e722.diff | 124 + .../dwm/patches/dwm-centeredmaster-6.1.diff | 142 + .../patches/dwm-cfacts-20200913-61bb8b2.diff | 117 + .../dwm-cfacts_centeredmaster-6.2.diff | 180 ++ suckless/dwm/patches/dwm-colorbar-6.2.diff | 68 + .../dwm-cyclelayouts-20180524-6.2.diff | 93 + suckless/dwm/patches/dwm-deck-6.0.diff | 90 + suckless/dwm/patches/dwm-dwmblocks-6.2.diff | 340 ++ suckless/dwm/patches/dwm-ewmhtags-6.2.diff | 161 + suckless/dwm/patches/dwm-fibonacci-5.8.2.diff | 85 + suckless/dwm/patches/dwm-fixborders-6.2.diff | 27 + .../dwm-gridmode-20170909-ceac8c9.diff | 73 + .../dwm/patches/dwm-inplacerotate-6.2.diff | 108 + .../dwm-leftlayout-20180524-c8e9479.diff | 69 + suckless/dwm/patches/dwm-movestack-6.1.diff | 73 + .../dwm-netclientliststacking-6.2.diff | 65 + .../patches/dwm-pertag-20170513-ceac8c9.diff | 177 ++ suckless/dwm/patches/dwm-rmaster-6.1.diff | 113 + .../dwm-statuspadding-20150524-c8e9479.diff | 62 + suckless/dwm/patches/dwm-switchcol-6.1.diff | 47 + .../patches/dwm-systray-20200914-61bb8b2.diff | 727 +++++ suckless/dwm/patches/dwm-uselessgap-6.2.diff | 81 + suckless/dwm/shiftview.c | 19 + suckless/dwm/transient.c | 42 + suckless/dwm/util.c | 35 + suckless/dwm/util.h | 8 + suckless/dwmblocks/.gitignore | 3 + suckless/dwmblocks/GNUmakefile | 32 + suckless/dwmblocks/LICENSE | 7 + suckless/dwmblocks/README.md | 66 + suckless/dwmblocks/blocks.h | 33 + suckless/dwmblocks/dwmblocks.c | 357 +++ suckless/dwmblocks/sigdwmblocks.c | 76 + suckless/dwmblocks/xgetrootname.c | 21 + tmux/tmux.conf | 117 + vim/vim/.gitignore | 3 + vim/vim/autoload/plug.vim | 2797 +++++++++++++++++ vim/vim/plugin/csyntaxafter.vim | 1 + vim/vim/plugin/ctrlp.vim | 6 + vim/vim/plugin/nerdtree.vim | 4 + vim/vim/plugin/plugins.vim | 85 + vim/vim/plugin/vim-rails.vim | 30 + vim/vim/plugin/vim-ripgrep.vim | 3 + vim/vim/plugin/vim-test.vim | 7 + vim/vimrc | 135 + xorg/xinitrc | 34 + xorg/xmodmap | 248 ++ zsh/antibody/p10k.zsh | 1641 ++++++++++ zsh/antibody/zsh_plugins.txt | 11 + zsh/cmds | 50 + zsh/zshrc | 60 + 122 files changed, 16384 insertions(+) create mode 100755 arch-setup.sh create mode 100644 gtk/gtk-3.0/bookmarks create mode 100644 gtk/gtk-3.0/settings.ini create mode 100644 gtk/gtk-4.0/settings.ini create mode 100755 install.sh create mode 100644 misc/dunst/dunstrc create mode 100644 misc/dunst/not.svg create mode 100644 misc/dunst/notif.png create mode 100644 misc/rofi/config.rasi create mode 100755 misc/rofi/music_menu create mode 100644 misc/rofi/sidebar-mod.rasi create mode 100644 misc/rofi/themes/denvit.rasi create mode 100644 misc/rofi/themes/dmenu.rasi create mode 100644 misc/zathura/a create mode 100644 misc/zathura/zathurarc create mode 100755 scripts/autotrim create mode 100755 scripts/bluetooth_battery.py create mode 100755 scripts/convertToHtmlMultipart create mode 100755 scripts/dmenu-killall create mode 100755 scripts/dmenu-logout create mode 100755 scripts/dunst_toggle.sh create mode 100755 scripts/gen_tracking_url create mode 100755 scripts/mail_tag.sh create mode 100755 scripts/mails.sh create mode 100755 scripts/newmail.sh create mode 100755 scripts/nm_sendmail.sh create mode 100755 scripts/status-bar/arch create mode 100755 scripts/status-bar/arch-block create mode 100755 scripts/status-bar/battery create mode 100755 scripts/status-bar/battery-blocks create mode 100755 scripts/status-bar/capslock create mode 100755 scripts/status-bar/clima create mode 100755 scripts/status-bar/clima-icon create mode 100755 scripts/status-bar/cpu-temp create mode 100755 scripts/status-bar/fecha create mode 100755 scripts/status-bar/fecha-block create mode 100755 scripts/status-bar/listener create mode 100755 scripts/status-bar/red create mode 100755 scripts/status-bar/red-texto create mode 100755 scripts/status-bar/sep1 create mode 100755 scripts/status-bar/spotify-bar create mode 100755 scripts/status-bar/spotify-block create mode 100755 scripts/status-bar/spotify_status.py create mode 100755 scripts/status-bar/volume create mode 100755 scripts/status-bar/volume-block create mode 100755 scripts/toggle_monitor.sh create mode 100755 scripts/toggle_touchpad.sh create mode 100755 scripts/update_events.sh create mode 100755 scripts/welcome.sh create mode 100644 suckless/dwm/, create mode 100644 suckless/dwm/LICENSE create mode 100644 suckless/dwm/Makefile create mode 100644 suckless/dwm/Makefile.bak create mode 100644 suckless/dwm/README.es.org create mode 100644 suckless/dwm/README.org create mode 100644 suckless/dwm/config.h create mode 100644 suckless/dwm/config.mk create mode 100644 suckless/dwm/drw.c create mode 100644 suckless/dwm/drw.h create mode 100644 suckless/dwm/dwm-systray-20200914-61bb8b2.diff create mode 100644 suckless/dwm/dwm.1 create mode 100644 suckless/dwm/dwm.c create mode 100644 suckless/dwm/dwm.png create mode 100644 suckless/dwm/dwm_config_pulseaudio.h create mode 100644 suckless/dwm/fibonacci.c create mode 100644 suckless/dwm/layouts.c create mode 100644 suckless/dwm/movestack.c create mode 100644 suckless/dwm/patches/dwm-6.0-winview.diff create mode 100644 suckless/dwm/patches/dwm-actualfullscreen-20191112-cb3f58a.diff create mode 100644 suckless/dwm/patches/dwm-alttagsdecoration-2020010304-cb3f58a.diff create mode 100644 suckless/dwm/patches/dwm-alwayscenter-20200625-f04cac6.diff create mode 100644 suckless/dwm/patches/dwm-barpadding-20200720-bb2e722.diff create mode 100644 suckless/dwm/patches/dwm-centeredmaster-6.1.diff create mode 100644 suckless/dwm/patches/dwm-cfacts-20200913-61bb8b2.diff create mode 100644 suckless/dwm/patches/dwm-cfacts_centeredmaster-6.2.diff create mode 100644 suckless/dwm/patches/dwm-colorbar-6.2.diff create mode 100644 suckless/dwm/patches/dwm-cyclelayouts-20180524-6.2.diff create mode 100644 suckless/dwm/patches/dwm-deck-6.0.diff create mode 100644 suckless/dwm/patches/dwm-dwmblocks-6.2.diff create mode 100644 suckless/dwm/patches/dwm-ewmhtags-6.2.diff create mode 100644 suckless/dwm/patches/dwm-fibonacci-5.8.2.diff create mode 100644 suckless/dwm/patches/dwm-fixborders-6.2.diff create mode 100644 suckless/dwm/patches/dwm-gridmode-20170909-ceac8c9.diff create mode 100644 suckless/dwm/patches/dwm-inplacerotate-6.2.diff create mode 100644 suckless/dwm/patches/dwm-leftlayout-20180524-c8e9479.diff create mode 100644 suckless/dwm/patches/dwm-movestack-6.1.diff create mode 100644 suckless/dwm/patches/dwm-netclientliststacking-6.2.diff create mode 100644 suckless/dwm/patches/dwm-pertag-20170513-ceac8c9.diff create mode 100644 suckless/dwm/patches/dwm-rmaster-6.1.diff create mode 100644 suckless/dwm/patches/dwm-statuspadding-20150524-c8e9479.diff create mode 100644 suckless/dwm/patches/dwm-switchcol-6.1.diff create mode 100644 suckless/dwm/patches/dwm-systray-20200914-61bb8b2.diff create mode 100644 suckless/dwm/patches/dwm-uselessgap-6.2.diff create mode 100644 suckless/dwm/shiftview.c create mode 100644 suckless/dwm/transient.c create mode 100644 suckless/dwm/util.c create mode 100644 suckless/dwm/util.h create mode 100644 suckless/dwmblocks/.gitignore create mode 100644 suckless/dwmblocks/GNUmakefile create mode 100644 suckless/dwmblocks/LICENSE create mode 100644 suckless/dwmblocks/README.md create mode 100644 suckless/dwmblocks/blocks.h create mode 100644 suckless/dwmblocks/dwmblocks.c create mode 100644 suckless/dwmblocks/sigdwmblocks.c create mode 100644 suckless/dwmblocks/xgetrootname.c create mode 100644 tmux/tmux.conf create mode 100644 vim/vim/.gitignore create mode 100644 vim/vim/autoload/plug.vim create mode 100644 vim/vim/plugin/csyntaxafter.vim create mode 100644 vim/vim/plugin/ctrlp.vim create mode 100644 vim/vim/plugin/nerdtree.vim create mode 100644 vim/vim/plugin/plugins.vim create mode 100644 vim/vim/plugin/vim-rails.vim create mode 100644 vim/vim/plugin/vim-ripgrep.vim create mode 100644 vim/vim/plugin/vim-test.vim create mode 100644 vim/vimrc create mode 100755 xorg/xinitrc create mode 100644 xorg/xmodmap create mode 100644 zsh/antibody/p10k.zsh create mode 100644 zsh/antibody/zsh_plugins.txt create mode 100644 zsh/cmds create mode 100644 zsh/zshrc diff --git a/arch-setup.sh b/arch-setup.sh new file mode 100755 index 00000000..e69de29b diff --git a/gtk/gtk-3.0/bookmarks b/gtk/gtk-3.0/bookmarks new file mode 100644 index 00000000..31db4099 --- /dev/null +++ b/gtk/gtk-3.0/bookmarks @@ -0,0 +1,7 @@ +smb://yigitcolakoglu.com;yigitcolakoglu@home.yigitcolakoglu.com/dockerstorage/ dockerstorage on home.yigitcolakoglu.com +file:///home/yigit/Projects Projects +file:///home/yigit/Downloads Downloads +file:///home/yigit/Nextcloud Nextcloud +file:///home/yigit/Pictures Pictures +file:///home/yigit/Documents/ +file:///home/yigit/Pictures/ diff --git a/gtk/gtk-3.0/settings.ini b/gtk/gtk-3.0/settings.ini new file mode 100644 index 00000000..61a4fe7f --- /dev/null +++ b/gtk/gtk-3.0/settings.ini @@ -0,0 +1,16 @@ +[Settings] +gtk-theme-name=Arc-Dark +gtk-icon-theme-name=Numix +gtk-font-name=Cantarell 11 +gtk-cursor-theme-name=Adwaita +gtk-cursor-theme-size=0 +gtk-toolbar-style=GTK_TOOLBAR_BOTH +gtk-toolbar-icon-size=GTK_ICON_SIZE_LARGE_TOOLBAR +gtk-button-images=1 +gtk-menu-images=1 +gtk-enable-event-sounds=1 +gtk-enable-input-feedback-sounds=1 +gtk-xft-antialias=1 +gtk-xft-hinting=1 +gtk-xft-hintstyle=hintfull +gtk-application-prefer-dark-theme=0 diff --git a/gtk/gtk-4.0/settings.ini b/gtk/gtk-4.0/settings.ini new file mode 100644 index 00000000..7c6461a7 --- /dev/null +++ b/gtk/gtk-4.0/settings.ini @@ -0,0 +1,2 @@ +[Settings] +gtk-application-prefer-dark-theme=0 diff --git a/install.sh b/install.sh new file mode 100755 index 00000000..26a49fc5 --- /dev/null +++ b/install.sh @@ -0,0 +1,35 @@ +#!/bin/bash + +# Vim +ln -s ~/.dotfiles/vim/vimrc ~/.vimrc +ln -s ~/.dotfiles/vim/vim ~/.vim + +# GTK +ln -s ~/.dotfiles/gtk/gtk-2.0 ~/.config/gtk-2.0 +ln -s ~/.dotfiles/gtk/gtk-3.0 ~/.config/gtk-3.0 +ln -s ~/.dotfiles/gtk/gtk-4.0 ~/.config/gtk-4.0 + +# Miscellaneous +ln -s ~/.dotfiles/misc/dunst ~/.config/dunst +ln -s ~/.dotfiles/misc/rofi ~/.config/rofi +ln -s ~/.dotfiles/misc/zathura ~/.config/zathura + +# Scripts +ln -s ~/.dotfiles/scripts ~/.scripts + +# Suckless +ln -s ~/.dotfiles/suckless ~/.config/suckless + +# Tmux +ln -s ~/.dotfiles/tmux/tmux.conf ~/.tmux.conf + +# Xorg +ln -s ~/.dotfiles/xorg/xinitrc ~/.xinitrc +ln -s ~/.dotfiles/xorg/xmodmap ~/.xmodmap + +# Zsh +ln -s ~/.dotfiles/zsh/antibody ~/.config/antibody +ln -s ~/.dotfiles/zsh/zshrc ~/.zshrc +ln -s ~/.dotfiles/zsh/cmds ~/.cmds +ln -s ~/.dotfiles/zsh/aliases ~/.aliases + diff --git a/misc/dunst/dunstrc b/misc/dunst/dunstrc new file mode 100644 index 00000000..d3f5b18c --- /dev/null +++ b/misc/dunst/dunstrc @@ -0,0 +1,323 @@ +[colors] +## gruvbox +# background = "#282828" +# foreground = "#fbf2c7" +# frame_color = "#282828" + +# dracula + background = "#282a36" + foreground = "#f8f8f2" + frame_color = "#282a36" + + +[global] + frame_width = 0 + #font = JetBrains Mono 10 + font = Ubuntu 10 + follow = none + + # Allow a small subset of html markup: + # bold + # italic + # strikethrough + # underline + # + # For a complete reference see + # . + # If markup is not allowed, those tags will be stripped out of the + # message. + markup = yes + stack_duplicates = true + # The format of the message. Possible variables are: + # %a appname + # %s summary + # %b body + # %i iconname (including its path) + # %I iconname (without its path) + # %p progress value if set ([ 0%] to [100%]) or nothing + # Markup is allowed + format = "%a \n %s %p\n%b" + + # Sort messages by urgency. + sort = yes + + # Show how many messages are currently hidden (because of geometry). + indicate_hidden = yes + + # Alignment of message text. + # Possible values are "left", "center" and "right". + alignment = left + + # The frequency with wich text that is longer than the notification + # window allows bounces back and forth. + # This option conflicts with "word_wrap". + # Set to 0 to disable. + bounce_freq = 5 + + + # Show age of message if message is older than show_age_threshold + # seconds. + # Set to -1 to disable. + show_age_threshold = 60 + + # Split notifications into multiple lines if they don't fit into + # geometry. + word_wrap = yes + + # Ignore newlines '\n' in notifications. + ignore_newline = no + + + # The geometry of the window: + # [{width}]x{height}[+/-{x}+/-{y}] + # The geometry of the message window. + # The height is measured in number of notifications everything else + # in pixels. If the width is omitted but the height is given + # ("-geometry x2"), the message window expands over the whole screen + # (dmenu-like). If width is 0, the window expands to the longest + # message displayed. A positive x is measured from the left, a + # negative from the right side of the screen. Y is measured from + # the top and down respectevly. + # The width can be negative. In this case the actual width is the + # screen width minus the width defined in within the geometry option. + geometry = "500x8-8-8" + + # Show how many messages are currently hidden (because of geometry). + indicate_hidden = yes + # Shrink window if it's smaller than the width. Will be ignored if + # width is 0. + shrink = yes + + # The transparency of the window. Range: [0; 100]. + # This option will only work if a compositing windowmanager is + # present (e.g. xcompmgr, compiz, etc.). + transparency = 0 + + # Don't remove messages, if the user is idle (no mouse or keyboard input) + # for longer than idle_threshold seconds. + # Set to 0 to disable. + # default 120 + idle_threshold = 120 + + # Which monitor should the notifications be displayed on. + monitor = 0 + + # Display notification on focused monitor. Possible modes are: + # mouse: follow mouse pointer + # keyboard: follow window with keyboard focus + # none: don't follow anything + # + # "keyboard" needs a windowmanager that exports the + # _NET_ACTIVE_WINDOW property. + # This should be the case for almost all modern windowmanagers. + # + # If this option is set to mouse or keyboard, the monitor option + # will be ignored. + + # Should a notification popped up from history be sticky or timeout + # as if it would normally do. + sticky_history = yes + + # Maximum amount of notifications kept in history + history_length = 20 + + # Display indicators for URLs (U) and actions (A). + show_indicators = yes + + # The height of a single line. If the height is smaller than the + # font height, it will get raised to the font height. + # This adds empty space above and under the text. + line_height = 0 + + # Draw a line of "separator_height" pixel height between two + # notifications. + # Set to 0 to disable. + separator_height = 1 + + # Padding between text and separator. + # padding = 8 + padding = 8 + + # Horizontal padding. + horizontal_padding = 10 + + # Define a color for the separator. + # possible values are: + # * auto: dunst tries to find a color fitting to the background; + # * foreground: use the same color as the foreground; + # * frame: use the same color as the frame; + # * anything else will be interpreted as a X color. + separator_color = auto + + # Print a notification on startup. + # This is mainly for error detection, since dbus (re-)starts dunst + # automatically after a crash. + startup_notification = false + + # dmenu path. + dmenu = /usr/bin/dmenu -p dunst: + + # Browser for opening urls in context menu. + browser = firefox-developer-edition + + # Align icons left/right/off + icon_position = left + + # Paths to default icons. + icon_path = /usr/share/icons/Adwaita/16x16/status/:/usr/share/icons/Adwaita/16x16/devices/:/usr/share/icons/Papirus-Dark/16x16/devices/:/usr/share/icons/Papirus-Dark/16x16/status/ + + # Limit icons size. + max_icon_size=32 + +[shortcuts] + + # Shortcuts are specified as [modifier+][modifier+]...key + # Available modifiers are "ctrl", "mod1" (the alt-key), "mod2", + # "mod3" and "mod4" (windows-key). + # Xev might be helpful to find names for keys. + + # Close notification. + # close = mod1+space + + # Close all notifications. + # close_all = ctrl+shift+space + close_all = ctrl+mod1+space + + # Redisplay last message(s). + # On the US keyboard layout "grave" is normally above TAB and left + # of "1". + history = shift+mod4+h + + # Context menu. + context = shift+mod4+space + +[urgency_low] + # IMPORTANT: colors have to be defined in quotation marks. + # Otherwise the "#" and following would be interpreted as a comment. + background = "#313D4A" + foreground = "#F9FAF9" + frame_color = "#9DB788" + timeout = 5 + +[urgency_normal] + background = "#313D4A" + foreground = "#F9FAF9" + frame_color = "#2E2E2D" + timeout = 5 + +[urgency_critical] + background = "#313D4A" + foreground = "#F9FAF9" + frame_color = "#D62929" + timeout = 0 + + +# Every section that isn't one of the above is interpreted as a rules to +# override settings for certain messages. +# Messages can be matched by "appname", "summary", "body", "icon", "category", +# "msg_urgency" and you can override the "timeout", "urgency", "foreground", +# "background", "new_icon" and "format". +# Shell-like globbing will get expanded. +# +# SCRIPTING +# You can specify a script that gets run when the rule matches by +# setting the "script" option. +# The script will be called as follows: +# script appname summary body icon urgency +# where urgency can be "LOW", "NORMAL" or "CRITICAL". +# +# NOTE: if you don't want a notification to be displayed, set the format +# to "". +# NOTE: It might be helpful to run dunst -print in a terminal in order +# to find fitting options for rules. + +#[espeak] +# summary = "*" +# script = dunst_espeak.sh + +#[script-test] +# summary = "*script*" +# script = dunst_test.sh + +#[ignore] +# # This notification will not be displayed +# summary = "foobar" +# format = "" + +#[signed_on] +# appname = Pidgin +# summary = "*signed on*" +# urgency = low +# +#[signed_off] +# appname = Pidgin +# summary = *signed off* +# urgency = low +# +#[says] +# appname = Pidgin +# summary = *says* +# urgency = critical +# +#[twitter] +# appname = Pidgin +# summary = *twitter.com* +# urgency = normal +# +#[Claws Mail] +# appname = claws-mail +# category = email.arrived +# urgency = normal +# background = "#2F899E" +# foreground = "#FFA247" +# +#[mute.sh] +# appname = mute +# category = mute.sound +# script = mute.sh +# +#[JDownloader] +# appname = JDownloader +# category = JD +# background = "#FFA247" +# foreground = "#FFFFFF" +# +#[newsbeuter] +# summary = *Feeds* +# background = "#A8EB41" +# foreground = "#FFFFFF" +# +[irc] + appname = weechat + timeout = 0 + background = "#0033bb" + foreground = "#dddddd" +# +[weechat hl] + appname = weechat + category = weechat.HL + background = "#FF5C47" + foreground = "#FFFFFF" +# +[weechat pn] + appname = weechat + category = weechat.PM + background = "#D53B84" + foreground = "#FFFFFF" +# +#[CMUS] +# appname = CMUS +# category = cmus +# background = "#6C4AB7" +# foreground = "#FFE756" +# +# +# background = "#30AB70" +# foreground = "#F67245" +# +[Spotify] + appname = Spotify + frame_color = "#30AB70" + timeout = 5 + +# vim: ft=cfg diff --git a/misc/dunst/not.svg b/misc/dunst/not.svg new file mode 100644 index 00000000..15a5cb83 --- /dev/null +++ b/misc/dunst/not.svg @@ -0,0 +1,9 @@ + + + + + + + diff --git a/misc/dunst/notif.png b/misc/dunst/notif.png new file mode 100644 index 0000000000000000000000000000000000000000..08a0234ce068462ea6ebf0faa7ab21304bd99f97 GIT binary patch literal 21416 zcmb5W2UHYI*Dl&UGr*9C93%{aBuN7z8HPM$Ns0kfKoAUwWCUy!B?_aUfJjCGQ6#Da zl@}%H2uM&QDmiBmB%K=l&iDQIzxVuiomslp{h>0#l%Yao4rbg`m;|#_h8-5QK(~nA;gbfxA%9 z|M(~Pf0X_=ThPt_#ZL)>+#o0wf+!HQ2Z5H75~Sn?DWyV66i8{0Ds)qV+}t3yRLG42 zx$RMPQD5(&I0#WvWCumOz+H-^UQlUKxvCAU;1H;R(m9+d?Urn)JmrYfaUlv4Moq<}8P zO^K4KM4>2A_5epw83u=R172%#0R+I9!omb8mOLxX#|eU{QHX*|*Uqfu8{6H+rWt_jBK{bV%BTAZT^T)DJXQX8yU z-E)zBS2|mor8(;V@C+p_GlN4koNMe znobMMhs)f??kYm72LPXm0yML?KpDCD|GTD}yd;n!@e9Fg$ z>kDQEN$GvVU_+0ygkD~I+i;)e#Htz6es|1}vgK0!*2d8HV|zYNQD4eZQ@}RvI<2oE z(jHl3XujUrqaB=NcpZZk49u7xA4zuEXE1pO$_^@$8VsqO_^r5WFnJTo_GaC>q^v_( zm)^CT42QBkSR*g<_J3QK*>ydi31y#^@EHuZf>^hRL$np}i77I(sr zvonZ3&3>D`T@ltx`%1W`6rbzpv zvE-)C*0DojqURH#Y~_*l3p$kgLfZ;p_28WO!134g*=JD^Pm)g6Y`wjZ&)p#d>**i$ z7!2FC^x-&hfOy_`>W#2)Rn!nGzbNs1<0;3!U$08ClEvw9{N5R77Jf86SURa^hQVHH ze))Ua>($aVJ$($;A}}sU{l&OP8YJ@70qpSvnDL{>Ca)XYfoo(HsuFzwqs$v%6S*<;)L$n3SHz# z(Mrtv_3b%1ZM2;QXvM6IT;J1(W`&hG@OGXYw%(5)C0T+F{61dW{&D%`l3JECDnfdo zQS;P`nGLZc^03~WR%h36V)x-SV+RFa)YI>Zf4_~<#WBjm^?tKilGP>#&v!zMC8!F=Cp%v6<oP`;+@DGD-Xe6%T+M(vf1IK?^)`o zh#1YLM}6EA95x4GJws_7^r-04RMufsL~wsYL?3@>P+=03Ekqc4IU%Br?=nP=+{sP3 z+*clDh4o{@cMWU1^>Ke^(xVbO|17d4b682w9)rDqzL0+5UB%dABUFUxp{oo(jps*P z^bA2}RAZxG+CP-G5rOpt`QO2tLwiS;bhCv(nkvH3!`u=4^th+(+sw^-y8#@+Tu()a z1-ciSNNi$$%fV5w|*hc1vep)H+?BieXs6VG5O)}c|7G8SOqLdfc5va z(%Zl24h9v*Kq56WDW__1nS4+2L{jls;>Eo&Wp!mXyx6z4gR3e|xwagz-c>^Rx}Ls_ z^nPOVoVfT`C(Xu*+YDIT)tMRk2ks7bh6wp2rD$i7DK;33v(bq5s1(j$Y7xS^Sz2yh7*D2P z2M6Aj+t%~+s&76wD&j-18qw}8pP99u?M@5HAR%Pk+aW6)I&e4ZbFr^j^xX+uE_)SGW zikt?CJWnyd=E}!y4^qpO=#k*-o6mrXc$VR!ICt0OQsE6qq$mw&`0{^)Y(PAIJV58! z$YZL`S3>G~bE=JKZqr3X$oEAriKqc2Eyb*c^Is`o^YKU? z<|ldrPw~!jb2fkD>sBA{5R&~DKJTnJ_r>sE0t@peS{S_3P#e}Z|(sNUuh8{Nk+VD z@Vu)Y7+%qS)jV4N8j5X7kBdh-^+A$8SUQ6t>Jbu5P5E*2!q6p#h!fONzkGlc;!m;y zV1kD3EGnBH6+vlrv6*YJ{|ldpoGWP^$<+@=MRfhvu={w{rb{0o_ga`2?F7bIv24=g zuEv6Mt7zi~ITI3j)t7SY+E03JE;jt=*FGf~tCE5!NTjOu>)C;(ChF;VZ{~vF*Ztbc z)MA`EeT{x@f1WrhVz$`j@|<3XTLBoKH8m+GuU%pLd+y7Ne-oM$2XWl= zej;f>`^mTU=OY~YU=VFyat^!X6yj760g1eGiZ^<9r;YJG4sVy0c)zx7$vc}J6~VAt zdhZ**lP7fo<6$m6bTuDLul$c11p3NGHl9&WR4(<`G~Q@EKX7e2zsLQ78M_AN*6hub zI2Al~>W=)%<9z&v;Vm$+I(#tiD_Ge`Il>0(9T0MUa;eig#Izt9%I0n&d^;?qEehtH zBe4(KUTVd*VeQ%Qb|Z(}`qpKJIrJRCWi4vzr54NnJWEsrUw_k{_K_m9pv>VF!AbF5 z6^bFEP!;)kZ+=)usNl=5$)zclwRg9UNm0xYh0?J;+W46b9hTL(rii|jb0O8}=R;v% zUABc4=-~Ri;vAY55^HI3*mlK}xNgkB;?*ytWd66}#FW;RxdgSjZioEJ!-0o?k|uDw z>c4*VXau?KC#HOy-Y;IUF#Jx_?pm5|W3boKR<~2!svVQI1Tm#??DQ`N(Kkk3#V@wb zJNA!E+?rG0y^unN&N5tYYC8Yo%ieaH|IW*$LYDO%uHV82*hCI|+`{sk)~ej}fG=Gw zc-EzCmi0kBPW;TC=|oXM{%`a-wy zg40@1UPhx1jVS1T>}G)QyHgE1fv>kVqW$(Q1cy{9Qg&3 zR^X6kL&A21cC0xOQMkR5?qn9H8r^;UbyuK#`{|4k<1o()0qVKH;}1#kLixBr#s$C)EnN(Pd<%1>3(QvQ1igrFukjOJ6Ok+Av9N=lO(86M&xadolb866*mQi1zpg3@!S(RbEul8T zv}|)wCB5Q!Zf)}E$l}@N8#0aiiM*FH-6hU;wG@4w!;f5of-1N6k@rp|Y(jT3=yA9C zeHEJuUg717HVXatUYX2ijhz>r*UffEMV$5TQQau^c5ma?Sc$JW7;^r$=UOWkgT2W# zbem1*jF`%j?F?a=qV>9Tw7wX}B2MJ}LH0Rk>_lVNXZy^0=(>PEqyJeGc{+Cd?40Y5 z&LV~73j1#-o|PUW3a;A+#y6bBV7JsOqMOefbKIVYVRxMkv-`ABrGLp-!zNjd9=EQf zC*1!<_^t5zw?)1?yDhA3mNTWQ2y|As%|(D#)lK*x;c3;JD;mKPPYJ>7Gaa9OtTD29f5l{d>dw1@wVJ!a zm3Pi4Su_=TJV-wt-{6G7p62yfXwqpMVp<-EGD|cf{4-soB6Eo|LQE57!rpsBJ`6|Q%elelQ7`bGa)a&qLM0WOJ?`!vShw$LA*Y6oLZ z;>jFN@k?j=F*Wrx^H&;Pz4}L9a<7(&!u64j0~#CgQ{qpv>E`1->UlbBuM;{AH7>E? zLtKBa+az9;U<$aE=`zr`K)5xP{LrFo$TdyJ{l*D*4nG4G*tE{rJ*>)PSj3 zBC=S#^ef}tg$|GD+OFVd4HXmHpI5qjl3T%p)!Dh(&F<{yM{9{G&CQ?#RBoZo{!-&(@UYPCl|yDn zn+?9YbJ|(%*Rjaf#@ME+y%SEeyNjPk`}_*-K|dq+FSuWqYFBabQ}%toGw%H)dHmhM z5@;rXKW&i(t`E4CpKo&^v^6R|A`b+ z3CQO;{RZk48gkM~IvIcH0$n2O`8y3m7_7W}+scAaNR$2c;fDUqQyI^_GUHX!KCgdX zbMp!D-U@uFDHYZ@6Lc!KY*uPi9u*O7)iao`6sK)>HT=DoxE2)0K#z-=)xLf#{8*+gq)!f?l{i;10kFO5b|-!t4k7%RA8QspoE<^5V_|IKZw z(_xcw4c9TGrq)CmmYqb*reovwm80r9^yIK}J^kB4^vj>xFFV?ni$pA7NUxSJ?ro%D zHl;3v_2BARQF+H2(pEz2ZN3OEk4MhehDZ?A?O$KpIyNgAa{qF4zwkvV17vkt#x11W#XWG6ceUV#UaKHaZR1;SNV3z~^6eqV z4|F;EPmgZ(Mt9F9pG$9EXnXI=jCR73S?u=0)&rjJ$iCX`W_~xbi7Sz#C$Cp7 zAv?(r1|#}kt&gpS;=I9FSdkt&y%=wy^gP+~lH5vkelU8JJ;C7S5p(U^EI@=1p5 z?r0!6150k~{*L@Ii>2MoIobW4T+``LD)DyqrTt*tC`Z$MohDDWxp|#K%2QF0$BFw* z9COo$v|aB!u+VcT1OoIj%Nt`Rp;>c z0B-GHKE@k2A3JE_@Rxpb+xOp{p&TrmPZ)kR8}-;h5P;KXf#%DZjn(g(hu$uXpq~rj zTjWuBCKmoj`Wxm#PlX#4pBVJpEtDQK_r}5X`7m&SRxPZ-3G% z55O1b@;xr=w^oNFZNwHkJmW{__&bE_Z$^T(jB6SuG^|*Max1UB$B<5{d;HX{ zYxtfQS#Y{~ZG*fMF~^R#2#UKm=4j<^+aIkd@AYPFBkmg>z_M!5F=H;@@{>hbey3Gl zd;8+ju;&*6xP#rw+P^~0Q7BmcYFO3VD{lf;d3o-9#gcEYeqZq`nQNH(-m)ui^maf- zIJ0=fy(Dcmzfyq=c^J3Ja_7OUv=aH+OgU7kevfIz!rmr?1)hDb(opiV+{4eIQD(D19hKJdwS2u+XBKIZ_Wp z5)IZtN6c~)Y&@bNkM}-yQm%gdF86O^$%h^OF$;cNJ)Aa^0*Cogb!S@`zc2&^Bjj~R*hMX7=7EjV08{d+L6mu710O{+9yh!c4t)YzM^^d zB!;x6S(me4$XVGC>6#Z|;PA{Ua<;{g<^U>PE&b8}v1=8<+ld>=$>Q*S<+sSafl=K! z*hb|fwy;%^R(_2GZ+|WBUPR1?$;V-+JhxxgK7#bngmSlFVm)feC{l1OMq=8yxI%Xe@!w2egK^wXgKr4 z36*DR31`EEhlR;d;a#oCiXVp?mB50UGSCnYOmNbGZL%XJbqdmcO;&Q?xd3XU`l#e8 zDo^{Eb;uEo(1C-197iSHT1||uMLLG$C-d{M2;pgAB2;+iKyAh7p+;qUc6?<}O#Myq zlpCJoeMJ=Mk1V~5oT6#`^yH5hb7r&H{5g)ABV7$bdMC=GOD%3;NRHgrzU^_5y#3%& z(QZu6l%=;c>Wf7vhGc(;kgdx?TlfGfY*A-mIgyiXQi&m1-yLOole>zh z@E%lnYai~!ICq{YDv#URy{?pz+C+mo{Jst z7sY?mABYp6!W#!1D%xa8fGF1^v>x39LVw|Hs4)B{cIqF$xB#&9=lMg-xB3b@I^zVE z%%Euyq}z9xFkA>qT_^sLk^fbUh}8iMDXd6R?)-plTo71Iko*v#ZT~IS+ z>KJ7W=|$@ ztd0?+ky#AMIlG0q0` zn{t+eAj$*@hsF2ST^JL3a>%oPZs3%4ZBSyFl7e+g&-yVWbr$`|OwIQnEs#7P{>SLR z+xOET6A1>oMJB549bg;l?odciz6eZ*3>?Y#pcc1%e(2ij=z6>;e2)^8#Jo68kiHp* zAt}0BAFfL?w4>#tC%eYyUPKls*3p|+??vapVXtF5@FMWNPx_q9i|-A)XzA(6rvzwF z*Q0x>uvrq*Vy6iw-6oc7chp+3&MMzpa8#6NQx$U$4(m1YBPT#6W9p`~8*M>JbW=bn z=L~YXHAj;d?E%oJ@;p1*{!x_*8=`=$+3~yQ3(vyIYbxKLWUy z-3}1hzeMv4=8Ad&lr25*r=zuqt0<8@+8N#*JwO6!VGT9^5$be9>;Q4Oy$Lfo@fUnS z{DHO>6%!>cN7=x;{(OddawxGoX_8z&yk1!!7~N0oSY*Ix=RCe<31EvPhQ)*e_N#1o z4})xIZ<$@}0DSM(G5jJyUe|^lfBaeQ5#)Lh{XLM#dO6&NK^J`?mMoKFj{G_wdH*hC zGOYO#6WFFMeajp}VvpC4Y*Xdc0*U@`DT#iuxPViU4R0coV~PZ%8yAwJAd~$un7|=L z(_01@63a`r`iYAN%t^>-R^tAU)@&P)WdXSy62fZm9O$-)m|`}XEjSs2uw>4RTmvNG zlwl<~5;FOzNEH~`{SjCK0qehTb!p5-yH66M2QbJXA_?gRRpi@H3-O@S#=}>Wpb$*8 z`jIcR4Bt@EI`5Z@%1ymbM2U(etb+cyH9dZm*v(5_bc@mUoJ_}oa*ig_HaVGb2Qneb z2lO;}*ili;JQco}Vpf?`5iML?M%K#ks14>zm za`fE!@8E(IP}S>VG6AaG*8A#sWZr)?M3Q(O!y#iLF}DRUB=0tB{<>qWIiAhB2xmSA z_w4lHr+;wuv;P#w=l+2M_<_FEU%1JduP*to_Jpcl&-c(IW+^OrI7b0_al9!l29mNk zXxNkPA5(}WcL@Clos(feZ#=ZUWXpzstk%Z8j`P!JK;>0fbkUUDEZAp*!#_4W4%L*z zt8lG)EO&;4_408!hX>Xga>mRv%WJ>rWygN#}$`W~DqMF@MpFoIl{0 zre2TjUl%W}IqKqDa|0!rGUq>N_DeAGa$0l65JyMDwIdmj z)W_(_68Zd`2@zsUb=*D3-;c9fKM0jqP$Nly<`|E)R+0oU=7g~cRMWw9kQKH`I_gmJ zszB%?2i{Q2&=AsyozB*TZMwYeFeT-GVcDGhNV=Bs=8;E`lr#gXXCO3*wSk_TlY>VF z1`PfUr(cfo092@`qtSm*|5||F%g6iSX_ z)%86AI@FdAp2UyJ%R9%3Dbb+2ktaelRgb*^`3DHB>3ajbND_M{z%t2HA4yu}rGaNJ zv;D!v=-BIbUs~&MN)Sz}@7#daaerZn-g@X?XjJgOQRAHV|3caE3dFyCW3WtrZSrOc z=+3bIHTwS$i@_*#%FD7vi=>J>z~iC-jRAN_p`u{!!H`T)7+P?R12F=JSA_ov^Caoc z2&2RpVH=wybO|e%!yqZCk8n>U)S`zZagIT=BjOBE9l+R{rA`||;s$a4|C;C{t{^ut zS0S)?SBAqMFjRxK{&t)rfP`uqz}64{doTa9$zS^a7YtnZ{*Td3p8R*9lWHK+rsH;Pr}JixX7P`W}O3!67mc1rX2YH^sXLD?Oou%xtyUUKkcuo zBQ>wD;~8=e!8YwKR3C=_4yE+YU-%M$lmG2mOqyCsT`OzmI;Wf)k`@T381W4GU)~Iq zp=;59t-S62ZFMP!A9-W&hxw%XQ@F?MZx=7AE;4c>B+U^{&IV|9Len&=9=NteJ`|v0moJHk5T9KqZqvLL^PZd-pPz79n1!+`4 z!e0R!UV-A#g}X&hzABW%i|q6pFEo1*v2vmRq`TDa{otm{Fs3hv=tonANU+6+c|o&vp_V9z8a?% z9c)99Hidh>sXvV>!;lCP)(mxTA9^H1q^xP{a1+*~Br&3Cv?6rd!BE8d9wc?(BgCtx(!hivi3Cg4 zi}>17hzMs{3{}DS099dB1ZWH&mX5v$R8E}zMxFd6nxN#8et>nj;3=L>+aw zg8f`Vz3iU9MML)=kX#^U%KjG&inqzZ!!{&NSRu|y99%{9asWiSL^=x{hdV22RP3QS8v|>ICN;0ocYU2~tRUJ~;+F=U|ZRi-z)6 z2&cF30f?zG-jk~EK_6&zU9#gC!;<&UQ+4EW9!eS`oTc$pFMpLH?o3`ODG>k2hBs7Y z6J+7;Hc&(5MP0Ik6jHtysh-wlvxe%fSQ^S(BAjeA5K{o(m;nKmhuOmZyuwl`Yl$SC z5f%|>wX7e;km$i3!_QeU82~Qw0^L_p!8yFJO}#ZIbOkAph+)GYxaho%ruz%)Fk{_?;T9{Y&ufipleza&{ ze0>fER(!>~UdL;hQzEI0P-Zo6Ybo3=FOV_C;gzmMon?*tDJdPxj%lWRCCr8sF6NZ| z(UJsOF@KdhP1%gN?iuXy*UuDnBiTiBmFfvcw19}JHPjVDADa48+Y7i#b;MB z&Ch)6ZJSH|c7`$qp3!7EAY+73rW9#46@(($xkZWNtGs9--nRYIvEU(CO|S`}GvZupn8h?d za(<0=sZKz-Tt>NC68gglvbl9BX;A9j&b%`Wtx3{`2!$ldk#fUL9E>174_8!T6a!V) zsE>E9t{@}#Lkie(YR%+-=2Wt^GsPUCxO3eUZ+dIQx5nlp8)@%s|nDqRz6I|2!;xM~$AG zs@bSO_oO7s)Ws6zDxStWUMH5*k&+0dnlN2G!>?lPNg*MW5p7yE1!m?TMo`@=k7Uh1 z9jyno)vOr46>a#OAPOt8_F>ODzhrN$22pwItQX{dkq>0Jh0-;Sl+?9yqw__ zuqR2E>GGKqMUrY@|HG3B1*w!K`z`_SIMunrfEoXJq!5&9O0ek%tvI)GlR2h&)%iTy zww%M&3FUg#KfLbLEG88c=aG?v0*{97_yMB$1Q(Vf{xlvutF$!K(LM=aKi4FKY3_PN zgIe(xZ+-?2Yf<5wsvNFIQLdig37yYyfWQbVR`PzW6OhYY1Q+1c9(|?@XINfY2T^np z^V!3-;CPssG9fpe&_Yj^I{txir6%gP%T<)CDff~dY<=C_5;2#$t)w8)#NKL%n3E)& zB>&MHtiqD%r#>(qm~7Sni4{o?%*F}^xr1Dm$Na-YnUVG+M}rJLb5TIARLAqXI-^|G zUuNrzSlha^HHhW zgd+xa`)%3r9MQT=Nk93%g0vk13rFV$jARu>U`1xDlB|*fLvbjERNC?U><=9O$xdPdDm;0>Cw?`EoMup&)p2|m2QSX`9&1oxgt z(!}alAw8LXa+HPdl!2il7pw@ov*|Hd-!%v6!qdth`KoAoFB(e*Z*+dpd{mEr=(-=} z8uE=07+#+vo*D)54FoYcW>u6Im_8998vWwc=aIa`X5VrM(>(c-;2SqMeNxo9K_O z3@F!AZG`jT0`obCQxS+S*#b}gXMw~`ir+p+j*gG9 zWy6auGYHzmFr2%Hay1}0grBN4$^_B1snZ@L$9|jSV8f3rF$mr(+ZW1@ay^txunWH! zpJU3G4DsDDnkOH%lNw>iyQn3EGmQFh`+Y3HG&@+jWT7@?axD4oLwsg&ws=wZTq|89 zZdB&B6#0v{owN%(UiA0}1sa zPfI_&4_-uB3pC(p%6g3|!8RMk7~X86Q?hk&oDmYIE9}&4Wi|MPo=lj0&&cIq_>Uqt ztazh_H-qSQm?ItpTE~pF`^T;REJ+2N}tX}k}K z{t4EVar%hBtmBGercNttXFg$Z|D_ z5m{C_-?JBlpCl82d(EZ-%=8tW%1>BK^V!QTM^JuO7!~)!SIJ%k@$eHexxs3WAT{v5 zpy2cVr^)Z>$@+n4)Y=la>mk%A&a&**??6UHe)uY+f~9vHYOLc#d+r%Aj0T z0Vv_6YqXzu+Xs#EyUGZ7E2hXf94RUFt*?VEgSw?Sp?6C;fwX)DO>A!J)=eRM>i~7mU)gzJ&Wp)h|C)EIGv}M zaDv?;_-j>nMCdB&udV*XG;3dW{s7N87>Aatz-6r0+Ou`rtbc$_KC}M_`JTVKGYJ?D zgvNfMtvJW0+?s)Do|khjfiHPibP-Xm?$xjLi!Rdg86mS2Zru5=7D;N?*zh%FG??CV zO3iqbt8o#pJ24h$=pnPsK%+M(N&OlQU!!(Mm$qU`-7{SaOHL0&Xr8a&E?h^sN(i0N zU764A|DFnczeVTJuFYDyE>85%qL*L&L6FXHq$djkWk(0YmU2;exiXjc6tVB3M1LZ* z*4^)dQKh4cde@(g4WvSwaa^_S*^w#GMhvw1 z!JA1UOQJ6YrZ#%)yF2XW*Ix(oYg~W+e9MTRhl^FiQte0H~DA)f0_fo(1BvC{w2@}3$x=FylJsN zE|TTx$pL}kEZYm$c?hD5Z1A$Ye0#XcI!Bl;vi*tC_lJgjhmHhs_a}`yu9mcy1a0FS?;jh0=AfOlDAE&Tvn<3l(pk#i?KX48u zA=~rnv`lr^TU~Da@IsBM@DNTxVcx3E#+YV#?nTr>RlM4bcUbbCLmgvnoAcl=dUB@B z4;t;O`&Ka5arm=bBbXnjxmVsABioA?Vfn@Aa}=&^BV-$|gIIlMS(b;F)0y#gJVyzR zVEfCm5naF!v%{Rb7D%mn{7-nX^!etpyj=6APquL^NSmr4*oyOk*7uC@%e*}kxN9Byrb=qR2NmZby5Qo{!9)gZHlAxYs%w};PpbhpMe_UbDYl75byo7(?1_A;W6o`+6Y2tE! zaXk6WNRHhYhgm8ELn4{y=(w%Jn@cBZ6=Lc@Kuyqz8t!oZXyvBC=T#GA9+-0L?zZq5uT^zG#> zN`p#w1X3(B(>kuvlSeilz)#x8Zj-f9qu~FuYQI0nR=$-wE|xi96DIXR6YH?ClKkM%)nBf<{z87MAv*g zBp31tirLIZThKLM3dw|4zJFlqdiwzVVcsVzV$Q-`@A(B4;{2Okh@mPrsKEO(ZPdU` zqS`A0N9FTwXz4dvvM_eN_6|UWiDw08u^x&<%i%4wq`RP!P0a}=vR}wG=z!ygM_tco z(WCp{Y9M9Y69if1r&Ul@fIlbMsBb3dBqQ##8DjoWTQsi}`cfm<{CKR%!Gfl_s_7U} z{ZmSIZ>J5?-|&itY*L<3%FlpHc!4}R5gONRjy%(Ri|X+7Q9gPQzRESkPBgL*QtBol zs=v|Amr7%%o{Cstq7vJ}w|g~Y-`s+N;=JhamvP7Vvy>AEZT3$d zLf(sN?ZxUUTwmGo!KY!_zQHEfV~Ogh(f%3MEbmV#3(_`*$f?FPn)Am(XM!$Z$$qCC zkq7p__UGMzysyf(M;e~HW3fyZHCRJbv2-3T(q9Kf^W|*6Ta&W&l&lE~{SdX9{Y2|l z7206MAWOxVuxF3=Lma|rR`W9&98v-5m}Q)ng6=dEz_$uvepf^tSE#9loww-Pi%i+Y zE+MBr_+cj7_OESCWtQ#Ut6o59^?fao((*u>S+l&9#YnBt(l*27z~S-tA8cr&eoa7| zLwW8@xGfzBd|Wq^!qI8Ui(k(~*S5Ts&^iqU$$j+XfFUK;;PeQ-@Rxd(Yi zan`vj`X4f3$9vy`0*5TjlcPtmI15f#J9&{?%oyp>$1dKoH%|%5!;;HiYeFHTs%{ib z8w|KpLgXLMd`uGol^BK=OFL7PI-7C$)>4`tT}rBlE0+BF5EL@5DE?W79TO!d4%IY& zZ4=W)1ezYhKWqsX-0tFu!}ZW&m1|qcN4luQi?F{B=ZYKq7|t+n6v|qG7Ac zG9}9w`EUR}!;{Ki&4@!{u;kOj_n;DR8(?;d9r70;hApuRo?$(Dc4t2kTE`Q^j(<>w z&(J-Vm>ask>nK3NmPG#b+~jQmf&8UQC9&W>bHeL5A9sew=+VQ)^pM71dc#C1WI*l6 zw2Hg8HMG$yKHkb{3T6j65Vnu_Z!gQ?9B8q!@2|ICe^l)Mx*Onx{R8-H-5F4rETN(l zbz6|ehiBngnLkO4dOiu>;{C~+vxG=pvCW*Qj4=N24QO`yZ$K{2q1{Vc_8d*gCnZmqaOS_$Kd5(1yXE zafQ>+h2HuL__*P< zdw1_m1mNTUpex|GqO2Snv``h-qL?THMhQ5Ju8;L$mZi-Q)gJC2E}MtLYfV>9jH?&3 zLwixFiphuIvbZ8l-H@E~6UqT_F5Y2Tyt|bm>C?i2Ke~*nl^-y{>x|OlUg4pInrIKj zR0D7wImUnto$EK)5VuBp%(06Zi78^`;QYU=3+>)tqZPA90vS<@FYL|lPUSJ+t^stN zQ^{4k5cR>|7kM}K@X7V$85ND_8JarQe1eX6l1#7Ma16XCes13&d2Ucrjt}yBKu~i_ zk|oNF(QF*>;7Anic$2;)B=|$8jiCG_NsjnPhGx)*ZWhAJ$G$Fr z1Ph$eKdq+Fqu(F+X6;KRtaOWnBCqM->LpyK(*f|Y89lhjlx-L6C)S$K1t00&N>H)K zL}B3GW1YW?gr~7M4TkW>O9y-RmTV8e%gdbKc(V*+Pl%5U*{^71Hrmskw_>L2*)7Uw z?;H?3Z!f#kw`cRkvGd$159H;eMww%24~1$5`jS`Y-9m%=vn2ibwZT0@3N{*A-NE(biITnl#$rf=rhGxBEJ8gKa&Ko(C*;bA<7-r``N` z^;-1WiLRQU#eg;1C|MEWVJA+?%494I>%L8W8+p0eU12T+x&VeuYCY|NPEPgO2@$aZf~&@TAA za(Vgclo~hr6vs)ry)Gl9wpO$87=~O(KnQ*+$=$zk$mjf;B81$?NaT)JP)|(Pfp(FrH{N9 z4EPN`m={8ib`SW)L5Rr9gn>gcn-2L@CU4h`1bHXd#og|`_1lMkanzC-UZ42VZKXxm zTx3>MhJ^aQnV$Aa2dy#hI7Xz+@pRDAk_NnNdK)@@;#tjr!UlNod!Nn(Yl~|QiV}B4 z^^pLR1Xe70$Wgl?5Z*ZJGybLtJgA)(x@b!mR$Veat%Mpqt&-4t4&Ku!8yaCmjXJiu zJ4F%Oioflo%fHrvm$M^Jezwdq<1teju{`ypt^aftTliZUORJpS&3n-1$Cg5s{q52D z=eo2s*zg*GPM)bW&o$moZ(S)6!8FGo&2ZB#=T68t$t*%#FFE1m{2G4l@JQR>R=GS} zmY--G$)|Vl<*S#$0(xMrW5g2k^pz?XcnN_=KQFFzh&$ zl`ik4tR1fT(#pMh+R_+_^YZf-Gt8=(yA^rVmIKdme87ZF(sj%CfW|mjBKEx=a3PwT z;^FPb0le*Uv%E+3^Lb{I|+74C9Q>A^`9=#@A*7FIjyTy z1hxh-TsHopgr!>jWjw2TEYq~I4SV);Byhr7!nS#(%_;J)gYE!}E0 z|MkJ8yZz&nOY^#y4;dkcMt4W&r`J71O-U}^OTq7!esl*GVMvLsUUF?h3GrG(IT3T? zQ>&g+1baFRX(Zzq>x)+hc-9jYDjSx*jC_Cp@#<6X$w64{;DdhfWzFGvGu}`BK1&bz zFCPZqWc*&;X&hae9PVZ0Sg%kGQ+FJ49CScpp`T-YJ1t}1f3LP22ZK7Qzg>&V?OgkQ z!TC|mr!(MVzfjGgAx)Wu;=%bN@o#hrzxsP`KjcX`<`rJ5u0pSnRQmqx+w>PsN@KIr zOLKCDPsA!5FUBWa9=a?qXLWR5o;MLX8`9>LeRcDp^h{^px0Clj>lIUe%1X%%<_xd3 z4lmDr9X=kUBr6*CJ!DJP!6|WUYGY&Vf#J(p_bq-7FEwx9;Oek9g$~-agZ6<~LlGk( zwc012c0AV>OHK{Gp{0yWP5nZ?*ABi}O(G19ob?IWUJVvq+Th1|(Juwdd&`TGT1xW7 zhu)@VX1+LDlourghO|BzHRI>hVBhG zdGQTi=Kp%k-96yb*x37-=kKS-*E&PCo?r{_mzte+nwZh4wfuQK@D1~C+wEU_LI10p zGyiMq*aCPGq6UQ~tg<&CvRP;XE+L_Uh^b4Y2r7c93Rn~c9$_sCLT!{KY!-#ERe30s zr-Bd=Ls*n05ed+OfGHvm&|nH0LqH8{Ptg7W@7MR+nfaV^@0qzX_s*R;=bMorbC&&F z>`Zk={EWdNVAl|#25VkDw?qUX8G$^3L!utyQRu`SXw3hg0{e+<`B=#Mf-YI#A8#b* z;-l|3#F2c4uR9Bz9~MK`SB9F{<;I+voRvua=#$9;tKxZ6%d7;1#YRXM{s0?)(dQev z4@hKkJpFi)Z7vpzy*(J|xEx4Zntrpz?5#IEw?^SI2ftVV9qO-L$mSQ(1?t{D2+#7rwhw`fZ^!;iXirw1=j&fSn(u zxArV{7rUrFPlK*^a!%5(UNSdkoN2i$|8_8LC@Fk^H@4th-CJa|h`LAKNwouzzT z>B7E(@bew<_YW|MVGR4NhWtre|G)rUn|yu!P}&qRaI5%+hHeCmsVVc)t>Slj-p24T zX8Y1YgpYji!aa$EE$d=WX%8AHM@;^u26RGB!c13ZB*-IKw5SWyOMeU5X+-rG54?^kiv_uH3M18qLa6#RcNDjQ$b-t3UA7 z*qK&38sl&;H|&dO4f}1#79;=EfW5hlDnC0E)6uEjNWdKPZH0b`c#z_lAt~h7UKYV% zu1fdG=qME2S}7D4bv)h5xaGGU#f)v+EI1g9^1A>c>F^nUMv)&NXJSbP@xFDRIu-q!is?I05?X6A7C&XW7pYl57D-!CK5KStD>&=)`buf_O+u~RRDN! z1lNrP4T9Zc^{z;ehuaziB$M%#LLPUO{vrAy2!tVU_yU32K@j;`4F7H(fRh@EVCa}apF_kMoCkqHwj2r8WGLPT-$JbRV?8Dnovh`_qaFp%S0 z>4GRG#GGDwrWOu6dQ^xO^GNQ(C*51cgnge|M(y;+OPddvuR^*KhuG?(q5X7MaMB~K zRW&JG&D0TtdlH+b$XYz|(=K3STnx4}YSVT71&7zZX*qy9cjC$=MDa}?TT3*&i%ziu zLef?K+xgzMA}2KF2cJ%!rQk+(5~BFdAt7suiruBDf!B`Kb=bgrhhoy;=0QQ#6kFPE zXbl|dP$-%ER$F6msq?y=4ad1@n^r4tem+@orAIRA4p0a50CDGZ-hR3*MD}Mr@)BN& z6RwNw)xh5jGvb(kDf-W$UZPdUBMr&%Fbr7%grAS4WgTTXj3PWhI5f}Y$BAt!G*1Es zXv|)`cPYwn5aS893?0tK1ehpjE|7@AsB`nd2vcjMt63c}V49-XaTpwp6fX`&(G4Lv zBrDZclE6V0!BFFp%mM4;Vo5~0+UMslxT|Q{J2-VvFD_I^UDSpd)hpAUEPE3{*WA4) zF)MSM#QDbr_iz-Gc}E-{uxKYz#o1SvcwF#6B3<{E5n1m$mm;RM@Gqav6D4z&o>1!< zL(G0Jv8sUB8kfg^nFD0z?)VCPrlyV!oRAPbbCmCLIE$<`F z0OjRwv$|=H)Dw$z4Q;gL*QfWW>)`O_G0n;4wd-PJ<;C#!nVFMFn;J7S)gT$^mJ{rBudR5;l~Xb6s%FwsLXl_*x^UV-Z=Ja;t#&E2^@|lkyFp9;%xc` znr7Pf#C@e?Uv2HYoD(3T?Cu9!$5csO^q}wY13BWB2q0WzL9)QqkwA=K3W^KmEmylTan@{@u+AVg)`Y2|7 zzpm-GJu=qLML=KO4%#u0eV{kRw*%t3XF{7Wq44!Q|!k4Z|*TC1jT-a>!#>uYm;|>lQlkOAvSJ;?H zXTKJHvt?JvK~t0GDE?U4`Gxci&@sKMe&SV;_pAn^+VlsGY9B@7$RLQ-3R(Ya6Zq;B{?Rl zIC3?amu#KjR8V_YJOkLbyopXh)vu>Q+@&?A%V3djH(WSu(%TR-UvuGIQ{h`x+}vzP z6t`(u+Vyz0Z+zM<@?i`L4Sy(|w*@7vuKCIMx_j=v8YgN n>qlPqH2WXdzKOZH%PPgU&i^W9rltTL5V2>MyIY0piHm;&e`6T# literal 0 HcmV?d00001 diff --git a/misc/rofi/config.rasi b/misc/rofi/config.rasi new file mode 100644 index 00000000..52af15b4 --- /dev/null +++ b/misc/rofi/config.rasi @@ -0,0 +1,149 @@ +configuration { +modi: "window,run,ssh,drun"; +/* width: 50;*/ +lines: 15; +/* columns: 1;*/ +font: "Cascadia Code 12"; +/* bw: 1;*/ +/* location: 0;*/ +/* padding: 5;*/ +/* yoffset: 0;*/ +/* xoffset: 0;*/ +/* fixed-num-lines: true;*/ +/* show-icons: false;*/ +/* terminal: "rofi-sensible-terminal";*/ +/* ssh-client: "ssh";*/ +/* ssh-command: "{terminal} -e {ssh-client} {host} [-p {port}]";*/ +/* run-command: "{cmd}";*/ +/* run-list-command: "";*/ +/* run-shell-command: "{terminal} -e {cmd}";*/ +/* window-command: "wmctrl -i -R {window}";*/ +/* window-match-fields: "all";*/ +/* icon-theme: ;*/ +/* drun-match-fields: "name,generic,exec,categories";*/ +/* drun-show-actions: false;*/ +/* drun-display-format: "{name} [({generic})]";*/ +/* disable-history: false;*/ +/* ignored-prefixes: "";*/ +/* sort: false;*/ +/* sorting-method: ;*/ +/* case-sensitive: false;*/ +/* cycle: true;*/ +/* sidebar-mode: false;*/ +/* eh: 1;*/ +/* auto-select: false;*/ +/* parse-hosts: false;*/ +/* parse-known-hosts: true;*/ +/* combi-modi: "window,run";*/ +/* matching: "normal";*/ +/* tokenize: true;*/ +/* m: "-5";*/ +/* line-margin: 2;*/ +/* line-padding: 1;*/ +/* filter: ;*/ +/* separator-style: "dash";*/ +/* hide-scrollbar: false;*/ +/* fullscreen: false;*/ +/* fake-transparency: false;*/ +/* dpi: -1;*/ +/* threads: 0;*/ +/* scrollbar-width: 8;*/ +/* scroll-method: 0;*/ +/* fake-background: "screenshot";*/ +/* window-format: "{w} {c} {t}";*/ +/* click-to-exit: true;*/ +/* show-match: true;*/ +/* theme: ;*/ +/* color-normal: ;*/ +/* color-urgent: ;*/ +/* color-active: ;*/ +/* color-window: ;*/ +/* max-history-size: 25;*/ +/* combi-hide-mode-prefix: false;*/ +/* matching-negate-char: '-' /* unsupported */;*/ +/* cache-dir: ;*/ +/* pid: "/run/user/1000/rofi.pid";*/ +/* display-window: ;*/ +/* display-windowcd: ;*/ +/* display-run: ;*/ +/* display-ssh: ;*/ +/* display-drun: ;*/ +/* display-combi: ;*/ +/* display-keys: ;*/ +/* kb-primary-paste: "Control+V,Shift+Insert";*/ +/* kb-secondary-paste: "Control+v,Insert";*/ +/* kb-clear-line: "Control+w";*/ +/* kb-move-front: "Control+a";*/ +/* kb-move-end: "Control+e";*/ +/* kb-move-word-back: "Alt+b,Control+Left";*/ +/* kb-move-word-forward: "Alt+f,Control+Right";*/ +/* kb-move-char-back: "Left,Control+b";*/ +/* kb-move-char-forward: "Right,Control+f";*/ +/* kb-remove-word-back: "Control+Alt+h,Control+BackSpace";*/ +/* kb-remove-word-forward: "Control+Alt+d";*/ +/* kb-remove-char-forward: "Delete,Control+d";*/ +/* kb-remove-char-back: "BackSpace,Shift+BackSpace,Control+h";*/ +/* kb-remove-to-eol: "Control+k";*/ +/* kb-remove-to-sol: "Control+u";*/ +/* kb-accept-entry: "Control+j,Control+m,Return,KP_Enter";*/ +/* kb-accept-custom: "Control+Return";*/ +/* kb-accept-alt: "Shift+Return";*/ +/* kb-delete-entry: "Shift+Delete";*/ +/* kb-mode-next: "Shift+Right,Control+Tab";*/ +/* kb-mode-previous: "Shift+Left,Control+ISO_Left_Tab";*/ +/* kb-row-left: "Control+Page_Up";*/ +/* kb-row-right: "Control+Page_Down";*/ +/* kb-row-up: "Up,Control+p,ISO_Left_Tab";*/ +/* kb-row-down: "Down,Control+n";*/ +/* kb-row-tab: "Tab";*/ +/* kb-page-prev: "Page_Up";*/ +/* kb-page-next: "Page_Down";*/ +/* kb-row-first: "Home,KP_Home";*/ +/* kb-row-last: "End,KP_End";*/ +/* kb-row-select: "Control+space";*/ +/* kb-screenshot: "Alt+S";*/ +/* kb-ellipsize: "Alt+period";*/ +/* kb-toggle-case-sensitivity: "grave,dead_grave";*/ +/* kb-toggle-sort: "Alt+grave";*/ +/* kb-cancel: "Escape,Control+g,Control+bracketleft";*/ +/* kb-custom-1: "Alt+1";*/ +/* kb-custom-2: "Alt+2";*/ +/* kb-custom-3: "Alt+3";*/ +/* kb-custom-4: "Alt+4";*/ +/* kb-custom-5: "Alt+5";*/ +/* kb-custom-6: "Alt+6";*/ +/* kb-custom-7: "Alt+7";*/ +/* kb-custom-8: "Alt+8";*/ +/* kb-custom-9: "Alt+9";*/ +/* kb-custom-10: "Alt+0";*/ +/* kb-custom-11: "Alt+exclam";*/ +/* kb-custom-12: "Alt+at";*/ +/* kb-custom-13: "Alt+numbersign";*/ +/* kb-custom-14: "Alt+dollar";*/ +/* kb-custom-15: "Alt+percent";*/ +/* kb-custom-16: "Alt+dead_circumflex";*/ +/* kb-custom-17: "Alt+ampersand";*/ +/* kb-custom-18: "Alt+asterisk";*/ +/* kb-custom-19: "Alt+parenleft";*/ +/* kb-select-1: "Super+1";*/ +/* kb-select-2: "Super+2";*/ +/* kb-select-3: "Super+3";*/ +/* kb-select-4: "Super+4";*/ +/* kb-select-5: "Super+5";*/ +/* kb-select-6: "Super+6";*/ +/* kb-select-7: "Super+7";*/ +/* kb-select-8: "Super+8";*/ +/* kb-select-9: "Super+9";*/ +/* kb-select-10: "Super+0";*/ +/* ml-row-left: "ScrollLeft";*/ +/* ml-row-right: "ScrollRight";*/ +/* ml-row-up: "ScrollUp";*/ +/* ml-row-down: "ScrollDown";*/ +/* me-select-entry: "MousePrimary";*/ +/* me-accept-entry: "MouseDPrimary";*/ +/* me-accept-custom: "Control+MouseDPrimary";*/ +} +@import "/home/yigit/.config/rofi/themes/dmenu.rasi" + + +/* vim:ft=css diff --git a/misc/rofi/music_menu b/misc/rofi/music_menu new file mode 100755 index 00000000..43bc6a17 --- /dev/null +++ b/misc/rofi/music_menu @@ -0,0 +1,10 @@ +action=$(echo ' +' | rofi -dmenu -theme music_actions ) + +if [ $action = '' ] +then + playerctl previous & +elif [ $action = '' ] +then + playerctl next & +fi diff --git a/misc/rofi/sidebar-mod.rasi b/misc/rofi/sidebar-mod.rasi new file mode 100644 index 00000000..cbae1d6c --- /dev/null +++ b/misc/rofi/sidebar-mod.rasi @@ -0,0 +1,109 @@ +/** + * User: qball + * Copyright: Dave Davenport + */ +* { + text-color: #f4f2f0; + background-color: rgba(0,0,0,0); + dark: #2c2541; + // Black + black: #3d335c; + lightblack: #483c6c; + // + // Red + red: #cd5c5c; + lightred: #cc5533; + // + // Green + green: #86af80; + lightgreen: #88cc22; + // + // Yellow + yellow: #e8ae5b; + lightyellow: #ffa75d; + // + // Blue + blue: #6495ed; + lightblue: #87ceeb; + // + // Magenta + magenta: #deb887; + lightmagenta: #996600; + // + // Cyan + cyan: #b0c4de; + lightcyan: #b0c4de; + // + // White + white: #bbaa99; + lightwhite: #ddccbb; + // + // Bold, Italic, Underline + highlight: bold #ffffff; +} +#window { + height: 50%; + width: 15em; + location: north east; + anchor: north east; + border: 0px 0px 0px 0px; + x-offset: -30px; + y-offset: 39px; + text-color: @lightwhite; + border-radius: 0px 0px 19px 19px; +} + +#mode-switcher { + border: 2px 0px 0px 0px; + background-color: @lightblack; + padding: 4px; +} +#button selected { + border-color: @lightgreen; + text-color: @lightgreen; +} +#inputbar { + background-color: #2c2541; + text-color: @lightgreen; + padding: 4px 4px 4px 4px; + border: 0px 0px 0px 0px; +} +#mainbox { + expand: true; + background-color: #1c1c1cee; + spacing: 1em; +} +#listview { + padding: 0em 1em 0em 1em; + dynamic: false; + lines: 0; +} + +#prompt { +margin: 0px 6px 0px 0px; +} +#element selected normal { + background-color: #da0f7a; +} +#element normal active { + text-color: @lightblue; +} +#element normal urgent { + text-color: @lightred; +} +#element alternate normal { +} +#element alternate active { + text-color: @lightblue; +} +#element alternate urgent { + text-color: @lightred; +} +#element selected active { + background-color: @lightblue; + text-color: @dark; +} +#element selected urgent { + background-color: @lightred; + text-color: @dark; +} diff --git a/misc/rofi/themes/denvit.rasi b/misc/rofi/themes/denvit.rasi new file mode 100644 index 00000000..72843d86 --- /dev/null +++ b/misc/rofi/themes/denvit.rasi @@ -0,0 +1,149 @@ +/* vim:ft=css */ +/************************************************ + * ROFI Color theme + * User: leofa + * Copyright: 2017 leofa + ***********************************************/ + +* { + selected-normal-foreground: rgba ( 249, 249, 249, 100 % ); + foreground: rgba ( 248, 248, 242, 100 % ); + normal-foreground: @foreground; + alternate-normal-background: rgba ( 35, 49, 63, 95%); + red: rgba ( 189, 147, 249, 100 % ); + selected-urgent-foreground: rgba ( 249, 249, 249, 100 % ); + blue: rgba ( 38, 139, 210, 100 % ); + urgent-foreground: rgba ( 204, 102, 102, 100 % ); + alternate-urgent-background: rgba ( 75, 81, 96, 90 % ); + active-foreground: rgba ( 101, 172, 255, 100 % ); + lightbg: rgba ( 238, 232, 213, 100 % ); + selected-active-foreground: rgba ( 249, 249, 249, 100 % ); + alternate-active-background: rgba ( 52,73,94, 60%); + background: rgba ( 189, 147, 249, 95 % ); + alternate-normal-foreground: @foreground; + normal-background: @background; + + lightfg: rgba ( 88, 104, 117, 100 % ); + selected-normal-background: rgba ( 189, 147, 249, 100 % ); + border-color: rgba ( 124, 131, 137, 100 % ); + spacing: 2; + separatorcolor: rgba ( 29, 31, 33, 100 % ); + urgent-background: rgba ( 29, 31, 33, 17 % ); + selected-urgent-background: rgba ( 189, 147, 249, 100 % ); + alternate-urgent-foreground: @urgent-foreground; + background-color: rgba ( 0, 0, 0, 0 % ); + alternate-active-foreground: @active-foreground; + active-background: rgba ( 29, 31, 33, 17 % ); + selected-active-background: rgba ( 189, 147, 249, 100 % ); +} +#window { + background-color: @background; + border: 1; + padding: 5; +} +#mainbox { + border: 0; + padding: 0; +} +#message { + border: 2px 0px 0px ; + border-color: @separatorcolor; + padding: 1px ; +} +#textbox { + text-color: @foreground; +} +#listview { + fixed-height: 0; + border: 0px 0px 0px ; + border-color: @separatorcolor; + spacing: 2px ; + scrollbar: true; + padding: 2px 0px 0px ; +} +#element { + border: 0; + padding: 1px; +} +#element.normal.normal { + background-color: @normal-background; + text-color: @normal-foreground; +} +#element.normal.urgent { + background-color: @urgent-background; + text-color: @urgent-foreground; +} +#element.normal.active { + background-color: @active-background; + text-color: @active-foreground; +} +#element.selected.normal { + background-color: @selected-normal-background; + text-color: @selected-normal-foreground; +} +#element.selected.urgent { + background-color: @selected-urgent-background; + text-color: @selected-urgent-foreground; +} +#element.selected.active { + background-color: @selected-active-background; + text-color: @selected-active-foreground; +} +#element.alternate.normal { + background-color: @alternate-normal-background; + text-color: @alternate-normal-foreground; +} +#element.alternate.urgent { + background-color: @alternate-urgent-background; + text-color: @alternate-urgent-foreground; +} +#element.alternate.active { + background-color: @alternate-active-background; + text-color: @alternate-active-foreground; +} +#scrollbar { + width: 4px ; + border: 0; + handle-color: @normal-foreground; + handle-width: 8px ; + padding: 0; +} +#sidebar { + border: 0px 0px 0px; + padding: 5px 0 0; + border-color: @separatorcolor; +} +#button { + spacing: 0; + text-color: @normal-foreground; +} +#button.selected { + background-color: @selected-normal-background; + text-color: @selected-normal-foreground; +} +#inputbar { + spacing: 0; + text-color: @normal-foreground; + padding: 1px ; +} +#case-indicator { + spacing: 0; + text-color: @normal-foreground; +} +#entry { + spacing: 0; + text-color: @normal-foreground; +} +#prompt { + spacing: 0; + text-color: @normal-foreground; +} +#inputbar { + children: [ prompt,textbox-prompt-colon,entry,case-indicator ]; +} +#textbox-prompt-colon { + expand: false; + str: ":"; + margin: 0px 0.3em 0em 0em ; + text-color: @normal-foreground; +} diff --git a/misc/rofi/themes/dmenu.rasi b/misc/rofi/themes/dmenu.rasi new file mode 100644 index 00000000..ffa214ca --- /dev/null +++ b/misc/rofi/themes/dmenu.rasi @@ -0,0 +1,44 @@ +/** + * ROFI Color theme + * User: Qball + * Copyright: Dave Davenport + */ +* { + background-color: rgba(40, 42, 54, 1); + border-color: rgba(248, 248, 242, 1); + text-color: rgba(248, 248, 242, 1); + font: "Hack Nerd Font 10"; +} + +window { + anchor: north; + location: north; + width: 100%; + padding: 6px; + children: [ horibox ]; +} + +horibox { + orientation: horizontal; + children: [ prompt, entry, listview ]; +} + +listview { + layout: horizontal; + spacing: 5px; + lines: 100; +} + +entry { + expand: false; + width: 10em; +} + +element { + padding: 0px 2px; +} +element selected { + background-color: rgba(189, 147, 249, 1); +} + +/* vim:ft=css diff --git a/misc/zathura/a b/misc/zathura/a new file mode 100644 index 00000000..e3079b59 --- /dev/null +++ b/misc/zathura/a @@ -0,0 +1,4 @@ +set synctex true +set synctex-editor-command "vim +%{line} %{input}" + +map recolor diff --git a/misc/zathura/zathurarc b/misc/zathura/zathurarc new file mode 100644 index 00000000..3cf62cf4 --- /dev/null +++ b/misc/zathura/zathurarc @@ -0,0 +1,64 @@ +# Zathura configuration file +# See man `man zathurarc' + +# Open document in fit-width mode by default +set adjust-open "best-fit" + +# One page per row by default +set pages-per-row 1 + +#stop at page boundries +set scroll-page-aware "true" +set smooth-scroll "true" +set scroll-full-overlap 0.01 +set scroll-step 100 + +#zoom settings +set zoom-min 10 +set guioptions "" + +# zathurarc-dark + +set font "inconsolata 15" +set default-bg "#000000" #00 +set default-fg "#F7F7F6" #01 + +set statusbar-fg "#B0B0B0" #04 +set statusbar-bg "#202020" #01 + +set inputbar-bg "#151515" #00 currently not used +set inputbar-fg "#FFFFFF" #02 + +set notification-error-bg "#AC4142" #08 +set notification-error-fg "#151515" #00 + +set notification-warning-bg "#AC4142" #08 +set notification-warning-fg "#151515" #00 + +set highlight-color "#F4BF75" #0A +set highlight-active-color "#6A9FB5" #0D + +set completion-highlight-fg "#151515" #02 +set completion-highlight-bg "#90A959" #0C + +set completion-bg "#303030" #02 +set completion-fg "#E0E0E0" #0C + +set notification-bg "#90A959" #0B +set notification-fg "#151515" #00 + +set recolor "true" +set recolor-lightcolor "#000000" #00 +set recolor-darkcolor "#E0E0E0" #06 +set recolor-reverse-video "true" +set recolor-keephue "true" +map recolor + + + +set render-loading "false" +set scroll-step 50 +unmap f +map f toggle_fullscreen +map [fullscreen] f toggle_fullscreen +set selection-clipboard clipboard diff --git a/scripts/autotrim b/scripts/autotrim new file mode 100755 index 00000000..443988c9 --- /dev/null +++ b/scripts/autotrim @@ -0,0 +1,163 @@ +#!/usr/bin/perl +# +# "Beautify" quoted message and make it "ready-to-reply" by Michael Velten + +use utf8; + +# keep quotes nested up to 3rd level +my $ind_max = 4; + +my $name = '[[:alpha:]]+([\'`-][[:alpha:]]+|[.])*'; +my $fullname = '\b(' . $name . '[,]?\s+)*' . $name . '\b'; + +# Possible reply greetings (regexes) (note that '> ' will be prefixed) +my @greetings = ( + 'Dear\s+' . $fullname . '([,.]|\s*!)?', + '[Hh](ello|i|ey)' . '(\s+' . $fullname . ')?' . '([,.]|\s*!)?', + 'Sehr geehrter?\s+' . $fullname . '([,.]|\s*!)?', + 'Lieber?\s+' . $fullname . '([,.]|\s*!)?', + 'Guten Tag' . '(\s+' . $fullname . ')?' . '([,.]|\s*!)?', + '[Hh]allo' . '(\s+' . $fullname . ')?' . '([,.]|\s*!)?', + '[Mm]oin' . '(\s+' . $fullname . ')?' . '([,.]|\s*!)?', + '[Mm]esdames(,| et) [Mm]essieurs([,.]|\s*!)?', + 'M(adame)\s+' . $fullname . '([,.]|\s*!)?', + 'M(onsieur)\s+' . $fullname . '([,.]|\s*!)?', + '[Cc]her\s+' . $fullname . '([,.]|\s*!)?', + '[Cc]h[eè]re\s+' . $fullname . '([,.]|\s*!)?', + '[Bb]onjour' . '(\s+' . $fullname . ')?' . '([,.]|\s*!)?', + '[Ss]alut' . '(\s+' . $fullname . ')?' . '([,.]|\s*!)?', + 'Senhor(ita|a)?' . '(\s+' . $fullname . ')?' . '([,.]|\s*!)?', + 'Sra?\.?' . '(\s+' . $fullname . ')?' . '([,.]|\s*!)?', + 'Car([ií]ssim)?[ao]s?' . '(\s+' . $fullname . ')?' . '([,.]|\s*!)?', + 'Prezad([ií]ssim)?[ao]s?' . '(\s+' . $fullname . ')?' . '([,.]|\s*!)?', + 'Estimad([ií]ssim)?[ao]s?' . '(\s+' . $fullname . ')?' . '([,.]|\s*!)?', + '[Bb]om [Dd]ia' . '(\s+' . $fullname . ')?' . '([,.]|\s*!)?', + '[Bb]oa ([Tt]arde|[Nn]oite)' . '(\s+' . $fullname . ')?' . '([,.]|\s*!)?', + '[Oo](i|l[aá])' . '(\s+' . $fullname . ')?' . '([,.]|\s*!)?', + '[Aa]l[ôo]' . '(\s+' . $fullname . ')?' . '([,.]|\s*!)?', + '[Hh]ola' . '(\s+' . $fullname . ')?' . '([,.]|\s*!)?', + 'Se[nñ]or(ita|a)?' . '(\s+' . $fullname . ')?' . '([,.]|\s*!)?', + ); + +# Possible reply "greetouts" (regexes) (note that '> ' will be prefixed) +my @greetouts = ( + '([Ww]ith )?(([Kk]ind|[Bb]est|[Ww]arm) )?([Rr]egards|[Ww]ishes)([,.]|\s*!)?', + '[Bb]est([,.]|\s*!)?', + '[Cc]heers([,.]|\s*!)?', + '[Mm]it ([Vv]iel|[Bb]est|[Ll]ieb|[Ff]reundlich)en [Gg]r([ü]|ue)([ß]|ss)en([,.]|\s*!)?', + '(([Vv]iel|[Bb]est|[Ll]ieb|[Ff]reundlich)e )?[Gg]r([ü]|ue)([ß]|ss)e([,.]|\s*!)?', + '(([[Bb]est|[Ll]ieb|[Ff]reundlich)e[rn] )?[Gg]ru([ß]|ss)([,.]|\s*!)?', + '[Mm]it (([[Bb]est|[Ll]ieb|[Ff]reundlich)em )?[Gg]ru([ß]|ss)([,.]|\s*!)?', + '([LV]|MF)G([,.]|\s*!)?', + '(([Tt]r[eè]s|[Bb]ien) )?([Cc]ordi|[Aa]mic)alement([,.]|\s*!)?', + '[Aa]miti[eé]s?([,.]|\s*!)?', + '[Aa]tenciosamente([,.]|\s*!)?', + '[Aa]tt([,.]|\s*!)?', + '[Aa]bra[cç]os?([,.]|\s*!)?', + '[Aa]tentamente([,.]|\s*!)?', + '[Cc]ordialmente([,.]|\s*!)?', + ); + +my $word = '[[:alpha:]]+([\'`-][[:alpha:]]+)*'; + +# my $saw_greeting = 0; +# my $saw_greetout = 0; +my $saw_own_sig = 0; +my $saw_blank_line = 0; +my $inds_other_sig = 0; +my $quote_header = 0; +my $extra_pref = ''; + +my (@mail, @purged_mail); + +my $msg = shift; +die "Usage: $0 MAIL" unless $msg; +open(MAIL, "+<:encoding(UTF-8)", $msg) or die "$0: Can't open $msg: $!"; +push(@mail, $_) while ; # Read whole mail + +# Process whole mail +LINE: +foreach my $line (@mail) { + +# Treat non-quoted lines as is + if ($line !~ /^>/) { + push(@purged_mail, $line); + next LINE; + } + +# Keep all lines after my own signature unmodified + if ($line =~ /^--\s?$/ || $saw_own_sig) { + $saw_own_sig = 1; + push(@purged_mail, $line); + next LINE; + } + + # $line =~ tr/\xA0/ /; +# tighten "> > " to ">> " + my ($pref, $suff) = $line =~ /^([>[:space:]]+)(.*)$/; + $pref =~ s/(>\s*(?!$))/>/g; +# reduce multiple pre- and post-blanks to one post-blank + $pref =~ s/^\s*(>+)\s*/$1 /; + $line = $pref . $suff . "\n"; + +# prepend additional '>' for each Outlook quote header + if ($line =~ /^>+ [-_=]{3,}\s*$word(\s+$word)*\s*[-_=]{3,}$/) { + $quote_header = 1; + next LINE; + } +# first line after Outlook quote header that does not start with ...: + if ($quote_header == 1 && $line !~ /^>+ ([-*]\s*)?$word(\s+$word)*\s*:\s+/) { + $extra_pref = '>' . $extra_pref; + $quote_header = 0; + } + $pref = $extra_pref . $pref; + $line = $pref . $suff . "\n"; + +# skip line if number of '>'s is greater than $ind_max + my $inds = $pref =~ tr/>//; + next LINE if $inds > $ind_max; + +# Remove other signatures + if ($line =~ /^>+ --\s?$/) { + $inds_other_sig = $inds; + } + if ($inds == $inds_other_sig) { + next LINE; + } else { + $inds_other_sig = 0; + } + +# Remove quoted greeting + # unless ($saw_greeting) { + foreach my $greeting (@greetings) { + if ($line =~ /^>+ $greeting$/) { + # $saw_greeting = 1; + next LINE; + } + } + # } + +# Remove quoted "greetout" + # unless ($saw_greetout) { + foreach my $greetout (@greetouts) { + if ($line =~ /^>+ $greetout$/) { + # $saw_greetout = 1; + next LINE; + } + } + # } + +# Remove quoted filler lines + if ($line =~ /^>+ \s*(-*|_*|=*|\+*|#*|\**)$/) { + next LINE; + } + +# Save purged line + push(@purged_mail, $line); +} + +# Overwrite original mail with purged mail +truncate(MAIL, 0); +seek(MAIL, 0, 0); +print MAIL @purged_mail; +close(MAIL); diff --git a/scripts/bluetooth_battery.py b/scripts/bluetooth_battery.py new file mode 100755 index 00000000..aade63e6 --- /dev/null +++ b/scripts/bluetooth_battery.py @@ -0,0 +1,89 @@ +#!/usr/bin/env python3 + +""" +A python script to get battery level from Bluetooth headsets +""" + +# License: GPL-3.0 +# Author: @TheWeirdDev +# 29 Sept 2019 + +import errno +import bluetooth +import sys + + +def send(sock, message): + sock.send(b"\r\n" + message + b"\r\n") + + +def getATCommand(sock, line, device): + blevel = -1 + + if b"BRSF" in line: + send(sock, b"+BRSF: 1024") + send(sock, b"OK") + elif b"CIND=" in line: + send(sock, b"+CIND: (\"battchg\",(0-5))") + send(sock, b"OK") + elif b"CIND?" in line: + send(sock, b"+CIND: 5") + send(sock, b"OK") + elif b"BIND=?" in line: + # Announce that we support the battery level HF indicator + # https://www.bluetooth.com/specifications/assigned-numbers/hands-free-profile/ + send(sock, b"+BIND: (2)") + send(sock, b"OK") + elif b"BIND?" in line: + # Enable battery level HF indicator + send(sock, b"+BIND: 2,1") + send(sock, b"OK") + elif b"XAPL=" in line: + send(sock, b"+XAPL: iPhone,7") + send(sock, b"OK") + elif b"IPHONEACCEV" in line: + parts = line.strip().split(b',')[1:] + if len(parts) > 1 and (len(parts) % 2) == 0: + parts = iter(parts) + params = dict(zip(parts, parts)) + if b'1' in params: + blevel = (int(params[b'1']) + 1) * 10 + elif b"BIEV=" in line: + params = line.strip().split(b"=")[1].split(b",") + if params[0] == b"2": + blevel = int(params[1]) + else: + send(sock, b"OK") + + if blevel != -1: + print(f"Battery level for {device} is {blevel}%") + return False + + return True + + +def main(): + if (len(sys.argv) < 2): + print("Usage: bl_battery.py [.PORT] ...") + print(" Port number is optional (default = 4)") + exit() + else: + for device in sys.argv[1:]: + i = device.find('.') + if i == -1: + port = 4 + else: + port = int(device[i+1:]) + device = device[:i] + try: + s = bluetooth.BluetoothSocket(bluetooth.RFCOMM) + s.connect((device, port)) + while getATCommand(s, s.recv(128), device): + pass + s.close() + except OSError as e: + print(f"{device} is offline", e) + + +if __name__ == "__main__": + main() diff --git a/scripts/convertToHtmlMultipart b/scripts/convertToHtmlMultipart new file mode 100755 index 00000000..74073e12 --- /dev/null +++ b/scripts/convertToHtmlMultipart @@ -0,0 +1,239 @@ +#!/usr/bin/env python3 +# Original Source: https://github.com/oblitum/dotfiles/blob/ArchLinux/.local/bin/MIMEmbellish + +import re +import sys +import email +import shlex +import mimetypes +import subprocess +from copy import copy +from hashlib import md5 +from email import charset +from email import encoders +from email.mime.text import MIMEText +from email.mime.multipart import MIMEMultipart +from email.mime.nonmultipart import MIMENonMultipart +from os.path import basename, splitext, expanduser + + +charset.add_charset('utf-8', charset.SHORTEST, '8bit') + + +def pandoc(from_format, to_format='markdown', plain='markdown', title=None): + markdown = ('markdown' + '-blank_before_blockquote') + + if from_format == 'plain': + from_format = plain + if from_format == 'markdown': + from_format = markdown + if to_format == 'markdown': + to_format = markdown + + command = 'pandoc -f {} -t {} --standalone --highlight-style=tango' + if to_format in ('html', 'html5'): + if title is not None: + command += ' --variable=pagetitle:{}'.format(shlex.quote(title)) + command += ' --webtex --template={}'.format( + expanduser('~/.pandoc/templates/email.html')) + return command.format(from_format, to_format) + + +def gmailfy(payload): + return payload.replace('
', + '
') + + +def make_alternative(message, part): + alternative = convert(part, 'html', + pandoc(part.get_content_subtype(), + to_format='html', + title=message.get('Subject'))) + alternative.set_payload(gmailfy(alternative.get_payload())) + return alternative + + +def make_replacement(message, part): + return convert(part, 'plain', pandoc(part.get_content_subtype())) + + +def convert(part, to_subtype, command): + payload = part.get_payload() + if isinstance(payload, str): + payload = payload.encode('utf-8') + else: + payload = part.get_payload(None, True) + if not isinstance(payload, bytes): + payload = payload.encode('utf-8') + process = subprocess.run( + shlex.split(command), + input=payload, stdout=subprocess.PIPE, check=True) + return MIMEText(process.stdout, to_subtype, 'utf-8') + + +def with_alternative(parent, part, from_signed, + make_alternative=make_alternative, + make_replacement=None): + try: + alternative = make_alternative(parent or part, from_signed or part) + replacement = (make_replacement(parent or part, part) + if from_signed is None and make_replacement is not None + else part) + except: + return parent or part + envelope = MIMEMultipart('alternative') + if parent is None: + for k, v in part.items(): + if (k.lower() != 'mime-version' + and not k.lower().startswith('content-')): + envelope.add_header(k, v) + del part[k] + envelope.attach(replacement) + envelope.attach(alternative) + if parent is None: + return envelope + payload = parent.get_payload() + payload[payload.index(part)] = envelope + return parent + + +def tag_attachments(message): + if message.get_content_type() == 'multipart/mixed': + for part in message.get_payload(): + if (part.get_content_maintype() in ['image'] + and 'Content-ID' not in part): + filename = part.get_param('filename', + header='Content-Disposition') + if isinstance(filename, tuple): + filename = str(filename[2], filename[0] or 'us-ascii') + if filename: + filename = splitext(basename(filename))[0] + if filename: + part.add_header('Content-ID', '<{}>'.format(filename)) + return message + + +def attachment_from_file_path(attachment_path): + try: + mime, encoding = mimetypes.guess_type(attachment_path, strict=False) + maintype, subtype = mime.split('/') + with open(attachment_path, 'rb') as payload: + attachment = MIMENonMultipart(maintype, subtype) + attachment.set_payload(payload.read()) + encoders.encode_base64(attachment) + if encoding: + attachment.add_header('Content-Encoding', encoding) + return attachment + except: + return None + + +attachment_path_pattern = re.compile(r'\]\s*\(\s*file://(/[^)]*\S)\s*\)|' + r'\]\s*:\s*file://(/.*\S)\s*$', + re.MULTILINE) + + +def link_attachments(payload): + attached = [] + attachments = [] + + def on_match(match): + if match.group(1): + attachment_path = match.group(1) + cid_fmt = '](cid:{})' + else: + attachment_path = match.group(2) + cid_fmt = ']: cid:{}' + attachment_id = md5(attachment_path.encode()).hexdigest() + if attachment_id in attached: + return cid_fmt.format(attachment_id) + attachment = attachment_from_file_path(attachment_path) + if attachment: + attachment.add_header('Content-ID', '<{}>'.format(attachment_id)) + attachments.append(attachment) + attached.append(attachment_id) + return cid_fmt.format(attachment_id) + return match.group() + + return attachments, attachment_path_pattern.sub(on_match, payload) + + +def with_local_attachments(parent, part, from_signed, + link_attachments=link_attachments): + if from_signed is None: + attachments, payload = link_attachments(part.get_payload()) + part.set_payload(payload) + else: + attachments, payload = link_attachments(from_signed.get_payload()) + from_signed = copy(from_signed) + from_signed.set_payload(payload) + if not attachments: + return parent, part, from_signed + if parent is None: + parent = MIMEMultipart('mixed') + for k, v in part.items(): + if (k.lower() != 'mime-version' + and not k.lower().startswith('content-')): + parent.add_header(k, v) + del part[k] + parent.attach(part) + for attachment in attachments: + parent.attach(attachment) + return parent, part, from_signed + + +def is_target(part, target_subtypes): + return (part.get('Content-Disposition', 'inline') == 'inline' + and part.get_content_maintype() == 'text' + and part.get_content_subtype() in target_subtypes) + + +def pick_from_signed(part, target_subtypes): + for from_signed in part.get_payload(): + if is_target(from_signed, target_subtypes): + return from_signed + + +def seek_target(message, target_subtypes=['plain', 'markdown']): + if message.is_multipart(): + if message.get_content_type() == 'multipart/signed': + part = pick_from_signed(message, target_subtypes) + if part is not None: + return None, message, part + elif message.get_content_type() == 'multipart/mixed': + for part in message.get_payload(): + if part.is_multipart(): + if part.get_content_type() == 'multipart/signed': + from_signed = pick_from_signed(part, target_subtypes) + if from_signed is not None: + return message, part, from_signed + elif is_target(part, target_subtypes): + return message, part, None + else: + if is_target(message, target_subtypes): + return None, message, None + return None, None, None + + +def main(): + try: + message = email.message_from_file(sys.stdin) + parent, part, from_signed = seek_target(message) + if (parent, part, from_signed) == (None, None, None): + print(message) + return + tag_attachments(message) + print(with_alternative( + *with_local_attachments(parent, part, from_signed))) + except (BrokenPipeError, KeyboardInterrupt): + pass + + +if __name__ == '__main__': + main() diff --git a/scripts/dmenu-killall b/scripts/dmenu-killall new file mode 100755 index 00000000..1ec89cdf --- /dev/null +++ b/scripts/dmenu-killall @@ -0,0 +1,80 @@ +#!/bin/sh +#description: dmenu for killall +#usage: dmenu-killall is best suited for launching from a shortcut + +#example: dmenu-killall +#a gui menu appears asking for which app to kill + +progname="$(expr "${0}" : '.*/\([^/]*\)')" + +#variables are impractical to save complex cmds because of shell expantion +#therefore functions are required: http://mywiki.wooledge.org/BashFAQ/050 +DMENU() { dmenu -p 'Kill'; } +#looks better on xft powered dmenu: +#https://bugs.launchpad.net/ubuntu/+source/suckless-tools/+bug/1093745 + +_usage() { + printf "%s\\n" "Usage: ${progname} [PATTERN]" + printf "%s\\n" "Dmenu window selector for i3-wm." + printf "%s\\n" + printf "%s\\n" " -h, --help show this message and exit" +} + +_die() { + [ -n "${1}" ] && _die_msg="${1}" || exit 1 + printf "%b%b\\n" "${_die_msg}" ", press to exit" | DMENU + exit 1 +} + +_notify() { + [ -z "${1}" ] && return 1 + kill -9 $(pgrep notify-osd) >/dev/null 2>&1 + if ! DISPLAY=${DISPLAY:-:0} notify-send -t 1000 "${1}" "${2}"; then + if command -v "gxmessage" 2>/dev/null; then + font="Monaco 9" + DISPLAY=${DISPLAY:-:0} gxmessage "${font:+-fn "$font"}" "${1}" "ok" + elif command -v "xmessage" 2>/dev/null; then + font="fixed" + DISPLAY=${DISPLAY:-:0} xmessage "${font:+-fn "$font"}" "${1}" "ok" + fi + fi +} + +_get_process_names() { + printf "%s\\n" "$(command ps xo command= | sed \ + -e "s: .*::; s:.*/::; s/:$//;" \ + -e "s:^\[.*\]$::" -e "/^$/d" \ + -e "s:^$::")" | sort | uniq +} + +if [ ! -t 0 ]; then + #add input comming from pipe or file to $@ + set -- "${@}" $(cat) +fi + +for arg in "${@}"; do #parse options + case "${arg}" in + -h|--help) _usage && exit ;; + esac +done + +if [ -z "${1}" ]; then + if ! command -v "dmenu" >/dev/null 2>&1; then + printf "%s\\n" "${progname}: install 'dmenu' to run this program" >&2 + exit 1 + fi + process_name="$(_get_process_names | DMENU)" +else + process_name="$(_get_process_names | grep -i "${@}" 2>/dev/null | head -1 )" +fi + +if [ -z "${process_name}" ]; then + _die +else + error_msg="$(kill -9 $(pgrep -x "${process_name}") 2>&1 1>/dev/null)" + if [ X"${?}" != X"0" ]; then + _notify "Error" "${error_msg}" + exit 1 + fi +fi +#vim:ft=sh diff --git a/scripts/dmenu-logout b/scripts/dmenu-logout new file mode 100755 index 00000000..6ecfdd63 --- /dev/null +++ b/scripts/dmenu-logout @@ -0,0 +1,61 @@ +#!/bin/sh + +# Set environment +export BSPWM_CONFIG="${XDG_CONFIG_HOME:-$HOME/.config}/bspwm" + +# Function to kill programs +killprogs() { + # Kill udisks-glue + pkill -x udisks-glue + # Kill panel + pkill -x panel + # Kill Redshift + pkill -x redshift +} + +# Restart function +# shellcheck source=/dev/null +restart() { + reboot +} + +# Logout function +logout() { + pkill dwm +} + +# Load dmenu config +# shellcheck source=/dev/null +[ -f "$HOME/.dmenurc" ] && . "$HOME/.dmenurc" || DMENU='dmenu -i' + +# Menu items +items="logout +suspend +reboot +poweroff" + +# Open menu +selection=$(printf '%s' "$items" | $DMENU) + +case $selection in + restart) + restart + ;; + logout) + logout + ;; + hibernate) + systemctl hibernate + ;; + suspend) + systemctl suspend + ;; + reboot) + reboot + ;; + halt|poweroff|shutdown) + shutdown -h now + ;; +esac + +exit diff --git a/scripts/dunst_toggle.sh b/scripts/dunst_toggle.sh new file mode 100755 index 00000000..0634ccef --- /dev/null +++ b/scripts/dunst_toggle.sh @@ -0,0 +1,23 @@ +#!/bin/zsh +getargs() { + while getopts "se" opt + do + case $opt in + s) start="true";; + e) end="true";; + esac + done +} +start_dnd() { + notify-send "DUNST_COMMAND_PAUSE"; +} +end_dnd() { + notify-send "DUNST_COMMAND_RESUME"; + notify-send "Do Not Disturb" "Do Not Disturb mode ended. Notifications will be shown."; +} +main() { + getargs "$@"; + [[ "$start" ]] && start_dnd; + [[ "$end" ]] && end_dnd; +} +main "$@" diff --git a/scripts/gen_tracking_url b/scripts/gen_tracking_url new file mode 100755 index 00000000..7ae42015 --- /dev/null +++ b/scripts/gen_tracking_url @@ -0,0 +1,26 @@ +#!/bin/python + +import sys +from base64 import b64decode +from hashlib import sha256 +from urllib.parse import quote +message = b64decode(sys.argv[1]).decode() + +userid = "1" +key = "Rwb3pUUG8fQAZUs3Q3qwdHH25Fdq8dyJyzUQqERzrCfxavKExfSExQbr8dZXho57abGvTZGdBmSbyXdVM59jDVi4L5ien9xoVHskMdx4FxNXyq7uBPYaAeA62JXzMZT9" +domain = "https://hermes.yigitcolakoglu.com/read" +subject = "NIL" +recipient = "NIL" + +for i in message.split("\n"): + if i.split(" ")[0] == "Subject:": + subject = i[9:] + elif i.split(" ")[0] == "To:": + recipient = i[4:] + +identifier = subject + recipient + userid + key +identifier_hash = sha256(identifier.encode("utf-8")).hexdigest() + +url = "{}/{}/{}/{}/{}".format(domain,userid,quote(subject),quote(recipient),identifier_hash) + +print('![Hermes]({})'.format(url)) diff --git a/scripts/mail_tag.sh b/scripts/mail_tag.sh new file mode 100755 index 00000000..7939c53d --- /dev/null +++ b/scripts/mail_tag.sh @@ -0,0 +1,15 @@ +notmuch tag +g_draft path:"Gmail/draft/**" +notmuch tag +g_sent path:"Gmail/sent/**" +notmuch tag +g_spam path:"Gmail/spam/**" +notmuch tag +g_archive path:"Gmail/archived/**" + +notmuch tag +o_draft path:"Outlook/draft/**" +notmuch tag +o_sent path:"Outlook/sent/**" +notmuch tag +o_spam path:"Outlook/spam/**" +notmuch tag +o_archive path:"Outlook/archive/**" + +notmuch tag +p_draft path:"Private/draft/**" +notmuch tag +p_sent path:"Private/sent/**" +notmuch tag +p_spam path:"Private/spam/**" +notmuch tag +p_archive path:"Private/archive/**" + diff --git a/scripts/mails.sh b/scripts/mails.sh new file mode 100755 index 00000000..d2dedadb --- /dev/null +++ b/scripts/mails.sh @@ -0,0 +1,8 @@ +new=$(notmuch search 'tag:inbox and tag:unread and NOT path:*/archive NOT tag:archive and NOT tag:spam and NOT tag:sent and NOT tag:draft' | wc -l) + +if [[ $new != 0 ]] +then +dunstify --icon='/home/yigit/.icons/mail.png' -a 'New Email' "You have $new new mail." +fi + +echo $new > /home/yigit/.config/mail_num diff --git a/scripts/newmail.sh b/scripts/newmail.sh new file mode 100755 index 00000000..838965ae --- /dev/null +++ b/scripts/newmail.sh @@ -0,0 +1,4 @@ +#!/bin/bash +mbsync $1 +notmuch new +notmuch tag --batch --input=/home/yigit/.notmuch_tag diff --git a/scripts/nm_sendmail.sh b/scripts/nm_sendmail.sh new file mode 100755 index 00000000..2dddabe9 --- /dev/null +++ b/scripts/nm_sendmail.sh @@ -0,0 +1,28 @@ +#!/bin/bash + +# Put the message, send to stdin, in a variable +m="$(cat -)" +m64="$(echo -e "$m" | base64)" +echo "$m64" > /tmp/test2 +tracking_url=$(/home/yigit/.scripts/gen_tracking_url "$m64" 2> /tmp/testerr) +echo $tracking_url > /tmp/test3 +# Look at the first argument, +# Use it to determine the account to use +# If not set, assume work +# All remaining arguments should be recipient addresses which should be passed to msmtp +account="$1" + +shift 1 +cleanHeaders(){ + # In the headers, delete any lines starting with markdown + cat - | sed '0,/^$/{/^markdown/Id;}' +} + +echo "$@" +echo "$message" | cleanHeaders > /tmp/headers +echo "msmtp -a $account $@" +echo "$message" | sed '/^$/q' | grep -q -i 'markdown: true' \ + && msg=$(echo "$message \n$tracking_url" | cleanHeaders | /home/yigit/.scripts/convertToHtmlMultipart && echo 1 >> /tmp/state) || msg=$(echo "$message" | cleanHeaders) +echo "$msg" > /tmp/test +echo "$msg" | notmuch insert --folder="$account/sent" +sent -inbox +echo "$msg" | msmtp -a $account $@ diff --git a/scripts/status-bar/arch b/scripts/status-bar/arch new file mode 100755 index 00000000..690da602 --- /dev/null +++ b/scripts/status-bar/arch @@ -0,0 +1,12 @@ +#!/bin/sh + +icon=󰮯 + +if ! updates=$(checkupdates 2> /dev/null | wc -l ); then + updates=0 +fi + +echo $updates > ~/.cache/pacman_updates + +#echo "$ifg $icon $tfg$(cat ~/.cache/pacman_updates)" +echo "$icon $(cat ~/.cache/pacman_updates)" diff --git a/scripts/status-bar/arch-block b/scripts/status-bar/arch-block new file mode 100755 index 00000000..6621b6d5 --- /dev/null +++ b/scripts/status-bar/arch-block @@ -0,0 +1,17 @@ +#!/bin/sh + +icon=󰮯 +ibg=^b#705B86^ +ifg=^c#fabd2f^ +tfg=^c#292541^ +tbg=^b#cdabb8^ +reset=^d^ + +if ! updates=$(checkupdates 2> /dev/null | wc -l ); then + updates=0t +fi + +echo $updates > ~/.cache/pacman_updates + +echo "$ibg$ifg $icon $tfg$tbg $(cat ~/.cache/pacman_updates) $reset" + diff --git a/scripts/status-bar/battery b/scripts/status-bar/battery new file mode 100755 index 00000000..9b939d1c --- /dev/null +++ b/scripts/status-bar/battery @@ -0,0 +1,37 @@ +#! /bin/sh + +bat=$(cat /sys/class/power_supply/BAT0/capacity) +status=$(cat /sys/class/power_supply/BAT0/status) + +ramp10=󰁺 +ramp20=󰁻 +ramp30=󰁼 +ramp40=󰁽 +ramp50=󰁾 +ramp60=󰁿 +ramp70=󰂀 +ramp80=󰂁 +ramp90=󰂂 +ramp100=󰁹 + +if [[ $bat -lt 10 ]]; then + echo " $ramp10 $bat% " +elif [[ $bat -lt 20 ]]; then + echo " $ramp20 $bat% " +elif [[ $bat -lt "30" ]]; then + echo " $ramp30 $bat% " +elif [[ $bat -lt "40" ]]; then + echo " $ramp40 $bat% " +elif [[ $bat -lt "50" ]]; then + echo " $ramp50 $bat% " +elif [[ $bat -lt "60" ]]; then + echo " $ramp60 $bat% " +elif [[ $bat -lt "70" ]]; then + echo " $ramp70 $bat% " +elif [[ $bat -lt "80" ]]; then + echo " $ramp80 $bat% " +elif [[ $bat -lt "90" ]]; then + echo " $ramp90 $bat% " +elif [[ $bat -le "100" ]]; then + echo " $ramp100 $bat% " +fi diff --git a/scripts/status-bar/battery-blocks b/scripts/status-bar/battery-blocks new file mode 100755 index 00000000..3ee27fdb --- /dev/null +++ b/scripts/status-bar/battery-blocks @@ -0,0 +1,49 @@ +#! /bin/sh + +bat=$(cat /sys/class/power_supply/BAT0/capacity) +status=$(cat /sys/class/power_supply/BAT0/status) + +ramp10=󰁺 +ramp20=󰁻 +ramp30=󰁼 +ramp40=󰁽 +ramp50=󰁾 +ramp60=󰁿 +ramp70=󰂀 +ramp80=󰂁 +ramp90=󰂂 +ramp100=󰁹 + +tbg=^b#cdabb8^ +tfg=^c#292541^ +reset=^d^ + +if [[ $status == "Discharging" ]]; then + ibg=^b#705b86^ +elif [[ $status == "Full" ]]; then + ibg=^b#50FA7B^ +else + ibg=^b#50FA7B^ +fi + +if [[ $bat -lt 10 ]]; then + echo "$ibg$tfg $ramp10 $tbg $bat% $reset" +elif [[ $bat -lt 20 ]]; then + echo "$ibg$tfg $ramp20 $tbg $bat% $reset" +elif [[ $bat -lt "30" ]]; then + echo "$ibg$tfg $ramp30 $tbg $bat% $reset" +elif [[ $bat -lt "40" ]]; then + echo "$ibg$tfg $ramp40 $tbg $bat% $reset" +elif [[ $bat -lt "50" ]]; then + echo "$ibg$tfg $ramp50 $tbg $bat% $reset" +elif [[ $bat -lt "60" ]]; then + echo "$ibg$tfg $ramp60 $tbg $bat% $reset" +elif [[ $bat -lt "70" ]]; then + echo "$ibg$tfg $ramp70 $tbg $bat% $reset" +elif [[ $bat -lt "80" ]]; then + echo "$ibg$tfg $ramp80 $tbg $bat% $reset" +elif [[ $bat -lt "90" ]]; then + echo "$ibg$tfg $ramp90 $tbg $bat% $reset" +elif [[ $bat -le "100" ]]; then + echo "$ibg$tfg $ramp100 $tbg $bat% $reset" +fi diff --git a/scripts/status-bar/capslock b/scripts/status-bar/capslock new file mode 100755 index 00000000..8658f2ca --- /dev/null +++ b/scripts/status-bar/capslock @@ -0,0 +1,14 @@ +#! /bin/sh + +icon=󰘲 +bfg=^b#292541^ +tfg=^c#cc241d^ +reset=^d^ + +cmd=$(cat /sys/class/leds/input3::capslock/brightness) + +if [[ "$cmd" == "1" ]]; then + echo "$tfg$tbg $icon $reset" +else + echo "" +fi diff --git a/scripts/status-bar/clima b/scripts/status-bar/clima new file mode 100755 index 00000000..0b5f119d --- /dev/null +++ b/scripts/status-bar/clima @@ -0,0 +1,12 @@ +#! /bin/sh + +#localización +#initloc=$(curl -s ifconfig.co/city) +#if [ "$initloc" == "La Paz" ]; then +# loc="LAP" +#else +# loc=init-loc +#fi +# obtener clima +#curl -s "wttr.in/$loc?format=%t" +curl -s "wttr.in/?format=%t" diff --git a/scripts/status-bar/clima-icon b/scripts/status-bar/clima-icon new file mode 100755 index 00000000..e1149ba2 --- /dev/null +++ b/scripts/status-bar/clima-icon @@ -0,0 +1,27 @@ +#! /bin/sh + +estado=$(curl -s "wttr.in/?format=%C" ) +case $estado in + Unknown) icon="";; + Cloudy) icon="";; + Fog) icon="";; + "Heavy rain") icon="";; + "Heavy showers") icon="";; + "Heavy snow") icon="";; + "Heavy snow showers") icon="";; + "Light rain") icon="";; + "Light showers") icon="";; + "Light sleet") icon="";; + "Light sleet showers") icon="";; + "Light snow") icon="";; + "Light snow showers") icon="";; + "Partly cloudy") icon="";; + "Sunny") icon="";; + "Clear") icon="";; + "Thundery heavy rain") icon="";; + "Thundery showers") icon="";; + "Thundery snow showers") icon="";; + "Very cloudy") icon="";; +esac + +echo $icon diff --git a/scripts/status-bar/cpu-temp b/scripts/status-bar/cpu-temp new file mode 100755 index 00000000..99fb627d --- /dev/null +++ b/scripts/status-bar/cpu-temp @@ -0,0 +1,6 @@ +#! /bin/sh + +temp=$(sed 's/000$/°C/' /sys/class/thermal/thermal_zone0/temp) +icon=󰔏 + +echo "$icon $temp " diff --git a/scripts/status-bar/fecha b/scripts/status-bar/fecha new file mode 100755 index 00000000..992a49dd --- /dev/null +++ b/scripts/status-bar/fecha @@ -0,0 +1,9 @@ +#! /bin/sh + +icon=󰸘 + +cmd=$(date +"%b %e, %R") + + +#echo "$ifg $icon $tfg$cmd" +echo "$icon $cmd" diff --git a/scripts/status-bar/fecha-block b/scripts/status-bar/fecha-block new file mode 100755 index 00000000..714ac7ca --- /dev/null +++ b/scripts/status-bar/fecha-block @@ -0,0 +1,11 @@ +#! /bin/sh + +icon=󰸘 +tfg=^c#292541^ +ibg=^b#705b86^ +tbg=^b#cdabb8^ +reset=^d^ +cmd=$(date +"%b %e, %R") + + +echo "$tfg$ibg$ifg $icon $tbg $cmd $reset" diff --git a/scripts/status-bar/listener b/scripts/status-bar/listener new file mode 100755 index 00000000..6d1a6d32 --- /dev/null +++ b/scripts/status-bar/listener @@ -0,0 +1,10 @@ +#! /bin/sh + +while true; do + read -t 1 -n 1 key + + if [[ $key == o ]]; then + notify-send "presionaste la o" + fi +done + diff --git a/scripts/status-bar/red b/scripts/status-bar/red new file mode 100755 index 00000000..f6f508d7 --- /dev/null +++ b/scripts/status-bar/red @@ -0,0 +1,9 @@ +#! /bin/sh + +if [[ $(cat /sys/class/net/wlp*/operstate) == "up" ]]; then + echo " 󰤨 " +else + echo " 󰤮 " +fi + + diff --git a/scripts/status-bar/red-texto b/scripts/status-bar/red-texto new file mode 100755 index 00000000..30d499db --- /dev/null +++ b/scripts/status-bar/red-texto @@ -0,0 +1,14 @@ +#! /bin/sh + +if [[ $(cat /sys/class/net/wlp*/operstate) == "up" ]]; then + echo " WiFi " +else + ping -c 1 google.com + if [[ $? == 0 ]]; then + echo "Eth" + else + " " + fi +fi + + diff --git a/scripts/status-bar/sep1 b/scripts/status-bar/sep1 new file mode 100755 index 00000000..d44bf717 --- /dev/null +++ b/scripts/status-bar/sep1 @@ -0,0 +1,3 @@ +#! /bin/sh + +echo "" diff --git a/scripts/status-bar/spotify-bar b/scripts/status-bar/spotify-bar new file mode 100755 index 00000000..b0cbacd0 --- /dev/null +++ b/scripts/status-bar/spotify-bar @@ -0,0 +1,14 @@ +#! /bin/sh + +icon=" 󰓇" + +#status=$(~/.local/bin/status-bar/spotify_status.py -f '{artist} - {song}') +status=$(playerctl metadata --format '{{artist}} - {{title}}' | cut -c 1-50) +runstate=$(playerctl status) + +if [[ $runstate == "Playing" ]]; then + echo " $icon $status" +else + echo "" +fi + diff --git a/scripts/status-bar/spotify-block b/scripts/status-bar/spotify-block new file mode 100755 index 00000000..6fcbe14c --- /dev/null +++ b/scripts/status-bar/spotify-block @@ -0,0 +1,17 @@ +#! /bin/sh + +icon="󰓇" +ibg=^b#875B82^ +ifg=^c#1DB954^ +tfg=^c#292541^ +tbg=^b#cdabb8^ +reset=^d^ +status=$(~/.local/bin/status-bar/spotify_status.py) +runstate=$(pgrep -c spotify) + +if [[ $runstate -le 1 ]]; then + echo "" +else + echo "$ibg$ifg $icon $tbg$tfg $status $reset" +fi + diff --git a/scripts/status-bar/spotify_status.py b/scripts/status-bar/spotify_status.py new file mode 100755 index 00000000..eaca49db --- /dev/null +++ b/scripts/status-bar/spotify_status.py @@ -0,0 +1,122 @@ +#!/bin/python + +import sys +import dbus +import argparse + + +parser = argparse.ArgumentParser() +parser.add_argument( + '-t', + '--trunclen', + type=int, + metavar='trunclen' +) +parser.add_argument( + '-f', + '--format', + type=str, + metavar='custom format', + dest='custom_format' +) +parser.add_argument( + '-p', + '--playpause', + type=str, + metavar='play-pause indicator', + dest='play_pause' +) +parser.add_argument( + '--font', + type=str, + metavar='the index of the font to use for the main label', + dest='font' +) +parser.add_argument( + '--playpause-font', + type=str, + metavar='the index of the font to use to display the playpause indicator', + dest='play_pause_font' +) + + +args = parser.parse_args() + +def fix_string(string): + # corrects encoding for the python version used + if sys.version_info.major == 3: + return string + else: + return string.encode('utf-8') + +# Default parameters +output = fix_string(u'{play_pause} {artist}: {song}') +trunclen = 35 +play_pause = fix_string(u'\u25B6,\u23F8') # first character is play, second is paused + +label_with_font = '%{{T{font}}}{label}%{{T-}}' +font = args.font +play_pause_font = args.play_pause_font + +# parameters can be overwritten by args +if args.trunclen is not None: + trunclen = args.trunclen +if args.custom_format is not None: + output = args.custom_format +if args.play_pause is not None: + play_pause = args.play_pause + +try: + session_bus = dbus.SessionBus() + spotify_bus = session_bus.get_object( + 'org.mpris.MediaPlayer2.spotify', + '/org/mpris/MediaPlayer2' + ) + + spotify_properties = dbus.Interface( + spotify_bus, + 'org.freedesktop.DBus.Properties' + ) + + metadata = spotify_properties.Get('org.mpris.MediaPlayer2.Player', 'Metadata') + status = spotify_properties.Get('org.mpris.MediaPlayer2.Player', 'PlaybackStatus') + + # Handle play/pause label + + play_pause = play_pause.split(',') + + if status == 'Playing': + play_pause = play_pause[0] + elif status == 'Paused': + play_pause = play_pause[1] + else: + play_pause = str() + + if play_pause_font: + play_pause = label_with_font.format(font=play_pause_font, label=play_pause) + + # Handle main label + + artist = fix_string(metadata['xesam:artist'][0]) if metadata['xesam:artist'] else '' + song = fix_string(metadata['xesam:title']) if metadata['xesam:title'] else '' + + if not artist and not song: + print('') + else: + if len(song) > trunclen: + song = song[0:trunclen] + song += '...' + if ('(' in song) and (')' not in song): + song += ')' + + if font: + artist = label_with_font.format(font=font, label=artist) + song = label_with_font.format(font=font, label=song) + + print(output.format(artist=artist, song=song, play_pause=play_pause)) + +except Exception as e: + if isinstance(e, dbus.exceptions.DBusException): + print('') + else: + print(e) diff --git a/scripts/status-bar/volume b/scripts/status-bar/volume new file mode 100755 index 00000000..ca968a57 --- /dev/null +++ b/scripts/status-bar/volume @@ -0,0 +1,24 @@ +#! /bin/sh + +#mute=$(amixer get Master | awk -F'[][]' 'END{ print $6 }' ) +#vol=$(amixer get Master | awk -F'[][]' 'END{ print $2 }' ) +mute=$(pamixer --get-mute) +vol=$(pamixer --get-volume) +iconmute=󰖁 +ramp1=󰕿 +ramp2=󰖀 +ramp3=󰕾 + +#if [[ $mute == "true" ]]; then +# echo " $iconmute $vol% " +if [[ $mute == "true" ]]; then + echo " $iconmute mute" +elif [[ "$vol" -ge "100" ]]; then + echo "$ramp3 $vol% " +elif [[ "$vol" -le "33" ]]; then + echo "$ramp1 $vol% " +elif [[ "$vol" -le "66" ]]; then + echo "$ramp2 $vol% " +elif [[ "$vol" -ge "66" ]]; then + echo "$ramp3 $vol% " +fi diff --git a/scripts/status-bar/volume-block b/scripts/status-bar/volume-block new file mode 100755 index 00000000..d33194ef --- /dev/null +++ b/scripts/status-bar/volume-block @@ -0,0 +1,29 @@ +#! /bin/sh + +#mute=$(amixer get Master | awk -F'[][]' 'END{ print $6 }' ) +#vol=$(amixer get Master | awk -F'[][]' 'END{ print $2 }' ) +mute=$(pamixer --get-mute) +vol=$(pamixer --get-volume) +iconmute=󰖁 +ramp1=󰕿 +ramp2=󰖀 +ramp3=󰕾 +mbg=^b#cc241d^ +tfg=^c#292541^ +ibg=^b#875b82^ +tbg=^b#cdabb8^ +reset=^d^ + +if [[ $mute == "true" ]]; then + echo "$mbg$tfg $iconmute $tbg$tfg $vol% $reset" +elif [[ "$vol" == "100" ]]; then + echo "$ibg$tfg $ramp3 $tbg$tfg $vol% $reset" +elif [[ "$vol" < "33" ]]; then + echo "$ibg$tfg $ramp1 $tbg$tfg $vol% $reset" +elif [[ "$vol" < "66" ]]; then + echo "$ibg$tfg $ramp2 $tbg$tfg $vol% $reset" +elif [[ "$vol" = "66" ]]; then + echo "$ibg$tfg $ramp2 $tbg$tfg $vol% $reset" +elif [[ "$vol" > "66" ]]; then + echo "$ibg$tfg $ramp3 $tbg$tfg $vol% $reset" +fi diff --git a/scripts/toggle_monitor.sh b/scripts/toggle_monitor.sh new file mode 100755 index 00000000..631f0f46 --- /dev/null +++ b/scripts/toggle_monitor.sh @@ -0,0 +1,6 @@ +#!/bin/bash +extern=HDMI1 + +if xrandr | grep -v "$extern disconnected"; then + xrandr --output eDP1 --mode 1920x1080 --pos 0x0 --rotate normal --output DP1 --off --output HDMI1 --primary --mode 1920x1080 --pos 1920x0 --rotate normal --output HDMI2 --off --output VIRTUAL1 --off +fi diff --git a/scripts/toggle_touchpad.sh b/scripts/toggle_touchpad.sh new file mode 100755 index 00000000..784a66c7 --- /dev/null +++ b/scripts/toggle_touchpad.sh @@ -0,0 +1,9 @@ +#!/bin/bash +if xinput list-props "MSFT0001:00 06CB:7E7E Touchpad" | grep "Device Enabled ([0-9]*):.*1" >/dev/null +then + xinput disable "MSFT0001:00 06CB:7E7E Touchpad" + notify-send -u low -i mouse "Trackpad disabled" +else + xinput enable "MSFT0001:00 06CB:7E7E Touchpad" + notify-send -u low -i mouse "Trackpad enabled" +fi diff --git a/scripts/update_events.sh b/scripts/update_events.sh new file mode 100755 index 00000000..0e242d33 --- /dev/null +++ b/scripts/update_events.sh @@ -0,0 +1,3 @@ +#!/bin/bash + +echo $((($(khal list -f \"{uid}\" | wc -l) - 1))) > /home/yigit/.cache/events diff --git a/scripts/welcome.sh b/scripts/welcome.sh new file mode 100755 index 00000000..c1ca8cab --- /dev/null +++ b/scripts/welcome.sh @@ -0,0 +1,28 @@ +NC='\033[0m' +RED='\033[0;31m' +GREEN='\033[0;32m' +ORANGE='\033[0;33m' +BLUE='\033[0;34m' +PURPLE='\033[0;35m' +CYAN='\033[0;36m' +LIGHTGRAY='\033[0;37m' +DARKGRAY='\033[1;30m' +LIGHTRED='\033[1;31m' +LIGHTGREEN='\033[1;32m' +YELLOW='\033[1;33m' +LIGHTBLUE='\033[1;34m' +LIGHTPURPLE='\033[1;35m' +LIGHTCYAN='\033[1;36m' +WHITE='\033[1;37m' +COLUMNS=$(tput cols) +PADDING="\t" + +echo -en "\n${CYAN}" +figlet -w $COLUMNS -c -f nancyj "Fr1nge" +echo -en ${NC} +footer="${BLUE}$(whoami)${NC}${YELLOW}@${NC}${RED}$(hostname)${NC}" +footer_nc="$(whoami)@$(hostname)" +printf "%*s" $((($COLUMNS-${#footer_nc})/2)) "" +echo -e "$footer" + +echo "" diff --git a/suckless/dwm/, b/suckless/dwm/, new file mode 100644 index 00000000..ce35be64 --- /dev/null +++ b/suckless/dwm/, @@ -0,0 +1,245 @@ +/* See LICENSE file for copyright and license details. */ + +#include +/* appearance */ +static const unsigned int borderpx = 3; /* border pixel of windows */ +static const unsigned int gappx = 6; +static const unsigned int snap = 32; /* snap pixel */ +static const int rmaster = 0; /* 1 = master at right*/ +static const int showbar = 1; /* 0 means no bar */ +static const int topbar = 1; /* 0 means bottom bar */ +static const int user_bh = 27; /* 0 means that dwm will calculate bar height, >= 1 means dwm will user_bh as bar height */ +static const int tag_padding = 0; +static const int vertpad = 0; /* vertical padding of bar */ +static const int sidepad = 0; /* horizontal padding of bar */ +static const char *fonts[] = {"Hack Nerd Font:Regular:size=10", "Material Design Icons:Regular:pixelsize=16:antialias=true"}; +static const char dmenufont[] = "Hack Nerd Font:size=10"; +static const char fore[] = "#f8f8f2"; +static const char back[] = "#282a36"; +static const char border[] = "#f8f8f2"; +static const char col0[] = "#000000"; +static const char col1[] = "#FF5555"; +static const char col2[] = "#50FA7B"; +static const char col3[] = "#F1FA8C"; +static const char col4[] = "#BD93F9"; +static const char col5[] = "#FF79C6"; +static const char col6[] = "#8BE9FD"; +static const char col7[] = "#BFBFBF"; +static const char col8[] = "#4D4D4D"; +static const char col9[] = "#FF6E67"; +static const char col10[] = "#5AF78E"; +static const char col11[] = "#F4F99D"; +static const char col12[] = "#CAA9FA"; +static const char col13[] = "#FF92D0"; +static const char col14[] = "#9AEDFE"; +static const char col15[] = "#E6E6E6"; + +static const char spotify[]= "#1FC167"; + + +static const char *colors[][3] = { + /* fg bg border */ + [SchemeNorm] = { fore, back, back }, // \x0b + [SchemeSel] = { fore, back, border }, // \x0c + [SchemeStatus] = { fore, back, border }, // \x0d Statusbar right + [SchemeTagsSel] = { col4, back, border }, // \x0e Tagbar left selected + [SchemeTagsNorm] = { fore, back, border }, // \x0f Tagbar left unselected + [SchemeInfoSel] = { fore, back, border }, // \x10 infobar middle selected + [SchemeInfoNorm] = { fore, back, border }, // \x11 infobar middle unselected + [SchemeCol1] = { col1, back, col0 }, // \x12 + [SchemeCol2] = { col2, back, col0 }, // \x13 + [SchemeCol3] = { col3, back, col0 }, // \x14 + [SchemeCol4] = { col4, back, col0 }, // \x15 + [SchemeCol5] = { col5, back, col0 }, // \x16 + [SchemeCol6] = { col6, back, col0 }, // \x17 + [SchemeCol7] = { col7, back, col0 }, // \x18 + [SchemeCol8] = { col8, back, col0 }, // \x19 + [SchemeCol9] = { col9, back, col0 }, // \x1a + [SchemeCol10] = { col10, back, col0 }, // \x1b + [SchemeCol11] = { col11, back, col0 }, // \x1c + [SchemeCol12] = { spotify, back, col0 }, // \x1d Spotify +}; + +/* tagging */ +static const char *tags[] = { "1", "2", "3", "4", "5", "6", "7", "8", "9", "0"}; +//static const char *alttags[] = { "󰄯", "󰄯", "󰄯", "󰄯"}; + +static const Rule rules[] = { + /* xprop(1): + * WM_CLASS(STRING) = instance, class + * WM_NAME(STRING) = title + */ + /* class instance title tags mask isfloating monitor */ + { "discord", NULL, NULL, 1 << 8, 0, -1 }, + { "Termite", NULL, NULL, 1 << 0, 0, -1 }, + { "firefoxdeveloperedition", NULL, NULL, 1 << 1, 0, -1 }, + { "Tor Browser", NULL, NULL, 1 << 1, 0, -1 }, + { "Chromium", NULL, NULL, 1 << 1, 0, -1 }, + { "zoom", NULL, NULL, 1 << 4, 0, -1 }, + { "TelegramDesktop", NULL, NULL, 1 << 8, 0, -1 }, + { "whatsapp-nativefier-d52542", NULL, NULL, 1 << 8, 0, -1 }, + { "neomutt", NULL, NULL, 1 << 7, 0, -1 }, + { "Sublime_Text", NULL, NULL, 1 << 2, 0, -1 }, + { "code-oss", NULL, NULL, 1 << 2, 0, -1 }, + { "jetbrains-idea", NULL, NULL, 1 << 2, 0, -1 }, + { "Nemo", NULL, NULL, 1 << 3, 1, -1 }, + { "Spotify", NULL, NULL, 1 << 9, 0, -1 }, +}; + +/* layout(s) */ +static const float mfact = 0.5; /* factor of master area size [0.05..0.95] */ +static const int nmaster = 1; /* number of clients in master area */ +static const int resizehints = 0; /* 1 means respect size hints in tiled resizals */ + +#include "fibonacci.c" +#include "layouts.c" +static const Layout layouts[] = { + /* symbol arrange function */ + { "鉶", tile }, /* first entry is default */ + { "", dwindle }, + { "ﱖ", grid }, + { "", centeredmaster }, + { "", centeredfloatingmaster }, + { "[M]", monocle }, + { "[D]", deck }, + { NULL, NULL }, +}; + +/* key definitions */ +#define MODKEY Mod4Mask +#define TAGKEYS(KEY,TAG) \ + { MODKEY, KEY, view, {.ui = 1 << TAG} }, \ + { MODKEY|Mod1Mask, KEY, toggleview, {.ui = 1 << TAG} }, \ + { MODKEY|ShiftMask, KEY, tag, {.ui = 1 << TAG} }, \ + { MODKEY|ControlMask, KEY, toggletag, {.ui = 1 << TAG} }, + +/* COSAS QUE TENGO QUE AVERIGUAR COMO QUITAR */ + +/* helper for spawning shell commands in the pre dwm-5.0 fashion */ +#define SHCMD(cmd) { .v = (const char*[]){ "/bin/sh", "-c", cmd, NULL } } +static char dmenumon[2] = "0"; /* component of dmenucmd, manipulated in spawn() */ +static const char *dmenucmd[] = { "/usr/bin/rofi","-show","drun", NULL }; +static const char *termcmd[] = { "/usr/bin/termite", "--title", "Terminal", NULL }; +static const char *upvol[] = { "/usr/bin/pactl", "set-sink-volume", "0", "+5%", NULL }; +static const char *downvol[] = { "/usr/bin/pactl", "set-sink-volume", "0", "-5%", NULL }; +static const char *mutevol[] = { "/usr/bin/pactl", "set-sink-mute", "0", "toggle", NULL }; + +static const char *upbright[] = {"/usr/bin/xbacklight","-inc","10",NULL}; +static const char *downbright[] = {"/usr/bin/xbacklight","-dec","10",NULL}; + +static const char *lock[] = {"/usr/bin/betterlockscreen","-l","-t","Stay the fuck out!",NULL}; +static const char *clipmenu[] = {"/usr/bin/clipmenu","-i",NULL}; +static const char *play[] = {"/usr/bin/playerctl","play-pause",NULL}; +static const char *prev[] = {"/usr/bin/playerctl","previous",NULL}; +static const char *next[] = {"/usr/bin/playerctl","next",NULL}; +static const char *outmenu[] = {"/home/yigit/.scripts/dmenu-logout"}; +static const char *bwmenu[] = {"/usr/bin/bwmenu", "--auto-lock", "-1"}; + +static const char *trackpad[] = {"/home/yigit/.scripts/toggle_touchpad.sh"}; + +static const char *screenshot[] = { "scrot","-d","3", "%Y-%m-%d-%s_$wx$h.jpg", "-e","xclip -selection clipboard -t image/jpg < $f; mv $f ~/Pictures/Screenshots/;dunstify -a 'SNAP' 'Email taken'", NULL }; +static const char *windowshot[] = { "scrot", "-u", "-d","3", "%Y-%m-%d-%s_$wx$h.jpg", "-e","xclip -selection clipboard -t image/jpg < $f; mv $f ~/Pictures/Screenshots/;dunstify -a 'SNAP' 'Email taken'", NULL }; + +/* commands */ +#include "movestack.c" +#include "shiftview.c" +static Key keys[] = { + /* modifier key function argument */ + { MODKEY, XK_d, spawn, {.v = dmenucmd } }, + { MODKEY, XK_p, spawn, {.v = bwmenu } }, + { MODKEY, XK_Return, spawn, {.v = termcmd } }, + { MODKEY, XK_b, togglebar, {0} }, + { MODKEY, XK_j, focusstack, {.i = +1 } }, + { MODKEY, XK_k, focusstack, {.i = -1 } }, + { MODKEY, XK_i, incnmaster, {.i = +1 } }, + { MODKEY, XK_s, incnmaster, {.i = -1 } }, + { MODKEY, XK_h, setmfact, {.f = -0.05} }, + { MODKEY, XK_l, setmfact, {.f = +0.05} }, + { MODKEY|ShiftMask, XK_Return, zoom, {0} }, + { MODKEY, XK_Tab, view, {0} }, + { MODKEY, XK_q, killclient, {0} }, + { MODKEY|ShiftMask, XK_j, movestack, {.i = +1 } }, /*Mover ventana hacia abajo*/ + { MODKEY|ShiftMask, XK_k, movestack, {.i = -1 } }, /*Mover ventana hacia arriba*/ + { MODKEY, XK_t, setlayout, {.v = &layouts[0]} }, /*tiled*/ + { MODKEY|Mod1Mask, XK_f, setlayout, {.v = &layouts[1]} }, /*Spiral*/ + { MODKEY|Mod1Mask, XK_g, setlayout, {.v = &layouts[2]} }, /*Grid*/ + { MODKEY|Mod1Mask, XK_c, setlayout, {.v = &layouts[3]} }, /*center*/ + { MODKEY, XK_m, setlayout, {.v = &layouts[5]} }, /*monocle*/ + { MODKEY|ShiftMask, XK_m, setlayout, {.v = &layouts[6]} }, /*Deck*/ + { MODKEY, XK_s, togglefloating, {0} }, /*float*/ + { MODKEY, XK_f, togglefullscr, {0} }, /*Fullscreen*/ + { MODKEY|Mod1Mask, XK_comma, cyclelayout, {.i = -1 } }, /*Ciclar layouts*/ + { MODKEY|Mod1Mask, XK_period, cyclelayout, {.i = +1 } }, /*Ciclar layouts*/ + { MODKEY, XK_a, view, {.ui = ~0 } }, + { MODKEY|ShiftMask, XK_a, tag, {.ui = ~0 } }, + { MODKEY, XK_comma, focusmon, {.i = -1 } }, + { MODKEY, XK_period, focusmon, {.i = +1 } }, + { MODKEY|ShiftMask, XK_comma, tagmon, {.i = -1 } }, + { MODKEY|ShiftMask, XK_period, tagmon, {.i = +1 } }, + /*Monitores*/ + { MODKEY|ShiftMask, XK_comma, tagmon, {.i = -1 } }, /*Mandar ventana a monitor anterior*/ + { MODKEY|ShiftMask, XK_period, tagmon, {.i = +1 } }, /*Mandar ventana a monitor siguiente*/ + TAGKEYS( XK_1, 0) + TAGKEYS( XK_2, 1) + TAGKEYS( XK_3, 2) + TAGKEYS( XK_4, 3) + TAGKEYS( XK_5, 4) + TAGKEYS( XK_6, 5) + TAGKEYS( XK_7, 6) + TAGKEYS( XK_8, 7) + TAGKEYS( XK_9, 8) + TAGKEYS( XK_0, 9) + { MODKEY|ShiftMask, XK_q, spawn, {.v = outmenu} }, + { MODKEY|ShiftMask, XK_t, spawn, {.v = trackpad} }, + { MODKEY, XK_x, spawn, {.v = lock } }, + { MODKEY, XK_c, spawn, {.v = clipmenu } }, + { 0, XF86XK_AudioLowerVolume, spawn, {.v = downvol } }, + { 0, XF86XK_MonBrightnessUp, spawn, {.v = upbright } }, + { 0, XF86XK_MonBrightnessDown, spawn, {.v = downbright } }, + { 0, XF86XK_AudioMute, spawn, {.v = mutevol } }, + { 0, XF86XK_AudioRaiseVolume, spawn, {.v = upvol } }, + { 0, XF86XK_AudioPrev, spawn, {.v = prev } }, + { 0, XF86XK_AudioPlay, spawn, {.v = play } }, + { 0, XF86XK_AudioNext, spawn, {.v = next } }, + { 0, XK_Print, spawn, {.v = screenshot } }, + { MODKEY, XK_Print, spawn, {.v = windowshot } }, + +}; + +/* button definitions */ +/* click can be ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle, ClkClientWin, or ClkRootWin */ + +static Button buttons[] = { + /* click event mask button function argument */ + { ClkLtSymbol, 0, Button1, setlayout, {0} }, + { ClkLtSymbol, 0, Button3, setlayout, {.v = &layouts[2]} }, + { ClkWinTitle, 0, Button2, zoom, {0} }, + { ClkStatusText, 0, Button2, spawn, {.v = termcmd } }, + { ClkClientWin, MODKEY, Button1, movemouse, {0} }, + { ClkClientWin, MODKEY, Button2, togglefloating, {0} }, + { ClkClientWin, MODKEY, Button3, resizemouse, {0} }, + { ClkTagBar, 0, Button1, view, {0} }, + { ClkTagBar, 0, Button3, toggleview, {0} }, + { ClkTagBar, MODKEY, Button1, tag, {0} }, + { ClkTagBar, MODKEY, Button3, toggletag, {0} }, +}; + +/* +static Button buttons[] = { + // click event mask button function argument + { ClkLtSymbol, 0, Button1, cyclelayout, {.i = +1 } }, + { ClkLtSymbol, 0, Button3, setlayout, {.v = &layouts[5]} }, + { ClkWinTitle, 0, Button2, zoom, {0} }, + { ClkStatusText, 0, Button1, sigdwmblocks, {.i = 1} }, + { ClkStatusText, 0, Button2, sigdwmblocks, {.i = 2} }, + { ClkStatusText, 0, Button3, sigdwmblocks, {.i = 3} }, + { ClkClientWin, MODKEY, Button1, movemouse, {0} }, + { ClkClientWin, MODKEY, Button2, togglefloating, {0} }, + { ClkClientWin, MODKEY, Button3, resizemouse, {0} }, + { ClkTagBar, 0, Button1, view, {0} }, + { ClkTagBar, 0, Button3, toggleview, {0} }, + { ClkTagBar, MODKEY, Button1, tag, {0} }, + { ClkTagBar, MODKEY, Button3, toggletag, {0} }, + { ClkClientWin, 0, Button1, winview, {0} }, +}; +*/ diff --git a/suckless/dwm/LICENSE b/suckless/dwm/LICENSE new file mode 100644 index 00000000..d221f09d --- /dev/null +++ b/suckless/dwm/LICENSE @@ -0,0 +1,37 @@ +MIT/X Consortium License + +© 2006-2019 Anselm R Garbe +© 2006-2009 Jukka Salmi +© 2006-2007 Sander van Dijk +© 2007-2011 Peter Hartlich +© 2007-2009 Szabolcs Nagy +© 2007-2009 Christof Musik +© 2007-2009 Premysl Hruby +© 2007-2008 Enno Gottox Boland +© 2008 Martin Hurton +© 2008 Neale Pickett +© 2009 Mate Nagy +© 2010-2016 Hiltjo Posthuma +© 2010-2012 Connor Lane Smith +© 2011 Christoph Lohmann <20h@r-36.net> +© 2015-2016 Quentin Rameau +© 2015-2016 Eric Pruitt +© 2016-2017 Markus Teich + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the "Software"), +to deal in the Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/suckless/dwm/Makefile b/suckless/dwm/Makefile new file mode 100644 index 00000000..77bcbc02 --- /dev/null +++ b/suckless/dwm/Makefile @@ -0,0 +1,51 @@ +# dwm - dynamic window manager +# See LICENSE file for copyright and license details. + +include config.mk + +SRC = drw.c dwm.c util.c +OBJ = ${SRC:.c=.o} + +all: options dwm + +options: + @echo dwm build options: + @echo "CFLAGS = ${CFLAGS}" + @echo "LDFLAGS = ${LDFLAGS}" + @echo "CC = ${CC}" + +.c.o: + ${CC} -c ${CFLAGS} $< + +${OBJ}: config.h config.mk + +config.h: + cp config.def.h $@ + +dwm: ${OBJ} + ${CC} -o $@ ${OBJ} ${LDFLAGS} + +clean: + rm -f dwm ${OBJ} dwm-${VERSION}.tar.gz + +dist: clean + mkdir -p dwm-${VERSION} + cp -R LICENSE Makefile README config.def.h config.mk\ + dwm.1 drw.h util.h ${SRC} dwm.png transient.c dwm-${VERSION} + tar -cf dwm-${VERSION}.tar dwm-${VERSION} + gzip dwm-${VERSION}.tar + rm -rf dwm-${VERSION} + +install: all + mkdir -p ${DESTDIR}${PREFIX}/bin + cp -f dwm ${DESTDIR}${PREFIX}/bin + chmod 755 ${DESTDIR}${PREFIX}/bin/dwm + mkdir -p ${DESTDIR}${MANPREFIX}/man1 + sed "s/VERSION/${VERSION}/g" < dwm.1 > ${DESTDIR}${MANPREFIX}/man1/dwm.1 + chmod 644 ${DESTDIR}${MANPREFIX}/man1/dwm.1 + +uninstall: + rm -f ${DESTDIR}${PREFIX}/bin/dwm\ + ${DESTDIR}${MANPREFIX}/man1/dwm.1 + +.PHONY: all options clean dist install uninstall diff --git a/suckless/dwm/Makefile.bak b/suckless/dwm/Makefile.bak new file mode 100644 index 00000000..da3269d7 --- /dev/null +++ b/suckless/dwm/Makefile.bak @@ -0,0 +1,50 @@ +# dwm - dynamic window manager +# See LICENSE file for copyright and license details. + +include config.mk + +SRC = drw.c dwm.c util.c +OBJ = ${SRC:.c=.o} + +all: options dwm + +options: + @echo dwm build options: + @echo "CFLAGS = ${CFLAGS}" + @echo "LDFLAGS = ${LDFLAGS}" + @echo "CC = ${CC}" + +.c.o: + ${CC} -c ${CFLAGS} $< + +${OBJ}: config.h config.mk + +config.h: + cp config.def.h $@ + +dwm: ${OBJ} + ${CC} -o $@ ${OBJ} ${LDFLAGS} + +clean: + rm -f dwm ${OBJ} dwm-${VERSION}.tar.gz + +dist: clean + mkdir -p dwm-${VERSION} + cp -R LICENSE Makefile README config.def.h config.mk\ + dwm.1 drw.h util.h ${SRC} dwm.png transient.c dwm-${VERSION} + tar -cf dwm-${VERSION}.tar dwm-${VERSION} + gzip dwm-${VERSION}.tar + rm -rf dwm-${VERSION} + +install: all + mkdir -p ~/.local + cp -f dwm ~/.local + chmod 755 ~/.local/dwm +# pkill dwm +# ~/.local/dwmblocks & + +uninstall: + rm -f ${DESTDIR}${PREFIX}/bin/dwm\ + ${DESTDIR}${MANPREFIX}/man1/dwm.1 + +.PHONY: all options clean dist install uninstall diff --git a/suckless/dwm/README.es.org b/suckless/dwm/README.es.org new file mode 100644 index 00000000..3143644a --- /dev/null +++ b/suckless/dwm/README.es.org @@ -0,0 +1,32 @@ +* Dynamic Window Manager + +Este es mi propio build de DWM, con algunos parches y configuraciones. + +*** Parches + +**** Funcionales +Aquellos parches que añaden nuevas funciones a DWM, algunas de ellas son funciones sencillas que están presentes en otros TWM. +- [[https://dwm.suckless.org/patches/actualfullscreen/dwm-actualfullscreen-20191112-cb3f58a.diff][actualfullscreen:]] Permite activar verdadera pantalla completa en lugar de solo activar el modo monocle y esconder el panel. +- [[https://dwm.suckless.org/patches/alwayscenter/][alwayscenter]]: Las ventanas flotantes siempre se colocan al centro de la pantalla. +- [[https://dwm.suckless.org/patches/cyclelayouts/dwm-cyclelayouts-20180524-6.2.diff][cyclelayouts:]] Pasa por la lista de layouts con una combinación de botones. +- [[https://dwm.suckless.org/patches/inplacerotate/][inplacerotate]]: Permite rotar las ventanas en el stack sin cambiar master. +- [[https://dwm.suckless.org/patches/movestack/dwm-movestack-6.1.diff][movestack:]] Permite mover las ventanas en la parte stack, cuando se usa el esquema por defecto. +- [[https://dwm.suckless.org/patches/pertag/dwm-pertag-20170513-ceac8c9.diff][pertag:]] Por defecto, dwm usa el mismo esquema para todos los tags. Con este parche cada tag tiene un esquema diferente (el esquema inicial es tile). +- [[https://dwm.suckless.org/patches/switchcol/][switchcol:]] Permite cambiar el foco entre master y stack con un solo /keybinding/. Útil con el layout /deck/. +- [[https://dwm.suckless.org/patches/winview/][winview]]: Si están viendo varios tags a la vez, al presionar un /keybinding/ se cambia al tag de la ventana enfocada. + +**** Layouts +Son aquellas /layouts/ nuevas que he agregado a DWM. +- [[https://dwm.suckless.org/patches/centeredmaster/][centeredmaster:]] La ventana /master/ se coloca en el centro mientras las otras aparecen en rejilla alrededor. +- [[https://dwm.suckless.org/patches/deck/][deck:]] La parte /stack/ solo muestra una ventana a la vez. Si se usa con /inplacerotate/ es posible cambiar la ventana en el /stack/ sin mover /master/. +- [[https://dwm.suckless.org/patches/fibonacci/dwm-fibonacci-5.8.2.diff][fibonacci:]] Dos esquemas nuevos: spiral y dwindle (à la bspwm). +- [[https://dwm.suckless.org/patches/gridmode/dwm-gridmode-20170909-ceac8c9.diff][gridmode:]] Esquema de rejilla para. +- [[https://dwm.suckless.org/patches/rmaster/dwm-rmaster-6.1.diff][rmaster:]] Permite invertir el orden del esquema tile: master a la izquierda y stack a la derecha. + +**** Estéticos +Parches que unicamente sirven para mejorar el aspecto estético del WM y aportan poco o nada al aspecto funcional. +- [[https://dwm.suckless.org/patches/alttagsdecoration/][alttagsdecoration]]: Permite declarar íconos diferentes para cada tag cuando están ocupados. +- [[https://dwm.suckless.org/patches/colorbar/][colorbar]]: Añade esquemas de colores nuevos para cada sección del panel. +- [[https://github.com/ashish-yadav11/dwmblocks][dwmblocks]]: Agrega soporte para texto coloreado y poder presionar en los módulos. +- [[https://dwm.suckless.org/patches/alpha/dwm-fixborders-6.2.diff][fixborders]]: Arregla los bordes transparentes cuando se usa compton/picom. +- [[https://dwm.suckless.org/patches/uselessgap/dwm-uselessgap-6.2.diff][uselessgap:]] Añade separaciones inútiles entre ventanas. Apesar de no ser el único parche, si es el más sencillo de aplicar. diff --git a/suckless/dwm/README.org b/suckless/dwm/README.org new file mode 100644 index 00000000..ff375b26 --- /dev/null +++ b/suckless/dwm/README.org @@ -0,0 +1,35 @@ +#+TITLE:DWM: Dynamic Window Manager + +This is my own build of DWM with some patches and configurations. + +*** Patches + +**** Feature related +Those patches that add new features to DWM, some of them are simple features that are present in other TWMs. +- [[https://dwm.suckless.org/patches/actualfullscreen/dwm-actualfullscreen-20191112-cb3f58a.diff][actualfullscreen:]] Allows to activate true fullscreen instead of just change to monocle layout and hide the bar. +- [[https://dwm.suckless.org/patches/alwayscenter/][alwayscenter]]: Floating windows are always placed at the center of the screen. +- [[https://dwm.suckless.org/patches/cyclelayouts/dwm-cyclelayouts-20180524-6.2.diff][cyclelayouts:]] Go through the layout list with a button combination. +- [[https://dwm.suckless.org/patches/inplacerotate/][inplacerotate]]: Allows to rotate the windows in the stack without changing master. +- [[https://dwm.suckless.org/patches/movestack/dwm-movestack-6.1.diff][movestack:]] Allows to move the windows in the stack part, when using the default layout. +- [[https://dwm.suckless.org/patches/pertag/dwm-pertag-20170513-ceac8c9.diff][pertag:]] By default, dwm uses the same layout for all tags. With this patch each tag has a different layout (the initial scheme is tile). +- [[https://dwm.suckless.org/patches/switchcol/][switchcol:]] It allows to change the focus between master and stack with a single keybinding. Useful with the /deck/ layout. +- [[https://dwm.suckless.org/patches/winview/][winview]]: If you are seeing several tags at once, pressing a keybinding switches to the tag in the focused window. + +**** Layouts +New layout I've added to DWM. +- [[https://dwm.suckless.org/patches/centeredmaster/][centeredmaster:]] The /master/ window is placed in the center while the others appear in a grid around it. +- [[https://dwm.suckless.org/patches/deck/][deck:]] The /stack/ part only shows one window at a time. If used with /inplacerotate/ it is possible to change the window in /stack/ without moving /master/. +- [[https://dwm.suckless.org/patches/fibonacci/dwm-fibonacci-5.8.2.diff][fibonacci:]] Two new layouts: spiral y dwindle (à la bspwm). +- [[https://dwm.suckless.org/patches/gridmode/dwm-gridmode-20170909-ceac8c9.diff][gridmode:]] Grid layout. +- [[https://dwm.suckless.org/patches/rmaster/dwm-rmaster-6.1.diff][rmaster:]] Allows to reverse the order of the tile scheme: master on the left and stack on the right. + +**** Aesthetic related +Patches that only serve to improve the aesthetic aspect of the WM and contribute little or nothing to the functional aspect. + +- [[https://dwm.suckless.org/patches/alttagsdecoration/][alttagsdecoration]]: Allows you to declare different icons for each tag when they are busy. +- [[https://dwm.suckless.org/patches/barpadding/][barpadding:]] Add vertical andhorizontal padding to the bar from the screen. +- [[https://dwm.suckless.org/patches/colorbar/][colorbar]]: Add new color schemes for each section of the panel. +- [[https://github.com/ashish-yadav11/dwmblocks][dwmblocks]]: Add support for colored text and click on the dwmblocks modules. +- [[https://dwm.suckless.org/patches/alpha/dwm-fixborders-6.2.diff][fixborders]]: Fix the transparent borders when using compton/picom. +- [[https://dwm.suckless.org/patches/uselessgap/dwm-uselessgap-6.2.diff][uselessgap:]] Add useless gaps between windows. Although it is not the only patch, it is the easiest to apply. + diff --git a/suckless/dwm/config.h b/suckless/dwm/config.h new file mode 100644 index 00000000..6ae6045e --- /dev/null +++ b/suckless/dwm/config.h @@ -0,0 +1,262 @@ +/* See LICENSE file for copyright and license details. */ + +#include +/* appearance */ +static const unsigned int borderpx = 3; /* border pixel of windows */ +static const unsigned int gappx = 6; +static const unsigned int snap = 32; /* snap pixel */ +static const int rmaster = 0; /* 1 = master at right*/ +static const int showbar = 1; /* 0 means no bar */ +static const unsigned int systraypinning = 0; /* 0: sloppy systray follows selected monitor, >0: pin systray to monitor X */ +static const unsigned int systrayspacing = 2; /* systray spacing */ +static const int systraypinningfailfirst = 1; /* 1: if pinning fails, display systray on the first monitor, False: display systray on the last monitor*/ +static const int showsystray = 1; /* 0 means no systray */ +static const int topbar = 1; /* 0 means bottom bar */ +static const int user_bh = 27; /* 0 means that dwm will calculate bar height, >= 1 means dwm will user_bh as bar height */ +static const int tag_padding = 0; +static const int vertpad = 0; /* vertical padding of bar */ +static const int sidepad = 0; /* horizontal padding of bar */ +static const char *fonts[] = {"Hack Nerd Font:Regular:size=10", "Material Design Icons:Regular:pixelsize=16:antialias=true"}; +static const char dmenufont[] = "Hack Nerd Font:size=10"; +static const char fore[] = "#f8f8f2"; +static const char back[] = "#282a36"; +static const char border[] = "#f8f8f2"; +static const char col0[] = "#000000"; +static const char col1[] = "#FF5555"; +static const char col2[] = "#50FA7B"; +static const char col3[] = "#F1FA8C"; +static const char col4[] = "#BD93F9"; +static const char col5[] = "#FF79C6"; +static const char col6[] = "#8BE9FD"; +static const char col7[] = "#BFBFBF"; +static const char col8[] = "#4D4D4D"; +static const char col9[] = "#FF6E67"; +static const char col10[] = "#5AF78E"; +static const char col11[] = "#F4F99D"; +static const char col12[] = "#CAA9FA"; +static const char col13[] = "#FF92D0"; +static const char col14[] = "#9AEDFE"; +static const char col15[] = "#E6E6E6"; + +static const char spotify[]= "#1FC167"; + + +static const char *colors[][3] = { + /* fg bg border */ + [SchemeNorm] = { fore, back, back }, // \x0b + [SchemeSel] = { fore, back, border }, // \x0c + [SchemeStatus] = { fore, back, border }, // \x0d Statusbar right + [SchemeTagsSel] = { col4, back, border }, // \x0e Tagbar left selected + [SchemeTagsNorm] = { fore, back, border }, // \x0f Tagbar left unselected + [SchemeInfoSel] = { fore, back, border }, // \x10 infobar middle selected + [SchemeInfoNorm] = { fore, back, border }, // \x11 infobar middle unselected + [SchemeCol1] = { col1, back, col0 }, // \x12 + [SchemeCol2] = { col2, back, col0 }, // \x13 + [SchemeCol3] = { col3, back, col0 }, // \x14 + [SchemeCol4] = { col4, back, col0 }, // \x15 + [SchemeCol5] = { col5, back, col0 }, // \x16 + [SchemeCol6] = { col6, back, col0 }, // \x17 + [SchemeCol7] = { col7, back, col0 }, // \x18 + [SchemeCol8] = { col8, back, col0 }, // \x19 + [SchemeCol9] = { col9, back, col0 }, // \x1a + [SchemeCol10] = { col10, back, col0 }, // \x1b + [SchemeCol11] = { col11, back, col0 }, // \x1c + [SchemeCol12] = { spotify, back, col0 }, // \x1d Spotify +}; + +/* tagging */ +static const char *tags[] = { "1", "2", "3", "4", "5", "6", "7", "8", "9", "0"}; +//static const char *alttags[] = { "󰄯", "󰄯", "󰄯", "󰄯"}; + +static const Rule rules[] = { + /* xprop(1): + * WM_CLASS(STRING) = instance, class + * WM_NAME(STRING) = title + */ + /* class instance title tags mask isfloating monitor */ + { "discord", NULL, NULL, 1 << 8, 0, -1 }, + { "mailspring", NULL, NULL, 1 << 8, 0, -1 }, + { "Termite", NULL, NULL, 1 << 0, 0, -1 }, + { "firefoxdeveloperedition", NULL, NULL, 1 << 1, 0, -1 }, + { "Tor Browser", NULL, NULL, 1 << 1, 0, -1 }, + { "Chromium", NULL, NULL, 1 << 1, 0, -1 }, +// { "zoom", NULL, NULL, 1 << 4, 0, -1 }, + { "TelegramDesktop", NULL, NULL, 1 << 8, 0, -1 }, + { "whatsapp-nativefier-d52542", NULL, NULL, 1 << 8, 0, -1 }, + { "neomutt", NULL, NULL, 1 << 7, 0, -1 }, + { "Sublime_Text", NULL, NULL, 1 << 2, 0, -1 }, + { "code-oss", NULL, NULL, 1 << 2, 0, -1 }, + { "jetbrains-idea", NULL, NULL, 1 << 2, 0, -1 }, + { "Nemo", NULL, NULL, 1 << 3, 0, -1 }, + { "Spotify", NULL, NULL, 1 << 9, 0, -1 }, +}; + +/* layout(s) */ +static const float mfact = 0.5; /* factor of master area size [0.05..0.95] */ +static const int nmaster = 1; /* number of clients in master area */ +static const int resizehints = 0; /* 1 means respect size hints in tiled resizals */ + +#include "fibonacci.c" +#include "layouts.c" +static const Layout layouts[] = { + /* symbol arrange function */ + { "鉶", tile }, /* first entry is default */ + { "", dwindle }, + { "ﱖ", grid }, + { "", centeredmaster }, + { "", centeredfloatingmaster }, + { "[M]", monocle }, + { "[D]", deck }, + { NULL, NULL }, +}; + +/* key definitions */ +#define MODKEY Mod4Mask +#define TAGKEYS(KEY,TAG) \ + { MODKEY, KEY, view, {.ui = 1 << TAG} }, \ + { MODKEY|Mod1Mask, KEY, toggleview, {.ui = 1 << TAG} }, \ + { MODKEY|ShiftMask, KEY, tag, {.ui = 1 << TAG} }, \ + { MODKEY|ControlMask, KEY, toggletag, {.ui = 1 << TAG} }, + +/* COSAS QUE TENGO QUE AVERIGUAR COMO QUITAR */ + +/* helper for spawning shell commands in the pre dwm-5.0 fashion */ +#define SHCMD(cmd) { .v = (const char*[]){ "/bin/sh", "-c", cmd, NULL } } +static char dmenumon[2] = "0"; /* component of dmenucmd, manipulated in spawn() */ +static const char *dmenucmd[] = { "/usr/bin/rofi","-show","drun", NULL }; +static const char *termcmd[] = { "/usr/bin/termite", "--title", "Terminal", NULL }; +static const char *upvol[] = { "/usr/bin/pactl", "set-sink-volume", "0", "+5%", NULL }; +static const char *downvol[] = { "/usr/bin/pactl", "set-sink-volume", "0", "-5%", NULL }; +static const char *mutevol[] = { "/usr/bin/pactl", "set-sink-mute", "0", "toggle", NULL }; + +static const char *upbright[] = {"/usr/bin/xbacklight","-inc","10",NULL}; +static const char *downbright[] = {"/usr/bin/xbacklight","-dec","10",NULL}; + +static const char *lock[] = {"/usr/bin/betterlockscreen","-l","-t","Stay the fuck out!",NULL}; +static const char *clipmenu[] = {"/usr/bin/clipmenu","-i",NULL}; +static const char *play[] = {"/usr/bin/playerctl","play-pause",NULL}; +static const char *prev[] = {"/usr/bin/playerctl","previous",NULL}; +static const char *next[] = {"/usr/bin/playerctl","next",NULL}; +static const char *outmenu[] = {"/home/yigit/.scripts/dmenu-logout"}; + +static const char *notification_off[] = {"/home/yigit/.scripts/dunst_toggle.sh","-s",NULL}; +static const char *notification_on[] = {"/home/yigit/.scripts/dunst_toggle.sh", "-e",NULL}; + +static const char *bwmenu[] = {"/usr/bin/bwmenu", "--auto-lock", "-1", NULL}; + +static const char *trackpad[] = {"/home/yigit/.scripts/toggle_touchpad.sh"}; + +static const char *kdeconnect[] = {"/home/yigit/.local/bin/dmenu_kdeconnect.sh", NULL}; + +static const char *bluetooth[] = {"/usr/bin/rofi-bluetooth", NULL}; + +static const char *screenshot[] = { "scrot","-d","3", "%Y-%m-%d-%s_$wx$h.jpg", "-e","xclip -selection clipboard -t image/jpg < $f; mv $f ~/Pictures/Screenshots/;dunstify --icon='/home/yigit/.icons/Numix-Circle/48/apps/camera.svg' -a 'SNAP' 'Screenshot taken'", NULL }; +static const char *windowshot[] = { "scrot", "-u", "-d","3", "%Y-%m-%d-%s_$wx$h.jpg", "-e","xclip -selection clipboard -t image/jpg < $f; mv $f ~/Pictures/Screenshots/;dunstify --icon='/home/yigit/.icons/Numix-Circle/48/apps/camera.svg' -a 'SNAP' 'Screenshot taken'", NULL }; + +/* commands */ +#include "movestack.c" +#include "shiftview.c" +static Key keys[] = { + /* modifier key function argument */ + { MODKEY, XK_d, spawn, {.v = dmenucmd } }, + { MODKEY, XK_p, spawn, {.v = bwmenu } }, + { MODKEY, XK_Return, spawn, {.v = termcmd } }, + { MODKEY, XK_b, togglebar, {0} }, + { MODKEY, XK_j, focusstack, {.i = +1 } }, + { MODKEY, XK_n, spawn, {.v = notification_off} }, + { MODKEY|ShiftMask, XK_n, spawn, {.v = notification_on } }, + { MODKEY, XK_k, focusstack, {.i = -1 } }, + { MODKEY, XK_i, incnmaster, {.i = +1 } }, + { MODKEY, XK_s, incnmaster, {.i = -1 } }, + { MODKEY, XK_h, setmfact, {.f = -0.05} }, + { MODKEY, XK_l, setmfact, {.f = +0.05} }, + { MODKEY|ShiftMask, XK_Return, zoom, {0} }, + { MODKEY, XK_Tab, view, {0} }, + { MODKEY, XK_q, killclient, {0} }, + { MODKEY|ShiftMask, XK_j, movestack, {.i = +1 } }, /*Mover ventana hacia abajo*/ + { MODKEY|ShiftMask, XK_k, movestack, {.i = -1 } }, /*Mover ventana hacia arriba*/ + { MODKEY, XK_t, setlayout, {.v = &layouts[0]} }, /*tiled*/ + { MODKEY|Mod1Mask, XK_f, setlayout, {.v = &layouts[1]} }, /*Spiral*/ + { MODKEY|Mod1Mask, XK_g, setlayout, {.v = &layouts[2]} }, /*Grid*/ + { MODKEY|Mod1Mask, XK_c, setlayout, {.v = &layouts[3]} }, /*center*/ + { MODKEY, XK_m, setlayout, {.v = &layouts[5]} }, /*monocle*/ + { MODKEY|ShiftMask, XK_m, setlayout, {.v = &layouts[6]} }, /*Deck*/ + { MODKEY, XK_s, togglefloating, {0} }, /*float*/ + { MODKEY, XK_f, togglefullscr, {0} }, /*Fullscreen*/ + { MODKEY|Mod1Mask, XK_comma, cyclelayout, {.i = -1 } }, /*Ciclar layouts*/ + { MODKEY|Mod1Mask, XK_period, cyclelayout, {.i = +1 } }, /*Ciclar layouts*/ + { MODKEY, XK_a, view, {.ui = ~0 } }, + { MODKEY|ShiftMask, XK_a, tag, {.ui = ~0 } }, + { MODKEY, XK_comma, focusmon, {.i = -1 } }, + { MODKEY, XK_period, focusmon, {.i = +1 } }, + { MODKEY|ShiftMask, XK_comma, tagmon, {.i = -1 } }, + { MODKEY|ShiftMask, XK_period, tagmon, {.i = +1 } }, + /*Monitores*/ + { MODKEY|ShiftMask, XK_comma, tagmon, {.i = -1 } }, /*Mandar ventana a monitor anterior*/ + { MODKEY|ShiftMask, XK_period, tagmon, {.i = +1 } }, /*Mandar ventana a monitor siguiente*/ + TAGKEYS( XK_1, 0) + TAGKEYS( XK_2, 1) + TAGKEYS( XK_3, 2) + TAGKEYS( XK_4, 3) + TAGKEYS( XK_5, 4) + TAGKEYS( XK_6, 5) + TAGKEYS( XK_7, 6) + TAGKEYS( XK_8, 7) + TAGKEYS( XK_9, 8) + TAGKEYS( XK_0, 9) + { MODKEY|ShiftMask, XK_q, spawn, {.v = outmenu} }, + { MODKEY|ShiftMask, XK_t, spawn, {.v = trackpad} }, + { MODKEY, XK_x, spawn, {.v = lock } }, + { MODKEY, XK_c, spawn, {.v = clipmenu } }, + { MODKEY|ShiftMask, XK_p, spawn, {.v = kdeconnect } }, + { MODKEY|ShiftMask, XK_b, spawn, {.v = bluetooth } }, + { 0, XF86XK_AudioLowerVolume, spawn, {.v = downvol } }, + { 0, XF86XK_MonBrightnessUp, spawn, {.v = upbright } }, + { 0, XF86XK_MonBrightnessDown, spawn, {.v = downbright } }, + { 0, XF86XK_AudioMute, spawn, {.v = mutevol } }, + { 0, XF86XK_AudioRaiseVolume, spawn, {.v = upvol } }, + { 0, XF86XK_AudioPrev, spawn, {.v = prev } }, + { 0, XF86XK_AudioPlay, spawn, {.v = play } }, + { 0, XF86XK_AudioNext, spawn, {.v = next } }, + { 0, XK_Print, spawn, {.v = screenshot } }, + { MODKEY, XK_Print, spawn, {.v = windowshot } }, + +}; + +/* button definitions */ +/* click can be ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle, ClkClientWin, or ClkRootWin */ + +static Button buttons[] = { + /* click event mask button function argument */ + { ClkLtSymbol, 0, Button1, setlayout, {0} }, + { ClkLtSymbol, 0, Button3, setlayout, {.v = &layouts[2]} }, + { ClkWinTitle, 0, Button2, zoom, {0} }, + { ClkStatusText, 0, Button2, spawn, {.v = termcmd } }, + { ClkClientWin, MODKEY, Button1, movemouse, {0} }, + { ClkClientWin, MODKEY, Button2, togglefloating, {0} }, + { ClkClientWin, MODKEY, Button3, resizemouse, {0} }, + { ClkTagBar, 0, Button1, view, {0} }, + { ClkTagBar, 0, Button3, toggleview, {0} }, + { ClkTagBar, MODKEY, Button1, tag, {0} }, + { ClkTagBar, MODKEY, Button3, toggletag, {0} }, +}; + +/* +static Button buttons[] = { + // click event mask button function argument + { ClkLtSymbol, 0, Button1, cyclelayout, {.i = +1 } }, + { ClkLtSymbol, 0, Button3, setlayout, {.v = &layouts[5]} }, + { ClkWinTitle, 0, Button2, zoom, {0} }, + { ClkStatusText, 0, Button1, sigdwmblocks, {.i = 1} }, + { ClkStatusText, 0, Button2, sigdwmblocks, {.i = 2} }, + { ClkStatusText, 0, Button3, sigdwmblocks, {.i = 3} }, + { ClkClientWin, MODKEY, Button1, movemouse, {0} }, + { ClkClientWin, MODKEY, Button2, togglefloating, {0} }, + { ClkClientWin, MODKEY, Button3, resizemouse, {0} }, + { ClkTagBar, 0, Button1, view, {0} }, + { ClkTagBar, 0, Button3, toggleview, {0} }, + { ClkTagBar, MODKEY, Button1, tag, {0} }, + { ClkTagBar, MODKEY, Button3, toggletag, {0} }, + { ClkClientWin, 0, Button1, winview, {0} }, +}; +*/ diff --git a/suckless/dwm/config.mk b/suckless/dwm/config.mk new file mode 100644 index 00000000..7084c333 --- /dev/null +++ b/suckless/dwm/config.mk @@ -0,0 +1,38 @@ +# dwm version +VERSION = 6.2 + +# Customize below to fit your system + +# paths +PREFIX = /usr/local +MANPREFIX = ${PREFIX}/share/man + +X11INC = /usr/X11R6/include +X11LIB = /usr/X11R6/lib + +# Xinerama, comment if you don't want it +XINERAMALIBS = -lXinerama +XINERAMAFLAGS = -DXINERAMA + +# freetype +FREETYPELIBS = -lfontconfig -lXft +FREETYPEINC = /usr/include/freetype2 +# OpenBSD (uncomment) +#FREETYPEINC = ${X11INC}/freetype2 + +# includes and libs +INCS = -I${X11INC} -I${FREETYPEINC} +LIBS = -L${X11LIB} -lX11 ${XINERAMALIBS} ${FREETYPELIBS} + +# flags +CPPFLAGS = -D_DEFAULT_SOURCE -D_BSD_SOURCE -D_POSIX_C_SOURCE=200809L -DVERSION=\"${VERSION}\" ${XINERAMAFLAGS} +#CFLAGS = -g -std=c99 -pedantic -Wall -O0 ${INCS} ${CPPFLAGS} +CFLAGS = -std=c99 -pedantic -Wall -Wno-deprecated-declarations -Os ${INCS} ${CPPFLAGS} +LDFLAGS = ${LIBS} + +# Solaris +#CFLAGS = -fast ${INCS} -DVERSION=\"${VERSION}\" +#LDFLAGS = ${LIBS} + +# compiler and linker +CC = cc diff --git a/suckless/dwm/drw.c b/suckless/dwm/drw.c new file mode 100644 index 00000000..cd899f89 --- /dev/null +++ b/suckless/dwm/drw.c @@ -0,0 +1,438 @@ +/* See LICENSE file for copyright and license details. */ +#include +#include +#include +#include +#include + +#include "drw.h" +#include "util.h" + +#define UTF_INVALID 0xFFFD +#define UTF_SIZ 4 + +static const unsigned char utfbyte[UTF_SIZ + 1] = {0x80, 0, 0xC0, 0xE0, 0xF0}; +static const unsigned char utfmask[UTF_SIZ + 1] = {0xC0, 0x80, 0xE0, 0xF0, 0xF8}; +static const long utfmin[UTF_SIZ + 1] = { 0, 0, 0x80, 0x800, 0x10000}; +static const long utfmax[UTF_SIZ + 1] = {0x10FFFF, 0x7F, 0x7FF, 0xFFFF, 0x10FFFF}; + +static long +utf8decodebyte(const char c, size_t *i) +{ + for (*i = 0; *i < (UTF_SIZ + 1); ++(*i)) + if (((unsigned char)c & utfmask[*i]) == utfbyte[*i]) + return (unsigned char)c & ~utfmask[*i]; + return 0; +} + +static size_t +utf8validate(long *u, size_t i) +{ + if (!BETWEEN(*u, utfmin[i], utfmax[i]) || BETWEEN(*u, 0xD800, 0xDFFF)) + *u = UTF_INVALID; + for (i = 1; *u > utfmax[i]; ++i) + ; + return i; +} + +static size_t +utf8decode(const char *c, long *u, size_t clen) +{ + size_t i, j, len, type; + long udecoded; + + *u = UTF_INVALID; + if (!clen) + return 0; + udecoded = utf8decodebyte(c[0], &len); + if (!BETWEEN(len, 1, UTF_SIZ)) + return 1; + for (i = 1, j = 1; i < clen && j < len; ++i, ++j) { + udecoded = (udecoded << 6) | utf8decodebyte(c[i], &type); + if (type) + return j; + } + if (j < len) + return 0; + *u = udecoded; + utf8validate(u, len); + + return len; +} + +Drw * +drw_create(Display *dpy, int screen, Window root, unsigned int w, unsigned int h) +{ + Drw *drw = ecalloc(1, sizeof(Drw)); + + drw->dpy = dpy; + drw->screen = screen; + drw->root = root; + drw->w = w; + drw->h = h; + drw->drawable = XCreatePixmap(dpy, root, w, h, DefaultDepth(dpy, screen)); + drw->gc = XCreateGC(dpy, root, 0, NULL); + XSetLineAttributes(dpy, drw->gc, 1, LineSolid, CapButt, JoinMiter); + + return drw; +} + +void +drw_resize(Drw *drw, unsigned int w, unsigned int h) +{ + if (!drw) + return; + + drw->w = w; + drw->h = h; + if (drw->drawable) + XFreePixmap(drw->dpy, drw->drawable); + drw->drawable = XCreatePixmap(drw->dpy, drw->root, w, h, DefaultDepth(drw->dpy, drw->screen)); +} + +void +drw_free(Drw *drw) +{ + XFreePixmap(drw->dpy, drw->drawable); + XFreeGC(drw->dpy, drw->gc); + drw_fontset_free(drw->fonts); + free(drw); +} + +/* This function is an implementation detail. Library users should use + * drw_fontset_create instead. + */ +static Fnt * +xfont_create(Drw *drw, const char *fontname, FcPattern *fontpattern) +{ + Fnt *font; + XftFont *xfont = NULL; + FcPattern *pattern = NULL; + + if (fontname) { + /* Using the pattern found at font->xfont->pattern does not yield the + * same substitution results as using the pattern returned by + * FcNameParse; using the latter results in the desired fallback + * behaviour whereas the former just results in missing-character + * rectangles being drawn, at least with some fonts. */ + if (!(xfont = XftFontOpenName(drw->dpy, drw->screen, fontname))) { + fprintf(stderr, "error, cannot load font from name: '%s'\n", fontname); + return NULL; + } + if (!(pattern = FcNameParse((FcChar8 *) fontname))) { + fprintf(stderr, "error, cannot parse font name to pattern: '%s'\n", fontname); + XftFontClose(drw->dpy, xfont); + return NULL; + } + } else if (fontpattern) { + if (!(xfont = XftFontOpenPattern(drw->dpy, fontpattern))) { + fprintf(stderr, "error, cannot load font from pattern.\n"); + return NULL; + } + } else { + die("no font specified."); + } + + /* Do not allow using color fonts. This is a workaround for a BadLength + * error from Xft with color glyphs. Modelled on the Xterm workaround. See + * https://bugzilla.redhat.com/show_bug.cgi?id=1498269 + * https://lists.suckless.org/dev/1701/30932.html + * https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=916349 + * and lots more all over the internet. + */ + FcBool iscol; + if(FcPatternGetBool(xfont->pattern, FC_COLOR, 0, &iscol) == FcResultMatch && iscol) { + XftFontClose(drw->dpy, xfont); + return NULL; + } + + font = ecalloc(1, sizeof(Fnt)); + font->xfont = xfont; + font->pattern = pattern; + font->h = xfont->ascent + xfont->descent; + font->dpy = drw->dpy; + + return font; +} + +static void +xfont_free(Fnt *font) +{ + if (!font) + return; + if (font->pattern) + FcPatternDestroy(font->pattern); + XftFontClose(font->dpy, font->xfont); + free(font); +} + +Fnt* +drw_fontset_create(Drw* drw, const char *fonts[], size_t fontcount) +{ + Fnt *cur, *ret = NULL; + size_t i; + + if (!drw || !fonts) + return NULL; + + for (i = 1; i <= fontcount; i++) { + if ((cur = xfont_create(drw, fonts[fontcount - i], NULL))) { + cur->next = ret; + ret = cur; + } + } + return (drw->fonts = ret); +} + +void +drw_fontset_free(Fnt *font) +{ + if (font) { + drw_fontset_free(font->next); + xfont_free(font); + } +} + +void +drw_clr_create(Drw *drw, Clr *dest, const char *clrname) +{ + if (!drw || !dest || !clrname) + return; + + if (!XftColorAllocName(drw->dpy, DefaultVisual(drw->dpy, drw->screen), + DefaultColormap(drw->dpy, drw->screen), + clrname, dest)) + die("error, cannot allocate color '%s'", clrname); + + dest->pixel |= 0xff << 24; +} + +/* Wrapper to create color schemes. The caller has to call free(3) on the + * returned color scheme when done using it. */ +Clr * +drw_scm_create(Drw *drw, const char *clrnames[], size_t clrcount) +{ + size_t i; + Clr *ret; + + /* need at least two colors for a scheme */ + if (!drw || !clrnames || clrcount < 2 || !(ret = ecalloc(clrcount, sizeof(XftColor)))) + return NULL; + + for (i = 0; i < clrcount; i++) + drw_clr_create(drw, &ret[i], clrnames[i]); + return ret; +} + +void +drw_setfontset(Drw *drw, Fnt *set) +{ + if (drw) + drw->fonts = set; +} + +void +drw_setscheme(Drw *drw, Clr *scm) +{ + if (drw) + drw->scheme = scm; +} + +void +drw_rect(Drw *drw, int x, int y, unsigned int w, unsigned int h, int filled, int invert) +{ + if (!drw || !drw->scheme) + return; + XSetForeground(drw->dpy, drw->gc, invert ? drw->scheme[ColBg].pixel : drw->scheme[ColFg].pixel); + if (filled) + XFillRectangle(drw->dpy, drw->drawable, drw->gc, x, y, w, h); + else + XDrawRectangle(drw->dpy, drw->drawable, drw->gc, x, y, w - 1, h - 1); +} + +int +drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lpad, const char *text, int invert) +{ + char buf[1024]; + int ty; + unsigned int ew; + XftDraw *d = NULL; + Fnt *usedfont, *curfont, *nextfont; + size_t i, len; + int utf8strlen, utf8charlen, render = x || y || w || h; + long utf8codepoint = 0; + const char *utf8str; + FcCharSet *fccharset; + FcPattern *fcpattern; + FcPattern *match; + XftResult result; + int charexists = 0; + + if (!drw || (render && !drw->scheme) || !text || !drw->fonts) + return 0; + + if (!render) { + w = ~w; + } else { + XSetForeground(drw->dpy, drw->gc, drw->scheme[invert ? ColFg : ColBg].pixel); + XFillRectangle(drw->dpy, drw->drawable, drw->gc, x, y, w, h); + d = XftDrawCreate(drw->dpy, drw->drawable, + DefaultVisual(drw->dpy, drw->screen), + DefaultColormap(drw->dpy, drw->screen)); + x += lpad; + w -= lpad; + } + + usedfont = drw->fonts; + while (1) { + utf8strlen = 0; + utf8str = text; + nextfont = NULL; + while (*text) { + utf8charlen = utf8decode(text, &utf8codepoint, UTF_SIZ); + for (curfont = drw->fonts; curfont; curfont = curfont->next) { + charexists = charexists || XftCharExists(drw->dpy, curfont->xfont, utf8codepoint); + if (charexists) { + if (curfont == usedfont) { + utf8strlen += utf8charlen; + text += utf8charlen; + } else { + nextfont = curfont; + } + break; + } + } + + if (!charexists || nextfont) + break; + else + charexists = 0; + } + + if (utf8strlen) { + drw_font_getexts(usedfont, utf8str, utf8strlen, &ew, NULL); + /* shorten text if necessary */ + for (len = MIN(utf8strlen, sizeof(buf) - 1); len && ew > w; len--) + drw_font_getexts(usedfont, utf8str, len, &ew, NULL); + + if (len) { + memcpy(buf, utf8str, len); + buf[len] = '\0'; + if (len < utf8strlen) + for (i = len; i && i > len - 3; buf[--i] = '.') + ; /* NOP */ + + if (render) { + ty = y + (h - usedfont->h) / 2 + usedfont->xfont->ascent; + XftDrawStringUtf8(d, &drw->scheme[invert ? ColBg : ColFg], + usedfont->xfont, x, ty, (XftChar8 *)buf, len); + } + x += ew; + w -= ew; + } + } + + if (!*text) { + break; + } else if (nextfont) { + charexists = 0; + usedfont = nextfont; + } else { + /* Regardless of whether or not a fallback font is found, the + * character must be drawn. */ + charexists = 1; + + fccharset = FcCharSetCreate(); + FcCharSetAddChar(fccharset, utf8codepoint); + + if (!drw->fonts->pattern) { + /* Refer to the comment in xfont_create for more information. */ + die("the first font in the cache must be loaded from a font string."); + } + + fcpattern = FcPatternDuplicate(drw->fonts->pattern); + FcPatternAddCharSet(fcpattern, FC_CHARSET, fccharset); + FcPatternAddBool(fcpattern, FC_SCALABLE, FcTrue); + FcPatternAddBool(fcpattern, FC_COLOR, FcFalse); + + FcConfigSubstitute(NULL, fcpattern, FcMatchPattern); + FcDefaultSubstitute(fcpattern); + match = XftFontMatch(drw->dpy, drw->screen, fcpattern, &result); + + FcCharSetDestroy(fccharset); + FcPatternDestroy(fcpattern); + + if (match) { + usedfont = xfont_create(drw, NULL, match); + if (usedfont && XftCharExists(drw->dpy, usedfont->xfont, utf8codepoint)) { + for (curfont = drw->fonts; curfont->next; curfont = curfont->next) + ; /* NOP */ + curfont->next = usedfont; + } else { + xfont_free(usedfont); + usedfont = drw->fonts; + } + } + } + } + if (d) + XftDrawDestroy(d); + + return x + (render ? w : 0); +} + +void +drw_map(Drw *drw, Window win, int x, int y, unsigned int w, unsigned int h) +{ + if (!drw) + return; + + XCopyArea(drw->dpy, drw->drawable, win, drw->gc, x, y, w, h, x, y); + XSync(drw->dpy, False); +} + +unsigned int +drw_fontset_getwidth(Drw *drw, const char *text) +{ + if (!drw || !drw->fonts || !text) + return 0; + return drw_text(drw, 0, 0, 0, 0, 0, text, 0); +} + +void +drw_font_getexts(Fnt *font, const char *text, unsigned int len, unsigned int *w, unsigned int *h) +{ + XGlyphInfo ext; + + if (!font || !text) + return; + + XftTextExtentsUtf8(font->dpy, font->xfont, (XftChar8 *)text, len, &ext); + if (w) + *w = ext.xOff; + if (h) + *h = font->h; +} + +Cur * +drw_cur_create(Drw *drw, int shape) +{ + Cur *cur; + + if (!drw || !(cur = ecalloc(1, sizeof(Cur)))) + return NULL; + + cur->cursor = XCreateFontCursor(drw->dpy, shape); + + return cur; +} + +void +drw_cur_free(Drw *drw, Cur *cursor) +{ + if (!cursor) + return; + + XFreeCursor(drw->dpy, cursor->cursor); + free(cursor); +} diff --git a/suckless/dwm/drw.h b/suckless/dwm/drw.h new file mode 100644 index 00000000..4bcd5add --- /dev/null +++ b/suckless/dwm/drw.h @@ -0,0 +1,57 @@ +/* See LICENSE file for copyright and license details. */ + +typedef struct { + Cursor cursor; +} Cur; + +typedef struct Fnt { + Display *dpy; + unsigned int h; + XftFont *xfont; + FcPattern *pattern; + struct Fnt *next; +} Fnt; + +enum { ColFg, ColBg, ColBorder }; /* Clr scheme index */ +typedef XftColor Clr; + +typedef struct { + unsigned int w, h; + Display *dpy; + int screen; + Window root; + Drawable drawable; + GC gc; + Clr *scheme; + Fnt *fonts; +} Drw; + +/* Drawable abstraction */ +Drw *drw_create(Display *dpy, int screen, Window win, unsigned int w, unsigned int h); +void drw_resize(Drw *drw, unsigned int w, unsigned int h); +void drw_free(Drw *drw); + +/* Fnt abstraction */ +Fnt *drw_fontset_create(Drw* drw, const char *fonts[], size_t fontcount); +void drw_fontset_free(Fnt* set); +unsigned int drw_fontset_getwidth(Drw *drw, const char *text); +void drw_font_getexts(Fnt *font, const char *text, unsigned int len, unsigned int *w, unsigned int *h); + +/* Colorscheme abstraction */ +void drw_clr_create(Drw *drw, Clr *dest, const char *clrname); +Clr *drw_scm_create(Drw *drw, const char *clrnames[], size_t clrcount); + +/* Cursor abstraction */ +Cur *drw_cur_create(Drw *drw, int shape); +void drw_cur_free(Drw *drw, Cur *cursor); + +/* Drawing context manipulation */ +void drw_setfontset(Drw *drw, Fnt *set); +void drw_setscheme(Drw *drw, Clr *scm); + +/* Drawing functions */ +void drw_rect(Drw *drw, int x, int y, unsigned int w, unsigned int h, int filled, int invert); +int drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lpad, const char *text, int invert); + +/* Map functions */ +void drw_map(Drw *drw, Window win, int x, int y, unsigned int w, unsigned int h); diff --git a/suckless/dwm/dwm-systray-20200914-61bb8b2.diff b/suckless/dwm/dwm-systray-20200914-61bb8b2.diff new file mode 100644 index 00000000..b2a4d572 --- /dev/null +++ b/suckless/dwm/dwm-systray-20200914-61bb8b2.diff @@ -0,0 +1,727 @@ +diff --git a/config.def.h b/config.def.h +index 1c0b587..2d824d1 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -3,6 +3,10 @@ + /* appearance */ + static const unsigned int borderpx = 1; /* border pixel of windows */ + static const unsigned int snap = 32; /* snap pixel */ ++static const unsigned int systraypinning = 0; /* 0: sloppy systray follows selected monitor, >0: pin systray to monitor X */ ++static const unsigned int systrayspacing = 2; /* systray spacing */ ++static const int systraypinningfailfirst = 1; /* 1: if pinning fails, display systray on the first monitor, False: display systray on the last monitor*/ ++static const int showsystray = 1; /* 0 means no systray */ + static const int showbar = 1; /* 0 means no bar */ + static const int topbar = 1; /* 0 means bottom bar */ + static const char *fonts[] = { "monospace:size=10" }; +diff --git a/dwm.c b/dwm.c +index 664c527..abce13d 100644 +--- a/dwm.c ++++ b/dwm.c +@@ -57,12 +57,30 @@ + #define TAGMASK ((1 << LENGTH(tags)) - 1) + #define TEXTW(X) (drw_fontset_getwidth(drw, (X)) + lrpad) + ++#define SYSTEM_TRAY_REQUEST_DOCK 0 ++ ++/* XEMBED messages */ ++#define XEMBED_EMBEDDED_NOTIFY 0 ++#define XEMBED_WINDOW_ACTIVATE 1 ++#define XEMBED_FOCUS_IN 4 ++#define XEMBED_MODALITY_ON 10 ++ ++#define XEMBED_MAPPED (1 << 0) ++#define XEMBED_WINDOW_ACTIVATE 1 ++#define XEMBED_WINDOW_DEACTIVATE 2 ++ ++#define VERSION_MAJOR 0 ++#define VERSION_MINOR 0 ++#define XEMBED_EMBEDDED_VERSION (VERSION_MAJOR << 16) | VERSION_MINOR ++ + /* enums */ + enum { CurNormal, CurResize, CurMove, CurLast }; /* cursor */ + enum { SchemeNorm, SchemeSel }; /* color schemes */ + enum { NetSupported, NetWMName, NetWMState, NetWMCheck, ++ NetSystemTray, NetSystemTrayOP, NetSystemTrayOrientation, NetSystemTrayOrientationHorz, + NetWMFullscreen, NetActiveWindow, NetWMWindowType, + NetWMWindowTypeDialog, NetClientList, NetLast }; /* EWMH atoms */ ++enum { Manager, Xembed, XembedInfo, XLast }; /* Xembed atoms */ + enum { WMProtocols, WMDelete, WMState, WMTakeFocus, WMLast }; /* default atoms */ + enum { ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle, + ClkClientWin, ClkRootWin, ClkLast }; /* clicks */ +@@ -141,6 +159,12 @@ typedef struct { + int monitor; + } Rule; + ++typedef struct Systray Systray; ++struct Systray { ++ Window win; ++ Client *icons; ++}; ++ + /* function declarations */ + static void applyrules(Client *c); + static int applysizehints(Client *c, int *x, int *y, int *w, int *h, int interact); +@@ -172,6 +196,7 @@ static void focusstack(const Arg *arg); + static Atom getatomprop(Client *c, Atom prop); + static int getrootptr(int *x, int *y); + static long getstate(Window w); ++static unsigned int getsystraywidth(); + static int gettextprop(Window w, Atom atom, char *text, unsigned int size); + static void grabbuttons(Client *c, int focused); + static void grabkeys(void); +@@ -189,13 +214,16 @@ static void pop(Client *); + static void propertynotify(XEvent *e); + static void quit(const Arg *arg); + static Monitor *recttomon(int x, int y, int w, int h); ++static void removesystrayicon(Client *i); + static void resize(Client *c, int x, int y, int w, int h, int interact); ++static void resizebarwin(Monitor *m); + static void resizeclient(Client *c, int x, int y, int w, int h); + static void resizemouse(const Arg *arg); ++static void resizerequest(XEvent *e); + static void restack(Monitor *m); + static void run(void); + static void scan(void); +-static int sendevent(Client *c, Atom proto); ++static int sendevent(Window w, Atom proto, int m, long d0, long d1, long d2, long d3, long d4); + static void sendmon(Client *c, Monitor *m); + static void setclientstate(Client *c, long state); + static void setfocus(Client *c); +@@ -207,6 +235,7 @@ static void seturgent(Client *c, int urg); + static void showhide(Client *c); + static void sigchld(int unused); + static void spawn(const Arg *arg); ++static Monitor *systraytomon(Monitor *m); + static void tag(const Arg *arg); + static void tagmon(const Arg *arg); + static void tile(Monitor *); +@@ -224,18 +253,23 @@ static int updategeom(void); + static void updatenumlockmask(void); + static void updatesizehints(Client *c); + static void updatestatus(void); ++static void updatesystray(void); ++static void updatesystrayicongeom(Client *i, int w, int h); ++static void updatesystrayiconstate(Client *i, XPropertyEvent *ev); + static void updatetitle(Client *c); + static void updatewindowtype(Client *c); + static void updatewmhints(Client *c); + static void view(const Arg *arg); + static Client *wintoclient(Window w); + static Monitor *wintomon(Window w); ++static Client *wintosystrayicon(Window w); + static int xerror(Display *dpy, XErrorEvent *ee); + static int xerrordummy(Display *dpy, XErrorEvent *ee); + static int xerrorstart(Display *dpy, XErrorEvent *ee); + static void zoom(const Arg *arg); + + /* variables */ ++static Systray *systray = NULL; + static const char broken[] = "broken"; + static char stext[256]; + static int screen; +@@ -258,9 +292,10 @@ static void (*handler[LASTEvent]) (XEvent *) = { + [MapRequest] = maprequest, + [MotionNotify] = motionnotify, + [PropertyNotify] = propertynotify, ++ [ResizeRequest] = resizerequest, + [UnmapNotify] = unmapnotify + }; +-static Atom wmatom[WMLast], netatom[NetLast]; ++static Atom wmatom[WMLast], netatom[NetLast], xatom[XLast]; + static int running = 1; + static Cur *cursor[CurLast]; + static Clr **scheme; +@@ -440,7 +475,7 @@ buttonpress(XEvent *e) + arg.ui = 1 << i; + } else if (ev->x < x + blw) + click = ClkLtSymbol; +- else if (ev->x > selmon->ww - (int)TEXTW(stext)) ++ else if (ev->x > selmon->ww - (int)TEXTW(stext) - getsystraywidth()) + click = ClkStatusText; + else + click = ClkWinTitle; +@@ -483,6 +518,11 @@ cleanup(void) + XUngrabKey(dpy, AnyKey, AnyModifier, root); + while (mons) + cleanupmon(mons); ++ if (showsystray) { ++ XUnmapWindow(dpy, systray->win); ++ XDestroyWindow(dpy, systray->win); ++ free(systray); ++ } + for (i = 0; i < CurLast; i++) + drw_cur_free(drw, cursor[i]); + for (i = 0; i < LENGTH(colors); i++) +@@ -513,9 +553,57 @@ cleanupmon(Monitor *mon) + void + clientmessage(XEvent *e) + { ++ XWindowAttributes wa; ++ XSetWindowAttributes swa; + XClientMessageEvent *cme = &e->xclient; + Client *c = wintoclient(cme->window); + ++ if (showsystray && cme->window == systray->win && cme->message_type == netatom[NetSystemTrayOP]) { ++ /* add systray icons */ ++ if (cme->data.l[1] == SYSTEM_TRAY_REQUEST_DOCK) { ++ if (!(c = (Client *)calloc(1, sizeof(Client)))) ++ die("fatal: could not malloc() %u bytes\n", sizeof(Client)); ++ if (!(c->win = cme->data.l[2])) { ++ free(c); ++ return; ++ } ++ c->mon = selmon; ++ c->next = systray->icons; ++ systray->icons = c; ++ if (!XGetWindowAttributes(dpy, c->win, &wa)) { ++ /* use sane defaults */ ++ wa.width = bh; ++ wa.height = bh; ++ wa.border_width = 0; ++ } ++ c->x = c->oldx = c->y = c->oldy = 0; ++ c->w = c->oldw = wa.width; ++ c->h = c->oldh = wa.height; ++ c->oldbw = wa.border_width; ++ c->bw = 0; ++ c->isfloating = True; ++ /* reuse tags field as mapped status */ ++ c->tags = 1; ++ updatesizehints(c); ++ updatesystrayicongeom(c, wa.width, wa.height); ++ XAddToSaveSet(dpy, c->win); ++ XSelectInput(dpy, c->win, StructureNotifyMask | PropertyChangeMask | ResizeRedirectMask); ++ XReparentWindow(dpy, c->win, systray->win, 0, 0); ++ /* use parents background color */ ++ swa.background_pixel = scheme[SchemeNorm][ColBg].pixel; ++ XChangeWindowAttributes(dpy, c->win, CWBackPixel, &swa); ++ sendevent(c->win, netatom[Xembed], StructureNotifyMask, CurrentTime, XEMBED_EMBEDDED_NOTIFY, 0 , systray->win, XEMBED_EMBEDDED_VERSION); ++ /* FIXME not sure if I have to send these events, too */ ++ sendevent(c->win, netatom[Xembed], StructureNotifyMask, CurrentTime, XEMBED_FOCUS_IN, 0 , systray->win, XEMBED_EMBEDDED_VERSION); ++ sendevent(c->win, netatom[Xembed], StructureNotifyMask, CurrentTime, XEMBED_WINDOW_ACTIVATE, 0 , systray->win, XEMBED_EMBEDDED_VERSION); ++ sendevent(c->win, netatom[Xembed], StructureNotifyMask, CurrentTime, XEMBED_MODALITY_ON, 0 , systray->win, XEMBED_EMBEDDED_VERSION); ++ XSync(dpy, False); ++ resizebarwin(selmon); ++ updatesystray(); ++ setclientstate(c, NormalState); ++ } ++ return; ++ } + if (!c) + return; + if (cme->message_type == netatom[NetWMState]) { +@@ -568,7 +656,7 @@ configurenotify(XEvent *e) + for (c = m->clients; c; c = c->next) + if (c->isfullscreen) + resizeclient(c, m->mx, m->my, m->mw, m->mh); +- XMoveResizeWindow(dpy, m->barwin, m->wx, m->by, m->ww, bh); ++ resizebarwin(m); + } + focus(NULL); + arrange(NULL); +@@ -653,6 +741,11 @@ destroynotify(XEvent *e) + + if ((c = wintoclient(ev->window))) + unmanage(c, 1); ++ else if ((c = wintosystrayicon(ev->window))) { ++ removesystrayicon(c); ++ resizebarwin(selmon); ++ updatesystray(); ++ } + } + + void +@@ -696,19 +789,23 @@ dirtomon(int dir) + void + drawbar(Monitor *m) + { +- int x, w, tw = 0; ++ int x, w, tw = 0, stw = 0; + int boxs = drw->fonts->h / 9; + int boxw = drw->fonts->h / 6 + 2; + unsigned int i, occ = 0, urg = 0; + Client *c; + ++ if(showsystray && m == systraytomon(m)) ++ stw = getsystraywidth(); ++ + /* draw status first so it can be overdrawn by tags later */ + if (m == selmon) { /* status is only drawn on selected monitor */ + drw_setscheme(drw, scheme[SchemeNorm]); +- tw = TEXTW(stext) - lrpad + 2; /* 2px right padding */ +- drw_text(drw, m->ww - tw, 0, tw, bh, 0, stext, 0); ++ tw = TEXTW(stext) - lrpad / 2 + 2; /* 2px right padding */ ++ drw_text(drw, m->ww - tw - stw, 0, tw, bh, lrpad / 2 - 2, stext, 0); + } + ++ resizebarwin(m); + for (c = m->clients; c; c = c->next) { + occ |= c->tags; + if (c->isurgent) +@@ -729,7 +826,7 @@ drawbar(Monitor *m) + drw_setscheme(drw, scheme[SchemeNorm]); + x = drw_text(drw, x, 0, w, bh, lrpad / 2, m->ltsymbol, 0); + +- if ((w = m->ww - tw - x) > bh) { ++ if ((w = m->ww - tw - stw - x) > bh) { + if (m->sel) { + drw_setscheme(drw, scheme[m == selmon ? SchemeSel : SchemeNorm]); + drw_text(drw, x, 0, w, bh, lrpad / 2, m->sel->name, 0); +@@ -740,7 +837,7 @@ drawbar(Monitor *m) + drw_rect(drw, x, 0, w, bh, 1, 1); + } + } +- drw_map(drw, m->barwin, 0, 0, m->ww, bh); ++ drw_map(drw, m->barwin, 0, 0, m->ww - stw, bh); + } + + void +@@ -777,8 +874,11 @@ expose(XEvent *e) + Monitor *m; + XExposeEvent *ev = &e->xexpose; + +- if (ev->count == 0 && (m = wintomon(ev->window))) ++ if (ev->count == 0 && (m = wintomon(ev->window))) { + drawbar(m); ++ if (m == selmon) ++ updatesystray(); ++ } + } + + void +@@ -863,10 +963,17 @@ getatomprop(Client *c, Atom prop) + unsigned long dl; + unsigned char *p = NULL; + Atom da, atom = None; ++ /* FIXME getatomprop should return the number of items and a pointer to ++ * the stored data instead of this workaround */ ++ Atom req = XA_ATOM; ++ if (prop == xatom[XembedInfo]) ++ req = xatom[XembedInfo]; + +- if (XGetWindowProperty(dpy, c->win, prop, 0L, sizeof atom, False, XA_ATOM, ++ if (XGetWindowProperty(dpy, c->win, prop, 0L, sizeof atom, False, req, + &da, &di, &dl, &dl, &p) == Success && p) { + atom = *(Atom *)p; ++ if (da == xatom[XembedInfo] && dl == 2) ++ atom = ((Atom *)p)[1]; + XFree(p); + } + return atom; +@@ -900,6 +1007,16 @@ getstate(Window w) + return result; + } + ++unsigned int ++getsystraywidth() ++{ ++ unsigned int w = 0; ++ Client *i; ++ if(showsystray) ++ for(i = systray->icons; i; w += i->w + systrayspacing, i = i->next) ; ++ return w ? w + systrayspacing : 1; ++} ++ + int + gettextprop(Window w, Atom atom, char *text, unsigned int size) + { +@@ -1004,7 +1121,7 @@ killclient(const Arg *arg) + { + if (!selmon->sel) + return; +- if (!sendevent(selmon->sel, wmatom[WMDelete])) { ++ if (!sendevent(selmon->sel->win, wmatom[WMDelete], NoEventMask, wmatom[WMDelete], CurrentTime, 0 , 0, 0)) { + XGrabServer(dpy); + XSetErrorHandler(xerrordummy); + XSetCloseDownMode(dpy, DestroyAll); +@@ -1092,6 +1209,12 @@ maprequest(XEvent *e) + { + static XWindowAttributes wa; + XMapRequestEvent *ev = &e->xmaprequest; ++ Client *i; ++ if ((i = wintosystrayicon(ev->window))) { ++ sendevent(i->win, netatom[Xembed], StructureNotifyMask, CurrentTime, XEMBED_WINDOW_ACTIVATE, 0, systray->win, XEMBED_EMBEDDED_VERSION); ++ resizebarwin(selmon); ++ updatesystray(); ++ } + + if (!XGetWindowAttributes(dpy, ev->window, &wa)) + return; +@@ -1216,6 +1339,16 @@ propertynotify(XEvent *e) + Window trans; + XPropertyEvent *ev = &e->xproperty; + ++ if ((c = wintosystrayicon(ev->window))) { ++ if (ev->atom == XA_WM_NORMAL_HINTS) { ++ updatesizehints(c); ++ updatesystrayicongeom(c, c->w, c->h); ++ } ++ else ++ updatesystrayiconstate(c, ev); ++ resizebarwin(selmon); ++ updatesystray(); ++ } + if ((ev->window == root) && (ev->atom == XA_WM_NAME)) + updatestatus(); + else if (ev->state == PropertyDelete) +@@ -1266,6 +1399,20 @@ recttomon(int x, int y, int w, int h) + return r; + } + ++void ++removesystrayicon(Client *i) ++{ ++ Client **ii; ++ ++ if (!showsystray || !i) ++ return; ++ for (ii = &systray->icons; *ii && *ii != i; ii = &(*ii)->next); ++ if (ii) ++ *ii = i->next; ++ free(i); ++} ++ ++ + void + resize(Client *c, int x, int y, int w, int h, int interact) + { +@@ -1273,6 +1420,14 @@ resize(Client *c, int x, int y, int w, int h, int interact) + resizeclient(c, x, y, w, h); + } + ++void ++resizebarwin(Monitor *m) { ++ unsigned int w = m->ww; ++ if (showsystray && m == systraytomon(m)) ++ w -= getsystraywidth(); ++ XMoveResizeWindow(dpy, m->barwin, m->wx, m->by, w, bh); ++} ++ + void + resizeclient(Client *c, int x, int y, int w, int h) + { +@@ -1345,6 +1500,19 @@ resizemouse(const Arg *arg) + } + } + ++void ++resizerequest(XEvent *e) ++{ ++ XResizeRequestEvent *ev = &e->xresizerequest; ++ Client *i; ++ ++ if ((i = wintosystrayicon(ev->window))) { ++ updatesystrayicongeom(i, ev->width, ev->height); ++ resizebarwin(selmon); ++ updatesystray(); ++ } ++} ++ + void + restack(Monitor *m) + { +@@ -1434,26 +1602,36 @@ setclientstate(Client *c, long state) + } + + int +-sendevent(Client *c, Atom proto) ++sendevent(Window w, Atom proto, int mask, long d0, long d1, long d2, long d3, long d4) + { + int n; +- Atom *protocols; ++ Atom *protocols, mt; + int exists = 0; + XEvent ev; + +- if (XGetWMProtocols(dpy, c->win, &protocols, &n)) { +- while (!exists && n--) +- exists = protocols[n] == proto; +- XFree(protocols); ++ if (proto == wmatom[WMTakeFocus] || proto == wmatom[WMDelete]) { ++ mt = wmatom[WMProtocols]; ++ if (XGetWMProtocols(dpy, w, &protocols, &n)) { ++ while (!exists && n--) ++ exists = protocols[n] == proto; ++ XFree(protocols); ++ } ++ } ++ else { ++ exists = True; ++ mt = proto; + } + if (exists) { + ev.type = ClientMessage; +- ev.xclient.window = c->win; +- ev.xclient.message_type = wmatom[WMProtocols]; ++ ev.xclient.window = w; ++ ev.xclient.message_type = mt; + ev.xclient.format = 32; +- ev.xclient.data.l[0] = proto; +- ev.xclient.data.l[1] = CurrentTime; +- XSendEvent(dpy, c->win, False, NoEventMask, &ev); ++ ev.xclient.data.l[0] = d0; ++ ev.xclient.data.l[1] = d1; ++ ev.xclient.data.l[2] = d2; ++ ev.xclient.data.l[3] = d3; ++ ev.xclient.data.l[4] = d4; ++ XSendEvent(dpy, w, False, mask, &ev); + } + return exists; + } +@@ -1467,7 +1645,7 @@ setfocus(Client *c) + XA_WINDOW, 32, PropModeReplace, + (unsigned char *) &(c->win), 1); + } +- sendevent(c, wmatom[WMTakeFocus]); ++ sendevent(c->win, wmatom[WMTakeFocus], NoEventMask, wmatom[WMTakeFocus], CurrentTime, 0, 0, 0); + } + + void +@@ -1556,6 +1734,10 @@ setup(void) + wmatom[WMTakeFocus] = XInternAtom(dpy, "WM_TAKE_FOCUS", False); + netatom[NetActiveWindow] = XInternAtom(dpy, "_NET_ACTIVE_WINDOW", False); + netatom[NetSupported] = XInternAtom(dpy, "_NET_SUPPORTED", False); ++ netatom[NetSystemTray] = XInternAtom(dpy, "_NET_SYSTEM_TRAY_S0", False); ++ netatom[NetSystemTrayOP] = XInternAtom(dpy, "_NET_SYSTEM_TRAY_OPCODE", False); ++ netatom[NetSystemTrayOrientation] = XInternAtom(dpy, "_NET_SYSTEM_TRAY_ORIENTATION", False); ++ netatom[NetSystemTrayOrientationHorz] = XInternAtom(dpy, "_NET_SYSTEM_TRAY_ORIENTATION_HORZ", False); + netatom[NetWMName] = XInternAtom(dpy, "_NET_WM_NAME", False); + netatom[NetWMState] = XInternAtom(dpy, "_NET_WM_STATE", False); + netatom[NetWMCheck] = XInternAtom(dpy, "_NET_SUPPORTING_WM_CHECK", False); +@@ -1563,6 +1745,9 @@ setup(void) + netatom[NetWMWindowType] = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE", False); + netatom[NetWMWindowTypeDialog] = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_DIALOG", False); + netatom[NetClientList] = XInternAtom(dpy, "_NET_CLIENT_LIST", False); ++ xatom[Manager] = XInternAtom(dpy, "MANAGER", False); ++ xatom[Xembed] = XInternAtom(dpy, "_XEMBED", False); ++ xatom[XembedInfo] = XInternAtom(dpy, "_XEMBED_INFO", False); + /* init cursors */ + cursor[CurNormal] = drw_cur_create(drw, XC_left_ptr); + cursor[CurResize] = drw_cur_create(drw, XC_sizing); +@@ -1571,6 +1756,8 @@ setup(void) + scheme = ecalloc(LENGTH(colors), sizeof(Clr *)); + for (i = 0; i < LENGTH(colors); i++) + scheme[i] = drw_scm_create(drw, colors[i], 3); ++ /* init system tray */ ++ updatesystray(); + /* init bars */ + updatebars(); + updatestatus(); +@@ -1704,7 +1891,18 @@ togglebar(const Arg *arg) + { + selmon->showbar = !selmon->showbar; + updatebarpos(selmon); +- XMoveResizeWindow(dpy, selmon->barwin, selmon->wx, selmon->by, selmon->ww, bh); ++ resizebarwin(selmon); ++ if (showsystray) { ++ XWindowChanges wc; ++ if (!selmon->showbar) ++ wc.y = -bh; ++ else if (selmon->showbar) { ++ wc.y = 0; ++ if (!selmon->topbar) ++ wc.y = selmon->mh - bh; ++ } ++ XConfigureWindow(dpy, systray->win, CWY, &wc); ++ } + arrange(selmon); + } + +@@ -1799,11 +1997,18 @@ unmapnotify(XEvent *e) + else + unmanage(c, 0); + } ++ else if ((c = wintosystrayicon(ev->window))) { ++ /* KLUDGE! sometimes icons occasionally unmap their windows, but do ++ * _not_ destroy them. We map those windows back */ ++ XMapRaised(dpy, c->win); ++ updatesystray(); ++ } + } + + void + updatebars(void) + { ++ unsigned int w; + Monitor *m; + XSetWindowAttributes wa = { + .override_redirect = True, +@@ -1814,10 +2019,15 @@ updatebars(void) + for (m = mons; m; m = m->next) { + if (m->barwin) + continue; +- m->barwin = XCreateWindow(dpy, root, m->wx, m->by, m->ww, bh, 0, DefaultDepth(dpy, screen), ++ w = m->ww; ++ if (showsystray && m == systraytomon(m)) ++ w -= getsystraywidth(); ++ m->barwin = XCreateWindow(dpy, root, m->wx, m->by, w, bh, 0, DefaultDepth(dpy, screen), + CopyFromParent, DefaultVisual(dpy, screen), + CWOverrideRedirect|CWBackPixmap|CWEventMask, &wa); + XDefineCursor(dpy, m->barwin, cursor[CurNormal]->cursor); ++ if (showsystray && m == systraytomon(m)) ++ XMapRaised(dpy, systray->win); + XMapRaised(dpy, m->barwin); + XSetClassHint(dpy, m->barwin, &ch); + } +@@ -1993,6 +2203,121 @@ updatestatus(void) + if (!gettextprop(root, XA_WM_NAME, stext, sizeof(stext))) + strcpy(stext, "dwm-"VERSION); + drawbar(selmon); ++ updatesystray(); ++} ++ ++void ++updatesystrayicongeom(Client *i, int w, int h) ++{ ++ if (i) { ++ i->h = bh; ++ if (w == h) ++ i->w = bh; ++ else if (h == bh) ++ i->w = w; ++ else ++ i->w = (int) ((float)bh * ((float)w / (float)h)); ++ applysizehints(i, &(i->x), &(i->y), &(i->w), &(i->h), False); ++ /* force icons into the systray dimensions if they don't want to */ ++ if (i->h > bh) { ++ if (i->w == i->h) ++ i->w = bh; ++ else ++ i->w = (int) ((float)bh * ((float)i->w / (float)i->h)); ++ i->h = bh; ++ } ++ } ++} ++ ++void ++updatesystrayiconstate(Client *i, XPropertyEvent *ev) ++{ ++ long flags; ++ int code = 0; ++ ++ if (!showsystray || !i || ev->atom != xatom[XembedInfo] || ++ !(flags = getatomprop(i, xatom[XembedInfo]))) ++ return; ++ ++ if (flags & XEMBED_MAPPED && !i->tags) { ++ i->tags = 1; ++ code = XEMBED_WINDOW_ACTIVATE; ++ XMapRaised(dpy, i->win); ++ setclientstate(i, NormalState); ++ } ++ else if (!(flags & XEMBED_MAPPED) && i->tags) { ++ i->tags = 0; ++ code = XEMBED_WINDOW_DEACTIVATE; ++ XUnmapWindow(dpy, i->win); ++ setclientstate(i, WithdrawnState); ++ } ++ else ++ return; ++ sendevent(i->win, xatom[Xembed], StructureNotifyMask, CurrentTime, code, 0, ++ systray->win, XEMBED_EMBEDDED_VERSION); ++} ++ ++void ++updatesystray(void) ++{ ++ XSetWindowAttributes wa; ++ XWindowChanges wc; ++ Client *i; ++ Monitor *m = systraytomon(NULL); ++ unsigned int x = m->mx + m->mw; ++ unsigned int w = 1; ++ ++ if (!showsystray) ++ return; ++ if (!systray) { ++ /* init systray */ ++ if (!(systray = (Systray *)calloc(1, sizeof(Systray)))) ++ die("fatal: could not malloc() %u bytes\n", sizeof(Systray)); ++ systray->win = XCreateSimpleWindow(dpy, root, x, m->by, w, bh, 0, 0, scheme[SchemeSel][ColBg].pixel); ++ wa.event_mask = ButtonPressMask | ExposureMask; ++ wa.override_redirect = True; ++ wa.background_pixel = scheme[SchemeNorm][ColBg].pixel; ++ XSelectInput(dpy, systray->win, SubstructureNotifyMask); ++ XChangeProperty(dpy, systray->win, netatom[NetSystemTrayOrientation], XA_CARDINAL, 32, ++ PropModeReplace, (unsigned char *)&netatom[NetSystemTrayOrientationHorz], 1); ++ XChangeWindowAttributes(dpy, systray->win, CWEventMask|CWOverrideRedirect|CWBackPixel, &wa); ++ XMapRaised(dpy, systray->win); ++ XSetSelectionOwner(dpy, netatom[NetSystemTray], systray->win, CurrentTime); ++ if (XGetSelectionOwner(dpy, netatom[NetSystemTray]) == systray->win) { ++ sendevent(root, xatom[Manager], StructureNotifyMask, CurrentTime, netatom[NetSystemTray], systray->win, 0, 0); ++ XSync(dpy, False); ++ } ++ else { ++ fprintf(stderr, "dwm: unable to obtain system tray.\n"); ++ free(systray); ++ systray = NULL; ++ return; ++ } ++ } ++ for (w = 0, i = systray->icons; i; i = i->next) { ++ /* make sure the background color stays the same */ ++ wa.background_pixel = scheme[SchemeNorm][ColBg].pixel; ++ XChangeWindowAttributes(dpy, i->win, CWBackPixel, &wa); ++ XMapRaised(dpy, i->win); ++ w += systrayspacing; ++ i->x = w; ++ XMoveResizeWindow(dpy, i->win, i->x, 0, i->w, i->h); ++ w += i->w; ++ if (i->mon != m) ++ i->mon = m; ++ } ++ w = w ? w + systrayspacing : 1; ++ x -= w; ++ XMoveResizeWindow(dpy, systray->win, x, m->by, w, bh); ++ wc.x = x; wc.y = m->by; wc.width = w; wc.height = bh; ++ wc.stack_mode = Above; wc.sibling = m->barwin; ++ XConfigureWindow(dpy, systray->win, CWX|CWY|CWWidth|CWHeight|CWSibling|CWStackMode, &wc); ++ XMapWindow(dpy, systray->win); ++ XMapSubwindows(dpy, systray->win); ++ /* redraw background */ ++ XSetForeground(dpy, drw->gc, scheme[SchemeNorm][ColBg].pixel); ++ XFillRectangle(dpy, systray->win, drw->gc, 0, 0, w, bh); ++ XSync(dpy, False); + } + + void +@@ -2060,6 +2385,16 @@ wintoclient(Window w) + return NULL; + } + ++Client * ++wintosystrayicon(Window w) { ++ Client *i = NULL; ++ ++ if (!showsystray || !w) ++ return i; ++ for (i = systray->icons; i && i->win != w; i = i->next) ; ++ return i; ++} ++ + Monitor * + wintomon(Window w) + { +@@ -2113,6 +2448,22 @@ xerrorstart(Display *dpy, XErrorEvent *ee) + return -1; + } + ++Monitor * ++systraytomon(Monitor *m) { ++ Monitor *t; ++ int i, n; ++ if(!systraypinning) { ++ if(!m) ++ return selmon; ++ return m == selmon ? m : NULL; ++ } ++ for(n = 1, t = mons; t && t->next; n++, t = t->next) ; ++ for(i = 1, t = mons; t && t->next && i < systraypinning; i++, t = t->next) ; ++ if(systraypinningfailfirst && n < systraypinning) ++ return mons; ++ return t; ++} ++ + void + zoom(const Arg *arg) + { diff --git a/suckless/dwm/dwm.1 b/suckless/dwm/dwm.1 new file mode 100644 index 00000000..f40bbbba --- /dev/null +++ b/suckless/dwm/dwm.1 @@ -0,0 +1,185 @@ +.TH DWM 1 dwm\-VERSION +.SH NAME +dwm \- dynamic window manager +.SH SYNOPSIS +.B dwm +.RB [ \-v ] +.SH DESCRIPTION +dwm is a dynamic window manager for X. It manages windows in tiled, monocle +and floating layouts. Either layout can be applied dynamically, optimising the +environment for the application in use and the task performed. +.P +In tiled layouts windows are managed in a master and stacking area. The master +area on the left contains one window by default, and the stacking area on the +right contains all other windows. The number of master area windows can be +adjusted from zero to an arbitrary number. In monocle layout all windows are +maximised to the screen size. In floating layout windows can be resized and +moved freely. Dialog windows are always managed floating, regardless of the +layout applied. +.P +Windows are grouped by tags. Each window can be tagged with one or multiple +tags. Selecting certain tags displays all windows with these tags. +.P +Each screen contains a small status bar which displays all available tags, the +layout, the title of the focused window, and the text read from the root window +name property, if the screen is focused. A floating window is indicated with an +empty square and a maximised floating window is indicated with a filled square +before the windows title. The selected tags are indicated with a different +color. The tags of the focused window are indicated with a filled square in the +top left corner. The tags which are applied to one or more windows are +indicated with an empty square in the top left corner. +.P +dwm draws a small border around windows to indicate the focus state. +.SH OPTIONS +.TP +.B \-v +prints version information to stderr, then exits. +.SH USAGE +.SS Status bar +.TP +.B X root window name +is read and displayed in the status text area. It can be set with the +.BR xsetroot (1) +command. +.TP +.B Button1 +click on a tag label to display all windows with that tag, click on the layout +label toggles between tiled and floating layout. +.TP +.B Button3 +click on a tag label adds/removes all windows with that tag to/from the view. +.TP +.B Mod1\-Button1 +click on a tag label applies that tag to the focused window. +.TP +.B Mod1\-Button3 +click on a tag label adds/removes that tag to/from the focused window. +.SS Keyboard commands +.TP +.B Mod1\-Shift\-Return +Start +.BR st(1). +.TP +.B Mod1\-p +Spawn +.BR dmenu(1) +for launching other programs. +.TP +.B Mod1\-, +Focus previous screen, if any. +.TP +.B Mod1\-. +Focus next screen, if any. +.TP +.B Mod1\-Shift\-, +Send focused window to previous screen, if any. +.TP +.B Mod1\-Shift\-. +Send focused window to next screen, if any. +.TP +.B Mod1\-b +Toggles bar on and off. +.TP +.B Mod1\-t +Sets tiled layout. +.TP +.B Mod1\-f +Sets floating layout. +.TP +.B Mod1\-m +Sets monocle layout. +.TP +.B Mod1\-space +Toggles between current and previous layout. +.TP +.B Mod1\-Control\-, +Cycles backwards in layout list. +.TP +.B Mod1\-Control\-. +Cycles forwards in layout list. +.TP +.B Mod1\-j +Focus next window. +.TP +.B Mod1\-k +Focus previous window. +.TP +.B Mod1\-i +Increase number of windows in master area. +.TP +.B Mod1\-d +Decrease number of windows in master area. +.TP +.B Mod1\-l +Increase master area size. +.TP +.B Mod1\-h +Decrease master area size. +.TP +.B Mod1\-o +Select view of the window in focus. The list of tags to be displayed is matched to the window tag list. +.TP +.B Mod1\-Return +Zooms/cycles focused window to/from master area (tiled layouts only). +.TP +.B Mod1\-Shift\-c +Close focused window. +.TP +.B Mod1\-Shift\-space +Toggle focused window between tiled and floating state. +.TP +.B Mod1\-Tab +Toggles to the previously selected tags. +.TP +.B Mod1\-Shift\-[1..n] +Apply nth tag to focused window. +.TP +.B Mod1\-Shift\-0 +Apply all tags to focused window. +.TP +.B Mod1\-Control\-Shift\-[1..n] +Add/remove nth tag to/from focused window. +.TP +.B Mod1\-[1..n] +View all windows with nth tag. +.TP +.B Mod1\-0 +View all windows with any tag. +.TP +.B Mod1\-Control\-[1..n] +Add/remove all windows with nth tag to/from the view. +.TP +.B Mod1\-Shift\-q +Quit dwm. +.SS Mouse commands +.TP +.B Mod1\-Button1 +Move focused window while dragging. Tiled windows will be toggled to the floating state. +.TP +.B Mod1\-Button2 +Toggles focused window between floating and tiled state. +.TP +.B Mod1\-Button3 +Resize focused window while dragging. Tiled windows will be toggled to the floating state. +.SH CUSTOMIZATION +dwm is customized by creating a custom config.h and (re)compiling the source +code. This keeps it fast, secure and simple. +.SH SEE ALSO +.BR dmenu (1), +.BR st (1) +.SH ISSUES +Java applications which use the XToolkit/XAWT backend may draw grey windows +only. The XToolkit/XAWT backend breaks ICCCM-compliance in recent JDK 1.5 and early +JDK 1.6 versions, because it assumes a reparenting window manager. Possible workarounds +are using JDK 1.4 (which doesn't contain the XToolkit/XAWT backend) or setting the +environment variable +.BR AWT_TOOLKIT=MToolkit +(to use the older Motif backend instead) or running +.B xprop -root -f _NET_WM_NAME 32a -set _NET_WM_NAME LG3D +or +.B wmname LG3D +(to pretend that a non-reparenting window manager is running that the +XToolkit/XAWT backend can recognize) or when using OpenJDK setting the environment variable +.BR _JAVA_AWT_WM_NONREPARENTING=1 . +.SH BUGS +Send all bug reports with a patch to hackers@suckless.org. diff --git a/suckless/dwm/dwm.c b/suckless/dwm/dwm.c new file mode 100644 index 00000000..dcf0e94b --- /dev/null +++ b/suckless/dwm/dwm.c @@ -0,0 +1,2768 @@ +/* See LICENSE file for copyright and license details. + * + * dynamic window manager is designed like any other X client as well. It is + * driven through handling X events. In contrast to other X clients, a window + * manager selects for SubstructureRedirectMask on the root window, to receive + * events about window (dis-)appearance. Only one X connection at a time is + * allowed to select for this event mask. + * + * The event handlers of dwm are organized in an array which is accessed + * whenever a new event has been fetched. This allows event dispatching + * in O(1) time. + * + * Each child of the root window is called a client, except windows which have + * set the override_redirect flag. Clients are organized in a linked client + * list on each monitor, the focus history is remembered through a stack list + * on each monitor. Each client contains a bit array to indicate the tags of a + * client. + * + * Keys and tagging rules are organized as arrays and defined in config.h. + * + * To understand everything else, start reading main(). + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef XINERAMA +#include +#endif /* XINERAMA */ +#include +#include +#include + +#include "drw.h" +#include "util.h" + +/* macros */ +#define BUTTONMASK (ButtonPressMask|ButtonReleaseMask) +#define CLEANMASK(mask) (mask & ~(numlockmask|LockMask) & (ShiftMask|ControlMask|Mod1Mask|Mod2Mask|Mod3Mask|Mod4Mask|Mod5Mask)) +#define INTERSECT(x,y,w,h,m) (MAX(0, MIN((x)+(w),(m)->wx+(m)->ww) - MAX((x),(m)->wx)) \ + * MAX(0, MIN((y)+(h),(m)->wy+(m)->wh) - MAX((y),(m)->wy))) +#define ISVISIBLE(C) ((C->tags & C->mon->tagset[C->mon->seltags])) +#define LENGTH(X) (sizeof X / sizeof X[0]) +#define MOUSEMASK (BUTTONMASK|PointerMotionMask) +#define WIDTH(X) ((X)->w + 2 * (X)->bw + gappx) +#define HEIGHT(X) ((X)->h + 2 * (X)->bw + gappx) +#define TAGMASK ((1 << LENGTH(tags)) - 1) +#define TAGSLENGTH (LENGTH(tags)) +#define TEXTW(X) (drw_fontset_getwidth(drw, (X)) + lrpad) +#define TTEXTW(X) drw_fontset_getwidth(drw, (X)) + +#define DWMBLOCKSLOCKFILE "/tmp/dwmblocks.pid" + +/* enums */ +enum { CurNormal, CurHand, CurResize, CurMove, CurLast }; /* cursor */ +enum { SchemeNorm, SchemeSel, SchemeStatus, SchemeTagsSel, SchemeTagsNorm, SchemeInfoSel, SchemeInfoNorm, SchemeCol1, SchemeCol2, SchemeCol3, + SchemeCol4, SchemeCol5, SchemeCol6, SchemeCol7, SchemeCol8, + SchemeCol9, SchemeCol10, SchemeCol11, SchemeCol12 }; /* color schemes */ +enum { NetSupported, NetWMName, NetWMState, NetWMCheck, + NetWMFullscreen, NetActiveWindow, NetWMWindowType, + NetWMWindowTypeDialog, NetClientList, NetClientListStacking, NetDesktopNames, NetDesktopViewport, NetNumberOfDesktops, NetCurrentDesktop, NetLast }; /* EWMH atoms */ +enum { WMProtocols, WMDelete, WMState, WMTakeFocus, WMLast }; /* default atoms */ +enum { ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle, + ClkClientWin, ClkRootWin, ClkLast }; /* clicks */ + +typedef union { + int i; + unsigned int ui; + float f; + const void *v; +} Arg; + +typedef struct { + unsigned int click; + unsigned int mask; + unsigned int button; + void (*func)(const Arg *arg); + const Arg arg; +} Button; + +typedef struct Monitor Monitor; +typedef struct Client Client; +struct Client { + char name[256]; + float mina, maxa; + float cfact; + int x, y, w, h; + int oldx, oldy, oldw, oldh; + int basew, baseh, incw, inch, maxw, maxh, minw, minh; + int bw, oldbw; + unsigned int tags; + int isfixed, isfloating, isurgent, neverfocus, oldstate, isfullscreen; + Client *next; + Client *snext; + Monitor *mon; + Window win; +}; + +typedef struct { + unsigned int mod; + KeySym keysym; + void (*func)(const Arg *); + const Arg arg; +} Key; + +typedef struct { + const char *symbol; + void (*arrange)(Monitor *); +} Layout; + +typedef struct Pertag Pertag; +struct Monitor { + char ltsymbol[16]; + float mfact; + int nmaster; + int num; + int by; /* bar geometry */ + int mx, my, mw, mh; /* screen size */ + int wx, wy, ww, wh; /* window area */ + unsigned int seltags; + unsigned int sellt; + unsigned int tagset[2]; + int rmaster; + int showbar; + int topbar; + Client *clients; + Client *sel; + Client *stack; + Monitor *next; + Window barwin; + const Layout *lt[2]; + Pertag *pertag; +}; + +typedef struct { + const char *class; + const char *instance; + const char *title; + unsigned int tags; + int isfloating; + int monitor; +} Rule; + +/* function declarations */ +static void applyrules(Client *c); +static int applysizehints(Client *c, int *x, int *y, int *w, int *h, int interact); +static void arrange(Monitor *m); +static void arrangemon(Monitor *m); +static void attach(Client *c); +static void attachstack(Client *c); +static void buttonpress(XEvent *e); +static void checkotherwm(void); +static void cleanup(void); +static void cleanupmon(Monitor *mon); +static void clientmessage(XEvent *e); +static void configure(Client *c); +static void configurenotify(XEvent *e); +static void configurerequest(XEvent *e); +static Monitor *createmon(void); +static void cyclelayout(const Arg *arg); +static void deck(Monitor *m); +static void destroynotify(XEvent *e); +static void detach(Client *c); +static void detachstack(Client *c); +static Monitor *dirtomon(int dir); +static void drawbar(Monitor *m); +static void drawbars(void); +static void enternotify(XEvent *e); +static void expose(XEvent *e); +static void focus(Client *c); +static void focusin(XEvent *e); +static void focusmon(const Arg *arg); +static void focusstack(const Arg *arg); +static Atom getatomprop(Client *c, Atom prop); +static int getrootptr(int *x, int *y); +static long getstate(Window w); +static int gettextprop(Window w, Atom atom, char *text, unsigned int size); +static void grabbuttons(Client *c, int focused); +static void grabkeys(void); +static void incnmaster(const Arg *arg); +static void inplacerotate(const Arg *arg); +static void keypress(XEvent *e); +static void killclient(const Arg *arg); +static void manage(Window w, XWindowAttributes *wa); +static void mappingnotify(XEvent *e); +static void maprequest(XEvent *e); +static void monocle(Monitor *m); +static void motionnotify(XEvent *e); +static void movemouse(const Arg *arg); +static Client *nexttiled(Client *c); +static void pop(Client *); +static void propertynotify(XEvent *e); +static void quit(const Arg *arg); +static Monitor *recttomon(int x, int y, int w, int h); +static void resize(Client *c, int x, int y, int w, int h, int interact); +static void resizeclient(Client *c, int x, int y, int w, int h); +static void resizemouse(const Arg *arg); +static void restack(Monitor *m); +static void run(void); +static void scan(void); +static int sendevent(Client *c, Atom proto); +static void sendmon(Client *c, Monitor *m); +static void setclientstate(Client *c, long state); +static void setcurrentdesktop(void); +static void setdesktopnames(void); +static void setfocus(Client *c); +static void setfullscreen(Client *c, int fullscreen); +static void setlayout(const Arg *arg); +static void setcfact(const Arg *arg); +static void setmfact(const Arg *arg); +static void setnumdesktops(void); +static void setup(void); +static void setviewport(void); +static void seturgent(Client *c, int urg); +static void showhide(Client *c); +static void sigchld(int unused); +static void sigdwmblocks(const Arg *arg); +static void spawn(const Arg *arg); +static void switchcol(const Arg *arg); +static void tag(const Arg *arg); +static void tagmon(const Arg *arg); +static void tile(Monitor *); +static void togglebar(const Arg *arg); +static void togglefloating(const Arg *arg); +static void togglermaster(const Arg *arg); +static void togglefullscr(const Arg *arg); +static void toggletag(const Arg *arg); +static void toggleview(const Arg *arg); +static void unfocus(Client *c, int setfocus); +static void unmanage(Client *c, int destroyed); +static void unmapnotify(XEvent *e); +static void updatecurrentdesktop(void); +static void updatebarcursor(int cursorpos); +static void updatebarpos(Monitor *m); +static void updatebars(void); +static void updateclientlist(void); +static void updatedwmblockssig(int x, int e); +static int updategeom(void); +static void updatenumlockmask(void); +static void updatesizehints(Client *c); +static void updatestatus(void); +static void updatetitle(Client *c); +static void updatewindowtype(Client *c); +static void updatewmhints(Client *c); +static void view(const Arg *arg); +static Client *wintoclient(Window w); +static Monitor *wintomon(Window w); +static void winview(const Arg* arg); +static int xerror(Display *dpy, XErrorEvent *ee); +static int xerrordummy(Display *dpy, XErrorEvent *ee); +static int xerrorstart(Display *dpy, XErrorEvent *ee); +static void zoom(const Arg *arg); +static void centeredmaster(Monitor *m); +static void centeredfloatingmaster(Monitor *m); + +/* variables */ +static const char broken[] = "broken"; +static char stextc[256]; +static char stexts[256]; +static int wstext; +static int dwmblockssig; +static int screen; +static int sw, sh; /* X display screen geometry width, height */ +static int bh, blw = 0; /* bar geometry */ +static int lrpad; /* sum of left and right padding for text */ +static int vp; /* vertical padding for bar */ +static int sp; /* side padding for bar */ +static int (*xerrorxlib)(Display *, XErrorEvent *); +static unsigned int numlockmask = 0; +static void (*handler[LASTEvent]) (XEvent *) = { + [ButtonPress] = buttonpress, + [ClientMessage] = clientmessage, + [ConfigureRequest] = configurerequest, + [ConfigureNotify] = configurenotify, + [DestroyNotify] = destroynotify, + [Expose] = expose, + [FocusIn] = focusin, + [KeyPress] = keypress, + [MappingNotify] = mappingnotify, + [MapRequest] = maprequest, + [MotionNotify] = motionnotify, + [PropertyNotify] = propertynotify, + [UnmapNotify] = unmapnotify +}; +static Atom wmatom[WMLast], netatom[NetLast]; +static int running = 1; +static Cur *cursor[CurLast]; +static Clr **scheme; +static Display *dpy; +static Drw *drw; +static Monitor *mons, *selmon; +static Window root, wmcheckwin; + +/* configuration, allows nested code to access above variables */ +#include "config.h" + +struct Pertag { + unsigned int curtag, prevtag; /* current and previous tag */ + int nmasters[LENGTH(tags) + 1]; /* number of windows in master area */ + float mfacts[LENGTH(tags) + 1]; /* mfacts per tag */ + unsigned int sellts[LENGTH(tags) + 1]; /* selected layouts */ + const Layout *ltidxs[LENGTH(tags) + 1][2]; /* matrix of tags and layouts indexes */ + int showbars[LENGTH(tags) + 1]; /* display bar for the current tag */ +}; + +/* compile-time check if all tags fit into an unsigned int bit array. */ +struct NumTags { char limitexceeded[LENGTH(tags) > 31 ? -1 : 1]; }; + +/* function implementations */ +void +applyrules(Client *c) +{ + const char *class, *instance; + unsigned int i; + const Rule *r; + Monitor *m; + XClassHint ch = { NULL, NULL }; + + /* rule matching */ + c->isfloating = 0; + c->tags = 0; + XGetClassHint(dpy, c->win, &ch); + class = ch.res_class ? ch.res_class : broken; + instance = ch.res_name ? ch.res_name : broken; + + for (i = 0; i < LENGTH(rules); i++) { + r = &rules[i]; + if ((!r->title || strstr(c->name, r->title)) + && (!r->class || strstr(class, r->class)) + && (!r->instance || strstr(instance, r->instance))) + { + c->isfloating = r->isfloating; + c->tags |= r->tags; + for (m = mons; m && m->num != r->monitor; m = m->next); + if (m) + c->mon = m; + } + } + if (ch.res_class) + XFree(ch.res_class); + if (ch.res_name) + XFree(ch.res_name); + c->tags = c->tags & TAGMASK ? c->tags & TAGMASK : c->mon->tagset[c->mon->seltags]; +} + +int +applysizehints(Client *c, int *x, int *y, int *w, int *h, int interact) +{ + int baseismin; + Monitor *m = c->mon; + + /* set minimum possible */ + *w = MAX(1, *w); + *h = MAX(1, *h); + if (interact) { + if (*x > sw) + *x = sw - WIDTH(c); + if (*y > sh) + *y = sh - HEIGHT(c); + if (*x + *w + 2 * c->bw < 0) + *x = 0; + if (*y + *h + 2 * c->bw < 0) + *y = 0; + } else { + if (*x >= m->wx + m->ww) + *x = m->wx + m->ww - WIDTH(c); + if (*y >= m->wy + m->wh) + *y = m->wy + m->wh - HEIGHT(c); + if (*x + *w + 2 * c->bw <= m->wx) + *x = m->wx; + if (*y + *h + 2 * c->bw <= m->wy) + *y = m->wy; + } + if (*h < bh) + *h = bh; + if (*w < bh) + *w = bh; + if (resizehints || c->isfloating || !c->mon->lt[c->mon->sellt]->arrange) { + /* see last two sentences in ICCCM 4.1.2.3 */ + baseismin = c->basew == c->minw && c->baseh == c->minh; + if (!baseismin) { /* temporarily remove base dimensions */ + *w -= c->basew; + *h -= c->baseh; + } + /* adjust for aspect limits */ + if (c->mina > 0 && c->maxa > 0) { + if (c->maxa < (float)*w / *h) + *w = *h * c->maxa + 0.5; + else if (c->mina < (float)*h / *w) + *h = *w * c->mina + 0.5; + } + if (baseismin) { /* increment calculation requires this */ + *w -= c->basew; + *h -= c->baseh; + } + /* adjust for increment value */ + if (c->incw) + *w -= *w % c->incw; + if (c->inch) + *h -= *h % c->inch; + /* restore base dimensions */ + *w = MAX(*w + c->basew, c->minw); + *h = MAX(*h + c->baseh, c->minh); + if (c->maxw) + *w = MIN(*w, c->maxw); + if (c->maxh) + *h = MIN(*h, c->maxh); + } + return *x != c->x || *y != c->y || *w != c->w || *h != c->h; +} + +void +arrange(Monitor *m) +{ + if (m) + showhide(m->stack); + else for (m = mons; m; m = m->next) + showhide(m->stack); + if (m) { + arrangemon(m); + restack(m); + } else for (m = mons; m; m = m->next) + arrangemon(m); +} + +void +arrangemon(Monitor *m) +{ + strncpy(m->ltsymbol, m->lt[m->sellt]->symbol, sizeof m->ltsymbol); + if (m->lt[m->sellt]->arrange) + m->lt[m->sellt]->arrange(m); +} + +void +attach(Client *c) +{ + c->next = c->mon->clients; + c->mon->clients = c; +} + +void +attachstack(Client *c) +{ + c->snext = c->mon->stack; + c->mon->stack = c; +} + +void +buttonpress(XEvent *e) +{ + unsigned int i, x, click; + Arg arg = {0}; + Client *c; + Monitor *m; + XButtonPressedEvent *ev = &e->xbutton; + + click = ClkRootWin; + /* focus monitor if necessary */ + if ((m = wintomon(ev->window)) && m != selmon) { + unfocus(selmon->sel, 1); + selmon = m; + focus(NULL); + } + if (ev->window == selmon->barwin) { + i = x = 0; + do + x += TEXTW(tags[i]); + while (ev->x >= x && ++i < LENGTH(tags)); + if (i < LENGTH(tags)) { + click = ClkTagBar; + arg.ui = 1 << i; + } else if (ev->x < x + blw) + click = ClkLtSymbol; + else if (ev->x < selmon->ww - wstext) + click = ClkWinTitle; +// else if (ev->x < selmon->ww - lrpad / 2 && ev->x >= (x = selmon->ww - wstext + lrpad / 2)) { + else if (ev->x < selmon->ww - lrpad / 2 && ev->x >= selmon->ww - wstext + lrpad / 2) { + click = ClkStatusText; +// updatedwmblockssig(x, ev->x); + } else + return; + } else if ((c = wintoclient(ev->window))) { + focus(c); + restack(selmon); + XAllowEvents(dpy, ReplayPointer, CurrentTime); + click = ClkClientWin; + } + for (i = 0; i < LENGTH(buttons); i++) + if (click == buttons[i].click && buttons[i].func && buttons[i].button == ev->button + && CLEANMASK(buttons[i].mask) == CLEANMASK(ev->state)) + buttons[i].func(click == ClkTagBar && buttons[i].arg.i == 0 ? &arg : &buttons[i].arg); +} + +void +checkotherwm(void) +{ + xerrorxlib = XSetErrorHandler(xerrorstart); + /* this causes an error if some other window manager is running */ + XSelectInput(dpy, DefaultRootWindow(dpy), SubstructureRedirectMask); + XSync(dpy, False); + XSetErrorHandler(xerror); + XSync(dpy, False); +} + +void +cleanup(void) +{ + Arg a = {.ui = ~0}; + Layout foo = { "", NULL }; + Monitor *m; + size_t i; + + view(&a); + selmon->lt[selmon->sellt] = &foo; + for (m = mons; m; m = m->next) + while (m->stack) + unmanage(m->stack, 0); + XUngrabKey(dpy, AnyKey, AnyModifier, root); + while (mons) + cleanupmon(mons); + for (i = 0; i < CurLast; i++) + drw_cur_free(drw, cursor[i]); + for (i = 0; i < LENGTH(colors); i++) + free(scheme[i]); + XDestroyWindow(dpy, wmcheckwin); + drw_free(drw); + XSync(dpy, False); + XSetInputFocus(dpy, PointerRoot, RevertToPointerRoot, CurrentTime); + XDeleteProperty(dpy, root, netatom[NetActiveWindow]); +} + +void +cleanupmon(Monitor *mon) +{ + Monitor *m; + + if (mon == mons) + mons = mons->next; + else { + for (m = mons; m && m->next != mon; m = m->next); + m->next = mon->next; + } + XUnmapWindow(dpy, mon->barwin); + XDestroyWindow(dpy, mon->barwin); + free(mon); +} + +void +clientmessage(XEvent *e) +{ + XClientMessageEvent *cme = &e->xclient; + Client *c = wintoclient(cme->window); + + if (!c) + return; + if (cme->message_type == netatom[NetWMState]) { + if (cme->data.l[1] == netatom[NetWMFullscreen] + || cme->data.l[2] == netatom[NetWMFullscreen]) + setfullscreen(c, (cme->data.l[0] == 1 /* _NET_WM_STATE_ADD */ + || (cme->data.l[0] == 2 /* _NET_WM_STATE_TOGGLE */ && !c->isfullscreen))); + } else if (cme->message_type == netatom[NetActiveWindow]) { + if (c != selmon->sel && !c->isurgent) + seturgent(c, 1); + } +} + +void +configure(Client *c) +{ + XConfigureEvent ce; + + ce.type = ConfigureNotify; + ce.display = dpy; + ce.event = c->win; + ce.window = c->win; + ce.x = c->x; + ce.y = c->y; + ce.width = c->w; + ce.height = c->h; + ce.border_width = c->bw; + ce.above = None; + ce.override_redirect = False; + XSendEvent(dpy, c->win, False, StructureNotifyMask, (XEvent *)&ce); +} + +void +configurenotify(XEvent *e) +{ + Monitor *m; + Client *c; + XConfigureEvent *ev = &e->xconfigure; + int dirty; + + /* TODO: updategeom handling sucks, needs to be simplified */ + if (ev->window == root) { + dirty = (sw != ev->width || sh != ev->height); + sw = ev->width; + sh = ev->height; + if (updategeom() || dirty) { + drw_resize(drw, sw, bh); + updatebars(); + for (m = mons; m; m = m->next) { + for (c = m->clients; c; c = c->next) + if (c->isfullscreen) + resizeclient(c, m->mx, m->my, m->mw, m->mh); + XMoveResizeWindow(dpy, m->barwin, m->wx + sp, m->by + vp, m->ww - 2 * sp, bh); + } + focus(NULL); + arrange(NULL); + } + } +} + +void +configurerequest(XEvent *e) +{ + Client *c; + Monitor *m; + XConfigureRequestEvent *ev = &e->xconfigurerequest; + XWindowChanges wc; + + if ((c = wintoclient(ev->window))) { + if (ev->value_mask & CWBorderWidth) + c->bw = ev->border_width; + else if (c->isfloating || !selmon->lt[selmon->sellt]->arrange) { + m = c->mon; + if (ev->value_mask & CWX) { + c->oldx = c->x; + c->x = m->mx + ev->x; + } + if (ev->value_mask & CWY) { + c->oldy = c->y; + c->y = m->my + ev->y; + } + if (ev->value_mask & CWWidth) { + c->oldw = c->w; + c->w = ev->width; + } + if (ev->value_mask & CWHeight) { + c->oldh = c->h; + c->h = ev->height; + } + if ((c->x + c->w) > m->mx + m->mw && c->isfloating) + c->x = m->mx + (m->mw / 2 - WIDTH(c) / 2); /* center in x direction */ + if ((c->y + c->h) > m->my + m->mh && c->isfloating) + c->y = m->my + (m->mh / 2 - HEIGHT(c) / 2); /* center in y direction */ + if ((ev->value_mask & (CWX|CWY)) && !(ev->value_mask & (CWWidth|CWHeight))) + configure(c); + if (ISVISIBLE(c)) + XMoveResizeWindow(dpy, c->win, c->x, c->y, c->w, c->h); + } else + configure(c); + } else { + wc.x = ev->x; + wc.y = ev->y; + wc.width = ev->width; + wc.height = ev->height; + wc.border_width = ev->border_width; + wc.sibling = ev->above; + wc.stack_mode = ev->detail; + XConfigureWindow(dpy, ev->window, ev->value_mask, &wc); + } + XSync(dpy, False); +} + +Monitor * +createmon(void) +{ + Monitor *m; + unsigned int i; + + m = ecalloc(1, sizeof(Monitor)); + m->tagset[0] = m->tagset[1] = 1; + m->mfact = mfact; + m->nmaster = nmaster; + m->rmaster = rmaster; + m->showbar = showbar; + m->topbar = topbar; + m->lt[0] = &layouts[0]; + m->lt[1] = &layouts[1 % LENGTH(layouts)]; + strncpy(m->ltsymbol, layouts[0].symbol, sizeof m->ltsymbol); + m->pertag = ecalloc(1, sizeof(Pertag)); + m->pertag->curtag = m->pertag->prevtag = 1; + + for (i = 0; i <= LENGTH(tags); i++) { + m->pertag->nmasters[i] = m->nmaster; + m->pertag->mfacts[i] = m->mfact; + + m->pertag->ltidxs[i][0] = m->lt[0]; + m->pertag->ltidxs[i][1] = m->lt[1]; + m->pertag->sellts[i] = m->sellt; + + m->pertag->showbars[i] = m->showbar; + } + + return m; +} + +void +cyclelayout(const Arg *arg) { + Layout *l; + for(l = (Layout *)layouts; l != selmon->lt[selmon->sellt]; l++); + if(arg->i > 0) { + if(l->symbol && (l + 1)->symbol) + setlayout(&((Arg) { .v = (l + 1) })); + else + setlayout(&((Arg) { .v = layouts })); + } else { + if(l != layouts && (l - 1)->symbol) + setlayout(&((Arg) { .v = (l - 1) })); + else + setlayout(&((Arg) { .v = &layouts[LENGTH(layouts) - 2] })); + } +} + +void +deck(Monitor *m) { + unsigned int i, n, h, mw, my; + float mfacts = 0; + Client *c; + + for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++) { + if (n < m->nmaster) + mfacts += c->cfact; + } + if(n == 0) + return; + + if(n > m->nmaster) { + mw = m->nmaster ? m->ww * m->mfact : 0; + snprintf(m->ltsymbol, sizeof m->ltsymbol, "[%d]", n - m->nmaster); + } + else + mw = m->ww; + for(i = my = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++) + if(i < m->nmaster) { + h = (m->wh - my) * (c->cfact / mfacts); + resize(c, m->wx, m->wy + my, mw - (2*c->bw), h - (2*c->bw), False); + if (my + HEIGHT(c) < m->wh) + my += HEIGHT(c); + mfacts -= c->cfact; + } + else + resize(c, m->wx + mw, m->wy, m->ww - mw - (2*c->bw), m->wh - (2*c->bw), False); +} + +void +destroynotify(XEvent *e) +{ + Client *c; + XDestroyWindowEvent *ev = &e->xdestroywindow; + + if ((c = wintoclient(ev->window))) + unmanage(c, 1); +} + +void +detach(Client *c) +{ + Client **tc; + + for (tc = &c->mon->clients; *tc && *tc != c; tc = &(*tc)->next); + *tc = c->next; +} + +void +detachstack(Client *c) +{ + Client **tc, *t; + + for (tc = &c->mon->stack; *tc && *tc != c; tc = &(*tc)->snext); + *tc = c->snext; + + if (c == c->mon->sel) { + for (t = c->mon->stack; t && !ISVISIBLE(t); t = t->snext); + c->mon->sel = t; + } +} + +Monitor * +dirtomon(int dir) +{ + Monitor *m = NULL; + + if (dir > 0) { + if (!(m = selmon->next)) + m = mons; + } else if (selmon == mons) + for (m = mons; m->next; m = m->next); + else + for (m = mons; m->next != selmon; m = m->next); + return m; +} + +void +drawbar(Monitor *m) +{ + int x, w; + int boxs = drw->fonts->h / 9; + int boxw = drw->fonts->h / 6 + 2; + unsigned int i, occ = 0, urg = 0; + Client *c; + + /* draw status first so it can be overdrawn by tags later */ + if (m == selmon) { /* status is only drawn on selected monitor */ + char *ts = stextc; + char *tp = stextc; + char ctmp; + + drw_setscheme(drw, scheme[SchemeStatus]); + x = drw_text(drw, m->ww - wstext -2 * sp, 0, lrpad / 2, bh, 0, "", 0); /* to keep left padding clean */ + for (;;) { + if ((unsigned char)*ts > LENGTH(colors) + 10) { + ts++; + continue; + } + ctmp = *ts; + *ts = '\0'; + if (*tp != '\0') + x = drw_text(drw, x, 0, TTEXTW(tp), bh, 0, tp, 0); + if (ctmp == '\0') + break; + /* - 11 to compensate for + 10 above */ + drw_setscheme(drw, scheme[(unsigned char)ctmp - 11]); + *ts = ctmp; + tp = ++ts; + } + drw_setscheme(drw, scheme[SchemeNorm]); + drw_text(drw, x, 0, m->ww - x, bh, 0, "", 0); /* to keep right padding clean */ + } + + for (c = m->clients; c; c = c->next) { + occ |= c->tags; + if (c->isurgent) + urg |= c->tags; + } + x = 0; + for (i = 0; i < LENGTH(tags); i++) { + w = TEXTW(tags[i]); + drw_setscheme(drw, scheme[m->tagset[m->seltags] & 1 << i ? SchemeTagsSel : SchemeTagsNorm]); + drw_text(drw, x, 0, w, bh, lrpad / 2, tags[i], urg & 1 << i); + if (occ & 1 << i) + drw_rect(drw, x + boxs, boxs, boxw, boxw, + m == selmon && selmon->sel && selmon->sel->tags & 1 << i, + urg & 1 << i); + x += w; + } + w = blw = TEXTW(m->ltsymbol); + drw_setscheme(drw, scheme[SchemeTagsNorm]); + x = drw_text(drw, x, 0, w, bh, lrpad / 2, m->ltsymbol, 0); + + if ((w = m->ww - wstext - x) > bh) { + if (m->sel) { + drw_setscheme(drw, scheme[m == selmon ? SchemeInfoSel : SchemeInfoNorm]); + drw_text(drw, x, 0, w -2 * sp, bh, lrpad / 2, m->sel->name, 0); + if (m->sel->isfloating) + drw_rect(drw, x + boxs, boxs, boxw, boxw, m->sel->isfixed, 0); + } else { + drw_setscheme(drw, scheme[SchemeInfoNorm]); + drw_rect(drw, x, 0, w -2 * sp, bh, 1, 1); + } + } + drw_map(drw, m->barwin, 0, 0, m->ww, bh); +} + +void +drawbars(void) +{ + Monitor *m; + + for (m = mons; m; m = m->next) + drawbar(m); +} + +void +enternotify(XEvent *e) +{ + Client *c; + Monitor *m; + XCrossingEvent *ev = &e->xcrossing; + + if ((ev->mode != NotifyNormal || ev->detail == NotifyInferior) && ev->window != root) + return; + c = wintoclient(ev->window); + m = c ? c->mon : wintomon(ev->window); + if (m != selmon) { + unfocus(selmon->sel, 1); + selmon = m; + } else if (!c || c == selmon->sel) + return; + focus(c); +} + +void +expose(XEvent *e) +{ + Monitor *m; + XExposeEvent *ev = &e->xexpose; + + if (ev->count == 0 && (m = wintomon(ev->window))) + drawbar(m); +} + +void +focus(Client *c) +{ + if (!c || !ISVISIBLE(c)) + for (c = selmon->stack; c && !ISVISIBLE(c); c = c->snext); + if (selmon->sel && selmon->sel != c) + unfocus(selmon->sel, 0); + if (c) { + if (c->mon != selmon) + selmon = c->mon; + if (c->isurgent) + seturgent(c, 0); + detachstack(c); + attachstack(c); + grabbuttons(c, 1); + XSetWindowBorder(dpy, c->win, scheme[SchemeSel][ColBorder].pixel); + setfocus(c); + } else { + XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime); + XDeleteProperty(dpy, root, netatom[NetActiveWindow]); + } + selmon->sel = c; + drawbars(); +} + +/* there are some broken focus acquiring clients needing extra handling */ +void +focusin(XEvent *e) +{ + XFocusChangeEvent *ev = &e->xfocus; + + if (selmon->sel && ev->window != selmon->sel->win) + setfocus(selmon->sel); +} + +void +focusmon(const Arg *arg) +{ + Monitor *m; + + if (!mons->next) + return; + if ((m = dirtomon(arg->i)) == selmon) + return; + unfocus(selmon->sel, 0); + selmon = m; + focus(NULL); +} + +void +focusstack(const Arg *arg) +{ + Client *c = NULL, *i; + + if (!selmon->sel) + return; + if (arg->i > 0) { + for (c = selmon->sel->next; c && !ISVISIBLE(c); c = c->next); + if (!c) + for (c = selmon->clients; c && !ISVISIBLE(c); c = c->next); + } else { + for (i = selmon->clients; i != selmon->sel; i = i->next) + if (ISVISIBLE(i)) + c = i; + if (!c) + for (; i; i = i->next) + if (ISVISIBLE(i)) + c = i; + } + if (c) { + focus(c); + restack(selmon); + } +} + +Atom +getatomprop(Client *c, Atom prop) +{ + int di; + unsigned long dl; + unsigned char *p = NULL; + Atom da, atom = None; + + if (XGetWindowProperty(dpy, c->win, prop, 0L, sizeof atom, False, XA_ATOM, + &da, &di, &dl, &dl, &p) == Success && p) { + atom = *(Atom *)p; + XFree(p); + } + return atom; +} + +int +getrootptr(int *x, int *y) +{ + int di; + unsigned int dui; + Window dummy; + + return XQueryPointer(dpy, root, &dummy, &dummy, x, y, &di, &di, &dui); +} + +long +getstate(Window w) +{ + int format; + long result = -1; + unsigned char *p = NULL; + unsigned long n, extra; + Atom real; + + if (XGetWindowProperty(dpy, w, wmatom[WMState], 0L, 2L, False, wmatom[WMState], + &real, &format, &n, &extra, (unsigned char **)&p) != Success) + return -1; + if (n != 0) + result = *p; + XFree(p); + return result; +} + +int +gettextprop(Window w, Atom atom, char *text, unsigned int size) +{ + char **list = NULL; + int n; + XTextProperty name; + + if (!text || size == 0) + return 0; + text[0] = '\0'; + if (!XGetTextProperty(dpy, w, &name, atom) || !name.nitems) + return 0; + if (name.encoding == XA_STRING) + strncpy(text, (char *)name.value, size - 1); + else { + if (XmbTextPropertyToTextList(dpy, &name, &list, &n) >= Success && n > 0 && *list) { + strncpy(text, *list, size - 1); + XFreeStringList(list); + } + } + text[size - 1] = '\0'; + XFree(name.value); + return 1; +} + +void +grabbuttons(Client *c, int focused) +{ + updatenumlockmask(); + { + unsigned int i, j; + unsigned int modifiers[] = { 0, LockMask, numlockmask, numlockmask|LockMask }; + XUngrabButton(dpy, AnyButton, AnyModifier, c->win); + if (!focused) + XGrabButton(dpy, AnyButton, AnyModifier, c->win, False, + BUTTONMASK, GrabModeSync, GrabModeSync, None, None); + for (i = 0; i < LENGTH(buttons); i++) + if (buttons[i].click == ClkClientWin) + for (j = 0; j < LENGTH(modifiers); j++) + XGrabButton(dpy, buttons[i].button, + buttons[i].mask | modifiers[j], + c->win, False, BUTTONMASK, + GrabModeAsync, GrabModeSync, None, None); + } +} + +void +grabkeys(void) +{ + updatenumlockmask(); + { + unsigned int i, j; + unsigned int modifiers[] = { 0, LockMask, numlockmask, numlockmask|LockMask }; + KeyCode code; + + XUngrabKey(dpy, AnyKey, AnyModifier, root); + for (i = 0; i < LENGTH(keys); i++) + if ((code = XKeysymToKeycode(dpy, keys[i].keysym))) + for (j = 0; j < LENGTH(modifiers); j++) + XGrabKey(dpy, code, keys[i].mod | modifiers[j], root, + True, GrabModeAsync, GrabModeAsync); + } +} + +void +incnmaster(const Arg *arg) +{ + selmon->nmaster = selmon->pertag->nmasters[selmon->pertag->curtag] = MAX(selmon->nmaster + arg->i, 0); + arrange(selmon); +} + +#ifdef XINERAMA +static int +isuniquegeom(XineramaScreenInfo *unique, size_t n, XineramaScreenInfo *info) +{ + while (n--) + if (unique[n].x_org == info->x_org && unique[n].y_org == info->y_org + && unique[n].width == info->width && unique[n].height == info->height) + return 0; + return 1; +} +#endif /* XINERAMA */ + +void +keypress(XEvent *e) +{ + unsigned int i; + KeySym keysym; + XKeyEvent *ev; + + ev = &e->xkey; + keysym = XKeycodeToKeysym(dpy, (KeyCode)ev->keycode, 0); + for (i = 0; i < LENGTH(keys); i++) + if (keysym == keys[i].keysym + && CLEANMASK(keys[i].mod) == CLEANMASK(ev->state) + && keys[i].func) + keys[i].func(&(keys[i].arg)); +} + +void +killclient(const Arg *arg) +{ + if (!selmon->sel) + return; + if (!sendevent(selmon->sel, wmatom[WMDelete])) { + XGrabServer(dpy); + XSetErrorHandler(xerrordummy); + XSetCloseDownMode(dpy, DestroyAll); + XKillClient(dpy, selmon->sel->win); + XSync(dpy, False); + XSetErrorHandler(xerror); + XUngrabServer(dpy); + } +} + +void +manage(Window w, XWindowAttributes *wa) +{ + Client *c, *t = NULL; + Window trans = None; + XWindowChanges wc; + + c = ecalloc(1, sizeof(Client)); + c->win = w; + /* geometry */ + c->x = c->oldx = wa->x; + c->y = c->oldy = wa->y; + c->w = c->oldw = wa->width; + c->h = c->oldh = wa->height; + c->oldbw = wa->border_width; + c->cfact = 1.0; + + updatetitle(c); + if (XGetTransientForHint(dpy, w, &trans) && (t = wintoclient(trans))) { + c->mon = t->mon; + c->tags = t->tags; + } else { + c->mon = selmon; + applyrules(c); + } + + if (c->x + WIDTH(c) > c->mon->mx + c->mon->mw) + c->x = c->mon->mx + c->mon->mw - WIDTH(c); + if (c->y + HEIGHT(c) > c->mon->my + c->mon->mh) + c->y = c->mon->my + c->mon->mh - HEIGHT(c); + c->x = MAX(c->x, c->mon->mx); + /* only fix client y-offset, if the client center might cover the bar */ + c->y = MAX(c->y, ((c->mon->by == c->mon->my) && (c->x + (c->w / 2) >= c->mon->wx) + && (c->x + (c->w / 2) < c->mon->wx + c->mon->ww)) ? bh : c->mon->my); + c->bw = borderpx; + + wc.border_width = c->bw; + XConfigureWindow(dpy, w, CWBorderWidth, &wc); + XSetWindowBorder(dpy, w, scheme[SchemeNorm][ColBorder].pixel); + configure(c); /* propagates border_width, if size doesn't change */ + updatewindowtype(c); + updatesizehints(c); + updatewmhints(c); + c->x = c->mon->mx + (c->mon->mw - WIDTH(c)) / 2; + c->y = c->mon->my + (c->mon->mh - HEIGHT(c)) / 2; + XSelectInput(dpy, w, EnterWindowMask|FocusChangeMask|PropertyChangeMask|StructureNotifyMask); + grabbuttons(c, 0); + if (!c->isfloating) + c->isfloating = c->oldstate = trans != None || c->isfixed; + if (c->isfloating) + XRaiseWindow(dpy, c->win); + attach(c); + attachstack(c); + XChangeProperty(dpy, root, netatom[NetClientList], XA_WINDOW, 32, PropModeAppend, + (unsigned char *) &(c->win), 1); + XChangeProperty(dpy, root, netatom[NetClientListStacking], XA_WINDOW, 32, PropModePrepend, + (unsigned char *) &(c->win), 1); + XMoveResizeWindow(dpy, c->win, c->x + 2 * sw, c->y, c->w, c->h); /* some windows require this */ + setclientstate(c, NormalState); + if (c->mon == selmon) + unfocus(selmon->sel, 0); + c->mon->sel = c; + arrange(c->mon); + XMapWindow(dpy, c->win); + focus(NULL); +} + +void +mappingnotify(XEvent *e) +{ + XMappingEvent *ev = &e->xmapping; + + XRefreshKeyboardMapping(ev); + if (ev->request == MappingKeyboard) + grabkeys(); +} + +void +maprequest(XEvent *e) +{ + static XWindowAttributes wa; + XMapRequestEvent *ev = &e->xmaprequest; + + if (!XGetWindowAttributes(dpy, ev->window, &wa)) + return; + if (wa.override_redirect) + return; + if (!wintoclient(ev->window)) + manage(ev->window, &wa); +} + +void +monocle(Monitor *m) +{ + unsigned int n = 0; + Client *c; + + for (c = m->clients; c; c = c->next) + if (ISVISIBLE(c)) + n++; + if (n > 0) /* override layout symbol */ + snprintf(m->ltsymbol, sizeof m->ltsymbol, "[%d]", n); + for (c = nexttiled(m->clients); c; c = nexttiled(c->next)) + resize(c, m->wx, m->wy, m->ww - 2 * c->bw, m->wh - 2 * c->bw, 0); +} + +void +motionnotify(XEvent *e) +{ + static Monitor *mon = NULL; + Monitor *m; + XMotionEvent *ev = &e->xmotion; + + if (ev->window != root) { + if (ev->window == selmon->barwin) + updatebarcursor(ev->x); + return; + } + if ((m = recttomon(ev->x_root, ev->y_root, 1, 1)) != mon && mon) { + unfocus(selmon->sel, 1); + selmon = m; + focus(NULL); + } + mon = m; +} + +void +movemouse(const Arg *arg) +{ + int x, y, ocx, ocy, nx, ny; + Client *c; + Monitor *m; + XEvent ev; + Time lasttime = 0; + + if (!(c = selmon->sel)) + return; + if (c->isfullscreen) /* no support moving fullscreen windows by mouse */ + return; + restack(selmon); + ocx = c->x; + ocy = c->y; + if (XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, GrabModeAsync, + None, cursor[CurMove]->cursor, CurrentTime) != GrabSuccess) + return; + if (!getrootptr(&x, &y)) + return; + do { + XMaskEvent(dpy, MOUSEMASK|ExposureMask|SubstructureRedirectMask, &ev); + switch(ev.type) { + case ConfigureRequest: + case Expose: + case MapRequest: + handler[ev.type](&ev); + break; + case MotionNotify: + if ((ev.xmotion.time - lasttime) <= (1000 / 60)) + continue; + lasttime = ev.xmotion.time; + + nx = ocx + (ev.xmotion.x - x); + ny = ocy + (ev.xmotion.y - y); + if (abs(selmon->wx - nx) < snap) + nx = selmon->wx; + else if (abs((selmon->wx + selmon->ww) - (nx + WIDTH(c))) < snap) + nx = selmon->wx + selmon->ww - WIDTH(c); + if (abs(selmon->wy - ny) < snap) + ny = selmon->wy; + else if (abs((selmon->wy + selmon->wh) - (ny + HEIGHT(c))) < snap) + ny = selmon->wy + selmon->wh - HEIGHT(c); + if (!c->isfloating && selmon->lt[selmon->sellt]->arrange + && (abs(nx - c->x) > snap || abs(ny - c->y) > snap)) + togglefloating(NULL); + if (!selmon->lt[selmon->sellt]->arrange || c->isfloating) + resize(c, nx, ny, c->w, c->h, 1); + break; + } + } while (ev.type != ButtonRelease); + XUngrabPointer(dpy, CurrentTime); + if ((m = recttomon(c->x, c->y, c->w, c->h)) != selmon) { + sendmon(c, m); + selmon = m; + focus(NULL); + } +} + +Client * +nexttiled(Client *c) +{ + for (; c && (c->isfloating || !ISVISIBLE(c)); c = c->next); + return c; +} + +void +pop(Client *c) +{ + detach(c); + attach(c); + focus(c); + arrange(c->mon); +} + +void +propertynotify(XEvent *e) +{ + Client *c; + Window trans; + XPropertyEvent *ev = &e->xproperty; + + if ((ev->window == root) && (ev->atom == XA_WM_NAME)) + updatestatus(); + else if (ev->state == PropertyDelete) + return; /* ignore */ + else if ((c = wintoclient(ev->window))) { + switch(ev->atom) { + default: break; + case XA_WM_TRANSIENT_FOR: + if (!c->isfloating && (XGetTransientForHint(dpy, c->win, &trans)) && + (c->isfloating = (wintoclient(trans)) != NULL)) + arrange(c->mon); + break; + case XA_WM_NORMAL_HINTS: + updatesizehints(c); + break; + case XA_WM_HINTS: + updatewmhints(c); + drawbars(); + break; + } + if (ev->atom == XA_WM_NAME || ev->atom == netatom[NetWMName]) { + updatetitle(c); + if (c == c->mon->sel) + drawbar(c->mon); + } + if (ev->atom == netatom[NetWMWindowType]) + updatewindowtype(c); + } +} + +void +quit(const Arg *arg) +{ + running = 0; +} + +Monitor * +recttomon(int x, int y, int w, int h) +{ + Monitor *m, *r = selmon; + int a, area = 0; + + for (m = mons; m; m = m->next) + if ((a = INTERSECT(x, y, w, h, m)) > area) { + area = a; + r = m; + } + return r; +} + +void +resize(Client *c, int x, int y, int w, int h, int interact) +{ + if (applysizehints(c, &x, &y, &w, &h, interact)) + resizeclient(c, x, y, w, h); +} + +void +resizeclient(Client *c, int x, int y, int w, int h) +{ + XWindowChanges wc; + unsigned int n; + unsigned int gapoffset; + unsigned int gapincr; + Client *nbc; + + wc.border_width = c->bw; + + /* Get number of clients for the selected monitor */ + for (n = 0, nbc = nexttiled(selmon->clients); nbc; nbc = nexttiled(nbc->next), n++); + + /* Do nothing if layout is floating */ + if (c->isfloating || selmon->lt[selmon->sellt]->arrange == NULL) { + gapincr = gapoffset = 0; + } else { + /* Remove border and gap if layout is monocle or only one client */ + if (selmon->lt[selmon->sellt]->arrange == monocle) { + gapoffset = gappx; + gapincr = 2 * gappx; + // wc.border_width = 0; + } else { + gapoffset = gappx; + gapincr = 2 * gappx; + } + } + + c->oldx = c->x; c->x = wc.x = x + gapoffset; + c->oldy = c->y; c->y = wc.y = y + gapoffset; + c->oldw = c->w; c->w = wc.width = w - gapincr; + c->oldh = c->h; c->h = wc.height = h - gapincr; + + XConfigureWindow(dpy, c->win, CWX|CWY|CWWidth|CWHeight|CWBorderWidth, &wc); + configure(c); + XSync(dpy, False); +} + +void +resizemouse(const Arg *arg) +{ + int ocx, ocy, nw, nh; + Client *c; + Monitor *m; + XEvent ev; + Time lasttime = 0; + + if (!(c = selmon->sel)) + return; + if (c->isfullscreen) /* no support resizing fullscreen windows by mouse */ + return; + restack(selmon); + ocx = c->x; + ocy = c->y; + if (XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, GrabModeAsync, + None, cursor[CurResize]->cursor, CurrentTime) != GrabSuccess) + return; + XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, c->w + c->bw - 1, c->h + c->bw - 1); + do { + XMaskEvent(dpy, MOUSEMASK|ExposureMask|SubstructureRedirectMask, &ev); + switch(ev.type) { + case ConfigureRequest: + case Expose: + case MapRequest: + handler[ev.type](&ev); + break; + case MotionNotify: + if ((ev.xmotion.time - lasttime) <= (1000 / 60)) + continue; + lasttime = ev.xmotion.time; + + nw = MAX(ev.xmotion.x - ocx - 2 * c->bw + 1, 1); + nh = MAX(ev.xmotion.y - ocy - 2 * c->bw + 1, 1); + if (c->mon->wx + nw >= selmon->wx && c->mon->wx + nw <= selmon->wx + selmon->ww + && c->mon->wy + nh >= selmon->wy && c->mon->wy + nh <= selmon->wy + selmon->wh) + { + if (!c->isfloating && selmon->lt[selmon->sellt]->arrange + && (abs(nw - c->w) > snap || abs(nh - c->h) > snap)) + togglefloating(NULL); + } + if (!selmon->lt[selmon->sellt]->arrange || c->isfloating) + resize(c, c->x, c->y, nw, nh, 1); + break; + } + } while (ev.type != ButtonRelease); + XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, c->w + c->bw - 1, c->h + c->bw - 1); + XUngrabPointer(dpy, CurrentTime); + while (XCheckMaskEvent(dpy, EnterWindowMask, &ev)); + if ((m = recttomon(c->x, c->y, c->w, c->h)) != selmon) { + sendmon(c, m); + selmon = m; + focus(NULL); + } +} + +void +restack(Monitor *m) +{ + Client *c; + XEvent ev; + XWindowChanges wc; + + drawbar(m); + if (!m->sel) + return; + if (m->sel->isfloating || !m->lt[m->sellt]->arrange) + XRaiseWindow(dpy, m->sel->win); + if (m->lt[m->sellt]->arrange) { + wc.stack_mode = Below; + wc.sibling = m->barwin; + for (c = m->stack; c; c = c->snext) + if (!c->isfloating && ISVISIBLE(c)) { + XConfigureWindow(dpy, c->win, CWSibling|CWStackMode, &wc); + wc.sibling = c->win; + } + } + XSync(dpy, False); + while (XCheckMaskEvent(dpy, EnterWindowMask, &ev)); +} + +void +run(void) +{ + XEvent ev; + /* main event loop */ + XSync(dpy, False); + while (running && !XNextEvent(dpy, &ev)) + if (handler[ev.type]) + handler[ev.type](&ev); /* call handler */ +} + +void +scan(void) +{ + unsigned int i, num; + Window d1, d2, *wins = NULL; + XWindowAttributes wa; + + if (XQueryTree(dpy, root, &d1, &d2, &wins, &num)) { + for (i = 0; i < num; i++) { + if (!XGetWindowAttributes(dpy, wins[i], &wa) + || wa.override_redirect || XGetTransientForHint(dpy, wins[i], &d1)) + continue; + if (wa.map_state == IsViewable || getstate(wins[i]) == IconicState) + manage(wins[i], &wa); + } + for (i = 0; i < num; i++) { /* now the transients */ + if (!XGetWindowAttributes(dpy, wins[i], &wa)) + continue; + if (XGetTransientForHint(dpy, wins[i], &d1) + && (wa.map_state == IsViewable || getstate(wins[i]) == IconicState)) + manage(wins[i], &wa); + } + if (wins) + XFree(wins); + } +} + +void +sendmon(Client *c, Monitor *m) +{ + if (c->mon == m) + return; + unfocus(c, 1); + detach(c); + detachstack(c); + c->mon = m; + c->tags = m->tagset[m->seltags]; /* assign tags of target monitor */ + attach(c); + attachstack(c); + focus(NULL); + arrange(NULL); +} + +void +setclientstate(Client *c, long state) +{ + long data[] = { state, None }; + + XChangeProperty(dpy, c->win, wmatom[WMState], wmatom[WMState], 32, + PropModeReplace, (unsigned char *)data, 2); +} +void +setcurrentdesktop(void){ + long data[] = { 0 }; + XChangeProperty(dpy, root, netatom[NetCurrentDesktop], XA_CARDINAL, 32, PropModeReplace, (unsigned char *)data, 1); +} +void setdesktopnames(void){ + XTextProperty text; + Xutf8TextListToTextProperty(dpy, tags, TAGSLENGTH, XUTF8StringStyle, &text); + XSetTextProperty(dpy, root, &text, netatom[NetDesktopNames]); +} + +int +sendevent(Client *c, Atom proto) +{ + int n; + Atom *protocols; + int exists = 0; + XEvent ev; + + if (XGetWMProtocols(dpy, c->win, &protocols, &n)) { + while (!exists && n--) + exists = protocols[n] == proto; + XFree(protocols); + } + if (exists) { + ev.type = ClientMessage; + ev.xclient.window = c->win; + ev.xclient.message_type = wmatom[WMProtocols]; + ev.xclient.format = 32; + ev.xclient.data.l[0] = proto; + ev.xclient.data.l[1] = CurrentTime; + XSendEvent(dpy, c->win, False, NoEventMask, &ev); + } + return exists; +} + +void +setnumdesktops(void){ + long data[] = { TAGSLENGTH }; + XChangeProperty(dpy, root, netatom[NetNumberOfDesktops], XA_CARDINAL, 32, PropModeReplace, (unsigned char *)data, 1); +} + +void +setfocus(Client *c) +{ + if (!c->neverfocus) { + XSetInputFocus(dpy, c->win, RevertToPointerRoot, CurrentTime); + XChangeProperty(dpy, root, netatom[NetActiveWindow], + XA_WINDOW, 32, PropModeReplace, + (unsigned char *) &(c->win), 1); + } + sendevent(c, wmatom[WMTakeFocus]); +} + +void +setfullscreen(Client *c, int fullscreen) +{ + if (fullscreen && !c->isfullscreen) { + XChangeProperty(dpy, c->win, netatom[NetWMState], XA_ATOM, 32, + PropModeReplace, (unsigned char*)&netatom[NetWMFullscreen], 1); + c->isfullscreen = 1; + c->oldstate = c->isfloating; + c->oldbw = c->bw; + c->bw = 0; + c->isfloating = 1; + resizeclient(c, c->mon->mx, c->mon->my, c->mon->mw, c->mon->mh); + XRaiseWindow(dpy, c->win); + } else if (!fullscreen && c->isfullscreen){ + XChangeProperty(dpy, c->win, netatom[NetWMState], XA_ATOM, 32, + PropModeReplace, (unsigned char*)0, 0); + c->isfullscreen = 0; + c->isfloating = c->oldstate; + c->bw = c->oldbw; + c->x = c->oldx; + c->y = c->oldy; + c->w = c->oldw; + c->h = c->oldh; + resizeclient(c, c->x, c->y, c->w, c->h); + arrange(c->mon); + } +} + +void +setlayout(const Arg *arg) +{ + if (!arg || !arg->v || arg->v != selmon->lt[selmon->sellt]) + selmon->sellt = selmon->pertag->sellts[selmon->pertag->curtag] ^= 1; + if (arg && arg->v) + selmon->lt[selmon->sellt] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt] = (Layout *)arg->v; + strncpy(selmon->ltsymbol, selmon->lt[selmon->sellt]->symbol, sizeof selmon->ltsymbol); + if (selmon->sel) + arrange(selmon); + else + drawbar(selmon); +} + +void setcfact(const Arg *arg) { + float f; + Client *c; + + c = selmon->sel; + + if(!arg || !c || !selmon->lt[selmon->sellt]->arrange) + return; + f = arg->f + c->cfact; + if(arg->f == 0.0) + f = 1.0; + else if(f < 0.25 || f > 4.0) + return; + c->cfact = f; + arrange(selmon); +} + +/* arg > 1.0 will set mfact absolutely */ +void +setmfact(const Arg *arg) +{ + float f; + + if (!arg || !selmon->lt[selmon->sellt]->arrange) + return; + f = arg->f < 1.0 ? arg->f + selmon->mfact : arg->f - 1.0; + if (f < 0.05 || f > 0.95) + return; + selmon->mfact = selmon->pertag->mfacts[selmon->pertag->curtag] = f; + arrange(selmon); +} + +void +setup(void) +{ + int i; + XSetWindowAttributes wa; + Atom utf8string; + + /* clean up any zombies immediately */ + sigchld(0); + + /* init screen */ + screen = DefaultScreen(dpy); + sw = DisplayWidth(dpy, screen); + sh = DisplayHeight(dpy, screen); + root = RootWindow(dpy, screen); + drw = drw_create(dpy, screen, root, sw, sh); + if (!drw_fontset_create(drw, fonts, LENGTH(fonts))) + die("no fonts could be loaded."); + lrpad = tag_padding ? tag_padding : drw->fonts->h; + bh = user_bh ? user_bh : drw->fonts->h + 2; + updategeom(); + sp = sidepad; + vp = (topbar == 1) ? vertpad : - vertpad; + + /* init atoms */ + utf8string = XInternAtom(dpy, "UTF8_STRING", False); + wmatom[WMProtocols] = XInternAtom(dpy, "WM_PROTOCOLS", False); + wmatom[WMDelete] = XInternAtom(dpy, "WM_DELETE_WINDOW", False); + wmatom[WMState] = XInternAtom(dpy, "WM_STATE", False); + wmatom[WMTakeFocus] = XInternAtom(dpy, "WM_TAKE_FOCUS", False); + netatom[NetActiveWindow] = XInternAtom(dpy, "_NET_ACTIVE_WINDOW", False); + netatom[NetSupported] = XInternAtom(dpy, "_NET_SUPPORTED", False); + netatom[NetWMName] = XInternAtom(dpy, "_NET_WM_NAME", False); + netatom[NetWMState] = XInternAtom(dpy, "_NET_WM_STATE", False); + netatom[NetWMCheck] = XInternAtom(dpy, "_NET_SUPPORTING_WM_CHECK", False); + netatom[NetWMFullscreen] = XInternAtom(dpy, "_NET_WM_STATE_FULLSCREEN", False); + netatom[NetWMWindowType] = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE", False); + netatom[NetWMWindowTypeDialog] = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_DIALOG", False); + netatom[NetClientList] = XInternAtom(dpy, "_NET_CLIENT_LIST", False); + netatom[NetClientListStacking] = XInternAtom(dpy, "_NET_CLIENT_LIST_STACKING", False); + + netatom[NetDesktopViewport] = XInternAtom(dpy, "_NET_DESKTOP_VIEWPORT", False); + netatom[NetNumberOfDesktops] = XInternAtom(dpy, "_NET_NUMBER_OF_DESKTOPS", False); + netatom[NetCurrentDesktop] = XInternAtom(dpy, "_NET_CURRENT_DESKTOP", False); + netatom[NetDesktopNames] = XInternAtom(dpy, "_NET_DESKTOP_NAMES", False); + /* init cursors */ + cursor[CurNormal] = drw_cur_create(drw, XC_left_ptr); + cursor[CurHand] = drw_cur_create(drw, XC_hand2); + cursor[CurResize] = drw_cur_create(drw, XC_sizing); + cursor[CurMove] = drw_cur_create(drw, XC_fleur); + /* init appearance */ + scheme = ecalloc(LENGTH(colors), sizeof(Clr *)); + for (i = 0; i < LENGTH(colors); i++) + scheme[i] = drw_scm_create(drw, colors[i], 3); + /* init bars */ + updatebars(); + updatestatus(); + updatebarpos(selmon); + /* supporting window for NetWMCheck */ + wmcheckwin = XCreateSimpleWindow(dpy, root, 0, 0, 1, 1, 0, 0, 0); + XChangeProperty(dpy, wmcheckwin, netatom[NetWMCheck], XA_WINDOW, 32, + PropModeReplace, (unsigned char *) &wmcheckwin, 1); + XChangeProperty(dpy, wmcheckwin, netatom[NetWMName], utf8string, 8, + PropModeReplace, (unsigned char *) "dwm", 3); + XChangeProperty(dpy, root, netatom[NetWMCheck], XA_WINDOW, 32, + PropModeReplace, (unsigned char *) &wmcheckwin, 1); + /* EWMH support per view */ + XChangeProperty(dpy, root, netatom[NetSupported], XA_ATOM, 32, + PropModeReplace, (unsigned char *) netatom, NetLast); + setnumdesktops(); + setcurrentdesktop(); + setdesktopnames(); + setviewport(); + XDeleteProperty(dpy, root, netatom[NetClientList]); + XDeleteProperty(dpy, root, netatom[NetClientListStacking]); + /* select events */ + wa.cursor = cursor[CurNormal]->cursor; + wa.event_mask = SubstructureRedirectMask|SubstructureNotifyMask + |ButtonPressMask|PointerMotionMask|EnterWindowMask + |LeaveWindowMask|StructureNotifyMask|PropertyChangeMask; + XChangeWindowAttributes(dpy, root, CWEventMask|CWCursor, &wa); + XSelectInput(dpy, root, wa.event_mask); + grabkeys(); + focus(NULL); +} +void +setviewport(void){ + long data[] = { 0, 0 }; + XChangeProperty(dpy, root, netatom[NetDesktopViewport], XA_CARDINAL, 32, PropModeReplace, (unsigned char *)data, 2); +} + + +void +seturgent(Client *c, int urg) +{ + XWMHints *wmh; + + c->isurgent = urg; + if (!(wmh = XGetWMHints(dpy, c->win))) + return; + wmh->flags = urg ? (wmh->flags | XUrgencyHint) : (wmh->flags & ~XUrgencyHint); + XSetWMHints(dpy, c->win, wmh); + XFree(wmh); +} + +void +showhide(Client *c) +{ + if (!c) + return; + if (ISVISIBLE(c)) { + /* show clients top down */ + XMoveWindow(dpy, c->win, c->x, c->y); + if ((!c->mon->lt[c->mon->sellt]->arrange || c->isfloating) && !c->isfullscreen) + resize(c, c->x, c->y, c->w, c->h, 0); + showhide(c->snext); + } else { + /* hide clients bottom up */ + showhide(c->snext); + XMoveWindow(dpy, c->win, WIDTH(c) * -2, c->y); + } +} + +void +sigchld(int unused) +{ + if (signal(SIGCHLD, sigchld) == SIG_ERR) + die("can't install SIGCHLD handler:"); + while (0 < waitpid(-1, NULL, WNOHANG)); +} + +void +sigdwmblocks(const Arg *arg) +{ + int fd; + struct flock fl; + union sigval sv; + + if (dwmblockssig <= 0 || dwmblockssig >= 10) + return; + sv.sival_int = (dwmblockssig << 8) | arg->i; + fd = open(DWMBLOCKSLOCKFILE, O_RDONLY); + if (fd == -1) + return; + fl.l_type = F_WRLCK; + fl.l_start = 0; + fl.l_whence = SEEK_SET; + fl.l_len = 0; + if (fcntl(fd, F_GETLK, &fl) == -1 || fl.l_type == F_UNLCK) + return; + sigqueue(fl.l_pid, SIGRTMIN, sv); +} + +void +spawn(const Arg *arg) +{ + if (fork() == 0) { + if (dpy) + close(ConnectionNumber(dpy)); + setsid(); + execvp(((char **)arg->v)[0], (char **)arg->v); + fprintf(stderr, "dwm: execvp %s", ((char **)arg->v)[0]); + perror(" failed"); + exit(EXIT_SUCCESS); + } +} + +void +switchcol(const Arg *arg) +{ + Client *c, *t; + int col = 0; + int i; + + if (!selmon->sel) + return; + for (i = 0, c = nexttiled(selmon->clients); c ; + c = nexttiled(c->next), i++) { + if (c == selmon->sel) + col = (i + 1) > selmon->nmaster; + } + if (i <= selmon->nmaster) + return; + for (c = selmon->stack; c; c = c->snext) { + if (!ISVISIBLE(c)) + continue; + for (i = 0, t = nexttiled(selmon->clients); t && t != c; + t = nexttiled(t->next), i++); + if (t && (i + 1 > selmon->nmaster) != col) { + focus(c); + restack(selmon); + break; + } + } +} + +void +tag(const Arg *arg) +{ + if (selmon->sel && arg->ui & TAGMASK) { + selmon->sel->tags = arg->ui & TAGMASK; + focus(NULL); + arrange(selmon); + } + updatecurrentdesktop(); +} + +void +tagmon(const Arg *arg) +{ + if (!selmon->sel || !mons->next) + return; + sendmon(selmon->sel, dirtomon(arg->i)); +} + +void +tile(Monitor *m) +{ + unsigned int i, n, h, mw, my, ty; + float mfacts = 0, sfacts = 0; + Client *c; + + for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++) { + if (n < m->nmaster) + mfacts += c->cfact; + else + sfacts += c->cfact; + } + if (n == 0) + return; + + if (n > m->nmaster) + mw = m->nmaster + ? m->ww * (m->rmaster ? 1.0 - m->mfact : m->mfact) + : 0; + else + mw = m->ww; + for (i = my = ty = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++) + if (i < m->nmaster) { + h = (m->wh - my) * (c->cfact / mfacts); + resize(c, m->rmaster ? m->wx + m->ww - mw : m->wx, + m->wy + my, mw - (2*c->bw), h - (2*c->bw), 0); + if (my + HEIGHT(c) < m->wh) + my += HEIGHT(c); + mfacts -= c->cfact; + } else { + h = (m->wh - ty) * (c->cfact / sfacts); + resize(c, m->rmaster ? m->wx : m->wx + mw, m->wy + ty, + m->ww - mw - (2*c->bw), h - (2*c->bw), 0); + if (ty + HEIGHT(c) < m->wh) + ty += HEIGHT(c); + sfacts -= c->cfact; + } +} + +void +togglebar(const Arg *arg) +{ + selmon->showbar = selmon->pertag->showbars[selmon->pertag->curtag] = !selmon->showbar; + updatebarpos(selmon); + XMoveResizeWindow(dpy, selmon->barwin, selmon->wx + sp, selmon->by + vp, selmon->ww - 2 * sp, bh); + arrange(selmon); +} + +void +togglefloating(const Arg *arg) +{ + if (!selmon->sel) + return; + if (selmon->sel->isfullscreen) /* no support for fullscreen windows */ + return; + selmon->sel->isfloating = !selmon->sel->isfloating || selmon->sel->isfixed; + if (selmon->sel->isfloating) + resize(selmon->sel, selmon->sel->x, selmon->sel->y, + selmon->sel->w, selmon->sel->h, 0); + arrange(selmon); +} + +void +togglefullscr(const Arg *arg) +{ + if(selmon->sel) + setfullscreen(selmon->sel, !selmon->sel->isfullscreen); +} + +void +togglermaster(const Arg *arg) +{ + selmon->rmaster = !selmon->rmaster; + /* now mfact represents the left factor */ + selmon->mfact = 1.0 - selmon->mfact; + if (selmon->lt[selmon->sellt]->arrange) + arrange(selmon); +} + +void +toggletag(const Arg *arg) +{ + unsigned int newtags; + + if (!selmon->sel) + return; + newtags = selmon->sel->tags ^ (arg->ui & TAGMASK); + if (newtags) { + selmon->sel->tags = newtags; + focus(NULL); + arrange(selmon); + } + updatecurrentdesktop(); +} + +void +toggleview(const Arg *arg) +{ + unsigned int newtagset = selmon->tagset[selmon->seltags] ^ (arg->ui & TAGMASK); + int i; + + if (newtagset) { + selmon->tagset[selmon->seltags] = newtagset; + + if (newtagset == ~0) { + selmon->pertag->prevtag = selmon->pertag->curtag; + selmon->pertag->curtag = 0; + } + + /* test if the user did not select the same tag */ + if (!(newtagset & 1 << (selmon->pertag->curtag - 1))) { + selmon->pertag->prevtag = selmon->pertag->curtag; + for (i = 0; !(newtagset & 1 << i); i++) ; + selmon->pertag->curtag = i + 1; + } + + /* apply settings for this view */ + selmon->nmaster = selmon->pertag->nmasters[selmon->pertag->curtag]; + selmon->mfact = selmon->pertag->mfacts[selmon->pertag->curtag]; + selmon->sellt = selmon->pertag->sellts[selmon->pertag->curtag]; + selmon->lt[selmon->sellt] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt]; + selmon->lt[selmon->sellt^1] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt^1]; + + if (selmon->showbar != selmon->pertag->showbars[selmon->pertag->curtag]) + togglebar(NULL); + + focus(NULL); + arrange(selmon); + } +} + +void +unfocus(Client *c, int setfocus) +{ + if (!c) + return; + grabbuttons(c, 0); + XSetWindowBorder(dpy, c->win, scheme[SchemeNorm][ColBorder].pixel); + if (setfocus) { + XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime); + XDeleteProperty(dpy, root, netatom[NetActiveWindow]); + } +} + +void +unmanage(Client *c, int destroyed) +{ + Monitor *m = c->mon; + XWindowChanges wc; + + detach(c); + detachstack(c); + if (!destroyed) { + wc.border_width = c->oldbw; + XGrabServer(dpy); /* avoid race conditions */ + XSetErrorHandler(xerrordummy); + XConfigureWindow(dpy, c->win, CWBorderWidth, &wc); /* restore border */ + XUngrabButton(dpy, AnyButton, AnyModifier, c->win); + setclientstate(c, WithdrawnState); + XSync(dpy, False); + XSetErrorHandler(xerror); + XUngrabServer(dpy); + } + free(c); + focus(NULL); + updateclientlist(); + arrange(m); +} + +void +unmapnotify(XEvent *e) +{ + Client *c; + XUnmapEvent *ev = &e->xunmap; + + if ((c = wintoclient(ev->window))) { + if (ev->send_event) + setclientstate(c, WithdrawnState); + else + unmanage(c, 0); + } +} + +void +updatebars(void) +{ + Monitor *m; + XSetWindowAttributes wa = { + .override_redirect = True, + .background_pixmap = ParentRelative, + .event_mask = ButtonPressMask|ExposureMask|PointerMotionMask + }; + XClassHint ch = {"dwm", "dwm"}; + for (m = mons; m; m = m->next) { + if (m->barwin) + continue; + m->barwin = XCreateWindow(dpy, root, m->wx + sp, m->by + vp, m->ww - 2 * sp, bh, 0, DefaultDepth(dpy, screen), + CopyFromParent, DefaultVisual(dpy, screen), + CWOverrideRedirect|CWBackPixmap|CWEventMask, &wa); + XDefineCursor(dpy, m->barwin, cursor[CurNormal]->cursor); + XMapRaised(dpy, m->barwin); + XSetClassHint(dpy, m->barwin, &ch); + } +} +void updatecurrentdesktop(void){ + long rawdata[] = { selmon->tagset[selmon->seltags] }; + int i=0; + while(*rawdata >> i+1){ + i++; + } + long data[] = { i }; + XChangeProperty(dpy, root, netatom[NetCurrentDesktop], XA_CARDINAL, 32, PropModeReplace, (unsigned char *)data, 1); +} + +void +updatebarcursor(int cursorpos) +{ + static int currentcursor = 0; + int x; + + if (BETWEEN(cursorpos, (x = selmon->ww - wstext + lrpad / 2), x + wstext - lrpad)) { + updatedwmblockssig(x, cursorpos); + if (currentcursor) { + if (dwmblockssig <= 0 || dwmblockssig >= 10) { + currentcursor = 0; + XDefineCursor(dpy, selmon->barwin, cursor[CurNormal]->cursor); + } + } else { + if (dwmblockssig > 0 && dwmblockssig < 10) { + currentcursor = 1; + XDefineCursor(dpy, selmon->barwin, cursor[CurHand]->cursor); + } + } + } else { + if (currentcursor) { + currentcursor = 0; + XDefineCursor(dpy, selmon->barwin, cursor[CurNormal]->cursor); + } + } +} + +void +updatebarpos(Monitor *m) +{ + m->wy = m->my; + m->wh = m->mh; + if (m->showbar) { + m->wh = m->wh - vertpad - bh; + m->by = m->topbar ? m->wy : m->wy + m->wh + vertpad; + m->wy = m->topbar ? m->wy + bh + vp : m->wy; + } else + m->by = -bh - vp; +} + +void +updateclientlist() +{ + Client *c; + Monitor *m; + + XDeleteProperty(dpy, root, netatom[NetClientList]); + for (m = mons; m; m = m->next) + for (c = m->clients; c; c = c->next) + XChangeProperty(dpy, root, netatom[NetClientList], + XA_WINDOW, 32, PropModeAppend, + (unsigned char *) &(c->win), 1); + + XDeleteProperty(dpy, root, netatom[NetClientListStacking]); + for (m = mons; m; m = m->next) + for (c = m->stack; c; c = c->snext) + XChangeProperty(dpy, root, netatom[NetClientListStacking], + XA_WINDOW, 32, PropModeAppend, + (unsigned char *) &(c->win), 1); +} + +void +updatedwmblockssig(int x, int e) +{ + char *ts = stexts; + char *tp = stexts; + char ctmp; + + while (*ts != '\0') { + if ((unsigned char)*ts > 10) { + ts++; + continue; + } + ctmp = *ts; + *ts = '\0'; + x += TTEXTW(tp); + *ts = ctmp; + if (x >= e) { + dwmblockssig = (unsigned char)ctmp; + return; + } + tp = ++ts; + } + dwmblockssig = 0; +} + +int +updategeom(void) +{ + int dirty = 0; + +#ifdef XINERAMA + if (XineramaIsActive(dpy)) { + int i, j, n, nn; + Client *c; + Monitor *m; + XineramaScreenInfo *info = XineramaQueryScreens(dpy, &nn); + XineramaScreenInfo *unique = NULL; + + for (n = 0, m = mons; m; m = m->next, n++); + /* only consider unique geometries as separate screens */ + unique = ecalloc(nn, sizeof(XineramaScreenInfo)); + for (i = 0, j = 0; i < nn; i++) + if (isuniquegeom(unique, j, &info[i])) + memcpy(&unique[j++], &info[i], sizeof(XineramaScreenInfo)); + XFree(info); + nn = j; + if (n <= nn) { /* new monitors available */ + for (i = 0; i < (nn - n); i++) { + for (m = mons; m && m->next; m = m->next); + if (m) + m->next = createmon(); + else + mons = createmon(); + } + for (i = 0, m = mons; i < nn && m; m = m->next, i++) + if (i >= n + || unique[i].x_org != m->mx || unique[i].y_org != m->my + || unique[i].width != m->mw || unique[i].height != m->mh) + { + dirty = 1; + m->num = i; + m->mx = m->wx = unique[i].x_org; + m->my = m->wy = unique[i].y_org; + m->mw = m->ww = unique[i].width; + m->mh = m->wh = unique[i].height; + updatebarpos(m); + } + } else { /* less monitors available nn < n */ + for (i = nn; i < n; i++) { + for (m = mons; m && m->next; m = m->next); + while ((c = m->clients)) { + dirty = 1; + m->clients = c->next; + detachstack(c); + c->mon = mons; + attach(c); + attachstack(c); + } + if (m == selmon) + selmon = mons; + cleanupmon(m); + } + } + free(unique); + } else +#endif /* XINERAMA */ + { /* default monitor setup */ + if (!mons) + mons = createmon(); + if (mons->mw != sw || mons->mh != sh) { + dirty = 1; + mons->mw = mons->ww = sw; + mons->mh = mons->wh = sh; + updatebarpos(mons); + } + } + if (dirty) { + selmon = mons; + selmon = wintomon(root); + } + return dirty; +} + +void +updatenumlockmask(void) +{ + unsigned int i, j; + XModifierKeymap *modmap; + + numlockmask = 0; + modmap = XGetModifierMapping(dpy); + for (i = 0; i < 8; i++) + for (j = 0; j < modmap->max_keypermod; j++) + if (modmap->modifiermap[i * modmap->max_keypermod + j] + == XKeysymToKeycode(dpy, XK_Num_Lock)) + numlockmask = (1 << i); + XFreeModifiermap(modmap); +} + +void +updatesizehints(Client *c) +{ + long msize; + XSizeHints size; + + if (!XGetWMNormalHints(dpy, c->win, &size, &msize)) + /* size is uninitialized, ensure that size.flags aren't used */ + size.flags = PSize; + if (size.flags & PBaseSize) { + c->basew = size.base_width; + c->baseh = size.base_height; + } else if (size.flags & PMinSize) { + c->basew = size.min_width; + c->baseh = size.min_height; + } else + c->basew = c->baseh = 0; + if (size.flags & PResizeInc) { + c->incw = size.width_inc; + c->inch = size.height_inc; + } else + c->incw = c->inch = 0; + if (size.flags & PMaxSize) { + c->maxw = size.max_width; + c->maxh = size.max_height; + } else + c->maxw = c->maxh = 0; + if (size.flags & PMinSize) { + c->minw = size.min_width; + c->minh = size.min_height; + } else if (size.flags & PBaseSize) { + c->minw = size.base_width; + c->minh = size.base_height; + } else + c->minw = c->minh = 0; + if (size.flags & PAspect) { + c->mina = (float)size.min_aspect.y / size.min_aspect.x; + c->maxa = (float)size.max_aspect.x / size.max_aspect.y; + } else + c->maxa = c->mina = 0.0; + c->isfixed = (c->maxw && c->maxh && c->maxw == c->minw && c->maxh == c->minh); +} + +void +updatestatus(void) +{ + char rawstext[256]; + + if (gettextprop(root, XA_WM_NAME, rawstext, sizeof rawstext)) { + char stextt[256]; + char *stc = stextc, *sts = stexts, *stt = stextt; + + for (char *rt = rawstext; *rt != '\0'; rt++) + if ((unsigned char)*rt >= ' ') + *(stc++) = *(sts++) = *(stt++) = *rt; + else if ((unsigned char)*rt > 10) + *(stc++) = *rt; + else + *(sts++) = *rt; + *stc = *sts = *stt = '\0'; + wstext = TEXTW(stextt); + } else { + strcpy(stextc, "dwm-"VERSION); + strcpy(stexts, stextc); + wstext = TEXTW(stextc); + } + drawbar(selmon); +} + +void +updatetitle(Client *c) +{ + if (!gettextprop(c->win, netatom[NetWMName], c->name, sizeof c->name)) + gettextprop(c->win, XA_WM_NAME, c->name, sizeof c->name); + if (c->name[0] == '\0') /* hack to mark broken clients */ + strcpy(c->name, broken); +} + +void +updatewindowtype(Client *c) +{ + Atom state = getatomprop(c, netatom[NetWMState]); + Atom wtype = getatomprop(c, netatom[NetWMWindowType]); + + if (state == netatom[NetWMFullscreen]) + setfullscreen(c, 1); + if (wtype == netatom[NetWMWindowTypeDialog]) + c->isfloating = 1; +} + +void +updatewmhints(Client *c) +{ + XWMHints *wmh; + + if ((wmh = XGetWMHints(dpy, c->win))) { + if (c == selmon->sel && wmh->flags & XUrgencyHint) { + wmh->flags &= ~XUrgencyHint; + XSetWMHints(dpy, c->win, wmh); + } else + c->isurgent = (wmh->flags & XUrgencyHint) ? 1 : 0; + if (wmh->flags & InputHint) + c->neverfocus = !wmh->input; + else + c->neverfocus = 0; + XFree(wmh); + } +} + +void +view(const Arg *arg) +{ + int i; + unsigned int tmptag; + + if ((arg->ui & TAGMASK) == selmon->tagset[selmon->seltags]) + return; + selmon->seltags ^= 1; /* toggle sel tagset */ + if (arg->ui & TAGMASK) { + selmon->tagset[selmon->seltags] = arg->ui & TAGMASK; + selmon->pertag->prevtag = selmon->pertag->curtag; + + if (arg->ui == ~0) + selmon->pertag->curtag = 0; + else { + for (i = 0; !(arg->ui & 1 << i); i++) ; + selmon->pertag->curtag = i + 1; + } + } else { + tmptag = selmon->pertag->prevtag; + selmon->pertag->prevtag = selmon->pertag->curtag; + selmon->pertag->curtag = tmptag; + } + + selmon->nmaster = selmon->pertag->nmasters[selmon->pertag->curtag]; + selmon->mfact = selmon->pertag->mfacts[selmon->pertag->curtag]; + selmon->sellt = selmon->pertag->sellts[selmon->pertag->curtag]; + selmon->lt[selmon->sellt] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt]; + selmon->lt[selmon->sellt^1] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt^1]; + + if (selmon->showbar != selmon->pertag->showbars[selmon->pertag->curtag]) + togglebar(NULL); + + focus(NULL); + arrange(selmon); + updatecurrentdesktop(); +} + +Client * +wintoclient(Window w) +{ + Client *c; + Monitor *m; + + for (m = mons; m; m = m->next) + for (c = m->clients; c; c = c->next) + if (c->win == w) + return c; + return NULL; +} + +Monitor * +wintomon(Window w) +{ + int x, y; + Client *c; + Monitor *m; + + if (w == root && getrootptr(&x, &y)) + return recttomon(x, y, 1, 1); + for (m = mons; m; m = m->next) + if (w == m->barwin) + return m; + if ((c = wintoclient(w))) + return c->mon; + return selmon; +} + +/* Selects for the view of the focused window. The list of tags */ +/* to be displayed is matched to the focused window tag list. */ +void +winview(const Arg* arg){ + Window win, win_r, win_p, *win_c; + unsigned nc; + int unused; + Client* c; + Arg a; + + if (!XGetInputFocus(dpy, &win, &unused)) return; + while(XQueryTree(dpy, win, &win_r, &win_p, &win_c, &nc) + && win_p != win_r) win = win_p; + + if (!(c = wintoclient(win))) return; + + a.ui = c->tags; + view(&a); +} + +/* There's no way to check accesses to destroyed windows, thus those cases are + * ignored (especially on UnmapNotify's). Other types of errors call Xlibs + * default error handler, which may call exit. */ +int +xerror(Display *dpy, XErrorEvent *ee) +{ + if (ee->error_code == BadWindow + || (ee->request_code == X_SetInputFocus && ee->error_code == BadMatch) + || (ee->request_code == X_PolyText8 && ee->error_code == BadDrawable) + || (ee->request_code == X_PolyFillRectangle && ee->error_code == BadDrawable) + || (ee->request_code == X_PolySegment && ee->error_code == BadDrawable) + || (ee->request_code == X_ConfigureWindow && ee->error_code == BadMatch) + || (ee->request_code == X_GrabButton && ee->error_code == BadAccess) + || (ee->request_code == X_GrabKey && ee->error_code == BadAccess) + || (ee->request_code == X_CopyArea && ee->error_code == BadDrawable)) + return 0; + fprintf(stderr, "dwm: fatal error: request code=%d, error code=%d\n", + ee->request_code, ee->error_code); + return xerrorxlib(dpy, ee); /* may call exit */ +} + +int +xerrordummy(Display *dpy, XErrorEvent *ee) +{ + return 0; +} + +/* Startup Error handler to check if another window manager + * is already running. */ +int +xerrorstart(Display *dpy, XErrorEvent *ee) +{ + die("dwm: another window manager is already running"); + return -1; +} + +void +zoom(const Arg *arg) +{ + Client *c = selmon->sel; + + if (!selmon->lt[selmon->sellt]->arrange + || (selmon->sel && selmon->sel->isfloating)) + return; + if (c == nexttiled(selmon->clients)) + if (!c || !(c = nexttiled(c->next))) + return; + pop(c); +} + +int +main(int argc, char *argv[]) +{ + if (argc == 2 && !strcmp("-v", argv[1])) + die("dwm-"VERSION); + else if (argc != 1) + die("usage: dwm [-v]"); + if (!setlocale(LC_CTYPE, "") || !XSupportsLocale()) + fputs("warning: no locale support\n", stderr); + if (!(dpy = XOpenDisplay(NULL))) + die("dwm: cannot open display"); + checkotherwm(); + setup(); +#ifdef __OpenBSD__ + if (pledge("stdio rpath proc exec", NULL) == -1) + die("pledge"); +#endif /* __OpenBSD__ */ + scan(); + run(); + cleanup(); + XCloseDisplay(dpy); + return EXIT_SUCCESS; +} + +void +centeredmaster(Monitor *m) +{ + unsigned int i, n, h, mw, mx, my, oty, ety, tw; + Client *c; + + /* count number of clients in the selected monitor */ + for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++); + if (n == 0) + return; + + /* initialize areas */ + mw = m->ww; + mx = 0; + my = 0; + tw = mw; + + if (n > m->nmaster) { + /* go mfact box in the center if more than nmaster clients */ + mw = m->nmaster ? m->ww * m->mfact : 0; + tw = m->ww - mw; + + if (n - m->nmaster > 1) { + /* only one client */ + mx = (m->ww - mw) / 2; + tw = (m->ww - mw) / 2; + } + } + + oty = 0; + ety = 0; + for (i = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++) + if (i < m->nmaster) { + /* nmaster clients are stacked vertically, in the center + * of the screen */ + h = (m->wh - my) / (MIN(n, m->nmaster) - i); + resize(c, m->wx + mx, m->wy + my, mw - (2*c->bw), + h - (2*c->bw), 0); + my += HEIGHT(c); + } else { + /* stack clients are stacked vertically */ + if ((i - m->nmaster) % 2 ) { + h = (m->wh - ety) / ( (1 + n - i) / 2); + resize(c, m->wx, m->wy + ety, tw - (2*c->bw), + h - (2*c->bw), 0); + ety += HEIGHT(c); + } else { + h = (m->wh - oty) / ((1 + n - i) / 2); + resize(c, m->wx + mx + mw, m->wy + oty, + tw - (2*c->bw), h - (2*c->bw), 0); + oty += HEIGHT(c); + } + } +} + +void +centeredfloatingmaster(Monitor *m) +{ + unsigned int i, n, w, mh, mw, mx, mxo, my, myo, tx; + Client *c; + + /* count number of clients in the selected monitor */ + for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++); + if (n == 0) + return; + + /* initialize nmaster area */ + if (n > m->nmaster) { + /* go mfact box in the center if more than nmaster clients */ + if (m->ww > m->wh) { + mw = m->nmaster ? m->ww * m->mfact : 0; + mh = m->nmaster ? m->wh * 0.9 : 0; + } else { + mh = m->nmaster ? m->wh * m->mfact : 0; + mw = m->nmaster ? m->ww * 0.9 : 0; + } + mx = mxo = (m->ww - mw) / 2; + my = myo = (m->wh - mh) / 2; + } else { + /* go fullscreen if all clients are in the master area */ + mh = m->wh; + mw = m->ww; + mx = mxo = 0; + my = myo = 0; + } + + for(i = tx = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++) + if (i < m->nmaster) { + /* nmaster clients are stacked horizontally, in the center + * of the screen */ + w = (mw + mxo - mx) / (MIN(n, m->nmaster) - i); + resize(c, m->wx + mx, m->wy + my, w - (2*c->bw), + mh - (2*c->bw), 0); + mx += WIDTH(c); + } else { + /* stack clients are stacked horizontally */ + w = (m->ww - tx) / (n - i); + resize(c, m->wx + tx, m->wy, w - (2*c->bw), + m->wh - (2*c->bw), 0); + tx += WIDTH(c); + } +} + +void +insertclient(Client *item, Client *insertItem, int after) { + Client *c; + if (item == NULL || insertItem == NULL || item == insertItem) return; + detach(insertItem); + if (!after && selmon->clients == item) { + attach(insertItem); + return; + } + if (after) { + c = item; + } else { + for (c = selmon->clients; c; c = c->next) { if (c->next == item) break; } + } + insertItem->next = c->next; + c->next = insertItem; +} + +void +inplacerotate(const Arg *arg) +{ + if(!selmon->sel || (selmon->sel->isfloating && !arg->f)) return; + + unsigned int selidx = 0, i = 0; + Client *c = NULL, *stail = NULL, *mhead = NULL, *mtail = NULL, *shead = NULL; + + // Determine positionings for insertclient + for (c = selmon->clients; c; c = c->next) { + if (ISVISIBLE(c) && !(c->isfloating)) { + if (selmon->sel == c) { selidx = i; } + if (i == selmon->nmaster - 1) { mtail = c; } + if (i == selmon->nmaster) { shead = c; } + if (mhead == NULL) { mhead = c; } + stail = c; + i++; + } + } + + // All clients rotate + if (arg->i == 2) insertclient(selmon->clients, stail, 0); + if (arg->i == -2) insertclient(stail, selmon->clients, 1); + // Stack xor master rotate + if (arg->i == -1 && selidx >= selmon->nmaster) insertclient(stail, shead, 1); + if (arg->i == 1 && selidx >= selmon->nmaster) insertclient(shead, stail, 0); + if (arg->i == -1 && selidx < selmon->nmaster) insertclient(mtail, mhead, 1); + if (arg->i == 1 && selidx < selmon->nmaster) insertclient(mhead, mtail, 0); + + // Restore focus position + i = 0; + for (c = selmon->clients; c; c = c->next) { + if (!ISVISIBLE(c) || (c->isfloating)) continue; + if (i == selidx) { focus(c); break; } + i++; + } + arrange(selmon); + focus(c); +} diff --git a/suckless/dwm/dwm.png b/suckless/dwm/dwm.png new file mode 100644 index 0000000000000000000000000000000000000000..b1f9ba7e5f4cc7350ee2392ebcea5fcbe00fb49b GIT binary patch literal 373 zcmeAS@N?(olHy`uVBq!ia0vp^2Y@($g9*gC@m3f}u_bxCyDx`7I;J! zGca%iWx0hJ8D`Cq01C2~c>21sUt<^MF=V?Ztt9{yk}YwKC~?lu%}vcKVQ?-=O)N=G zQ7F$W$xsN%NL6t6^bL5QqM8R(c+=CxF{I+w+q;fj4F)_6j>`Z3pZ>_($QEQ&92OXP z%lpEKGwG8$G-U1H{@Y%;mx-mNK|p|siBVAj$Z~Mt-~h6K0!}~{PyozQ07(f5fTdVi zm=-zT`NweeJ#%S&{fequZGmkDDC*%x$$Sa*fAP=$`nJkhx1Y~k<8b2;Hq)FOdV=P$ q&oWzoxz_&nv&n0)xBzV8k*jsxheTIy&cCY600f?{elF{r5}E*x)opSB literal 0 HcmV?d00001 diff --git a/suckless/dwm/dwm_config_pulseaudio.h b/suckless/dwm/dwm_config_pulseaudio.h new file mode 100644 index 00000000..8e1d6f90 --- /dev/null +++ b/suckless/dwm/dwm_config_pulseaudio.h @@ -0,0 +1,28 @@ +/** + * dwmconfig.h + * Hardware multimedia keys + */ +/* Somewhere at the beginning of config.h include: + +#include + +/* Add somewhere in your constants definition section */ + +static const char *upvol[] = { "/usr/bin/pactl", "set-sink-volume", "0", "+5%", NULL }; +static const char *downvol[] = { "/usr/bin/pactl", "set-sink-volume", "0", "-5%", NULL }; +static const char *mutevol[] = { "/usr/bin/pactl", "set-sink-mute", "0", "toggle", NULL }; + +/* Add to keys[] array. With 0 as modifier, you are able to use the keys directly. */ +static Key keys[] = { + { 0, XF86XK_AudioLowerVolume, spawn, {.v = downvol } }, + { 0, XF86XK_AudioMute, spawn, {.v = mutevol } }, + { 0, XF86XK_AudioRaiseVolume, spawn, {.v = upvol } }, +}; + +/* If you have a small laptop keyboard or don't want to spring your fingers too far away. */ + +static Key keys[] = { + { MODKEY, XK_F11, spawn, {.v = downvol } }, + { MODKEY, XK_F9, spawn, {.v = mutevol } }, + { MODKEY, XK_F12, spawn, {.v = upvol } }, +}; diff --git a/suckless/dwm/fibonacci.c b/suckless/dwm/fibonacci.c new file mode 100644 index 00000000..fce0a577 --- /dev/null +++ b/suckless/dwm/fibonacci.c @@ -0,0 +1,66 @@ +void +fibonacci(Monitor *mon, int s) { + unsigned int i, n, nx, ny, nw, nh; + Client *c; + + for(n = 0, c = nexttiled(mon->clients); c; c = nexttiled(c->next), n++); + if(n == 0) + return; + + nx = mon->wx; + ny = 0; + nw = mon->ww; + nh = mon->wh; + + for(i = 0, c = nexttiled(mon->clients); c; c = nexttiled(c->next)) { + if((i % 2 && nh / 2 > 2 * c->bw) + || (!(i % 2) && nw / 2 > 2 * c->bw)) { + if(i < n - 1) { + if(i % 2) + nh /= 2; + else + nw /= 2; + if((i % 4) == 2 && !s) + nx += nw; + else if((i % 4) == 3 && !s) + ny += nh; + } + if((i % 4) == 0) { + if(s) + ny += nh; + else + ny -= nh; + } + else if((i % 4) == 1) + nx += nw; + else if((i % 4) == 2) + ny += nh; + else if((i % 4) == 3) { + if(s) + nx += nw; + else + nx -= nw; + } + if(i == 0) + { + if(n != 1) + nw = mon->ww * mon->mfact; + ny = mon->wy; + } + else if(i == 1) + nw = mon->ww - nw; + i++; + } + resize(c, nx, ny, nw - 2 * c->bw, nh - 2 * c->bw, False); + } +} + +void +dwindle(Monitor *mon) { + fibonacci(mon, 1); +} + +void +spiral(Monitor *mon) { + fibonacci(mon, 0); +} diff --git a/suckless/dwm/layouts.c b/suckless/dwm/layouts.c new file mode 100644 index 00000000..d26acf34 --- /dev/null +++ b/suckless/dwm/layouts.c @@ -0,0 +1,27 @@ +void +grid(Monitor *m) { + unsigned int i, n, cx, cy, cw, ch, aw, ah, cols, rows; + Client *c; + + for(n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next)) + n++; + + /* grid dimensions */ + for(rows = 0; rows <= n/2; rows++) + if(rows*rows >= n) + break; + cols = (rows && (rows - 1) * rows >= n) ? rows - 1 : rows; + + /* window geoms (cell height/width) */ + ch = m->wh / (rows ? rows : 1); + cw = m->ww / (cols ? cols : 1); + for(i = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next)) { + cx = m->wx + (i / rows) * cw; + cy = m->wy + (i % rows) * ch; + /* adjust height/width of last row/column's windows */ + ah = ((i + 1) % rows == 0) ? m->wh - ch * rows : 0; + aw = (i >= rows * (cols - 1)) ? m->ww - cw * cols : 0; + resize(c, cx, cy, cw - 2 * c->bw + aw, ch - 2 * c->bw + ah, False); + i++; + } +} diff --git a/suckless/dwm/movestack.c b/suckless/dwm/movestack.c new file mode 100644 index 00000000..c0404624 --- /dev/null +++ b/suckless/dwm/movestack.c @@ -0,0 +1,49 @@ +void +movestack(const Arg *arg) { + Client *c = NULL, *p = NULL, *pc = NULL, *i; + + if(arg->i > 0) { + /* find the client after selmon->sel */ + for(c = selmon->sel->next; c && (!ISVISIBLE(c) || c->isfloating); c = c->next); + if(!c) + for(c = selmon->clients; c && (!ISVISIBLE(c) || c->isfloating); c = c->next); + + } + else { + /* find the client before selmon->sel */ + for(i = selmon->clients; i != selmon->sel; i = i->next) + if(ISVISIBLE(i) && !i->isfloating) + c = i; + if(!c) + for(; i; i = i->next) + if(ISVISIBLE(i) && !i->isfloating) + c = i; + } + /* find the client before selmon->sel and c */ + for(i = selmon->clients; i && (!p || !pc); i = i->next) { + if(i->next == selmon->sel) + p = i; + if(i->next == c) + pc = i; + } + + /* swap c and selmon->sel selmon->clients in the selmon->clients list */ + if(c && c != selmon->sel) { + Client *temp = selmon->sel->next==c?selmon->sel:selmon->sel->next; + selmon->sel->next = c->next==selmon->sel?c:c->next; + c->next = temp; + + if(p && p != c) + p->next = c; + if(pc && pc != selmon->sel) + pc->next = selmon->sel; + + if(selmon->sel == selmon->clients) + selmon->clients = c; + else if(c == selmon->clients) + selmon->clients = selmon->sel; + + arrange(selmon); + } +} + diff --git a/suckless/dwm/patches/dwm-6.0-winview.diff b/suckless/dwm/patches/dwm-6.0-winview.diff new file mode 100644 index 00000000..1b796b53 --- /dev/null +++ b/suckless/dwm/patches/dwm-6.0-winview.diff @@ -0,0 +1,65 @@ +diff --git a/config.def.h b/config.def.h +index 77ff358..3ba0efe 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -84,6 +84,7 @@ static Key keys[] = { + TAGKEYS( XK_8, 7) + TAGKEYS( XK_9, 8) + { MODKEY|ShiftMask, XK_q, quit, {0} }, ++ { MODKEY, XK_o, winview, {0} }, + }; + + /* button definitions */ +diff --git a/dwm.1 b/dwm.1 +index 5268a06..1188c82 100644 +--- a/dwm.1 ++++ b/dwm.1 +@@ -104,6 +104,9 @@ Increase master area size. + .B Mod1\-h + Decrease master area size. + .TP ++.B Mod1\-o ++Select view of the window in focus. The list of tags to be displayed is matched to the window tag list. ++.TP + .B Mod1\-Return + Zooms/cycles focused window to/from master area (tiled layouts only). + .TP +diff --git a/dwm.c b/dwm.c +index 1d78655..abf944c 100644 +--- a/dwm.c ++++ b/dwm.c +@@ -247,6 +247,7 @@ static void updatewmhints(Client *c); + static void view(const Arg *arg); + static Client *wintoclient(Window w); + static Monitor *wintomon(Window w); ++static void winview(const Arg* arg); + static int xerror(Display *dpy, XErrorEvent *ee); + static int xerrordummy(Display *dpy, XErrorEvent *ee); + static int xerrorstart(Display *dpy, XErrorEvent *ee); +@@ -2080,6 +2081,26 @@ wintomon(Window w) { + return selmon; + } + ++/* Selects for the view of the focused window. The list of tags */ ++/* to be displayed is matched to the focused window tag list. */ ++void ++winview(const Arg* arg){ ++ Window win, win_r, win_p, *win_c; ++ unsigned nc; ++ int unused; ++ Client* c; ++ Arg a; ++ ++ if (!XGetInputFocus(dpy, &win, &unused)) return; ++ while(XQueryTree(dpy, win, &win_r, &win_p, &win_c, &nc) ++ && win_p != win_r) win = win_p; ++ ++ if (!(c = wintoclient(win))) return; ++ ++ a.ui = c->tags; ++ view(&a); ++} ++ + /* There's no way to check accesses to destroyed windows, thus those cases are + * ignored (especially on UnmapNotify's). Other types of errors call Xlibs + * default error handler, which may call exit. */ diff --git a/suckless/dwm/patches/dwm-actualfullscreen-20191112-cb3f58a.diff b/suckless/dwm/patches/dwm-actualfullscreen-20191112-cb3f58a.diff new file mode 100644 index 00000000..21eea19e --- /dev/null +++ b/suckless/dwm/patches/dwm-actualfullscreen-20191112-cb3f58a.diff @@ -0,0 +1,53 @@ +From 3a16816a6f5d38014c2a06ce395873c545c8789a Mon Sep 17 00:00:00 2001 +From: Soenke Lambert +Date: Tue, 12 Nov 2019 10:44:02 +0100 +Subject: [PATCH] Fullscreen current window with [Alt]+[Shift]+[f] + +This actually fullscreens a window, instead of just hiding the statusbar +and applying the monocle layout. +--- + config.def.h | 1 + + dwm.c | 8 ++++++++ + 2 files changed, 9 insertions(+) + +diff --git a/config.def.h b/config.def.h +index 1c0b587..8cd3204 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -78,6 +78,7 @@ static Key keys[] = { + { MODKEY, XK_m, setlayout, {.v = &layouts[2]} }, + { MODKEY, XK_space, setlayout, {0} }, + { MODKEY|ShiftMask, XK_space, togglefloating, {0} }, ++ { MODKEY|ShiftMask, XK_f, togglefullscr, {0} }, + { MODKEY, XK_0, view, {.ui = ~0 } }, + { MODKEY|ShiftMask, XK_0, tag, {.ui = ~0 } }, + { MODKEY, XK_comma, focusmon, {.i = -1 } }, +diff --git a/dwm.c b/dwm.c +index 4465af1..c1b899a 100644 +--- a/dwm.c ++++ b/dwm.c +@@ -211,6 +211,7 @@ static void tagmon(const Arg *arg); + static void tile(Monitor *); + static void togglebar(const Arg *arg); + static void togglefloating(const Arg *arg); ++static void togglefullscr(const Arg *arg); + static void toggletag(const Arg *arg); + static void toggleview(const Arg *arg); + static void unfocus(Client *c, int setfocus); +@@ -1719,6 +1720,13 @@ togglefloating(const Arg *arg) + arrange(selmon); + } + ++void ++togglefullscr(const Arg *arg) ++{ ++ if(selmon->sel) ++ setfullscreen(selmon->sel, !selmon->sel->isfullscreen); ++} ++ + void + toggletag(const Arg *arg) + { +-- +2.17.1 + diff --git a/suckless/dwm/patches/dwm-alttagsdecoration-2020010304-cb3f58a.diff b/suckless/dwm/patches/dwm-alttagsdecoration-2020010304-cb3f58a.diff new file mode 100644 index 00000000..fcbc1ef1 --- /dev/null +++ b/suckless/dwm/patches/dwm-alttagsdecoration-2020010304-cb3f58a.diff @@ -0,0 +1,67 @@ +diff --git a/config.def.h b/config.def.h +index 1c0b587..d4b11fc 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -20,6 +20,7 @@ static const char *colors[][3] = { + + /* tagging */ + static const char *tags[] = { "1", "2", "3", "4", "5", "6", "7", "8", "9" }; ++static const char *alttags[] = { "<01>", "<02>", "<03>", "<04>", "<05>" }; + + static const Rule rules[] = { + /* xprop(1): +diff --git a/dwm.c b/dwm.c +index 4465af1..a394159 100644 +--- a/dwm.c ++++ b/dwm.c +@@ -416,7 +416,7 @@ attachstack(Client *c) + void + buttonpress(XEvent *e) + { +- unsigned int i, x, click; ++ unsigned int i, x, click, occ; + Arg arg = {0}; + Client *c; + Monitor *m; +@@ -430,9 +430,13 @@ buttonpress(XEvent *e) + focus(NULL); + } + if (ev->window == selmon->barwin) { +- i = x = 0; ++ i = x = occ = 0; ++ /* Bitmask of occupied tags */ ++ for (c = m->clients; c; c = c->next) ++ occ |= c->tags; ++ + do +- x += TEXTW(tags[i]); ++ x += TEXTW(occ & 1 << i ? alttags[i] : tags[i]); + while (ev->x >= x && ++i < LENGTH(tags)); + if (i < LENGTH(tags)) { + click = ClkTagBar; +@@ -699,6 +703,7 @@ drawbar(Monitor *m) + int boxs = drw->fonts->h / 9; + int boxw = drw->fonts->h / 6 + 2; + unsigned int i, occ = 0, urg = 0; ++ const char *tagtext; + Client *c; + + /* draw status first so it can be overdrawn by tags later */ +@@ -715,13 +720,10 @@ drawbar(Monitor *m) + } + x = 0; + for (i = 0; i < LENGTH(tags); i++) { +- w = TEXTW(tags[i]); +- drw_setscheme(drw, scheme[m->tagset[m->seltags] & 1 << i ? SchemeSel : SchemeNorm]); +- drw_text(drw, x, 0, w, bh, lrpad / 2, tags[i], urg & 1 << i); +- if (occ & 1 << i) +- drw_rect(drw, x + boxs, boxs, boxw, boxw, +- m == selmon && selmon->sel && selmon->sel->tags & 1 << i, +- urg & 1 << i); ++ tagtext = occ & 1 << i ? alttags[i] : tags[i]; ++ w = TEXTW(tagtext); ++ drw_setscheme(drw, scheme[m->tagset[m->seltags] & 1 << i ? SchemeSel : SchemeNorm]); ++ drw_text(drw, x, 0, w, bh, lrpad / 2, tagtext, urg & 1 << i); + x += w; + } + w = blw = TEXTW(m->ltsymbol); diff --git a/suckless/dwm/patches/dwm-alwayscenter-20200625-f04cac6.diff b/suckless/dwm/patches/dwm-alwayscenter-20200625-f04cac6.diff new file mode 100644 index 00000000..03ea9ef2 --- /dev/null +++ b/suckless/dwm/patches/dwm-alwayscenter-20200625-f04cac6.diff @@ -0,0 +1,12 @@ +diff -up dwm/dwm.c dwmmod/dwm.c +--- dwm/dwm.c 2020-06-25 00:21:30.383692180 -0300 ++++ dwmmod/dwm.c 2020-06-25 00:20:35.643692330 -0300 +@@ -1057,6 +1057,8 @@ manage(Window w, XWindowAttributes *wa) + updatewindowtype(c); + updatesizehints(c); + updatewmhints(c); ++ c->x = c->mon->mx + (c->mon->mw - WIDTH(c)) / 2; ++ c->y = c->mon->my + (c->mon->mh - HEIGHT(c)) / 2; + XSelectInput(dpy, w, EnterWindowMask|FocusChangeMask|PropertyChangeMask|StructureNotifyMask); + grabbuttons(c, 0); + if (!c->isfloating) diff --git a/suckless/dwm/patches/dwm-barpadding-20200720-bb2e722.diff b/suckless/dwm/patches/dwm-barpadding-20200720-bb2e722.diff new file mode 100644 index 00000000..35f490a2 --- /dev/null +++ b/suckless/dwm/patches/dwm-barpadding-20200720-bb2e722.diff @@ -0,0 +1,124 @@ +From 2f6da65e84288941babde413b9c3f4a619f853a1 Mon Sep 17 00:00:00 2001 +From: Pavel Oborin +Date: Mon, 20 Jul 2020 21:42:43 +0300 +Subject: [PATCH] Fixed drawbar + +--- + config.def.h | 2 ++ + dwm.c | 26 ++++++++++++++++---------- + 2 files changed, 18 insertions(+), 10 deletions(-) + +diff --git a/config.def.h b/config.def.h +index 1c0b587..867312f 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -5,6 +5,8 @@ static const unsigned int borderpx = 1; /* border pixel of windows */ + static const unsigned int snap = 32; /* snap pixel */ + static const int showbar = 1; /* 0 means no bar */ + static const int topbar = 1; /* 0 means bottom bar */ ++static const int vertpad = 10; /* vertical padding of bar */ ++static const int sidepad = 10; /* horizontal padding of bar */ + static const char *fonts[] = { "monospace:size=10" }; + static const char dmenufont[] = "monospace:size=10"; + static const char col_gray1[] = "#222222"; +diff --git a/dwm.c b/dwm.c +index 9fd0286..ec9c293 100644 +--- a/dwm.c ++++ b/dwm.c +@@ -242,6 +242,8 @@ static int screen; + static int sw, sh; /* X display screen geometry width, height */ + static int bh, blw = 0; /* bar geometry */ + static int lrpad; /* sum of left and right padding for text */ ++static int vp; /* vertical padding for bar */ ++static int sp; /* side padding for bar */ + static int (*xerrorxlib)(Display *, XErrorEvent *); + static unsigned int numlockmask = 0; + static void (*handler[LASTEvent]) (XEvent *) = { +@@ -568,7 +570,7 @@ configurenotify(XEvent *e) + for (c = m->clients; c; c = c->next) + if (c->isfullscreen) + resizeclient(c, m->mx, m->my, m->mw, m->mh); +- XMoveResizeWindow(dpy, m->barwin, m->wx, m->by, m->ww, bh); ++ XMoveResizeWindow(dpy, m->barwin, m->wx + sp, m->by + vp, m->ww - 2 * sp, bh); + } + focus(NULL); + arrange(NULL); +@@ -706,7 +708,7 @@ drawbar(Monitor *m) + if (m == selmon) { /* status is only drawn on selected monitor */ + drw_setscheme(drw, scheme[SchemeNorm]); + tw = TEXTW(stext) - lrpad + 2; /* 2px right padding */ +- drw_text(drw, m->ww - tw, 0, tw, bh, 0, stext, 0); ++ drw_text(drw, m->ww - tw - 2 * sp, 0, tw, bh, 0, stext, 0); + } + + for (c = m->clients; c; c = c->next) { +@@ -732,12 +734,12 @@ drawbar(Monitor *m) + if ((w = m->ww - tw - x) > bh) { + if (m->sel) { + drw_setscheme(drw, scheme[m == selmon ? SchemeSel : SchemeNorm]); +- drw_text(drw, x, 0, w, bh, lrpad / 2, m->sel->name, 0); ++ drw_text(drw, x, 0, w - 2 * sp, bh, lrpad / 2, m->sel->name, 0); + if (m->sel->isfloating) + drw_rect(drw, x + boxs, boxs, boxw, boxw, m->sel->isfixed, 0); + } else { + drw_setscheme(drw, scheme[SchemeNorm]); +- drw_rect(drw, x, 0, w, bh, 1, 1); ++ drw_rect(drw, x, 0, w - 2 * sp, bh, 1, 1); + } + } + drw_map(drw, m->barwin, 0, 0, m->ww, bh); +@@ -1548,6 +1550,9 @@ setup(void) + lrpad = drw->fonts->h; + bh = drw->fonts->h + 2; + updategeom(); ++ sp = sidepad; ++ vp = (topbar == 1) ? vertpad : - vertpad; ++ + /* init atoms */ + utf8string = XInternAtom(dpy, "UTF8_STRING", False); + wmatom[WMProtocols] = XInternAtom(dpy, "WM_PROTOCOLS", False); +@@ -1574,6 +1579,7 @@ setup(void) + /* init bars */ + updatebars(); + updatestatus(); ++ updatebarpos(selmon); + /* supporting window for NetWMCheck */ + wmcheckwin = XCreateSimpleWindow(dpy, root, 0, 0, 1, 1, 0, 0, 0); + XChangeProperty(dpy, wmcheckwin, netatom[NetWMCheck], XA_WINDOW, 32, +@@ -1704,7 +1710,7 @@ togglebar(const Arg *arg) + { + selmon->showbar = !selmon->showbar; + updatebarpos(selmon); +- XMoveResizeWindow(dpy, selmon->barwin, selmon->wx, selmon->by, selmon->ww, bh); ++ XMoveResizeWindow(dpy, selmon->barwin, selmon->wx + sp, selmon->by + vp, selmon->ww - 2 * sp, bh); + arrange(selmon); + } + +@@ -1814,7 +1820,7 @@ updatebars(void) + for (m = mons; m; m = m->next) { + if (m->barwin) + continue; +- m->barwin = XCreateWindow(dpy, root, m->wx, m->by, m->ww, bh, 0, DefaultDepth(dpy, screen), ++ m->barwin = XCreateWindow(dpy, root, m->wx + sp, m->by + vp, m->ww - 2 * sp, bh, 0, DefaultDepth(dpy, screen), + CopyFromParent, DefaultVisual(dpy, screen), + CWOverrideRedirect|CWBackPixmap|CWEventMask, &wa); + XDefineCursor(dpy, m->barwin, cursor[CurNormal]->cursor); +@@ -1829,11 +1835,11 @@ updatebarpos(Monitor *m) + m->wy = m->my; + m->wh = m->mh; + if (m->showbar) { +- m->wh -= bh; +- m->by = m->topbar ? m->wy : m->wy + m->wh; +- m->wy = m->topbar ? m->wy + bh : m->wy; ++ m->wh = m->wh - vertpad - bh; ++ m->by = m->topbar ? m->wy : m->wy + m->wh + vertpad; ++ m->wy = m->topbar ? m->wy + bh + vp : m->wy; + } else +- m->by = -bh; ++ m->by = -bh - vp; + } + + void +-- +2.27.0 + diff --git a/suckless/dwm/patches/dwm-centeredmaster-6.1.diff b/suckless/dwm/patches/dwm-centeredmaster-6.1.diff new file mode 100644 index 00000000..69268927 --- /dev/null +++ b/suckless/dwm/patches/dwm-centeredmaster-6.1.diff @@ -0,0 +1,142 @@ +diff --git a/config.def.h b/config.def.h +index 7054c06..527b214 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -39,6 +39,8 @@ static const Layout layouts[] = { + { "[]=", tile }, /* first entry is default */ + { "><>", NULL }, /* no layout function means floating behavior */ + { "[M]", monocle }, ++ { "|M|", centeredmaster }, ++ { ">M>", centeredfloatingmaster }, + }; + + /* key definitions */ +@@ -74,6 +76,8 @@ static Key keys[] = { + { MODKEY, XK_t, setlayout, {.v = &layouts[0]} }, + { MODKEY, XK_f, setlayout, {.v = &layouts[1]} }, + { MODKEY, XK_m, setlayout, {.v = &layouts[2]} }, ++ { MODKEY, XK_u, setlayout, {.v = &layouts[3]} }, ++ { MODKEY, XK_o, setlayout, {.v = &layouts[4]} }, + { MODKEY, XK_space, setlayout, {0} }, + { MODKEY|ShiftMask, XK_space, togglefloating, {0} }, + { MODKEY, XK_0, view, {.ui = ~0 } }, +diff --git a/dwm.c b/dwm.c +index 0362114..1e81412 100644 +--- a/dwm.c ++++ b/dwm.c +@@ -233,6 +233,8 @@ static int xerror(Display *dpy, XErrorEvent *ee); + static int xerrordummy(Display *dpy, XErrorEvent *ee); + static int xerrorstart(Display *dpy, XErrorEvent *ee); + static void zoom(const Arg *arg); ++static void centeredmaster(Monitor *m); ++static void centeredfloatingmaster(Monitor *m); + + /* variables */ + static const char broken[] = "broken"; +@@ -2139,3 +2141,106 @@ main(int argc, char *argv[]) + XCloseDisplay(dpy); + return EXIT_SUCCESS; + } ++ ++void ++centeredmaster(Monitor *m) ++{ ++ unsigned int i, n, h, mw, mx, my, oty, ety, tw; ++ Client *c; ++ ++ /* count number of clients in the selected monitor */ ++ for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++); ++ if (n == 0) ++ return; ++ ++ /* initialize areas */ ++ mw = m->ww; ++ mx = 0; ++ my = 0; ++ tw = mw; ++ ++ if (n > m->nmaster) { ++ /* go mfact box in the center if more than nmaster clients */ ++ mw = m->nmaster ? m->ww * m->mfact : 0; ++ tw = m->ww - mw; ++ ++ if (n - m->nmaster > 1) { ++ /* only one client */ ++ mx = (m->ww - mw) / 2; ++ tw = (m->ww - mw) / 2; ++ } ++ } ++ ++ oty = 0; ++ ety = 0; ++ for (i = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++) ++ if (i < m->nmaster) { ++ /* nmaster clients are stacked vertically, in the center ++ * of the screen */ ++ h = (m->wh - my) / (MIN(n, m->nmaster) - i); ++ resize(c, m->wx + mx, m->wy + my, mw - (2*c->bw), ++ h - (2*c->bw), 0); ++ my += HEIGHT(c); ++ } else { ++ /* stack clients are stacked vertically */ ++ if ((i - m->nmaster) % 2 ) { ++ h = (m->wh - ety) / ( (1 + n - i) / 2); ++ resize(c, m->wx, m->wy + ety, tw - (2*c->bw), ++ h - (2*c->bw), 0); ++ ety += HEIGHT(c); ++ } else { ++ h = (m->wh - oty) / ((1 + n - i) / 2); ++ resize(c, m->wx + mx + mw, m->wy + oty, ++ tw - (2*c->bw), h - (2*c->bw), 0); ++ oty += HEIGHT(c); ++ } ++ } ++} ++ ++void ++centeredfloatingmaster(Monitor *m) ++{ ++ unsigned int i, n, w, mh, mw, mx, mxo, my, myo, tx; ++ Client *c; ++ ++ /* count number of clients in the selected monitor */ ++ for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++); ++ if (n == 0) ++ return; ++ ++ /* initialize nmaster area */ ++ if (n > m->nmaster) { ++ /* go mfact box in the center if more than nmaster clients */ ++ if (m->ww > m->wh) { ++ mw = m->nmaster ? m->ww * m->mfact : 0; ++ mh = m->nmaster ? m->wh * 0.9 : 0; ++ } else { ++ mh = m->nmaster ? m->wh * m->mfact : 0; ++ mw = m->nmaster ? m->ww * 0.9 : 0; ++ } ++ mx = mxo = (m->ww - mw) / 2; ++ my = myo = (m->wh - mh) / 2; ++ } else { ++ /* go fullscreen if all clients are in the master area */ ++ mh = m->wh; ++ mw = m->ww; ++ mx = mxo = 0; ++ my = myo = 0; ++ } ++ ++ for(i = tx = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++) ++ if (i < m->nmaster) { ++ /* nmaster clients are stacked horizontally, in the center ++ * of the screen */ ++ w = (mw + mxo - mx) / (MIN(n, m->nmaster) - i); ++ resize(c, m->wx + mx, m->wy + my, w - (2*c->bw), ++ mh - (2*c->bw), 0); ++ mx += WIDTH(c); ++ } else { ++ /* stack clients are stacked horizontally */ ++ w = (m->ww - tx) / (n - i); ++ resize(c, m->wx + tx, m->wy, w - (2*c->bw), ++ m->wh - (2*c->bw), 0); ++ tx += WIDTH(c); ++ } ++} diff --git a/suckless/dwm/patches/dwm-cfacts-20200913-61bb8b2.diff b/suckless/dwm/patches/dwm-cfacts-20200913-61bb8b2.diff new file mode 100644 index 00000000..bb70e138 --- /dev/null +++ b/suckless/dwm/patches/dwm-cfacts-20200913-61bb8b2.diff @@ -0,0 +1,117 @@ +From c32a879432573d71dec7fcb4bf68927d2f4cdf10 Mon Sep 17 00:00:00 2001 +From: iofq +Date: Sat, 12 Sep 2020 22:28:09 -0500 +Subject: [PATCH] Fixed 'cfacts' patch failure due to upstream commit + 'f09418bbb...' + +--- + config.def.h | 3 +++ + dwm.c | 34 +++++++++++++++++++++++++++++++--- + 2 files changed, 34 insertions(+), 3 deletions(-) + +diff --git a/config.def.h b/config.def.h +index 1c0b587..83910c1 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -70,6 +70,9 @@ static Key keys[] = { + { MODKEY, XK_d, incnmaster, {.i = -1 } }, + { MODKEY, XK_h, setmfact, {.f = -0.05} }, + { MODKEY, XK_l, setmfact, {.f = +0.05} }, ++ { MODKEY|ShiftMask, XK_h, setcfact, {.f = +0.25} }, ++ { MODKEY|ShiftMask, XK_l, setcfact, {.f = -0.25} }, ++ { MODKEY|ShiftMask, XK_o, setcfact, {.f = 0.00} }, + { MODKEY, XK_Return, zoom, {0} }, + { MODKEY, XK_Tab, view, {0} }, + { MODKEY|ShiftMask, XK_c, killclient, {0} }, +diff --git a/dwm.c b/dwm.c +index 664c527..5233229 100644 +--- a/dwm.c ++++ b/dwm.c +@@ -87,6 +87,7 @@ typedef struct Client Client; + struct Client { + char name[256]; + float mina, maxa; ++ float cfact; + int x, y, w, h; + int oldx, oldy, oldw, oldh; + int basew, baseh, incw, inch, maxw, maxh, minw, minh; +@@ -201,6 +202,7 @@ static void setclientstate(Client *c, long state); + static void setfocus(Client *c); + static void setfullscreen(Client *c, int fullscreen); + static void setlayout(const Arg *arg); ++static void setcfact(const Arg *arg); + static void setmfact(const Arg *arg); + static void setup(void); + static void seturgent(Client *c, int urg); +@@ -1030,6 +1032,7 @@ manage(Window w, XWindowAttributes *wa) + c->w = c->oldw = wa->width; + c->h = c->oldh = wa->height; + c->oldbw = wa->border_width; ++ c->cfact = 1.0; + + updatetitle(c); + if (XGetTransientForHint(dpy, w, &trans) && (t = wintoclient(trans))) { +@@ -1512,6 +1515,23 @@ setlayout(const Arg *arg) + drawbar(selmon); + } + ++void setcfact(const Arg *arg) { ++ float f; ++ Client *c; ++ ++ c = selmon->sel; ++ ++ if(!arg || !c || !selmon->lt[selmon->sellt]->arrange) ++ return; ++ f = arg->f + c->cfact; ++ if(arg->f == 0.0) ++ f = 1.0; ++ else if(f < 0.25 || f > 4.0) ++ return; ++ c->cfact = f; ++ arrange(selmon); ++} ++ + /* arg > 1.0 will set mfact absolutely */ + void + setmfact(const Arg *arg) +@@ -1675,9 +1695,15 @@ void + tile(Monitor *m) + { + unsigned int i, n, h, mw, my, ty; ++ float mfacts = 0, sfacts = 0; + Client *c; + +- for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++); ++ for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++) { ++ if (n < m->nmaster) ++ mfacts += c->cfact; ++ else ++ sfacts += c->cfact; ++ } + if (n == 0) + return; + +@@ -1687,15 +1713,17 @@ tile(Monitor *m) + mw = m->ww; + for (i = my = ty = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++) + if (i < m->nmaster) { +- h = (m->wh - my) / (MIN(n, m->nmaster) - i); ++ h = (m->wh - my) * (c->cfact / mfacts); + resize(c, m->wx, m->wy + my, mw - (2*c->bw), h - (2*c->bw), 0); + if (my + HEIGHT(c) < m->wh) + my += HEIGHT(c); ++ mfacts -= c->cfact; + } else { +- h = (m->wh - ty) / (n - i); ++ h = (m->wh - ty) * (c->cfact / sfacts); + resize(c, m->wx + mw, m->wy + ty, m->ww - mw - (2*c->bw), h - (2*c->bw), 0); + if (ty + HEIGHT(c) < m->wh) + ty += HEIGHT(c); ++ sfacts -= c->cfact; + } + } + +-- +2.28.0 + diff --git a/suckless/dwm/patches/dwm-cfacts_centeredmaster-6.2.diff b/suckless/dwm/patches/dwm-cfacts_centeredmaster-6.2.diff new file mode 100644 index 00000000..9a00b08e --- /dev/null +++ b/suckless/dwm/patches/dwm-cfacts_centeredmaster-6.2.diff @@ -0,0 +1,180 @@ +diff -up a/config.def.h b/config.def.h +--- a/config.def.h 2019-06-05 02:24:05.503321320 +0200 ++++ b/config.def.h 2019-06-05 10:46:48.099997829 +0200 +@@ -41,6 +41,8 @@ static const Layout layouts[] = { + { "[]=", tile }, /* first entry is default */ + { "><>", NULL }, /* no layout function means floating behavior */ + { "[M]", monocle }, ++ { "|M|", centeredmaster }, ++ { ">M>", centeredfloatingmaster }, + }; + + /* key definitions */ +@@ -79,6 +81,8 @@ static Key keys[] = { + { MODKEY, XK_t, setlayout, {.v = &layouts[0]} }, + { MODKEY, XK_f, setlayout, {.v = &layouts[1]} }, + { MODKEY, XK_m, setlayout, {.v = &layouts[2]} }, ++ { MODKEY, XK_u, setlayout, {.v = &layouts[3]} }, ++ { MODKEY, XK_o, setlayout, {.v = &layouts[4]} }, + { MODKEY, XK_space, setlayout, {0} }, + { MODKEY|ShiftMask, XK_space, togglefloating, {0} }, + { MODKEY, XK_0, view, {.ui = ~0 } }, +Only in a: config.def.h.orig +Only in b: dwm-bottomstack-20160719-56a31dc.diff +diff -up a/dwm.c b/dwm.c +--- a/dwm.c 2019-06-05 02:25:40.169986187 +0200 ++++ b/dwm.c 2019-06-05 10:48:42.443328992 +0200 +@@ -235,6 +235,8 @@ static int xerror(Display *dpy, XErrorEv + static int xerrordummy(Display *dpy, XErrorEvent *ee); + static int xerrorstart(Display *dpy, XErrorEvent *ee); + static void zoom(const Arg *arg); ++static void centeredmaster(Monitor *m); ++static void centeredfloatingmaster(Monitor *m); + + /* variables */ + static const char broken[] = "broken"; +@@ -2175,3 +2177,144 @@ main(int argc, char *argv[]) + XCloseDisplay(dpy); + return EXIT_SUCCESS; + } ++ ++void ++centeredmaster(Monitor *m) ++{ ++ unsigned int i, n, h, mw, mx, my, oty, ety, tw; ++ float mfacts = 0, lfacts = 0, rfacts = 0; ++ Client *c; ++ ++ /* count number of clients in the selected monitor */ ++ for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++) { ++ if (n < m->nmaster) ++ mfacts += c->cfact; ++ else if ((n - m->nmaster) % 2) ++ lfacts += c->cfact; ++ else ++ rfacts += c->cfact; ++ } ++ if (n == 0) ++ return; ++ if(n == 1){ ++ c = nexttiled(m->clients); ++ resize(c, m->wx, m->wy, m->ww - 2 * c->bw, m->wh - 2 * c->bw, 0); ++ return; ++ } ++ ++ /* initialize areas */ ++ mw = m->ww; ++ mx = 0; ++ my = 0; ++ tw = mw; ++ ++ if (n > m->nmaster) { ++ /* go mfact box in the center if more than nmaster clients */ ++ mw = m->nmaster ? m->ww * m->mfact : 0; ++ tw = m->ww - mw; ++ ++ if (n - m->nmaster > 1) { ++ /* only one client */ ++ mx = (m->ww - mw) / 2; ++ tw = (m->ww - mw) / 2; ++ } ++ } ++ ++ oty = 0; ++ ety = 0; ++ for (i = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++) ++ if (i < m->nmaster) { ++ /* nmaster clients are stacked vertically, in the center ++ * of the screen */ ++ h = (m->wh - my) * (c->cfact / mfacts); ++ resize(c, m->wx + mx, m->wy + my, mw - 2*c->bw, ++ h - 2*c->bw, 0); ++ if(my + HEIGHT(c) < m->mh) ++ my += HEIGHT(c); ++ mfacts -= c->cfact; ++ } else { ++ /* stack clients are stacked vertically */ ++ if ((i - m->nmaster) % 2) { ++ h = (m->wh - ety) * (c->cfact / lfacts); ++ if(m->nmaster == 0) ++ resize(c, m->wx, m->wy + ety, tw - 2*c->bw, ++ h - 2*c->bw, 0); ++ else ++ resize(c, m->wx, m->wy + ety, tw - 2*c->bw, ++ h - 2*c->bw, 0); ++ if(ety + HEIGHT(c) < m->mh) ++ ety += HEIGHT(c); ++ lfacts -= c->cfact; ++ } else { ++ h = (m->wh - oty) * (c->cfact / rfacts); ++ resize(c, m->wx + mx + mw, m->wy + oty, ++ tw - 2*c->bw, h - 2*c->bw, 0); ++ if(oty + HEIGHT(c) < m->mh) ++ oty += HEIGHT(c); ++ rfacts -= c->cfact; ++ } ++ } ++} ++ ++void ++centeredfloatingmaster(Monitor *m) ++{ ++ unsigned int i, n, w, mh, mw, mx, mxo, my, myo, tx; ++ float mfacts = 0, sfacts = 0; ++ Client *c; ++ ++ /* count number of clients in the selected monitor */ ++ for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++) { ++ if (n < m->nmaster) ++ mfacts += c->cfact; ++ else ++ sfacts += c->cfact; ++ } ++ if (n == 0) ++ return; ++ if(n == 1){ ++ c = nexttiled(m->clients); ++ resize(c, m->wx, m->wy, m->ww - 2 * c->bw, m->wh - 2 * c->bw, 0); ++ return; ++ } ++ ++ /* initialize nmaster area */ ++ if (n > m->nmaster) { ++ /* go mfact box in the center if more than nmaster clients */ ++ if (m->ww > m->wh) { ++ mw = m->nmaster ? m->ww * m->mfact : 0; ++ mh = m->nmaster ? m->wh * 0.9 : 0; ++ } else { ++ mh = m->nmaster ? m->wh * m->mfact : 0; ++ mw = m->nmaster ? m->ww * 0.9 : 0; ++ } ++ mx = mxo = (m->ww - mw) / 2; ++ my = myo = (m->wh - mh) / 2; ++ } else { ++ /* go fullscreen if all clients are in the master area */ ++ mh = m->wh; ++ mw = m->ww; ++ mx = mxo = 0; ++ my = myo = 0; ++ } ++ ++ for(i = tx = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++) ++ if (i < m->nmaster) { ++ /* nmaster clients are stacked horizontally, in the center ++ * of the screen */ ++ w = (mw + mxo - mx) * (c->cfact / mfacts); ++ resize(c, m->wx + mx, m->wy + my, w - 2*c->bw, ++ mh - 2*c->bw, 0); ++ if(mx + WIDTH(c) < m->mw) ++ mx += WIDTH(c); ++ mfacts -= c->cfact; ++ } else { ++ /* stack clients are stacked horizontally */ ++ w = (m->ww - tx) * (c->cfact / sfacts); ++ resize(c, m->wx + tx, m->wy, w - 2*c->bw, ++ m->wh - 2*c->bw, 0); ++ if(tx + WIDTH(c) < m->mw) ++ tx += WIDTH(c); ++ sfacts -= c->cfact; ++ } ++} diff --git a/suckless/dwm/patches/dwm-colorbar-6.2.diff b/suckless/dwm/patches/dwm-colorbar-6.2.diff new file mode 100644 index 00000000..91c067da --- /dev/null +++ b/suckless/dwm/patches/dwm-colorbar-6.2.diff @@ -0,0 +1,68 @@ +diff --git a/config.def.h b/config.def.h +index 1c0b587..a516645 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -16,6 +16,11 @@ static const char *colors[][3] = { + /* fg bg border */ + [SchemeNorm] = { col_gray3, col_gray1, col_gray2 }, + [SchemeSel] = { col_gray4, col_cyan, col_cyan }, ++ [SchemeStatus] = { col_gray3, col_gray1, "#000000" }, // Statusbar right {text,background,not used but cannot be empty} ++ [SchemeTagsSel] = { col_gray4, col_cyan, "#000000" }, // Tagbar left selected {text,background,not used but cannot be empty} ++ [SchemeTagsNorm] = { col_gray3, col_gray1, "#000000" }, // Tagbar left unselected {text,background,not used but cannot be empty} ++ [SchemeInfoSel] = { col_gray4, col_cyan, "#000000" }, // infobar middle selected {text,background,not used but cannot be empty} ++ [SchemeInfoNorm] = { col_gray3, col_gray1, "#000000" }, // infobar middle unselected {text,background,not used but cannot be empty} + }; + + /* tagging */ +diff --git a/dwm.c b/dwm.c +index 4465af1..0d1d2f7 100644 +--- a/dwm.c ++++ b/dwm.c +@@ -59,7 +59,7 @@ + + /* enums */ + enum { CurNormal, CurResize, CurMove, CurLast }; /* cursor */ +-enum { SchemeNorm, SchemeSel }; /* color schemes */ ++enum { SchemeNorm, SchemeSel, SchemeStatus, SchemeTagsSel, SchemeTagsNorm, SchemeInfoSel, SchemeInfoNorm }; /* color schemes */ + enum { NetSupported, NetWMName, NetWMState, NetWMCheck, + NetWMFullscreen, NetActiveWindow, NetWMWindowType, + NetWMWindowTypeDialog, NetClientList, NetLast }; /* EWMH atoms */ +@@ -703,7 +703,7 @@ drawbar(Monitor *m) + + /* draw status first so it can be overdrawn by tags later */ + if (m == selmon) { /* status is only drawn on selected monitor */ +- drw_setscheme(drw, scheme[SchemeNorm]); ++ drw_setscheme(drw, scheme[SchemeStatus]); + sw = TEXTW(stext) - lrpad + 2; /* 2px right padding */ + drw_text(drw, m->ww - sw, 0, sw, bh, 0, stext, 0); + } +@@ -716,7 +716,7 @@ drawbar(Monitor *m) + x = 0; + for (i = 0; i < LENGTH(tags); i++) { + w = TEXTW(tags[i]); +- drw_setscheme(drw, scheme[m->tagset[m->seltags] & 1 << i ? SchemeSel : SchemeNorm]); ++ drw_setscheme(drw, scheme[m->tagset[m->seltags] & 1 << i ? SchemeTagsSel : SchemeTagsNorm]); + drw_text(drw, x, 0, w, bh, lrpad / 2, tags[i], urg & 1 << i); + if (occ & 1 << i) + drw_rect(drw, x + boxs, boxs, boxw, boxw, +@@ -725,17 +725,17 @@ drawbar(Monitor *m) + x += w; + } + w = blw = TEXTW(m->ltsymbol); +- drw_setscheme(drw, scheme[SchemeNorm]); ++ drw_setscheme(drw, scheme[SchemeTagsNorm]); + x = drw_text(drw, x, 0, w, bh, lrpad / 2, m->ltsymbol, 0); + + if ((w = m->ww - sw - x) > bh) { + if (m->sel) { +- drw_setscheme(drw, scheme[m == selmon ? SchemeSel : SchemeNorm]); ++ drw_setscheme(drw, scheme[m == selmon ? SchemeInfoSel : SchemeInfoNorm]); + drw_text(drw, x, 0, w, bh, lrpad / 2, m->sel->name, 0); + if (m->sel->isfloating) + drw_rect(drw, x + boxs, boxs, boxw, boxw, m->sel->isfixed, 0); + } else { +- drw_setscheme(drw, scheme[SchemeNorm]); ++ drw_setscheme(drw, scheme[SchemeInfoNorm]); + drw_rect(drw, x, 0, w, bh, 1, 1); + } + } diff --git a/suckless/dwm/patches/dwm-cyclelayouts-20180524-6.2.diff b/suckless/dwm/patches/dwm-cyclelayouts-20180524-6.2.diff new file mode 100644 index 00000000..8079028b --- /dev/null +++ b/suckless/dwm/patches/dwm-cyclelayouts-20180524-6.2.diff @@ -0,0 +1,93 @@ +From a09e766a4342f580582082a92b2de65f33208eb4 Mon Sep 17 00:00:00 2001 +From: Christopher Drelich +Date: Thu, 24 May 2018 00:56:56 -0400 +Subject: [PATCH] Function to cycle through available layouts. + +MOD-CTRL-, and MOD-CTRL-. +cycle backwards and forwards through available layouts. +Probably only useful if you have a lot of additional layouts. +The NULL, NULL layout should always be the last layout in your list, +in order to guarantee consistent behavior. +--- + config.def.h | 3 +++ + dwm.1 | 6 ++++++ + dwm.c | 18 ++++++++++++++++++ + 3 files changed, 27 insertions(+) + +diff --git a/config.def.h b/config.def.h +index a9ac303..153b880 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -41,6 +41,7 @@ static const Layout layouts[] = { + { "[]=", tile }, /* first entry is default */ + { "><>", NULL }, /* no layout function means floating behavior */ + { "[M]", monocle }, ++ { NULL, NULL }, + }; + + /* key definitions */ +@@ -76,6 +77,8 @@ static Key keys[] = { + { MODKEY, XK_t, setlayout, {.v = &layouts[0]} }, + { MODKEY, XK_f, setlayout, {.v = &layouts[1]} }, + { MODKEY, XK_m, setlayout, {.v = &layouts[2]} }, ++ { MODKEY|ControlMask, XK_comma, cyclelayout, {.i = -1 } }, ++ { MODKEY|ControlMask, XK_period, cyclelayout, {.i = +1 } }, + { MODKEY, XK_space, setlayout, {0} }, + { MODKEY|ShiftMask, XK_space, togglefloating, {0} }, + { MODKEY, XK_0, view, {.ui = ~0 } }, +diff --git a/dwm.1 b/dwm.1 +index 13b3729..165891b 100644 +--- a/dwm.1 ++++ b/dwm.1 +@@ -92,6 +92,12 @@ Sets monocle layout. + .B Mod1\-space + Toggles between current and previous layout. + .TP ++.B Mod1\-Control\-, ++Cycles backwards in layout list. ++.TP ++.B Mod1\-Control\-. ++Cycles forwards in layout list. ++.TP + .B Mod1\-j + Focus next window. + .TP +diff --git a/dwm.c b/dwm.c +index bb95e26..db73000 100644 +--- a/dwm.c ++++ b/dwm.c +@@ -157,6 +157,7 @@ static void configure(Client *c); + static void configurenotify(XEvent *e); + static void configurerequest(XEvent *e); + static Monitor *createmon(void); ++static void cyclelayout(const Arg *arg); + static void destroynotify(XEvent *e); + static void detach(Client *c); + static void detachstack(Client *c); +@@ -645,6 +646,23 @@ createmon(void) + } + + void ++cyclelayout(const Arg *arg) { ++ Layout *l; ++ for(l = (Layout *)layouts; l != selmon->lt[selmon->sellt]; l++); ++ if(arg->i > 0) { ++ if(l->symbol && (l + 1)->symbol) ++ setlayout(&((Arg) { .v = (l + 1) })); ++ else ++ setlayout(&((Arg) { .v = layouts })); ++ } else { ++ if(l != layouts && (l - 1)->symbol) ++ setlayout(&((Arg) { .v = (l - 1) })); ++ else ++ setlayout(&((Arg) { .v = &layouts[LENGTH(layouts) - 2] })); ++ } ++} ++ ++void + destroynotify(XEvent *e) + { + Client *c; +-- +2.7.4 + diff --git a/suckless/dwm/patches/dwm-deck-6.0.diff b/suckless/dwm/patches/dwm-deck-6.0.diff new file mode 100644 index 00000000..39ec2ad9 --- /dev/null +++ b/suckless/dwm/patches/dwm-deck-6.0.diff @@ -0,0 +1,90 @@ +From cb3cac91db32403bb581aecbc2957b00bb49c898 Mon Sep 17 00:00:00 2001 +From: aleks +Date: Mon, 6 May 2019 16:34:58 +0200 +Subject: [PATCH] Add deck-layout + +deck is a dwm-layout which is inspired by the TTWM window manager. +It applies the monocle-layout to the clients in the stack. +The master-client is still visible. The stacked clients are like +a deck of cards, hence the name. + +The vanilla patch doesn't work properly with patches which add gaps. +This means that when the deck-layout is activated gaps are omitted. +To make it work with the tilegap-patch apply the dwm-deck-tilegap patch +on top of the dwm-deck patch. + +The vanilla patch doesn't respect the master-area which is defined by +the rmaster-patch. To make it work with the rmaster-patch apply the +dwm-deck-rmaster patch on top of the dwm-deck patch. +--- + config.def.h | 2 ++ + dwm.c | 26 ++++++++++++++++++++++++++ + 2 files changed, 28 insertions(+) + +diff --git a/config.def.h b/config.def.h +index 77ff358..55d8a07 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -32,6 +32,7 @@ static const Layout layouts[] = { + { "[]=", tile }, /* first entry is default */ + { "><>", NULL }, /* no layout function means floating behavior */ + { "[M]", monocle }, ++ { "[D]", deck }, + }; + + /* key definitions */ +@@ -66,6 +67,7 @@ static Key keys[] = { + { MODKEY, XK_t, setlayout, {.v = &layouts[0]} }, + { MODKEY, XK_f, setlayout, {.v = &layouts[1]} }, + { MODKEY, XK_m, setlayout, {.v = &layouts[2]} }, ++ { MODKEY, XK_c, setlayout, {.v = &layouts[3]} }, + { MODKEY, XK_space, setlayout, {0} }, + { MODKEY|ShiftMask, XK_space, togglefloating, {0} }, + { MODKEY, XK_0, view, {.ui = ~0 } }, +diff --git a/dwm.c b/dwm.c +index 1d78655..356ab44 100644 +--- a/dwm.c ++++ b/dwm.c +@@ -171,6 +171,7 @@ static void configure(Client *c); + static void configurenotify(XEvent *e); + static void configurerequest(XEvent *e); + static Monitor *createmon(void); ++static void deck(Monitor *m); + static void destroynotify(XEvent *e); + static void detach(Client *c); + static void detachstack(Client *c); +@@ -669,6 +670,31 @@ destroynotify(XEvent *e) { + unmanage(c, True); + } + ++void ++deck(Monitor *m) { ++ unsigned int i, n, h, mw, my; ++ Client *c; ++ ++ for(n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++); ++ if(n == 0) ++ return; ++ ++ if(n > m->nmaster) { ++ mw = m->nmaster ? m->ww * m->mfact : 0; ++ snprintf(m->ltsymbol, sizeof m->ltsymbol, "[%d]", n - m->nmaster); ++ } ++ else ++ mw = m->ww; ++ for(i = my = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++) ++ if(i < m->nmaster) { ++ h = (m->wh - my) / (MIN(n, m->nmaster) - i); ++ resize(c, m->wx, m->wy + my, mw - (2*c->bw), h - (2*c->bw), False); ++ my += HEIGHT(c); ++ } ++ else ++ resize(c, m->wx + mw, m->wy, m->ww - mw - (2*c->bw), m->wh - (2*c->bw), False); ++} ++ + void + detach(Client *c) { + Client **tc; +-- +2.21.0 + diff --git a/suckless/dwm/patches/dwm-dwmblocks-6.2.diff b/suckless/dwm/patches/dwm-dwmblocks-6.2.diff new file mode 100644 index 00000000..626175f1 --- /dev/null +++ b/suckless/dwm/patches/dwm-dwmblocks-6.2.diff @@ -0,0 +1,340 @@ +diff -ruN dwm-6.2-ori/config.def.h dwm-6.2/config.def.h +--- dwm-6.2-ori/config.def.h 2019-02-02 18:25:28.000000000 +0530 ++++ dwm-6.2/config.def.h 2020-07-30 00:13:59.458409207 +0530 +@@ -12,10 +12,34 @@ + static const char col_gray3[] = "#bbbbbb"; + static const char col_gray4[] = "#eeeeee"; + static const char col_cyan[] = "#005577"; ++static const char col1[] = "#ffffff"; ++static const char col2[] = "#ffffff"; ++static const char col3[] = "#ffffff"; ++static const char col4[] = "#ffffff"; ++static const char col5[] = "#ffffff"; ++static const char col6[] = "#ffffff"; ++static const char col7[] = "#ffffff"; ++static const char col8[] = "#ffffff"; ++static const char col9[] = "#ffffff"; ++static const char col10[] = "#ffffff"; ++static const char col11[] = "#ffffff"; ++static const char col12[] = "#ffffff"; + static const char *colors[][3] = { + /* fg bg border */ +- [SchemeNorm] = { col_gray3, col_gray1, col_gray2 }, +- [SchemeSel] = { col_gray4, col_cyan, col_cyan }, ++ [SchemeNorm] = { col_gray3, col_gray1, col_gray2 }, ++ [SchemeSel] = { col_gray4, col_cyan, col_cyan }, ++ [SchemeCol1] = { col1, col_gray1, col_gray2 }, ++ [SchemeCol2] = { col2, col_gray1, col_gray2 }, ++ [SchemeCol3] = { col3, col_gray1, col_gray2 }, ++ [SchemeCol4] = { col4, col_gray1, col_gray2 }, ++ [SchemeCol5] = { col5, col_gray1, col_gray2 }, ++ [SchemeCol6] = { col6, col_gray1, col_gray2 }, ++ [SchemeCol7] = { col7, col_gray1, col_gray2 }, ++ [SchemeCol8] = { col8, col_gray1, col_gray2 }, ++ [SchemeCol9] = { col8, col_gray1, col_gray2 }, ++ [SchemeCol10] = { col10, col_gray1, col_gray2 }, ++ [SchemeCol11] = { col11, col_gray1, col_gray2 }, ++ [SchemeCol12] = { col12, col_gray1, col_gray2 }, + }; + + /* tagging */ +@@ -103,7 +127,9 @@ + { ClkLtSymbol, 0, Button1, setlayout, {0} }, + { ClkLtSymbol, 0, Button3, setlayout, {.v = &layouts[2]} }, + { ClkWinTitle, 0, Button2, zoom, {0} }, +- { ClkStatusText, 0, Button2, spawn, {.v = termcmd } }, ++ { ClkStatusText, 0, Button1, sigdwmblocks, {.i = 1} }, ++ { ClkStatusText, 0, Button2, sigdwmblocks, {.i = 2} }, ++ { ClkStatusText, 0, Button3, sigdwmblocks, {.i = 3} }, + { ClkClientWin, MODKEY, Button1, movemouse, {0} }, + { ClkClientWin, MODKEY, Button2, togglefloating, {0} }, + { ClkClientWin, MODKEY, Button3, resizemouse, {0} }, +diff -ruN dwm-6.2-ori/dwm.c dwm-6.2/dwm.c +--- dwm-6.2-ori/dwm.c 2019-02-02 18:25:28.000000000 +0530 ++++ dwm-6.2/dwm.c 2020-07-30 00:22:43.991855443 +0530 +@@ -40,6 +40,8 @@ + #include + #endif /* XINERAMA */ + #include ++#include ++#include + + #include "drw.h" + #include "util.h" +@@ -56,10 +58,15 @@ + #define HEIGHT(X) ((X)->h + 2 * (X)->bw) + #define TAGMASK ((1 << LENGTH(tags)) - 1) + #define TEXTW(X) (drw_fontset_getwidth(drw, (X)) + lrpad) ++#define TTEXTW(X) drw_fontset_getwidth(drw, (X)) ++ ++#define DWMBLOCKSLOCKFILE "/tmp/dwmblocks.pid" + + /* enums */ +-enum { CurNormal, CurResize, CurMove, CurLast }; /* cursor */ +-enum { SchemeNorm, SchemeSel }; /* color schemes */ ++enum { CurNormal, CurHand, CurResize, CurMove, CurLast }; /* cursor */ ++enum { SchemeNorm, SchemeSel, SchemeCol1, SchemeCol2, SchemeCol3, ++ SchemeCol4, SchemeCol5, SchemeCol6, SchemeCol7, SchemeCol8, ++ SchemeCol9, SchemeCol10, SchemeCol11, SchemeCol12 }; /* color schemes */ + enum { NetSupported, NetWMName, NetWMState, NetWMCheck, + NetWMFullscreen, NetActiveWindow, NetWMWindowType, + NetWMWindowTypeDialog, NetClientList, NetLast }; /* EWMH atoms */ +@@ -205,6 +212,7 @@ + static void seturgent(Client *c, int urg); + static void showhide(Client *c); + static void sigchld(int unused); ++static void sigdwmblocks(const Arg *arg); + static void spawn(const Arg *arg); + static void tag(const Arg *arg); + static void tagmon(const Arg *arg); +@@ -216,9 +224,11 @@ + static void unfocus(Client *c, int setfocus); + static void unmanage(Client *c, int destroyed); + static void unmapnotify(XEvent *e); ++static void updatebarcursor(int cursorpos); + static void updatebarpos(Monitor *m); + static void updatebars(void); + static void updateclientlist(void); ++static void updatedwmblockssig(int x, int e); + static int updategeom(void); + static void updatenumlockmask(void); + static void updatesizehints(Client *c); +@@ -236,7 +246,10 @@ + + /* variables */ + static const char broken[] = "broken"; +-static char stext[256]; ++static char stextc[256]; ++static char stexts[256]; ++static int wstext; ++static int dwmblockssig; + static int screen; + static int sw, sh; /* X display screen geometry width, height */ + static int bh, blw = 0; /* bar geometry */ +@@ -439,10 +452,14 @@ + arg.ui = 1 << i; + } else if (ev->x < x + blw) + click = ClkLtSymbol; +- else if (ev->x > selmon->ww - TEXTW(stext)) +- click = ClkStatusText; +- else +- click = ClkWinTitle; ++ else if (ev->x < selmon->ww - wstext) ++ click = ClkWinTitle; ++// else if (ev->x < selmon->ww - lrpad / 2 && ev->x >= (x = selmon->ww - wstext + lrpad / 2)) { ++ else if (ev->x < selmon->ww - lrpad / 2 && ev->x >= selmon->ww - wstext + lrpad / 2) { ++ click = ClkStatusText; ++// updatedwmblockssig(x, ev->x); ++ } else ++ return; + } else if ((c = wintoclient(ev->window))) { + focus(c); + restack(selmon); +@@ -695,7 +712,7 @@ + void + drawbar(Monitor *m) + { +- int x, w, sw = 0; ++ int x, w; + int boxs = drw->fonts->h / 9; + int boxw = drw->fonts->h / 6 + 2; + unsigned int i, occ = 0, urg = 0; +@@ -703,9 +720,30 @@ + + /* draw status first so it can be overdrawn by tags later */ + if (m == selmon) { /* status is only drawn on selected monitor */ +- drw_setscheme(drw, scheme[SchemeNorm]); +- sw = TEXTW(stext) - lrpad + 2; /* 2px right padding */ +- drw_text(drw, m->ww - sw, 0, sw, bh, 0, stext, 0); ++ char *ts = stextc; ++ char *tp = stextc; ++ char ctmp; ++ ++ drw_setscheme(drw, scheme[SchemeNorm]); ++ x = drw_text(drw, m->ww - wstext, 0, lrpad / 2, bh, 0, "", 0); /* to keep left padding clean */ ++ for (;;) { ++ if ((unsigned char)*ts > LENGTH(colors) + 10) { ++ ts++; ++ continue; ++ } ++ ctmp = *ts; ++ *ts = '\0'; ++ if (*tp != '\0') ++ x = drw_text(drw, x, 0, TTEXTW(tp), bh, 0, tp, 0); ++ if (ctmp == '\0') ++ break; ++ /* - 11 to compensate for + 10 above */ ++ drw_setscheme(drw, scheme[(unsigned char)ctmp - 11]); ++ *ts = ctmp; ++ tp = ++ts; ++ } ++ drw_setscheme(drw, scheme[SchemeNorm]); ++ drw_text(drw, x, 0, m->ww - x, bh, 0, "", 0); /* to keep right padding clean */ + } + + for (c = m->clients; c; c = c->next) { +@@ -728,7 +766,7 @@ + drw_setscheme(drw, scheme[SchemeNorm]); + x = drw_text(drw, x, 0, w, bh, lrpad / 2, m->ltsymbol, 0); + +- if ((w = m->ww - sw - x) > bh) { ++ if ((w = m->ww - wstext - x) > bh) { + if (m->sel) { + drw_setscheme(drw, scheme[m == selmon ? SchemeSel : SchemeNorm]); + drw_text(drw, x, 0, w, bh, lrpad / 2, m->sel->name, 0); +@@ -1122,8 +1160,11 @@ + Monitor *m; + XMotionEvent *ev = &e->xmotion; + +- if (ev->window != root) ++ if (ev->window != root) { ++ if (ev->window == selmon->barwin) ++ updatebarcursor(ev->x); + return; ++ } + if ((m = recttomon(ev->x_root, ev->y_root, 1, 1)) != mon && mon) { + unfocus(selmon->sel, 1); + selmon = m; +@@ -1564,6 +1605,7 @@ + netatom[NetClientList] = XInternAtom(dpy, "_NET_CLIENT_LIST", False); + /* init cursors */ + cursor[CurNormal] = drw_cur_create(drw, XC_left_ptr); ++ cursor[CurHand] = drw_cur_create(drw, XC_hand2); + cursor[CurResize] = drw_cur_create(drw, XC_sizing); + cursor[CurMove] = drw_cur_create(drw, XC_fleur); + /* init appearance */ +@@ -1637,6 +1679,28 @@ + } + + void ++sigdwmblocks(const Arg *arg) ++{ ++ int fd; ++ struct flock fl; ++ union sigval sv; ++ ++ if (dwmblockssig <= 0 || dwmblockssig >= 10) ++ return; ++ sv.sival_int = (dwmblockssig << 8) | arg->i; ++ fd = open(DWMBLOCKSLOCKFILE, O_RDONLY); ++ if (fd == -1) ++ return; ++ fl.l_type = F_WRLCK; ++ fl.l_start = 0; ++ fl.l_whence = SEEK_SET; ++ fl.l_len = 0; ++ if (fcntl(fd, F_GETLK, &fl) == -1 || fl.l_type == F_UNLCK) ++ return; ++ sigqueue(fl.l_pid, SIGRTMIN, sv); ++} ++ ++void + spawn(const Arg *arg) + { + if (arg->v == dmenucmd) +@@ -1805,7 +1869,7 @@ + XSetWindowAttributes wa = { + .override_redirect = True, + .background_pixmap = ParentRelative, +- .event_mask = ButtonPressMask|ExposureMask ++ .event_mask = ButtonPressMask|ExposureMask|PointerMotionMask + }; + XClassHint ch = {"dwm", "dwm"}; + for (m = mons; m; m = m->next) { +@@ -1821,6 +1885,33 @@ + } + + void ++updatebarcursor(int cursorpos) ++{ ++ static int currentcursor = 0; ++ int x; ++ ++ if (BETWEEN(cursorpos, (x = selmon->ww - wstext + lrpad / 2), x + wstext - lrpad)) { ++ updatedwmblockssig(x, cursorpos); ++ if (currentcursor) { ++ if (dwmblockssig <= 0 || dwmblockssig >= 10) { ++ currentcursor = 0; ++ XDefineCursor(dpy, selmon->barwin, cursor[CurNormal]->cursor); ++ } ++ } else { ++ if (dwmblockssig > 0 && dwmblockssig < 10) { ++ currentcursor = 1; ++ XDefineCursor(dpy, selmon->barwin, cursor[CurHand]->cursor); ++ } ++ } ++ } else { ++ if (currentcursor) { ++ currentcursor = 0; ++ XDefineCursor(dpy, selmon->barwin, cursor[CurNormal]->cursor); ++ } ++ } ++} ++ ++void + updatebarpos(Monitor *m) + { + m->wy = m->my; +@@ -1847,6 +1938,31 @@ + (unsigned char *) &(c->win), 1); + } + ++void ++updatedwmblockssig(int x, int e) ++{ ++ char *ts = stexts; ++ char *tp = stexts; ++ char ctmp; ++ ++ while (*ts != '\0') { ++ if ((unsigned char)*ts > 10) { ++ ts++; ++ continue; ++ } ++ ctmp = *ts; ++ *ts = '\0'; ++ x += TTEXTW(tp); ++ *ts = ctmp; ++ if (x >= e) { ++ dwmblockssig = (unsigned char)ctmp; ++ return; ++ } ++ tp = ++ts; ++ } ++ dwmblockssig = 0; ++} ++ + int + updategeom(void) + { +@@ -1987,9 +2103,27 @@ + void + updatestatus(void) + { +- if (!gettextprop(root, XA_WM_NAME, stext, sizeof(stext))) +- strcpy(stext, "dwm-"VERSION); +- drawbar(selmon); ++ char rawstext[256]; ++ ++ if (gettextprop(root, XA_WM_NAME, rawstext, sizeof rawstext)) { ++ char stextt[256]; ++ char *stc = stextc, *sts = stexts, *stt = stextt; ++ ++ for (char *rt = rawstext; *rt != '\0'; rt++) ++ if ((unsigned char)*rt >= ' ') ++ *(stc++) = *(sts++) = *(stt++) = *rt; ++ else if ((unsigned char)*rt > 10) ++ *(stc++) = *rt; ++ else ++ *(sts++) = *rt; ++ *stc = *sts = *stt = '\0'; ++ wstext = TEXTW(stextt); ++ } else { ++ strcpy(stextc, "dwm-"VERSION); ++ strcpy(stexts, stextc); ++ wstext = TEXTW(stextc); ++ } ++ drawbar(selmon); + } + + void diff --git a/suckless/dwm/patches/dwm-ewmhtags-6.2.diff b/suckless/dwm/patches/dwm-ewmhtags-6.2.diff new file mode 100644 index 00000000..32abb8c3 --- /dev/null +++ b/suckless/dwm/patches/dwm-ewmhtags-6.2.diff @@ -0,0 +1,161 @@ +From e5f0eefa921e6bad1e6f75faced0c3ae519995b3 Mon Sep 17 00:00:00 2001 +From: Ryan Kes +Date: Thu, 28 Mar 2019 14:49:28 +0100 +Subject: [PATCH] dwm-ewhmtags-6.2 + +--- + dwm.c | 49 ++++++++++++++++++++++++++++++++++++++++++++++++- + 1 file changed, 48 insertions(+), 1 deletion(-) + +diff --git a/dwm.c b/dwm.c +index 4465af1..92022a1 100644 +--- a/dwm.c ++++ b/dwm.c +@@ -55,6 +55,7 @@ + #define WIDTH(X) ((X)->w + 2 * (X)->bw) + #define HEIGHT(X) ((X)->h + 2 * (X)->bw) + #define TAGMASK ((1 << LENGTH(tags)) - 1) ++#define TAGSLENGTH (LENGTH(tags)) + #define TEXTW(X) (drw_fontset_getwidth(drw, (X)) + lrpad) + + /* enums */ +@@ -62,7 +63,7 @@ enum { CurNormal, CurResize, CurMove, CurLast }; /* cursor */ + enum { SchemeNorm, SchemeSel }; /* color schemes */ + enum { NetSupported, NetWMName, NetWMState, NetWMCheck, + NetWMFullscreen, NetActiveWindow, NetWMWindowType, +- NetWMWindowTypeDialog, NetClientList, NetLast }; /* EWMH atoms */ ++ NetWMWindowTypeDialog, NetClientList, NetDesktopNames, NetDesktopViewport, NetNumberOfDesktops, NetCurrentDesktop, NetLast }; /* EWMH atoms */ + enum { WMProtocols, WMDelete, WMState, WMTakeFocus, WMLast }; /* default atoms */ + enum { ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle, + ClkClientWin, ClkRootWin, ClkLast }; /* clicks */ +@@ -197,11 +198,15 @@ static void scan(void); + static int sendevent(Client *c, Atom proto); + static void sendmon(Client *c, Monitor *m); + static void setclientstate(Client *c, long state); ++static void setcurrentdesktop(void); ++static void setdesktopnames(void); + static void setfocus(Client *c); + static void setfullscreen(Client *c, int fullscreen); + static void setlayout(const Arg *arg); + static void setmfact(const Arg *arg); ++static void setnumdesktops(void); + static void setup(void); ++static void setviewport(void); + static void seturgent(Client *c, int urg); + static void showhide(Client *c); + static void sigchld(int unused); +@@ -216,6 +221,7 @@ static void toggleview(const Arg *arg); + static void unfocus(Client *c, int setfocus); + static void unmanage(Client *c, int destroyed); + static void unmapnotify(XEvent *e); ++static void updatecurrentdesktop(void); + static void updatebarpos(Monitor *m); + static void updatebars(void); + static void updateclientlist(void); +@@ -1431,6 +1437,16 @@ setclientstate(Client *c, long state) + XChangeProperty(dpy, c->win, wmatom[WMState], wmatom[WMState], 32, + PropModeReplace, (unsigned char *)data, 2); + } ++void ++setcurrentdesktop(void){ ++ long data[] = { 0 }; ++ XChangeProperty(dpy, root, netatom[NetCurrentDesktop], XA_CARDINAL, 32, PropModeReplace, (unsigned char *)data, 1); ++} ++void setdesktopnames(void){ ++ XTextProperty text; ++ Xutf8TextListToTextProperty(dpy, tags, TAGSLENGTH, XUTF8StringStyle, &text); ++ XSetTextProperty(dpy, root, &text, netatom[NetDesktopNames]); ++} + + int + sendevent(Client *c, Atom proto) +@@ -1457,6 +1473,12 @@ sendevent(Client *c, Atom proto) + return exists; + } + ++void ++setnumdesktops(void){ ++ long data[] = { TAGSLENGTH }; ++ XChangeProperty(dpy, root, netatom[NetNumberOfDesktops], XA_CARDINAL, 32, PropModeReplace, (unsigned char *)data, 1); ++} ++ + void + setfocus(Client *c) + { +@@ -1562,6 +1584,10 @@ setup(void) + netatom[NetWMWindowType] = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE", False); + netatom[NetWMWindowTypeDialog] = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_DIALOG", False); + netatom[NetClientList] = XInternAtom(dpy, "_NET_CLIENT_LIST", False); ++ netatom[NetDesktopViewport] = XInternAtom(dpy, "_NET_DESKTOP_VIEWPORT", False); ++ netatom[NetNumberOfDesktops] = XInternAtom(dpy, "_NET_NUMBER_OF_DESKTOPS", False); ++ netatom[NetCurrentDesktop] = XInternAtom(dpy, "_NET_CURRENT_DESKTOP", False); ++ netatom[NetDesktopNames] = XInternAtom(dpy, "_NET_DESKTOP_NAMES", False); + /* init cursors */ + cursor[CurNormal] = drw_cur_create(drw, XC_left_ptr); + cursor[CurResize] = drw_cur_create(drw, XC_sizing); +@@ -1584,6 +1610,10 @@ setup(void) + /* EWMH support per view */ + XChangeProperty(dpy, root, netatom[NetSupported], XA_ATOM, 32, + PropModeReplace, (unsigned char *) netatom, NetLast); ++ setnumdesktops(); ++ setcurrentdesktop(); ++ setdesktopnames(); ++ setviewport(); + XDeleteProperty(dpy, root, netatom[NetClientList]); + /* select events */ + wa.cursor = cursor[CurNormal]->cursor; +@@ -1595,6 +1625,11 @@ setup(void) + grabkeys(); + focus(NULL); + } ++void ++setviewport(void){ ++ long data[] = { 0, 0 }; ++ XChangeProperty(dpy, root, netatom[NetDesktopViewport], XA_CARDINAL, 32, PropModeReplace, (unsigned char *)data, 2); ++} + + + void +@@ -1732,6 +1767,7 @@ toggletag(const Arg *arg) + focus(NULL); + arrange(selmon); + } ++ updatecurrentdesktop(); + } + + void +@@ -1744,6 +1780,7 @@ toggleview(const Arg *arg) + focus(NULL); + arrange(selmon); + } ++ updatecurrentdesktop(); + } + + void +@@ -1846,6 +1883,15 @@ updateclientlist() + XA_WINDOW, 32, PropModeAppend, + (unsigned char *) &(c->win), 1); + } ++void updatecurrentdesktop(void){ ++ long rawdata[] = { selmon->tagset[selmon->seltags] }; ++ int i=0; ++ while(*rawdata >> i+1){ ++ i++; ++ } ++ long data[] = { i }; ++ XChangeProperty(dpy, root, netatom[NetCurrentDesktop], XA_CARDINAL, 32, PropModeReplace, (unsigned char *)data, 1); ++} + + int + updategeom(void) +@@ -2042,6 +2088,7 @@ view(const Arg *arg) + selmon->tagset[selmon->seltags] = arg->ui & TAGMASK; + focus(NULL); + arrange(selmon); ++ updatecurrentdesktop(); + } + + Client * +-- +2.21.0 + diff --git a/suckless/dwm/patches/dwm-fibonacci-5.8.2.diff b/suckless/dwm/patches/dwm-fibonacci-5.8.2.diff new file mode 100644 index 00000000..78664c89 --- /dev/null +++ b/suckless/dwm/patches/dwm-fibonacci-5.8.2.diff @@ -0,0 +1,85 @@ +diff --git a/config.def.h b/config.def.h +index cca37df..91b91aa 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -29,1 +29,2 @@ ++#include "fibonacci.c" + static const Layout layouts[] = { +@@ -34,3 +35,5 @@ ++ { "[@]", spiral }, ++ { "[\\]", dwindle }, + }; + + /* key definitions */ +diff --git a/fibonacci.c b/fibonacci.c +new file mode 100644 +index 0000000..fce0a57 +--- /dev/null ++++ b/fibonacci.c +@@ -0,0 +1,66 @@ ++void ++fibonacci(Monitor *mon, int s) { ++ unsigned int i, n, nx, ny, nw, nh; ++ Client *c; ++ ++ for(n = 0, c = nexttiled(mon->clients); c; c = nexttiled(c->next), n++); ++ if(n == 0) ++ return; ++ ++ nx = mon->wx; ++ ny = 0; ++ nw = mon->ww; ++ nh = mon->wh; ++ ++ for(i = 0, c = nexttiled(mon->clients); c; c = nexttiled(c->next)) { ++ if((i % 2 && nh / 2 > 2 * c->bw) ++ || (!(i % 2) && nw / 2 > 2 * c->bw)) { ++ if(i < n - 1) { ++ if(i % 2) ++ nh /= 2; ++ else ++ nw /= 2; ++ if((i % 4) == 2 && !s) ++ nx += nw; ++ else if((i % 4) == 3 && !s) ++ ny += nh; ++ } ++ if((i % 4) == 0) { ++ if(s) ++ ny += nh; ++ else ++ ny -= nh; ++ } ++ else if((i % 4) == 1) ++ nx += nw; ++ else if((i % 4) == 2) ++ ny += nh; ++ else if((i % 4) == 3) { ++ if(s) ++ nx += nw; ++ else ++ nx -= nw; ++ } ++ if(i == 0) ++ { ++ if(n != 1) ++ nw = mon->ww * mon->mfact; ++ ny = mon->wy; ++ } ++ else if(i == 1) ++ nw = mon->ww - nw; ++ i++; ++ } ++ resize(c, nx, ny, nw - 2 * c->bw, nh - 2 * c->bw, False); ++ } ++} ++ ++void ++dwindle(Monitor *mon) { ++ fibonacci(mon, 1); ++} ++ ++void ++spiral(Monitor *mon) { ++ fibonacci(mon, 0); ++} diff --git a/suckless/dwm/patches/dwm-fixborders-6.2.diff b/suckless/dwm/patches/dwm-fixborders-6.2.diff new file mode 100644 index 00000000..0a17b9e7 --- /dev/null +++ b/suckless/dwm/patches/dwm-fixborders-6.2.diff @@ -0,0 +1,27 @@ +From 1529909466206016f2101457bbf37c67195714c8 Mon Sep 17 00:00:00 2001 +From: Jakub Leszczak +Date: Fri, 22 Nov 2019 10:46:53 +0800 +Subject: [PATCH] Fix transparent borders + +When terminal has transparency then its borders also become transparent. +Fix it by removing transparency from any pixels drawn. +--- + drw.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drw.c b/drw.c +index 8fd1ca4..490a592 100644 +--- a/drw.c ++++ b/drw.c +@@ -202,6 +202,8 @@ drw_clr_create(Drw *drw, Clr *dest, const char *clrname) + DefaultColormap(drw->dpy, drw->screen), + clrname, dest)) + die("error, cannot allocate color '%s'", clrname); ++ ++ dest->pixel |= 0xff << 24; + } + + /* Wrapper to create color schemes. The caller has to call free(3) on the +-- +2.26.2 + diff --git a/suckless/dwm/patches/dwm-gridmode-20170909-ceac8c9.diff b/suckless/dwm/patches/dwm-gridmode-20170909-ceac8c9.diff new file mode 100644 index 00000000..feec67b0 --- /dev/null +++ b/suckless/dwm/patches/dwm-gridmode-20170909-ceac8c9.diff @@ -0,0 +1,73 @@ +From b04bb473cf9818277d33a591f7fe2dfae96afaaf Mon Sep 17 00:00:00 2001 +From: Joshua Haase +Date: Mon, 15 Aug 2016 17:06:18 -0500 +Subject: [PATCH] Apply modified gridmode patch. + +--- + config.def.h | 3 +++ + layouts.c | 27 +++++++++++++++++++++++++++ + 2 files changed, 30 insertions(+) + create mode 100644 layouts.c + +diff --git a/config.def.h b/config.def.h +index a9ac303..30b7c4a 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -36,11 +36,13 @@ static const float mfact = 0.55; /* factor of master area size [0.05..0.95] + static const int nmaster = 1; /* number of clients in master area */ + static const int resizehints = 1; /* 1 means respect size hints in tiled resizals */ + ++#include "layouts.c" + static const Layout layouts[] = { + /* symbol arrange function */ + { "[]=", tile }, /* first entry is default */ + { "><>", NULL }, /* no layout function means floating behavior */ + { "[M]", monocle }, ++ { "HHH", grid }, + }; + + /* key definitions */ +@@ -76,6 +78,7 @@ static Key keys[] = { + { MODKEY, XK_t, setlayout, {.v = &layouts[0]} }, + { MODKEY, XK_f, setlayout, {.v = &layouts[1]} }, + { MODKEY, XK_m, setlayout, {.v = &layouts[2]} }, ++ { MODKEY, XK_g, setlayout, {.v = &layouts[3]} }, + { MODKEY, XK_space, setlayout, {0} }, + { MODKEY|ShiftMask, XK_space, togglefloating, {0} }, + { MODKEY, XK_0, view, {.ui = ~0 } }, +diff --git a/layouts.c b/layouts.c +new file mode 100644 +index 0000000..d26acf3 +--- /dev/null ++++ b/layouts.c +@@ -0,0 +1,27 @@ ++void ++grid(Monitor *m) { ++ unsigned int i, n, cx, cy, cw, ch, aw, ah, cols, rows; ++ Client *c; ++ ++ for(n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next)) ++ n++; ++ ++ /* grid dimensions */ ++ for(rows = 0; rows <= n/2; rows++) ++ if(rows*rows >= n) ++ break; ++ cols = (rows && (rows - 1) * rows >= n) ? rows - 1 : rows; ++ ++ /* window geoms (cell height/width) */ ++ ch = m->wh / (rows ? rows : 1); ++ cw = m->ww / (cols ? cols : 1); ++ for(i = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next)) { ++ cx = m->wx + (i / rows) * cw; ++ cy = m->wy + (i % rows) * ch; ++ /* adjust height/width of last row/column's windows */ ++ ah = ((i + 1) % rows == 0) ? m->wh - ch * rows : 0; ++ aw = (i >= rows * (cols - 1)) ? m->ww - cw * cols : 0; ++ resize(c, cx, cy, cw - 2 * c->bw + aw, ch - 2 * c->bw + ah, False); ++ i++; ++ } ++} +-- +2.14.1 + diff --git a/suckless/dwm/patches/dwm-inplacerotate-6.2.diff b/suckless/dwm/patches/dwm-inplacerotate-6.2.diff new file mode 100644 index 00000000..d331368b --- /dev/null +++ b/suckless/dwm/patches/dwm-inplacerotate-6.2.diff @@ -0,0 +1,108 @@ +From 75012a6ab9cc1b6c319af7f4ae7d682b16a66ce3 Mon Sep 17 00:00:00 2001 +From: Miles Alan +Date: Sun, 26 Apr 2020 16:05:43 -0500 +Subject: [PATCH] Add inplacerotate fn to rotate all, master, or stacks clients + inplace + +CW (+2) or CCW (-2) Rotates all windows. +CW (+1) or CCW (-1) Rotates master xor stack windows (depending on focus). + +Focus position stays 'in-place' so the area of the screen you are focused +on remains unchanged. +--- + config.def.h | 4 ++++ + dwm.c | 59 ++++++++++++++++++++++++++++++++++++++++++++++++++++ + 2 files changed, 63 insertions(+) + +diff --git a/config.def.h b/config.def.h +index 1c0b587..9bcb792 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -66,6 +66,10 @@ static Key keys[] = { + { MODKEY, XK_b, togglebar, {0} }, + { MODKEY, XK_j, focusstack, {.i = +1 } }, + { MODKEY, XK_k, focusstack, {.i = -1 } }, ++ { MODKEY|ShiftMask, XK_j, inplacerotate, {.i = +1} }, ++ { MODKEY|ShiftMask, XK_k, inplacerotate, {.i = -1} }, ++ { MODKEY|ShiftMask, XK_h, inplacerotate, {.i = +2} }, ++ { MODKEY|ShiftMask, XK_l, inplacerotate, {.i = -2} }, + { MODKEY, XK_i, incnmaster, {.i = +1 } }, + { MODKEY, XK_d, incnmaster, {.i = -1 } }, + { MODKEY, XK_h, setmfact, {.f = -0.05} }, +diff --git a/dwm.c b/dwm.c +index 4465af1..3930680 100644 +--- a/dwm.c ++++ b/dwm.c +@@ -175,6 +175,7 @@ static int gettextprop(Window w, Atom atom, char *text, unsigned int size); + static void grabbuttons(Client *c, int focused); + static void grabkeys(void); + static void incnmaster(const Arg *arg); ++static void inplacerotate(const Arg *arg); + static void keypress(XEvent *e); + static void killclient(const Arg *arg); + static void manage(Window w, XWindowAttributes *wa); +@@ -2147,3 +2148,61 @@ main(int argc, char *argv[]) + XCloseDisplay(dpy); + return EXIT_SUCCESS; + } ++ ++void ++insertclient(Client *item, Client *insertItem, int after) { ++ Client *c; ++ if (item == NULL || insertItem == NULL || item == insertItem) return; ++ detach(insertItem); ++ if (!after && selmon->clients == item) { ++ attach(insertItem); ++ return; ++ } ++ if (after) { ++ c = item; ++ } else { ++ for (c = selmon->clients; c; c = c->next) { if (c->next == item) break; } ++ } ++ insertItem->next = c->next; ++ c->next = insertItem; ++} ++ ++void ++inplacerotate(const Arg *arg) ++{ ++ if(!selmon->sel || (selmon->sel->isfloating && !arg->f)) return; ++ ++ unsigned int selidx = 0, i = 0; ++ Client *c = NULL, *stail = NULL, *mhead = NULL, *mtail = NULL, *shead = NULL; ++ ++ // Determine positionings for insertclient ++ for (c = selmon->clients; c; c = c->next) { ++ if (ISVISIBLE(c) && !(c->isfloating)) { ++ if (selmon->sel == c) { selidx = i; } ++ if (i == selmon->nmaster - 1) { mtail = c; } ++ if (i == selmon->nmaster) { shead = c; } ++ if (mhead == NULL) { mhead = c; } ++ stail = c; ++ i++; ++ } ++ } ++ ++ // All clients rotate ++ if (arg->i == 2) insertclient(selmon->clients, stail, 0); ++ if (arg->i == -2) insertclient(stail, selmon->clients, 1); ++ // Stack xor master rotate ++ if (arg->i == -1 && selidx >= selmon->nmaster) insertclient(stail, shead, 1); ++ if (arg->i == 1 && selidx >= selmon->nmaster) insertclient(shead, stail, 0); ++ if (arg->i == -1 && selidx < selmon->nmaster) insertclient(mtail, mhead, 1); ++ if (arg->i == 1 && selidx < selmon->nmaster) insertclient(mhead, mtail, 0); ++ ++ // Restore focus position ++ i = 0; ++ for (c = selmon->clients; c; c = c->next) { ++ if (!ISVISIBLE(c) || (c->isfloating)) continue; ++ if (i == selidx) { focus(c); break; } ++ i++; ++ } ++ arrange(selmon); ++ focus(c); ++} +-- +2.23.1 + diff --git a/suckless/dwm/patches/dwm-leftlayout-20180524-c8e9479.diff b/suckless/dwm/patches/dwm-leftlayout-20180524-c8e9479.diff new file mode 100644 index 00000000..95466b11 --- /dev/null +++ b/suckless/dwm/patches/dwm-leftlayout-20180524-c8e9479.diff @@ -0,0 +1,69 @@ +From 73f9b8a4563ff89953459feae5bdbda8bdff94e7 Mon Sep 17 00:00:00 2001 +From: Christopher Drelich +Date: Thu, 24 May 2018 20:40:58 -0400 +Subject: [PATCH] Moved layout symbol to left-hand side. + +--- + dwm.c | 31 +++++++++++++++++-------------- + 1 file changed, 17 insertions(+), 14 deletions(-) + +diff --git a/dwm.c b/dwm.c +index bb95e26..9a57082 100644 +--- a/dwm.c ++++ b/dwm.c +@@ -431,18 +431,21 @@ buttonpress(XEvent *e) + } + if (ev->window == selmon->barwin) { + i = x = 0; +- do +- x += TEXTW(tags[i]); +- while (ev->x >= x && ++i < LENGTH(tags)); +- if (i < LENGTH(tags)) { +- click = ClkTagBar; +- arg.ui = 1 << i; +- } else if (ev->x < x + blw) ++ x += blw; ++ if (ev->x < x) { + click = ClkLtSymbol; +- else if (ev->x > selmon->ww - TEXTW(stext)) +- click = ClkStatusText; +- else +- click = ClkWinTitle; ++ } else { ++ do ++ x += TEXTW(tags[i]); ++ while (ev->x >= x && ++i < LENGTH(tags)); ++ if (i < LENGTH(tags)) { ++ click = ClkTagBar; ++ arg.ui = 1 << i; ++ } else if (ev->x > selmon->ww - TEXTW(stext)) ++ click = ClkStatusText; ++ else ++ click = ClkWinTitle; ++ } + } else if ((c = wintoclient(ev->window))) { + focus(c); + restack(selmon); +@@ -714,6 +717,9 @@ drawbar(Monitor *m) + urg |= c->tags; + } + x = 0; ++ w = blw = TEXTW(m->ltsymbol); ++ drw_setscheme(drw, scheme[SchemeNorm]); ++ x = drw_text(drw, x, 0, w, bh, lrpad / 2, m->ltsymbol, 0); + for (i = 0; i < LENGTH(tags); i++) { + w = TEXTW(tags[i]); + drw_setscheme(drw, scheme[m->tagset[m->seltags] & 1 << i ? SchemeSel : SchemeNorm]); +@@ -724,9 +730,6 @@ drawbar(Monitor *m) + urg & 1 << i); + x += w; + } +- w = blw = TEXTW(m->ltsymbol); +- drw_setscheme(drw, scheme[SchemeNorm]); +- x = drw_text(drw, x, 0, w, bh, lrpad / 2, m->ltsymbol, 0); + + if ((w = m->ww - sw - x) > bh) { + if (m->sel) { +-- +2.7.4 + diff --git a/suckless/dwm/patches/dwm-movestack-6.1.diff b/suckless/dwm/patches/dwm-movestack-6.1.diff new file mode 100644 index 00000000..a6c83fae --- /dev/null +++ b/suckless/dwm/patches/dwm-movestack-6.1.diff @@ -0,0 +1,73 @@ +diff -r 050d521d66d8 config.def.h +--- a/config.def.h Tue Aug 24 13:13:20 2010 +0100 ++++ b/config.def.h Sun Sep 05 18:43:07 2010 +0200 +@@ -57,6 +57,7 @@ + static const char *dmenucmd[] = { "dmenu_run", "-m", dmenumon, "-fn", dmenufont, "-nb", normbgcolor, "-nf", normfgcolor, "-sb", selbgcolor, "-sf", selfgcolor, NULL }; + static const char *termcmd[] = { "st", NULL }; + ++#include "movestack.c" + static Key keys[] = { + /* modifier key function argument */ + { MODKEY, XK_p, spawn, {.v = dmenucmd } }, +@@ -68,6 +69,8 @@ + { MODKEY, XK_d, incnmaster, {.i = -1 } }, + { MODKEY, XK_h, setmfact, {.f = -0.05} }, + { MODKEY, XK_l, setmfact, {.f = +0.05} }, ++ { MODKEY|ShiftMask, XK_j, movestack, {.i = +1 } }, ++ { MODKEY|ShiftMask, XK_k, movestack, {.i = -1 } }, + { MODKEY, XK_Return, zoom, {0} }, + { MODKEY, XK_Tab, view, {0} }, + { MODKEY|ShiftMask, XK_c, killclient, {0} }, +diff -r 050d521d66d8 movestack.c +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/movestack.c Sun Sep 05 18:43:07 2010 +0200 +@@ -0,0 +1,49 @@ ++void ++movestack(const Arg *arg) { ++ Client *c = NULL, *p = NULL, *pc = NULL, *i; ++ ++ if(arg->i > 0) { ++ /* find the client after selmon->sel */ ++ for(c = selmon->sel->next; c && (!ISVISIBLE(c) || c->isfloating); c = c->next); ++ if(!c) ++ for(c = selmon->clients; c && (!ISVISIBLE(c) || c->isfloating); c = c->next); ++ ++ } ++ else { ++ /* find the client before selmon->sel */ ++ for(i = selmon->clients; i != selmon->sel; i = i->next) ++ if(ISVISIBLE(i) && !i->isfloating) ++ c = i; ++ if(!c) ++ for(; i; i = i->next) ++ if(ISVISIBLE(i) && !i->isfloating) ++ c = i; ++ } ++ /* find the client before selmon->sel and c */ ++ for(i = selmon->clients; i && (!p || !pc); i = i->next) { ++ if(i->next == selmon->sel) ++ p = i; ++ if(i->next == c) ++ pc = i; ++ } ++ ++ /* swap c and selmon->sel selmon->clients in the selmon->clients list */ ++ if(c && c != selmon->sel) { ++ Client *temp = selmon->sel->next==c?selmon->sel:selmon->sel->next; ++ selmon->sel->next = c->next==selmon->sel?c:c->next; ++ c->next = temp; ++ ++ if(p && p != c) ++ p->next = c; ++ if(pc && pc != selmon->sel) ++ pc->next = selmon->sel; ++ ++ if(selmon->sel == selmon->clients) ++ selmon->clients = c; ++ else if(c == selmon->clients) ++ selmon->clients = selmon->sel; ++ ++ arrange(selmon); ++ } ++} ++ diff --git a/suckless/dwm/patches/dwm-netclientliststacking-6.2.diff b/suckless/dwm/patches/dwm-netclientliststacking-6.2.diff new file mode 100644 index 00000000..18d857f5 --- /dev/null +++ b/suckless/dwm/patches/dwm-netclientliststacking-6.2.diff @@ -0,0 +1,65 @@ +From 67840904a9510d6a6fc991b7f04046e74d196a26 Mon Sep 17 00:00:00 2001 +From: bakkeby +Date: Sun, 25 Oct 2020 16:40:05 +0100 +Subject: [PATCH] Adds the _NET_CLIENT_LIST_STACKING property which may be + needed by some applications, e.g. zoom for window sharing. + +--- + dwm.c | 13 ++++++++++++- + 1 file changed, 12 insertions(+), 1 deletion(-) + +diff --git a/dwm.c b/dwm.c +index 4465af1..0be261f 100644 +--- a/dwm.c ++++ b/dwm.c +@@ -62,7 +62,7 @@ enum { CurNormal, CurResize, CurMove, CurLast }; /* cursor */ + enum { SchemeNorm, SchemeSel }; /* color schemes */ + enum { NetSupported, NetWMName, NetWMState, NetWMCheck, + NetWMFullscreen, NetActiveWindow, NetWMWindowType, +- NetWMWindowTypeDialog, NetClientList, NetLast }; /* EWMH atoms */ ++ NetWMWindowTypeDialog, NetClientList, NetClientListStacking, NetLast }; /* EWMH atoms */ + enum { WMProtocols, WMDelete, WMState, WMTakeFocus, WMLast }; /* default atoms */ + enum { ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle, + ClkClientWin, ClkRootWin, ClkLast }; /* clicks */ +@@ -1066,6 +1066,8 @@ manage(Window w, XWindowAttributes *wa) + attachstack(c); + XChangeProperty(dpy, root, netatom[NetClientList], XA_WINDOW, 32, PropModeAppend, + (unsigned char *) &(c->win), 1); ++ XChangeProperty(dpy, root, netatom[NetClientListStacking], XA_WINDOW, 32, PropModePrepend, ++ (unsigned char *) &(c->win), 1); + XMoveResizeWindow(dpy, c->win, c->x + 2 * sw, c->y, c->w, c->h); /* some windows require this */ + setclientstate(c, NormalState); + if (c->mon == selmon) +@@ -1562,6 +1564,7 @@ setup(void) + netatom[NetWMWindowType] = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE", False); + netatom[NetWMWindowTypeDialog] = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_DIALOG", False); + netatom[NetClientList] = XInternAtom(dpy, "_NET_CLIENT_LIST", False); ++ netatom[NetClientListStacking] = XInternAtom(dpy, "_NET_CLIENT_LIST_STACKING", False); + /* init cursors */ + cursor[CurNormal] = drw_cur_create(drw, XC_left_ptr); + cursor[CurResize] = drw_cur_create(drw, XC_sizing); +@@ -1585,6 +1588,7 @@ setup(void) + XChangeProperty(dpy, root, netatom[NetSupported], XA_ATOM, 32, + PropModeReplace, (unsigned char *) netatom, NetLast); + XDeleteProperty(dpy, root, netatom[NetClientList]); ++ XDeleteProperty(dpy, root, netatom[NetClientListStacking]); + /* select events */ + wa.cursor = cursor[CurNormal]->cursor; + wa.event_mask = SubstructureRedirectMask|SubstructureNotifyMask +@@ -1845,6 +1849,13 @@ updateclientlist() + XChangeProperty(dpy, root, netatom[NetClientList], + XA_WINDOW, 32, PropModeAppend, + (unsigned char *) &(c->win), 1); ++ ++ XDeleteProperty(dpy, root, netatom[NetClientListStacking]); ++ for (m = mons; m; m = m->next) ++ for (c = m->stack; c; c = c->snext) ++ XChangeProperty(dpy, root, netatom[NetClientListStacking], ++ XA_WINDOW, 32, PropModeAppend, ++ (unsigned char *) &(c->win), 1); + } + + int +-- +2.19.1 + diff --git a/suckless/dwm/patches/dwm-pertag-20170513-ceac8c9.diff b/suckless/dwm/patches/dwm-pertag-20170513-ceac8c9.diff new file mode 100644 index 00000000..1a2a3cf3 --- /dev/null +++ b/suckless/dwm/patches/dwm-pertag-20170513-ceac8c9.diff @@ -0,0 +1,177 @@ +diff --git a/dwm.c b/dwm.c +index a5ce993..45f1e27 100644 +--- a/dwm.c ++++ b/dwm.c +@@ -112,6 +112,7 @@ typedef struct { + void (*arrange)(Monitor *); + } Layout; + ++typedef struct Pertag Pertag; + struct Monitor { + char ltsymbol[16]; + float mfact; +@@ -131,6 +132,7 @@ struct Monitor { + Monitor *next; + Window barwin; + const Layout *lt[2]; ++ Pertag *pertag; + }; + + typedef struct { +@@ -272,6 +274,15 @@ static Window root, wmcheckwin; + /* configuration, allows nested code to access above variables */ + #include "config.h" + ++struct Pertag { ++ unsigned int curtag, prevtag; /* current and previous tag */ ++ int nmasters[LENGTH(tags) + 1]; /* number of windows in master area */ ++ float mfacts[LENGTH(tags) + 1]; /* mfacts per tag */ ++ unsigned int sellts[LENGTH(tags) + 1]; /* selected layouts */ ++ const Layout *ltidxs[LENGTH(tags) + 1][2]; /* matrix of tags and layouts indexes */ ++ int showbars[LENGTH(tags) + 1]; /* display bar for the current tag */ ++}; ++ + /* compile-time check if all tags fit into an unsigned int bit array. */ + struct NumTags { char limitexceeded[LENGTH(tags) > 31 ? -1 : 1]; }; + +@@ -632,6 +643,7 @@ Monitor * + createmon(void) + { + Monitor *m; ++ unsigned int i; + + m = ecalloc(1, sizeof(Monitor)); + m->tagset[0] = m->tagset[1] = 1; +@@ -642,6 +654,20 @@ createmon(void) + m->lt[0] = &layouts[0]; + m->lt[1] = &layouts[1 % LENGTH(layouts)]; + strncpy(m->ltsymbol, layouts[0].symbol, sizeof m->ltsymbol); ++ m->pertag = ecalloc(1, sizeof(Pertag)); ++ m->pertag->curtag = m->pertag->prevtag = 1; ++ ++ for (i = 0; i <= LENGTH(tags); i++) { ++ m->pertag->nmasters[i] = m->nmaster; ++ m->pertag->mfacts[i] = m->mfact; ++ ++ m->pertag->ltidxs[i][0] = m->lt[0]; ++ m->pertag->ltidxs[i][1] = m->lt[1]; ++ m->pertag->sellts[i] = m->sellt; ++ ++ m->pertag->showbars[i] = m->showbar; ++ } ++ + return m; + } + +@@ -968,7 +994,7 @@ grabkeys(void) + void + incnmaster(const Arg *arg) + { +- selmon->nmaster = MAX(selmon->nmaster + arg->i, 0); ++ selmon->nmaster = selmon->pertag->nmasters[selmon->pertag->curtag] = MAX(selmon->nmaster + arg->i, 0); + arrange(selmon); + } + +@@ -1503,9 +1529,9 @@ void + setlayout(const Arg *arg) + { + if (!arg || !arg->v || arg->v != selmon->lt[selmon->sellt]) +- selmon->sellt ^= 1; ++ selmon->sellt = selmon->pertag->sellts[selmon->pertag->curtag] ^= 1; + if (arg && arg->v) +- selmon->lt[selmon->sellt] = (Layout *)arg->v; ++ selmon->lt[selmon->sellt] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt] = (Layout *)arg->v; + strncpy(selmon->ltsymbol, selmon->lt[selmon->sellt]->symbol, sizeof selmon->ltsymbol); + if (selmon->sel) + arrange(selmon); +@@ -1524,7 +1550,7 @@ setmfact(const Arg *arg) + f = arg->f < 1.0 ? arg->f + selmon->mfact : arg->f - 1.0; + if (f < 0.1 || f > 0.9) + return; +- selmon->mfact = f; ++ selmon->mfact = selmon->pertag->mfacts[selmon->pertag->curtag] = f; + arrange(selmon); + } + +@@ -1701,7 +1727,7 @@ tile(Monitor *m) + void + togglebar(const Arg *arg) + { +- selmon->showbar = !selmon->showbar; ++ selmon->showbar = selmon->pertag->showbars[selmon->pertag->curtag] = !selmon->showbar; + updatebarpos(selmon); + XMoveResizeWindow(dpy, selmon->barwin, selmon->wx, selmon->by, selmon->ww, bh); + arrange(selmon); +@@ -1740,9 +1766,33 @@ void + toggleview(const Arg *arg) + { + unsigned int newtagset = selmon->tagset[selmon->seltags] ^ (arg->ui & TAGMASK); ++ int i; + + if (newtagset) { + selmon->tagset[selmon->seltags] = newtagset; ++ ++ if (newtagset == ~0) { ++ selmon->pertag->prevtag = selmon->pertag->curtag; ++ selmon->pertag->curtag = 0; ++ } ++ ++ /* test if the user did not select the same tag */ ++ if (!(newtagset & 1 << (selmon->pertag->curtag - 1))) { ++ selmon->pertag->prevtag = selmon->pertag->curtag; ++ for (i = 0; !(newtagset & 1 << i); i++) ; ++ selmon->pertag->curtag = i + 1; ++ } ++ ++ /* apply settings for this view */ ++ selmon->nmaster = selmon->pertag->nmasters[selmon->pertag->curtag]; ++ selmon->mfact = selmon->pertag->mfacts[selmon->pertag->curtag]; ++ selmon->sellt = selmon->pertag->sellts[selmon->pertag->curtag]; ++ selmon->lt[selmon->sellt] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt]; ++ selmon->lt[selmon->sellt^1] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt^1]; ++ ++ if (selmon->showbar != selmon->pertag->showbars[selmon->pertag->curtag]) ++ togglebar(NULL); ++ + focus(NULL); + arrange(selmon); + } +@@ -2036,11 +2086,37 @@ updatewmhints(Client *c) + void + view(const Arg *arg) + { ++ int i; ++ unsigned int tmptag; ++ + if ((arg->ui & TAGMASK) == selmon->tagset[selmon->seltags]) + return; + selmon->seltags ^= 1; /* toggle sel tagset */ +- if (arg->ui & TAGMASK) ++ if (arg->ui & TAGMASK) { + selmon->tagset[selmon->seltags] = arg->ui & TAGMASK; ++ selmon->pertag->prevtag = selmon->pertag->curtag; ++ ++ if (arg->ui == ~0) ++ selmon->pertag->curtag = 0; ++ else { ++ for (i = 0; !(arg->ui & 1 << i); i++) ; ++ selmon->pertag->curtag = i + 1; ++ } ++ } else { ++ tmptag = selmon->pertag->prevtag; ++ selmon->pertag->prevtag = selmon->pertag->curtag; ++ selmon->pertag->curtag = tmptag; ++ } ++ ++ selmon->nmaster = selmon->pertag->nmasters[selmon->pertag->curtag]; ++ selmon->mfact = selmon->pertag->mfacts[selmon->pertag->curtag]; ++ selmon->sellt = selmon->pertag->sellts[selmon->pertag->curtag]; ++ selmon->lt[selmon->sellt] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt]; ++ selmon->lt[selmon->sellt^1] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt^1]; ++ ++ if (selmon->showbar != selmon->pertag->showbars[selmon->pertag->curtag]) ++ togglebar(NULL); ++ + focus(NULL); + arrange(selmon); + } diff --git a/suckless/dwm/patches/dwm-rmaster-6.1.diff b/suckless/dwm/patches/dwm-rmaster-6.1.diff new file mode 100644 index 00000000..f8a14496 --- /dev/null +++ b/suckless/dwm/patches/dwm-rmaster-6.1.diff @@ -0,0 +1,113 @@ +From 3aca05f642469799086acbc243e173cfda527683 Mon Sep 17 00:00:00 2001 +From: aleks +Date: Thu, 23 May 2019 22:39:13 +0200 +Subject: [PATCH] Enable swapping master- and stack-area + +Enables swapping the master- and stack area such that the master-client +appears on the right and the stack-clients appear on the left. + +A variable and a toggle-function are introduced to achieve this +behaviour which are set in the config.h: + +* The rmaster-variable can be set to 1 to make the right area the +default master-area +* The togglemaster-function can be used to swap the master- and +stack-areas dynamically. +--- + config.def.h | 2 ++ + dwm.c | 23 ++++++++++++++++++++--- + 2 files changed, 22 insertions(+), 3 deletions(-) + +diff --git a/config.def.h b/config.def.h +index 7054c06..5a69035 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -13,6 +13,7 @@ static const char selbgcolor[] = "#005577"; + static const char selfgcolor[] = "#eeeeee"; + static const unsigned int borderpx = 1; /* border pixel of windows */ + static const unsigned int snap = 32; /* snap pixel */ ++static const int rmaster = 1; /* 1 means master-area is initially on the right */ + static const int showbar = 1; /* 0 means no bar */ + static const int topbar = 1; /* 0 means bottom bar */ + +@@ -76,6 +77,7 @@ static Key keys[] = { + { MODKEY, XK_m, setlayout, {.v = &layouts[2]} }, + { MODKEY, XK_space, setlayout, {0} }, + { MODKEY|ShiftMask, XK_space, togglefloating, {0} }, ++ { MODKEY, XK_r, togglermaster, {0} }, + { MODKEY, XK_0, view, {.ui = ~0 } }, + { MODKEY|ShiftMask, XK_0, tag, {.ui = ~0 } }, + { MODKEY, XK_comma, focusmon, {.i = -1 } }, +diff --git a/dwm.c b/dwm.c +index 0362114..e11bd8b 100644 +--- a/dwm.c ++++ b/dwm.c +@@ -122,6 +122,7 @@ struct Monitor { + unsigned int seltags; + unsigned int sellt; + unsigned int tagset[2]; ++ int rmaster; + int showbar; + int topbar; + Client *clients; +@@ -211,6 +212,7 @@ static void tagmon(const Arg *arg); + static void tile(Monitor *); + static void togglebar(const Arg *arg); + static void togglefloating(const Arg *arg); ++static void togglermaster(const Arg *arg); + static void toggletag(const Arg *arg); + static void toggleview(const Arg *arg); + static void unfocus(Client *c, int setfocus); +@@ -645,6 +647,7 @@ createmon(void) + m->tagset[0] = m->tagset[1] = 1; + m->mfact = mfact; + m->nmaster = nmaster; ++ m->rmaster = rmaster; + m->showbar = showbar; + m->topbar = topbar; + m->lt[0] = &layouts[0]; +@@ -1674,17 +1677,21 @@ tile(Monitor *m) + return; + + if (n > m->nmaster) +- mw = m->nmaster ? m->ww * m->mfact : 0; ++ mw = m->nmaster ++ ? m->ww * (m->rmaster ? 1.0 - m->mfact : m->mfact) ++ : 0; + else + mw = m->ww; + for (i = my = ty = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++) + if (i < m->nmaster) { + h = (m->wh - my) / (MIN(n, m->nmaster) - i); +- resize(c, m->wx, m->wy + my, mw - (2*c->bw), h - (2*c->bw), 0); ++ resize(c, m->rmaster ? m->wx + m->ww - mw : m->wx, ++ m->wy + my, mw - (2*c->bw), h - (2*c->bw), 0); + my += HEIGHT(c); + } else { + h = (m->wh - ty) / (n - i); +- resize(c, m->wx + mw, m->wy + ty, m->ww - mw - (2*c->bw), h - (2*c->bw), 0); ++ resize(c, m->rmaster ? m->wx : m->wx + mw, m->wy + ty, ++ m->ww - mw - (2*c->bw), h - (2*c->bw), 0); + ty += HEIGHT(c); + } + } +@@ -1712,6 +1719,16 @@ togglefloating(const Arg *arg) + arrange(selmon); + } + ++void ++togglermaster(const Arg *arg) ++{ ++ selmon->rmaster = !selmon->rmaster; ++ /* now mfact represents the left factor */ ++ selmon->mfact = 1.0 - selmon->mfact; ++ if (selmon->lt[selmon->sellt]->arrange) ++ arrange(selmon); ++} ++ + void + toggletag(const Arg *arg) + { +-- +2.21.0 + diff --git a/suckless/dwm/patches/dwm-statuspadding-20150524-c8e9479.diff b/suckless/dwm/patches/dwm-statuspadding-20150524-c8e9479.diff new file mode 100644 index 00000000..eab4bf90 --- /dev/null +++ b/suckless/dwm/patches/dwm-statuspadding-20150524-c8e9479.diff @@ -0,0 +1,62 @@ +From 75d5edbe16ee2fc060ff8b05eea17791d6334a59 Mon Sep 17 00:00:00 2001 +From: Christopher Drelich +Date: Thu, 24 May 2018 23:24:12 -0400 +Subject: [PATCH] Replaces magic numbers in statusbar with configurable + variables. + +horizpadbar for horizontal statusbar padding +vertpadbar for vertical statusbar padding + +StatusText now has both left and right padding, +as well as the vertical padding that all of the statusbar shares. + +Other than the addition of left padding to StatusText, appearance +of the statusbar is identical to pre-patch when using the defaults +in config.def.h +--- + config.def.h | 2 ++ + dwm.c | 8 ++++---- + 2 files changed, 6 insertions(+), 4 deletions(-) + +diff --git a/config.def.h b/config.def.h +index a9ac303..5819399 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -5,6 +5,8 @@ static const unsigned int borderpx = 1; /* border pixel of windows */ + static const unsigned int snap = 32; /* snap pixel */ + static const int showbar = 1; /* 0 means no bar */ + static const int topbar = 1; /* 0 means bottom bar */ ++static const int horizpadbar = 2; /* horizontal padding for statusbar */ ++static const int vertpadbar = 0; /* vertical padding for statusbar */ + static const char *fonts[] = { "monospace:size=10" }; + static const char dmenufont[] = "monospace:size=10"; + static const char col_gray1[] = "#222222"; +diff --git a/dwm.c b/dwm.c +index bb95e26..7b9ed42 100644 +--- a/dwm.c ++++ b/dwm.c +@@ -704,8 +704,8 @@ drawbar(Monitor *m) + /* draw status first so it can be overdrawn by tags later */ + if (m == selmon) { /* status is only drawn on selected monitor */ + drw_setscheme(drw, scheme[SchemeNorm]); +- sw = TEXTW(stext) - lrpad + 2; /* 2px right padding */ +- drw_text(drw, m->ww - sw, 0, sw, bh, 0, stext, 0); ++ sw = TEXTW(stext); ++ drw_text(drw, m->ww - sw, 0, sw, bh, lrpad / 2, stext, 0); + } + + for (c = m->clients; c; c = c->next) { +@@ -1544,8 +1544,8 @@ setup(void) + drw = drw_create(dpy, screen, root, sw, sh); + if (!drw_fontset_create(drw, fonts, LENGTH(fonts))) + die("no fonts could be loaded."); +- lrpad = drw->fonts->h; +- bh = drw->fonts->h + 2; ++ lrpad = drw->fonts->h + horizpadbar; ++ bh = drw->fonts->h + vertpadbar; + updategeom(); + /* init atoms */ + utf8string = XInternAtom(dpy, "UTF8_STRING", False); +-- +2.7.4 + diff --git a/suckless/dwm/patches/dwm-switchcol-6.1.diff b/suckless/dwm/patches/dwm-switchcol-6.1.diff new file mode 100644 index 00000000..14c0c78c --- /dev/null +++ b/suckless/dwm/patches/dwm-switchcol-6.1.diff @@ -0,0 +1,47 @@ +diff -urp dwm-6.1/dwm.c dwm-6.1-patched/dwm.c +--- dwm-6.1/dwm.c 2015-11-09 06:39:37.000000000 +0800 ++++ dwm-6.1-patched/dwm.c 2016-03-24 23:56:35.435047948 +0800 +@@ -206,6 +206,7 @@ static void setup(void); + static void showhide(Client *c); + static void sigchld(int unused); + static void spawn(const Arg *arg); ++static void switchcol(const Arg *arg); + static void tag(const Arg *arg); + static void tagmon(const Arg *arg); + static void tile(Monitor *); +@@ -1645,6 +1646,35 @@ spawn(const Arg *arg) + } + } + ++void ++switchcol(const Arg *arg) ++{ ++ Client *c, *t; ++ int col = 0; ++ int i; ++ ++ if (!selmon->sel) ++ return; ++ for (i = 0, c = nexttiled(selmon->clients); c ; ++ c = nexttiled(c->next), i++) { ++ if (c == selmon->sel) ++ col = (i + 1) > selmon->nmaster; ++ } ++ if (i <= selmon->nmaster) ++ return; ++ for (c = selmon->stack; c; c = c->snext) { ++ if (!ISVISIBLE(c)) ++ continue; ++ for (i = 0, t = nexttiled(selmon->clients); t && t != c; ++ t = nexttiled(t->next), i++); ++ if (t && (i + 1 > selmon->nmaster) != col) { ++ focus(c); ++ restack(selmon); ++ break; ++ } ++ } ++} ++ + void + tag(const Arg *arg) + { diff --git a/suckless/dwm/patches/dwm-systray-20200914-61bb8b2.diff b/suckless/dwm/patches/dwm-systray-20200914-61bb8b2.diff new file mode 100644 index 00000000..b2a4d572 --- /dev/null +++ b/suckless/dwm/patches/dwm-systray-20200914-61bb8b2.diff @@ -0,0 +1,727 @@ +diff --git a/config.def.h b/config.def.h +index 1c0b587..2d824d1 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -3,6 +3,10 @@ + /* appearance */ + static const unsigned int borderpx = 1; /* border pixel of windows */ + static const unsigned int snap = 32; /* snap pixel */ ++static const unsigned int systraypinning = 0; /* 0: sloppy systray follows selected monitor, >0: pin systray to monitor X */ ++static const unsigned int systrayspacing = 2; /* systray spacing */ ++static const int systraypinningfailfirst = 1; /* 1: if pinning fails, display systray on the first monitor, False: display systray on the last monitor*/ ++static const int showsystray = 1; /* 0 means no systray */ + static const int showbar = 1; /* 0 means no bar */ + static const int topbar = 1; /* 0 means bottom bar */ + static const char *fonts[] = { "monospace:size=10" }; +diff --git a/dwm.c b/dwm.c +index 664c527..abce13d 100644 +--- a/dwm.c ++++ b/dwm.c +@@ -57,12 +57,30 @@ + #define TAGMASK ((1 << LENGTH(tags)) - 1) + #define TEXTW(X) (drw_fontset_getwidth(drw, (X)) + lrpad) + ++#define SYSTEM_TRAY_REQUEST_DOCK 0 ++ ++/* XEMBED messages */ ++#define XEMBED_EMBEDDED_NOTIFY 0 ++#define XEMBED_WINDOW_ACTIVATE 1 ++#define XEMBED_FOCUS_IN 4 ++#define XEMBED_MODALITY_ON 10 ++ ++#define XEMBED_MAPPED (1 << 0) ++#define XEMBED_WINDOW_ACTIVATE 1 ++#define XEMBED_WINDOW_DEACTIVATE 2 ++ ++#define VERSION_MAJOR 0 ++#define VERSION_MINOR 0 ++#define XEMBED_EMBEDDED_VERSION (VERSION_MAJOR << 16) | VERSION_MINOR ++ + /* enums */ + enum { CurNormal, CurResize, CurMove, CurLast }; /* cursor */ + enum { SchemeNorm, SchemeSel }; /* color schemes */ + enum { NetSupported, NetWMName, NetWMState, NetWMCheck, ++ NetSystemTray, NetSystemTrayOP, NetSystemTrayOrientation, NetSystemTrayOrientationHorz, + NetWMFullscreen, NetActiveWindow, NetWMWindowType, + NetWMWindowTypeDialog, NetClientList, NetLast }; /* EWMH atoms */ ++enum { Manager, Xembed, XembedInfo, XLast }; /* Xembed atoms */ + enum { WMProtocols, WMDelete, WMState, WMTakeFocus, WMLast }; /* default atoms */ + enum { ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle, + ClkClientWin, ClkRootWin, ClkLast }; /* clicks */ +@@ -141,6 +159,12 @@ typedef struct { + int monitor; + } Rule; + ++typedef struct Systray Systray; ++struct Systray { ++ Window win; ++ Client *icons; ++}; ++ + /* function declarations */ + static void applyrules(Client *c); + static int applysizehints(Client *c, int *x, int *y, int *w, int *h, int interact); +@@ -172,6 +196,7 @@ static void focusstack(const Arg *arg); + static Atom getatomprop(Client *c, Atom prop); + static int getrootptr(int *x, int *y); + static long getstate(Window w); ++static unsigned int getsystraywidth(); + static int gettextprop(Window w, Atom atom, char *text, unsigned int size); + static void grabbuttons(Client *c, int focused); + static void grabkeys(void); +@@ -189,13 +214,16 @@ static void pop(Client *); + static void propertynotify(XEvent *e); + static void quit(const Arg *arg); + static Monitor *recttomon(int x, int y, int w, int h); ++static void removesystrayicon(Client *i); + static void resize(Client *c, int x, int y, int w, int h, int interact); ++static void resizebarwin(Monitor *m); + static void resizeclient(Client *c, int x, int y, int w, int h); + static void resizemouse(const Arg *arg); ++static void resizerequest(XEvent *e); + static void restack(Monitor *m); + static void run(void); + static void scan(void); +-static int sendevent(Client *c, Atom proto); ++static int sendevent(Window w, Atom proto, int m, long d0, long d1, long d2, long d3, long d4); + static void sendmon(Client *c, Monitor *m); + static void setclientstate(Client *c, long state); + static void setfocus(Client *c); +@@ -207,6 +235,7 @@ static void seturgent(Client *c, int urg); + static void showhide(Client *c); + static void sigchld(int unused); + static void spawn(const Arg *arg); ++static Monitor *systraytomon(Monitor *m); + static void tag(const Arg *arg); + static void tagmon(const Arg *arg); + static void tile(Monitor *); +@@ -224,18 +253,23 @@ static int updategeom(void); + static void updatenumlockmask(void); + static void updatesizehints(Client *c); + static void updatestatus(void); ++static void updatesystray(void); ++static void updatesystrayicongeom(Client *i, int w, int h); ++static void updatesystrayiconstate(Client *i, XPropertyEvent *ev); + static void updatetitle(Client *c); + static void updatewindowtype(Client *c); + static void updatewmhints(Client *c); + static void view(const Arg *arg); + static Client *wintoclient(Window w); + static Monitor *wintomon(Window w); ++static Client *wintosystrayicon(Window w); + static int xerror(Display *dpy, XErrorEvent *ee); + static int xerrordummy(Display *dpy, XErrorEvent *ee); + static int xerrorstart(Display *dpy, XErrorEvent *ee); + static void zoom(const Arg *arg); + + /* variables */ ++static Systray *systray = NULL; + static const char broken[] = "broken"; + static char stext[256]; + static int screen; +@@ -258,9 +292,10 @@ static void (*handler[LASTEvent]) (XEvent *) = { + [MapRequest] = maprequest, + [MotionNotify] = motionnotify, + [PropertyNotify] = propertynotify, ++ [ResizeRequest] = resizerequest, + [UnmapNotify] = unmapnotify + }; +-static Atom wmatom[WMLast], netatom[NetLast]; ++static Atom wmatom[WMLast], netatom[NetLast], xatom[XLast]; + static int running = 1; + static Cur *cursor[CurLast]; + static Clr **scheme; +@@ -440,7 +475,7 @@ buttonpress(XEvent *e) + arg.ui = 1 << i; + } else if (ev->x < x + blw) + click = ClkLtSymbol; +- else if (ev->x > selmon->ww - (int)TEXTW(stext)) ++ else if (ev->x > selmon->ww - (int)TEXTW(stext) - getsystraywidth()) + click = ClkStatusText; + else + click = ClkWinTitle; +@@ -483,6 +518,11 @@ cleanup(void) + XUngrabKey(dpy, AnyKey, AnyModifier, root); + while (mons) + cleanupmon(mons); ++ if (showsystray) { ++ XUnmapWindow(dpy, systray->win); ++ XDestroyWindow(dpy, systray->win); ++ free(systray); ++ } + for (i = 0; i < CurLast; i++) + drw_cur_free(drw, cursor[i]); + for (i = 0; i < LENGTH(colors); i++) +@@ -513,9 +553,57 @@ cleanupmon(Monitor *mon) + void + clientmessage(XEvent *e) + { ++ XWindowAttributes wa; ++ XSetWindowAttributes swa; + XClientMessageEvent *cme = &e->xclient; + Client *c = wintoclient(cme->window); + ++ if (showsystray && cme->window == systray->win && cme->message_type == netatom[NetSystemTrayOP]) { ++ /* add systray icons */ ++ if (cme->data.l[1] == SYSTEM_TRAY_REQUEST_DOCK) { ++ if (!(c = (Client *)calloc(1, sizeof(Client)))) ++ die("fatal: could not malloc() %u bytes\n", sizeof(Client)); ++ if (!(c->win = cme->data.l[2])) { ++ free(c); ++ return; ++ } ++ c->mon = selmon; ++ c->next = systray->icons; ++ systray->icons = c; ++ if (!XGetWindowAttributes(dpy, c->win, &wa)) { ++ /* use sane defaults */ ++ wa.width = bh; ++ wa.height = bh; ++ wa.border_width = 0; ++ } ++ c->x = c->oldx = c->y = c->oldy = 0; ++ c->w = c->oldw = wa.width; ++ c->h = c->oldh = wa.height; ++ c->oldbw = wa.border_width; ++ c->bw = 0; ++ c->isfloating = True; ++ /* reuse tags field as mapped status */ ++ c->tags = 1; ++ updatesizehints(c); ++ updatesystrayicongeom(c, wa.width, wa.height); ++ XAddToSaveSet(dpy, c->win); ++ XSelectInput(dpy, c->win, StructureNotifyMask | PropertyChangeMask | ResizeRedirectMask); ++ XReparentWindow(dpy, c->win, systray->win, 0, 0); ++ /* use parents background color */ ++ swa.background_pixel = scheme[SchemeNorm][ColBg].pixel; ++ XChangeWindowAttributes(dpy, c->win, CWBackPixel, &swa); ++ sendevent(c->win, netatom[Xembed], StructureNotifyMask, CurrentTime, XEMBED_EMBEDDED_NOTIFY, 0 , systray->win, XEMBED_EMBEDDED_VERSION); ++ /* FIXME not sure if I have to send these events, too */ ++ sendevent(c->win, netatom[Xembed], StructureNotifyMask, CurrentTime, XEMBED_FOCUS_IN, 0 , systray->win, XEMBED_EMBEDDED_VERSION); ++ sendevent(c->win, netatom[Xembed], StructureNotifyMask, CurrentTime, XEMBED_WINDOW_ACTIVATE, 0 , systray->win, XEMBED_EMBEDDED_VERSION); ++ sendevent(c->win, netatom[Xembed], StructureNotifyMask, CurrentTime, XEMBED_MODALITY_ON, 0 , systray->win, XEMBED_EMBEDDED_VERSION); ++ XSync(dpy, False); ++ resizebarwin(selmon); ++ updatesystray(); ++ setclientstate(c, NormalState); ++ } ++ return; ++ } + if (!c) + return; + if (cme->message_type == netatom[NetWMState]) { +@@ -568,7 +656,7 @@ configurenotify(XEvent *e) + for (c = m->clients; c; c = c->next) + if (c->isfullscreen) + resizeclient(c, m->mx, m->my, m->mw, m->mh); +- XMoveResizeWindow(dpy, m->barwin, m->wx, m->by, m->ww, bh); ++ resizebarwin(m); + } + focus(NULL); + arrange(NULL); +@@ -653,6 +741,11 @@ destroynotify(XEvent *e) + + if ((c = wintoclient(ev->window))) + unmanage(c, 1); ++ else if ((c = wintosystrayicon(ev->window))) { ++ removesystrayicon(c); ++ resizebarwin(selmon); ++ updatesystray(); ++ } + } + + void +@@ -696,19 +789,23 @@ dirtomon(int dir) + void + drawbar(Monitor *m) + { +- int x, w, tw = 0; ++ int x, w, tw = 0, stw = 0; + int boxs = drw->fonts->h / 9; + int boxw = drw->fonts->h / 6 + 2; + unsigned int i, occ = 0, urg = 0; + Client *c; + ++ if(showsystray && m == systraytomon(m)) ++ stw = getsystraywidth(); ++ + /* draw status first so it can be overdrawn by tags later */ + if (m == selmon) { /* status is only drawn on selected monitor */ + drw_setscheme(drw, scheme[SchemeNorm]); +- tw = TEXTW(stext) - lrpad + 2; /* 2px right padding */ +- drw_text(drw, m->ww - tw, 0, tw, bh, 0, stext, 0); ++ tw = TEXTW(stext) - lrpad / 2 + 2; /* 2px right padding */ ++ drw_text(drw, m->ww - tw - stw, 0, tw, bh, lrpad / 2 - 2, stext, 0); + } + ++ resizebarwin(m); + for (c = m->clients; c; c = c->next) { + occ |= c->tags; + if (c->isurgent) +@@ -729,7 +826,7 @@ drawbar(Monitor *m) + drw_setscheme(drw, scheme[SchemeNorm]); + x = drw_text(drw, x, 0, w, bh, lrpad / 2, m->ltsymbol, 0); + +- if ((w = m->ww - tw - x) > bh) { ++ if ((w = m->ww - tw - stw - x) > bh) { + if (m->sel) { + drw_setscheme(drw, scheme[m == selmon ? SchemeSel : SchemeNorm]); + drw_text(drw, x, 0, w, bh, lrpad / 2, m->sel->name, 0); +@@ -740,7 +837,7 @@ drawbar(Monitor *m) + drw_rect(drw, x, 0, w, bh, 1, 1); + } + } +- drw_map(drw, m->barwin, 0, 0, m->ww, bh); ++ drw_map(drw, m->barwin, 0, 0, m->ww - stw, bh); + } + + void +@@ -777,8 +874,11 @@ expose(XEvent *e) + Monitor *m; + XExposeEvent *ev = &e->xexpose; + +- if (ev->count == 0 && (m = wintomon(ev->window))) ++ if (ev->count == 0 && (m = wintomon(ev->window))) { + drawbar(m); ++ if (m == selmon) ++ updatesystray(); ++ } + } + + void +@@ -863,10 +963,17 @@ getatomprop(Client *c, Atom prop) + unsigned long dl; + unsigned char *p = NULL; + Atom da, atom = None; ++ /* FIXME getatomprop should return the number of items and a pointer to ++ * the stored data instead of this workaround */ ++ Atom req = XA_ATOM; ++ if (prop == xatom[XembedInfo]) ++ req = xatom[XembedInfo]; + +- if (XGetWindowProperty(dpy, c->win, prop, 0L, sizeof atom, False, XA_ATOM, ++ if (XGetWindowProperty(dpy, c->win, prop, 0L, sizeof atom, False, req, + &da, &di, &dl, &dl, &p) == Success && p) { + atom = *(Atom *)p; ++ if (da == xatom[XembedInfo] && dl == 2) ++ atom = ((Atom *)p)[1]; + XFree(p); + } + return atom; +@@ -900,6 +1007,16 @@ getstate(Window w) + return result; + } + ++unsigned int ++getsystraywidth() ++{ ++ unsigned int w = 0; ++ Client *i; ++ if(showsystray) ++ for(i = systray->icons; i; w += i->w + systrayspacing, i = i->next) ; ++ return w ? w + systrayspacing : 1; ++} ++ + int + gettextprop(Window w, Atom atom, char *text, unsigned int size) + { +@@ -1004,7 +1121,7 @@ killclient(const Arg *arg) + { + if (!selmon->sel) + return; +- if (!sendevent(selmon->sel, wmatom[WMDelete])) { ++ if (!sendevent(selmon->sel->win, wmatom[WMDelete], NoEventMask, wmatom[WMDelete], CurrentTime, 0 , 0, 0)) { + XGrabServer(dpy); + XSetErrorHandler(xerrordummy); + XSetCloseDownMode(dpy, DestroyAll); +@@ -1092,6 +1209,12 @@ maprequest(XEvent *e) + { + static XWindowAttributes wa; + XMapRequestEvent *ev = &e->xmaprequest; ++ Client *i; ++ if ((i = wintosystrayicon(ev->window))) { ++ sendevent(i->win, netatom[Xembed], StructureNotifyMask, CurrentTime, XEMBED_WINDOW_ACTIVATE, 0, systray->win, XEMBED_EMBEDDED_VERSION); ++ resizebarwin(selmon); ++ updatesystray(); ++ } + + if (!XGetWindowAttributes(dpy, ev->window, &wa)) + return; +@@ -1216,6 +1339,16 @@ propertynotify(XEvent *e) + Window trans; + XPropertyEvent *ev = &e->xproperty; + ++ if ((c = wintosystrayicon(ev->window))) { ++ if (ev->atom == XA_WM_NORMAL_HINTS) { ++ updatesizehints(c); ++ updatesystrayicongeom(c, c->w, c->h); ++ } ++ else ++ updatesystrayiconstate(c, ev); ++ resizebarwin(selmon); ++ updatesystray(); ++ } + if ((ev->window == root) && (ev->atom == XA_WM_NAME)) + updatestatus(); + else if (ev->state == PropertyDelete) +@@ -1266,6 +1399,20 @@ recttomon(int x, int y, int w, int h) + return r; + } + ++void ++removesystrayicon(Client *i) ++{ ++ Client **ii; ++ ++ if (!showsystray || !i) ++ return; ++ for (ii = &systray->icons; *ii && *ii != i; ii = &(*ii)->next); ++ if (ii) ++ *ii = i->next; ++ free(i); ++} ++ ++ + void + resize(Client *c, int x, int y, int w, int h, int interact) + { +@@ -1273,6 +1420,14 @@ resize(Client *c, int x, int y, int w, int h, int interact) + resizeclient(c, x, y, w, h); + } + ++void ++resizebarwin(Monitor *m) { ++ unsigned int w = m->ww; ++ if (showsystray && m == systraytomon(m)) ++ w -= getsystraywidth(); ++ XMoveResizeWindow(dpy, m->barwin, m->wx, m->by, w, bh); ++} ++ + void + resizeclient(Client *c, int x, int y, int w, int h) + { +@@ -1345,6 +1500,19 @@ resizemouse(const Arg *arg) + } + } + ++void ++resizerequest(XEvent *e) ++{ ++ XResizeRequestEvent *ev = &e->xresizerequest; ++ Client *i; ++ ++ if ((i = wintosystrayicon(ev->window))) { ++ updatesystrayicongeom(i, ev->width, ev->height); ++ resizebarwin(selmon); ++ updatesystray(); ++ } ++} ++ + void + restack(Monitor *m) + { +@@ -1434,26 +1602,36 @@ setclientstate(Client *c, long state) + } + + int +-sendevent(Client *c, Atom proto) ++sendevent(Window w, Atom proto, int mask, long d0, long d1, long d2, long d3, long d4) + { + int n; +- Atom *protocols; ++ Atom *protocols, mt; + int exists = 0; + XEvent ev; + +- if (XGetWMProtocols(dpy, c->win, &protocols, &n)) { +- while (!exists && n--) +- exists = protocols[n] == proto; +- XFree(protocols); ++ if (proto == wmatom[WMTakeFocus] || proto == wmatom[WMDelete]) { ++ mt = wmatom[WMProtocols]; ++ if (XGetWMProtocols(dpy, w, &protocols, &n)) { ++ while (!exists && n--) ++ exists = protocols[n] == proto; ++ XFree(protocols); ++ } ++ } ++ else { ++ exists = True; ++ mt = proto; + } + if (exists) { + ev.type = ClientMessage; +- ev.xclient.window = c->win; +- ev.xclient.message_type = wmatom[WMProtocols]; ++ ev.xclient.window = w; ++ ev.xclient.message_type = mt; + ev.xclient.format = 32; +- ev.xclient.data.l[0] = proto; +- ev.xclient.data.l[1] = CurrentTime; +- XSendEvent(dpy, c->win, False, NoEventMask, &ev); ++ ev.xclient.data.l[0] = d0; ++ ev.xclient.data.l[1] = d1; ++ ev.xclient.data.l[2] = d2; ++ ev.xclient.data.l[3] = d3; ++ ev.xclient.data.l[4] = d4; ++ XSendEvent(dpy, w, False, mask, &ev); + } + return exists; + } +@@ -1467,7 +1645,7 @@ setfocus(Client *c) + XA_WINDOW, 32, PropModeReplace, + (unsigned char *) &(c->win), 1); + } +- sendevent(c, wmatom[WMTakeFocus]); ++ sendevent(c->win, wmatom[WMTakeFocus], NoEventMask, wmatom[WMTakeFocus], CurrentTime, 0, 0, 0); + } + + void +@@ -1556,6 +1734,10 @@ setup(void) + wmatom[WMTakeFocus] = XInternAtom(dpy, "WM_TAKE_FOCUS", False); + netatom[NetActiveWindow] = XInternAtom(dpy, "_NET_ACTIVE_WINDOW", False); + netatom[NetSupported] = XInternAtom(dpy, "_NET_SUPPORTED", False); ++ netatom[NetSystemTray] = XInternAtom(dpy, "_NET_SYSTEM_TRAY_S0", False); ++ netatom[NetSystemTrayOP] = XInternAtom(dpy, "_NET_SYSTEM_TRAY_OPCODE", False); ++ netatom[NetSystemTrayOrientation] = XInternAtom(dpy, "_NET_SYSTEM_TRAY_ORIENTATION", False); ++ netatom[NetSystemTrayOrientationHorz] = XInternAtom(dpy, "_NET_SYSTEM_TRAY_ORIENTATION_HORZ", False); + netatom[NetWMName] = XInternAtom(dpy, "_NET_WM_NAME", False); + netatom[NetWMState] = XInternAtom(dpy, "_NET_WM_STATE", False); + netatom[NetWMCheck] = XInternAtom(dpy, "_NET_SUPPORTING_WM_CHECK", False); +@@ -1563,6 +1745,9 @@ setup(void) + netatom[NetWMWindowType] = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE", False); + netatom[NetWMWindowTypeDialog] = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_DIALOG", False); + netatom[NetClientList] = XInternAtom(dpy, "_NET_CLIENT_LIST", False); ++ xatom[Manager] = XInternAtom(dpy, "MANAGER", False); ++ xatom[Xembed] = XInternAtom(dpy, "_XEMBED", False); ++ xatom[XembedInfo] = XInternAtom(dpy, "_XEMBED_INFO", False); + /* init cursors */ + cursor[CurNormal] = drw_cur_create(drw, XC_left_ptr); + cursor[CurResize] = drw_cur_create(drw, XC_sizing); +@@ -1571,6 +1756,8 @@ setup(void) + scheme = ecalloc(LENGTH(colors), sizeof(Clr *)); + for (i = 0; i < LENGTH(colors); i++) + scheme[i] = drw_scm_create(drw, colors[i], 3); ++ /* init system tray */ ++ updatesystray(); + /* init bars */ + updatebars(); + updatestatus(); +@@ -1704,7 +1891,18 @@ togglebar(const Arg *arg) + { + selmon->showbar = !selmon->showbar; + updatebarpos(selmon); +- XMoveResizeWindow(dpy, selmon->barwin, selmon->wx, selmon->by, selmon->ww, bh); ++ resizebarwin(selmon); ++ if (showsystray) { ++ XWindowChanges wc; ++ if (!selmon->showbar) ++ wc.y = -bh; ++ else if (selmon->showbar) { ++ wc.y = 0; ++ if (!selmon->topbar) ++ wc.y = selmon->mh - bh; ++ } ++ XConfigureWindow(dpy, systray->win, CWY, &wc); ++ } + arrange(selmon); + } + +@@ -1799,11 +1997,18 @@ unmapnotify(XEvent *e) + else + unmanage(c, 0); + } ++ else if ((c = wintosystrayicon(ev->window))) { ++ /* KLUDGE! sometimes icons occasionally unmap their windows, but do ++ * _not_ destroy them. We map those windows back */ ++ XMapRaised(dpy, c->win); ++ updatesystray(); ++ } + } + + void + updatebars(void) + { ++ unsigned int w; + Monitor *m; + XSetWindowAttributes wa = { + .override_redirect = True, +@@ -1814,10 +2019,15 @@ updatebars(void) + for (m = mons; m; m = m->next) { + if (m->barwin) + continue; +- m->barwin = XCreateWindow(dpy, root, m->wx, m->by, m->ww, bh, 0, DefaultDepth(dpy, screen), ++ w = m->ww; ++ if (showsystray && m == systraytomon(m)) ++ w -= getsystraywidth(); ++ m->barwin = XCreateWindow(dpy, root, m->wx, m->by, w, bh, 0, DefaultDepth(dpy, screen), + CopyFromParent, DefaultVisual(dpy, screen), + CWOverrideRedirect|CWBackPixmap|CWEventMask, &wa); + XDefineCursor(dpy, m->barwin, cursor[CurNormal]->cursor); ++ if (showsystray && m == systraytomon(m)) ++ XMapRaised(dpy, systray->win); + XMapRaised(dpy, m->barwin); + XSetClassHint(dpy, m->barwin, &ch); + } +@@ -1993,6 +2203,121 @@ updatestatus(void) + if (!gettextprop(root, XA_WM_NAME, stext, sizeof(stext))) + strcpy(stext, "dwm-"VERSION); + drawbar(selmon); ++ updatesystray(); ++} ++ ++void ++updatesystrayicongeom(Client *i, int w, int h) ++{ ++ if (i) { ++ i->h = bh; ++ if (w == h) ++ i->w = bh; ++ else if (h == bh) ++ i->w = w; ++ else ++ i->w = (int) ((float)bh * ((float)w / (float)h)); ++ applysizehints(i, &(i->x), &(i->y), &(i->w), &(i->h), False); ++ /* force icons into the systray dimensions if they don't want to */ ++ if (i->h > bh) { ++ if (i->w == i->h) ++ i->w = bh; ++ else ++ i->w = (int) ((float)bh * ((float)i->w / (float)i->h)); ++ i->h = bh; ++ } ++ } ++} ++ ++void ++updatesystrayiconstate(Client *i, XPropertyEvent *ev) ++{ ++ long flags; ++ int code = 0; ++ ++ if (!showsystray || !i || ev->atom != xatom[XembedInfo] || ++ !(flags = getatomprop(i, xatom[XembedInfo]))) ++ return; ++ ++ if (flags & XEMBED_MAPPED && !i->tags) { ++ i->tags = 1; ++ code = XEMBED_WINDOW_ACTIVATE; ++ XMapRaised(dpy, i->win); ++ setclientstate(i, NormalState); ++ } ++ else if (!(flags & XEMBED_MAPPED) && i->tags) { ++ i->tags = 0; ++ code = XEMBED_WINDOW_DEACTIVATE; ++ XUnmapWindow(dpy, i->win); ++ setclientstate(i, WithdrawnState); ++ } ++ else ++ return; ++ sendevent(i->win, xatom[Xembed], StructureNotifyMask, CurrentTime, code, 0, ++ systray->win, XEMBED_EMBEDDED_VERSION); ++} ++ ++void ++updatesystray(void) ++{ ++ XSetWindowAttributes wa; ++ XWindowChanges wc; ++ Client *i; ++ Monitor *m = systraytomon(NULL); ++ unsigned int x = m->mx + m->mw; ++ unsigned int w = 1; ++ ++ if (!showsystray) ++ return; ++ if (!systray) { ++ /* init systray */ ++ if (!(systray = (Systray *)calloc(1, sizeof(Systray)))) ++ die("fatal: could not malloc() %u bytes\n", sizeof(Systray)); ++ systray->win = XCreateSimpleWindow(dpy, root, x, m->by, w, bh, 0, 0, scheme[SchemeSel][ColBg].pixel); ++ wa.event_mask = ButtonPressMask | ExposureMask; ++ wa.override_redirect = True; ++ wa.background_pixel = scheme[SchemeNorm][ColBg].pixel; ++ XSelectInput(dpy, systray->win, SubstructureNotifyMask); ++ XChangeProperty(dpy, systray->win, netatom[NetSystemTrayOrientation], XA_CARDINAL, 32, ++ PropModeReplace, (unsigned char *)&netatom[NetSystemTrayOrientationHorz], 1); ++ XChangeWindowAttributes(dpy, systray->win, CWEventMask|CWOverrideRedirect|CWBackPixel, &wa); ++ XMapRaised(dpy, systray->win); ++ XSetSelectionOwner(dpy, netatom[NetSystemTray], systray->win, CurrentTime); ++ if (XGetSelectionOwner(dpy, netatom[NetSystemTray]) == systray->win) { ++ sendevent(root, xatom[Manager], StructureNotifyMask, CurrentTime, netatom[NetSystemTray], systray->win, 0, 0); ++ XSync(dpy, False); ++ } ++ else { ++ fprintf(stderr, "dwm: unable to obtain system tray.\n"); ++ free(systray); ++ systray = NULL; ++ return; ++ } ++ } ++ for (w = 0, i = systray->icons; i; i = i->next) { ++ /* make sure the background color stays the same */ ++ wa.background_pixel = scheme[SchemeNorm][ColBg].pixel; ++ XChangeWindowAttributes(dpy, i->win, CWBackPixel, &wa); ++ XMapRaised(dpy, i->win); ++ w += systrayspacing; ++ i->x = w; ++ XMoveResizeWindow(dpy, i->win, i->x, 0, i->w, i->h); ++ w += i->w; ++ if (i->mon != m) ++ i->mon = m; ++ } ++ w = w ? w + systrayspacing : 1; ++ x -= w; ++ XMoveResizeWindow(dpy, systray->win, x, m->by, w, bh); ++ wc.x = x; wc.y = m->by; wc.width = w; wc.height = bh; ++ wc.stack_mode = Above; wc.sibling = m->barwin; ++ XConfigureWindow(dpy, systray->win, CWX|CWY|CWWidth|CWHeight|CWSibling|CWStackMode, &wc); ++ XMapWindow(dpy, systray->win); ++ XMapSubwindows(dpy, systray->win); ++ /* redraw background */ ++ XSetForeground(dpy, drw->gc, scheme[SchemeNorm][ColBg].pixel); ++ XFillRectangle(dpy, systray->win, drw->gc, 0, 0, w, bh); ++ XSync(dpy, False); + } + + void +@@ -2060,6 +2385,16 @@ wintoclient(Window w) + return NULL; + } + ++Client * ++wintosystrayicon(Window w) { ++ Client *i = NULL; ++ ++ if (!showsystray || !w) ++ return i; ++ for (i = systray->icons; i && i->win != w; i = i->next) ; ++ return i; ++} ++ + Monitor * + wintomon(Window w) + { +@@ -2113,6 +2448,22 @@ xerrorstart(Display *dpy, XErrorEvent *ee) + return -1; + } + ++Monitor * ++systraytomon(Monitor *m) { ++ Monitor *t; ++ int i, n; ++ if(!systraypinning) { ++ if(!m) ++ return selmon; ++ return m == selmon ? m : NULL; ++ } ++ for(n = 1, t = mons; t && t->next; n++, t = t->next) ; ++ for(i = 1, t = mons; t && t->next && i < systraypinning; i++, t = t->next) ; ++ if(systraypinningfailfirst && n < systraypinning) ++ return mons; ++ return t; ++} ++ + void + zoom(const Arg *arg) + { diff --git a/suckless/dwm/patches/dwm-uselessgap-6.2.diff b/suckless/dwm/patches/dwm-uselessgap-6.2.diff new file mode 100644 index 00000000..a7847b5e --- /dev/null +++ b/suckless/dwm/patches/dwm-uselessgap-6.2.diff @@ -0,0 +1,81 @@ +From 58a5ece9406ca6c90dc362617c065e4aac19417f Mon Sep 17 00:00:00 2001 +From: Cyril Cressent +Date: Wed, 3 Jul 2019 21:33:45 -0700 +Subject: [PATCH] Port the uselessgap patch to 6.2 + +--- + config.def.h | 1 + + dwm.c | 36 ++++++++++++++++++++++++++++++------ + 2 files changed, 31 insertions(+), 6 deletions(-) + +diff --git a/config.def.h b/config.def.h +index 1c0b587..b11471d 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -2,6 +2,7 @@ + + /* appearance */ + static const unsigned int borderpx = 1; /* border pixel of windows */ ++static const unsigned int gappx = 6; /* gaps between windows */ + static const unsigned int snap = 32; /* snap pixel */ + static const int showbar = 1; /* 0 means no bar */ + static const int topbar = 1; /* 0 means bottom bar */ +diff --git a/dwm.c b/dwm.c +index 4465af1..4545e05 100644 +--- a/dwm.c ++++ b/dwm.c +@@ -52,8 +52,8 @@ + #define ISVISIBLE(C) ((C->tags & C->mon->tagset[C->mon->seltags])) + #define LENGTH(X) (sizeof X / sizeof X[0]) + #define MOUSEMASK (BUTTONMASK|PointerMotionMask) +-#define WIDTH(X) ((X)->w + 2 * (X)->bw) +-#define HEIGHT(X) ((X)->h + 2 * (X)->bw) ++#define WIDTH(X) ((X)->w + 2 * (X)->bw + gappx) ++#define HEIGHT(X) ((X)->h + 2 * (X)->bw + gappx) + #define TAGMASK ((1 << LENGTH(tags)) - 1) + #define TEXTW(X) (drw_fontset_getwidth(drw, (X)) + lrpad) + +@@ -1276,13 +1276,37 @@ void + resizeclient(Client *c, int x, int y, int w, int h) + { + XWindowChanges wc; ++ unsigned int n; ++ unsigned int gapoffset; ++ unsigned int gapincr; ++ Client *nbc; + +- c->oldx = c->x; c->x = wc.x = x; +- c->oldy = c->y; c->y = wc.y = y; +- c->oldw = c->w; c->w = wc.width = w; +- c->oldh = c->h; c->h = wc.height = h; + wc.border_width = c->bw; ++ ++ /* Get number of clients for the selected monitor */ ++ for (n = 0, nbc = nexttiled(selmon->clients); nbc; nbc = nexttiled(nbc->next), n++); ++ ++ /* Do nothing if layout is floating */ ++ if (c->isfloating || selmon->lt[selmon->sellt]->arrange == NULL) { ++ gapincr = gapoffset = 0; ++ } else { ++ /* Remove border and gap if layout is monocle or only one client */ ++ if (selmon->lt[selmon->sellt]->arrange == monocle || n == 1) { ++ gapoffset = 0; ++ gapincr = -2 * borderpx; ++ wc.border_width = 0; ++ } else { ++ gapoffset = gappx; ++ gapincr = 2 * gappx; ++ } ++ } ++ ++ c->oldx = c->x; c->x = wc.x = x + gapoffset; ++ c->oldy = c->y; c->y = wc.y = y + gapoffset; ++ c->oldw = c->w; c->w = wc.width = w - gapincr; ++ c->oldh = c->h; c->h = wc.height = h - gapincr; ++ + XConfigureWindow(dpy, c->win, CWX|CWY|CWWidth|CWHeight|CWBorderWidth, &wc); + configure(c); + XSync(dpy, False); + +2.22.0 + diff --git a/suckless/dwm/shiftview.c b/suckless/dwm/shiftview.c new file mode 100644 index 00000000..e82053a4 --- /dev/null +++ b/suckless/dwm/shiftview.c @@ -0,0 +1,19 @@ +/** Function to shift the current view to the left/right + * + * @param: "arg->i" stores the number of tags to shift right (positive value) + * or left (negative value) + */ +void +shiftview(const Arg *arg) { + Arg shifted; + + if(arg->i > 0) // left circular shift + shifted.ui = (selmon->tagset[selmon->seltags] << arg->i) + | (selmon->tagset[selmon->seltags] >> (LENGTH(tags) - arg->i)); + + else // right circular shift + shifted.ui = selmon->tagset[selmon->seltags] >> (- arg->i) + | selmon->tagset[selmon->seltags] << (LENGTH(tags) + arg->i); + + view(&shifted); +} diff --git a/suckless/dwm/transient.c b/suckless/dwm/transient.c new file mode 100644 index 00000000..040adb5b --- /dev/null +++ b/suckless/dwm/transient.c @@ -0,0 +1,42 @@ +/* cc transient.c -o transient -lX11 */ + +#include +#include +#include +#include + +int main(void) { + Display *d; + Window r, f, t = None; + XSizeHints h; + XEvent e; + + d = XOpenDisplay(NULL); + if (!d) + exit(1); + r = DefaultRootWindow(d); + + f = XCreateSimpleWindow(d, r, 100, 100, 400, 400, 0, 0, 0); + h.min_width = h.max_width = h.min_height = h.max_height = 400; + h.flags = PMinSize | PMaxSize; + XSetWMNormalHints(d, f, &h); + XStoreName(d, f, "floating"); + XMapWindow(d, f); + + XSelectInput(d, f, ExposureMask); + while (1) { + XNextEvent(d, &e); + + if (t == None) { + sleep(5); + t = XCreateSimpleWindow(d, r, 50, 50, 100, 100, 0, 0, 0); + XSetTransientForHint(d, t, f); + XStoreName(d, t, "transient"); + XMapWindow(d, t); + XSelectInput(d, t, ExposureMask); + } + } + + XCloseDisplay(d); + exit(0); +} diff --git a/suckless/dwm/util.c b/suckless/dwm/util.c new file mode 100644 index 00000000..fe044fc7 --- /dev/null +++ b/suckless/dwm/util.c @@ -0,0 +1,35 @@ +/* See LICENSE file for copyright and license details. */ +#include +#include +#include +#include + +#include "util.h" + +void * +ecalloc(size_t nmemb, size_t size) +{ + void *p; + + if (!(p = calloc(nmemb, size))) + die("calloc:"); + return p; +} + +void +die(const char *fmt, ...) { + va_list ap; + + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); + + if (fmt[0] && fmt[strlen(fmt)-1] == ':') { + fputc(' ', stderr); + perror(NULL); + } else { + fputc('\n', stderr); + } + + exit(1); +} diff --git a/suckless/dwm/util.h b/suckless/dwm/util.h new file mode 100644 index 00000000..f633b517 --- /dev/null +++ b/suckless/dwm/util.h @@ -0,0 +1,8 @@ +/* See LICENSE file for copyright and license details. */ + +#define MAX(A, B) ((A) > (B) ? (A) : (B)) +#define MIN(A, B) ((A) < (B) ? (A) : (B)) +#define BETWEEN(X, A, B) ((A) <= (X) && (X) <= (B)) + +void die(const char *fmt, ...); +void *ecalloc(size_t nmemb, size_t size); diff --git a/suckless/dwmblocks/.gitignore b/suckless/dwmblocks/.gitignore new file mode 100644 index 00000000..2f27b1b4 --- /dev/null +++ b/suckless/dwmblocks/.gitignore @@ -0,0 +1,3 @@ +dwmblocks +sigdwmblocks +xgetrootname diff --git a/suckless/dwmblocks/GNUmakefile b/suckless/dwmblocks/GNUmakefile new file mode 100644 index 00000000..74c7cd0c --- /dev/null +++ b/suckless/dwmblocks/GNUmakefile @@ -0,0 +1,32 @@ +#PREFIX := /usr/local +PREFIX := ${HOME}/.local + +CC := gcc +CFLAGS := -O3 -Wall -Wextra +CFLAGSEXTRA := -Wno-missing-field-initializers -Wno-unused-parameter + +X11CFLAGS := $(shell pkg-config --cflags x11) +X11LIBS := $(shell pkg-config --libs x11) + +all: dwmblocks sigdwmblocks + +dwmblocks: dwmblocks.c blocks.h + ${CC} -o $@ ${CFLAGS} ${CFLAGSEXTRA} ${X11CFLAGS} $< ${X11LIBS} + +sigdwmblocks: sigdwmblocks.c + ${CC} -o $@ ${CFLAGS} $< + +xgetrootname: xgetrootname.c + ${CC} -o $@ ${CFLAGS} ${X11CFLAGS} $< ${X11LIBS} + +clean: + rm -f dwmblocks sigdwmblocks + +install: all + install -m 0755 dwmblocks ${DESTDIR}${PREFIX}/dwmblocks + install -m 0755 sigdwmblocks ${DESTDIR}${PREFIX}/sigdwmblocks + +uninstall: + rm -f ${DESTDIR}${PREFIX}/bin/dwmblocks ${DESTDIR}${PREFIX}/sigdwmblocks + +.PHONY: all clean install uninstall diff --git a/suckless/dwmblocks/LICENSE b/suckless/dwmblocks/LICENSE new file mode 100644 index 00000000..ac54ae5b --- /dev/null +++ b/suckless/dwmblocks/LICENSE @@ -0,0 +1,7 @@ +ISC License (ISC) + +Copyright 2020 Ashish Kumar Yadav + +Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. diff --git a/suckless/dwmblocks/README.md b/suckless/dwmblocks/README.md new file mode 100644 index 00000000..0999105e --- /dev/null +++ b/suckless/dwmblocks/README.md @@ -0,0 +1,66 @@ +# dwmblocks + +Modular status monitor for dwm written in C with features including +signaling, clickability, cursor hinting and color. + +# Usage + +`dwmblocks [-d ]` + +# Modifying blocks + +Blocks are added and removed by editing the [blocks.h](blocks.h) file. Read it +for more info. + +# Colored output and Clickability + +The patches folder contains two patches for dwm, one for dwm already patched +with systray patch and the other for dwm without systray. One of the patches, +whichever appropriate, is essential for dwmblocks to function properly. It will +add support for colored text, clickability and cursor hinting when hovering on +clickable blocks (inspired by polybar). + +Clickability is inspired by the statuscmd patch for dwm. On clicking on text +corresponding to a clickable block, the program specified to handle clicks for +that block is executed with the first argument specifying which button was +clicked (1 for left, 2 for middle and 3 for right by default). + +Colored output is inspired by the statuscolors patch for dwm. To add colors, +have your programs for the blocks output raw characters from '\x0b' to '\x31'. +'\x0b' in status text switches the active colorscheme to the first one in the +scheme array in dwm and so on. See +[statuscolors patch](https://dwm.suckless.org/patches/statuscolors/) +for more info. Keep in mind that you have to start from '\x0b' instead of '\x01' +as instructed on the page. + +# Signaling changes + +To signal a specific block to update, run `sigdwmblocks []`. +`` is optional and must be an integer. If provided, it is passed as the +first argument to the program specified for updating the block. + +# xgetrootname + +It is a tiny program to get the current root name. May prove helpful in +debugging. + +# Installation + +Clone the repository and run `make install clean` after getting in the project +directory. By default the program is installed in `$HOME/.local/bin` +(see [GNUmakefile](GNUmakefile)). If xgetrootname is required run +`make xgetrootname`. + +# Acknowledgements + +Some ideas and code was taken from other projects. Credits for those go to - + +* torrinfail ([original dwmblocks implementation](https://github.com/torrinfail/dwmblocks)) +* Daniel Bylinka ([statuscmd patch for dwm](https://dwm.suckless.org/patches/statuscmd/)) +* Jeremy Jay ([statuscolors patch for dwm](https://dwm.suckless.org/patches/statuscolors/)) + +# See also + +* [dsblocks](https://github.com/ashish-yadav11/dsblocks) - A clone of this + project with the only difference being that C functions instead of external + programs are used to update blocks and handle clicks. diff --git a/suckless/dwmblocks/blocks.h b/suckless/dwmblocks/blocks.h new file mode 100644 index 00000000..525dc069 --- /dev/null +++ b/suckless/dwmblocks/blocks.h @@ -0,0 +1,33 @@ +/* time interval in seconds to sleep before looking for updates in the main loop */ +#define SLEEPINTERVAL 1 + +#define PATH(name) "/home/yigit/.scripts/status-bar/"name + +/* If interval of a block is set to 0, the block will only be updated once at startup. + * If interval is set to a negative value, the block will never be updated in the main loop. + * Set signal to 0 if signalling is not required for the block. + * Signal must be less than 10 for clickable blocks. + * If multiple realtime signals are pending, then the lowest numbered signal is delivered first. */ + +/* pathu - path of the program whose output is to be used for status text + * pathc - path of the program to be executed on clicks */ +static Block blocks[] = { + + { PATH("spotify-bar"), NULL, 5, 6}, + + { PATH("fecha"), NULL, 60, 3}, + + { PATH("arch"), NULL, 3600, 1}, + + { PATH("volume"), NULL, 0, 4}, + + { PATH("cpu-temp"), NULL, 15, 7}, + + { PATH("battery"), NULL, 120, 2}, + + { PATH("red"), NULL, 30, 5}, + + { NULL } /* just to mark the end of the array */ +}; + +static const char *delim = " "; diff --git a/suckless/dwmblocks/dwmblocks.c b/suckless/dwmblocks/dwmblocks.c new file mode 100644 index 00000000..2b753838 --- /dev/null +++ b/suckless/dwmblocks/dwmblocks.c @@ -0,0 +1,357 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define CMDLENGTH 150 +#define STTLENGTH 256 +#define NILL INT_MIN +#define LOCKFILE "/tmp/dwmblocks.pid" + +typedef struct { + char *pathu; + char *pathc; + const int interval; + const int signal; + char cmdoutcur[CMDLENGTH]; + char cmdoutprv[CMDLENGTH]; +} Block; + +#include "blocks.h" + +static void buttonhandler(int signal, siginfo_t *si, void *ucontext); +static void getcmd(Block *block, int sigval); +static void setroot(); +static void setupsignals(); +static void sighandler(int signal, siginfo_t *si, void *ucontext); +static void statusloop(); +static void termhandler(int signum); +static int updatestatus(); +static void writepid(); + +static int statuscontinue = 1; +static char statusstr[STTLENGTH]; +static size_t delimlength; +static Display *dpy; +static sigset_t blocksigmask; + +void +buttonhandler(int signal, siginfo_t *si, void *ucontext) +{ + signal = si->si_value.sival_int >> 8; + switch (fork()) { + case -1: + perror("buttonhandler - fork"); + exit(1); + case 0: + close(ConnectionNumber(dpy)); + for (Block *current = blocks; current->pathu; current++) { + if (current->signal == signal) { + char button[] = { '0' + (si->si_value.sival_int & 0xff), '\0' }; + char *arg[] = { current->pathc, button, NULL }; + + setsid(); + execv(arg[0], arg); + perror("buttonhandler - child - execv"); + _exit(127); + } + } + exit(0); + } +} + +void +getcmd(Block *block, int sigval) +{ + int fd[2]; + + if (pipe(fd) == -1) { + perror("getcmd - pipe"); + exit(1); + } + switch (fork()) { + case -1: + perror("getcmd - fork"); + exit(1); + case 0: + close(ConnectionNumber(dpy)); + close(fd[0]); + if (fd[1] != STDOUT_FILENO) { + if (dup2(fd[1], STDOUT_FILENO) != STDOUT_FILENO) { + perror("getcmd - child - dup2"); + exit(1); + } + close(fd[1]); + } + if (sigval == NILL) { + char *arg[] = { block->pathu, NULL }; + + execv(arg[0], arg); + } else { + char buf[12]; + char *arg[] = { block->pathu, buf, NULL }; + + snprintf(buf, sizeof buf, "%d", sigval); + execv(arg[0], arg); + } + perror("getcmd - child - execv"); + _exit(127); + default: + close(fd[1]); + if (read(fd[0], block->cmdoutcur, CMDLENGTH) == -1) { + perror("getcmd - read"); + exit(1); + } + close(fd[0]); + } +} + +void +setroot() +{ + if (updatestatus()) { + XStoreName(dpy, DefaultRootWindow(dpy), statusstr); + XSync(dpy, False); + } +} + +void +setupsignals() +{ + struct sigaction sa; + + /* to handle HUP, INT and TERM */ + sa.sa_flags = SA_RESTART; + sigemptyset(&sa.sa_mask); + sa.sa_handler = termhandler; + sigaction(SIGHUP, &sa, NULL); + sigaction(SIGINT, &sa, NULL); + sigaction(SIGTERM, &sa, NULL); + + /* to ignore unused realtime signals */ + // sa.sa_flags = SA_RESTART; + // sigemptyset(&sa.sa_mask); + sa.sa_handler = SIG_IGN; + for (int i = SIGRTMIN + 1; i <= SIGRTMAX; i++) + sigaction(i, &sa, NULL); + + /* to prevent forked children from becoming zombies */ + sa.sa_flags = SA_NOCLDSTOP | SA_NOCLDWAIT | SA_RESTART; + // sigemptyset(&sa.sa_mask); + sa.sa_handler = SIG_DFL; + sigaction(SIGCHLD, &sa, NULL); + + /* to handle signals generated by dwm on click events */ + sa.sa_flags = SA_RESTART | SA_SIGINFO; + // sigemptyset(&sa.sa_mask); + sa.sa_sigaction = buttonhandler; + sigaction(SIGRTMIN, &sa, NULL); + + /* to handle update signals for individual blocks */ + sa.sa_flags |= SA_NODEFER; + sa.sa_mask = blocksigmask; + sa.sa_sigaction = sighandler; + for (Block *current = blocks; current->pathu; current++) + if (current->signal > 0) + sigaction(SIGRTMIN + current->signal, &sa, NULL); +} + +void +sighandler(int signal, siginfo_t *si, void *ucontext) +{ + signal -= SIGRTMIN; + for (Block *current = blocks; current->pathu; current++) + if (current->signal == signal) + getcmd(current, si->si_value.sival_int); + setroot(); +} + +void +statusloop() +{ + int i; + + /* first run */ + sigprocmask(SIG_BLOCK, &blocksigmask, NULL); + for (Block *current = blocks; current->pathu; current++) + if (current->interval >= 0) + getcmd(current, NILL); + setroot(); + sigprocmask(SIG_UNBLOCK, &blocksigmask, NULL); + sleep(SLEEPINTERVAL); + i = SLEEPINTERVAL; + /* main loop */ + while (statuscontinue) { + sigprocmask(SIG_BLOCK, &blocksigmask, NULL); + for (Block *current = blocks; current->pathu; current++) + if (current->interval > 0 && i % current->interval == 0) + getcmd(current, NILL); + setroot(); + sigprocmask(SIG_UNBLOCK, &blocksigmask, NULL); + sleep(SLEEPINTERVAL); + i += SLEEPINTERVAL; + } +} + +void +termhandler(int signum) +{ + statuscontinue = 0; +} + +/* returns whether block outputs have changed and updates statusstr if they have */ +int +updatestatus() +{ + char *s = statusstr; + char *c, *p; /* for cmdoutcur and cmdoutprv */ + const char *d; /* for delimiter */ + Block *current = blocks; + + /* checking half of the function */ + /* find the first non-empty block */ + for (;; current++) { + /* all blocks are empty */ + if (!current->pathu) + return 0; + /* contents of the current block just changed */ + if (*current->cmdoutcur != *current->cmdoutprv) + goto update0; + /* no delimiter before the first non-empty block */ + if (*current->cmdoutcur != '\n' && *current->cmdoutcur != '\0') + goto skipdelimc; + } + /* main loop */ + for (; current->pathu; current++) { + /* contents of the current block just changed */ + if (*current->cmdoutcur != *current->cmdoutprv) + goto update1; + /* delimiter handler */ + /* current block is non-empty */ + if (*current->cmdoutcur != '\n' && *current->cmdoutcur != '\0') + s += delimlength; + /* skip over empty blocks */ + else + continue; +skipdelimc: + /* checking for the first byte has been done */ + c = current->cmdoutcur + 1, p = current->cmdoutprv + 1; + for (; *c != '\n' && *c != '\0'; c++, p++) + /* contents of the current block just changed */ + if (*c != *p) { + s += c - current->cmdoutcur; + goto update2; + } + s += c - current->cmdoutcur; + /* byte containing info about signal number for the block */ + if (current->pathc && current->signal) + s++; + } + return 0; + + /* updating half of the function */ + /* find the first non-empty block */ + for (;; current++) { + /* all blocks are empty */ + if (!current->pathu) + return 1; +update0: + /* skip delimiter before the first non-empty block */ + if (*current->cmdoutcur != '\n' && *current->cmdoutcur != '\0') + goto skipdelimu; + *current->cmdoutprv = *current->cmdoutcur; + } + /* main loop */ + for (; current->pathu; current++) { +update1: + /* delimiter handler */ + /* current block is non-empty */ + if (*current->cmdoutcur != '\n' && *current->cmdoutcur != '\0') { + d = delim; + while (*d != '\0') + *(s++) = *(d++); + *(s++) = '\n'; /* to mark the end of delimiter */ + /* skip over empty blocks */ + } else { + *current->cmdoutprv = *current->cmdoutcur; + continue; + } +skipdelimu: + c = current->cmdoutcur, p = current->cmdoutprv; +update2: + do { + *(s++) = *c; + *p = *c; + c++, p++; + } while (*c != '\n' && *c != '\0'); + if (current->pathc && current->signal) + *(s++) = current->signal; + } + *s = '\0'; + return 1; +} + +void +writepid() +{ + int fd; + struct flock fl; + + fd = open(LOCKFILE, O_RDWR|O_CREAT, 0644); + if (fd == -1) { + perror("writepid - fd"); + exit(1); + } + fl.l_type = F_WRLCK; + fl.l_start = 0; + fl.l_whence = SEEK_SET; + fl.l_len = 0; + if (fcntl(fd, F_SETLK, &fl) == -1) { + if (errno == EACCES || errno == EAGAIN) { + fputs("Error: another instance of dwmblocks is already running.\n", stderr); + exit(2); + } + perror("writepid - fcntl"); + exit(1); + } + if (ftruncate(fd, 0) == -1) { + perror("writepid - ftruncate"); + exit(1); + } + if (dprintf(fd, "%ld", (long)getpid()) < 0) { + perror("writepid - dprintf"); + exit(1); + } +} + +int +main(int argc, char *argv[]) +{ + writepid(); + if (argc > 2) + if (strcmp(argv[1], "-d") == 0) + delim = argv[2]; + delimlength = strlen(delim) + 1; + if (!(dpy = XOpenDisplay(NULL))) { + fputs("Error: could not open display.\n", stderr); + return 1; + } + sigemptyset(&blocksigmask); + sigaddset(&blocksigmask, SIGHUP); + sigaddset(&blocksigmask, SIGINT); + sigaddset(&blocksigmask, SIGTERM); + for (Block *current = blocks; current->pathu; current++) + if (current->signal > 0) + sigaddset(&blocksigmask, SIGRTMIN + current->signal); + setupsignals(); + statusloop(); + unlink(LOCKFILE); + XStoreName(dpy, DefaultRootWindow(dpy), ""); + XCloseDisplay(dpy); + return 0; +} diff --git a/suckless/dwmblocks/sigdwmblocks.c b/suckless/dwmblocks/sigdwmblocks.c new file mode 100644 index 00000000..5d5fb80e --- /dev/null +++ b/suckless/dwmblocks/sigdwmblocks.c @@ -0,0 +1,76 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#define LOCKFILE "/tmp/dwmblocks.pid" + +void +sendsignal(int signum, union sigval sv) +{ + int fd; + struct flock fl; + + fd = open(LOCKFILE, O_RDONLY); + if (fd == -1) { + if (errno == ENOENT) { + fputs("Error: no running instance of dwmblocks.\n", stderr); + exit(2); + } + perror("sendsignal - fd"); + exit(1); + } + fl.l_type = F_WRLCK; + fl.l_start = 0; + fl.l_whence = SEEK_SET; + fl.l_len = 0; + if (fcntl(fd, F_GETLK, &fl) == -1) { + perror("sendsignal - fcntl"); + exit(1); + } + if (fl.l_type == F_UNLCK) { + fputs("Error: no running instance of dwmblocks.\n", stderr); + exit(2); + } + if (sigqueue(fl.l_pid, signum, sv) == -1) { + if (errno == EINVAL) { + fputs("Error: invalid signal provided in argument.\n", stderr); + exit(3); + } else if (errno == ESRCH) { + fputs("Error: no running instance of dwmblocks.\n", stderr); + exit(2); + } else { + perror("sendsignal - sigqueue"); + exit(1); + } + } +} + +int +main(int argc, char *argv[]) +{ + if (argc > 1) { + int signal; + union sigval sv; + + if (sscanf(argv[1], "%d", &signal) == 1 && + signal > 0 && (signal += SIGRTMIN) <= SIGRTMAX) { + if (argc == 2) { + sv.sival_int = INT_MIN; + sendsignal(signal, sv); + return 0; + } else if (argc == 3 && + sscanf(argv[2], "%d", &(sv.sival_int)) == 1) { + sendsignal(signal, sv); + return 0; + } + } + } + + fprintf(stderr, "Usage: %s []\n", argv[0]); + return 3; +} diff --git a/suckless/dwmblocks/xgetrootname.c b/suckless/dwmblocks/xgetrootname.c new file mode 100644 index 00000000..e04154c0 --- /dev/null +++ b/suckless/dwmblocks/xgetrootname.c @@ -0,0 +1,21 @@ +#include +#include + +int +main() +{ + Display *dpy; + char *name; + + if (!(dpy = XOpenDisplay(NULL))) { + fputs("Error: could not open display.\n", stderr); + return 1; + } + if (XFetchName(dpy, DefaultRootWindow(dpy), &name) && name[0]) + printf("%s\n", name); + else + puts("No name has been set for the root window."); + XFree(name); + XCloseDisplay(dpy); + return 0; +} diff --git a/tmux/tmux.conf b/tmux/tmux.conf new file mode 100644 index 00000000..8a84d285 --- /dev/null +++ b/tmux/tmux.conf @@ -0,0 +1,117 @@ +# Bind escape to copy mode +unbind [ +bind Escape copy-mode + +# p = paste +unbind p +bind p paste-buffer + +# no escape delay +set -sg escape-time 0 + +# remap prefix to Control + a +set -g prefix C-a +unbind C-b +bind C-a send-prefix + +# Start window numbering at 1 (default => 0) +set -g base-index 1 + +set -g clock-mode-style 12 + +# Renumber windows after removing one +set -g renumber-windows on + +# use 256 colors +# set -g default-terminal 'tmux-256color-italic' +set-option -ga terminal-overrides ",xterm-256color-italic:Tc" +# set -g default-terminal "tmux-256color-italic" + + +# change tmux bar colors +set -g status-bg '#B388FF' +set -g status-fg '#EEEEEE' + +# Keep plenty of history for scrollback +set -g history-limit 50000 + +# mouse +set -g mouse on + + +# Act like vim in copy mode +set -g status-keys vi +setw -g mode-keys vi +bind-key -Tcopy-mode-vi 'v' send -X begin-selection + +# Smart pane switching with awareness of Vim splits. +# See: https://github.com/christoomey/vim-tmux-navigator +is_vim="ps -o state= -o comm= -t '#{pane_tty}' \ + | grep -iqE '^[^TXZ ]+ +(\\S+\\/)?g?(view|n?vim?x?)(diff)?$'" +bind-key -n C-h if-shell "$is_vim" "send-keys C-h" "select-pane -L" +bind-key -n C-j if-shell "$is_vim" "send-keys C-j" "select-pane -D" +bind-key -n C-k if-shell "$is_vim" "send-keys C-k" "select-pane -U" +bind-key -n C-l if-shell "$is_vim" "send-keys C-l" "select-pane -R" +bind-key -n C-\\ if-shell "$is_vim" "send-keys C-\\" "select-pane -l" + +# Secondary binding for C-l to retain redraw +bind C-l send-keys 'C-l' + +# Easy rotating of panes +bind C-k swap-pane -U + +# increase display time +set -g display-panes-time 1200 + +# status bar stuff +set -g status-left-length 40 + +# Simplify status bar display. +set -g status-left '[#S]' +set -g status-right "%I:%M %p " +# set -g status-right "#[fg=red][44%%]#[default] - %I:%M %p " + +# Dismiss current pane to background window +bind b break-pane -d +bind-key j command-prompt -p "join pane from: " "join-pane -h -s '%%'" + +# more intuitive keybindings for splitting +bind \\ split-window -h -c "#{pane_current_path}" +bind - split-window -v -c "#{pane_current_path}" + +# Easy return to Vim from tmux runner zoom runner pane +bind C-p run "(tmux display-message -p '#{pane_current_command}' | grep -iqE '(^|\/)vim$' && tmux send-keys ':VtrZoomRunnerPane' 'C-m') || tmux send-keys 'C-c' && tmux select-pane -l" + +# Make C-j display a selectable list of sessions +bind C-j choose-tree + +# Keep window names as I set them +setw -g automatic-rename off + +# Reload tmux.conf with prefix-r +bind C-r source-file ~/.tmux.conf \; display "Reloaded ~/.tmux.conf" + +# Provide access to the clipboard for pbpaste, pbcopy (details: http://goo.gl/DN82E) +set-window-option -g automatic-rename on + +# Enable VI mode +set-window-option -g mode-keys vi + +# Set ability to capture on start and restore on exit window data when running an application +setw -g alternate-screen on + +# bind resizing of panes to H,J,K,L (resizes by steps of 10 lines/columns) +# # Note, bindings are repeatable (within the default 500ms time limit) so that +# # you don't have to keep entering the prefix. (Prefix-H-H-H resizes by 15) +bind -n S-Left resize-pane -L 2 +bind -n S-Right resize-pane -R 2 +bind -n S-Down resize-pane -D 1 +bind -n S-Up resize-pane -U 1 +unbind -n C-Left +unbind -n C-Down +unbind -n C-Up +unbind -n C-Right +bind -n C-Left resize-pane -L 10 +bind -n C-Right resize-pane -R 10 +bind -n C-Down resize-pane -D 5 +bind -n C-Up resize-pane -U 5 diff --git a/vim/vim/.gitignore b/vim/vim/.gitignore new file mode 100644 index 00000000..4f7b616b --- /dev/null +++ b/vim/vim/.gitignore @@ -0,0 +1,3 @@ +# Folder Created By vim-plug +plugged +after diff --git a/vim/vim/autoload/plug.vim b/vim/vim/autoload/plug.vim new file mode 100644 index 00000000..2b89b5a6 --- /dev/null +++ b/vim/vim/autoload/plug.vim @@ -0,0 +1,2797 @@ +" vim-plug: Vim plugin manager +" ============================ +" +" Download plug.vim and put it in ~/.vim/autoload +" +" curl -fLo ~/.vim/autoload/plug.vim --create-dirs \ +" https://raw.githubusercontent.com/junegunn/vim-plug/master/plug.vim +" +" Edit your .vimrc +" +" call plug#begin('~/.vim/plugged') +" +" " Make sure you use single quotes +" +" " Shorthand notation; fetches https://github.com/junegunn/vim-easy-align +" Plug 'junegunn/vim-easy-align' +" +" " Any valid git URL is allowed +" Plug 'https://github.com/junegunn/vim-github-dashboard.git' +" +" " Multiple Plug commands can be written in a single line using | separators +" Plug 'SirVer/ultisnips' | Plug 'honza/vim-snippets' +" +" " On-demand loading +" Plug 'scrooloose/nerdtree', { 'on': 'NERDTreeToggle' } +" Plug 'tpope/vim-fireplace', { 'for': 'clojure' } +" +" " Using a non-default branch +" Plug 'rdnetto/YCM-Generator', { 'branch': 'stable' } +" +" " Using a tagged release; wildcard allowed (requires git 1.9.2 or above) +" Plug 'fatih/vim-go', { 'tag': '*' } +" +" " Plugin options +" Plug 'nsf/gocode', { 'tag': 'v.20150303', 'rtp': 'vim' } +" +" " Plugin outside ~/.vim/plugged with post-update hook +" Plug 'junegunn/fzf', { 'dir': '~/.fzf', 'do': './install --all' } +" +" " Unmanaged plugin (manually installed and updated) +" Plug '~/my-prototype-plugin' +" +" " Initialize plugin system +" call plug#end() +" +" Then reload .vimrc and :PlugInstall to install plugins. +" +" Plug options: +" +"| Option | Description | +"| ----------------------- | ------------------------------------------------ | +"| `branch`/`tag`/`commit` | Branch/tag/commit of the repository to use | +"| `rtp` | Subdirectory that contains Vim plugin | +"| `dir` | Custom directory for the plugin | +"| `as` | Use different name for the plugin | +"| `do` | Post-update hook (string or funcref) | +"| `on` | On-demand loading: Commands or ``-mappings | +"| `for` | On-demand loading: File types | +"| `frozen` | Do not update unless explicitly specified | +" +" More information: https://github.com/junegunn/vim-plug +" +" +" Copyright (c) 2017 Junegunn Choi +" +" MIT License +" +" Permission is hereby granted, free of charge, to any person obtaining +" a copy of this software and associated documentation files (the +" "Software"), to deal in the Software without restriction, including +" without limitation the rights to use, copy, modify, merge, publish, +" distribute, sublicense, and/or sell copies of the Software, and to +" permit persons to whom the Software is furnished to do so, subject to +" the following conditions: +" +" The above copyright notice and this permission notice shall be +" included in all copies or substantial portions of the Software. +" +" THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +" EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +" MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +" NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +" LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +" OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +" WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +if exists('g:loaded_plug') + finish +endif +let g:loaded_plug = 1 + +let s:cpo_save = &cpo +set cpo&vim + +let s:plug_src = 'https://github.com/junegunn/vim-plug.git' +let s:plug_tab = get(s:, 'plug_tab', -1) +let s:plug_buf = get(s:, 'plug_buf', -1) +let s:mac_gui = has('gui_macvim') && has('gui_running') +let s:is_win = has('win32') +let s:nvim = has('nvim-0.2') || (has('nvim') && exists('*jobwait') && !s:is_win) +let s:vim8 = has('patch-8.0.0039') && exists('*job_start') +if s:is_win && &shellslash + set noshellslash + let s:me = resolve(expand(':p')) + set shellslash +else + let s:me = resolve(expand(':p')) +endif +let s:base_spec = { 'branch': '', 'frozen': 0 } +let s:TYPE = { +\ 'string': type(''), +\ 'list': type([]), +\ 'dict': type({}), +\ 'funcref': type(function('call')) +\ } +let s:loaded = get(s:, 'loaded', {}) +let s:triggers = get(s:, 'triggers', {}) + +function! s:isabsolute(dir) abort + return a:dir =~# '^/' || (has('win32') && a:dir =~? '^\%(\\\|[A-Z]:\)') +endfunction + +function! s:git_dir(dir) abort + let gitdir = s:trim(a:dir) . '/.git' + if isdirectory(gitdir) + return gitdir + endif + if !filereadable(gitdir) + return '' + endif + let gitdir = matchstr(get(readfile(gitdir), 0, ''), '^gitdir: \zs.*') + if len(gitdir) && !s:isabsolute(gitdir) + let gitdir = a:dir . '/' . gitdir + endif + return isdirectory(gitdir) ? gitdir : '' +endfunction + +function! s:git_origin_url(dir) abort + let gitdir = s:git_dir(a:dir) + let config = gitdir . '/config' + if empty(gitdir) || !filereadable(config) + return '' + endif + return matchstr(join(readfile(config)), '\[remote "origin"\].\{-}url\s*=\s*\zs\S*\ze') +endfunction + +function! s:git_revision(dir) abort + let gitdir = s:git_dir(a:dir) + let head = gitdir . '/HEAD' + if empty(gitdir) || !filereadable(head) + return '' + endif + + let line = get(readfile(head), 0, '') + let ref = matchstr(line, '^ref: \zs.*') + if empty(ref) + return line + endif + + if filereadable(gitdir . '/' . ref) + return get(readfile(gitdir . '/' . ref), 0, '') + endif + + if filereadable(gitdir . '/packed-refs') + for line in readfile(gitdir . '/packed-refs') + if line =~# ' ' . ref + return matchstr(line, '^[0-9a-f]*') + endif + endfor + endif + + return '' +endfunction + +function! s:git_local_branch(dir) abort + let gitdir = s:git_dir(a:dir) + let head = gitdir . '/HEAD' + if empty(gitdir) || !filereadable(head) + return '' + endif + let branch = matchstr(get(readfile(head), 0, ''), '^ref: refs/heads/\zs.*') + return len(branch) ? branch : 'HEAD' +endfunction + +function! s:git_origin_branch(spec) + if len(a:spec.branch) + return a:spec.branch + endif + + " The file may not be present if this is a local repository + let gitdir = s:git_dir(a:spec.dir) + let origin_head = gitdir.'/refs/remotes/origin/HEAD' + if len(gitdir) && filereadable(origin_head) + return matchstr(get(readfile(origin_head), 0, ''), + \ '^ref: refs/remotes/origin/\zs.*') + endif + + " The command may not return the name of a branch in detached HEAD state + let result = s:lines(s:system('git symbolic-ref --short HEAD', a:spec.dir)) + return v:shell_error ? '' : result[-1] +endfunction + +if s:is_win + function! s:plug_call(fn, ...) + let shellslash = &shellslash + try + set noshellslash + return call(a:fn, a:000) + finally + let &shellslash = shellslash + endtry + endfunction +else + function! s:plug_call(fn, ...) + return call(a:fn, a:000) + endfunction +endif + +function! s:plug_getcwd() + return s:plug_call('getcwd') +endfunction + +function! s:plug_fnamemodify(fname, mods) + return s:plug_call('fnamemodify', a:fname, a:mods) +endfunction + +function! s:plug_expand(fmt) + return s:plug_call('expand', a:fmt, 1) +endfunction + +function! s:plug_tempname() + return s:plug_call('tempname') +endfunction + +function! plug#begin(...) + if a:0 > 0 + let s:plug_home_org = a:1 + let home = s:path(s:plug_fnamemodify(s:plug_expand(a:1), ':p')) + elseif exists('g:plug_home') + let home = s:path(g:plug_home) + elseif !empty(&rtp) + let home = s:path(split(&rtp, ',')[0]) . '/plugged' + else + return s:err('Unable to determine plug home. Try calling plug#begin() with a path argument.') + endif + if s:plug_fnamemodify(home, ':t') ==# 'plugin' && s:plug_fnamemodify(home, ':h') ==# s:first_rtp + return s:err('Invalid plug home. '.home.' is a standard Vim runtime path and is not allowed.') + endif + + let g:plug_home = home + let g:plugs = {} + let g:plugs_order = [] + let s:triggers = {} + + call s:define_commands() + return 1 +endfunction + +function! s:define_commands() + command! -nargs=+ -bar Plug call plug#() + if !executable('git') + return s:err('`git` executable not found. Most commands will not be available. To suppress this message, prepend `silent!` to `call plug#begin(...)`.') + endif + if has('win32') + \ && &shellslash + \ && (&shell =~# 'cmd\(\.exe\)\?$' || &shell =~# 'powershell\(\.exe\)\?$') + return s:err('vim-plug does not support shell, ' . &shell . ', when shellslash is set.') + endif + if !has('nvim') + \ && (has('win32') || has('win32unix')) + \ && !has('multi_byte') + return s:err('Vim needs +multi_byte feature on Windows to run shell commands. Enable +iconv for best results.') + endif + command! -nargs=* -bar -bang -complete=customlist,s:names PlugInstall call s:install(0, []) + command! -nargs=* -bar -bang -complete=customlist,s:names PlugUpdate call s:update(0, []) + command! -nargs=0 -bar -bang PlugClean call s:clean(0) + command! -nargs=0 -bar PlugUpgrade if s:upgrade() | execute 'source' s:esc(s:me) | endif + command! -nargs=0 -bar PlugStatus call s:status() + command! -nargs=0 -bar PlugDiff call s:diff() + command! -nargs=? -bar -bang -complete=file PlugSnapshot call s:snapshot(0, ) +endfunction + +function! s:to_a(v) + return type(a:v) == s:TYPE.list ? a:v : [a:v] +endfunction + +function! s:to_s(v) + return type(a:v) == s:TYPE.string ? a:v : join(a:v, "\n") . "\n" +endfunction + +function! s:glob(from, pattern) + return s:lines(globpath(a:from, a:pattern)) +endfunction + +function! s:source(from, ...) + let found = 0 + for pattern in a:000 + for vim in s:glob(a:from, pattern) + execute 'source' s:esc(vim) + let found = 1 + endfor + endfor + return found +endfunction + +function! s:assoc(dict, key, val) + let a:dict[a:key] = add(get(a:dict, a:key, []), a:val) +endfunction + +function! s:ask(message, ...) + call inputsave() + echohl WarningMsg + let answer = input(a:message.(a:0 ? ' (y/N/a) ' : ' (y/N) ')) + echohl None + call inputrestore() + echo "\r" + return (a:0 && answer =~? '^a') ? 2 : (answer =~? '^y') ? 1 : 0 +endfunction + +function! s:ask_no_interrupt(...) + try + return call('s:ask', a:000) + catch + return 0 + endtry +endfunction + +function! s:lazy(plug, opt) + return has_key(a:plug, a:opt) && + \ (empty(s:to_a(a:plug[a:opt])) || + \ !isdirectory(a:plug.dir) || + \ len(s:glob(s:rtp(a:plug), 'plugin')) || + \ len(s:glob(s:rtp(a:plug), 'after/plugin'))) +endfunction + +function! plug#end() + if !exists('g:plugs') + return s:err('plug#end() called without calling plug#begin() first') + endif + + if exists('#PlugLOD') + augroup PlugLOD + autocmd! + augroup END + augroup! PlugLOD + endif + let lod = { 'ft': {}, 'map': {}, 'cmd': {} } + + if exists('g:did_load_filetypes') + filetype off + endif + for name in g:plugs_order + if !has_key(g:plugs, name) + continue + endif + let plug = g:plugs[name] + if get(s:loaded, name, 0) || !s:lazy(plug, 'on') && !s:lazy(plug, 'for') + let s:loaded[name] = 1 + continue + endif + + if has_key(plug, 'on') + let s:triggers[name] = { 'map': [], 'cmd': [] } + for cmd in s:to_a(plug.on) + if cmd =~? '^.\+' + if empty(mapcheck(cmd)) && empty(mapcheck(cmd, 'i')) + call s:assoc(lod.map, cmd, name) + endif + call add(s:triggers[name].map, cmd) + elseif cmd =~# '^[A-Z]' + let cmd = substitute(cmd, '!*$', '', '') + if exists(':'.cmd) != 2 + call s:assoc(lod.cmd, cmd, name) + endif + call add(s:triggers[name].cmd, cmd) + else + call s:err('Invalid `on` option: '.cmd. + \ '. Should start with an uppercase letter or ``.') + endif + endfor + endif + + if has_key(plug, 'for') + let types = s:to_a(plug.for) + if !empty(types) + augroup filetypedetect + call s:source(s:rtp(plug), 'ftdetect/**/*.vim', 'after/ftdetect/**/*.vim') + augroup END + endif + for type in types + call s:assoc(lod.ft, type, name) + endfor + endif + endfor + + for [cmd, names] in items(lod.cmd) + execute printf( + \ 'command! -nargs=* -range -bang -complete=file %s call s:lod_cmd(%s, "", , , , %s)', + \ cmd, string(cmd), string(names)) + endfor + + for [map, names] in items(lod.map) + for [mode, map_prefix, key_prefix] in + \ [['i', '', ''], ['n', '', ''], ['v', '', 'gv'], ['o', '', '']] + execute printf( + \ '%snoremap %s %s:call lod_map(%s, %s, %s, "%s")', + \ mode, map, map_prefix, string(map), string(names), mode != 'i', key_prefix) + endfor + endfor + + for [ft, names] in items(lod.ft) + augroup PlugLOD + execute printf('autocmd FileType %s call lod_ft(%s, %s)', + \ ft, string(ft), string(names)) + augroup END + endfor + + call s:reorg_rtp() + filetype plugin indent on + if has('vim_starting') + if has('syntax') && !exists('g:syntax_on') + syntax enable + end + else + call s:reload_plugins() + endif +endfunction + +function! s:loaded_names() + return filter(copy(g:plugs_order), 'get(s:loaded, v:val, 0)') +endfunction + +function! s:load_plugin(spec) + call s:source(s:rtp(a:spec), 'plugin/**/*.vim', 'after/plugin/**/*.vim') +endfunction + +function! s:reload_plugins() + for name in s:loaded_names() + call s:load_plugin(g:plugs[name]) + endfor +endfunction + +function! s:trim(str) + return substitute(a:str, '[\/]\+$', '', '') +endfunction + +function! s:version_requirement(val, min) + for idx in range(0, len(a:min) - 1) + let v = get(a:val, idx, 0) + if v < a:min[idx] | return 0 + elseif v > a:min[idx] | return 1 + endif + endfor + return 1 +endfunction + +function! s:git_version_requirement(...) + if !exists('s:git_version') + let s:git_version = map(split(split(s:system(['git', '--version']))[2], '\.'), 'str2nr(v:val)') + endif + return s:version_requirement(s:git_version, a:000) +endfunction + +function! s:progress_opt(base) + return a:base && !s:is_win && + \ s:git_version_requirement(1, 7, 1) ? '--progress' : '' +endfunction + +function! s:rtp(spec) + return s:path(a:spec.dir . get(a:spec, 'rtp', '')) +endfunction + +if s:is_win + function! s:path(path) + return s:trim(substitute(a:path, '/', '\', 'g')) + endfunction + + function! s:dirpath(path) + return s:path(a:path) . '\' + endfunction + + function! s:is_local_plug(repo) + return a:repo =~? '^[a-z]:\|^[%~]' + endfunction + + " Copied from fzf + function! s:wrap_cmds(cmds) + let cmds = [ + \ '@echo off', + \ 'setlocal enabledelayedexpansion'] + \ + (type(a:cmds) == type([]) ? a:cmds : [a:cmds]) + \ + ['endlocal'] + if has('iconv') + if !exists('s:codepage') + let s:codepage = libcallnr('kernel32.dll', 'GetACP', 0) + endif + return map(cmds, printf('iconv(v:val."\r", "%s", "cp%d")', &encoding, s:codepage)) + endif + return map(cmds, 'v:val."\r"') + endfunction + + function! s:batchfile(cmd) + let batchfile = s:plug_tempname().'.bat' + call writefile(s:wrap_cmds(a:cmd), batchfile) + let cmd = plug#shellescape(batchfile, {'shell': &shell, 'script': 0}) + if &shell =~# 'powershell\(\.exe\)\?$' + let cmd = '& ' . cmd + endif + return [batchfile, cmd] + endfunction +else + function! s:path(path) + return s:trim(a:path) + endfunction + + function! s:dirpath(path) + return substitute(a:path, '[/\\]*$', '/', '') + endfunction + + function! s:is_local_plug(repo) + return a:repo[0] =~ '[/$~]' + endfunction +endif + +function! s:err(msg) + echohl ErrorMsg + echom '[vim-plug] '.a:msg + echohl None +endfunction + +function! s:warn(cmd, msg) + echohl WarningMsg + execute a:cmd 'a:msg' + echohl None +endfunction + +function! s:esc(path) + return escape(a:path, ' ') +endfunction + +function! s:escrtp(path) + return escape(a:path, ' ,') +endfunction + +function! s:remove_rtp() + for name in s:loaded_names() + let rtp = s:rtp(g:plugs[name]) + execute 'set rtp-='.s:escrtp(rtp) + let after = globpath(rtp, 'after') + if isdirectory(after) + execute 'set rtp-='.s:escrtp(after) + endif + endfor +endfunction + +function! s:reorg_rtp() + if !empty(s:first_rtp) + execute 'set rtp-='.s:first_rtp + execute 'set rtp-='.s:last_rtp + endif + + " &rtp is modified from outside + if exists('s:prtp') && s:prtp !=# &rtp + call s:remove_rtp() + unlet! s:middle + endif + + let s:middle = get(s:, 'middle', &rtp) + let rtps = map(s:loaded_names(), 's:rtp(g:plugs[v:val])') + let afters = filter(map(copy(rtps), 'globpath(v:val, "after")'), '!empty(v:val)') + let rtp = join(map(rtps, 'escape(v:val, ",")'), ',') + \ . ','.s:middle.',' + \ . join(map(afters, 'escape(v:val, ",")'), ',') + let &rtp = substitute(substitute(rtp, ',,*', ',', 'g'), '^,\|,$', '', 'g') + let s:prtp = &rtp + + if !empty(s:first_rtp) + execute 'set rtp^='.s:first_rtp + execute 'set rtp+='.s:last_rtp + endif +endfunction + +function! s:doautocmd(...) + if exists('#'.join(a:000, '#')) + execute 'doautocmd' ((v:version > 703 || has('patch442')) ? '' : '') join(a:000) + endif +endfunction + +function! s:dobufread(names) + for name in a:names + let path = s:rtp(g:plugs[name]) + for dir in ['ftdetect', 'ftplugin', 'after/ftdetect', 'after/ftplugin'] + if len(finddir(dir, path)) + if exists('#BufRead') + doautocmd BufRead + endif + return + endif + endfor + endfor +endfunction + +function! plug#load(...) + if a:0 == 0 + return s:err('Argument missing: plugin name(s) required') + endif + if !exists('g:plugs') + return s:err('plug#begin was not called') + endif + let names = a:0 == 1 && type(a:1) == s:TYPE.list ? a:1 : a:000 + let unknowns = filter(copy(names), '!has_key(g:plugs, v:val)') + if !empty(unknowns) + let s = len(unknowns) > 1 ? 's' : '' + return s:err(printf('Unknown plugin%s: %s', s, join(unknowns, ', '))) + end + let unloaded = filter(copy(names), '!get(s:loaded, v:val, 0)') + if !empty(unloaded) + for name in unloaded + call s:lod([name], ['ftdetect', 'after/ftdetect', 'plugin', 'after/plugin']) + endfor + call s:dobufread(unloaded) + return 1 + end + return 0 +endfunction + +function! s:remove_triggers(name) + if !has_key(s:triggers, a:name) + return + endif + for cmd in s:triggers[a:name].cmd + execute 'silent! delc' cmd + endfor + for map in s:triggers[a:name].map + execute 'silent! unmap' map + execute 'silent! iunmap' map + endfor + call remove(s:triggers, a:name) +endfunction + +function! s:lod(names, types, ...) + for name in a:names + call s:remove_triggers(name) + let s:loaded[name] = 1 + endfor + call s:reorg_rtp() + + for name in a:names + let rtp = s:rtp(g:plugs[name]) + for dir in a:types + call s:source(rtp, dir.'/**/*.vim') + endfor + if a:0 + if !s:source(rtp, a:1) && !empty(s:glob(rtp, a:2)) + execute 'runtime' a:1 + endif + call s:source(rtp, a:2) + endif + call s:doautocmd('User', name) + endfor +endfunction + +function! s:lod_ft(pat, names) + let syn = 'syntax/'.a:pat.'.vim' + call s:lod(a:names, ['plugin', 'after/plugin'], syn, 'after/'.syn) + execute 'autocmd! PlugLOD FileType' a:pat + call s:doautocmd('filetypeplugin', 'FileType') + call s:doautocmd('filetypeindent', 'FileType') +endfunction + +function! s:lod_cmd(cmd, bang, l1, l2, args, names) + call s:lod(a:names, ['ftdetect', 'after/ftdetect', 'plugin', 'after/plugin']) + call s:dobufread(a:names) + execute printf('%s%s%s %s', (a:l1 == a:l2 ? '' : (a:l1.','.a:l2)), a:cmd, a:bang, a:args) +endfunction + +function! s:lod_map(map, names, with_prefix, prefix) + call s:lod(a:names, ['ftdetect', 'after/ftdetect', 'plugin', 'after/plugin']) + call s:dobufread(a:names) + let extra = '' + while 1 + let c = getchar(0) + if c == 0 + break + endif + let extra .= nr2char(c) + endwhile + + if a:with_prefix + let prefix = v:count ? v:count : '' + let prefix .= '"'.v:register.a:prefix + if mode(1) == 'no' + if v:operator == 'c' + let prefix = "\" . prefix + endif + let prefix .= v:operator + endif + call feedkeys(prefix, 'n') + endif + call feedkeys(substitute(a:map, '^', "\", '') . extra) +endfunction + +function! plug#(repo, ...) + if a:0 > 1 + return s:err('Invalid number of arguments (1..2)') + endif + + try + let repo = s:trim(a:repo) + let opts = a:0 == 1 ? s:parse_options(a:1) : s:base_spec + let name = get(opts, 'as', s:plug_fnamemodify(repo, ':t:s?\.git$??')) + let spec = extend(s:infer_properties(name, repo), opts) + if !has_key(g:plugs, name) + call add(g:plugs_order, name) + endif + let g:plugs[name] = spec + let s:loaded[name] = get(s:loaded, name, 0) + catch + return s:err(repo . ' ' . v:exception) + endtry +endfunction + +function! s:parse_options(arg) + let opts = copy(s:base_spec) + let type = type(a:arg) + let opt_errfmt = 'Invalid argument for "%s" option of :Plug (expected: %s)' + if type == s:TYPE.string + if empty(a:arg) + throw printf(opt_errfmt, 'tag', 'string') + endif + let opts.tag = a:arg + elseif type == s:TYPE.dict + for opt in ['branch', 'tag', 'commit', 'rtp', 'dir', 'as'] + if has_key(a:arg, opt) + \ && (type(a:arg[opt]) != s:TYPE.string || empty(a:arg[opt])) + throw printf(opt_errfmt, opt, 'string') + endif + endfor + for opt in ['on', 'for'] + if has_key(a:arg, opt) + \ && type(a:arg[opt]) != s:TYPE.list + \ && (type(a:arg[opt]) != s:TYPE.string || empty(a:arg[opt])) + throw printf(opt_errfmt, opt, 'string or list') + endif + endfor + if has_key(a:arg, 'do') + \ && type(a:arg.do) != s:TYPE.funcref + \ && (type(a:arg.do) != s:TYPE.string || empty(a:arg.do)) + throw printf(opt_errfmt, 'do', 'string or funcref') + endif + call extend(opts, a:arg) + if has_key(opts, 'dir') + let opts.dir = s:dirpath(s:plug_expand(opts.dir)) + endif + else + throw 'Invalid argument type (expected: string or dictionary)' + endif + return opts +endfunction + +function! s:infer_properties(name, repo) + let repo = a:repo + if s:is_local_plug(repo) + return { 'dir': s:dirpath(s:plug_expand(repo)) } + else + if repo =~ ':' + let uri = repo + else + if repo !~ '/' + throw printf('Invalid argument: %s (implicit `vim-scripts'' expansion is deprecated)', repo) + endif + let fmt = get(g:, 'plug_url_format', 'https://git::@github.com/%s.git') + let uri = printf(fmt, repo) + endif + return { 'dir': s:dirpath(g:plug_home.'/'.a:name), 'uri': uri } + endif +endfunction + +function! s:install(force, names) + call s:update_impl(0, a:force, a:names) +endfunction + +function! s:update(force, names) + call s:update_impl(1, a:force, a:names) +endfunction + +function! plug#helptags() + if !exists('g:plugs') + return s:err('plug#begin was not called') + endif + for spec in values(g:plugs) + let docd = join([s:rtp(spec), 'doc'], '/') + if isdirectory(docd) + silent! execute 'helptags' s:esc(docd) + endif + endfor + return 1 +endfunction + +function! s:syntax() + syntax clear + syntax region plug1 start=/\%1l/ end=/\%2l/ contains=plugNumber + syntax region plug2 start=/\%2l/ end=/\%3l/ contains=plugBracket,plugX + syn match plugNumber /[0-9]\+[0-9.]*/ contained + syn match plugBracket /[[\]]/ contained + syn match plugX /x/ contained + syn match plugDash /^-\{1}\ / + syn match plugPlus /^+/ + syn match plugStar /^*/ + syn match plugMessage /\(^- \)\@<=.*/ + syn match plugName /\(^- \)\@<=[^ ]*:/ + syn match plugSha /\%(: \)\@<=[0-9a-f]\{4,}$/ + syn match plugTag /(tag: [^)]\+)/ + syn match plugInstall /\(^+ \)\@<=[^:]*/ + syn match plugUpdate /\(^* \)\@<=[^:]*/ + syn match plugCommit /^ \X*[0-9a-f]\{7,9} .*/ contains=plugRelDate,plugEdge,plugTag + syn match plugEdge /^ \X\+$/ + syn match plugEdge /^ \X*/ contained nextgroup=plugSha + syn match plugSha /[0-9a-f]\{7,9}/ contained + syn match plugRelDate /([^)]*)$/ contained + syn match plugNotLoaded /(not loaded)$/ + syn match plugError /^x.*/ + syn region plugDeleted start=/^\~ .*/ end=/^\ze\S/ + syn match plugH2 /^.*:\n-\+$/ + syn match plugH2 /^-\{2,}/ + syn keyword Function PlugInstall PlugStatus PlugUpdate PlugClean + hi def link plug1 Title + hi def link plug2 Repeat + hi def link plugH2 Type + hi def link plugX Exception + hi def link plugBracket Structure + hi def link plugNumber Number + + hi def link plugDash Special + hi def link plugPlus Constant + hi def link plugStar Boolean + + hi def link plugMessage Function + hi def link plugName Label + hi def link plugInstall Function + hi def link plugUpdate Type + + hi def link plugError Error + hi def link plugDeleted Ignore + hi def link plugRelDate Comment + hi def link plugEdge PreProc + hi def link plugSha Identifier + hi def link plugTag Constant + + hi def link plugNotLoaded Comment +endfunction + +function! s:lpad(str, len) + return a:str . repeat(' ', a:len - len(a:str)) +endfunction + +function! s:lines(msg) + return split(a:msg, "[\r\n]") +endfunction + +function! s:lastline(msg) + return get(s:lines(a:msg), -1, '') +endfunction + +function! s:new_window() + execute get(g:, 'plug_window', 'vertical topleft new') +endfunction + +function! s:plug_window_exists() + let buflist = tabpagebuflist(s:plug_tab) + return !empty(buflist) && index(buflist, s:plug_buf) >= 0 +endfunction + +function! s:switch_in() + if !s:plug_window_exists() + return 0 + endif + + if winbufnr(0) != s:plug_buf + let s:pos = [tabpagenr(), winnr(), winsaveview()] + execute 'normal!' s:plug_tab.'gt' + let winnr = bufwinnr(s:plug_buf) + execute winnr.'wincmd w' + call add(s:pos, winsaveview()) + else + let s:pos = [winsaveview()] + endif + + setlocal modifiable + return 1 +endfunction + +function! s:switch_out(...) + call winrestview(s:pos[-1]) + setlocal nomodifiable + if a:0 > 0 + execute a:1 + endif + + if len(s:pos) > 1 + execute 'normal!' s:pos[0].'gt' + execute s:pos[1] 'wincmd w' + call winrestview(s:pos[2]) + endif +endfunction + +function! s:finish_bindings() + nnoremap R :call retry() + nnoremap D :PlugDiff + nnoremap S :PlugStatus + nnoremap U :call status_update() + xnoremap U :call status_update() + nnoremap ]] :silent! call section('') + nnoremap [[ :silent! call section('b') +endfunction + +function! s:prepare(...) + if empty(s:plug_getcwd()) + throw 'Invalid current working directory. Cannot proceed.' + endif + + for evar in ['$GIT_DIR', '$GIT_WORK_TREE'] + if exists(evar) + throw evar.' detected. Cannot proceed.' + endif + endfor + + call s:job_abort() + if s:switch_in() + if b:plug_preview == 1 + pc + endif + enew + else + call s:new_window() + endif + + nnoremap q :call close_pane() + if a:0 == 0 + call s:finish_bindings() + endif + let b:plug_preview = -1 + let s:plug_tab = tabpagenr() + let s:plug_buf = winbufnr(0) + call s:assign_name() + + for k in ['', 'L', 'o', 'X', 'd', 'dd'] + execute 'silent! unmap ' k + endfor + setlocal buftype=nofile bufhidden=wipe nobuflisted nolist noswapfile nowrap cursorline modifiable nospell + if exists('+colorcolumn') + setlocal colorcolumn= + endif + setf vim-plug + if exists('g:syntax_on') + call s:syntax() + endif +endfunction + +function! s:close_pane() + if b:plug_preview == 1 + pc + let b:plug_preview = -1 + else + bd + endif +endfunction + +function! s:assign_name() + " Assign buffer name + let prefix = '[Plugins]' + let name = prefix + let idx = 2 + while bufexists(name) + let name = printf('%s (%s)', prefix, idx) + let idx = idx + 1 + endwhile + silent! execute 'f' fnameescape(name) +endfunction + +function! s:chsh(swap) + let prev = [&shell, &shellcmdflag, &shellredir] + if !s:is_win + set shell=sh + endif + if a:swap + if &shell =~# 'powershell\(\.exe\)\?$' || &shell =~# 'pwsh$' + let &shellredir = '2>&1 | Out-File -Encoding UTF8 %s' + elseif &shell =~# 'sh' || &shell =~# 'cmd\(\.exe\)\?$' + set shellredir=>%s\ 2>&1 + endif + endif + return prev +endfunction + +function! s:bang(cmd, ...) + let batchfile = '' + try + let [sh, shellcmdflag, shrd] = s:chsh(a:0) + " FIXME: Escaping is incomplete. We could use shellescape with eval, + " but it won't work on Windows. + let cmd = a:0 ? s:with_cd(a:cmd, a:1) : a:cmd + if s:is_win + let [batchfile, cmd] = s:batchfile(cmd) + endif + let g:_plug_bang = (s:is_win && has('gui_running') ? 'silent ' : '').'!'.escape(cmd, '#!%') + execute "normal! :execute g:_plug_bang\\" + finally + unlet g:_plug_bang + let [&shell, &shellcmdflag, &shellredir] = [sh, shellcmdflag, shrd] + if s:is_win && filereadable(batchfile) + call delete(batchfile) + endif + endtry + return v:shell_error ? 'Exit status: ' . v:shell_error : '' +endfunction + +function! s:regress_bar() + let bar = substitute(getline(2)[1:-2], '.*\zs=', 'x', '') + call s:progress_bar(2, bar, len(bar)) +endfunction + +function! s:is_updated(dir) + return !empty(s:system_chomp(['git', 'log', '--pretty=format:%h', 'HEAD...HEAD@{1}'], a:dir)) +endfunction + +function! s:do(pull, force, todo) + for [name, spec] in items(a:todo) + if !isdirectory(spec.dir) + continue + endif + let installed = has_key(s:update.new, name) + let updated = installed ? 0 : + \ (a:pull && index(s:update.errors, name) < 0 && s:is_updated(spec.dir)) + if a:force || installed || updated + execute 'cd' s:esc(spec.dir) + call append(3, '- Post-update hook for '. name .' ... ') + let error = '' + let type = type(spec.do) + if type == s:TYPE.string + if spec.do[0] == ':' + if !get(s:loaded, name, 0) + let s:loaded[name] = 1 + call s:reorg_rtp() + endif + call s:load_plugin(spec) + try + execute spec.do[1:] + catch + let error = v:exception + endtry + if !s:plug_window_exists() + cd - + throw 'Warning: vim-plug was terminated by the post-update hook of '.name + endif + else + let error = s:bang(spec.do) + endif + elseif type == s:TYPE.funcref + try + call s:load_plugin(spec) + let status = installed ? 'installed' : (updated ? 'updated' : 'unchanged') + call spec.do({ 'name': name, 'status': status, 'force': a:force }) + catch + let error = v:exception + endtry + else + let error = 'Invalid hook type' + endif + call s:switch_in() + call setline(4, empty(error) ? (getline(4) . 'OK') + \ : ('x' . getline(4)[1:] . error)) + if !empty(error) + call add(s:update.errors, name) + call s:regress_bar() + endif + cd - + endif + endfor +endfunction + +function! s:hash_match(a, b) + return stridx(a:a, a:b) == 0 || stridx(a:b, a:a) == 0 +endfunction + +function! s:checkout(spec) + let sha = a:spec.commit + let output = s:git_revision(a:spec.dir) + if !empty(output) && !s:hash_match(sha, s:lines(output)[0]) + let credential_helper = s:git_version_requirement(2) ? '-c credential.helper= ' : '' + let output = s:system( + \ 'git '.credential_helper.'fetch --depth 999999 && git checkout '.plug#shellescape(sha).' --', a:spec.dir) + endif + return output +endfunction + +function! s:finish(pull) + let new_frozen = len(filter(keys(s:update.new), 'g:plugs[v:val].frozen')) + if new_frozen + let s = new_frozen > 1 ? 's' : '' + call append(3, printf('- Installed %d frozen plugin%s', new_frozen, s)) + endif + call append(3, '- Finishing ... ') | 4 + redraw + call plug#helptags() + call plug#end() + call setline(4, getline(4) . 'Done!') + redraw + let msgs = [] + if !empty(s:update.errors) + call add(msgs, "Press 'R' to retry.") + endif + if a:pull && len(s:update.new) < len(filter(getline(5, '$'), + \ "v:val =~ '^- ' && v:val !~# 'Already up.to.date'")) + call add(msgs, "Press 'D' to see the updated changes.") + endif + echo join(msgs, ' ') + call s:finish_bindings() +endfunction + +function! s:retry() + if empty(s:update.errors) + return + endif + echo + call s:update_impl(s:update.pull, s:update.force, + \ extend(copy(s:update.errors), [s:update.threads])) +endfunction + +function! s:is_managed(name) + return has_key(g:plugs[a:name], 'uri') +endfunction + +function! s:names(...) + return sort(filter(keys(g:plugs), 'stridx(v:val, a:1) == 0 && s:is_managed(v:val)')) +endfunction + +function! s:check_ruby() + silent! ruby require 'thread'; VIM::command("let g:plug_ruby = '#{RUBY_VERSION}'") + if !exists('g:plug_ruby') + redraw! + return s:warn('echom', 'Warning: Ruby interface is broken') + endif + let ruby_version = split(g:plug_ruby, '\.') + unlet g:plug_ruby + return s:version_requirement(ruby_version, [1, 8, 7]) +endfunction + +function! s:update_impl(pull, force, args) abort + let sync = index(a:args, '--sync') >= 0 || has('vim_starting') + let args = filter(copy(a:args), 'v:val != "--sync"') + let threads = (len(args) > 0 && args[-1] =~ '^[1-9][0-9]*$') ? + \ remove(args, -1) : get(g:, 'plug_threads', 16) + + let managed = filter(copy(g:plugs), 's:is_managed(v:key)') + let todo = empty(args) ? filter(managed, '!v:val.frozen || !isdirectory(v:val.dir)') : + \ filter(managed, 'index(args, v:key) >= 0') + + if empty(todo) + return s:warn('echo', 'No plugin to '. (a:pull ? 'update' : 'install')) + endif + + if !s:is_win && s:git_version_requirement(2, 3) + let s:git_terminal_prompt = exists('$GIT_TERMINAL_PROMPT') ? $GIT_TERMINAL_PROMPT : '' + let $GIT_TERMINAL_PROMPT = 0 + for plug in values(todo) + let plug.uri = substitute(plug.uri, + \ '^https://git::@github\.com', 'https://github.com', '') + endfor + endif + + if !isdirectory(g:plug_home) + try + call mkdir(g:plug_home, 'p') + catch + return s:err(printf('Invalid plug directory: %s. '. + \ 'Try to call plug#begin with a valid directory', g:plug_home)) + endtry + endif + + if has('nvim') && !exists('*jobwait') && threads > 1 + call s:warn('echom', '[vim-plug] Update Neovim for parallel installer') + endif + + let use_job = s:nvim || s:vim8 + let python = (has('python') || has('python3')) && !use_job + let ruby = has('ruby') && !use_job && (v:version >= 703 || v:version == 702 && has('patch374')) && !(s:is_win && has('gui_running')) && threads > 1 && s:check_ruby() + + let s:update = { + \ 'start': reltime(), + \ 'all': todo, + \ 'todo': copy(todo), + \ 'errors': [], + \ 'pull': a:pull, + \ 'force': a:force, + \ 'new': {}, + \ 'threads': (python || ruby || use_job) ? min([len(todo), threads]) : 1, + \ 'bar': '', + \ 'fin': 0 + \ } + + call s:prepare(1) + call append(0, ['', '']) + normal! 2G + silent! redraw + + let s:clone_opt = [] + if get(g:, 'plug_shallow', 1) + call extend(s:clone_opt, ['--depth', '1']) + if s:git_version_requirement(1, 7, 10) + call add(s:clone_opt, '--no-single-branch') + endif + endif + + if has('win32unix') || has('wsl') + call extend(s:clone_opt, ['-c', 'core.eol=lf', '-c', 'core.autocrlf=input']) + endif + + let s:submodule_opt = s:git_version_requirement(2, 8) ? ' --jobs='.threads : '' + + " Python version requirement (>= 2.7) + if python && !has('python3') && !ruby && !use_job && s:update.threads > 1 + redir => pyv + silent python import platform; print platform.python_version() + redir END + let python = s:version_requirement( + \ map(split(split(pyv)[0], '\.'), 'str2nr(v:val)'), [2, 6]) + endif + + if (python || ruby) && s:update.threads > 1 + try + let imd = &imd + if s:mac_gui + set noimd + endif + if ruby + call s:update_ruby() + else + call s:update_python() + endif + catch + let lines = getline(4, '$') + let printed = {} + silent! 4,$d _ + for line in lines + let name = s:extract_name(line, '.', '') + if empty(name) || !has_key(printed, name) + call append('$', line) + if !empty(name) + let printed[name] = 1 + if line[0] == 'x' && index(s:update.errors, name) < 0 + call add(s:update.errors, name) + end + endif + endif + endfor + finally + let &imd = imd + call s:update_finish() + endtry + else + call s:update_vim() + while use_job && sync + sleep 100m + if s:update.fin + break + endif + endwhile + endif +endfunction + +function! s:log4(name, msg) + call setline(4, printf('- %s (%s)', a:msg, a:name)) + redraw +endfunction + +function! s:update_finish() + if exists('s:git_terminal_prompt') + let $GIT_TERMINAL_PROMPT = s:git_terminal_prompt + endif + if s:switch_in() + call append(3, '- Updating ...') | 4 + for [name, spec] in items(filter(copy(s:update.all), 'index(s:update.errors, v:key) < 0 && (s:update.force || s:update.pull || has_key(s:update.new, v:key))')) + let [pos, _] = s:logpos(name) + if !pos + continue + endif + if has_key(spec, 'commit') + call s:log4(name, 'Checking out '.spec.commit) + let out = s:checkout(spec) + elseif has_key(spec, 'tag') + let tag = spec.tag + if tag =~ '\*' + let tags = s:lines(s:system('git tag --list '.plug#shellescape(tag).' --sort -version:refname 2>&1', spec.dir)) + if !v:shell_error && !empty(tags) + let tag = tags[0] + call s:log4(name, printf('Latest tag for %s -> %s', spec.tag, tag)) + call append(3, '') + endif + endif + call s:log4(name, 'Checking out '.tag) + let out = s:system('git checkout -q '.plug#shellescape(tag).' -- 2>&1', spec.dir) + else + let branch = s:git_origin_branch(spec) + call s:log4(name, 'Merging origin/'.s:esc(branch)) + let out = s:system('git checkout -q '.plug#shellescape(branch).' -- 2>&1' + \. (has_key(s:update.new, name) ? '' : ('&& git merge --ff-only '.plug#shellescape('origin/'.branch).' 2>&1')), spec.dir) + endif + if !v:shell_error && filereadable(spec.dir.'/.gitmodules') && + \ (s:update.force || has_key(s:update.new, name) || s:is_updated(spec.dir)) + call s:log4(name, 'Updating submodules. This may take a while.') + let out .= s:bang('git submodule update --init --recursive'.s:submodule_opt.' 2>&1', spec.dir) + endif + let msg = s:format_message(v:shell_error ? 'x': '-', name, out) + if v:shell_error + call add(s:update.errors, name) + call s:regress_bar() + silent execute pos 'd _' + call append(4, msg) | 4 + elseif !empty(out) + call setline(pos, msg[0]) + endif + redraw + endfor + silent 4 d _ + try + call s:do(s:update.pull, s:update.force, filter(copy(s:update.all), 'index(s:update.errors, v:key) < 0 && has_key(v:val, "do")')) + catch + call s:warn('echom', v:exception) + call s:warn('echo', '') + return + endtry + call s:finish(s:update.pull) + call setline(1, 'Updated. Elapsed time: ' . split(reltimestr(reltime(s:update.start)))[0] . ' sec.') + call s:switch_out('normal! gg') + endif +endfunction + +function! s:job_abort() + if (!s:nvim && !s:vim8) || !exists('s:jobs') + return + endif + + for [name, j] in items(s:jobs) + if s:nvim + silent! call jobstop(j.jobid) + elseif s:vim8 + silent! call job_stop(j.jobid) + endif + if j.new + call s:rm_rf(g:plugs[name].dir) + endif + endfor + let s:jobs = {} +endfunction + +function! s:last_non_empty_line(lines) + let len = len(a:lines) + for idx in range(len) + let line = a:lines[len-idx-1] + if !empty(line) + return line + endif + endfor + return '' +endfunction + +function! s:job_out_cb(self, data) abort + let self = a:self + let data = remove(self.lines, -1) . a:data + let lines = map(split(data, "\n", 1), 'split(v:val, "\r", 1)[-1]') + call extend(self.lines, lines) + " To reduce the number of buffer updates + let self.tick = get(self, 'tick', -1) + 1 + if !self.running || self.tick % len(s:jobs) == 0 + let bullet = self.running ? (self.new ? '+' : '*') : (self.error ? 'x' : '-') + let result = self.error ? join(self.lines, "\n") : s:last_non_empty_line(self.lines) + call s:log(bullet, self.name, result) + endif +endfunction + +function! s:job_exit_cb(self, data) abort + let a:self.running = 0 + let a:self.error = a:data != 0 + call s:reap(a:self.name) + call s:tick() +endfunction + +function! s:job_cb(fn, job, ch, data) + if !s:plug_window_exists() " plug window closed + return s:job_abort() + endif + call call(a:fn, [a:job, a:data]) +endfunction + +function! s:nvim_cb(job_id, data, event) dict abort + return (a:event == 'stdout' || a:event == 'stderr') ? + \ s:job_cb('s:job_out_cb', self, 0, join(a:data, "\n")) : + \ s:job_cb('s:job_exit_cb', self, 0, a:data) +endfunction + +function! s:spawn(name, cmd, opts) + let job = { 'name': a:name, 'running': 1, 'error': 0, 'lines': [''], + \ 'new': get(a:opts, 'new', 0) } + let s:jobs[a:name] = job + + if s:nvim + if has_key(a:opts, 'dir') + let job.cwd = a:opts.dir + endif + let argv = a:cmd + call extend(job, { + \ 'on_stdout': function('s:nvim_cb'), + \ 'on_stderr': function('s:nvim_cb'), + \ 'on_exit': function('s:nvim_cb'), + \ }) + let jid = s:plug_call('jobstart', argv, job) + if jid > 0 + let job.jobid = jid + else + let job.running = 0 + let job.error = 1 + let job.lines = [jid < 0 ? argv[0].' is not executable' : + \ 'Invalid arguments (or job table is full)'] + endif + elseif s:vim8 + let cmd = join(map(copy(a:cmd), 'plug#shellescape(v:val, {"script": 0})')) + if has_key(a:opts, 'dir') + let cmd = s:with_cd(cmd, a:opts.dir, 0) + endif + let argv = s:is_win ? ['cmd', '/s', '/c', '"'.cmd.'"'] : ['sh', '-c', cmd] + let jid = job_start(s:is_win ? join(argv, ' ') : argv, { + \ 'out_cb': function('s:job_cb', ['s:job_out_cb', job]), + \ 'err_cb': function('s:job_cb', ['s:job_out_cb', job]), + \ 'exit_cb': function('s:job_cb', ['s:job_exit_cb', job]), + \ 'err_mode': 'raw', + \ 'out_mode': 'raw' + \}) + if job_status(jid) == 'run' + let job.jobid = jid + else + let job.running = 0 + let job.error = 1 + let job.lines = ['Failed to start job'] + endif + else + let job.lines = s:lines(call('s:system', has_key(a:opts, 'dir') ? [a:cmd, a:opts.dir] : [a:cmd])) + let job.error = v:shell_error != 0 + let job.running = 0 + endif +endfunction + +function! s:reap(name) + let job = s:jobs[a:name] + if job.error + call add(s:update.errors, a:name) + elseif get(job, 'new', 0) + let s:update.new[a:name] = 1 + endif + let s:update.bar .= job.error ? 'x' : '=' + + let bullet = job.error ? 'x' : '-' + let result = job.error ? join(job.lines, "\n") : s:last_non_empty_line(job.lines) + call s:log(bullet, a:name, empty(result) ? 'OK' : result) + call s:bar() + + call remove(s:jobs, a:name) +endfunction + +function! s:bar() + if s:switch_in() + let total = len(s:update.all) + call setline(1, (s:update.pull ? 'Updating' : 'Installing'). + \ ' plugins ('.len(s:update.bar).'/'.total.')') + call s:progress_bar(2, s:update.bar, total) + call s:switch_out() + endif +endfunction + +function! s:logpos(name) + let max = line('$') + for i in range(4, max > 4 ? max : 4) + if getline(i) =~# '^[-+x*] '.a:name.':' + for j in range(i + 1, max > 5 ? max : 5) + if getline(j) !~ '^ ' + return [i, j - 1] + endif + endfor + return [i, i] + endif + endfor + return [0, 0] +endfunction + +function! s:log(bullet, name, lines) + if s:switch_in() + let [b, e] = s:logpos(a:name) + if b > 0 + silent execute printf('%d,%d d _', b, e) + if b > winheight('.') + let b = 4 + endif + else + let b = 4 + endif + " FIXME For some reason, nomodifiable is set after :d in vim8 + setlocal modifiable + call append(b - 1, s:format_message(a:bullet, a:name, a:lines)) + call s:switch_out() + endif +endfunction + +function! s:update_vim() + let s:jobs = {} + + call s:bar() + call s:tick() +endfunction + +function! s:tick() + let pull = s:update.pull + let prog = s:progress_opt(s:nvim || s:vim8) +while 1 " Without TCO, Vim stack is bound to explode + if empty(s:update.todo) + if empty(s:jobs) && !s:update.fin + call s:update_finish() + let s:update.fin = 1 + endif + return + endif + + let name = keys(s:update.todo)[0] + let spec = remove(s:update.todo, name) + let new = empty(globpath(spec.dir, '.git', 1)) + + call s:log(new ? '+' : '*', name, pull ? 'Updating ...' : 'Installing ...') + redraw + + let has_tag = has_key(spec, 'tag') + if !new + let [error, _] = s:git_validate(spec, 0) + if empty(error) + if pull + let cmd = s:git_version_requirement(2) ? ['git', '-c', 'credential.helper=', 'fetch'] : ['git', 'fetch'] + if has_tag && !empty(globpath(spec.dir, '.git/shallow')) + call extend(cmd, ['--depth', '99999999']) + endif + if !empty(prog) + call add(cmd, prog) + endif + call s:spawn(name, cmd, { 'dir': spec.dir }) + else + let s:jobs[name] = { 'running': 0, 'lines': ['Already installed'], 'error': 0 } + endif + else + let s:jobs[name] = { 'running': 0, 'lines': s:lines(error), 'error': 1 } + endif + else + let cmd = ['git', 'clone'] + if !has_tag + call extend(cmd, s:clone_opt) + endif + if !empty(prog) + call add(cmd, prog) + endif + call s:spawn(name, extend(cmd, [spec.uri, s:trim(spec.dir)]), { 'new': 1 }) + endif + + if !s:jobs[name].running + call s:reap(name) + endif + if len(s:jobs) >= s:update.threads + break + endif +endwhile +endfunction + +function! s:update_python() +let py_exe = has('python') ? 'python' : 'python3' +execute py_exe "<< EOF" +import datetime +import functools +import os +try: + import queue +except ImportError: + import Queue as queue +import random +import re +import shutil +import signal +import subprocess +import tempfile +import threading as thr +import time +import traceback +import vim + +G_NVIM = vim.eval("has('nvim')") == '1' +G_PULL = vim.eval('s:update.pull') == '1' +G_RETRIES = int(vim.eval('get(g:, "plug_retries", 2)')) + 1 +G_TIMEOUT = int(vim.eval('get(g:, "plug_timeout", 60)')) +G_CLONE_OPT = ' '.join(vim.eval('s:clone_opt')) +G_PROGRESS = vim.eval('s:progress_opt(1)') +G_LOG_PROB = 1.0 / int(vim.eval('s:update.threads')) +G_STOP = thr.Event() +G_IS_WIN = vim.eval('s:is_win') == '1' + +class PlugError(Exception): + def __init__(self, msg): + self.msg = msg +class CmdTimedOut(PlugError): + pass +class CmdFailed(PlugError): + pass +class InvalidURI(PlugError): + pass +class Action(object): + INSTALL, UPDATE, ERROR, DONE = ['+', '*', 'x', '-'] + +class Buffer(object): + def __init__(self, lock, num_plugs, is_pull): + self.bar = '' + self.event = 'Updating' if is_pull else 'Installing' + self.lock = lock + self.maxy = int(vim.eval('winheight(".")')) + self.num_plugs = num_plugs + + def __where(self, name): + """ Find first line with name in current buffer. Return line num. """ + found, lnum = False, 0 + matcher = re.compile('^[-+x*] {0}:'.format(name)) + for line in vim.current.buffer: + if matcher.search(line) is not None: + found = True + break + lnum += 1 + + if not found: + lnum = -1 + return lnum + + def header(self): + curbuf = vim.current.buffer + curbuf[0] = self.event + ' plugins ({0}/{1})'.format(len(self.bar), self.num_plugs) + + num_spaces = self.num_plugs - len(self.bar) + curbuf[1] = '[{0}{1}]'.format(self.bar, num_spaces * ' ') + + with self.lock: + vim.command('normal! 2G') + vim.command('redraw') + + def write(self, action, name, lines): + first, rest = lines[0], lines[1:] + msg = ['{0} {1}{2}{3}'.format(action, name, ': ' if first else '', first)] + msg.extend([' ' + line for line in rest]) + + try: + if action == Action.ERROR: + self.bar += 'x' + vim.command("call add(s:update.errors, '{0}')".format(name)) + elif action == Action.DONE: + self.bar += '=' + + curbuf = vim.current.buffer + lnum = self.__where(name) + if lnum != -1: # Found matching line num + del curbuf[lnum] + if lnum > self.maxy and action in set([Action.INSTALL, Action.UPDATE]): + lnum = 3 + else: + lnum = 3 + curbuf.append(msg, lnum) + + self.header() + except vim.error: + pass + +class Command(object): + CD = 'cd /d' if G_IS_WIN else 'cd' + + def __init__(self, cmd, cmd_dir=None, timeout=60, cb=None, clean=None): + self.cmd = cmd + if cmd_dir: + self.cmd = '{0} {1} && {2}'.format(Command.CD, cmd_dir, self.cmd) + self.timeout = timeout + self.callback = cb if cb else (lambda msg: None) + self.clean = clean if clean else (lambda: None) + self.proc = None + + @property + def alive(self): + """ Returns true only if command still running. """ + return self.proc and self.proc.poll() is None + + def execute(self, ntries=3): + """ Execute the command with ntries if CmdTimedOut. + Returns the output of the command if no Exception. + """ + attempt, finished, limit = 0, False, self.timeout + + while not finished: + try: + attempt += 1 + result = self.try_command() + finished = True + return result + except CmdTimedOut: + if attempt != ntries: + self.notify_retry() + self.timeout += limit + else: + raise + + def notify_retry(self): + """ Retry required for command, notify user. """ + for count in range(3, 0, -1): + if G_STOP.is_set(): + raise KeyboardInterrupt + msg = 'Timeout. Will retry in {0} second{1} ...'.format( + count, 's' if count != 1 else '') + self.callback([msg]) + time.sleep(1) + self.callback(['Retrying ...']) + + def try_command(self): + """ Execute a cmd & poll for callback. Returns list of output. + Raises CmdFailed -> return code for Popen isn't 0 + Raises CmdTimedOut -> command exceeded timeout without new output + """ + first_line = True + + try: + tfile = tempfile.NamedTemporaryFile(mode='w+b') + preexec_fn = not G_IS_WIN and os.setsid or None + self.proc = subprocess.Popen(self.cmd, stdout=tfile, + stderr=subprocess.STDOUT, + stdin=subprocess.PIPE, shell=True, + preexec_fn=preexec_fn) + thrd = thr.Thread(target=(lambda proc: proc.wait()), args=(self.proc,)) + thrd.start() + + thread_not_started = True + while thread_not_started: + try: + thrd.join(0.1) + thread_not_started = False + except RuntimeError: + pass + + while self.alive: + if G_STOP.is_set(): + raise KeyboardInterrupt + + if first_line or random.random() < G_LOG_PROB: + first_line = False + line = '' if G_IS_WIN else nonblock_read(tfile.name) + if line: + self.callback([line]) + + time_diff = time.time() - os.path.getmtime(tfile.name) + if time_diff > self.timeout: + raise CmdTimedOut(['Timeout!']) + + thrd.join(0.5) + + tfile.seek(0) + result = [line.decode('utf-8', 'replace').rstrip() for line in tfile] + + if self.proc.returncode != 0: + raise CmdFailed([''] + result) + + return result + except: + self.terminate() + raise + + def terminate(self): + """ Terminate process and cleanup. """ + if self.alive: + if G_IS_WIN: + os.kill(self.proc.pid, signal.SIGINT) + else: + os.killpg(self.proc.pid, signal.SIGTERM) + self.clean() + +class Plugin(object): + def __init__(self, name, args, buf_q, lock): + self.name = name + self.args = args + self.buf_q = buf_q + self.lock = lock + self.tag = args.get('tag', 0) + + def manage(self): + try: + if os.path.exists(self.args['dir']): + self.update() + else: + self.install() + with self.lock: + thread_vim_command("let s:update.new['{0}'] = 1".format(self.name)) + except PlugError as exc: + self.write(Action.ERROR, self.name, exc.msg) + except KeyboardInterrupt: + G_STOP.set() + self.write(Action.ERROR, self.name, ['Interrupted!']) + except: + # Any exception except those above print stack trace + msg = 'Trace:\n{0}'.format(traceback.format_exc().rstrip()) + self.write(Action.ERROR, self.name, msg.split('\n')) + raise + + def install(self): + target = self.args['dir'] + if target[-1] == '\\': + target = target[0:-1] + + def clean(target): + def _clean(): + try: + shutil.rmtree(target) + except OSError: + pass + return _clean + + self.write(Action.INSTALL, self.name, ['Installing ...']) + callback = functools.partial(self.write, Action.INSTALL, self.name) + cmd = 'git clone {0} {1} {2} {3} 2>&1'.format( + '' if self.tag else G_CLONE_OPT, G_PROGRESS, self.args['uri'], + esc(target)) + com = Command(cmd, None, G_TIMEOUT, callback, clean(target)) + result = com.execute(G_RETRIES) + self.write(Action.DONE, self.name, result[-1:]) + + def repo_uri(self): + cmd = 'git rev-parse --abbrev-ref HEAD 2>&1 && git config -f .git/config remote.origin.url' + command = Command(cmd, self.args['dir'], G_TIMEOUT,) + result = command.execute(G_RETRIES) + return result[-1] + + def update(self): + actual_uri = self.repo_uri() + expect_uri = self.args['uri'] + regex = re.compile(r'^(?:\w+://)?(?:[^@/]*@)?([^:/]*(?::[0-9]*)?)[:/](.*?)(?:\.git)?/?$') + ma = regex.match(actual_uri) + mb = regex.match(expect_uri) + if ma is None or mb is None or ma.groups() != mb.groups(): + msg = ['', + 'Invalid URI: {0}'.format(actual_uri), + 'Expected {0}'.format(expect_uri), + 'PlugClean required.'] + raise InvalidURI(msg) + + if G_PULL: + self.write(Action.UPDATE, self.name, ['Updating ...']) + callback = functools.partial(self.write, Action.UPDATE, self.name) + fetch_opt = '--depth 99999999' if self.tag and os.path.isfile(os.path.join(self.args['dir'], '.git/shallow')) else '' + cmd = 'git fetch {0} {1} 2>&1'.format(fetch_opt, G_PROGRESS) + com = Command(cmd, self.args['dir'], G_TIMEOUT, callback) + result = com.execute(G_RETRIES) + self.write(Action.DONE, self.name, result[-1:]) + else: + self.write(Action.DONE, self.name, ['Already installed']) + + def write(self, action, name, msg): + self.buf_q.put((action, name, msg)) + +class PlugThread(thr.Thread): + def __init__(self, tname, args): + super(PlugThread, self).__init__() + self.tname = tname + self.args = args + + def run(self): + thr.current_thread().name = self.tname + buf_q, work_q, lock = self.args + + try: + while not G_STOP.is_set(): + name, args = work_q.get_nowait() + plug = Plugin(name, args, buf_q, lock) + plug.manage() + work_q.task_done() + except queue.Empty: + pass + +class RefreshThread(thr.Thread): + def __init__(self, lock): + super(RefreshThread, self).__init__() + self.lock = lock + self.running = True + + def run(self): + while self.running: + with self.lock: + thread_vim_command('noautocmd normal! a') + time.sleep(0.33) + + def stop(self): + self.running = False + +if G_NVIM: + def thread_vim_command(cmd): + vim.session.threadsafe_call(lambda: vim.command(cmd)) +else: + def thread_vim_command(cmd): + vim.command(cmd) + +def esc(name): + return '"' + name.replace('"', '\"') + '"' + +def nonblock_read(fname): + """ Read a file with nonblock flag. Return the last line. """ + fread = os.open(fname, os.O_RDONLY | os.O_NONBLOCK) + buf = os.read(fread, 100000).decode('utf-8', 'replace') + os.close(fread) + + line = buf.rstrip('\r\n') + left = max(line.rfind('\r'), line.rfind('\n')) + if left != -1: + left += 1 + line = line[left:] + + return line + +def main(): + thr.current_thread().name = 'main' + nthreads = int(vim.eval('s:update.threads')) + plugs = vim.eval('s:update.todo') + mac_gui = vim.eval('s:mac_gui') == '1' + + lock = thr.Lock() + buf = Buffer(lock, len(plugs), G_PULL) + buf_q, work_q = queue.Queue(), queue.Queue() + for work in plugs.items(): + work_q.put(work) + + start_cnt = thr.active_count() + for num in range(nthreads): + tname = 'PlugT-{0:02}'.format(num) + thread = PlugThread(tname, (buf_q, work_q, lock)) + thread.start() + if mac_gui: + rthread = RefreshThread(lock) + rthread.start() + + while not buf_q.empty() or thr.active_count() != start_cnt: + try: + action, name, msg = buf_q.get(True, 0.25) + buf.write(action, name, ['OK'] if not msg else msg) + buf_q.task_done() + except queue.Empty: + pass + except KeyboardInterrupt: + G_STOP.set() + + if mac_gui: + rthread.stop() + rthread.join() + +main() +EOF +endfunction + +function! s:update_ruby() + ruby << EOF + module PlugStream + SEP = ["\r", "\n", nil] + def get_line + buffer = '' + loop do + char = readchar rescue return + if SEP.include? char.chr + buffer << $/ + break + else + buffer << char + end + end + buffer + end + end unless defined?(PlugStream) + + def esc arg + %["#{arg.gsub('"', '\"')}"] + end + + def killall pid + pids = [pid] + if /mswin|mingw|bccwin/ =~ RUBY_PLATFORM + pids.each { |pid| Process.kill 'INT', pid.to_i rescue nil } + else + unless `which pgrep 2> /dev/null`.empty? + children = pids + until children.empty? + children = children.map { |pid| + `pgrep -P #{pid}`.lines.map { |l| l.chomp } + }.flatten + pids += children + end + end + pids.each { |pid| Process.kill 'TERM', pid.to_i rescue nil } + end + end + + def compare_git_uri a, b + regex = %r{^(?:\w+://)?(?:[^@/]*@)?([^:/]*(?::[0-9]*)?)[:/](.*?)(?:\.git)?/?$} + regex.match(a).to_a.drop(1) == regex.match(b).to_a.drop(1) + end + + require 'thread' + require 'fileutils' + require 'timeout' + running = true + iswin = VIM::evaluate('s:is_win').to_i == 1 + pull = VIM::evaluate('s:update.pull').to_i == 1 + base = VIM::evaluate('g:plug_home') + all = VIM::evaluate('s:update.todo') + limit = VIM::evaluate('get(g:, "plug_timeout", 60)') + tries = VIM::evaluate('get(g:, "plug_retries", 2)') + 1 + nthr = VIM::evaluate('s:update.threads').to_i + maxy = VIM::evaluate('winheight(".")').to_i + vim7 = VIM::evaluate('v:version').to_i <= 703 && RUBY_PLATFORM =~ /darwin/ + cd = iswin ? 'cd /d' : 'cd' + tot = VIM::evaluate('len(s:update.todo)') || 0 + bar = '' + skip = 'Already installed' + mtx = Mutex.new + take1 = proc { mtx.synchronize { running && all.shift } } + logh = proc { + cnt = bar.length + $curbuf[1] = "#{pull ? 'Updating' : 'Installing'} plugins (#{cnt}/#{tot})" + $curbuf[2] = '[' + bar.ljust(tot) + ']' + VIM::command('normal! 2G') + VIM::command('redraw') + } + where = proc { |name| (1..($curbuf.length)).find { |l| $curbuf[l] =~ /^[-+x*] #{name}:/ } } + log = proc { |name, result, type| + mtx.synchronize do + ing = ![true, false].include?(type) + bar += type ? '=' : 'x' unless ing + b = case type + when :install then '+' when :update then '*' + when true, nil then '-' else + VIM::command("call add(s:update.errors, '#{name}')") + 'x' + end + result = + if type || type.nil? + ["#{b} #{name}: #{result.lines.to_a.last || 'OK'}"] + elsif result =~ /^Interrupted|^Timeout/ + ["#{b} #{name}: #{result}"] + else + ["#{b} #{name}"] + result.lines.map { |l| " " << l } + end + if lnum = where.call(name) + $curbuf.delete lnum + lnum = 4 if ing && lnum > maxy + end + result.each_with_index do |line, offset| + $curbuf.append((lnum || 4) - 1 + offset, line.gsub(/\e\[./, '').chomp) + end + logh.call + end + } + bt = proc { |cmd, name, type, cleanup| + tried = timeout = 0 + begin + tried += 1 + timeout += limit + fd = nil + data = '' + if iswin + Timeout::timeout(timeout) do + tmp = VIM::evaluate('tempname()') + system("(#{cmd}) > #{tmp}") + data = File.read(tmp).chomp + File.unlink tmp rescue nil + end + else + fd = IO.popen(cmd).extend(PlugStream) + first_line = true + log_prob = 1.0 / nthr + while line = Timeout::timeout(timeout) { fd.get_line } + data << line + log.call name, line.chomp, type if name && (first_line || rand < log_prob) + first_line = false + end + fd.close + end + [$? == 0, data.chomp] + rescue Timeout::Error, Interrupt => e + if fd && !fd.closed? + killall fd.pid + fd.close + end + cleanup.call if cleanup + if e.is_a?(Timeout::Error) && tried < tries + 3.downto(1) do |countdown| + s = countdown > 1 ? 's' : '' + log.call name, "Timeout. Will retry in #{countdown} second#{s} ...", type + sleep 1 + end + log.call name, 'Retrying ...', type + retry + end + [false, e.is_a?(Interrupt) ? "Interrupted!" : "Timeout!"] + end + } + main = Thread.current + threads = [] + watcher = Thread.new { + if vim7 + while VIM::evaluate('getchar(1)') + sleep 0.1 + end + else + require 'io/console' # >= Ruby 1.9 + nil until IO.console.getch == 3.chr + end + mtx.synchronize do + running = false + threads.each { |t| t.raise Interrupt } unless vim7 + end + threads.each { |t| t.join rescue nil } + main.kill + } + refresh = Thread.new { + while true + mtx.synchronize do + break unless running + VIM::command('noautocmd normal! a') + end + sleep 0.2 + end + } if VIM::evaluate('s:mac_gui') == 1 + + clone_opt = VIM::evaluate('s:clone_opt').join(' ') + progress = VIM::evaluate('s:progress_opt(1)') + nthr.times do + mtx.synchronize do + threads << Thread.new { + while pair = take1.call + name = pair.first + dir, uri, tag = pair.last.values_at *%w[dir uri tag] + exists = File.directory? dir + ok, result = + if exists + chdir = "#{cd} #{iswin ? dir : esc(dir)}" + ret, data = bt.call "#{chdir} && git rev-parse --abbrev-ref HEAD 2>&1 && git config -f .git/config remote.origin.url", nil, nil, nil + current_uri = data.lines.to_a.last + if !ret + if data =~ /^Interrupted|^Timeout/ + [false, data] + else + [false, [data.chomp, "PlugClean required."].join($/)] + end + elsif !compare_git_uri(current_uri, uri) + [false, ["Invalid URI: #{current_uri}", + "Expected: #{uri}", + "PlugClean required."].join($/)] + else + if pull + log.call name, 'Updating ...', :update + fetch_opt = (tag && File.exist?(File.join(dir, '.git/shallow'))) ? '--depth 99999999' : '' + bt.call "#{chdir} && git fetch #{fetch_opt} #{progress} 2>&1", name, :update, nil + else + [true, skip] + end + end + else + d = esc dir.sub(%r{[\\/]+$}, '') + log.call name, 'Installing ...', :install + bt.call "git clone #{clone_opt unless tag} #{progress} #{uri} #{d} 2>&1", name, :install, proc { + FileUtils.rm_rf dir + } + end + mtx.synchronize { VIM::command("let s:update.new['#{name}'] = 1") } if !exists && ok + log.call name, result, ok + end + } if running + end + end + threads.each { |t| t.join rescue nil } + logh.call + refresh.kill if refresh + watcher.kill +EOF +endfunction + +function! s:shellesc_cmd(arg, script) + let escaped = substitute('"'.a:arg.'"', '[&|<>()@^!"]', '^&', 'g') + return substitute(escaped, '%', (a:script ? '%' : '^') . '&', 'g') +endfunction + +function! s:shellesc_ps1(arg) + return "'".substitute(escape(a:arg, '\"'), "'", "''", 'g')."'" +endfunction + +function! s:shellesc_sh(arg) + return "'".substitute(a:arg, "'", "'\\\\''", 'g')."'" +endfunction + +" Escape the shell argument based on the shell. +" Vim and Neovim's shellescape() are insufficient. +" 1. shellslash determines whether to use single/double quotes. +" Double-quote escaping is fragile for cmd.exe. +" 2. It does not work for powershell. +" 3. It does not work for *sh shells if the command is executed +" via cmd.exe (ie. cmd.exe /c sh -c command command_args) +" 4. It does not support batchfile syntax. +" +" Accepts an optional dictionary with the following keys: +" - shell: same as Vim/Neovim 'shell' option. +" If unset, fallback to 'cmd.exe' on Windows or 'sh'. +" - script: If truthy and shell is cmd.exe, escape for batchfile syntax. +function! plug#shellescape(arg, ...) + if a:arg =~# '^[A-Za-z0-9_/:.-]\+$' + return a:arg + endif + let opts = a:0 > 0 && type(a:1) == s:TYPE.dict ? a:1 : {} + let shell = get(opts, 'shell', s:is_win ? 'cmd.exe' : 'sh') + let script = get(opts, 'script', 1) + if shell =~# 'cmd\(\.exe\)\?$' + return s:shellesc_cmd(a:arg, script) + elseif shell =~# 'powershell\(\.exe\)\?$' || shell =~# 'pwsh$' + return s:shellesc_ps1(a:arg) + endif + return s:shellesc_sh(a:arg) +endfunction + +function! s:glob_dir(path) + return map(filter(s:glob(a:path, '**'), 'isdirectory(v:val)'), 's:dirpath(v:val)') +endfunction + +function! s:progress_bar(line, bar, total) + call setline(a:line, '[' . s:lpad(a:bar, a:total) . ']') +endfunction + +function! s:compare_git_uri(a, b) + " See `git help clone' + " https:// [user@] github.com[:port] / junegunn/vim-plug [.git] + " [git@] github.com[:port] : junegunn/vim-plug [.git] + " file:// / junegunn/vim-plug [/] + " / junegunn/vim-plug [/] + let pat = '^\%(\w\+://\)\='.'\%([^@/]*@\)\='.'\([^:/]*\%(:[0-9]*\)\=\)'.'[:/]'.'\(.\{-}\)'.'\%(\.git\)\=/\?$' + let ma = matchlist(a:a, pat) + let mb = matchlist(a:b, pat) + return ma[1:2] ==# mb[1:2] +endfunction + +function! s:format_message(bullet, name, message) + if a:bullet != 'x' + return [printf('%s %s: %s', a:bullet, a:name, s:lastline(a:message))] + else + let lines = map(s:lines(a:message), '" ".v:val') + return extend([printf('x %s:', a:name)], lines) + endif +endfunction + +function! s:with_cd(cmd, dir, ...) + let script = a:0 > 0 ? a:1 : 1 + return printf('cd%s %s && %s', s:is_win ? ' /d' : '', plug#shellescape(a:dir, {'script': script}), a:cmd) +endfunction + +function! s:system(cmd, ...) + let batchfile = '' + try + let [sh, shellcmdflag, shrd] = s:chsh(1) + if type(a:cmd) == s:TYPE.list + " Neovim's system() supports list argument to bypass the shell + " but it cannot set the working directory for the command. + " Assume that the command does not rely on the shell. + if has('nvim') && a:0 == 0 + return system(a:cmd) + endif + let cmd = join(map(copy(a:cmd), 'plug#shellescape(v:val, {"shell": &shell, "script": 0})')) + if &shell =~# 'powershell\(\.exe\)\?$' + let cmd = '& ' . cmd + endif + else + let cmd = a:cmd + endif + if a:0 > 0 + let cmd = s:with_cd(cmd, a:1, type(a:cmd) != s:TYPE.list) + endif + if s:is_win && type(a:cmd) != s:TYPE.list + let [batchfile, cmd] = s:batchfile(cmd) + endif + return system(cmd) + finally + let [&shell, &shellcmdflag, &shellredir] = [sh, shellcmdflag, shrd] + if s:is_win && filereadable(batchfile) + call delete(batchfile) + endif + endtry +endfunction + +function! s:system_chomp(...) + let ret = call('s:system', a:000) + return v:shell_error ? '' : substitute(ret, '\n$', '', '') +endfunction + +function! s:git_validate(spec, check_branch) + let err = '' + if isdirectory(a:spec.dir) + let result = [s:git_local_branch(a:spec.dir), s:git_origin_url(a:spec.dir)] + let remote = result[-1] + if empty(remote) + let err = join([remote, 'PlugClean required.'], "\n") + elseif !s:compare_git_uri(remote, a:spec.uri) + let err = join(['Invalid URI: '.remote, + \ 'Expected: '.a:spec.uri, + \ 'PlugClean required.'], "\n") + elseif a:check_branch && has_key(a:spec, 'commit') + let sha = s:git_revision(a:spec.dir) + if empty(sha) + let err = join(add(result, 'PlugClean required.'), "\n") + elseif !s:hash_match(sha, a:spec.commit) + let err = join([printf('Invalid HEAD (expected: %s, actual: %s)', + \ a:spec.commit[:6], sha[:6]), + \ 'PlugUpdate required.'], "\n") + endif + elseif a:check_branch + let current_branch = result[0] + " Check tag + let origin_branch = s:git_origin_branch(a:spec) + if has_key(a:spec, 'tag') + let tag = s:system_chomp('git describe --exact-match --tags HEAD 2>&1', a:spec.dir) + if a:spec.tag !=# tag && a:spec.tag !~ '\*' + let err = printf('Invalid tag: %s (expected: %s). Try PlugUpdate.', + \ (empty(tag) ? 'N/A' : tag), a:spec.tag) + endif + " Check branch + elseif origin_branch !=# current_branch + let err = printf('Invalid branch: %s (expected: %s). Try PlugUpdate.', + \ current_branch, origin_branch) + endif + if empty(err) + let [ahead, behind] = split(s:lastline(s:system([ + \ 'git', 'rev-list', '--count', '--left-right', + \ printf('HEAD...origin/%s', origin_branch) + \ ], a:spec.dir)), '\t') + if !v:shell_error && ahead + if behind + " Only mention PlugClean if diverged, otherwise it's likely to be + " pushable (and probably not that messed up). + let err = printf( + \ "Diverged from origin/%s (%d commit(s) ahead and %d commit(s) behind!\n" + \ .'Backup local changes and run PlugClean and PlugUpdate to reinstall it.', origin_branch, ahead, behind) + else + let err = printf("Ahead of origin/%s by %d commit(s).\n" + \ .'Cannot update until local changes are pushed.', + \ origin_branch, ahead) + endif + endif + endif + endif + else + let err = 'Not found' + endif + return [err, err =~# 'PlugClean'] +endfunction + +function! s:rm_rf(dir) + if isdirectory(a:dir) + return s:system(s:is_win + \ ? 'rmdir /S /Q '.plug#shellescape(a:dir) + \ : ['rm', '-rf', a:dir]) + endif +endfunction + +function! s:clean(force) + call s:prepare() + call append(0, 'Searching for invalid plugins in '.g:plug_home) + call append(1, '') + + " List of valid directories + let dirs = [] + let errs = {} + let [cnt, total] = [0, len(g:plugs)] + for [name, spec] in items(g:plugs) + if !s:is_managed(name) + call add(dirs, spec.dir) + else + let [err, clean] = s:git_validate(spec, 1) + if clean + let errs[spec.dir] = s:lines(err)[0] + else + call add(dirs, spec.dir) + endif + endif + let cnt += 1 + call s:progress_bar(2, repeat('=', cnt), total) + normal! 2G + redraw + endfor + + let allowed = {} + for dir in dirs + let allowed[s:dirpath(s:plug_fnamemodify(dir, ':h:h'))] = 1 + let allowed[dir] = 1 + for child in s:glob_dir(dir) + let allowed[child] = 1 + endfor + endfor + + let todo = [] + let found = sort(s:glob_dir(g:plug_home)) + while !empty(found) + let f = remove(found, 0) + if !has_key(allowed, f) && isdirectory(f) + call add(todo, f) + call append(line('$'), '- ' . f) + if has_key(errs, f) + call append(line('$'), ' ' . errs[f]) + endif + let found = filter(found, 'stridx(v:val, f) != 0') + end + endwhile + + 4 + redraw + if empty(todo) + call append(line('$'), 'Already clean.') + else + let s:clean_count = 0 + call append(3, ['Directories to delete:', '']) + redraw! + if a:force || s:ask_no_interrupt('Delete all directories?') + call s:delete([6, line('$')], 1) + else + call setline(4, 'Cancelled.') + nnoremap d :set opfunc=delete_opg@ + nmap dd d_ + xnoremap d :call delete_op(visualmode(), 1) + echo 'Delete the lines (d{motion}) to delete the corresponding directories' + endif + endif + 4 + setlocal nomodifiable +endfunction + +function! s:delete_op(type, ...) + call s:delete(a:0 ? [line("'<"), line("'>")] : [line("'["), line("']")], 0) +endfunction + +function! s:delete(range, force) + let [l1, l2] = a:range + let force = a:force + let err_count = 0 + while l1 <= l2 + let line = getline(l1) + if line =~ '^- ' && isdirectory(line[2:]) + execute l1 + redraw! + let answer = force ? 1 : s:ask('Delete '.line[2:].'?', 1) + let force = force || answer > 1 + if answer + let err = s:rm_rf(line[2:]) + setlocal modifiable + if empty(err) + call setline(l1, '~'.line[1:]) + let s:clean_count += 1 + else + delete _ + call append(l1 - 1, s:format_message('x', line[1:], err)) + let l2 += len(s:lines(err)) + let err_count += 1 + endif + let msg = printf('Removed %d directories.', s:clean_count) + if err_count > 0 + let msg .= printf(' Failed to remove %d directories.', err_count) + endif + call setline(4, msg) + setlocal nomodifiable + endif + endif + let l1 += 1 + endwhile +endfunction + +function! s:upgrade() + echo 'Downloading the latest version of vim-plug' + redraw + let tmp = s:plug_tempname() + let new = tmp . '/plug.vim' + + try + let out = s:system(['git', 'clone', '--depth', '1', s:plug_src, tmp]) + if v:shell_error + return s:err('Error upgrading vim-plug: '. out) + endif + + if readfile(s:me) ==# readfile(new) + echo 'vim-plug is already up-to-date' + return 0 + else + call rename(s:me, s:me . '.old') + call rename(new, s:me) + unlet g:loaded_plug + echo 'vim-plug has been upgraded' + return 1 + endif + finally + silent! call s:rm_rf(tmp) + endtry +endfunction + +function! s:upgrade_specs() + for spec in values(g:plugs) + let spec.frozen = get(spec, 'frozen', 0) + endfor +endfunction + +function! s:status() + call s:prepare() + call append(0, 'Checking plugins') + call append(1, '') + + let ecnt = 0 + let unloaded = 0 + let [cnt, total] = [0, len(g:plugs)] + for [name, spec] in items(g:plugs) + let is_dir = isdirectory(spec.dir) + if has_key(spec, 'uri') + if is_dir + let [err, _] = s:git_validate(spec, 1) + let [valid, msg] = [empty(err), empty(err) ? 'OK' : err] + else + let [valid, msg] = [0, 'Not found. Try PlugInstall.'] + endif + else + if is_dir + let [valid, msg] = [1, 'OK'] + else + let [valid, msg] = [0, 'Not found.'] + endif + endif + let cnt += 1 + let ecnt += !valid + " `s:loaded` entry can be missing if PlugUpgraded + if is_dir && get(s:loaded, name, -1) == 0 + let unloaded = 1 + let msg .= ' (not loaded)' + endif + call s:progress_bar(2, repeat('=', cnt), total) + call append(3, s:format_message(valid ? '-' : 'x', name, msg)) + normal! 2G + redraw + endfor + call setline(1, 'Finished. '.ecnt.' error(s).') + normal! gg + setlocal nomodifiable + if unloaded + echo "Press 'L' on each line to load plugin, or 'U' to update" + nnoremap L :call status_load(line('.')) + xnoremap L :call status_load(line('.')) + end +endfunction + +function! s:extract_name(str, prefix, suffix) + return matchstr(a:str, '^'.a:prefix.' \zs[^:]\+\ze:.*'.a:suffix.'$') +endfunction + +function! s:status_load(lnum) + let line = getline(a:lnum) + let name = s:extract_name(line, '-', '(not loaded)') + if !empty(name) + call plug#load(name) + setlocal modifiable + call setline(a:lnum, substitute(line, ' (not loaded)$', '', '')) + setlocal nomodifiable + endif +endfunction + +function! s:status_update() range + let lines = getline(a:firstline, a:lastline) + let names = filter(map(lines, 's:extract_name(v:val, "[x-]", "")'), '!empty(v:val)') + if !empty(names) + echo + execute 'PlugUpdate' join(names) + endif +endfunction + +function! s:is_preview_window_open() + silent! wincmd P + if &previewwindow + wincmd p + return 1 + endif +endfunction + +function! s:find_name(lnum) + for lnum in reverse(range(1, a:lnum)) + let line = getline(lnum) + if empty(line) + return '' + endif + let name = s:extract_name(line, '-', '') + if !empty(name) + return name + endif + endfor + return '' +endfunction + +function! s:preview_commit() + if b:plug_preview < 0 + let b:plug_preview = !s:is_preview_window_open() + endif + + let sha = matchstr(getline('.'), '^ \X*\zs[0-9a-f]\{7,9}') + if empty(sha) + return + endif + + let name = s:find_name(line('.')) + if empty(name) || !has_key(g:plugs, name) || !isdirectory(g:plugs[name].dir) + return + endif + + if exists('g:plug_pwindow') && !s:is_preview_window_open() + execute g:plug_pwindow + execute 'e' sha + else + execute 'pedit' sha + wincmd P + endif + setlocal previewwindow filetype=git buftype=nofile nobuflisted modifiable + let batchfile = '' + try + let [sh, shellcmdflag, shrd] = s:chsh(1) + let cmd = 'cd '.plug#shellescape(g:plugs[name].dir).' && git show --no-color --pretty=medium '.sha + if s:is_win + let [batchfile, cmd] = s:batchfile(cmd) + endif + execute 'silent %!' cmd + finally + let [&shell, &shellcmdflag, &shellredir] = [sh, shellcmdflag, shrd] + if s:is_win && filereadable(batchfile) + call delete(batchfile) + endif + endtry + setlocal nomodifiable + nnoremap q :q + wincmd p +endfunction + +function! s:section(flags) + call search('\(^[x-] \)\@<=[^:]\+:', a:flags) +endfunction + +function! s:format_git_log(line) + let indent = ' ' + let tokens = split(a:line, nr2char(1)) + if len(tokens) != 5 + return indent.substitute(a:line, '\s*$', '', '') + endif + let [graph, sha, refs, subject, date] = tokens + let tag = matchstr(refs, 'tag: [^,)]\+') + let tag = empty(tag) ? ' ' : ' ('.tag.') ' + return printf('%s%s%s%s%s (%s)', indent, graph, sha, tag, subject, date) +endfunction + +function! s:append_ul(lnum, text) + call append(a:lnum, ['', a:text, repeat('-', len(a:text))]) +endfunction + +function! s:diff() + call s:prepare() + call append(0, ['Collecting changes ...', '']) + let cnts = [0, 0] + let bar = '' + let total = filter(copy(g:plugs), 's:is_managed(v:key) && isdirectory(v:val.dir)') + call s:progress_bar(2, bar, len(total)) + for origin in [1, 0] + let plugs = reverse(sort(items(filter(copy(total), (origin ? '' : '!').'(has_key(v:val, "commit") || has_key(v:val, "tag"))')))) + if empty(plugs) + continue + endif + call s:append_ul(2, origin ? 'Pending updates:' : 'Last update:') + for [k, v] in plugs + let branch = s:git_origin_branch(v) + if len(branch) + let range = origin ? '..origin/'.branch : 'HEAD@{1}..' + let cmd = ['git', 'log', '--graph', '--color=never'] + if s:git_version_requirement(2, 10, 0) + call add(cmd, '--no-show-signature') + endif + call extend(cmd, ['--pretty=format:%x01%h%x01%d%x01%s%x01%cr', range]) + if has_key(v, 'rtp') + call extend(cmd, ['--', v.rtp]) + endif + let diff = s:system_chomp(cmd, v.dir) + if !empty(diff) + let ref = has_key(v, 'tag') ? (' (tag: '.v.tag.')') : has_key(v, 'commit') ? (' '.v.commit) : '' + call append(5, extend(['', '- '.k.':'.ref], map(s:lines(diff), 's:format_git_log(v:val)'))) + let cnts[origin] += 1 + endif + endif + let bar .= '=' + call s:progress_bar(2, bar, len(total)) + normal! 2G + redraw + endfor + if !cnts[origin] + call append(5, ['', 'N/A']) + endif + endfor + call setline(1, printf('%d plugin(s) updated.', cnts[0]) + \ . (cnts[1] ? printf(' %d plugin(s) have pending updates.', cnts[1]) : '')) + + if cnts[0] || cnts[1] + nnoremap (plug-preview) :silent! call preview_commit() + if empty(maparg("\", 'n')) + nmap (plug-preview) + endif + if empty(maparg('o', 'n')) + nmap o (plug-preview) + endif + endif + if cnts[0] + nnoremap X :call revert() + echo "Press 'X' on each block to revert the update" + endif + normal! gg + setlocal nomodifiable +endfunction + +function! s:revert() + if search('^Pending updates', 'bnW') + return + endif + + let name = s:find_name(line('.')) + if empty(name) || !has_key(g:plugs, name) || + \ input(printf('Revert the update of %s? (y/N) ', name)) !~? '^y' + return + endif + + call s:system('git reset --hard HEAD@{1} && git checkout '.plug#shellescape(g:plugs[name].branch).' --', g:plugs[name].dir) + setlocal modifiable + normal! "_dap + setlocal nomodifiable + echo 'Reverted' +endfunction + +function! s:snapshot(force, ...) abort + call s:prepare() + setf vim + call append(0, ['" Generated by vim-plug', + \ '" '.strftime("%c"), + \ '" :source this file in vim to restore the snapshot', + \ '" or execute: vim -S snapshot.vim', + \ '', '', 'PlugUpdate!']) + 1 + let anchor = line('$') - 3 + let names = sort(keys(filter(copy(g:plugs), + \'has_key(v:val, "uri") && !has_key(v:val, "commit") && isdirectory(v:val.dir)'))) + for name in reverse(names) + let sha = s:git_revision(g:plugs[name].dir) + if !empty(sha) + call append(anchor, printf("silent! let g:plugs['%s'].commit = '%s'", name, sha)) + redraw + endif + endfor + + if a:0 > 0 + let fn = s:plug_expand(a:1) + if filereadable(fn) && !(a:force || s:ask(a:1.' already exists. Overwrite?')) + return + endif + call writefile(getline(1, '$'), fn) + echo 'Saved as '.a:1 + silent execute 'e' s:esc(fn) + setf vim + endif +endfunction + +function! s:split_rtp() + return split(&rtp, '\\\@ :NERDTreeToggle +" Current file in nerdtree +map :NERDTreeFind diff --git a/vim/vim/plugin/plugins.vim b/vim/vim/plugin/plugins.vim new file mode 100644 index 00000000..2f1b39f0 --- /dev/null +++ b/vim/vim/plugin/plugins.vim @@ -0,0 +1,85 @@ +call plug#begin('~/.vim/plugged') + +" Themes +" +Plug 'hzchirs/vim-material' + +" Addons +Plug 'scrooloose/nerdtree' +Plug 'yegappan/mru' +Plug 'alvan/vim-closetag' +Plug 'vim-scripts/vim-auto-save' +Plug 'airblade/vim-gitgutter' +Plug 'ervandew/supertab' +Plug 'tpope/vim-rhubarb' +Plug 'tpope/vim-repeat' +Plug 'tpope/vim-bundler' +Plug 'tpope/vim-endwise' +Plug 'tpope/vim-surround' +Plug 'tmhedberg/matchit' +Plug 'kana/vim-textobj-user' +Plug 'nelstrom/vim-textobj-rubyblock' +Plug 'ecomba/vim-ruby-refactoring' +Plug 'vim-scripts/tComment' +" Plug 'jremmen/vim-ripgrep' +Plug 'blarghmatey/split-expander' +Plug 'farmergreg/vim-lastplace' +Plug 'jlanzarotta/bufexplorer' +Plug 'jeffkreeftmeijer/vim-numbertoggle' +Plug 'roman/golden-ratio' +Plug 'fatih/vim-go', { 'do': ':GoUpdateBinaries' } +Plug 'sheerun/vim-polyglot' +Plug 'M4R7iNP/vim-inky' +Plug 'vim-airline/vim-airline' +Plug 'noscript/cSyntaxAfter' +Plug 'uiiaoo/java-syntax.vim' + +" Plug 'neoclide/coc.nvim', {'branch': 'release'} + +" +" if has('nvim') +" Plug 'Shougo/deoplete.nvim', { 'do': ':UpdateRemotePlugins' } +" else +" Plug 'Shougo/deoplete.nvim' +" Plug 'roxma/nvim-yarp' +" Plug 'roxma/vim-hug-neovim-rpc' +" endif +" let g:deoplete#enable_at_startup = 1 + + +" Tmux integration +Plug 'benmills/vimux' +Plug 'christoomey/vim-tmux-navigator' + +" File system navigation +Plug 'tpope/vim-eunuch' +Plug 'junegunn/fzf', { 'dir': '~/.fzf', 'do': './install --all' } +Plug 'junegunn/fzf.vim' + +" Syntax highlighting +" Plug 'vim-ruby/vim-ruby' +Plug 'tpope/vim-endwise' +Plug 'tpope/vim-rails' +Plug 'elzr/vim-json' +Plug 'tpope/vim-markdown' +" Plug 'groenewege/vim-less' +" Plug 'tpope/vim-haml' +" Plug 'pangloss/vim-javascript' +" Plug 'mxw/vim-jsx' +" Plug 'jparise/vim-graphql' +Plug 'leafgarland/typescript-vim' + +" Syntax errors +Plug 'vim-syntastic/syntastic' +Plug 'ntpeters/vim-better-whitespace' + +" Git support +Plug 'tpope/vim-fugitive' + +" Testing +Plug 'janko-m/vim-test' + +" Gist +Plug 'mattn/webapi-vim' | Plug 'mattn/gist-vim' + +call plug#end() diff --git a/vim/vim/plugin/vim-rails.vim b/vim/vim/plugin/vim-rails.vim new file mode 100644 index 00000000..0719e1d8 --- /dev/null +++ b/vim/vim/plugin/vim-rails.vim @@ -0,0 +1,30 @@ +" Create related file (Rails test file if missing). :AC +function! s:CreateRelated() + let related = rails#buffer().alternate_candidates()[0] + call s:Open(related) +endfunction + +function! s:Open(file) + exec('vsplit ' . a:file) +endfunction + +command! AC :call CreateRelated() + +let g:rails_projections = { + \ "app/view_models/*.rb": { + \ "command": "viewmodel", + \ "template": ["class {camelcase|capitalize|colons} < ViewModel", "end"], + \ "test": ["test/view_models/{}_test.rb"] + \ }, + \ "test/integration/*_controller_test.rb": { + \ "alternate": ["app/controllers/{}_controller.rb"] + \ }, + \ "test/integration/api/*_test.rb": { + \ "alternate": ["app/api/{}.rb"] + \ }, + \ "app/api/*.rb": { + \ "alternate": ["test/integration/api/{}_test.rb"] + \ }, + \ "app/controllers/*_controller.rb": { + \ "test": ["test/integration/{}_controller_test.rb"] + \ } } diff --git a/vim/vim/plugin/vim-ripgrep.vim b/vim/vim/plugin/vim-ripgrep.vim new file mode 100644 index 00000000..64611f77 --- /dev/null +++ b/vim/vim/plugin/vim-ripgrep.vim @@ -0,0 +1,3 @@ +" bind K to search word under cursor +nnoremap K :Rg +cnoreabbrev Ag ((getcmdtype() is# ':' && getcmdline() is# 'Ag')?('Rg'):('Ag')) diff --git a/vim/vim/plugin/vim-test.vim b/vim/vim/plugin/vim-test.vim new file mode 100644 index 00000000..62330ac6 --- /dev/null +++ b/vim/vim/plugin/vim-test.vim @@ -0,0 +1,7 @@ +let test#strategy = "vimux" +let test#runners = {'Ruby': ['GitHub']} + +nmap s :TestNearest +nmap t :TestFile +nmap a :TestSuite +nmap l :TestLast diff --git a/vim/vimrc b/vim/vimrc new file mode 100644 index 00000000..dac81bea --- /dev/null +++ b/vim/vimrc @@ -0,0 +1,135 @@ +" +" Vim settings for @mscoutermarsh +" + +" Settings in this file may depend on plugins, so let's install them first. +" Not to be confused with the contents of ~/.vim/plugin/* which are +" configuration options for each plugin and automatically loaded by Vim. +source ~/.vim/plugin/plugins.vim + +" Set leader +let mapleader = "," + +" Leader Mappings +map +map w :update +map q :qall +map gs :Gstatus + +" Recently edited files +map h :History + +" CtrlP use FZF (faster!) +nnoremap :Files + +syntax on +autocmd Filetype scss if getfsize(@%) > 300 | setlocal syntax=OFF | endif + +augroup twig_ft + au! + autocmd BufNewFile,BufRead *.html.inky set syntax=eruby +augroup END + + +set autoread " Auto reload changed files +set wildmenu " Tab autocomplete in command mode +set backspace=indent,eol,start " http://vi.stackexchange.com/a/2163 +set laststatus=2 " Show status line on startup +set splitright " Open new splits to the right +set splitbelow " Open new splits to the bottom +set lazyredraw " Reduce the redraw frequency +set ttyfast " Send more characters in fast terminals +set nowrap " Don't wrap long lines +set listchars=extends:→ " Show arrow if line continues rightwards +set listchars+=precedes:← " Show arrow if line continues leftwards +set nobackup nowritebackup noswapfile " Turn off backup files +set noerrorbells novisualbell " Turn off visual and audible bells +set expandtab shiftwidth=2 tabstop=2 " Two spaces for tabs everywhere +set history=500 +set hlsearch " Highlight search results +set ignorecase smartcase " Search queries intelligently set case +set incsearch " Show search results as you type +set timeoutlen=1000 ttimeoutlen=0 " Remove timeout when hitting escape +set showcmd " Show size of visual selection +set termguicolors + +" Persistent undo +set undodir=~/.vim/undo/ +set undofile +set undolevels=1000 +set undoreload=10000 + +" Ignored files/directories from autocomplete (and CtrlP) +set wildignore+=*/tmp/* +set wildignore+=*.so +set wildignore+=*.zip +set wildignore+=*/vendor/bundle/* +set wildignore+=*/node_modules/ + +"------------------------------------------------------------------------------- +" Interface +"------------------------------------------------------------------------------- + +set number " Enable line numbers +set scrolloff=5 " Leave 5 lines of buffer when scrolling +set sidescrolloff=10 " Leave 10 characters of horizontal buffer when scrolling + +"------------------------------------------------------------------------------- +" Colors & Formatting +"------------------------------------------------------------------------------- + +let g:material_style='oceanic' +set background=dark +colorscheme vim-material +let g:airline_theme='material' + +" Showcase comments in italics +highlight Comment cterm=italic gui=italic + +" Open most recently used files on start +" autocmd VimEnter * Mru . + +" Easy tab navigation +nnoremap :tabprevious +nnoremap :tabnext + +" Golang specific settings +let g:go_highlight_build_constraints = 1 +let g:go_highlight_extra_types = 1 +let g:go_highlight_fields = 1 +let g:go_highlight_functions = 1 +let g:go_highlight_methods = 1 +let g:go_highlight_operators = 1 +let g:go_highlight_structs = 1 +let g:go_highlight_types = 1 +let g:go_auto_type_info = 1 + +let g:go_fmt_command = "goimports" + +" Find/replace +vnoremap "hy:%s/h//g + +" let g:auto_save = 1 " enable AutoSave on Vim startup +" let g:auto_save_in_insert_mode = 0 " do not save in insert mode + +" Get off my lawn - helpful when learning Vim :) +nnoremap :echoe "Use Esc" +nnoremap :echoe "Use h" +nnoremap :echoe "Use l" +nnoremap :echoe "Use k" +nnoremap :echoe "Use j" +" +"------------------------------------------------------------------------------- +" Neovim-specific configurations +"------------------------------------------------------------------------------- + +if has('nvim') + let $NVIM_TUI_ENABLE_TRUE_COLOR=1 + set termguicolors + + " Fix vim-tmux-navigator https://git.io/viGRU + nmap h + + " Fix vim-tmux-navigator https://git.io/vS5QH + nmap :TmuxNavigateLeft +endif diff --git a/xorg/xinitrc b/xorg/xinitrc new file mode 100755 index 00000000..7441d937 --- /dev/null +++ b/xorg/xinitrc @@ -0,0 +1,34 @@ +#! /bin/sh + +#wal -sR & +#~/.scripts/toggle_monitor.sh +export DRI_PRIME=1 +feh --bg-fill /home/yigit/Pictures/Wallpapers/ocean-cliff.jpg #Backgroun +xrdb ~/.Xresources & +clipmenud > /tmp/clipmenud.out 2> /tmp/clipmenud.err & +/usr/lib/kdeconnectd & +dunst & +~/.local/dwmblocks > /tmp/dwmblocks.out 2> /tmp/dwmblocks.err & +setxkbmap tr +firefox-developer-edition & +nextcloud --background & +jetbrains-toolbox --minimize & +/usr/lib/polkit-gnome/polkit-gnome-authentication-agent-1 & +xss-lock -- betterlockscreen -l -t 'Stay the fuck out!' & +picom --no-fading-openclose & +xmodmap ~/.Xmodmap +aw-server & +aw-watcher-window & +aw-watcher-afk & +mconnect -d & +mailspring & +dbus-update-activation-environment --systemd DISPLAY +eval $(/usr/bin/gnome-keyring-daemon --start --components=pkcs11,secrets,ssh) +export SSH_AUTH_SOCK +export QT_QPA_PLATFORMTHEME="qt5ct" +if [ -f ~/.xmodmap ]; then + xmodmap ~/.xmodmap +fi +exec dwm + + diff --git a/xorg/xmodmap b/xorg/xmodmap new file mode 100644 index 00000000..365b4b4d --- /dev/null +++ b/xorg/xmodmap @@ -0,0 +1,248 @@ +keycode 8 = +keycode 9 = Escape NoSymbol Escape +keycode 10 = 1 exclam 1 exclam greater exclamdown greater +keycode 11 = 2 apostrophe 2 apostrophe sterling twosuperior sterling +keycode 12 = 3 asciicircum 3 asciicircum numbersign threesuperior numbersign +keycode 13 = 4 plus 4 plus dollar onequarter dollar +keycode 14 = 5 percent 5 percent onehalf threeeighths onehalf +keycode 15 = 6 ampersand 6 ampersand threequarters VoidSymbol threequarters +keycode 16 = 7 slash 7 slash braceleft VoidSymbol braceleft +keycode 17 = 8 parenleft 8 parenleft bracketleft VoidSymbol bracketleft +keycode 18 = 9 parenright 9 parenright bracketright plusminus bracketright +keycode 19 = 0 equal 0 equal braceright degree braceright +keycode 20 = asterisk question asterisk question backslash questiondown backslash +keycode 21 = minus underscore minus underscore bar VoidSymbol bar +keycode 22 = BackSpace BackSpace BackSpace BackSpace +keycode 23 = Tab ISO_Left_Tab Tab ISO_Left_Tab +keycode 24 = q Q q Q at Greek_OMEGA at +keycode 25 = w W w W VoidSymbol VoidSymbol VoidSymbol +keycode 26 = e E e E EuroSign VoidSymbol EuroSign +keycode 27 = r R r R paragraph registered paragraph +keycode 28 = t T t T U20BA VoidSymbol U20BA +keycode 29 = y Y y Y leftarrow yen leftarrow +keycode 30 = u U u U ucircumflex Ucircumflex ucircumflex +keycode 31 = idotless I idotless I icircumflex Icircumflex icircumflex +keycode 32 = o O o O ocircumflex Ocircumflex ocircumflex +keycode 33 = p P p P VoidSymbol VoidSymbol VoidSymbol +keycode 34 = gbreve Gbreve gbreve Gbreve dead_diaeresis dead_abovering dead_diaeresis +keycode 35 = udiaeresis Udiaeresis udiaeresis Udiaeresis asciitilde dead_macron asciitilde +keycode 36 = Return NoSymbol Return +keycode 37 = Control_L NoSymbol Control_L +keycode 38 = a A a A acircumflex Acircumflex acircumflex +keycode 39 = s S s S ssharp VoidSymbol ssharp +keycode 40 = d D d D VoidSymbol VoidSymbol VoidSymbol +keycode 41 = f F f F ordfeminine VoidSymbol ordfeminine +keycode 42 = g G g G VoidSymbol VoidSymbol VoidSymbol +keycode 43 = h H h H VoidSymbol VoidSymbol VoidSymbol +keycode 44 = j J j J dead_hook dead_horn dead_hook +keycode 45 = k K k K VoidSymbol VoidSymbol VoidSymbol +keycode 46 = l L l L VoidSymbol VoidSymbol VoidSymbol +keycode 47 = scedilla Scedilla scedilla Scedilla acute dead_acute acute +keycode 48 = i Iabovedot i Iabovedot apostrophe dead_caron apostrophe +keycode 49 = quotedbl eacute quotedbl eacute less degree less +keycode 50 = Shift_L NoSymbol Shift_L +keycode 51 = comma semicolon comma semicolon grave dead_grave grave +keycode 52 = z Z z Z guillemotleft less guillemotleft +keycode 53 = x X x X guillemotright greater guillemotright +keycode 54 = c C c C cent copyright cent +keycode 55 = v V v V leftdoublequotemark leftsinglequotemark leftdoublequotemark +keycode 56 = b B b B rightdoublequotemark rightsinglequotemark rightdoublequotemark +keycode 57 = n N n N n N n +keycode 58 = m M m M mu masculine mu +keycode 59 = odiaeresis Odiaeresis odiaeresis Odiaeresis multiply VoidSymbol multiply +keycode 60 = ccedilla Ccedilla ccedilla Ccedilla periodcentered division periodcentered +keycode 61 = period colon period colon dead_abovedot dead_abovedot dead_abovedot +keycode 62 = Shift_R NoSymbol Shift_R +keycode 63 = KP_Multiply KP_Multiply KP_Multiply KP_Multiply KP_Multiply KP_Multiply XF86ClearGrab +keycode 64 = Alt_L Meta_L Alt_L Meta_L +keycode 65 = space NoSymbol space +keycode 66 = Escape NoSymbol Escape +keycode 67 = F1 F1 F1 F1 F1 F1 XF86Switch_VT_1 +keycode 68 = F2 F2 F2 F2 F2 F2 XF86Switch_VT_2 +keycode 69 = F3 F3 F3 F3 F3 F3 XF86Switch_VT_3 +keycode 70 = F4 F4 F4 F4 F4 F4 XF86Switch_VT_4 +keycode 71 = F5 F5 F5 F5 F5 F5 XF86Switch_VT_5 +keycode 72 = F6 F6 F6 F6 F6 F6 XF86Switch_VT_6 +keycode 73 = F7 F7 F7 F7 F7 F7 XF86Switch_VT_7 +keycode 74 = F8 F8 F8 F8 F8 F8 XF86Switch_VT_8 +keycode 75 = F9 F9 F9 F9 F9 F9 XF86Switch_VT_9 +keycode 76 = F10 F10 F10 F10 F10 F10 XF86Switch_VT_10 +keycode 77 = Num_Lock NoSymbol Num_Lock +keycode 78 = Scroll_Lock NoSymbol Scroll_Lock +keycode 79 = KP_Home KP_7 KP_Home KP_7 +keycode 80 = KP_Up KP_8 KP_Up KP_8 +keycode 81 = KP_Prior KP_9 KP_Prior KP_9 +keycode 82 = KP_Subtract KP_Subtract KP_Subtract KP_Subtract KP_Subtract KP_Subtract XF86Prev_VMode +keycode 83 = KP_Left KP_4 KP_Left KP_4 +keycode 84 = KP_Begin KP_5 KP_Begin KP_5 +keycode 85 = KP_Right KP_6 KP_Right KP_6 +keycode 86 = KP_Add KP_Add KP_Add KP_Add KP_Add KP_Add XF86Next_VMode +keycode 87 = KP_End KP_1 KP_End KP_1 +keycode 88 = KP_Down KP_2 KP_Down KP_2 +keycode 89 = KP_Next KP_3 KP_Next KP_3 +keycode 90 = KP_Insert KP_0 KP_Insert KP_0 +keycode 91 = KP_Delete KP_Separator KP_Delete KP_Separator +keycode 92 = ISO_Level3_Shift NoSymbol ISO_Level3_Shift +keycode 93 = +keycode 94 = less greater less greater bar brokenbar bar +keycode 95 = F11 F11 F11 F11 F11 F11 XF86Switch_VT_11 +keycode 96 = F12 F12 F12 F12 F12 F12 XF86Switch_VT_12 +keycode 97 = +keycode 98 = Katakana NoSymbol Katakana +keycode 99 = Hiragana NoSymbol Hiragana +keycode 100 = Henkan_Mode NoSymbol Henkan_Mode +keycode 101 = Hiragana_Katakana NoSymbol Hiragana_Katakana +keycode 102 = Muhenkan NoSymbol Muhenkan +keycode 103 = +keycode 104 = KP_Enter NoSymbol KP_Enter +keycode 105 = Control_R NoSymbol Control_R +keycode 106 = KP_Divide KP_Divide KP_Divide KP_Divide KP_Divide KP_Divide XF86Ungrab +keycode 107 = Print Sys_Req Print Sys_Req +keycode 108 = ISO_Level3_Shift NoSymbol ISO_Level3_Shift +keycode 109 = Linefeed NoSymbol Linefeed +keycode 110 = Home NoSymbol Home +keycode 111 = Up NoSymbol Up +keycode 112 = Prior NoSymbol Prior +keycode 113 = Left NoSymbol Left +keycode 114 = Right NoSymbol Right +keycode 115 = End NoSymbol End +keycode 116 = Down NoSymbol Down +keycode 117 = Next NoSymbol Next +keycode 118 = Insert NoSymbol Insert +keycode 119 = Delete NoSymbol Delete +keycode 120 = +keycode 121 = XF86AudioMute NoSymbol XF86AudioMute +keycode 122 = XF86AudioLowerVolume NoSymbol XF86AudioLowerVolume +keycode 123 = XF86AudioRaiseVolume NoSymbol XF86AudioRaiseVolume +keycode 124 = XF86PowerOff NoSymbol XF86PowerOff +keycode 125 = KP_Equal NoSymbol KP_Equal +keycode 126 = plusminus NoSymbol plusminus +keycode 127 = Pause Break Pause Break +keycode 128 = XF86LaunchA NoSymbol XF86LaunchA +keycode 129 = KP_Decimal KP_Decimal KP_Decimal KP_Decimal +keycode 130 = Hangul NoSymbol Hangul +keycode 131 = Hangul_Hanja NoSymbol Hangul_Hanja +keycode 132 = +keycode 133 = Super_L NoSymbol Super_L +keycode 134 = Super_R NoSymbol Super_R +keycode 135 = Menu NoSymbol Menu +keycode 136 = Cancel NoSymbol Cancel +keycode 137 = Redo NoSymbol Redo +keycode 138 = SunProps NoSymbol SunProps +keycode 139 = Undo NoSymbol Undo +keycode 140 = SunFront NoSymbol SunFront +keycode 141 = XF86Copy NoSymbol XF86Copy +keycode 142 = XF86Open NoSymbol XF86Open +keycode 143 = XF86Paste NoSymbol XF86Paste +keycode 144 = Find NoSymbol Find +keycode 145 = XF86Cut NoSymbol XF86Cut +keycode 146 = Help NoSymbol Help +keycode 147 = XF86MenuKB NoSymbol XF86MenuKB +keycode 148 = XF86Calculator NoSymbol XF86Calculator +keycode 149 = +keycode 150 = XF86Sleep NoSymbol XF86Sleep +keycode 151 = XF86WakeUp NoSymbol XF86WakeUp +keycode 152 = XF86Explorer NoSymbol XF86Explorer +keycode 153 = XF86Send NoSymbol XF86Send +keycode 154 = +keycode 155 = XF86Xfer NoSymbol XF86Xfer +keycode 156 = XF86Launch1 NoSymbol XF86Launch1 +keycode 157 = XF86Launch2 NoSymbol XF86Launch2 +keycode 158 = XF86WWW NoSymbol XF86WWW +keycode 159 = XF86DOS NoSymbol XF86DOS +keycode 160 = XF86ScreenSaver NoSymbol XF86ScreenSaver +keycode 161 = XF86RotateWindows NoSymbol XF86RotateWindows +keycode 162 = XF86TaskPane NoSymbol XF86TaskPane +keycode 163 = XF86Mail NoSymbol XF86Mail +keycode 164 = XF86Favorites NoSymbol XF86Favorites +keycode 165 = XF86MyComputer NoSymbol XF86MyComputer +keycode 166 = XF86Back NoSymbol XF86Back +keycode 167 = XF86Forward NoSymbol XF86Forward +keycode 168 = +keycode 169 = XF86Eject NoSymbol XF86Eject +keycode 170 = XF86Eject XF86Eject XF86Eject XF86Eject +keycode 171 = XF86AudioNext NoSymbol XF86AudioNext +keycode 172 = XF86AudioPlay XF86AudioPause XF86AudioPlay XF86AudioPause +keycode 173 = XF86AudioPrev NoSymbol XF86AudioPrev +keycode 174 = XF86AudioStop XF86Eject XF86AudioStop XF86Eject +keycode 175 = XF86AudioRecord NoSymbol XF86AudioRecord +keycode 176 = XF86AudioRewind NoSymbol XF86AudioRewind +keycode 177 = XF86Phone NoSymbol XF86Phone +keycode 178 = +keycode 179 = XF86Tools NoSymbol XF86Tools +keycode 180 = XF86HomePage NoSymbol XF86HomePage +keycode 181 = XF86Reload NoSymbol XF86Reload +keycode 182 = XF86Close NoSymbol XF86Close +keycode 183 = +keycode 184 = +keycode 185 = XF86ScrollUp NoSymbol XF86ScrollUp +keycode 186 = XF86ScrollDown NoSymbol XF86ScrollDown +keycode 187 = parenleft NoSymbol parenleft +keycode 188 = parenright NoSymbol parenright +keycode 189 = XF86New NoSymbol XF86New +keycode 190 = Redo NoSymbol Redo +keycode 191 = XF86Tools NoSymbol XF86Tools +keycode 192 = XF86Launch5 NoSymbol XF86Launch5 +keycode 193 = XF86Launch6 NoSymbol XF86Launch6 +keycode 194 = XF86Launch7 NoSymbol XF86Launch7 +keycode 195 = XF86Launch8 NoSymbol XF86Launch8 +keycode 196 = XF86Launch9 NoSymbol XF86Launch9 +keycode 197 = +keycode 198 = XF86AudioMicMute NoSymbol XF86AudioMicMute +keycode 199 = XF86TouchpadToggle NoSymbol XF86TouchpadToggle +keycode 200 = XF86TouchpadOn NoSymbol XF86TouchpadOn +keycode 201 = XF86TouchpadOff NoSymbol XF86TouchpadOff +keycode 202 = +keycode 203 = Mode_switch NoSymbol Mode_switch +keycode 204 = NoSymbol Alt_L NoSymbol Alt_L +keycode 205 = NoSymbol Meta_L NoSymbol Meta_L +keycode 206 = NoSymbol Super_L NoSymbol Super_L +keycode 207 = NoSymbol Hyper_L NoSymbol Hyper_L +keycode 208 = XF86AudioPlay NoSymbol XF86AudioPlay +keycode 209 = XF86AudioPause NoSymbol XF86AudioPause +keycode 210 = XF86Launch3 NoSymbol XF86Launch3 +keycode 211 = XF86Launch4 NoSymbol XF86Launch4 +keycode 212 = XF86LaunchB NoSymbol XF86LaunchB +keycode 213 = XF86Suspend NoSymbol XF86Suspend +keycode 214 = XF86Close NoSymbol XF86Close +keycode 215 = XF86AudioPlay NoSymbol XF86AudioPlay +keycode 216 = XF86AudioForward NoSymbol XF86AudioForward +keycode 217 = +keycode 218 = Print NoSymbol Print +keycode 219 = +keycode 220 = XF86WebCam NoSymbol XF86WebCam +keycode 221 = XF86AudioPreset NoSymbol XF86AudioPreset +keycode 222 = +keycode 223 = XF86Mail NoSymbol XF86Mail +keycode 224 = XF86Messenger NoSymbol XF86Messenger +keycode 225 = XF86Search NoSymbol XF86Search +keycode 226 = XF86Go NoSymbol XF86Go +keycode 227 = XF86Finance NoSymbol XF86Finance +keycode 228 = XF86Game NoSymbol XF86Game +keycode 229 = XF86Shop NoSymbol XF86Shop +keycode 230 = +keycode 231 = Cancel NoSymbol Cancel +keycode 232 = XF86MonBrightnessDown NoSymbol XF86MonBrightnessDown +keycode 233 = XF86MonBrightnessUp NoSymbol XF86MonBrightnessUp +keycode 234 = XF86AudioMedia NoSymbol XF86AudioMedia +keycode 235 = XF86Display NoSymbol XF86Display +keycode 236 = XF86KbdLightOnOff NoSymbol XF86KbdLightOnOff +keycode 237 = XF86KbdBrightnessDown NoSymbol XF86KbdBrightnessDown +keycode 238 = XF86KbdBrightnessUp NoSymbol XF86KbdBrightnessUp +keycode 239 = XF86Send NoSymbol XF86Send +keycode 240 = XF86Reply NoSymbol XF86Reply +keycode 241 = XF86MailForward NoSymbol XF86MailForward +keycode 242 = XF86Save NoSymbol XF86Save +keycode 243 = XF86Documents NoSymbol XF86Documents +keycode 244 = XF86Battery NoSymbol XF86Battery +keycode 245 = XF86Bluetooth NoSymbol XF86Bluetooth +keycode 246 = XF86WLAN NoSymbol XF86WLAN +keycode 247 = +keycode 248 = +keycode 249 = +keycode 250 = +keycode 251 = XF86MonBrightnessCycle NoSymbol XF86MonBrightnessCycle +keycode 252 = +keycode 253 = +keycode 254 = XF86WWAN NoSymbol XF86WWAN +keycode 255 = XF86RFKill NoSymbol XF86RFKill diff --git a/zsh/antibody/p10k.zsh b/zsh/antibody/p10k.zsh new file mode 100644 index 00000000..b767a304 --- /dev/null +++ b/zsh/antibody/p10k.zsh @@ -0,0 +1,1641 @@ +# Generated by Powerlevel10k configuration wizard on 2020-07-02 at 12:51 CEST. +# Based on romkatv/powerlevel10k/config/p10k-rainbow.zsh, checksum 15764. +# Wizard options: awesome-fontconfig + powerline, large icons, rainbow, unicode, +# angled separators, sharp heads, flat tails, 1 line, compact, few icons, concise, +# transient_prompt, instant_prompt=verbose. +# Type `p10k configure` to generate another config. +# +# Config for Powerlevel10k with powerline prompt style with colorful background. +# Type `p10k configure` to generate your own config based on it. +# +# Tip: Looking for a nice color? Here's a one-liner to print colormap. +# +# for i in {0..255}; do print -Pn "%K{$i} %k%F{$i}${(l:3::0:)i}%f " ${${(M)$((i%6)):#3}:+$'\n'}; done + +# Temporarily change options. +'builtin' 'local' '-a' 'p10k_config_opts' +[[ ! -o 'aliases' ]] || p10k_config_opts+=('aliases') +[[ ! -o 'sh_glob' ]] || p10k_config_opts+=('sh_glob') +[[ ! -o 'no_brace_expand' ]] || p10k_config_opts+=('no_brace_expand') +'builtin' 'setopt' 'no_aliases' 'no_sh_glob' 'brace_expand' + +() { + emulate -L zsh -o extended_glob + + # Unset all configuration options. This allows you to apply configuration changes without + # restarting zsh. Edit ~/.p10k.zsh and type `source ~/.p10k.zsh`. + unset -m '(POWERLEVEL9K_*|DEFAULT_USER)~POWERLEVEL9K_GITSTATUS_DIR' + + # Zsh >= 5.1 is required. + autoload -Uz is-at-least && is-at-least 5.1 || return + + # The list of segments shown on the left. Fill it with the most important segments. + typeset -g POWERLEVEL9K_LEFT_PROMPT_ELEMENTS=( + os_icon # os identifier + dir # current directory + vcs # git status + #prompt_char # prompt symbol + ) + + # The list of segments shown on the right. Fill it with less important segments. + # Right prompt on the last prompt line (where you are typing your commands) gets + # automatically hidden when the input line reaches it. Right prompt above the + # last prompt line gets hidden if it would overlap with left prompt. + typeset -g POWERLEVEL9K_RIGHT_PROMPT_ELEMENTS=( + #status # exit code of the last command + command_execution_time # duration of the last command + background_jobs # presence of background jobs + direnv # direnv status (https://direnv.net/) + asdf # asdf version manager (https://github.com/asdf-vm/asdf) + virtualenv # python virtual environment (https://docs.python.org/3/library/venv.html) + anaconda # conda environment (https://conda.io/) + pyenv # python environment (https://github.com/pyenv/pyenv) + goenv # go environment (https://github.com/syndbg/goenv) + nodenv # node.js version from nodenv (https://github.com/nodenv/nodenv) + nvm # node.js version from nvm (https://github.com/nvm-sh/nvm) + nodeenv # node.js environment (https://github.com/ekalinin/nodeenv) + # node_version # node.js version + # go_version # go version (https://golang.org) + # rust_version # rustc version (https://www.rust-lang.org) + # dotnet_version # .NET version (https://dotnet.microsoft.com) + # php_version # php version (https://www.php.net/) + # laravel_version # laravel php framework version (https://laravel.com/) + # java_version # java version (https://www.java.com/) + # package # name@version from package.json (https://docs.npmjs.com/files/package.json) + rbenv # ruby version from rbenv (https://github.com/rbenv/rbenv) + rvm # ruby version from rvm (https://rvm.io) + fvm # flutter version management (https://github.com/leoafarias/fvm) + luaenv # lua version from luaenv (https://github.com/cehoffman/luaenv) + jenv # java version from jenv (https://github.com/jenv/jenv) + plenv # perl version from plenv (https://github.com/tokuhirom/plenv) + phpenv # php version from phpenv (https://github.com/phpenv/phpenv) + haskell_stack # haskell version from stack (https://haskellstack.org/) + kubecontext # current kubernetes context (https://kubernetes.io/) + terraform # terraform workspace (https://www.terraform.io) + aws # aws profile (https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-profiles.html) + aws_eb_env # aws elastic beanstalk environment (https://aws.amazon.com/elasticbeanstalk/) + azure # azure account name (https://docs.microsoft.com/en-us/cli/azure) + gcloud # google cloud cli account and project (https://cloud.google.com/) + google_app_cred # google application credentials (https://cloud.google.com/docs/authentication/production) + context # user@hostname + nordvpn # nordvpn connection status, linux only (https://nordvpn.com/) + ranger # ranger shell (https://github.com/ranger/ranger) + nnn # nnn shell (https://github.com/jarun/nnn) + vim_shell # vim shell indicator (:sh) + midnight_commander # midnight commander shell (https://midnight-commander.org/) + nix_shell # nix shell (https://nixos.org/nixos/nix-pills/developing-with-nix-shell.html) + vi_mode # vi mode (you don't need this if you've enabled prompt_char) + # vpn_ip # virtual private network indicator + # load # CPU load + # disk_usage # disk usage + # ram # free RAM + # swap # used swap + todo # todo items (https://github.com/todotxt/todo.txt-cli) + timewarrior # timewarrior tracking status (https://timewarrior.net/) + taskwarrior # taskwarrior task count (https://taskwarrior.org/) + # time # current time + # ip # ip address and bandwidth usage for a specified network interface + # public_ip # public IP address + # proxy # system-wide http/https/ftp proxy + # battery # internal battery + # wifi # wifi speed + # example # example user-defined segment (see prompt_example function below) + ) + + # Defines character set used by powerlevel10k. It's best to let `p10k configure` set it for you. + typeset -g POWERLEVEL9K_MODE=awesome-fontconfig + # When set to `moderate`, some icons will have an extra space after them. This is meant to avoid + # icon overlap when using non-monospace fonts. When set to `none`, spaces are not added. + typeset -g POWERLEVEL9K_ICON_PADDING=moderate + + # When set to true, icons appear before content on both sides of the prompt. When set + # to false, icons go after content. If empty or not set, icons go before content in the left + # prompt and after content in the right prompt. + # + # You can also override it for a specific segment: + # + # POWERLEVEL9K_STATUS_ICON_BEFORE_CONTENT=false + # + # Or for a specific segment in specific state: + # + # POWERLEVEL9K_DIR_NOT_WRITABLE_ICON_BEFORE_CONTENT=false + typeset -g POWERLEVEL9K_ICON_BEFORE_CONTENT= + + # Add an empty line before each prompt. + typeset -g POWERLEVEL9K_PROMPT_ADD_NEWLINE=true + + # Connect left prompt lines with these symbols. You'll probably want to use the same color + # as POWERLEVEL9K_MULTILINE_FIRST_PROMPT_GAP_FOREGROUND below. + typeset -g POWERLEVEL9K_MULTILINE_FIRST_PROMPT_PREFIX='%242F╭─a' + typeset -g POWERLEVEL9K_MULTILINE_NEWLINE_PROMPT_PREFIX='%242F├─' + typeset -g POWERLEVEL9K_MULTILINE_LAST_PROMPT_PREFIX='%242F╰─' + # Connect right prompt lines with these symbols. + typeset -g POWERLEVEL9K_MULTILINE_FIRST_PROMPT_SUFFIX='%242F─╮' + typeset -g POWERLEVEL9K_MULTILINE_NEWLINE_PROMPT_SUFFIX='%242F─┤' + typeset -g POWERLEVEL9K_MULTILINE_LAST_PROMPT_SUFFIX='%242F─╯' + + # Filler between left and right prompt on the first prompt line. You can set it to ' ', '·' or + # '─'. The last two make it easier to see the alignment between left and right prompt and to + # separate prompt from command output. You might want to set POWERLEVEL9K_PROMPT_ADD_NEWLINE=false + # for more compact prompt if using using this option. + typeset -g POWERLEVEL9K_MULTILINE_FIRST_PROMPT_GAP_CHAR=' ' + typeset -g POWERLEVEL9K_MULTILINE_FIRST_PROMPT_GAP_BACKGROUND= + typeset -g POWERLEVEL9K_MULTILINE_NEWLINE_PROMPT_GAP_BACKGROUND= + if [[ $POWERLEVEL9K_MULTILINE_FIRST_PROMPT_GAP_CHAR != ' ' ]]; then + # The color of the filler. You'll probably want to match the color of POWERLEVEL9K_MULTILINE + # ornaments defined above. + typeset -g POWERLEVEL9K_MULTILINE_FIRST_PROMPT_GAP_FOREGROUND=242 + # Start filler from the edge of the screen if there are no left segments on the first line. + typeset -g POWERLEVEL9K_EMPTY_LINE_LEFT_PROMPT_FIRST_SEGMENT_END_SYMBOL='%{%}' + # End filler on the edge of the screen if there are no right segments on the first line. + typeset -g POWERLEVEL9K_EMPTY_LINE_RIGHT_PROMPT_FIRST_SEGMENT_START_SYMBOL='%{%}' + fi + + # Separator between same-color segments on the left. + typeset -g POWERLEVEL9K_LEFT_SUBSEGMENT_SEPARATOR='\uE0B1' + # Separator between same-color segments on the right. + typeset -g POWERLEVEL9K_RIGHT_SUBSEGMENT_SEPARATOR='\uE0B3' + # Separator between different-color segments on the left. + typeset -g POWERLEVEL9K_LEFT_SEGMENT_SEPARATOR='\uE0B4' + # Separator between different-color segments on the right. + typeset -g POWERLEVEL9K_RIGHT_SEGMENT_SEPARATOR='\uE0B2' + # The right end of left prompt. + typeset -g POWERLEVEL9K_LEFT_PROMPT_LAST_SEGMENT_END_SYMBOL='\uE0B4' + # The left end of right prompt. + typeset -g POWERLEVEL9K_RIGHT_PROMPT_FIRST_SEGMENT_START_SYMBOL='\uE0B6' + # The left end of left prompt. + typeset -g POWERLEVEL9K_LEFT_PROMPT_FIRST_SEGMENT_START_SYMBOL='\uE0B6' + # The right end of right prompt. + typeset -g POWERLEVEL9K_RIGHT_PROMPT_LAST_SEGMENT_END_SYMBOL='\uE0B4' + # Left prompt terminator for lines without any segments. + typeset -g POWERLEVEL9K_EMPTY_LINE_LEFT_PROMPT_LAST_SEGMENT_END_SYMBOL= + + #################################[ os_icon: os identifier ]################################## + # OS identifier color. + typeset -g POWERLEVEL9K_OS_ICON_FOREGROUND=15 + typeset -g POWERLEVEL9K_OS_ICON_BACKGROUND=105 + # Custom icon. + typeset -g POWERLEVEL9K_OS_ICON_CONTENT_EXPANSION='א' + + ################################[ prompt_char: prompt symbol ]################################ + # Transparent background. + typeset -g POWERLEVEL9K_PROMPT_CHAR_BACKGROUND= + # Green prompt symbol if the last command succeeded. + typeset -g POWERLEVEL9K_PROMPT_CHAR_OK_{VIINS,VICMD,VIVIS,VIOWR}_FOREGROUND=76 + # Red prompt symbol if the last command failed. + typeset -g POWERLEVEL9K_PROMPT_CHAR_ERROR_{VIINS,VICMD,VIVIS,VIOWR}_FOREGROUND=196 + # Default prompt symbol. + typeset -g POWERLEVEL9K_PROMPT_CHAR_{OK,ERROR}_VIINS_CONTENT_EXPANSION='❯' + # Prompt symbol in command vi mode. + typeset -g POWERLEVEL9K_PROMPT_CHAR_{OK,ERROR}_VICMD_CONTENT_EXPANSION='❮' + # Prompt symbol in visual vi mode. + typeset -g POWERLEVEL9K_PROMPT_CHAR_{OK,ERROR}_VIVIS_CONTENT_EXPANSION='V' + # Prompt symbol in overwrite vi mode. + typeset -g POWERLEVEL9K_PROMPT_CHAR_{OK,ERROR}_VIOWR_CONTENT_EXPANSION='▶' + typeset -g POWERLEVEL9K_PROMPT_CHAR_OVERWRITE_STATE=true + # No line terminator if prompt_char is the last segment. + typeset -g POWERLEVEL9K_PROMPT_CHAR_LEFT_PROMPT_LAST_SEGMENT_END_SYMBOL= + # No line introducer if prompt_char is the first segment. + typeset -g POWERLEVEL9K_PROMPT_CHAR_LEFT_PROMPT_FIRST_SEGMENT_START_SYMBOL= + # No surrounding whitespace. + typeset -g POWERLEVEL9K_PROMPT_CHAR_LEFT_{LEFT,RIGHT}_WHITESPACE= + + ##################################[ dir: current directory ]################################## + # Current directory background color. + typeset -g POWERLEVEL9K_DIR_BACKGROUND=105 + # Default current directory foreground color. + typeset -g POWERLEVEL9K_DIR_FOREGROUND=15 + # If directory is too long, shorten some of its segments to the shortest possible unique + # prefix. The shortened directory can be tab-completed to the original. + typeset -g POWERLEVEL9K_SHORTEN_STRATEGY=truncate_to_unique + # Replace removed segment suffixes with this symbol. + typeset -g POWERLEVEL9K_SHORTEN_DELIMITER= + # Color of the shortened directory segments. + typeset -g POWERLEVEL9K_DIR_SHORTENED_FOREGROUND=15 + # Color of the anchor directory segments. Anchor segments are never shortened. The first + # segment is always an anchor. + typeset -g POWERLEVEL9K_DIR_ANCHOR_FOREGROUND=15 + # Display anchor directory segments in bold. + typeset -g POWERLEVEL9K_DIR_ANCHOR_BOLD=true + # Don't shorten directories that contain any of these files. They are anchors. + local anchor_files=( + .bzr + .citc + .git + .hg + .node-version + .python-version + .go-version + .ruby-version + .lua-version + .java-version + .perl-version + .php-version + .tool-version + .shorten_folder_marker + .svn + .terraform + CVS + Cargo.toml + composer.json + go.mod + package.json + stack.yaml + ) + typeset -g POWERLEVEL9K_SHORTEN_FOLDER_MARKER="(${(j:|:)anchor_files})" + # If set to "first" ("last"), remove everything before the first (last) subdirectory that contains + # files matching $POWERLEVEL9K_SHORTEN_FOLDER_MARKER. For example, when the current directory is + # /foo/bar/git_repo/nested_git_repo/baz, prompt will display git_repo/nested_git_repo/baz (first) + # or nested_git_repo/baz (last). This assumes that git_repo and nested_git_repo contain markers + # and other directories don't. + typeset -g POWERLEVEL9K_DIR_TRUNCATE_BEFORE_MARKER=false + # Don't shorten this many last directory segments. They are anchors. + typeset -g POWERLEVEL9K_SHORTEN_DIR_LENGTH=1 + # Shorten directory if it's longer than this even if there is space for it. The value can + # be either absolute (e.g., '80') or a percentage of terminal width (e.g, '50%'). If empty, + # directory will be shortened only when prompt doesn't fit or when other parameters demand it + # (see POWERLEVEL9K_DIR_MIN_COMMAND_COLUMNS and POWERLEVEL9K_DIR_MIN_COMMAND_COLUMNS_PCT below). + # If set to `0`, directory will always be shortened to its minimum length. + typeset -g POWERLEVEL9K_DIR_MAX_LENGTH=80 + # When `dir` segment is on the last prompt line, try to shorten it enough to leave at least this + # many columns for typing commands. + typeset -g POWERLEVEL9K_DIR_MIN_COMMAND_COLUMNS=40 + # When `dir` segment is on the last prompt line, try to shorten it enough to leave at least + # COLUMNS * POWERLEVEL9K_DIR_MIN_COMMAND_COLUMNS_PCT * 0.01 columns for typing commands. + typeset -g POWERLEVEL9K_DIR_MIN_COMMAND_COLUMNS_PCT=50 + # If set to true, embed a hyperlink into the directory. Useful for quickly + # opening a directory in the file manager simply by clicking the link. + # Can also be handy when the directory is shortened, as it allows you to see + # the full directory that was used in previous commands. + typeset -g POWERLEVEL9K_DIR_HYPERLINK=false + + # Enable special styling for non-writable directories. See POWERLEVEL9K_LOCK_ICON and + # POWERLEVEL9K_DIR_CLASSES below. + typeset -g POWERLEVEL9K_DIR_SHOW_WRITABLE=v2 + + # The default icon shown next to non-writable directories when POWERLEVEL9K_DIR_SHOW_WRITABLE is + # set to v2. + # typeset -g POWERLEVEL9K_LOCK_ICON='⭐' + + # POWERLEVEL9K_DIR_CLASSES allows you to specify custom icons and colors for different + # directories. It must be an array with 3 * N elements. Each triplet consists of: + # + # 1. A pattern against which the current directory ($PWD) is matched. Matching is done with + # extended_glob option enabled. + # 2. Directory class for the purpose of styling. + # 3. An empty string. + # + # Triplets are tried in order. The first triplet whose pattern matches $PWD wins. + # + # If POWERLEVEL9K_DIR_SHOW_WRITABLE is set to v2 and the current directory is not writable, + # its class gets suffix _NOT_WRITABLE. + # + # For example, given these settings: + # + # typeset -g POWERLEVEL9K_DIR_CLASSES=( + # '~/work(|/*)' WORK '' + # '~(|/*)' HOME '' + # '*' DEFAULT '') + # + # Whenever the current directory is ~/work or a subdirectory of ~/work, it gets styled with class + # WORK or WORK_NOT_WRITABLE. + # + # Simply assigning classes to directories don't have any visible effects. It merely gives you an + # option to define custom colors and icons for different directory classes. + # + # # Styling for WORK. + # typeset -g POWERLEVEL9K_DIR_WORK_VISUAL_IDENTIFIER_EXPANSION='⭐' + # typeset -g POWERLEVEL9K_DIR_WORK_BACKGROUND=4 + # typeset -g POWERLEVEL9K_DIR_WORK_FOREGROUND=254 + # typeset -g POWERLEVEL9K_DIR_WORK_SHORTENED_FOREGROUND=250 + # typeset -g POWERLEVEL9K_DIR_WORK_ANCHOR_FOREGROUND=255 + # + # # Styling for WORK_NOT_WRITABLE. + # typeset -g POWERLEVEL9K_DIR_WORK_NOT_WRITABLE_VISUAL_IDENTIFIER_EXPANSION='⭐' + # typeset -g POWERLEVEL9K_DIR_WORK_NOT_WRITABLE_BACKGROUND=4 + # typeset -g POWERLEVEL9K_DIR_WORK_NOT_WRITABLE_FOREGROUND=254 + # typeset -g POWERLEVEL9K_DIR_WORK_NOT_WRITABLE_SHORTENED_FOREGROUND=250 + # typeset -g POWERLEVEL9K_DIR_WORK_NOT_WRITABLE_ANCHOR_FOREGROUND=255 + # + # If a styling parameter isn't explicitly defined for some class, it falls back to the classless + # parameter. For example, if POWERLEVEL9K_DIR_WORK_NOT_WRITABLE_FOREGROUND is not set, it falls + # back to POWERLEVEL9K_DIR_FOREGROUND. + # + typeset -g POWERLEVEL9K_DIR_CLASSES=() + + # Custom prefix. + # typeset -g POWERLEVEL9K_DIR_PREFIX='in ' + + #####################################[ vcs: git status ]###################################### + # Version control system colors. + typeset -g POWERLEVEL9K_VCS_CLEAN_BACKGROUND=22 + typeset -g POWERLEVEL9K_VCS_MODIFIED_BACKGROUND=163 + typeset -g POWERLEVEL9K_VCS_UNTRACKED_BACKGROUND=20 + typeset -g POWERLEVEL9K_VCS_CONFLICTED_BACKGROUND=20 + typeset -g POWERLEVEL9K_VCS_LOADING_BACKGROUND=20 + + # Branch icon. Set this parameter to '\uF126 ' for the popular Powerline branch icon. + typeset -g POWERLEVEL9K_VCS_BRANCH_ICON='\uF126' + + # Untracked files icon. It's really a question mark, your font isn't broken. + # Change the value of this parameter to show a different icon. + typeset -g POWERLEVEL9K_VCS_UNTRACKED_ICON='?' + + # Formatter for Git status. + # + # Example output: master ⇣42⇡42 *42 merge ~42 +42 !42 ?42. + # + # You can edit the function to customize how Git status looks. + # + # VCS_STATUS_* parameters are set by gitstatus plugin. See reference: + # https://github.com/romkatv/gitstatus/blob/master/gitstatus.plugin.zsh. + function my_git_formatter() { + emulate -L zsh + + if [[ -n $P9K_CONTENT ]]; then + # If P9K_CONTENT is not empty, use it. It's either "loading" or from vcs_info (not from + # gitstatus plugin). VCS_STATUS_* parameters are not available in this case. + typeset -g my_git_format=$P9K_CONTENT + return + fi + + # Styling for different parts of Git status. + local meta='%255F' + local clean='%255F' + local modified='%11F' + local untracked='%11F' + local conflicted='%10F' + + local res + local where # branch or tag + if [[ -n $VCS_STATUS_LOCAL_BRANCH ]]; then + res+="${clean}${(g::)POWERLEVEL9K_VCS_BRANCH_ICON}" + where=${(V)VCS_STATUS_LOCAL_BRANCH} + elif [[ -n $VCS_STATUS_TAG ]]; then + res+="${meta}#" + where=${(V)VCS_STATUS_TAG} + fi + + # If local branch name or tag is at most 32 characters long, show it in full. + # Otherwise show the first 12 … the last 12. + # Tip: To always show local branch name in full without truncation, delete the next line. + (( $#where > 32 )) && where[13,-13]="…" + res+="${clean}${where//\%/%%}" # escape % + + # Display the current Git commit if there is no branch or tag. + # Tip: To always display the current Git commit, remove `[[ -z $where ]] &&` from the next line. + [[ -z $where ]] && res+="${meta}@${clean}${VCS_STATUS_COMMIT[1,8]}" + + # Show tracking branch name if it differs from local branch. + if [[ -n ${VCS_STATUS_REMOTE_BRANCH:#$VCS_STATUS_LOCAL_BRANCH} ]]; then + res+="${meta}:${clean}${(V)VCS_STATUS_REMOTE_BRANCH//\%/%%}" # escape % + fi + + # ⇣42 if behind the remote. + (( VCS_STATUS_COMMITS_BEHIND )) && res+=" ${clean}⇣${VCS_STATUS_COMMITS_BEHIND}" + # ⇡42 if ahead of the remote; no leading space if also behind the remote: ⇣42⇡42. + (( VCS_STATUS_COMMITS_AHEAD && !VCS_STATUS_COMMITS_BEHIND )) && res+=" " + (( VCS_STATUS_COMMITS_AHEAD )) && res+="${clean}⇡${VCS_STATUS_COMMITS_AHEAD}" + # ⇠42 if behind the push remote. + (( VCS_STATUS_PUSH_COMMITS_BEHIND )) && res+=" ${clean}⇠${VCS_STATUS_PUSH_COMMITS_BEHIND}" + (( VCS_STATUS_PUSH_COMMITS_AHEAD && !VCS_STATUS_PUSH_COMMITS_BEHIND )) && res+=" " + # ⇢42 if ahead of the push remote; no leading space if also behind: ⇠42⇢42. + (( VCS_STATUS_PUSH_COMMITS_AHEAD )) && res+="${clean}⇢${VCS_STATUS_PUSH_COMMITS_AHEAD}" + # *42 if have stashes. + (( VCS_STATUS_STASHES )) && res+=" ${clean}*${VCS_STATUS_STASHES}" + # 'merge' if the repo is in an unusual state. + [[ -n $VCS_STATUS_ACTION ]] && res+=" ${conflicted}${VCS_STATUS_ACTION}" + # ~42 if have merge conflicts. + (( VCS_STATUS_NUM_CONFLICTED )) && res+=" ${conflicted}~${VCS_STATUS_NUM_CONFLICTED}" + # +42 if have staged changes. + (( VCS_STATUS_NUM_STAGED )) && res+=" ${modified}+${VCS_STATUS_NUM_STAGED}" + # !42 if have unstaged changes. + (( VCS_STATUS_NUM_UNSTAGED )) && res+=" ${modified}!${VCS_STATUS_NUM_UNSTAGED}" + # ?42 if have untracked files. It's really a question mark, your font isn't broken. + # See POWERLEVEL9K_VCS_UNTRACKED_ICON above if you want to use a different icon. + # Remove the next line if you don't want to see untracked files at all. + (( VCS_STATUS_NUM_UNTRACKED )) && res+=" ${untracked}${(g::)POWERLEVEL9K_VCS_UNTRACKED_ICON}${VCS_STATUS_NUM_UNTRACKED}" + # "─" if the number of unstaged files is unknown. This can happen due to + # POWERLEVEL9K_VCS_MAX_INDEX_SIZE_DIRTY (see below) being set to a non-negative number lower + # than the number of files in the Git index, or due to bash.showDirtyState being set to false + # in the repository config. The number of staged and untracked files may also be unknown + # in this case. + (( VCS_STATUS_HAS_UNSTAGED == -1 )) && res+=" ${modified}─" + + typeset -g my_git_format=$res + } + functions -M my_git_formatter 2>/dev/null + + # Don't count the number of unstaged, untracked and conflicted files in Git repositories with + # more than this many files in the index. Negative value means infinity. + # + # If you are working in Git repositories with tens of millions of files and seeing performance + # sagging, try setting POWERLEVEL9K_VCS_MAX_INDEX_SIZE_DIRTY to a number lower than the output + # of `git ls-files | wc -l`. Alternatively, add `bash.showDirtyState = false` to the repository's + # config: `git config bash.showDirtyState false`. + typeset -g POWERLEVEL9K_VCS_MAX_INDEX_SIZE_DIRTY=-1 + + # Don't show Git status in prompt for repositories whose workdir matches this pattern. + # For example, if set to '~', the Git repository at $HOME/.git will be ignored. + # Multiple patterns can be combined with '|': '~(|/foo)|/bar/baz/*'. + typeset -g POWERLEVEL9K_VCS_DISABLED_WORKDIR_PATTERN='~' + + # Disable the default Git status formatting. + typeset -g POWERLEVEL9K_VCS_DISABLE_GITSTATUS_FORMATTING=true + # Install our own Git status formatter. + typeset -g POWERLEVEL9K_VCS_CONTENT_EXPANSION='${$((my_git_formatter()))+${my_git_format}}' + # Enable counters for staged, unstaged, etc. + typeset -g POWERLEVEL9K_VCS_{STAGED,UNSTAGED,UNTRACKED,CONFLICTED,COMMITS_AHEAD,COMMITS_BEHIND}_MAX_NUM=-1 + + # Custom icon. + typeset -g POWERLEVEL9K_VCS_VISUAL_IDENTIFIER_EXPANSION= + # Custom prefix. + # typeset -g POWERLEVEL9K_VCS_PREFIX='on ' + + # Show status of repositories of these types. You can add svn and/or hg if you are + # using them. If you do, your prompt may become slow even when your current directory + # isn't in an svn or hg reposotiry. + typeset -g POWERLEVEL9K_VCS_BACKENDS=(git) + + ##########################[ status: exit code of the last command ]########################### + # Enable OK_PIPE, ERROR_PIPE and ERROR_SIGNAL status states to allow us to enable, disable and + # style them independently from the regular OK and ERROR state. + typeset -g POWERLEVEL9K_STATUS_EXTENDED_STATES=true + + # Status on success. No content, just an icon. No need to show it if prompt_char is enabled as + # it will signify success by turning green. + typeset -g POWERLEVEL9K_STATUS_OK=true + typeset -g POWERLEVEL9K_STATUS_OK_VISUAL_IDENTIFIER_EXPANSION='✔' + # typeset -g POWERLEVEL9K_STATUS_OK_FOREGROUND=2 + # typeset -g POWERLEVEL9K_STATUS_OK_BACKGROUND=0 + + # Status when some part of a pipe command fails but the overall exit status is zero. It may look + # like this: 1|0. + typeset -g POWERLEVEL9K_STATUS_OK_PIPE=true + typeset -g POWERLEVEL9K_STATUS_OK_PIPE_VISUAL_IDENTIFIER_EXPANSION='✔' + # typeset -g POWERLEVEL9K_STATUS_OK_PIPE_FOREGROUND=2 + # typeset -g POWERLEVEL9K_STATUS_OK_PIPE_BACKGROUND=0 + + # Status when it's just an error code (e.g., '1'). No need to show it if prompt_char is enabled as + # it will signify error by turning red. + typeset -g POWERLEVEL9K_STATUS_ERROR=true + typeset -g POWERLEVEL9K_STATUS_ERROR_VISUAL_IDENTIFIER_EXPANSION='✘' + # typeset -g POWERLEVEL9K_STATUS_ERROR_FOREGROUND=3 + # typeset -g POWERLEVEL9K_STATUS_ERROR_BACKGROUND=1 + + # Status when the last command was terminated by a signal. + typeset -g POWERLEVEL9K_STATUS_ERROR_SIGNAL=true + # Use terse signal names: "INT" instead of "SIGINT(2)". + typeset -g POWERLEVEL9K_STATUS_VERBOSE_SIGNAME=false + typeset -g POWERLEVEL9K_STATUS_ERROR_SIGNAL_VISUAL_IDENTIFIER_EXPANSION='✘' + # typeset -g POWERLEVEL9K_STATUS_ERROR_SIGNAL_FOREGROUND=3 + # typeset -g POWERLEVEL9K_STATUS_ERROR_SIGNAL_BACKGROUND=1 + + # Status when some part of a pipe command fails and the overall exit status is also non-zero. + # It may look like this: 1|0. + typeset -g POWERLEVEL9K_STATUS_ERROR_PIPE=true + typeset -g POWERLEVEL9K_STATUS_ERROR_PIPE_VISUAL_IDENTIFIER_EXPANSION='✘' + # typeset -g POWERLEVEL9K_STATUS_ERROR_PIPE_FOREGROUND=3 + # typeset -g POWERLEVEL9K_STATUS_ERROR_PIPE_BACKGROUND=1 + + ###################[ command_execution_time: duration of the last command ]################### + # Execution time color. + typeset -g POWERLEVEL9K_COMMAND_EXECUTION_TIME_FOREGROUND=0 + typeset -g POWERLEVEL9K_COMMAND_EXECUTION_TIME_BACKGROUND=2 + # Show duration of the last command if takes longer than this many seconds. + typeset -g POWERLEVEL9K_COMMAND_EXECUTION_TIME_THRESHOLD=3 + # Show this many fractional digits. Zero means round to seconds. + typeset -g POWERLEVEL9K_COMMAND_EXECUTION_TIME_PRECISION=0 + # Duration format: 1d 2h 3m 4s. + typeset -g POWERLEVEL9K_COMMAND_EXECUTION_TIME_FORMAT='d h m s' + # Custom icon. + typeset -g POWERLEVEL9K_COMMAND_EXECUTION_TIME_VISUAL_IDENTIFIER_EXPANSION= + # Custom prefix. + # typeset -g POWERLEVEL9K_COMMAND_EXECUTION_TIME_PREFIX='took ' + + #######################[ background_jobs: presence of background jobs ]####################### + # Background jobs color. + # typeset -g POWERLEVEL9K_BACKGROUND_JOBS_FOREGROUND=6 + # typeset -g POWERLEVEL9K_BACKGROUND_JOBS_BACKGROUND=0 + # Don't show the number of background jobs. + typeset -g POWERLEVEL9K_BACKGROUND_JOBS_VERBOSE=false + # Custom icon. + # typeset -g POWERLEVEL9K_BACKGROUND_JOBS_VISUAL_IDENTIFIER_EXPANSION='⭐' + + #######################[ direnv: direnv status (https://direnv.net/) ]######################## + # Direnv color. + # typeset -g POWERLEVEL9K_DIRENV_FOREGROUND=3 + # typeset -g POWERLEVEL9K_DIRENV_BACKGROUND=0 + # Custom icon. + # typeset -g POWERLEVEL9K_DIRENV_VISUAL_IDENTIFIER_EXPANSION='⭐' + + ###############[ asdf: asdf version manager (https://github.com/asdf-vm/asdf) ]############### + # Default asdf color. Only used to display tools for which there is no color override (see below). + # Tip: Override these parameters for ${TOOL} with POWERLEVEL9K_ASDF_${TOOL}_FOREGROUND and + # POWERLEVEL9K_ASDF_${TOOL}_BACKGROUND. + typeset -g POWERLEVEL9K_ASDF_FOREGROUND=0 + typeset -g POWERLEVEL9K_ASDF_BACKGROUND=7 + + # There are four parameters that can be used to hide asdf tools. Each parameter describes + # conditions under which a tool gets hidden. Parameters can hide tools but not unhide them. If at + # least one parameter decides to hide a tool, that tool gets hidden. If no parameter decides to + # hide a tool, it gets shown. + # + # Special note on the difference between POWERLEVEL9K_ASDF_SOURCES and + # POWERLEVEL9K_ASDF_PROMPT_ALWAYS_SHOW. Consider the effect of the following commands: + # + # asdf local python 3.8.1 + # asdf global python 3.8.1 + # + # After running both commands the current python version is 3.8.1 and its source is "local" as + # it takes precedence over "global". If POWERLEVEL9K_ASDF_PROMPT_ALWAYS_SHOW is set to false, + # it'll hide python version in this case because 3.8.1 is the same as the global version. + # POWERLEVEL9K_ASDF_SOURCES will hide python version only if the value of this parameter doesn't + # contain "local". + + # Hide tool versions that don't come from one of these sources. + # + # Available sources: + # + # - shell `asdf current` says "set by ASDF_${TOOL}_VERSION environment variable" + # - local `asdf current` says "set by /some/not/home/directory/file" + # - global `asdf current` says "set by /home/username/file" + # + # Note: If this parameter is set to (shell local global), it won't hide tools. + # Tip: Override this parameter for ${TOOL} with POWERLEVEL9K_ASDF_${TOOL}_SOURCES. + typeset -g POWERLEVEL9K_ASDF_SOURCES=(shell local global) + + # If set to false, hide tool versions that are the same as global. + # + # Note: The name of this parameter doesn't reflect its meaning at all. + # Note: If this parameter is set to true, it won't hide tools. + # Tip: Override this parameter for ${TOOL} with POWERLEVEL9K_ASDF_${TOOL}_PROMPT_ALWAYS_SHOW. + typeset -g POWERLEVEL9K_ASDF_PROMPT_ALWAYS_SHOW=false + + # If set to false, hide tool versions that are equal to "system". + # + # Note: If this parameter is set to true, it won't hide tools. + # Tip: Override this parameter for ${TOOL} with POWERLEVEL9K_ASDF_${TOOL}_SHOW_SYSTEM. + typeset -g POWERLEVEL9K_ASDF_SHOW_SYSTEM=true + + # If set to non-empty value, hide tools unless there is a file matching the specified file pattern + # in the current directory, or its parent diretory, or its grandparent directory, and so on. + # + # Note: If this parameter is set to empty value, it won't hide tools. + # Note: SHOW_ON_UPGLOB isn't specific to asdf. It works with all prompt segments. + # Tip: Override this parameter for ${TOOL} with POWERLEVEL9K_ASDF_${TOOL}_SHOW_ON_UPGLOB. + # + # Example: Hide nodejs version when there is no package.json and no *.js files in the current + # directory, in `..`, in `../..` and so on. + # + # typeset -g POWERLEVEL9K_ASDF_NODEJS_SHOW_ON_UPGLOB='*.js|package.json' + typeset -g POWERLEVEL9K_ASDF_SHOW_ON_UPGLOB= + + # Ruby version from asdf. + typeset -g POWERLEVEL9K_ASDF_RUBY_FOREGROUND=0 + typeset -g POWERLEVEL9K_ASDF_RUBY_BACKGROUND=1 + # typeset -g POWERLEVEL9K_ASDF_RUBY_VISUAL_IDENTIFIER_EXPANSION='⭐' + # typeset -g POWERLEVEL9K_ASDF_RUBY_SHOW_ON_UPGLOB='*.foo|*.bar' + + # Python version from asdf. + typeset -g POWERLEVEL9K_ASDF_PYTHON_FOREGROUND=0 + typeset -g POWERLEVEL9K_ASDF_PYTHON_BACKGROUND=4 + # typeset -g POWERLEVEL9K_ASDF_PYTHON_VISUAL_IDENTIFIER_EXPANSION='⭐' + # typeset -g POWERLEVEL9K_ASDF_PYTHON_SHOW_ON_UPGLOB='*.foo|*.bar' + + # Go version from asdf. + typeset -g POWERLEVEL9K_ASDF_GOLANG_FOREGROUND=0 + typeset -g POWERLEVEL9K_ASDF_GOLANG_BACKGROUND=4 + # typeset -g POWERLEVEL9K_ASDF_GOLANG_VISUAL_IDENTIFIER_EXPANSION='⭐' + # typeset -g POWERLEVEL9K_ASDF_GOLANG_SHOW_ON_UPGLOB='*.foo|*.bar' + + # Node.js version from asdf. + typeset -g POWERLEVEL9K_ASDF_NODEJS_FOREGROUND=0 + typeset -g POWERLEVEL9K_ASDF_NODEJS_BACKGROUND=2 + # typeset -g POWERLEVEL9K_ASDF_NODEJS_VISUAL_IDENTIFIER_EXPANSION='⭐' + # typeset -g POWERLEVEL9K_ASDF_NODEJS_SHOW_ON_UPGLOB='*.foo|*.bar' + + # Rust version from asdf. + typeset -g POWERLEVEL9K_ASDF_RUST_FOREGROUND=0 + typeset -g POWERLEVEL9K_ASDF_RUST_BACKGROUND=208 + # typeset -g POWERLEVEL9K_ASDF_RUST_VISUAL_IDENTIFIER_EXPANSION='⭐' + # typeset -g POWERLEVEL9K_ASDF_RUST_SHOW_ON_UPGLOB='*.foo|*.bar' + + # .NET Core version from asdf. + typeset -g POWERLEVEL9K_ASDF_DOTNET_CORE_FOREGROUND=0 + typeset -g POWERLEVEL9K_ASDF_DOTNET_CORE_BACKGROUND=5 + # typeset -g POWERLEVEL9K_ASDF_DOTNET_CORE_VISUAL_IDENTIFIER_EXPANSION='⭐' + # typeset -g POWERLEVEL9K_ASDF_DOTNET_CORE_SHOW_ON_UPGLOB='*.foo|*.bar' + + # Flutter version from asdf. + typeset -g POWERLEVEL9K_ASDF_FLUTTER_FOREGROUND=0 + typeset -g POWERLEVEL9K_ASDF_FLUTTER_BACKGROUND=4 + # typeset -g POWERLEVEL9K_ASDF_FLUTTER_VISUAL_IDENTIFIER_EXPANSION='⭐' + # typeset -g POWERLEVEL9K_ASDF_FLUTTER_SHOW_ON_UPGLOB='*.foo|*.bar' + + # Lua version from asdf. + typeset -g POWERLEVEL9K_ASDF_LUA_FOREGROUND=0 + typeset -g POWERLEVEL9K_ASDF_LUA_BACKGROUND=4 + # typeset -g POWERLEVEL9K_ASDF_LUA_VISUAL_IDENTIFIER_EXPANSION='⭐' + # typeset -g POWERLEVEL9K_ASDF_LUA_SHOW_ON_UPGLOB='*.foo|*.bar' + + # Java version from asdf. + typeset -g POWERLEVEL9K_ASDF_JAVA_FOREGROUND=1 + typeset -g POWERLEVEL9K_ASDF_JAVA_BACKGROUND=7 + # typeset -g POWERLEVEL9K_ASDF_JAVA_VISUAL_IDENTIFIER_EXPANSION='⭐' + # typeset -g POWERLEVEL9K_ASDF_JAVA_SHOW_ON_UPGLOB='*.foo|*.bar' + + # Perl version from asdf. + typeset -g POWERLEVEL9K_ASDF_PERL_FOREGROUND=0 + typeset -g POWERLEVEL9K_ASDF_PERL_BACKGROUND=4 + # typeset -g POWERLEVEL9K_ASDF_PERL_VISUAL_IDENTIFIER_EXPANSION='⭐' + # typeset -g POWERLEVEL9K_ASDF_PERL_SHOW_ON_UPGLOB='*.foo|*.bar' + + # Erlang version from asdf. + typeset -g POWERLEVEL9K_ASDF_ERLANG_FOREGROUND=0 + typeset -g POWERLEVEL9K_ASDF_ERLANG_BACKGROUND=1 + # typeset -g POWERLEVEL9K_ASDF_ERLANG_VISUAL_IDENTIFIER_EXPANSION='⭐' + # typeset -g POWERLEVEL9K_ASDF_ERLANG_SHOW_ON_UPGLOB='*.foo|*.bar' + + # Elixir version from asdf. + typeset -g POWERLEVEL9K_ASDF_ELIXIR_FOREGROUND=0 + typeset -g POWERLEVEL9K_ASDF_ELIXIR_BACKGROUND=5 + # typeset -g POWERLEVEL9K_ASDF_ELIXIR_VISUAL_IDENTIFIER_EXPANSION='⭐' + # typeset -g POWERLEVEL9K_ASDF_ELIXIR_SHOW_ON_UPGLOB='*.foo|*.bar' + + # Postgres version from asdf. + typeset -g POWERLEVEL9K_ASDF_POSTGRES_FOREGROUND=0 + typeset -g POWERLEVEL9K_ASDF_POSTGRES_BACKGROUND=6 + # typeset -g POWERLEVEL9K_ASDF_POSTGRES_VISUAL_IDENTIFIER_EXPANSION='⭐' + # typeset -g POWERLEVEL9K_ASDF_POSTGRES_SHOW_ON_UPGLOB='*.foo|*.bar' + + # PHP version from asdf. + typeset -g POWERLEVEL9K_ASDF_PHP_FOREGROUND=0 + typeset -g POWERLEVEL9K_ASDF_PHP_BACKGROUND=5 + # typeset -g POWERLEVEL9K_ASDF_PHP_VISUAL_IDENTIFIER_EXPANSION='⭐' + # typeset -g POWERLEVEL9K_ASDF_PHP_SHOW_ON_UPGLOB='*.foo|*.bar' + + # Haskell version from asdf. + typeset -g POWERLEVEL9K_ASDF_HASKELL_FOREGROUND=0 + typeset -g POWERLEVEL9K_ASDF_HASKELL_BACKGROUND=3 + # typeset -g POWERLEVEL9K_ASDF_HASKELL_VISUAL_IDENTIFIER_EXPANSION='⭐' + # typeset -g POWERLEVEL9K_ASDF_HASKELL_SHOW_ON_UPGLOB='*.foo|*.bar' + + # Julia version from asdf. + typeset -g POWERLEVEL9K_ASDF_JULIA_FOREGROUND=0 + typeset -g POWERLEVEL9K_ASDF_JULIA_BACKGROUND=2 + # typeset -g POWERLEVEL9K_ASDF_JULIA_VISUAL_IDENTIFIER_EXPANSION='⭐' + # typeset -g POWERLEVEL9K_ASDF_JULIA_SHOW_ON_UPGLOB='*.foo|*.bar' + + ##########[ nordvpn: nordvpn connection status, linux only (https://nordvpn.com/) ]########### + # NordVPN connection indicator color. + # typeset -g POWERLEVEL9K_NORDVPN_FOREGROUND=7 + # typeset -g POWERLEVEL9K_NORDVPN_BACKGROUND=4 + # Hide NordVPN connection indicator when not connected. + typeset -g POWERLEVEL9K_NORDVPN_{DISCONNECTED,CONNECTING,DISCONNECTING}_CONTENT_EXPANSION= + typeset -g POWERLEVEL9K_NORDVPN_{DISCONNECTED,CONNECTING,DISCONNECTING}_VISUAL_IDENTIFIER_EXPANSION= + # Custom icon. + # typeset -g POWERLEVEL9K_NORDVPN_VISUAL_IDENTIFIER_EXPANSION='⭐' + + #################[ ranger: ranger shell (https://github.com/ranger/ranger) ]################## + # Ranger shell color. + # typeset -g POWERLEVEL9K_RANGER_FOREGROUND=3 + # typeset -g POWERLEVEL9K_RANGER_BACKGROUND=0 + # Custom icon. + # typeset -g POWERLEVEL9K_RANGER_VISUAL_IDENTIFIER_EXPANSION='⭐' + + ######################[ nnn: nnn shell (https://github.com/jarun/nnn) ]####################### + # Nnn shell color. + # typeset -g POWERLEVEL9K_NNN_FOREGROUND=0 + # typeset -g POWERLEVEL9K_NNN_BACKGROUND=6 + # Custom icon. + # typeset -g POWERLEVEL9K_NNN_VISUAL_IDENTIFIER_EXPANSION='⭐' + + ###########################[ vim_shell: vim shell indicator (:sh) ]########################### + # Vim shell indicator color. + # typeset -g POWERLEVEL9K_VIM_SHELL_FOREGROUND=0 + # typeset -g POWERLEVEL9K_VIM_SHELL_BACKGROUND=2 + # Custom icon. + # typeset -g POWERLEVEL9K_VIM_SHELL_VISUAL_IDENTIFIER_EXPANSION='⭐' + + ######[ midnight_commander: midnight commander shell (https://midnight-commander.org/) ]###### + # Midnight Commander shell color. + # typeset -g POWERLEVEL9K_MIDNIGHT_COMMANDER_FOREGROUND=3 + # typeset -g POWERLEVEL9K_MIDNIGHT_COMMANDER_BACKGROUND=0 + # Custom icon. + # typeset -g POWERLEVEL9K_MIDNIGHT_COMMANDER_VISUAL_IDENTIFIER_EXPANSION='⭐' + + #[ nix_shell: nix shell (https://nixos.org/nixos/nix-pills/developing-with-nix-shell.html) ]## + # Nix shell color. + # typeset -g POWERLEVEL9K_NIX_SHELL_FOREGROUND=0 + # typeset -g POWERLEVEL9K_NIX_SHELL_BACKGROUND=4 + + # Tip: If you want to see just the icon without "pure" and "impure", uncomment the next line. + # typeset -g POWERLEVEL9K_NIX_SHELL_CONTENT_EXPANSION= + + # Custom icon. + # typeset -g POWERLEVEL9K_NIX_SHELL_VISUAL_IDENTIFIER_EXPANSION='⭐' + + ##################################[ disk_usage: disk usage ]################################## + # Colors for different levels of disk usage. + # typeset -g POWERLEVEL9K_DISK_USAGE_NORMAL_FOREGROUND=3 + # typeset -g POWERLEVEL9K_DISK_USAGE_NORMAL_BACKGROUND=0 + # typeset -g POWERLEVEL9K_DISK_USAGE_WARNING_FOREGROUND=0 + # typeset -g POWERLEVEL9K_DISK_USAGE_WARNING_BACKGROUND=3 + # typeset -g POWERLEVEL9K_DISK_USAGE_CRITICAL_FOREGROUND=7 + # typeset -g POWERLEVEL9K_DISK_USAGE_CRITICAL_BACKGROUND=1 + # Thresholds for different levels of disk usage (percentage points). + typeset -g POWERLEVEL9K_DISK_USAGE_WARNING_LEVEL=90 + typeset -g POWERLEVEL9K_DISK_USAGE_CRITICAL_LEVEL=95 + # If set to true, hide disk usage when below $POWERLEVEL9K_DISK_USAGE_WARNING_LEVEL percent. + typeset -g POWERLEVEL9K_DISK_USAGE_ONLY_WARNING=false + # Custom icon. + # typeset -g POWERLEVEL9K_DISK_USAGE_VISUAL_IDENTIFIER_EXPANSION='⭐' + + ###########[ vi_mode: vi mode (you don't need this if you've enabled prompt_char) ]########### + # Foreground color. + typeset -g POWERLEVEL9K_VI_MODE_FOREGROUND=0 + # Text and color for normal (a.k.a. command) vi mode. + typeset -g POWERLEVEL9K_VI_COMMAND_MODE_STRING=NORMAL + typeset -g POWERLEVEL9K_VI_MODE_NORMAL_BACKGROUND=2 + # Text and color for visual vi mode. + typeset -g POWERLEVEL9K_VI_VISUAL_MODE_STRING=VISUAL + typeset -g POWERLEVEL9K_VI_MODE_VISUAL_BACKGROUND=4 + # Text and color for overtype (a.k.a. overwrite and replace) vi mode. + typeset -g POWERLEVEL9K_VI_OVERWRITE_MODE_STRING=OVERTYPE + typeset -g POWERLEVEL9K_VI_MODE_OVERWRITE_BACKGROUND=3 + # Text and color for insert vi mode. + typeset -g POWERLEVEL9K_VI_INSERT_MODE_STRING= + typeset -g POWERLEVEL9K_VI_MODE_INSERT_FOREGROUND=8 + + ######################################[ ram: free RAM ]####################################### + # RAM color. + # typeset -g POWERLEVEL9K_RAM_FOREGROUND=0 + # typeset -g POWERLEVEL9K_RAM_BACKGROUND=3 + # Custom icon. + # typeset -g POWERLEVEL9K_RAM_VISUAL_IDENTIFIER_EXPANSION='⭐' + + #####################################[ swap: used swap ]###################################### + # Swap color. + # typeset -g POWERLEVEL9K_SWAP_FOREGROUND=0 + # typeset -g POWERLEVEL9K_SWAP_BACKGROUND=3 + # Custom icon. + # typeset -g POWERLEVEL9K_SWAP_VISUAL_IDENTIFIER_EXPANSION='⭐' + + ######################################[ load: CPU load ]###################################### + # Show average CPU load over this many last minutes. Valid values are 1, 5 and 15. + typeset -g POWERLEVEL9K_LOAD_WHICH=5 + # Load color when load is under 50%. + # typeset -g POWERLEVEL9K_LOAD_NORMAL_FOREGROUND=0 + # typeset -g POWERLEVEL9K_LOAD_NORMAL_BACKGROUND=2 + # Load color when load is between 50% and 70%. + # typeset -g POWERLEVEL9K_LOAD_WARNING_FOREGROUND=0 + # typeset -g POWERLEVEL9K_LOAD_WARNING_BACKGROUND=3 + # Load color when load is over 70%. + # typeset -g POWERLEVEL9K_LOAD_CRITICAL_FOREGROUND=0 + # typeset -g POWERLEVEL9K_LOAD_CRITICAL_BACKGROUND=1 + # Custom icon. + # typeset -g POWERLEVEL9K_LOAD_VISUAL_IDENTIFIER_EXPANSION='⭐' + + ################[ todo: todo items (https://github.com/todotxt/todo.txt-cli) ]################ + # Todo color. + # typeset -g POWERLEVEL9K_TODO_FOREGROUND=0 + # typeset -g POWERLEVEL9K_TODO_BACKGROUND=8 + # Hide todo when the total number of tasks is zero. + typeset -g POWERLEVEL9K_TODO_HIDE_ZERO_TOTAL=true + # Hide todo when the number of tasks after filtering is zero. + typeset -g POWERLEVEL9K_TODO_HIDE_ZERO_FILTERED=false + + # Todo format. The following parameters are available within the expansion. + # + # - P9K_TODO_TOTAL_TASK_COUNT The total number of tasks. + # - P9K_TODO_FILTERED_TASK_COUNT The number of tasks after filtering. + # + # These variables correspond to the last line of the output of `todo.sh -p ls`: + # + # TODO: 24 of 42 tasks shown + # + # Here 24 is P9K_TODO_FILTERED_TASK_COUNT and 42 is P9K_TODO_TOTAL_TASK_COUNT. + # + # typeset -g POWERLEVEL9K_TODO_CONTENT_EXPANSION='$P9K_TODO_FILTERED_TASK_COUNT' + + # Custom icon. + # typeset -g POWERLEVEL9K_TODO_VISUAL_IDENTIFIER_EXPANSION='⭐' + + ###########[ timewarrior: timewarrior tracking status (https://timewarrior.net/) ]############ + # Timewarrior color. + # typeset -g POWERLEVEL9K_TIMEWARRIOR_FOREGROUND=255 + # typeset -g POWERLEVEL9K_TIMEWARRIOR_BACKGROUND=8 + + # If the tracked task is longer than 24 characters, truncate and append "…". + # Tip: To always display tasks without truncation, delete the following parameter. + # Tip: To hide task names and display just the icon when time tracking is enabled, set the + # value of the following parameter to "". + typeset -g POWERLEVEL9K_TIMEWARRIOR_CONTENT_EXPANSION='${P9K_CONTENT:0:24}${${P9K_CONTENT:24}:+…}' + + # Custom icon. + # typeset -g POWERLEVEL9K_TIMEWARRIOR_VISUAL_IDENTIFIER_EXPANSION='⭐' + + ##############[ taskwarrior: taskwarrior task count (https://taskwarrior.org/) ]############## + # Taskwarrior color. + # typeset -g POWERLEVEL9K_TASKWARRIOR_FOREGROUND=0 + # typeset -g POWERLEVEL9K_TASKWARRIOR_BACKGROUND=6 + + # Taskwarrior segment format. The following parameters are available within the expansion. + # + # - P9K_TASKWARRIOR_PENDING_COUNT The number of pending tasks: `task +PENDING count`. + # - P9K_TASKWARRIOR_OVERDUE_COUNT The number of overdue tasks: `task +OVERDUE count`. + # + # Zero values are represented as empty parameters. + # + # The default format: + # + # '${P9K_TASKWARRIOR_OVERDUE_COUNT:+"!$P9K_TASKWARRIOR_OVERDUE_COUNT/"}$P9K_TASKWARRIOR_PENDING_COUNT' + # + # typeset -g POWERLEVEL9K_TASKWARRIOR_CONTENT_EXPANSION='$P9K_TASKWARRIOR_PENDING_COUNT' + + # Custom icon. + # typeset -g POWERLEVEL9K_TASKWARRIOR_VISUAL_IDENTIFIER_EXPANSION='⭐' + + ##################################[ context: user@hostname ]################################## + # Context color when running with privileges. + typeset -g POWERLEVEL9K_CONTEXT_ROOT_FOREGROUND=1 + typeset -g POWERLEVEL9K_CONTEXT_ROOT_BACKGROUND=0 + # Context color in SSH without privileges. + typeset -g POWERLEVEL9K_CONTEXT_{REMOTE,REMOTE_SUDO}_FOREGROUND=3 + typeset -g POWERLEVEL9K_CONTEXT_{REMOTE,REMOTE_SUDO}_BACKGROUND=0 + # Default context color (no privileges, no SSH). + typeset -g POWERLEVEL9K_CONTEXT_FOREGROUND=3 + typeset -g POWERLEVEL9K_CONTEXT_BACKGROUND=0 + + # Context format when running with privileges: user@hostname. + typeset -g POWERLEVEL9K_CONTEXT_ROOT_TEMPLATE='%n@%m' + # Context format when in SSH without privileges: user@hostname. + typeset -g POWERLEVEL9K_CONTEXT_{REMOTE,REMOTE_SUDO}_TEMPLATE='%n@%m' + # Default context format (no privileges, no SSH): user@hostname. + typeset -g POWERLEVEL9K_CONTEXT_TEMPLATE='%n@%m' + + # Don't show context unless running with privileges or in SSH. + # Tip: Remove the next line to always show context. + typeset -g POWERLEVEL9K_CONTEXT_{DEFAULT,SUDO}_{CONTENT,VISUAL_IDENTIFIER}_EXPANSION= + + # Custom icon. + # typeset -g POWERLEVEL9K_CONTEXT_VISUAL_IDENTIFIER_EXPANSION='⭐' + # Custom prefix. + # typeset -g POWERLEVEL9K_CONTEXT_PREFIX='with ' + + ###[ virtualenv: python virtual environment (https://docs.python.org/3/library/venv.html) ]### + # Python virtual environment color. + # typeset -g POWERLEVEL9K_VIRTUALENV_FOREGROUND=0 + # typeset -g POWERLEVEL9K_VIRTUALENV_BACKGROUND=4 + # Don't show Python version next to the virtual environment name. + typeset -g POWERLEVEL9K_VIRTUALENV_SHOW_PYTHON_VERSION=false + # Don't show virtualenv if pyenv is already shown. + typeset -g POWERLEVEL9K_VIRTUALENV_SHOW_WITH_PYENV=false + # Separate environment name from Python version only with a space. + typeset -g POWERLEVEL9K_VIRTUALENV_{LEFT,RIGHT}_DELIMITER= + # Custom icon. + typeset -g POWERLEVEL9K_VIRTUALENV_VISUAL_IDENTIFIER_EXPANSION='🐍' + + #####################[ anaconda: conda environment (https://conda.io/) ]###################### + # Anaconda environment color. + # typeset -g POWERLEVEL9K_ANACONDA_FOREGROUND=0 + # typeset -g POWERLEVEL9K_ANACONDA_BACKGROUND=4 + + # Anaconda segment format. The following parameters are available within the expansion. + # + # - CONDA_PREFIX Absolute path to the active Anaconda/Miniconda environment. + # - CONDA_DEFAULT_ENV Name of the active Anaconda/Miniconda environment. + # - CONDA_PROMPT_MODIFIER Configurable prompt modifier (see below). + # - P9K_ANACONDA_PYTHON_VERSION Current python version (python --version). + # + # CONDA_PROMPT_MODIFIER can be configured with the following command: + # + # conda config --set env_prompt '({default_env}) ' + # + # The last argument is a Python format string that can use the following variables: + # + # - prefix The same as CONDA_PREFIX. + # - default_env The same as CONDA_DEFAULT_ENV. + # - name The last segment of CONDA_PREFIX. + # - stacked_env Comma-separated list of names in the environment stack. The first element is + # always the same as default_env. + # + # Note: '({default_env}) ' is the default value of env_prompt. + # + # The default value of POWERLEVEL9K_ANACONDA_CONTENT_EXPANSION expands to $CONDA_PROMPT_MODIFIER + # without the surrounding parentheses, or to the last path component of CONDA_PREFIX if the former + # is empty. + typeset -g POWERLEVEL9K_ANACONDA_CONTENT_EXPANSION='${${${${CONDA_PROMPT_MODIFIER#\(}% }%\)}:-${CONDA_PREFIX:t}}' + + # Custom icon. + typeset -g POWERLEVEL9K_ANACONDA_VISUAL_IDENTIFIER_EXPANSION='🐍' + + ################[ pyenv: python environment (https://github.com/pyenv/pyenv) ]################ + # Pyenv color. + # typeset -g POWERLEVEL9K_PYENV_FOREGROUND=0 + # typeset -g POWERLEVEL9K_PYENV_BACKGROUND=4 + # Hide python version if it doesn't come from one of these sources. + typeset -g POWERLEVEL9K_PYENV_SOURCES=(shell local global) + # If set to false, hide python version if it's the same as global: + # $(pyenv version-name) == $(pyenv global). + typeset -g POWERLEVEL9K_PYENV_PROMPT_ALWAYS_SHOW=false + # If set to false, hide python version if it's equal to "system". + typeset -g POWERLEVEL9K_PYENV_SHOW_SYSTEM=true + + # Pyenv segment format. The following parameters are available within the expansion. + # + # - P9K_CONTENT Current pyenv environment (pyenv version-name). + # - P9K_PYENV_PYTHON_VERSION Current python version (python --version). + # + # The default format has the following logic: + # + # 1. Display "$P9K_CONTENT $P9K_PYENV_PYTHON_VERSION" if $P9K_PYENV_PYTHON_VERSION is not + # empty and unequal to $P9K_CONTENT. + # 2. Otherwise display just "$P9K_CONTENT". + typeset -g POWERLEVEL9K_PYENV_CONTENT_EXPANSION='${P9K_CONTENT}${${P9K_PYENV_PYTHON_VERSION:#$P9K_CONTENT}:+ $P9K_PYENV_PYTHON_VERSION}' + + # Custom icon. + typeset -g POWERLEVEL9K_PYENV_VISUAL_IDENTIFIER_EXPANSION='🐍' + + ################[ goenv: go environment (https://github.com/syndbg/goenv) ]################ + # Goenv color. + # typeset -g POWERLEVEL9K_GOENV_FOREGROUND=0 + # typeset -g POWERLEVEL9K_GOENV_BACKGROUND=4 + # Hide go version if it doesn't come from one of these sources. + typeset -g POWERLEVEL9K_GOENV_SOURCES=(shell local global) + # If set to false, hide go version if it's the same as global: + # $(goenv version-name) == $(goenv global). + typeset -g POWERLEVEL9K_GOENV_PROMPT_ALWAYS_SHOW=false + # If set to false, hide go version if it's equal to "system". + typeset -g POWERLEVEL9K_GOENV_SHOW_SYSTEM=true + # Custom icon. + # typeset -g POWERLEVEL9K_GOENV_VISUAL_IDENTIFIER_EXPANSION='⭐' + + ##########[ nodenv: node.js version from nodenv (https://github.com/nodenv/nodenv) ]########## + # Nodenv color. + # typeset -g POWERLEVEL9K_NODENV_FOREGROUND=2 + # typeset -g POWERLEVEL9K_NODENV_BACKGROUND=0 + # Hide node version if it doesn't come from one of these sources. + typeset -g POWERLEVEL9K_NODENV_SOURCES=(shell local global) + # If set to false, hide node version if it's the same as global: + # $(nodenv version-name) == $(nodenv global). + typeset -g POWERLEVEL9K_NODENV_PROMPT_ALWAYS_SHOW=false + # If set to false, hide node version if it's equal to "system". + typeset -g POWERLEVEL9K_NODENV_SHOW_SYSTEM=true + # Custom icon. + # typeset -g POWERLEVEL9K_NODENV_VISUAL_IDENTIFIER_EXPANSION='⭐' + + ##############[ nvm: node.js version from nvm (https://github.com/nvm-sh/nvm) ]############### + # Nvm color. + # typeset -g POWERLEVEL9K_NVM_FOREGROUND=0 + # typeset -g POWERLEVEL9K_NVM_BACKGROUND=5 + # Custom icon. + # typeset -g POWERLEVEL9K_NVM_VISUAL_IDENTIFIER_EXPANSION='⭐' + + ############[ nodeenv: node.js environment (https://github.com/ekalinin/nodeenv) ]############ + # Nodeenv color. + # typeset -g POWERLEVEL9K_NODEENV_FOREGROUND=2 + # typeset -g POWERLEVEL9K_NODEENV_BACKGROUND=0 + # Don't show Node version next to the environment name. + typeset -g POWERLEVEL9K_NODEENV_SHOW_NODE_VERSION=false + # Separate environment name from Node version only with a space. + typeset -g POWERLEVEL9K_NODEENV_{LEFT,RIGHT}_DELIMITER= + # Custom icon. + # typeset -g POWERLEVEL9K_NODEENV_VISUAL_IDENTIFIER_EXPANSION='⭐' + + ##############################[ node_version: node.js version ]############################### + # Node version color. + # typeset -g POWERLEVEL9K_NODE_VERSION_FOREGROUND=7 + # typeset -g POWERLEVEL9K_NODE_VERSION_BACKGROUND=2 + # Show node version only when in a directory tree containing package.json. + typeset -g POWERLEVEL9K_NODE_VERSION_PROJECT_ONLY=true + # Custom icon. + # typeset -g POWERLEVEL9K_NODE_VERSION_VISUAL_IDENTIFIER_EXPANSION='⭐' + + #######################[ go_version: go version (https://golang.org) ]######################## + # Go version color. + # typeset -g POWERLEVEL9K_GO_VERSION_FOREGROUND=255 + # typeset -g POWERLEVEL9K_GO_VERSION_BACKGROUND=2 + # Show go version only when in a go project subdirectory. + typeset -g POWERLEVEL9K_GO_VERSION_PROJECT_ONLY=true + # Custom icon. + # typeset -g POWERLEVEL9K_GO_VERSION_VISUAL_IDENTIFIER_EXPANSION='⭐' + + #################[ rust_version: rustc version (https://www.rust-lang.org) ]################## + # Rust version color. + # typeset -g POWERLEVEL9K_RUST_VERSION_FOREGROUND=0 + # typeset -g POWERLEVEL9K_RUST_VERSION_BACKGROUND=208 + # Show rust version only when in a rust project subdirectory. + typeset -g POWERLEVEL9K_RUST_VERSION_PROJECT_ONLY=true + # Custom icon. + # typeset -g POWERLEVEL9K_RUST_VERSION_VISUAL_IDENTIFIER_EXPANSION='⭐' + + ###############[ dotnet_version: .NET version (https://dotnet.microsoft.com) ]################ + # .NET version color. + # typeset -g POWERLEVEL9K_DOTNET_VERSION_FOREGROUND=7 + # typeset -g POWERLEVEL9K_DOTNET_VERSION_BACKGROUND=5 + # Show .NET version only when in a .NET project subdirectory. + typeset -g POWERLEVEL9K_DOTNET_VERSION_PROJECT_ONLY=true + # Custom icon. + # typeset -g POWERLEVEL9K_DOTNET_VERSION_VISUAL_IDENTIFIER_EXPANSION='⭐' + + #####################[ php_version: php version (https://www.php.net/) ]###################### + # PHP version color. + typeset -g POWERLEVEL9K_PHP_VERSION_FOREGROUND=0 + typeset -g POWERLEVEL9K_PHP_VERSION_BACKGROUND=5 + # Show PHP version only when in a PHP project subdirectory. + typeset -g POWERLEVEL9K_PHP_VERSION_PROJECT_ONLY=true + # Custom icon. + # typeset -g POWERLEVEL9K_PHP_VERSION_VISUAL_IDENTIFIER_EXPANSION='⭐' + + ##########[ laravel_version: laravel php framework version (https://laravel.com/) ]########### + # Laravel version color. + typeset -g POWERLEVEL9K_LARAVEL_VERSION_FOREGROUND=1 + typeset -g POWERLEVEL9K_LARAVEL_VERSION_BACKGROUND=7 + # Custom icon. + # typeset -g POWERLEVEL9K_LARAVEL_VERSION_VISUAL_IDENTIFIER_EXPANSION='⭐' + + #############[ rbenv: ruby version from rbenv (https://github.com/rbenv/rbenv) ]############## + # Rbenv color. + # typeset -g POWERLEVEL9K_RBENV_FOREGROUND=0 + # typeset -g POWERLEVEL9K_RBENV_BACKGROUND=1 + # Hide ruby version if it doesn't come from one of these sources. + typeset -g POWERLEVEL9K_RBENV_SOURCES=(shell local global) + # If set to false, hide ruby version if it's the same as global: + # $(rbenv version-name) == $(rbenv global). + typeset -g POWERLEVEL9K_RBENV_PROMPT_ALWAYS_SHOW=false + # If set to false, hide ruby version if it's equal to "system". + typeset -g POWERLEVEL9K_RBENV_SHOW_SYSTEM=true + # Custom icon. + # typeset -g POWERLEVEL9K_RBENV_VISUAL_IDENTIFIER_EXPANSION='⭐' + + ####################[ java_version: java version (https://www.java.com/) ]#################### + # Java version color. + typeset -g POWERLEVEL9K_JAVA_VERSION_FOREGROUND=1 + typeset -g POWERLEVEL9K_JAVA_VERSION_BACKGROUND=7 + # Show java version only when in a java project subdirectory. + typeset -g POWERLEVEL9K_JAVA_VERSION_PROJECT_ONLY=true + # Show brief version. + typeset -g POWERLEVEL9K_JAVA_VERSION_FULL=false + # Custom icon. + # typeset -g POWERLEVEL9K_JAVA_VERSION_VISUAL_IDENTIFIER_EXPANSION='⭐' + + ###[ package: name@version from package.json (https://docs.npmjs.com/files/package.json) ]#### + # Package color. + # typeset -g POWERLEVEL9K_PACKAGE_FOREGROUND=0 + # typeset -g POWERLEVEL9K_PACKAGE_BACKGROUND=6 + + # Package format. The following parameters are available within the expansion. + # + # - P9K_PACKAGE_NAME The value of `name` field in package.json. + # - P9K_PACKAGE_VERSION The value of `version` field in package.json. + # + # typeset -g POWERLEVEL9K_PACKAGE_CONTENT_EXPANSION='${P9K_PACKAGE_NAME//\%/%%}@${P9K_PACKAGE_VERSION//\%/%%}' + + # Custom icon. + # typeset -g POWERLEVEL9K_PACKAGE_VISUAL_IDENTIFIER_EXPANSION='⭐' + + #######################[ rvm: ruby version from rvm (https://rvm.io) ]######################## + # Rvm color. + # typeset -g POWERLEVEL9K_RVM_FOREGROUND=0 + # typeset -g POWERLEVEL9K_RVM_BACKGROUND=240 + # Don't show @gemset at the end. + typeset -g POWERLEVEL9K_RVM_SHOW_GEMSET=false + # Don't show ruby- at the front. + typeset -g POWERLEVEL9K_RVM_SHOW_PREFIX=false + # Custom icon. + # typeset -g POWERLEVEL9K_RVM_VISUAL_IDENTIFIER_EXPANSION='⭐' + + ###########[ fvm: flutter version management (https://github.com/leoafarias/fvm) ]############ + # Fvm color. + # typeset -g POWERLEVEL9K_FVM_FOREGROUND=0 + # typeset -g POWERLEVEL9K_FVM_BACKGROUND=4 + # Custom icon. + # typeset -g POWERLEVEL9K_FVM_VISUAL_IDENTIFIER_EXPANSION='⭐' + + ##########[ luaenv: lua version from luaenv (https://github.com/cehoffman/luaenv) ]########### + # Lua color. + # typeset -g POWERLEVEL9K_LUAENV_FOREGROUND=0 + # typeset -g POWERLEVEL9K_LUAENV_BACKGROUND=4 + # Hide lua version if it doesn't come from one of these sources. + typeset -g POWERLEVEL9K_LUAENV_SOURCES=(shell local global) + # If set to false, hide lua version if it's the same as global: + # $(luaenv version-name) == $(luaenv global). + typeset -g POWERLEVEL9K_LUAENV_PROMPT_ALWAYS_SHOW=false + # If set to false, hide lua version if it's equal to "system". + typeset -g POWERLEVEL9K_LUAENV_SHOW_SYSTEM=true + # Custom icon. + # typeset -g POWERLEVEL9K_LUAENV_VISUAL_IDENTIFIER_EXPANSION='⭐' + + ###############[ jenv: java version from jenv (https://github.com/jenv/jenv) ]################ + # Java color. + # typeset -g POWERLEVEL9K_JENV_FOREGROUND=1 + # typeset -g POWERLEVEL9K_JENV_BACKGROUND=7 + # Hide java version if it doesn't come from one of these sources. + typeset -g POWERLEVEL9K_JENV_SOURCES=(shell local global) + # If set to false, hide java version if it's the same as global: + # $(jenv version-name) == $(jenv global). + typeset -g POWERLEVEL9K_JENV_PROMPT_ALWAYS_SHOW=false + # If set to false, hide java version if it's equal to "system". + typeset -g POWERLEVEL9K_JENV_SHOW_SYSTEM=true + # Custom icon. + # typeset -g POWERLEVEL9K_JENV_VISUAL_IDENTIFIER_EXPANSION='⭐' + + ###########[ plenv: perl version from plenv (https://github.com/tokuhirom/plenv) ]############ + # Perl color. + # typeset -g POWERLEVEL9K_PLENV_FOREGROUND=0 + # typeset -g POWERLEVEL9K_PLENV_BACKGROUND=4 + # Hide perl version if it doesn't come from one of these sources. + typeset -g POWERLEVEL9K_PLENV_SOURCES=(shell local global) + # If set to false, hide perl version if it's the same as global: + # $(plenv version-name) == $(plenv global). + typeset -g POWERLEVEL9K_PLENV_PROMPT_ALWAYS_SHOW=false + # If set to false, hide perl version if it's equal to "system". + typeset -g POWERLEVEL9K_PLENV_SHOW_SYSTEM=true + # Custom icon. + # typeset -g POWERLEVEL9K_PLENV_VISUAL_IDENTIFIER_EXPANSION='⭐' + + ############[ phpenv: php version from phpenv (https://github.com/phpenv/phpenv) ]############ + # PHP color. + # typeset -g POWERLEVEL9K_PHPENV_FOREGROUND=0 + # typeset -g POWERLEVEL9K_PHPENV_BACKGROUND=5 + # Hide php version if it doesn't come from one of these sources. + typeset -g POWERLEVEL9K_PHPENV_SOURCES=(shell local global) + # If set to false, hide php version if it's the same as global: + # $(phpenv version-name) == $(phpenv global). + typeset -g POWERLEVEL9K_PHPENV_PROMPT_ALWAYS_SHOW=false + # If set to false, hide PHP version if it's equal to "system". + typeset -g POWERLEVEL9K_PHPENV_SHOW_SYSTEM=true + # Custom icon. + # typeset -g POWERLEVEL9K_PHPENV_VISUAL_IDENTIFIER_EXPANSION='⭐' + + ##########[ haskell_stack: haskell version from stack (https://haskellstack.org/) ]########### + # Haskell color. + # typeset -g POWERLEVEL9K_HASKELL_STACK_FOREGROUND=0 + # typeset -g POWERLEVEL9K_HASKELL_STACK_BACKGROUND=3 + + # Hide haskell version if it doesn't come from one of these sources. + # + # shell: version is set by STACK_YAML + # local: version is set by stack.yaml up the directory tree + # global: version is set by the implicit global project (~/.stack/global-project/stack.yaml) + typeset -g POWERLEVEL9K_HASKELL_STACK_SOURCES=(shell local) + # If set to false, hide haskell version if it's the same as in the implicit global project. + typeset -g POWERLEVEL9K_HASKELL_STACK_ALWAYS_SHOW=true + # Custom icon. + # typeset -g POWERLEVEL9K_HASKELL_STACK_VISUAL_IDENTIFIER_EXPANSION='⭐' + + ################[ terraform: terraform workspace (https://www.terraform.io) ]################# + # POWERLEVEL9K_TERRAFORM_CLASSES is an array with even number of elements. The first element + # in each pair defines a pattern against which the current terraform workspace gets matched. + # More specifically, it's P9K_CONTENT prior to the application of context expansion (see below) + # that gets matched. If you unset all POWERLEVEL9K_TERRAFORM_*CONTENT_EXPANSION parameters, + # you'll see this value in your prompt. The second element of each pair in + # POWERLEVEL9K_TERRAFORM_CLASSES defines the workspace class. Patterns are tried in order. The + # first match wins. + # + # For example, given these settings: + # + # typeset -g POWERLEVEL9K_TERRAFORM_CLASSES=( + # '*prod*' PROD + # '*test*' TEST + # '*' DEFAULT) + # + # If your current terraform workspace is "project_test", its class is TEST because "project_test" + # doesn't match the pattern '*prod*' but does match '*test*'. + # + # You can define different colors, icons and content expansions for different classes: + # + # typeset -g POWERLEVEL9K_TERRAFORM_TEST_FOREGROUND=2 + # typeset -g POWERLEVEL9K_TERRAFORM_TEST_VISUAL_IDENTIFIER_EXPANSION='⭐' + # typeset -g POWERLEVEL9K_TERRAFORM_TEST_CONTENT_EXPANSION='> ${P9K_CONTENT} <' + typeset -g POWERLEVEL9K_TERRAFORM_CLASSES=( + # '*prod*' PROD # These values are examples that are unlikely + # '*test*' TEST # to match your needs. Customize them as needed. + '*' DEFAULT) + typeset -g POWERLEVEL9K_TERRAFORM_DEFAULT_FOREGROUND=4 + typeset -g POWERLEVEL9K_TERRAFORM_DEFAULT_BACKGROUND=0 + # typeset -g POWERLEVEL9K_TERRAFORM_DEFAULT_VISUAL_IDENTIFIER_EXPANSION='⭐' + + #############[ kubecontext: current kubernetes context (https://kubernetes.io/) ]############# + # Show kubecontext only when the the command you are typing invokes one of these tools. + # Tip: Remove the next line to always show kubecontext. + typeset -g POWERLEVEL9K_KUBECONTEXT_SHOW_ON_COMMAND='kubectl|helm|kubens|kubectx|oc|istioctl|kogito' + + # Kubernetes context classes for the purpose of using different colors, icons and expansions with + # different contexts. + # + # POWERLEVEL9K_KUBECONTEXT_CLASSES is an array with even number of elements. The first element + # in each pair defines a pattern against which the current kubernetes context gets matched. + # More specifically, it's P9K_CONTENT prior to the application of context expansion (see below) + # that gets matched. If you unset all POWERLEVEL9K_KUBECONTEXT_*CONTENT_EXPANSION parameters, + # you'll see this value in your prompt. The second element of each pair in + # POWERLEVEL9K_KUBECONTEXT_CLASSES defines the context class. Patterns are tried in order. The + # first match wins. + # + # For example, given these settings: + # + # typeset -g POWERLEVEL9K_KUBECONTEXT_CLASSES=( + # '*prod*' PROD + # '*test*' TEST + # '*' DEFAULT) + # + # If your current kubernetes context is "deathray-testing/default", its class is TEST + # because "deathray-testing/default" doesn't match the pattern '*prod*' but does match '*test*'. + # + # You can define different colors, icons and content expansions for different classes: + # + # typeset -g POWERLEVEL9K_KUBECONTEXT_TEST_FOREGROUND=0 + # typeset -g POWERLEVEL9K_KUBECONTEXT_TEST_BACKGROUND=2 + # typeset -g POWERLEVEL9K_KUBECONTEXT_TEST_VISUAL_IDENTIFIER_EXPANSION='⭐' + # typeset -g POWERLEVEL9K_KUBECONTEXT_TEST_CONTENT_EXPANSION='> ${P9K_CONTENT} <' + typeset -g POWERLEVEL9K_KUBECONTEXT_CLASSES=( + # '*prod*' PROD # These values are examples that are unlikely + # '*test*' TEST # to match your needs. Customize them as needed. + '*' DEFAULT) + typeset -g POWERLEVEL9K_KUBECONTEXT_DEFAULT_FOREGROUND=7 + typeset -g POWERLEVEL9K_KUBECONTEXT_DEFAULT_BACKGROUND=5 + # typeset -g POWERLEVEL9K_KUBECONTEXT_DEFAULT_VISUAL_IDENTIFIER_EXPANSION='⭐' + + # Use POWERLEVEL9K_KUBECONTEXT_CONTENT_EXPANSION to specify the content displayed by kubecontext + # segment. Parameter expansions are very flexible and fast, too. See reference: + # http://zsh.sourceforge.net/Doc/Release/Expansion.html#Parameter-Expansion. + # + # Within the expansion the following parameters are always available: + # + # - P9K_CONTENT The content that would've been displayed if there was no content + # expansion defined. + # - P9K_KUBECONTEXT_NAME The current context's name. Corresponds to column NAME in the + # output of `kubectl config get-contexts`. + # - P9K_KUBECONTEXT_CLUSTER The current context's cluster. Corresponds to column CLUSTER in the + # output of `kubectl config get-contexts`. + # - P9K_KUBECONTEXT_NAMESPACE The current context's namespace. Corresponds to column NAMESPACE + # in the output of `kubectl config get-contexts`. If there is no + # namespace, the parameter is set to "default". + # - P9K_KUBECONTEXT_USER The current context's user. Corresponds to column AUTHINFO in the + # output of `kubectl config get-contexts`. + # + # If the context points to Google Kubernetes Engine (GKE) or Elastic Kubernetes Service (EKS), + # the following extra parameters are available: + # + # - P9K_KUBECONTEXT_CLOUD_NAME Either "gke" or "eks". + # - P9K_KUBECONTEXT_CLOUD_ACCOUNT Account/project ID. + # - P9K_KUBECONTEXT_CLOUD_ZONE Availability zone. + # - P9K_KUBECONTEXT_CLOUD_CLUSTER Cluster. + # + # P9K_KUBECONTEXT_CLOUD_* parameters are derived from P9K_KUBECONTEXT_CLUSTER. For example, + # if P9K_KUBECONTEXT_CLUSTER is "gke_my-account_us-east1-a_my-cluster-01": + # + # - P9K_KUBECONTEXT_CLOUD_NAME=gke + # - P9K_KUBECONTEXT_CLOUD_ACCOUNT=my-account + # - P9K_KUBECONTEXT_CLOUD_ZONE=us-east1-a + # - P9K_KUBECONTEXT_CLOUD_CLUSTER=my-cluster-01 + # + # If P9K_KUBECONTEXT_CLUSTER is "arn:aws:eks:us-east-1:123456789012:cluster/my-cluster-01": + # + # - P9K_KUBECONTEXT_CLOUD_NAME=eks + # - P9K_KUBECONTEXT_CLOUD_ACCOUNT=123456789012 + # - P9K_KUBECONTEXT_CLOUD_ZONE=us-east-1 + # - P9K_KUBECONTEXT_CLOUD_CLUSTER=my-cluster-01 + typeset -g POWERLEVEL9K_KUBECONTEXT_DEFAULT_CONTENT_EXPANSION= + # Show P9K_KUBECONTEXT_CLOUD_CLUSTER if it's not empty and fall back to P9K_KUBECONTEXT_NAME. + POWERLEVEL9K_KUBECONTEXT_DEFAULT_CONTENT_EXPANSION+='${P9K_KUBECONTEXT_CLOUD_CLUSTER:-${P9K_KUBECONTEXT_NAME}}' + # Append the current context's namespace if it's not "default". + POWERLEVEL9K_KUBECONTEXT_DEFAULT_CONTENT_EXPANSION+='${${:-/$P9K_KUBECONTEXT_NAMESPACE}:#/default}' + + # Custom prefix. + # typeset -g POWERLEVEL9K_KUBECONTEXT_PREFIX='at ' + + #[ aws: aws profile (https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-profiles.html) ]# + # Show aws only when the the command you are typing invokes one of these tools. + # Tip: Remove the next line to always show aws. + typeset -g POWERLEVEL9K_AWS_SHOW_ON_COMMAND='aws|awless|terraform|pulumi' + + # POWERLEVEL9K_AWS_CLASSES is an array with even number of elements. The first element + # in each pair defines a pattern against which the current AWS profile gets matched. + # More specifically, it's P9K_CONTENT prior to the application of context expansion (see below) + # that gets matched. If you unset all POWERLEVEL9K_AWS_*CONTENT_EXPANSION parameters, + # you'll see this value in your prompt. The second element of each pair in + # POWERLEVEL9K_AWS_CLASSES defines the profile class. Patterns are tried in order. The + # first match wins. + # + # For example, given these settings: + # + # typeset -g POWERLEVEL9K_AWS_CLASSES=( + # '*prod*' PROD + # '*test*' TEST + # '*' DEFAULT) + # + # If your current AWS profile is "company_test", its class is TEST + # because "company_test" doesn't match the pattern '*prod*' but does match '*test*'. + # + # You can define different colors, icons and content expansions for different classes: + # + # typeset -g POWERLEVEL9K_AWS_TEST_FOREGROUND=28 + # typeset -g POWERLEVEL9K_AWS_TEST_VISUAL_IDENTIFIER_EXPANSION='⭐' + # typeset -g POWERLEVEL9K_AWS_TEST_CONTENT_EXPANSION='> ${P9K_CONTENT} <' + typeset -g POWERLEVEL9K_AWS_CLASSES=( + # '*prod*' PROD # These values are examples that are unlikely + # '*test*' TEST # to match your needs. Customize them as needed. + '*' DEFAULT) + # typeset -g POWERLEVEL9K_AWS_DEFAULT_FOREGROUND=7 + # typeset -g POWERLEVEL9K_AWS_DEFAULT_BACKGROUND=1 + # typeset -g POWERLEVEL9K_AWS_DEFAULT_VISUAL_IDENTIFIER_EXPANSION='⭐' + + #[ aws_eb_env: aws elastic beanstalk environment (https://aws.amazon.com/elasticbeanstalk/) ]# + # AWS Elastic Beanstalk environment color. + # typeset -g POWERLEVEL9K_AWS_EB_ENV_FOREGROUND=2 + # typeset -g POWERLEVEL9K_AWS_EB_ENV_BACKGROUND=0 + # Custom icon. + # typeset -g POWERLEVEL9K_AWS_EB_ENV_VISUAL_IDENTIFIER_EXPANSION='⭐' + + ##########[ azure: azure account name (https://docs.microsoft.com/en-us/cli/azure) ]########## + # Show azure only when the the command you are typing invokes one of these tools. + # Tip: Remove the next line to always show azure. + typeset -g POWERLEVEL9K_AZURE_SHOW_ON_COMMAND='az|terraform|pulumi' + # Azure account name color. + # typeset -g POWERLEVEL9K_AZURE_FOREGROUND=7 + # typeset -g POWERLEVEL9K_AZURE_BACKGROUND=4 + # Custom icon. + # typeset -g POWERLEVEL9K_AZURE_VISUAL_IDENTIFIER_EXPANSION='⭐' + + ##########[ gcloud: google cloud account and project (https://cloud.google.com/) ]########### + # Show gcloud only when the the command you are typing invokes one of these tools. + # Tip: Remove the next line to always show gcloud. + typeset -g POWERLEVEL9K_GCLOUD_SHOW_ON_COMMAND='gcloud|gcs' + # Google cloud color. + # typeset -g POWERLEVEL9K_GCLOUD_FOREGROUND=7 + # typeset -g POWERLEVEL9K_GCLOUD_BACKGROUND=4 + + # Google cloud format. Change the value of POWERLEVEL9K_GCLOUD_PARTIAL_CONTENT_EXPANSION and/or + # POWERLEVEL9K_GCLOUD_COMPLETE_CONTENT_EXPANSION if the default is too verbose or not informative + # enough. You can use the following parameters in the expansions. Each of them corresponds to the + # output of `gcloud` tool. + # + # Parameter | Source + # -------------------------|-------------------------------------------------------------------- + # P9K_GCLOUD_CONFIGURATION | gcloud config configurations list --format='value(name)' + # P9K_GCLOUD_ACCOUNT | gcloud config get-value account + # P9K_GCLOUD_PROJECT_ID | gcloud config get-value project + # P9K_GCLOUD_PROJECT_NAME | gcloud projects describe $P9K_GCLOUD_PROJECT_ID --format='value(name)' + # + # Note: ${VARIABLE//\%/%%} expands to ${VARIABLE} with all occurences of '%' replaced with '%%'. + # + # Obtaining project name requires sending a request to Google servers. This can take a long time + # and even fail. When project name is unknown, P9K_GCLOUD_PROJECT_NAME is not set and gcloud + # prompt segment is in state PARTIAL. When project name gets known, P9K_GCLOUD_PROJECT_NAME gets + # set and gcloud prompt segment transitions to state COMPLETE. + # + # You can customize the format, icon and colors of gcloud segment separately for states PARTIAL + # and COMPLETE. You can also hide gcloud in state PARTIAL by setting + # POWERLEVEL9K_GCLOUD_PARTIAL_VISUAL_IDENTIFIER_EXPANSION and + # POWERLEVEL9K_GCLOUD_PARTIAL_CONTENT_EXPANSION to empty. + typeset -g POWERLEVEL9K_GCLOUD_PARTIAL_CONTENT_EXPANSION='${P9K_GCLOUD_PROJECT_ID//\%/%%}' + typeset -g POWERLEVEL9K_GCLOUD_COMPLETE_CONTENT_EXPANSION='${P9K_GCLOUD_PROJECT_NAME//\%/%%}' + + # Send a request to Google (by means of `gcloud projects describe ...`) to obtain project name + # this often. Negative value disables periodic polling. In this mode project name is retrieved + # only when the current configuration, account or project id changes. + typeset -g POWERLEVEL9K_GCLOUD_REFRESH_PROJECT_NAME_SECONDS=60 + + # Custom icon. + # typeset -g POWERLEVEL9K_GCLOUD_VISUAL_IDENTIFIER_EXPANSION='⭐' + + #[ google_app_cred: google application credentials (https://cloud.google.com/docs/authentication/production) ]# + # Show google_app_cred only when the the command you are typing invokes one of these tools. + # Tip: Remove the next line to always show google_app_cred. + typeset -g POWERLEVEL9K_GOOGLE_APP_CRED_SHOW_ON_COMMAND='terraform|pulumi' + + # Google application credentials classes for the purpose of using different colors, icons and + # expansions with different credentials. + # + # POWERLEVEL9K_GOOGLE_APP_CRED_CLASSES is an array with even number of elements. The first + # element in each pair defines a pattern against which the current kubernetes context gets + # matched. More specifically, it's P9K_CONTENT prior to the application of context expansion + # (see below) that gets matched. If you unset all POWERLEVEL9K_GOOGLE_APP_CRED_*CONTENT_EXPANSION + # parameters, you'll see this value in your prompt. The second element of each pair in + # POWERLEVEL9K_GOOGLE_APP_CRED_CLASSES defines the context class. Patterns are tried in order. + # The first match wins. + # + # For example, given these settings: + # + # typeset -g POWERLEVEL9K_GOOGLE_APP_CRED_CLASSES=( + # '*:*prod*:*' PROD + # '*:*test*:*' TEST + # '*' DEFAULT) + # + # If your current Google application credentials is "service_account deathray-testing x@y.com", + # its class is TEST because it doesn't match the pattern '* *prod* *' but does match '* *test* *'. + # + # You can define different colors, icons and content expansions for different classes: + # + # typeset -g POWERLEVEL9K_GOOGLE_APP_CRED_TEST_FOREGROUND=28 + # typeset -g POWERLEVEL9K_GOOGLE_APP_CRED_TEST_VISUAL_IDENTIFIER_EXPANSION='⭐' + # typeset -g POWERLEVEL9K_GOOGLE_APP_CRED_TEST_CONTENT_EXPANSION='$P9K_GOOGLE_APP_CRED_PROJECT_ID' + typeset -g POWERLEVEL9K_GOOGLE_APP_CRED_CLASSES=( + # '*:*prod*:*' PROD # These values are examples that are unlikely + # '*:*test*:*' TEST # to match your needs. Customize them as needed. + '*' DEFAULT) + # typeset -g POWERLEVEL9K_GOOGLE_APP_CRED_DEFAULT_FOREGROUND=7 + # typeset -g POWERLEVEL9K_GOOGLE_APP_CRED_DEFAULT_BACKGROUND=4 + # typeset -g POWERLEVEL9K_GOOGLE_APP_CRED_DEFAULT_VISUAL_IDENTIFIER_EXPANSION='⭐' + + # Use POWERLEVEL9K_GOOGLE_APP_CRED_CONTENT_EXPANSION to specify the content displayed by + # google_app_cred segment. Parameter expansions are very flexible and fast, too. See reference: + # http://zsh.sourceforge.net/Doc/Release/Expansion.html#Parameter-Expansion. + # + # You can use the following parameters in the expansion. Each of them corresponds to one of the + # fields in the JSON file pointed to by GOOGLE_APPLICATION_CREDENTIALS. + # + # Parameter | JSON key file field + # ---------------------------------+--------------- + # P9K_GOOGLE_APP_CRED_TYPE | type + # P9K_GOOGLE_APP_CRED_PROJECT_ID | project_id + # P9K_GOOGLE_APP_CRED_CLIENT_EMAIL | client_email + # + # Note: ${VARIABLE//\%/%%} expands to ${VARIABLE} with all occurences of '%' replaced by '%%'. + typeset -g POWERLEVEL9K_GOOGLE_APP_CRED_DEFAULT_CONTENT_EXPANSION='${P9K_GOOGLE_APP_CRED_PROJECT_ID//\%/%%}' + + ###############################[ public_ip: public IP address ]############################### + # Public IP color. + # typeset -g POWERLEVEL9K_PUBLIC_IP_FOREGROUND=7 + # typeset -g POWERLEVEL9K_PUBLIC_IP_BACKGROUND=0 + # Custom icon. + # typeset -g POWERLEVEL9K_PUBLIC_IP_VISUAL_IDENTIFIER_EXPANSION='⭐' + + ########################[ vpn_ip: virtual private network indicator ]######################### + # VPN IP color. + # typeset -g POWERLEVEL9K_VPN_IP_FOREGROUND=0 + # typeset -g POWERLEVEL9K_VPN_IP_BACKGROUND=6 + # When on VPN, show just an icon without the IP address. + # Tip: To display the private IP address when on VPN, remove the next line. + typeset -g POWERLEVEL9K_VPN_IP_CONTENT_EXPANSION= + # Regular expression for the VPN network interface. Run `ifconfig` or `ip -4 a show` while on VPN + # to see the name of the interface. + typeset -g POWERLEVEL9K_VPN_IP_INTERFACE='(wg|(.*tun))[0-9]*' + # If set to true, show one segment per matching network interface. If set to false, show only + # one segment corresponding to the first matching network interface. + # Tip: If you set it to true, you'll probably want to unset POWERLEVEL9K_VPN_IP_CONTENT_EXPANSION. + typeset -g POWERLEVEL9K_VPN_IP_SHOW_ALL=false + # Custom icon. + # typeset -g POWERLEVEL9K_VPN_IP_VISUAL_IDENTIFIER_EXPANSION='⭐' + + ###########[ ip: ip address and bandwidth usage for a specified network interface ]########### + # IP color. + typeset -g POWERLEVEL9K_IP_BACKGROUND=4 + typeset -g POWERLEVEL9K_IP_FOREGROUND=0 + # The following parameters are accessible within the expansion: + # + # Parameter | Meaning + # ----------------------+--------------- + # P9K_IP_IP | IP address + # P9K_IP_INTERFACE | network interface + # P9K_IP_RX_BYTES | total number of bytes received + # P9K_IP_TX_BYTES | total number of bytes sent + # P9K_IP_RX_RATE | receive rate (since last prompt) + # P9K_IP_TX_RATE | send rate (since last prompt) + typeset -g POWERLEVEL9K_IP_CONTENT_EXPANSION='${P9K_IP_RX_RATE:+⇣$P9K_IP_RX_RATE }${P9K_IP_TX_RATE:+⇡$P9K_IP_TX_RATE }$P9K_IP_IP' + # Show information for the first network interface whose name matches this regular expression. + # Run `ifconfig` or `ip -4 a show` to see the names of all network interfaces. + typeset -g POWERLEVEL9K_IP_INTERFACE='e.*' + # Custom icon. + # typeset -g POWERLEVEL9K_IP_VISUAL_IDENTIFIER_EXPANSION='⭐' + + #########################[ proxy: system-wide http/https/ftp proxy ]########################## + # Proxy color. + # typeset -g POWERLEVEL9K_PROXY_FOREGROUND=4 + # typeset -g POWERLEVEL9K_PROXY_BACKGROUND=0 + # Custom icon. + # typeset -g POWERLEVEL9K_PROXY_VISUAL_IDENTIFIER_EXPANSION='⭐' + + ################################[ battery: internal battery ]################################# + # Show battery in red when it's below this level and not connected to power supply. + typeset -g POWERLEVEL9K_BATTERY_LOW_THRESHOLD=20 + typeset -g POWERLEVEL9K_BATTERY_LOW_FOREGROUND=1 + # Show battery in green when it's charging or fully charged. + typeset -g POWERLEVEL9K_BATTERY_{CHARGING,CHARGED}_FOREGROUND=2 + # Show battery in yellow when it's discharging. + typeset -g POWERLEVEL9K_BATTERY_DISCONNECTED_FOREGROUND=3 + # Battery pictograms going from low to high level of charge. + typeset -g POWERLEVEL9K_BATTERY_STAGES=('%K{232}▁' '%K{232}▂' '%K{232}▃' '%K{232}▄' '%K{232}▅' '%K{232}▆' '%K{232}▇' '%K{232}█') + # Don't show the remaining time to charge/discharge. + typeset -g POWERLEVEL9K_BATTERY_VERBOSE=false + # typeset -g POWERLEVEL9K_BATTERY_BACKGROUND=0 + + #####################################[ wifi: wifi speed ]##################################### + # WiFi color. + # typeset -g POWERLEVEL9K_WIFI_FOREGROUND=0 + # typeset -g POWERLEVEL9K_WIFI_BACKGROUND=4 + # Custom icon. + # typeset -g POWERLEVEL9K_WIFI_VISUAL_IDENTIFIER_EXPANSION='⭐' + + # Use different colors and icons depending on signal strength ($P9K_WIFI_BARS). + # + # # Wifi colors and icons for different signal strength levels (low to high). + # typeset -g my_wifi_fg=(0 0 0 0 0) # <-- change these values + # typeset -g my_wifi_icon=('WiFi' 'WiFi' 'WiFi' 'WiFi' 'WiFi') # <-- change these values + # + # typeset -g POWERLEVEL9K_WIFI_CONTENT_EXPANSION='%F{${my_wifi_fg[P9K_WIFI_BARS+1]}}$P9K_WIFI_LAST_TX_RATE Mbps' + # typeset -g POWERLEVEL9K_WIFI_VISUAL_IDENTIFIER_EXPANSION='%F{${my_wifi_fg[P9K_WIFI_BARS+1]}}${my_wifi_icon[P9K_WIFI_BARS+1]}' + # + # The following parameters are accessible within the expansions: + # + # Parameter | Meaning + # ----------------------+--------------- + # P9K_WIFI_SSID | service set identifier, a.k.a. network name + # P9K_WIFI_LINK_AUTH | authentication protocol such as "wpa2-psk" or "none" + # P9K_WIFI_LAST_TX_RATE | wireless transmit rate in megabits per second + # P9K_WIFI_RSSI | signal strength in dBm, from -120 to 0 + # P9K_WIFI_NOISE | noise in dBm, from -120 to 0 + # P9K_WIFI_BARS | signal strength in bars, from 0 to 4 (derived from P9K_WIFI_RSSI and P9K_WIFI_NOISE) + # + # All parameters except P9K_WIFI_BARS are extracted from the output of the following command: + # + # /System/Library/PrivateFrameworks/Apple80211.framework/Versions/Current/Resources/airport -I + + ####################################[ time: current time ]#################################### + # Current time color. + # typeset -g POWERLEVEL9K_TIME_FOREGROUND=0 + # typeset -g POWERLEVEL9K_TIME_BACKGROUND=7 + # Format for the current time: 09:51:02. See `man 3 strftime`. + typeset -g POWERLEVEL9K_TIME_FORMAT='%D{%H:%M:%S}' + # If set to true, time will update when you hit enter. This way prompts for the past + # commands will contain the start times of their commands as opposed to the default + # behavior where they contain the end times of their preceding commands. + typeset -g POWERLEVEL9K_TIME_UPDATE_ON_COMMAND=false + # Custom icon. + typeset -g POWERLEVEL9K_TIME_VISUAL_IDENTIFIER_EXPANSION= + # Custom prefix. + # typeset -g POWERLEVEL9K_TIME_PREFIX='at ' + + # Example of a user-defined prompt segment. Function prompt_example will be called on every + # prompt if `example` prompt segment is added to POWERLEVEL9K_LEFT_PROMPT_ELEMENTS or + # POWERLEVEL9K_RIGHT_PROMPT_ELEMENTS. It displays an icon and yellow text on red background + # greeting the user. + # + # Type `p10k help segment` for documentation and a more sophisticated example. + function prompt_example() { + p10k segment -b 1 -f 3 -i '⭐' -t 'hello, %n' + } + + # User-defined prompt segments may optionally provide an instant_prompt_* function. Its job + # is to generate the prompt segment for display in instant prompt. See + # https://github.com/romkatv/powerlevel10k/blob/master/README.md#instant-prompt. + # + # Powerlevel10k will call instant_prompt_* at the same time as the regular prompt_* function + # and will record all `p10k segment` calls it makes. When displaying instant prompt, Powerlevel10k + # will replay these calls without actually calling instant_prompt_*. It is imperative that + # instant_prompt_* always makes the same `p10k segment` calls regardless of environment. If this + # rule is not observed, the content of instant prompt will be incorrect. + # + # Usually, you should either not define instant_prompt_* or simply call prompt_* from it. If + # instant_prompt_* is not defined for a segment, the segment won't be shown in instant prompt. + function instant_prompt_example() { + # Since prompt_example always makes the same `p10k segment` calls, we can call it from + # instant_prompt_example. This will give us the same `example` prompt segment in the instant + # and regular prompts. + prompt_example + } + + # User-defined prompt segments can be customized the same way as built-in segments. + # typeset -g POWERLEVEL9K_EXAMPLE_FOREGROUND=3 + # typeset -g POWERLEVEL9K_EXAMPLE_VISUAL_IDENTIFIER_EXPANSION='⭐' + + # Transient prompt works similarly to the builtin transient_rprompt option. It trims down prompt + # when accepting a command line. Supported values: + # + # - off: Don't change prompt when accepting a command line. + # - always: Trim down prompt when accepting a command line. + # - same-dir: Trim down prompt when accepting a command line unless this is the first command + # typed after changing current working directory. + typeset -g POWERLEVEL9K_TRANSIENT_PROMPT=off + + # Instant prompt mode. + # + # - off: Disable instant prompt. Choose this if you've tried instant prompt and found + # it incompatible with your zsh configuration files. + # - quiet: Enable instant prompt and don't print warnings when detecting console output + # during zsh initialization. Choose this if you've read and understood + # https://github.com/romkatv/powerlevel10k/blob/master/README.md#instant-prompt. + # - verbose: Enable instant prompt and print a warning when detecting console output during + # zsh initialization. Choose this if you've never tried instant prompt, haven't + # seen the warning, or if you are unsure what this all means. + typeset -g POWERLEVEL9K_INSTANT_PROMPT=verbose + + # Hot reload allows you to change POWERLEVEL9K options after Powerlevel10k has been initialized. + # For example, you can type POWERLEVEL9K_BACKGROUND=red and see your prompt turn red. Hot reload + # can slow down prompt by 1-2 milliseconds, so it's better to keep it turned off unless you + # really need it. + typeset -g POWERLEVEL9K_DISABLE_HOT_RELOAD=true + + # If p10k is already loaded, reload configuration. + # This works even with POWERLEVEL9K_DISABLE_HOT_RELOAD=true. + (( ! $+functions[p10k] )) || p10k reload +} + +# Tell `p10k configure` which file it should overwrite. +typeset -g POWERLEVEL9K_CONFIG_FILE=${${(%):-%x}:a} + +(( ${#p10k_config_opts} )) && setopt ${p10k_config_opts[@]} +'builtin' 'unset' 'p10k_config_opts' diff --git a/zsh/antibody/zsh_plugins.txt b/zsh/antibody/zsh_plugins.txt new file mode 100644 index 00000000..1471da00 --- /dev/null +++ b/zsh/antibody/zsh_plugins.txt @@ -0,0 +1,11 @@ +zsh-users/zsh-completions + +# robbyrussell/oh-my-zsh path:plugins/aws + +~/.config/antibody/powerlevel10k + +zsh-users/zsh-syntax-highlighting +zsh-users/zsh-history-substring-search +zsh-users/zsh-autosuggestions +le0me55i/zsh-extract + diff --git a/zsh/cmds b/zsh/cmds new file mode 100644 index 00000000..11f49c73 --- /dev/null +++ b/zsh/cmds @@ -0,0 +1,50 @@ +#!/usr/bin/zsh + +alias backup="sudo borg create --progress --stats /mnt/hdd/backups::laptop_$(date +%m_%d_%Y) /home /usr /etc /var /opt /boot --exclude /var/lib --exclude /home/yigit/Projects/UltimateStudent/recordings" +alias metis_backup="mysqldump --no-tablespaces --single-transaction -u bcaa49b6f602ea -h eu-cdbr-west-03.cleardb.net heroku_a78e4b025f8259d -pdc691280 > ~/.db_backups/metis_$(date +%m_%d_%Y).sql" +alias feh="feh --scale-down --auto-zoom" +alias idea="/home/yigit/.local/share/JetBrains/Toolbox/apps/IDEA-U/ch-0/201.7223.91/bin/idea.sh" +alias lights_off="curl 'http://yeetclock/setcolor?R=2000&G=10&B=000&O=0'" +alias open=xdg-open +alias rm="rm -i" +alias clip="xclip -selection clipboard" + +count() { + echo -n $1 | wc -c +} + +dec() { + echo "obase=10; ibase=16; $(echo "$1" | tr a-z A-Z)" | bc +} + +hex() { + echo "obase=16; ibase=10; $1" | bc +} + +ulimit -n 5000 + +colors() { + color=1; + count=0; + space=" "; + while [ $color -lt 256 ]; do + if [[ $color == 10 ]] + then + space=" " + fi + if [[ $color == 100 ]] + then + space=" " + fi + echo -en "$color:$space\\033[38;5;${color}myeet\\033[48;5;${color}mworld\\033[0m" + echo -n " " + if [[ $count == 10 ]] + then + echo -en "\n"; + count=-1 + fi + ((color++)); + ((count++)) + done + echo "" +} diff --git a/zsh/zshrc b/zsh/zshrc new file mode 100644 index 00000000..b0f3ef0f --- /dev/null +++ b/zsh/zshrc @@ -0,0 +1,60 @@ +~/.scripts/welcome.sh +eval "$(direnv hook zsh)" >> /tmp/direnv +# Enable Powerlevel10k instant prompt. Should stay close to the top of ~/.zshrc. +# Initialization code that may require console input (password prompts, [y/n] +# confirmations, etc.) must go above this block; everything else may go below. +if [[ -r "${XDG_CACHE_HOME:-$HOME/.cache}/p10k-instant-prompt-${(%):-%n}.zsh" ]]; then + source "${XDG_CACHE_HOME:-$HOME/.cache}/p10k-instant-prompt-${(%):-%n}.zsh" +fi + +export TERM=xterm-256color +# Created by kuro for 5.8 +source <(antibody init) + + +export GOPATH=$HOME/go +export PATH="$PATH:/home/yigit/.gem/ruby/2.7.0/bin:$GOPATH/bin:$GOPATH/binexport:/home/yigit/.local/bin" +alias yain="yay -Syu " +alias ls="ls --color" + +HISTFILE=~/.zsh_history +HISTSIZE=10000 +SAVEHIST=10000 +setopt appendhistory + +#Autocompletion +autoload -Uz compinit +compinit + +antibody bundle < ~/.config/antibody/zsh_plugins.txt + +[[ ! -f ~/.config/antibody/p10k.zsh ]] || source ~/.config/antibody/p10k.zsh + +bindkey "^[[H" beginning-of-line +bindkey "^[[F" end-of-line +bindkey "^[[3~" delete-char + +bindkey "^[[1;5C" forward-word +bindkey "^[[1;5D" backward-word + +fpath=(~/.completion $fpath) +source ~/.cmds +export ZSH_AUTOSUGGEST_HIGHLIGHT_STYLE='fg=241' + +export BROWSER=firefox-developer-edition +export EDITOR=vim + +alias t="TERM=screen-256color-bce tmux" +alias tn="TERM=screen-256color-bce tmux new -s " +alias ta="TERM=screen-256color-bce tmux a " + +# added by travis gem +[ ! -s /home/yigit/.travis/travis.sh ] || source /home/yigit/.travis/travis.sh + +export ANDROID_HOME=~/Android/Sdk +export FLUTTER_HOME=~/flutter +export PATH=$PATH:$ANDROID_HOME/tools +export PATH=$PATH:$ANDROID_HOME/platform-tools +export PATH=$PATH:$FLUTTER_HOME/bin + +[ -f ~/.fzf.zsh ] && source ~/.fzf.zsh