diff options
| author | Danilo M. <danix@danix.xyz> | 2026-10-18 11:42:52 +0200 |
|---|---|---|
| committer | Danilo M. <danix@danix.xyz> | 2026-10-18 11:42:52 +0200 |
| commit | 1d527c4e47514540541abf57aa1adb6a14ae5b54 (patch) | |
| tree | dde8c34cd5e7f25291962d5a6e1bca5ac6631b5d | |
| download | rofi-scripts-1d527c4e47514540541abf57aa1adb6a14ae5b54.tar.gz rofi-scripts-1d527c4e47514540541abf57aa1adb6a14ae5b54.zip | |
Initial commit: rofi-scripts, the scripts behind the rofi menus
Power menu, launcher, screenshot picker, SSH host cards, pass browser,
emoji picker, Firefox profile picker, notification actions and an
sd-server model picker. install.sh symlinks them into ~/bin; their
layouts come from unified-desktop-theme.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
| -rw-r--r-- | AGENTS.md | 63 | ||||
| -rw-r--r-- | CLAUDE.md | 6 | ||||
| -rw-r--r-- | LICENSE | 338 | ||||
| -rw-r--r-- | README.md | 55 | ||||
| -rwxr-xr-x | bin/blackpearl-emoji.sh | 19 | ||||
| -rwxr-xr-x | bin/blackpearl-sshmenu.sh | 40 | ||||
| -rwxr-xr-x | bin/firefox-profile | 48 | ||||
| -rwxr-xr-x | bin/notify-actions.sh | 41 | ||||
| -rwxr-xr-x | bin/qar-scrotmenu.sh | 34 | ||||
| -rwxr-xr-x | bin/rofipass | 351 | ||||
| -rwxr-xr-x | bin/sd-webui | 86 | ||||
| -rwxr-xr-x | bin/udt-launcher.sh | 22 | ||||
| -rwxr-xr-x | bin/udt-powermenu.sh | 96 | ||||
| -rwxr-xr-x | install.sh | 25 |
14 files changed, 1224 insertions, 0 deletions
diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..4b44a10 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,63 @@ +# AGENTS.md + +Guidance for AI coding agents working in this repository. + +## What this is + +`rofi-scripts`: the shell scripts that open rofi menus on a Hyprland desktop. +Plain bash or POSIX sh, one file per menu under `bin/`, no build step. Runtime +deps are rofi 2.0 plus whatever each menu drives (pass, grimblast, notifyctl, +sd-server, firefox). + +`./install.sh` symlinks every file in `bin/` into `~/bin/`, so edits are live +on the next launch. The names are the ones hypr-theme's keybindings call +(`udt-powermenu.sh`, `qar-scrotmenu.sh`, `blackpearl-sshmenu.sh`, ...), so a +rename here must be matched there. + +## The themes live elsewhere + +Every script points rofi at a layout under `~/.config/rofi/udt/`, which the +sibling `unified-desktop-theme` repo installs. This repo holds no `.rasi`. +A layout change (header, card grid, banner) belongs there; here only the +per-menu bits passed on the command line: `-p` title, `-mesg`, +`-theme-str` overrides, keybindings. + +Menus on the searchable layouts (`list.rasi`, `grid.rasi`, `ssh.rasi`) show a +wallpaper banner with the `-p` text as a title plate above the search bar. +The house style for that title is a Nerd Font glyph, two spaces, a word and a +colon: `' Pass:'`. Pick glyphs from the `U+F0xxx` range; `ClearlyU` claims +much of the older Private Use Area and draws a blank instead. +`fc-match ":charset=f030b" family` says which font wins. + +## Gotchas + +- **One quoted string per `-theme-str`.** rofi 2.0's lexer reads from the + first `"` to the last, so `textbox { font: "A"; } entry { placeholder: "B"; }` + in one argument silently swallows the second block. Pass two `-theme-str`. +- **Glyph-only elements need `children: [ element-text ]`** in their layout, + or the hidden icon slot pushes the glyph off centre. +- Do not judge a menu by exit code: rofi exits non-zero on Escape. + +## Conventions + +- New menu: one file in `bin/`, license header, then `./install.sh`. +- Placeholders only in code, docs and commits: no hostnames, account names or + home paths. A gitleaks hook enforces it. + +## Testing + +No test suite. `bash -n bin/<script>` (or `sh -n`) for syntax. For anything +visual, open the menu in the session, screenshot and look: + + grim -o DP-1 /tmp/shot.png + +`wtype -k Escape` closes it from a script. + +## Repo facts + +- License: GPLv2 only (`LICENSE`, header in each source file), except + `bin/rofipass` (derived from MIT-licensed upstream, notice kept in the file) + and `bin/udt-powermenu.sh`, `bin/udt-launcher.sh` (derived from adi1090x/rofi, + GPL-3.0 like upstream). +- `origin` is the personal git server (cgit section "Linux"). +- Work directly on master. diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..0d86339 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,6 @@ +# CLAUDE.md + +This file is intentionally thin. AGENTS.md is the single source of truth for +project guidance, shared across every agent tool. Edit AGENTS.md instead. + +@AGENTS.md @@ -0,0 +1,338 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + <https://fsf.org/> + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + <one line to give the program's name and a brief idea of what it does.> + Copyright (C) <year> <name of author> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, see <https://www.gnu.org/licenses/>. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + <signature of Moe Ghoul>, 1 April 1989 + Moe Ghoul, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. diff --git a/README.md b/README.md new file mode 100644 index 0000000..4eae4d9 --- /dev/null +++ b/README.md @@ -0,0 +1,55 @@ +# rofi-scripts + +The scripts behind the rofi menus on my Hyprland desktop: power menu, app +launcher, screenshot picker, SSH host cards, password store, emoji picker, +Firefox profile picker, notification actions and a Stable Diffusion model +picker. They are styled by the layouts from +[unified-desktop-theme](https://git.danix.xyz/unified-desktop-theme/), which +must be installed for them to look right. + +## Requirements + +- rofi 2.0 +- unified-desktop-theme's rofi layouts in `~/.config/rofi/udt/` +- a Nerd Font (Inconsolata Nerd Font Mono) for the menu glyphs +- per menu: `pass` (rofipass), `grimblast` (screenshots), `notifyctl` + (notification actions), `sd-server` (sd-webui), `hyprctl`, `jq` + +## Install + + ./install.sh + +Symlinks every script in `bin/` into `~/bin/` (which must be on `PATH`), +replacing any file of the same name. Bind them to keys in your window manager. + +## Scripts + +| Script | What it opens | +| --- | --- | +| `udt-powermenu.sh` | shutdown, reboot, sleep, logout, with a confirmation step | +| `udt-launcher.sh` | application launcher | +| `qar-scrotmenu.sh` | whole screen or area screenshot | +| `blackpearl-sshmenu.sh` | hosts from `~/.ssh/config` as cards, opens `ssh` in a terminal | +| `rofipass` | password store browser: copy, add, edit, delete, OTP | +| `blackpearl-emoji.sh` | emoji picker | +| `firefox-profile` | Firefox profile picker, one profile behind a password | +| `notify-actions.sh` | pick one of a notification's actions | +| `sd-webui` | pick a Stable Diffusion model, start sd-server, open its web UI | + +## License + +Copyright (C) 2026 Danilo M. <danix@danix.xyz> + +GPLv2 only. See [LICENSE](LICENSE) for the full text. Exceptions, noted in +each file: `rofipass` derives from +[aocoronel/rofipass](https://github.com/aocoronel/rofipass) (MIT), and +`udt-powermenu.sh` and `udt-launcher.sh` derive from +[adi1090x/rofi](https://github.com/adi1090x/rofi) (GPL-3.0). + +## Development Approach + +This project is developed using AI-assisted tools. Code is generated with the help of AI based on human-provided specifications, design decisions, and iterative feedback. + +All contributions are reviewed, tested, and curated by the maintainer before being included in the codebase. AI is used as a productivity and exploration tool, while human oversight remains central to all decisions. + +The goal is to combine the flexibility of AI-assisted development with standard open-source practices such as transparency, review, and accountability. diff --git a/bin/blackpearl-emoji.sh b/bin/blackpearl-emoji.sh new file mode 100755 index 0000000..3969c43 --- /dev/null +++ b/bin/blackpearl-emoji.sh @@ -0,0 +1,19 @@ +#!/bin/sh +# blackpearl-emoji.sh - emoji picker, rofi themed by udt +# Copyright (C) 2026 Danilo M. <danix@danix.xyz> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +rofi -no-lazy-grab -modi emoji -show emoji -display-emoji ' Emoji:' -theme ~/.config/rofi/udt/grid.rasi + diff --git a/bin/blackpearl-sshmenu.sh b/bin/blackpearl-sshmenu.sh new file mode 100755 index 0000000..b0a0fc1 --- /dev/null +++ b/bin/blackpearl-sshmenu.sh @@ -0,0 +1,40 @@ +#!/bin/bash +# blackpearl-sshmenu.sh - the hosts in ~/.ssh/config as rofi cards +# Copyright (C) 2026 Danilo M. <danix@danix.xyz> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +# rofi's own ssh mode shows the alias only, so the config is read here. +# ponytail: plain "Keyword value" lines in ~/.ssh/config only; Include and +# Match are not followed, wildcard Host patterns are skipped. +mapfile -t hosts < <(awk ' + function flush() { if (name != "") print name "\t" user "\t" addr } + tolower($1) == "host" { flush(); name = ($2 ~ /[*?]/) ? "" : $2; user = ""; addr = $2 } + tolower($1) == "hostname" { addr = $2 } + tolower($1) == "user" { user = $2 } + END { flush() }' ~/.ssh/config) + +# Two lines a card: the alias, then "user · address" with the user only where +# the config sets one. Entries are joined on "|" so each can hold a newline. +entries=() +for h in "${hosts[@]}"; do + IFS=$'\t' read -r name user addr <<< "$h" + entries+=("<b>$name</b> +<span size='small' fgalpha='65%'>${user:+$user · }$addr</span>") +done + +i=$(IFS='|'; printf '%s' "${entries[*]}" | rofi -dmenu -i -markup-rows \ + -sep '|' -eh 2 -format i -p ' SSH:' -theme ~/.config/rofi/udt/ssh.rasi) || exit +name=${hosts[i]%%$'\t'*} +exec rofi-sensible-terminal -e ssh "$name" diff --git a/bin/firefox-profile b/bin/firefox-profile new file mode 100755 index 0000000..3920e09 --- /dev/null +++ b/bin/firefox-profile @@ -0,0 +1,48 @@ +#!/bin/bash +# firefox-profile - pick a Firefox profile with rofi, one behind a password +# Copyright (C) 2026 Danilo M. <danix@danix.xyz> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +# Pick a Firefox profile with rofi; one profile requires a password. +# Hash file: printf '%s' 'secret' | sha256sum | cut -d' ' -f1 > ~/.config/firefox-profile.hash +# ponytail: wrapper gate only, `firefox -P <name>` bypasses it. Encrypt the profile dir if that matters. + +PROTECTED="danix" +HASHFILE="$HOME/.config/firefox-profile.hash" +INI="$HOME/.mozilla/firefox/profiles.ini" + +# Opening a link with exactly one profile running: hand it to that instance, +# no picker. The protected profile was already unlocked to get it running. +if [ $# -gt 0 ]; then + running=$(pgrep -af '^/usr/lib64/firefox/firefox(-bin)? (.* )?-P ' | sed -n 's/.* -P \([^ ]*\).*/\1/p' | sort -u) + [ -n "$running" ] && [ "$(wc -l <<<"$running")" -eq 1 ] && exec firefox -P "$running" "$@" +fi + +profile=$(sed -n 's/^Name=//p' "$INI" | rofi -dmenu -theme ~/.config/rofi/udt/list.rasi -i -p ' Firefox:') || exit 0 +[ -n "$profile" ] || exit 0 + +if [ "$profile" = "$PROTECTED" ]; then + pass=$(rofi -dmenu -theme ~/.config/rofi/udt/list.rasi -password -l 0 \ + -mesg "Unlock Firefox profile: $profile" \ + -theme-str 'mainbox { children: [ message, inputbar ]; padding: 16px; spacing: 8px; } message { background-color: transparent; padding: 0 0 4px 2px; } textbox { font: "Noto Sans Bold 13"; }' \ + -theme-str 'entry { placeholder: "Password"; }' </dev/null) || exit 0 + hash=$(printf '%s' "$pass" | sha256sum | cut -d' ' -f1) + if [ "$hash" != "$(cat "$HASHFILE" 2>/dev/null)" ]; then + notify-send "Firefox" "Wrong password" 2>/dev/null + exit 1 + fi +fi + +exec firefox -P "$profile" "$@" diff --git a/bin/notify-actions.sh b/bin/notify-actions.sh new file mode 100755 index 0000000..0c49c6b --- /dev/null +++ b/bin/notify-actions.sh @@ -0,0 +1,41 @@ +#!/bin/bash +# +# Copyright (C) 2026 Danilo M. <danix@danix.xyz> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# Pick one of a notification's actions with rofi and invoke it. The renderer +# passes the labels and keys as arguments, so nothing here parses JSON. +# +# notify-actions.sh <id> <label> <key> [label key ...] + +set -u + +[[ $# -ge 3 ]] || { echo "usage: ${0##*/} <id> <label> <key> ..." >&2; exit 2; } + +id="$1"; shift +labels=() +keys=() +while [[ $# -ge 2 ]]; do + labels+=("$1") + keys+=("$2") + shift 2 +done + +choice="$(printf '%s\n' "${labels[@]}" | rofi -dmenu -i -p "Notification" \ + -theme "$HOME/.config/rofi/udt/menu.rasi")" +[[ -n "$choice" ]] || exit 0 + +for i in "${!labels[@]}"; do + if [[ "${labels[$i]}" == "$choice" ]]; then + notifyctl action "$id" "${keys[$i]}" + exit $? + fi +done diff --git a/bin/qar-scrotmenu.sh b/bin/qar-scrotmenu.sh new file mode 100755 index 0000000..2b7341f --- /dev/null +++ b/bin/qar-scrotmenu.sh @@ -0,0 +1,34 @@ +#!/bin/bash +# qar-scrotmenu.sh - screenshot menu, rofi themed by udt +# Copyright (C) 2026 Danilo M. <danix@danix.xyz> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +rofi_command=(rofi -theme ~/.config/rofi/udt/screenshot.rasi) + +### Options ### +screen="" +area="" +# Variable passed to rofi +options="$screen\n$area" + +chosen="$(echo -e "$options" | "${rofi_command[@]}" -dmenu -selected-row 1 -p ' Screenshot:')" +case $chosen in + $screen) + grimblast -w 3 -n -t png copysave active + ;; + $area) + grimblast -n -t png copysave area + ;; +esac diff --git a/bin/rofipass b/bin/rofipass new file mode 100755 index 0000000..b9620f8 --- /dev/null +++ b/bin/rofipass @@ -0,0 +1,351 @@ +#!/usr/bin/env sh +# rofipass - rofi front end for pass +# +# Derived from rofipass by Augusto Coronel (https://github.com/aocoronel/rofipass), +# released under the MIT License, whose notice is kept below as it requires. +# Modifications Copyright (C) 2026 Danilo M. <danix@danix.xyz>, released under +# the GNU General Public License version 2 (see LICENSE). +# +# MIT License +# +# Copyright (c) 2025 Augusto Coronel +# +# 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. + +### Colors + +help_color="#7c5cff" +div_color="#334433" +label="#f067fc" + +### + +### Bindings + +kb_copy_email="Ctrl+2" # EMAIL +kb_copy_otp="Ctrl-1" # COPY TOTP +kb_add_pass="Ctrl+r" # PASSWORD +kb_add_otp="Ctrl+t" # ADD TOTP +kb_delete="Ctrl-x" # DELETE +kb_edit="Ctrl+y" # EDIT +kb_close_tomb="Ctrl-z" # CLOSE TOMB +kb_open_tomb="Ctrl-o" # OPEN TOMB + +### + +clipmethod="$XDG_SESSION_TYPE" +passdir=${PASSWORD_STORE_DIR:-$HOME/.password-store} + +COLOR_YELLOW="$(tput setaf 226)" +COLOR_RED="$(tput setaf 196)" +COLOR_GREEN="$(tput setaf 82)" +COLOR_BLUE="$(tput setaf 87)" +COLOR_RESET=$(tput sgr0) + +printfc() { + mode=$1 + case $mode in + "ERROR" | "FATAL") + color="$COLOR_RED" + ;; + "WARN") + mode="WARNING" + color="$COLOR_YELLOW" + ;; + "DEBUG") + color="$COLOR_BLUE" + ;; + "INFO") + color="$COLOR_GREEN" + ;; + esac + text=$2 + printf "%s[%s]:%s %s\n" "${color}" "${mode}" "${COLOR_RESET}" "${text}" +} + +check_command() { + for cmd in "$@"; do + if ! command -v "$cmd" >/dev/null 2>&1; then + printfc FATAL "$cmd is not installed." + return 1 + fi + done +} + +_notify() { + message="$1" + header="rofipass" + urgency="$2" + time=${3:-$time} + echo "$message" + if [ "$time" -eq 0 ]; then + notify-send -u "$urgency" "$header" "$message" + else + notify-send -u "$urgency" "$header" "$message" --expire-time="$time"000 --wait + fi +} + +die() { + mode=$1 + message=$2 + urgency=$3 + + printfc "$mode" "$message" + _notify "$message" "$urgency" + exit 1 +} + +version() { + echo "v1.1.0" +} + +usage() { + cat <<EOF +rofipass | A rofi extension for pass + +Usage: rofipass [OPTIONS] <COMMAND> + +Options: + -e <EDITOR> Set editor + -f Lift swap restrictions (for tomb) + -h Display this help message and exit + -l <LENGTH> Default password length on generation + -t <TERM> Default terminal emulator (for tomb) + -v Display the current version number + -T <SECONDS> Clearing time + +Example: + rofipass -f -l 72 -t kitty -e nvim -T 10 +EOF +} + +_rofi() { + rofi -dmenu -theme ~/.config/rofi/udt/list.rasi -i -no-levenshtein-sort "$@" +} + +copy_email() { + email=$(pass "$menu" | sed -n 's/^email=//p') + case "$clipmethod" in + "x11") + xclip "$email" || die FATAL "failed to copy the email." "critical" + _notify "Copied to clipboard. Clearing in $time seconds" "normal" + ;; + "wayland") + wl-copy "$email" || die FATAL "failed to copy the email." "critical" + _notify "Copied to clipboard. Clearing in $time seconds" "normal" + ;; + esac + # clearboard +} + +append_otp() { + check_command zbarimg || die FATAL "zbarimg is not installed." "critical" + case "$clipmethod" in + "x11") + xclip -o | zbarimg -q --raw - | pass otp append "$menu" || die FATAL "failed to append OTP to $menu" "critical" + _notify "Inserted OTP successfully to $menu" "normal" + ;; + "wayland") + wl-paste --type image/png | zbarimg -q --raw - | pass otp append "$menu" || die FATAL "failed to append OTP to $menu" "critical" + _notify "Inserted OTP successfully to $menu" "normal" + ;; + esac +} + +clearboard() { + [ -x "$(command -v notifyctl)" ] && notifyctl close-all + + case "$clipmethod" in + "x11") + echo "" | xclip -sel clip + ;; + "wayland") + [ -x "$(command -v cliphist)" ] && cliphist wipe + echo "" | wl-copy + ;; + esac +} + +tomb_open() { + if [ -n "$FORCE" ]; then + $term -e sh -c "pass open -f" + else + $term -e sh -c "pass open" + fi +} + +tomb_close() { + $term -e sh -c "pass close" + pass_val=$? + if [ "$pass_val" -ne 0 ]; then + die FATAL "failed to close tomb." -u "critical" + else + _notify "Your password tomb has been closed!" "normal" 0 + fi +} + +deleteMenu() { + delask=$(printf "1. Yes\n2. No" | _rofi -p ' Delete:' -mesg "<span color='${label}'>Really delete</span> <span color='${help_color}'>$menu?</span>") + val=$? + [ $val -eq 1 ] && { + _notify "Cancelled!" "low" 0 + main + } + [ "$delask" = "1. Yes" ] && pass rm -f "$menu" && _notify "Deleted $menu" "normal" 0 + main +} + +add_password() { + length=${length:-72} + addmenu=$( + echo | _rofi -p ' New password:' -lines 0 \ + -theme-str 'window { width: 25em; } listview { lines: 0; } entry { placeholder: "Enter password name"; }' + ) + val=$? + if [ $val -eq 1 ]; then + _notify "Cancelled!" "low" 0 + main + elif [ $val -eq 0 ]; then + if command -v "passgen.py" >/dev/null 2>&1; then + passgen.py 3 | pass insert -e "$addmenu" + else + pass generate "$addmenu" "$length" + fi + if [ $val -eq 1 ]; then + _notify ERROR "failed to add password" 0 + main + else + _notify "Added $addmenu" "normal" 0 + fi + fi + main +} + +edit_password() { + $term -e sh -c "export EDITOR=\"$editor\"; pass edit \"$menu\"" +} + +main() { + enable_tomb=0 + enable_otp=0 + enable_zbar=0 + + if ! command -v "tomb" >/dev/null 2>&1; then + enable_tomb=1 + fi + if ! command -v "zbarimg" >/dev/null 2>&1; then + enable_zbar=1 + fi + + pass otp -h >/dev/null 2>&1 || enable_otp=1 + + HELP="" + + HELP="$HELP<span color='${label}'>Actions: </span><span color='${help_color}'>${kb_add_pass}</span>: Add <span color='${div_color}'>|</span> <span color='${help_color}'>${kb_delete}</span>: Delete <span color='${div_color}'>|</span> <span color='${help_color}'>${kb_edit}</span>: Edit" + + if [ "$enable_zbar" -eq 0 ]; then + ZBAR_HELP=" <span color='${div_color}'>|</span> <span color='${help_color}'>${kb_add_otp}</span>: Add OTP" + HELP="$HELP$ZBAR_HELP" + fi + + HELP="$HELP +<span color='${label}'>Copy: </span><span color='${help_color}'>Enter</span>: Copy Password <span color='${div_color}'>|</span> <span color='${help_color}'>${kb_copy_email}</span>: Copy Email" + + if [ "$enable_otp" -eq 0 ]; then + OTP_HELP=" <span color='${div_color}'>|</span> <span color='${help_color}'>${kb_copy_otp}</span>: Copy OTP" + HELP="$HELP$OTP_HELP" + fi + + if [ "$enable_tomb" -eq 0 ]; then + TOMB_HELP="<span color='${label}'>Tomb: </span><span color='${help_color}'>${kb_close_tomb}</span>: Close Tomb <span color='${div_color}'>|</span> <span color='${help_color}'>${kb_open_tomb}</span>: Open Tomb" + HELP="$HELP +$TOMB_HELP" + fi + + pass=$(find -L "$passdir" -type f -name '*.gpg' -printf '%P\n' | sed 's/\.gpg//') + menu=$(echo "${pass}" | _rofi -p ' Pass:' -mesg "${HELP}" -kb-custom-1 "${kb_add_pass}" -kb-custom-2 "${kb_copy_otp}" -kb-custom-3 "${kb_delete}" -kb-custom-4 "${kb_edit}" -kb-custom-5 "${kb_close_tomb}" -kb-custom-6 "${kb_open_tomb}" -kb-custom-7 "${kb_copy_email}" -kb-custom-8 "${kb_add_otp}") + + val=$? + case "$val" in + 1) exit ;; + 12) deleteMenu ;; + 11) # OTP Copy + [ "$enable_otp" -eq 0 ] && { + timeout 3 pass otp -c "$menu" || die ERROR "failed to copy OTP!" "normal" + _notify "Copied to clipboard. Clearing in $time seconds" "normal" + # clearboard + } + ;; + 10) add_password ;; + 13) edit_password ;; + 14) [ "$enable_tomb" -eq 0 ] && tomb_close ;; + 15) [ "$enable_tomb" -eq 0 ] && tomb_open ;; + 16) copy_email ;; + 17) [ "$enable_zbar" -eq 0 ] && append_otp ;; + 0) + pass -c "$menu" || die ERROR "failed to copy the password!" "normal" + _notify "Copied to clipboard. Clearing in $time seconds" "normal" + # clearboard + ;; + esac +} + +while getopts ":hvfl:t:T:e:" opt; do + case "$opt" in + h) + usage + exit 0 + ;; + e) + editor="$OPTARG" + ;; + v) + version + exit 0 + ;; + f) + FORCE=true + ;; + l) + length="$OPTARG" + ;; + t) + term="$OPTARG" + ;; + T) + time="$OPTARG" + ;; + ?) + printfc FATAL "invalid option '-$OPTARG'" >&2 + exit 1 + ;; + esac +done + +shift $((OPTIND - 1)) + +check_command rofi pass || exit 1 + +[ ! -d "$passdir" ] && die FATAL "no password directory found!" "low" + +[ -z "$editor" ] && editor=${EDITOR:-nano} +term=${term:-kitty} +time=${time:-5} + +main diff --git a/bin/sd-webui b/bin/sd-webui new file mode 100755 index 0000000..0d72547 --- /dev/null +++ b/bin/sd-webui @@ -0,0 +1,86 @@ +#!/bin/bash +# sd-webui - start sd-server with a model picked from rofi +# Copyright (C) 2026 Danilo M. <danix@danix.xyz> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +# Start sd-server (stable-diffusion.cpp) with a model picked from rofi and open its web UI. +# Runs in the foreground: close the terminal (or Ctrl-C) to stop it and free VRAM. + +M=/data/LLM-models/SD +QWEN=(--llm $M/Qwen3VL-8B-Instruct-Q8_0.gguf + --llm_vision $M/mmproj-Qwen3VL-8B-Instruct-F16.gguf + --vae $M/vae/qwen_image_2.1_vae_bf16.safetensors) +SDXL=(--cfg-scale 7.0 --steps 25) # same defaults as imggen + +# Pick the model (sd-server loads one per process, so choose at start). +case $(printf '%s\n' \ + "Qwen Image 2.1 (base, 20 steps, text/edit/RGBA)" \ + "Qwen Image 2.1 turbo (6 steps)" \ + "Z-Image Turbo (8 steps, photoreal)" \ + "FLUX.2 klein 4B (4 steps, edit)" \ + "Krea 2 Turbo (8 steps, photoreal)" \ + "Wan2.2 TI2V 5B (video, text/image)" \ + "SDXL base" \ + "RealVisXL V5" \ + "Pony Diffusion V6 XL" \ + | rofi -dmenu -i -theme ~/.config/rofi/udt/list.rasi -p ' SD model:' \ + -theme-str 'entry { placeholder: "Search models"; }') in + "Qwen Image 2.1 (base"*) MODEL=(--diffusion-model $M/qwen_image_2.1-Q8_0.gguf "${QWEN[@]}" + --cfg-scale 6.0 --cache-mode cache-dit) ;; + "Qwen Image 2.1 turbo"*) MODEL=(--diffusion-model $M/Qwen-Image-2.1-viggle-turbo-v0.3-6step-Q8_0.gguf "${QWEN[@]}" + --cfg-scale 1.0 --steps 6) ;; + Z-Image*) MODEL=(--diffusion-model $M/z_image_turbo-Q8_0.gguf + --llm $M/Qwen3-4B-Instruct-2507-Q8_0.gguf --vae $M/vae/flux1-ae.safetensors + --cfg-scale 1.0 --steps 8 --diffusion-fa) ;; + FLUX.2*) MODEL=(--diffusion-model $M/flux-2-klein-4b-Q8_0.gguf + --llm $M/Qwen3-4B-Q8_0.gguf --vae $M/vae/flux2-vae.safetensors + --cfg-scale 1.0 --steps 4 --diffusion-fa) ;; + # Q6_K: same output as Q8_0 at seed 42, ~20% faster (both still offload on 12G). + Krea*) MODEL=(--diffusion-model $M/Krea-2-Turbo-Q6_K.gguf + --llm $M/Qwen3VL-4B-Instruct-Q8_0.gguf --vae $M/vae/wan_2.1_vae.safetensors + --cfg-scale 1.0 --steps 8 --diffusion-fa) ;; + # 1280x704 is the model's native 720p. Frames must be 4k+1 at 24 fps: 49 = 2 s, 121 = 5 s. + # Settings follow upstream Wan2.2 5B defaults (cfg 5, shift 5); drop to 832x480 if too slow. + Wan2.2*) MODEL=(--diffusion-model $M/Wan2.2-TI2V-5B-Q8_0.gguf + --t5xxl $M/umt5-xxl-encoder-Q8_0.gguf --vae $M/vae/wan2.2_vae.safetensors + --cfg-scale 5.0 --steps 30 --flow-shift 5.0 --diffusion-fa + -W 1280 -H 704 --video-frames 49 --temporal-tiling) ;; + # imggen's diffusers weights, symlinked into the layout sd.cpp loads as a directory + "SDXL base") MODEL=(-m $M/sdxl-links/sdxl "${SDXL[@]}") ;; + RealVisXL*) MODEL=(-m $M/sdxl-links/realvis "${SDXL[@]}") ;; + Pony*) MODEL=(-m $M/sdxl-links/pony "${SDXL[@]}" --clip-skip 2) ;; + *) exit 0 ;; +esac + +PORT=${PORT:-7860} +URL=http://127.0.0.1:$PORT/ + +# Open the browser once the server answers (model loading takes a while). +( + until curl -sf -o /dev/null "$URL"; do sleep 1; done + notify-send -a sd-server -i applications-graphics "Stable Diffusion server started" "$URL" + xdg-open "$URL" >/dev/null 2>&1 +) & +trap 'kill $! 2>/dev/null' EXIT + +# Log to a file too: the terminal loses the output when the server crashes. +# stdbuf -oL: line-buffer stdout so the last lines before a crash reach the log. +LOG=${XDG_CACHE_HOME:-$HOME/.cache}/sd-server.log +# MODEL goes after the shared defaults so a model can override them (e.g. Wan's -W/-H). +stdbuf -oL -eL sd-server --listen-port "$PORT" \ + --lora-model-dir $M/loras \ + --sampling-method euler -W 1024 -H 1024 --seed -1 \ + "${MODEL[@]}" \ + --offload-to-cpu -v "$@" 2>&1 | tee "$LOG" diff --git a/bin/udt-launcher.sh b/bin/udt-launcher.sh new file mode 100755 index 0000000..d0a8013 --- /dev/null +++ b/bin/udt-launcher.sh @@ -0,0 +1,22 @@ +#!/usr/bin/env bash + +## Author : Aditya Shakya (adi1090x) +## Github : @adi1090x +## Derived from adi1090x/rofi, GPL-3.0 like upstream. Modifications +## Copyright (C) 2026 Danilo M. <danix@danix.xyz> +# +## Rofi : Launcher (Modi Drun, Run, File Browser, Window) +# +## Available Styles +# +## style-1 style-2 style-3 style-4 style-5 +## style-6 style-7 style-8 style-9 style-10 +## style-11 style-12 style-13 style-14 style-15 + +dir="$HOME/.config/rofi/udt" +theme='launcher' + +## Run +rofi \ + -show drun \ + -theme ${dir}/${theme}.rasi diff --git a/bin/udt-powermenu.sh b/bin/udt-powermenu.sh new file mode 100755 index 0000000..6d8fb84 --- /dev/null +++ b/bin/udt-powermenu.sh @@ -0,0 +1,96 @@ +#!/usr/bin/env bash + +## Author : Aditya Shakya (adi1090x) +## Github : @adi1090x +## Derived from adi1090x/rofi, GPL-3.0 like upstream. Modifications +## Copyright (C) 2026 Danilo M. <danix@danix.xyz> +# +## Rofi : Power Menu +# +## Available Styles +# +## style-1 style-2 style-3 style-4 style-5 + +# Current Theme +dir="$HOME/.config/rofi/udt" +theme='powermenu' + +# CMDs +uptime="`uptime -p | sed -e 's/up //g'`" +host=`hostname` + +# Options +shutdown='' +reboot='' +logout='' +sleep='' +yes='' +no='' + +# Rofi CMD +rofi_cmd() { + rofi -dmenu \ + -p "'ndi vidimu ${USER}" \ + -mesg "Uptime: $uptime" \ + -theme ${dir}/${theme}.rasi +} + +# Confirmation CMD +confirm_cmd() { + rofi -dmenu \ + -p 'Confirmation' \ + -selected-row 1 \ + -mesg 'Simu Sicuri?' \ + -theme "$HOME/.config/rofi/udt/confirm.rasi" +} + +# Ask for confirmation +confirm_exit() { + echo -e "$yes\n$no" | confirm_cmd +} + +# Pass variables to rofi dmenu +run_rofi() { + echo -e "$shutdown\n$reboot\n$sleep\n$logout" | rofi_cmd +} + +# Execute Command +run_cmd() { + selected="$(confirm_exit)" + if [[ "$selected" == "$yes" ]]; then + if [[ $1 == '--shutdown' ]]; then + notify-send 'system shutdown' 'the system is going to shutdown now' + sleep 1 + /usr/bin/loginctl poweroff + elif [[ $1 == '--reboot' ]]; then + notify-send 'system reboot' 'the system is going to reboot now' + sleep 1 + /usr/bin/loginctl reboot + elif [[ $1 == '--sleep' ]]; then + notify-send 'suspend to ram' 'the system is going to sleep now' + sleep 1 + /usr/bin/loginctl suspend + elif [[ $1 == '--logout' ]]; then + hyprctl dispatch 'hl.dsp.exit()' + fi + else + exit 0 + fi +} + +# Actions +chosen="$(run_rofi)" +case ${chosen} in + $shutdown) + run_cmd --shutdown + ;; + $reboot) + run_cmd --reboot + ;; + $sleep) + run_cmd --sleep + ;; + $logout) + run_cmd --logout + ;; +esac diff --git a/install.sh b/install.sh new file mode 100755 index 0000000..e9add5b --- /dev/null +++ b/install.sh @@ -0,0 +1,25 @@ +#!/bin/bash +# install.sh - symlink the rofi scripts into ~/bin +# Copyright (C) 2026 Danilo M. <danix@danix.xyz> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +# Links, not copies, so an edit here is live on the next launch. A file of +# the same name already in ~/bin is replaced by the link. +repo="$(cd "$(dirname "$0")" && pwd)" +mkdir -p "$HOME/bin" +for f in "$repo"/bin/*; do + ln -sfn "$f" "$HOME/bin/${f##*/}" + echo "linked ~/bin/${f##*/}" +done |
